Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1148520
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2016-09-17 16:12:17

//////////////////////drivers/mtd/nand/s3c_nand.c

module_init(s3c_nand_init);//模块初始化
static int __init s3c_nand_init(void)
{
    printk("S3C NAND Driver, (c) 2008 Samsung Electronics\n");
    platform_driver_register(&s3c6400_nand_driver);
        platform_driver_register(&s3c6410_nand_driver);
}


////////////drivers/mtd/nand/s3c_nand.c
platform平台总线驱动结构体
static struct platform_driver s3c6410_nand_driver = {
    .probe        = s3c6410_nand_probe,
    .remove        = s3c_nand_remove,
    .suspend    = s3c_nand_suspend,
    .resume        = s3c_nand_resume,
    .driver        = {
        .name    = "s3c6410-nand",
        .owner    = THIS_MODULE,
    },
};

////////////drivers/mtd/nand/s3c_nand.c
static int s3c6410_nand_probe(struct platform_device *dev)
{
    return s3c_nand_probe(dev, TYPE_S3C6410);
}
///////////////////////////////////////////////////drivers/mtd/nand/s3c_nand.c
/* s3c_nand_probe
 *
 * called by device layer when it finds a device matching
 * one our driver can handled. This code checks to see if
 * it can allocate all necessary resources then calls the
 * nand layer to look for devices
 */
//设备 和 驱动匹配到 后执行
static int s3c_nand_probe(struct platform_device *pdev, enum s3c_cpu_type cpu_type)
{   
  //在Mach-smdk6410.c (linux2.6.28\arch\arm\mach-s3c6410)文件中,有个函数:smdk6410_machine_init
    //s3c_device_nand.dev.platform_data = &s3c_nand_mtd_part_info;  nand有关
    struct s3c_nand_mtd_info *plat_info = pdev->dev.platform_data;
    struct mtd_partition *partition_info = (struct mtd_partition *)plat_info->partition;
    struct nand_chip *nand;
    struct resource *res;
    int err = 0;
    int ret = 0;
    int i, j, size;

#if defined(CONFIG_MTD_NAND_S3C_HWECC)
    struct nand_flash_dev *type = NULL;
    u_char tmp;
#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 */
  //得到I/O内存资源
    /* currently we assume we have the one resource */
    res  = pdev->resource;
    size = res->end - res->start + 1;
//I/O内存资源申请
    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;
//将一个IO地址空间映射到内核的虚拟地址空间上去,便于访问。
    s3c_nand.regs       = ioremap(res->start, size);

    if (s3c_nand.regs == NULL) {
        dev_err(&pdev->dev, "cannot reserve register region\n");
        err = -EIO;
        goto exit_error;
    }

    /* 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 */
//
kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);  跳过sizeof(struct mtd_info)个字节   

   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 < plat_info->chip_nr; i++) {
   //上面s3c_nand.regs       = ioremap(res->start, size);   所以是nand的基地址
////#define S3C_NFDATA        S3C2410_NFR
EG(0x10)

图片
 

        nand->IO_ADDR_R        = (char *)(s3c_nand.regs + S3C_NFDATA);
        nand->IO_AD
DR_W        = (char *)(s3c_nand.regs + S3C_NFDATA);
        nand->cmd_ctrl        = s3c_nand_hwcontrol;
        nand->dev_ready        = s3c_nand_device_ready;       
        nand->scan_bbt        = s3c_nand_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
        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 */
        tmp = readb(nand->IO_ADDR_R);            /* the 4th byte */

        if (!type->pagesize) {
            if (((nand->cellinfo >> 2) & 0x3) == 0) {
                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;
                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;
            }
        } 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;//软件ECC
        printk("S3C NAND Driver is using software ECC.\n");
#endif
        if (nand_scan(s3c_mtd, 1)) {//以mtd_info为参数调用nand_scan()函数探测NAND Flash的存在
            ret = -ENXIO;
            goto exit_error;
        }

        /* Register the partitions */
//如果要分区,则以mtd_info和mtd_partition为参   数调用add_mtd_partitions(),
添加分区信息

        add_mtd_partitions(s3c_mtd, partition_info, plat_info->mtd_part_nr);
    }

    pr_debug("initialized ok\n");
    return 0;

exit_error:
    kfree(s3c_mtd);

    return ret;
}

/////////////////////////////drivers/mtd/nand/s3c_nand.c
struct s3c_nand_info {
    /* mtd info */
    struct nand_hw_control        controller;
    struct s3c_nand_mtd_info    *mtds;
    struct s3c2410_platform_nand    *platform;

    /* device info */
    struct device            *device;
    struct resource            *area;
    struct clk            *clk;
    void __iomem            *regs;
    void __iomem            *sel_reg;
    int                sel_bit;
    int                mtd_count;

    enum s3c_cpu_type        cpu_type;
};
static struct s3c_nand_info s3c_nand;





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