学习笔记

飞凌nand flash驱动移植

(一)飞凌的nand驱动目录下(driver/mtd/nand)多出了一个 s3c_nand.c文件


Kconfig文件中多了几个选项:

config MTD_NAND_S3C
    tristate "NAND support for Samsung S3C"
    depends on (ARCH_S3C64XX || ARCH_S5P64XX || ARCH_S5PC1XX) && MTD_NAND
    help
      This enables the NAND flash controller on the S3C

      No board specific support is done by this driver, each board
      must advertise a platform_device for the driver to attach.

config MTD_NAND_S3C_DEBUG
    bool "S3C NAND driver debug"
    depends on MTD_NAND_S3C
    help
      Enable debugging of the S3C NAND driver

config MTD_NAND_S3C_HWECC
    bool "S3C NAND Hardware ECC"
    depends on MTD_NAND_S3C
    help
      Enable the use of the S3C's internal ECC generator when
      using NAND. Early versions of the chip have had problems with
      incorrect ECC generation, and if using these, the default of
      software ECC is preferable.

      If you lay down a device with the hardware ECC, then you will
      currently not be able to switch to software, as there is no
      implementation for ECC method used by the S3C

Makefile中多了一个编译选项:

obj-$(CONFIG_MTD_NAND_S3C)        += s3c_nand.o


(二)

s3c_nand.c文件中的函数声明在  /arch/arm/plat-samsung/include/plat/regs.nand.h

和   /include/linux/mtd/partitions.h中。


arch/arm/plat-samsung/dev-nand.c中,

MTD体系结构:

在linux中提供了MTD(Memory Technology Device,内存技术设备)系统来建立Flash针对linux的统一、抽象的接口

引入MTD后,linux系统中的Flash设备驱动及接口可分为4层:

设备节点

MTD设备层

MTD原始设备层

硬件驱动层

硬件驱动层:Flash硬件驱动层负责底层硬件设备实际的读、写、擦除,Linux MTD设备的NAND型Flash驱动位于driver/mtd/nand子目录下

s3c2410对应的nand Flash驱动为s3c2410.c

MTD原始设备层:

原始设备层有两部分组成,一部分是MTD原始设备的通用代码,另一部分是各个特定的Flash的数据,例如分区。

用于描述MTD原始设备的数据结构是mtd_info,这其中定义了大量的关于MTD的数据和操作函数。

mtd_table(mtdcore.c)则是所有MTD原始设备的列表,mtd_part(mtd_part.c)是用于表示MTD原始设备分区的结构,其中包含了mtd_info,因为每一个分区都是被看成一个MTD原始设备加在mtd_table中的,mtd_part.mtd_info中的大部分数据都从该分区的主分区mtd_part->master中获得。

在drivers/mtd/maps/子目录下存放的是特定的flash的数据,每一个文件都描述了一块板子上的flash。其中调用add_mtd_device()、del_mtd_device()建立/删除 mtd_info结构并将其加入/删除mtd_table(或者调用add_mtd_partition()、del_mtd_partition() (mtdpart.c)建立/删除mtd_part结构并将mtd_part.mtd_info加入/删除mtd_table 中)。

mtd层用一个数组struct mtd_info *mtd_table[MAX_MTD_DEVICES]保存系统中所有的设备,mtd设备利用struct mtd_info 这个结构来描述,该结构中描述了存储设备的基本信息和具体操作所需要的内核函数,mtd系统的那个机制主要就是围绕这个结构来实现的。

结构体在include/linux/mtd/mtd.h中定义:

struct mtd_info {

u_char type;            //MTD 设备类型

u_int32_t flags;        //MTD设备属性标志

u_int32_t size;         //标示了这个mtd设备的大小

u_int32_t erasesize;    //MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小

u_int32_t oobblock;     //oob区在页内的位置,对于512字节一页的nand来说是512

u_int32_t oobsize;      //oob区的大小,对于512字节一页的nand来说是16

u_int32_t ecctype;      //ecc校验类型

u_int32_t eccsize;      //ecc的大小

char *name;             //设备的名字

int index;              //设备在MTD列表中的位置

struct nand_oobinfo oobinfo; //oob区的信息,包括是否使用ecc,ecc的大小

//以下是关于mtd的一些读写函数,将在nand_base中的nand_scan中重载

int (*erase)

int (*read)

int (*write)

int (*read_ecc)

int (*write_ecc)

int (*read_oob)

int (*read_oob)

void *priv;//设备私有数据指针,对于NandFlash来说指nand芯片的结构

下面看nand_chip结构,在include/linux/mtd/nand.h中定义:

struct nand_chip {

void __iomem   *IO_ADDR_R;   //这是nandflash的读写寄存器

void __iomem     *IO_ADDR_W;

//以下都是nandflash的操作函数,这些函数将根据相应的配置进行重载

u_char    (*read_byte)(struct mtd_info *mtd);

void      (*write_byte)(struct mtd_info *mtd, u_char byte);

u16       (*read_word)(struct mtd_info *mtd);

void      (*write_word)(struct mtd_info *mtd, u16 word);

void     (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);

void     (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);

int     (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);

void     (*select_chip)(struct mtd_info *mtd, int chip);

int     (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);

int      (*block_markbad)(struct mtd_info *mtd, loff_t ofs);

void     (*hwcontrol)(struct mtd_info *mtd, int cmd);

int      (*dev_ready)(struct mtd_info *mtd);

void     (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);

int    (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);

int     (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);

int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);

void   (*enable_hwecc)(struct mtd_info *mtd, int mode);

void    (*erase_cmd)(struct mtd_info *mtd, int page);

int     (*scan_bbt)(struct mtd_info *mtd);

int       eccmode;     //ecc的校验模式(软件,硬件)

int      chip_delay; //芯片时序延迟参数

int       page_shift; //页偏移,对于512B/页的,一般是9

u_char    *data_buf;   //数据缓存区


MTD原始设备层与FLASH硬件驱动之间的交互。

一个MTD原始设备可以通过mtd_part分割成数个MTD原始设备注册进mtd_table,mtd_table中的每个MTD原始设备都可以被注册成一个MTD设备,有两个函数可以完成这个工作,即 add_mtd_device函数和add_mtd_partitions函数。

其中add_mtd_device函数是把整个NAND FLASH注册进MTD Core,而add_mtd_partitions函数则是把NAND FLASH的各个分区分别注册进MTD Core。

add_mtd_partitions函数的原型是:
int add_mtd_partitions( struct mtd_info * master,

             const struct mtd_partition * parts, int nbparts) ;


其中master就是这个MTD原始设备,parts即NAND的分区信息,nbparts指有几个分区。那么parts和nbparts怎么来?caorr_platform_default_nand 就是起这个作用了。static struct mtd_partition caorr_platform_default_nand[ ] = {
    [ 0] = {
               . name = "Boot Strap" ,
               . offset = 0,
               . size = 0x40000,
    } ,
    [ 1] = {
               . name = "Bootloader" ,
               . offset = MTDPART_OFS_APPEND,
               . size = 0x40000,
    } ,
    [ 2] = {
               . name = "Partition Table" ,
               . offset = MTDPART_OFS_APPEND,
               . size = 0x40000,
    } ,
    [ 3] = {
               . name = "Linux Kernel" ,
               . offset = MTDPART_OFS_APPEND,
               . size = 0x500000,
    } ,
    [ 4] = {
               . name = "Rootfs" ,
               . offset = MTDPART_OFS_APPEND,
               . size = MTDPART_SIZ_FULL,
    } ,
} ;


其中offset是分区开始的偏移地址,在后4个分区我们设为 MTDPART_OFS_APPEND,表示紧接着上一个分区,MTD Core会自动计算和处理分区地址;size是分区的大小,在最后一个分区我们设为MTDPART_SIZ_FULL,表示这个NADN剩下的所有部分。



MTD设备层:

基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90)。MTD字符设备的定义在mtdchar.c中实现,通过注册一系列file operation函数(lseek、open、close、read、write)。MTD块设备则是定义了一个描述MTD块设备的结构 mtdblk_dev,并声明了一个名为mtdblks的指针数组,这数组中的每一个mtdblk_dev和mtd_table中的每一个 mtd_info一一对应。


Flash 驱动中使用如下两个函数来注册 和注销MTD 设备:

int add_mtd_device(struct mtd_info *mtd);

int del_mtd_device (struct mtd_info *mtd)

4、mtd_part 结构体分析     此结构定义在 ../drivers/mtd/mtdpart.c 中

  1. struct mtd_part {  
  2.     struct mtd_info mtd;      // 分区的信息(大部分由其 master 决定)  
  3.     struct mtd_info *master;  // 该分区的主分区  
  4.     uint64_t offset;          // 分区的偏移地址  
  5.     struct list_head list;    // 分区号  
  6. };  
mtd_part 结构体由于表示分区,它在mtd_info 结构体成员用于描述该分区, 它会被加入到 mtd_table (定义为 struct mtd_info *mtd_table[MAX_MTD_DEVICES])中,

其大部分成员有 mtd_part—> 决定,各种函数也指向主分区的相应函数。


5、mtd_partition 结构体分析    该结构体定义在 include/linux/mtd/partitions.h 中

  1. struct mtd_partition {  
  2.     char *name;         /* identifier string */     // 标识字符串  
  3.     uint64_t size;          /* partition size */        // 分区大小  
  4.     uint64_t offset;        /* offset within the master MTD space */                              // 主MTD空间内的偏移量                        
  5.     uint32_t mask_flags;        /* master MTD flags to mask out for this partition */                 // 掩码标志  
  6.     struct nand_ecclayout *ecclayout;   /* out of band layout for this partition (NAND only)*/  
  7. };  

mtd_partttion 会在MTD 原始设备层调用 add_mtd_partitons() 时传递分区信息,并通过下面两个函数进行注册和注销 分区:

  1. int add_mtd_partitions( struct mtd_info *master, struct mtd_partition *parts, int nbparts);  
  2. int del_mtd_partitions (struct mtd_info *master);  
add_mtd_partitions() 会对每一个新建立的分区建立一个新的 mtd_part 结构体,将其加入 mtd_partitions 中,并调用 add_mtd_device () 将此分区作为 MTD 设备加入 mtd_tabe。


第二、NAND Flash 驱动程序分析:

Linux 内核在 MTD的下层实现了通用NAND 驱动(主要通过 drivers/mtd/nand/nand_base.c 文件实现),因此芯片级的驱动不再需要实现 mtd_info 中的: read(), write() ,

read_oob(), write_oob 等成员函数,而主体 转移到了 nand_chip 数据结构。

 

关键词解析:

ALE:地址锁存使能(Address Latch Enable, ALE):当ALE为高时,在WE#信号的上升沿,地址被锁存到NAND地址寄存器中。

CLE:指令锁存使能(Command Latch Enable, CLE): 当CLE为高时,在WE#信号的上升沿,指令被锁存到NAND指令寄存器中。

BSP:Board Support Package

1、nand_chip 结构体分析       该结构体定义在 ./include/linux/mtd/nand.h

  1. struct nand_chip {  
  2.     void  __iomem   *IO_ADDR_R;               // 读 8 位 I/O 线地址,由主板决定  
  3.     void  __iomem   *IO_ADDR_W;               // 写 8 为 I/O 线地址,由主板决定   
  4.   
  5.     uint8_t     (*read_byte)(struct mtd_info *mtd);  
  6.     u16     (*read_word)(struct mtd_info *mtd);  
  7.     void        (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);  
  8.     void        (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);  
  9.     int     (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);  
  10.     void        (*select_chip)(struct mtd_info *mtd, int chip);                    // 片选芯片  
  11.     int     (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);       // 是否为坏块  
  12.     int     (*block_markbad)(struct mtd_info *mtd, loff_t ofs);                // 标记坏块  
  13.     void        (*cmd_ctrl)(struct mtd_info *mtd, int dat,  
  14.                     unsigned int ctrl);                                    // 控制 AEL/CLE/nCE, 也用于写命令 和 地址  
  15.     int     (*dev_ready)(struct mtd_info *mtd);                                // 设备就绪  
  16.     void        (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);  
  17.     int     (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);  
  18.     void        (*erase_cmd)(struct mtd_info *mtd, int page);  
  19.     int     (*scan_bbt)(struct mtd_info *mtd);  
  20.     int     (*errstat)(struct mtd_info *mtd, struct nand_chip *thisint state, int status, int page);  
  21.     int     (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,  
  22.                       const uint8_t *buf, int page, int cached, int raw);  
  23.   
  24.     int     chip_delay;  
  25.     unsigned int    options;  
  26.   
  27.     int     page_shift;  
  28.     int     phys_erase_shift;  
  29.     int     bbt_erase_shift;  
  30.     int     chip_shift;  
  31.     int     numchips;  
  32.     uint64_t    chipsize;  
  33.     int     pagemask;  
  34.     int     pagebuf;  
  35.     int     subpagesize;  
  36.     uint8_t     cellinfo;  
  37.     int     badblockpos;  
  38.     int     badblockbits;  
  39.   
  40.     flstate_t   state;  
  41.   
  42.     uint8_t     *oob_poi;  
  43.     struct nand_hw_control  *controller;  
  44.     struct nand_ecclayout   *ecclayout;  
  45.   
  46.     struct nand_ecc_ctrl ecc;  
  47.     struct nand_buffers *buffers;  
  48.     struct nand_hw_control hwcontrol;  
  49.   
  50.     struct mtd_oob_ops ops;  
  51.   
  52.     uint8_t     *bbt;  
  53.     struct nand_bbt_descr   *bbt_td;  
  54.     struct nand_bbt_descr   *bbt_md;  
  55.   
  56.     struct nand_bbt_descr   *badblock_pattern;  
  57.   
  58.     void        *priv;  
  59. };  

MTD 使用 nand_chip 数据结构表示一个NAND Flash 芯片,这个结构体中包含了关于 NAND Flash 的地址信息、读写方法、ECC模式、硬件控制等一系列底层机制。

2、S3C6410 nand_chip 初始化 与 NAND 探测

S3C6410 的 NAND 驱动以 platform 驱动的形式存在,在执行probe() 时,初始化nand_chip 实例并运行 nand_scan 扫描 NAND 设备, 最后调用 add_mtd_partitions() 添加主板中定义的分区表,nand_chip 是nanf flash 驱动的核心数据结构,这个结构体重的成员直接对应这 NAND Flash 的底层操作,针对具体情况的NAND 控制器情况

 

分析 s3c_nand_probe 函数体对 S3C6410 nand_chip  的初始化和注册: 该文件定义在 drivers/mtd/nand/s3c_nand.c 中,而在基础内核2.6.36.2 中的这个文件为s3c2410.c

所以如果你想在 Linux 2.6.36.2 的内核对 S3C6410 nand flash 控制器进行支持的话,s3c_nand.c 这个文件需要自己添加。

  1. static int s3c_nand_probe(struct platform_device *pdev, enum s3c_cpu_type cpu_type)  
  2. {     
  3.     struct s3c2410_platform_nand *plat = pdev->dev.platform_data;  
  4.     struct s3c2410_nand_set *sets;  
  5.     struct nand_chip *nand;  
  6.     struct resource *res;  
  7.     int err = 0;  
  8.     int ret = 0;  
  9.     int nr_sets;  
  10.     int i, j, size;  
  11.   
  12. #if defined(CONFIG_MTD_NAND_S3C_HWECC)  
  13.     struct nand_flash_dev *type = NULL;  
  14.     u_char tmp;  
  15.     u_char dev_id;  
  16. #endif   
  17.   
  18.     /* get the clock source and enable it */  
  19.   
  20.     s3c_nand.clk = clk_get(&pdev->dev, "nand");  
  21.     if (IS_ERR(s3c_nand.clk)) {  
  22.         dev_err(&pdev->dev, "failed to get clock");  
  23.         err = -ENOENT;  
  24.         goto exit_error;  
  25.     }  
  26.   
  27.     clk_enable(s3c_nand.clk);  
  28.   
  29.     /* allocate and map the resource */  
  30.   
  31.     /* currently we assume we have the one resource */  
  32.     res  = pdev->resource;  
  33.     size = res->end - res->start + 1;  
  34.   
  35.     s3c_nand.area = request_mem_region(res->start, size, pdev->name);  
  36.   
  37.     if (s3c_nand.area == NULL) {  
  38.         dev_err(&pdev->dev, "cannot reserve register region\n");  
  39.         err = -ENOENT;  
  40.         goto exit_error;  
  41.     }  
  42.   
  43.     s3c_nand.cpu_type   = cpu_type;  
  44.     s3c_nand.device     = &pdev->dev;  
  45.     s3c_nand.regs       = ioremap(res->start, size);  
  46.     s3c_nand.platform   = plat;  
  47.   
  48.     if (s3c_nand.regs == NULL) {  
  49.         dev_err(&pdev->dev, "cannot reserve register region\n");  
  50.         err = -EIO;  
  51.         goto exit_error;  
  52.     }  
  53.   
  54.     sets = (plat != NULL) ? plat->sets : NULL;  
  55.     nr_sets = (plat != NULL) ? plat->nr_sets : 1;  
  56.   
  57.     s3c_nand.mtd_count = nr_sets;  
  58.   
  59.     /* allocate memory for MTD device structure and private data */  
  60.     s3c_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);  
  61.   
  62.     if (!s3c_mtd) {  
  63.         printk("Unable to allocate NAND MTD dev structure.\n");  
  64.         return -ENOMEM;  
  65.     }  
  66.   
  67.     /* Get pointer to private data */  
  68.     nand = (struct nand_chip *) (&s3c_mtd[1]);  
  69.   
  70.     /* Initialize structures */  
  71.     memset((char *) s3c_mtd, 0, sizeof(struct mtd_info));  
  72.     memset((char *) nand, 0, sizeof(struct nand_chip));  
  73.   
  74.     /* Link the private data with the MTD structure */  
  75.     s3c_mtd->priv = nand;  
  76.   
  77.     for (i = 0; i < sets->nr_chips; i++) {  
  78.         nand->IO_ADDR_R      = (char *)(s3c_nand.regs + S3C_NFDATA);      // 初始化 IO_ADDR_R  
  79.         nand->IO_ADDR_W      = (char *)(s3c_nand.regs + S3C_NFDATA);      // 初始化 IO_ADDR_W  
  80.         nand->cmd_ctrl       = s3c_nand_hwcontrol;                        // 初始化 cmd_crtl()   
  81.         nand->dev_ready      = s3c_nand_device_ready;             // 初始化 dev_read()  
  82.         nand->scan_bbt       = s3c_nand_scan_bbt;                         // 初始化 scan_bbt()  
  83.         nand->options        = 0;  
  84.   
  85. #if defined(CONFIG_MTD_NAND_S3C_CACHEDPROG)  
  86.         nand->options        |= NAND_CACHEPRG;  
  87. #endif  
  88.   
  89. #if defined(CONFIG_MTD_NAND_S3C_HWECC)  
  90.         nand->ecc.mode       = NAND_ECC_HW;  
  91.         nand->ecc.hwctl      = s3c_nand_enable_hwecc;  
  92.         nand->ecc.calculate  = s3c_nand_calculate_ecc;  
  93.         nand->ecc.correct    = s3c_nand_correct_data;  
  94.           
  95.         s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);  
  96.         s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);  
  97.         s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE);  
  98.         s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  
  99.         s3c_nand_device_ready(0);  
  100.   
  101.         tmp = readb(nand->IO_ADDR_R); /* Maf. ID */               // 制造商ID  
  102.         dev_id = tmp = readb(nand->IO_ADDR_R); /* Device ID */    // 设备ID  
  103.   
  104.         for (j = 0; nand_flash_ids[j].name != NULL; j++) {  
  105.             if (tmp == nand_flash_ids[j].id) {  
  106.                 type = &nand_flash_ids[j];  
  107.                 break;  
  108.             }  
  109.         }  
  110.   
  111.         if (!type) {  
  112.             printk("Unknown NAND Device.\n");  
  113.             goto exit_error;  
  114.         }  
  115.           
  116.         nand->cellinfo = readb(nand->IO_ADDR_R);  /* the 3rd byte */  // 第3个字节  
  117.         tmp = readb(nand->IO_ADDR_R);            /* the 4th byte */  // 第4个字节  
  118.         if (!type->pagesize) {  
  119.             if (((nand->cellinfo >> 2) & 0x3) == 0) {  
  120.                 nand_type = S3C_NAND_TYPE_MLC_4BIT;  
  121.                 nand->options |= NAND_NO_SUBPAGE_WRITE;  /* NOP = 1 if MLC */  
  122.                 nand->ecc.read_page = s3c_nand_read_page_4bit;  
  123.                 nand->ecc.write_page = s3c_nand_write_page_4bit;  
  124.                 nand->ecc.size = 512;  
  125.                 nand->ecc.bytes = 8; /* really 7 bytes */  
  126.                   
  127.   
  128.                 if ((1024 << (tmp & 0x3)) > 512) {  
  129.                     nand->ecc.layout = &s3c_nand_oob_mlc_64;  
  130.                 } else {  
  131.                     nand->ecc.layout = &s3c_nand_oob_16;  
  132.                 }  
  133. /* 
  134.                 nand_type = S3C_NAND_TYPE_SLC;               
  135.                 nand->ecc.size = 512; 
  136.                 nand->ecc.bytes  = 4; 
  137.  
  138.                 if ((1024 << (tmp & 0x3)) > 512) { 
  139.                     nand->ecc.read_page = s3c_nand_read_page_1bit; 
  140.                     nand->ecc.write_page = s3c_nand_write_page_1bit; 
  141.                     nand->ecc.read_oob = s3c_nand_read_oob_1bit; 
  142.                     nand->ecc.write_oob = s3c_nand_write_oob_1bit; 
  143.                     nand->ecc.layout = &s3c_nand_oob_64; 
  144.                 } else { 
  145.                     nand->ecc.layout = &s3c_nand_oob_16; 
  146.                 } 
  147. */  
  148.             } else {  
  149.                 nand_type = S3C_NAND_TYPE_MLC_4BIT;  
  150.                 nand->options |= NAND_NO_SUBPAGE_WRITE;  /* NOP = 1 if MLC */  
  151.                 nand->ecc.read_page = s3c_nand_read_page_4bit;  
  152.                 nand->ecc.write_page = s3c_nand_write_page_4bit;  
  153.                 nand->ecc.size = 512;  
  154.                 nand->ecc.bytes = 8; /* really 7 bytes */  
  155.                 nand->ecc.layout = &s3c_nand_oob_mlc_64;  
  156.   
  157.   
  158.                 if(dev_id == 0xd5)  
  159.                 {  
  160.                     printk("dev_id == 0xd5 select s3c_nand_oob_mlc_128\n");  
  161.                     nand_type = S3C_NAND_TYPE_MLC_8BIT;  
  162.                     nand->ecc.read_page = s3c_nand_read_page_8bit;  
  163.                     nand->ecc.write_page = s3c_nand_write_page_8bit;  
  164.                     nand->ecc.size = 512;  
  165.                     nand->ecc.bytes = 13;    /* really 7 bytes */  
  166.                     nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;  
  167.                 }  
  168.             }  
  169.         } else {  
  170.             nand_type = S3C_NAND_TYPE_SLC;  
  171.             nand->ecc.size = 512;  
  172.             nand->cellinfo = 0;  
  173.             nand->ecc.bytes = 4;  
  174.             nand->ecc.layout = &s3c_nand_oob_16;   
  175.         }  
  176.   
  177.         printk("S3C NAND Driver is using hardware ECC.\n");  
  178. #else   
  179.         nand->ecc.mode = NAND_ECC_SOFT;  
  180.         printk("S3C NAND Driver is using software ECC.\n");  
  181. #endif  
  182.         if (nand_scan(s3c_mtd, 1)) {  
  183.             ret = -ENXIO;  
  184.             goto exit_error;  
  185.         }  
  186.   
  187.         /* Register the partitions */      
  188.         add_mtd_partitions(s3c_mtd, sets->partitions, sets->nr_partitions);     // 注册分区信息  
  189.     }  
  190.   
  191.     pr_debug("initialized ok\n");  
  192.     return 0;  
  193.   
  194. exit_error:  
  195.     kfree(s3c_mtd);  
  196.   
  197.     return ret;  
  198. }  

drivers/mtd/nand/s3c_nand.c 是一个platform 驱动, 加入我们需要移植 OK6410 的 NAND Flash 驱动这要在 OK6410 的BSP(板级支持包)中田间针对 NAND 的 platform 设备和 分区信息即可,也就是在 arch/arm/mach-s3c64xx/mach-smdk6410.c 中添加这些信息,就可以将上面的NAND Flash 驱动移植成功。

参考文献:设备驱动开发详解(第2版) 华清远见 宋宝华著  http://www.linuxidc.com/Linux/2011-04/35312.htm

NAND Flash驱动移植方法、可以参考我的上篇文章:http://www.linuxidc.com/Linux/2012-04/59293.htm

将这篇文章和上一篇文章( http://www.linuxidc.com/Linux/2012-04/59293.htm)一起来阅读,理解 NAND Flash驱动就能容易些了


plat/map-base.h 含有LCD驱动函数的定义。

s3c_device_fimc0  在 plat-samsung/dev-fimc0.c 和 dev-fimc1.c中调用。

s3c_device_fimc0  在plat-samsung/include/devs.h中定义。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值