Chinaunix首页 | 论坛 | 博客
  • 博客访问: 346838
  • 博文数量: 108
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 65
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-16 11:38
文章分类
文章存档

2016年(2)

2015年(44)

2014年(62)

分类: 嵌入式

2014-10-29 17:17:54

原文地址:

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 这个文件需要自己添加。

static int s3c_nand_probe(struct platform_device *pdev, enum s3c_cpu_type cpu_type)  
{     
    struct s3c2410_platform_nand *plat = pdev->dev.platform_data;  
    struct s3c2410_nand_set *sets;  
    struct nand_chip *nand;  
    struct resource *res;  
    int err = 0;  
    int ret = 0;  
    int nr_sets;  
    int i, j, size;  
  
#if defined(CONFIG_MTD_NAND_S3C_HWECC)   
    struct nand_flash_dev *type = NULL;  
    u_char tmp;  
    u_char dev_id;  
#endif   
  
    /* get the clock source and enable it */  
  
    s3c_nand.clk = clk_get(&pdev->dev, "nand");  
    if (IS_ERR(s3c_nand.clk)) {  
        dev_err(&pdev->dev, "failed to get clock");  
        err = -ENOENT;  
        goto exit_error;  
    }  
  
    clk_enable(s3c_nand.clk);  
  
    /* allocate and map the resource */  
  
    /* currently we assume we have the one resource */  
    res  = pdev->resource;  
    size = res->end - res->start + 1;  
  
    s3c_nand.area = request_mem_region(res->start, size, pdev->name);  
  
    if (s3c_nand.area == NULL) {  
        dev_err(&pdev->dev, "cannot reserve register region\n");  
        err = -ENOENT;  
        goto exit_error;  
    }  
  
    s3c_nand.cpu_type   = cpu_type;  
    s3c_nand.device     = &pdev->dev;  
    s3c_nand.regs       = ioremap(res->start, size);  
    s3c_nand.platform   = plat;  
  
    if (s3c_nand.regs == NULL) {  
        dev_err(&pdev->dev, "cannot reserve register region\n");  
        err = -EIO;  
        goto exit_error;  
    }  
  
    sets = (plat != NULL) ? plat->sets : NULL;  
    nr_sets = (plat != NULL) ? plat->nr_sets : 1;  
  
    s3c_nand.mtd_count = nr_sets;  
  
    /* allocate memory for MTD device structure and private data */  
    s3c_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);  
  
    if (!s3c_mtd) {  
        printk("Unable to allocate NAND MTD dev structure.\n");  
        return -ENOMEM;  
    }  
  
    /* Get pointer to private data */  
    nand = (struct nand_chip *) (&s3c_mtd[1]);  
  
    /* Initialize structures */  
    memset((char *) s3c_mtd, 0, sizeof(struct mtd_info));  
    memset((char *) nand, 0, sizeof(struct nand_chip));  
  
    /* Link the private data with the MTD structure */  
    s3c_mtd->priv = nand;  
  
    for (i = 0; i < sets->nr_chips; i++) {  
        nand->IO_ADDR_R      = (char *)(s3c_nand.regs + S3C_NFDATA);      // 初始化 IO_ADDR_R   
        nand->IO_ADDR_W      = (char *)(s3c_nand.regs + S3C_NFDATA);      // 初始化 IO_ADDR_W   
        nand->cmd_ctrl       = s3c_nand_hwcontrol;                        // 初始化 cmd_crtl()    
        nand->dev_ready      = s3c_nand_device_ready;             // 初始化 dev_read()   
        nand->scan_bbt       = s3c_nand_scan_bbt;                         // 初始化 scan_bbt()   
        nand->options        = 0;  
  
#if defined(CONFIG_MTD_NAND_S3C_CACHEDPROG)   
        nand->options        |= NAND_CACHEPRG;  
#endif   
  
#if defined(CONFIG_MTD_NAND_S3C_HWECC)   
        nand->ecc.mode       = NAND_ECC_HW;  
        nand->ecc.hwctl      = s3c_nand_enable_hwecc;  
        nand->ecc.calculate  = s3c_nand_calculate_ecc;  
        nand->ecc.correct    = s3c_nand_correct_data;  
          
        s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);  
        s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);  
        s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE);  
        s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  
        s3c_nand_device_ready(0);  
  
        tmp = readb(nand->IO_ADDR_R); /* Maf. ID */               // 制造商ID   
        dev_id = tmp = readb(nand->IO_ADDR_R); /* Device ID */    // 设备ID   
  
        for (j = 0; nand_flash_ids[j].name != NULL; j++) {  
            if (tmp == nand_flash_ids[j].id) {  
                type = &nand_flash_ids[j];  
                break;  
            }  
        }  
  
        if (!type) {  
            printk("Unknown NAND Device.\n");  
            goto exit_error;  
        }  
          
        nand->cellinfo = readb(nand->IO_ADDR_R);  /* the 3rd byte */  // 第3个字节   
        tmp = readb(nand->IO_ADDR_R);            /* the 4th byte */  // 第4个字节   
        if (!type->pagesize) {  
            if (((nand->cellinfo >> 2) & 0x3) == 0) {  
                nand_type = S3C_NAND_TYPE_MLC_4BIT;  
                nand->options |= NAND_NO_SUBPAGE_WRITE;  /* NOP = 1 if MLC */  
                nand->ecc.read_page = s3c_nand_read_page_4bit;  
                nand->ecc.write_page = s3c_nand_write_page_4bit;  
                nand->ecc.size = 512;  
                nand->ecc.bytes = 8; /* really 7 bytes */  
                  
  
                if ((1024 << (tmp & 0x3)) > 512) {  
                    nand->ecc.layout = &s3c_nand_oob_mlc_64;  
                } else {  
                    nand->ecc.layout = &s3c_nand_oob_16;  
                }  
/* 
                nand_type = S3C_NAND_TYPE_SLC;               
                nand->ecc.size = 512; 
                nand->ecc.bytes  = 4; 
 
                if ((1024 << (tmp & 0x3)) > 512) { 
                    nand->ecc.read_page = s3c_nand_read_page_1bit; 
                    nand->ecc.write_page = s3c_nand_write_page_1bit; 
                    nand->ecc.read_oob = s3c_nand_read_oob_1bit; 
                    nand->ecc.write_oob = s3c_nand_write_oob_1bit; 
                    nand->ecc.layout = &s3c_nand_oob_64; 
                } else { 
                    nand->ecc.layout = &s3c_nand_oob_16; 
                } 
*/  
            } else {  
                nand_type = S3C_NAND_TYPE_MLC_4BIT;  
                nand->options |= NAND_NO_SUBPAGE_WRITE;  /* NOP = 1 if MLC */  
                nand->ecc.read_page = s3c_nand_read_page_4bit;  
                nand->ecc.write_page = s3c_nand_write_page_4bit;  
                nand->ecc.size = 512;  
                nand->ecc.bytes = 8; /* really 7 bytes */  
                nand->ecc.layout = &s3c_nand_oob_mlc_64;  
  
  
                if(dev_id == 0xd5)  
                {  
                    printk("dev_id == 0xd5 select s3c_nand_oob_mlc_128\n");  
                    nand_type = S3C_NAND_TYPE_MLC_8BIT;  
                    nand->ecc.read_page = s3c_nand_read_page_8bit;  
                    nand->ecc.write_page = s3c_nand_write_page_8bit;  
                    nand->ecc.size = 512;  
                    nand->ecc.bytes = 13;    /* really 7 bytes */  
                    nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;  
                }  
            }  
        } else {  
            nand_type = S3C_NAND_TYPE_SLC;  
            nand->ecc.size = 512;  
            nand->cellinfo = 0;  
            nand->ecc.bytes = 4;  
            nand->ecc.layout = &s3c_nand_oob_16;   
        }  
  
        printk("S3C NAND Driver is using hardware ECC.\n");  
#else   
        nand->ecc.mode = NAND_ECC_SOFT;  
        printk("S3C NAND Driver is using software ECC.\n");  
#endif   
        if (nand_scan(s3c_mtd, 1)) {  
            ret = -ENXIO;  
            goto exit_error;  
        }  
  
        /* Register the partitions */      
        add_mtd_partitions(s3c_mtd, sets->partitions, sets->nr_partitions);     // 注册分区信息   
    }  
  
    pr_debug("initialized ok\n");  
    return 0;  
  
exit_error:  
    kfree(s3c_mtd);  
  
    return ret;  

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

参考文献:设备驱动开发详解(第2版) 华清远见 宋宝华著 

NAND Flash驱动移植方法、可以参考我的上篇文章:

将这篇文章和上一篇文章()一起来阅读,理解 NAND Flash驱动就能容易些了。

本篇文章来源于 Linux公社网站()  原文链接:



阅读(807) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~