加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

MTD原始设备与NANDFLASH硬件驱动交互

发布时间:2020-12-15 06:33:26 所属栏目:百科 来源:网络整理
导读:好久没写博客了,今天再次分析NANDFLASH驱动程序,每一次读源码总有一点的收获 1、首先从入口函数开始 probe函数将是我们遇到的第一个与具体硬件打交道,同时也相对复杂的函数对于很多外设的driver来说,只要能成功实现probe函数,那基本上完成这个外设的drive

好久没写博客了,今天再次分析NANDFLASH驱动程序,每一次读源码总有一点的收获

1、首先从入口函数开始

probe函数将是我们遇到的第一个与具体硬件打交道,同时也相对复杂的函数对于很多外设的driver来说,只要能成功实现probe函数,那基本上完成这个外设的driver也就成功了一多半,基于MTD的NAND driver就是一个典型的例子。稍后就可以看到,在NAND driver的probe函数中,就已经涉及到了对NAND芯片的读写。
?
在基于MTD的NAND driver的probe函数中,主要可以分为两部分内容,其一是与很多外设driver类似的一些工作,如申请地址,中断,DMA等资源,kzalloc及初始化一些结构体,分配DMA用的内存等等;其二就是与MTD相关的一

static int s3c24xx_nand_probe(struct platform_device *pdev)
{
??? /***获取平台数据信息return dev->dev.platform_data;**********/
?? ?struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
?? ?enum s3c_cpu_type cpu_type;
?? ?struct s3c2410_nand_info *info;//NANDFLASH控制器信息,在分析驱动源码的时候我发现了一个问题,好像每一个驱动程序都有一个这样类似的结构体,里面封装着各种与该驱动相关的信息**/
?? ?struct s3c2410_nand_mtd *nmtd;
?? ?struct s3c2410_nand_set *sets;
?? ?struct resource *res;
?? ?int err = 0;
?? ?int size;
?? ?int nr_sets;
?? ?int setno;
??? /*****获取芯片CPU类型唯一标识符**/
?? ?cpu_type = platform_get_device_id(pdev)->driver_data;

?? ?pr_debug("s3c2410_nand_probe(%p)n",pdev);

?? ?info = kzalloc(sizeof(*info),GFP_KERNEL);
?? ?if (info == NULL) {
?? ??? ?dev_err(&pdev->dev,"no memory for flash infon");
?? ??? ?err = -ENOMEM;
?? ??? ?goto exit_error;
?? ?}
??? /******把驱动相关的数据信息设置到内核里面*********/
?? ?platform_set_drvdata(pdev,info);
??? /**初始化硬件控制器控制结构**/
?? ?spin_lock_init(&info->controller.lock);/**初始化自旋锁**/
?? ?init_waitqueue_head(&info->controller.wq);//初始化等待队列

?? ?/* get the clock source and enable it */

?? ?info->clk = clk_get(&pdev->dev,"nand");/***获取时钟**/
?? ?if (IS_ERR(info->clk)) {
?? ??? ?dev_err(&pdev->dev,"failed to get clockn");
?? ??? ?err = -ENOENT;
?? ??? ?goto exit_error;
?? ?}

?? ?clk_enable(info->clk);//使能时钟

?? ?/* allocate and map the resource */
??? /****获取平台设备所需要的资源***在arch/arm/plat-samsung/dev-nand.c***********/
?? ?/* currently we assume we have the one resource */
?? ?res? = pdev->resource;
?? ?size = resource_size(res);//计算资源的大小
??? /**为平台设备资源分配空间**/
?? ?info->area = request_mem_region(res->start,size,pdev->name);

?? ?if (info->area == NULL) {
?? ??? ?dev_err(&pdev->dev,"cannot reserve register regionn");
?? ??? ?err = -ENOENT;
?? ??? ?goto exit_error;
?? ?}
??? /**填充s3c2410_nand_info结构***/
?? ?info->device???? = &pdev->dev;
?? ?info->platform?? = plat; /*保存 s3c2410_platform_nand结构信息*/
?? ?info->regs?????? = ioremap(res->start,size);/**映射IO**/
?? ?info->cpu_type?? = cpu_type;

?? ?if (info->regs == NULL) {
?? ??? ?dev_err(&pdev->dev,"cannot reserve register regionn");
?? ??? ?err = -EIO;
?? ??? ?goto exit_error;
?? ?}

?? ?dev_dbg(&pdev->dev,"mapped registers at %pn",info->regs);

?? ?/* initialise the hardware*/

?? ?err = s3c2410_nand_inithw(info);//硬件初始化 主要是配置NFCONF寄存器
?? ?if (err != 0)
?? ??? ?goto exit_error;

?? ?sets = (plat != NULL) ? plat->sets : NULL;
?? ?nr_sets = (plat != NULL) ? plat->nr_sets : 1;

?? ?info->mtd_count = nr_sets;

?? ?/* allocate our information */
??? /****分配MTD设备结构*****/
?? ?size = nr_sets * sizeof(*info->mtds);
?? ?info->mtds = kzalloc(size,GFP_KERNEL);
?? ?if (info->mtds == NULL) {
?? ??? ?dev_err(&pdev->dev,"failed to allocate mtd storagen");
?? ??? ?err = -ENOMEM;
?? ??? ?goto exit_error;
?? ?}

?? ?/* initialise all possible chips */
?? ?
?? ?nmtd = info->mtds;

?? ?for (setno = 0; setno < nr_sets; setno++,nmtd++) {
?? ??? ?pr_debug("initialising set %d (%p,info %p)n",setno,nmtd,info);
????? /***填充nand_chip结构**/
?? ??? ?s3c2410_nand_init_chip(info,sets);
??????? /**扫描nand芯片读取芯片ID等**/
?? ??? ?nmtd->scan_res = nand_scan_ident(&nmtd->mtd,
?? ??? ??? ??? ??? ??? ? (sets) ? sets->nr_chips : 1,
?? ??? ??? ??? ??? ??? ? NULL);

?? ??? ?if (nmtd->scan_res == 0) {
?? ??? ??? ?s3c2410_nand_update_chip(info,nmtd);
?? ??? ??? ?nand_scan_tail(&nmtd->mtd);
?? ??? ??? ?s3c2410_nand_add_partition(info,sets);
?? ??? ?}

?? ??? ?if (sets != NULL)
?? ??? ??? ?sets++;
?? ?}

?? ?err = s3c2410_nand_cpufreq_register(info);
?? ?if (err < 0) {
?? ??? ?dev_err(&pdev->dev,"failed to init cpufreq supportn");
?? ??? ?goto exit_error;
?? ?}

?? ?if (allow_clk_stop(info)) {
?? ??? ?dev_info(&pdev->dev,"clock idle support enabledn");
?? ??? ?clk_disable(info->clk);
?? ?}

?? ?pr_debug("initialised okn");
?? ?return 0;

?exit_error:
?? ?s3c24xx_nand_remove(pdev);

?? ?if (err == 0)
?? ??? ?err = -EINVAL;
?? ?return err;
}

static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,?? ??? ??? ??? ??? struct s3c2410_nand_mtd *nmtd,?? ??? ??? ??? ??? struct s3c2410_nand_set *set) { ?? ?struct nand_chip *chip = &nmtd->chip; ?? ?void __iomem *regs = info->regs; ?? ?chip->write_buf??? = s3c2410_nand_write_buf; ?? ?chip->read_buf???? = s3c2410_nand_read_buf; ?? ?chip->select_chip? = s3c2410_nand_select_chip; ?? ?chip->chip_delay?? = 50; ?? ?chip->priv?? ??? = nmtd; ?? ?chip->options?? ??? = set->options; ?? ?chip->controller?? = &info->controller; ?? ?switch (info->cpu_type) { ?? ?case TYPE_S3C2410: ?? ??? ?chip->IO_ADDR_W = regs + S3C2410_NFDATA; ?? ??? ?info->sel_reg?? = regs + S3C2410_NFCONF; ?? ??? ?info->sel_bit?? ?= S3C2410_NFCONF_nFCE; ?? ??? ?chip->cmd_ctrl? = s3c2410_nand_hwcontrol; ?? ??? ?chip->dev_ready = s3c2410_nand_devready; ?? ??? ?break; ?? ?case TYPE_S3C2440: ?? ??? ?chip->IO_ADDR_W = regs + S3C2440_NFDATA; ?? ??? ?info->sel_reg?? = regs + S3C2440_NFCONT; ?? ??? ?info->sel_bit?? ?= S3C2440_NFCONT_nFCE; ?? ??? ?chip->cmd_ctrl? = s3c2440_nand_hwcontrol; ?? ??? ?chip->dev_ready = s3c2440_nand_devready; ?? ??? ?chip->read_buf? = s3c2440_nand_read_buf; ?? ??? ?chip->write_buf?? ?= s3c2440_nand_write_buf; ?? ??? ?break; ?? ?case TYPE_S3C2412: ?? ??? ?chip->IO_ADDR_W = regs + S3C2440_NFDATA; ?? ??? ?info->sel_reg?? = regs + S3C2440_NFCONT; ?? ??? ?info->sel_bit?? ?= S3C2412_NFCONT_nFCE0; ?? ??? ?chip->cmd_ctrl? = s3c2440_nand_hwcontrol; ?? ??? ?chip->dev_ready = s3c2412_nand_devready; ?? ??? ?if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT) ?? ??? ??? ?dev_info(info->device,"System booted from NANDn"); ?? ??? ?break; ? ?? ?} ?? ?chip->IO_ADDR_R = chip->IO_ADDR_W; ?? ?nmtd->info?? ??? = info; ?? ?nmtd->mtd.priv?? ??? = chip; ?? ?nmtd->mtd.owner??? = THIS_MODULE; ?? ?nmtd->set?? ??? = set; ?? ?if (hardware_ecc) { ?? ??? ?chip->ecc.calculate = s3c2410_nand_calculate_ecc; ?? ??? ?chip->ecc.correct?? = s3c2410_nand_correct_data; ?? ??? ?chip->ecc.mode?? ???? = NAND_ECC_HW; ?? ??? ?switch (info->cpu_type) { ?? ??? ?case TYPE_S3C2410: ?? ??? ??? ?chip->ecc.hwctl?? ???? = s3c2410_nand_enable_hwecc; ?? ??? ??? ?chip->ecc.calculate = s3c2410_nand_calculate_ecc; ?? ??? ??? ?break; ?? ??? ?case TYPE_S3C2412: ? ?? ??? ??? ?chip->ecc.hwctl???? = s3c2412_nand_enable_hwecc; ? ?? ??? ??? ?chip->ecc.calculate = s3c2412_nand_calculate_ecc; ?? ??? ??? ?break; ?? ??? ?case TYPE_S3C2440: ? ?? ??? ??? ?chip->ecc.hwctl???? = s3c2440_nand_enable_hwecc; ? ?? ??? ??? ?chip->ecc.calculate = s3c2440_nand_calculate_ecc; ?? ??? ??? ?break; ?? ??? ?} ?? ?} else { ?? ??? ?chip->ecc.mode?? ???? = NAND_ECC_SOFT; ?? ?} ?? ?if (set->ecc_layout != NULL) ?? ??? ?chip->ecc.layout = set->ecc_layout; ?? ?if (set->disable_ecc) ?? ??? ?chip->ecc.mode?? ?= NAND_ECC_NONE; ?? ?switch (chip->ecc.mode) { ?? ?case NAND_ECC_NONE: ?? ??? ?dev_info(info->device,"NAND ECC disabledn"); ?? ??? ?break; ?? ?case NAND_ECC_SOFT: ?? ??? ?dev_info(info->device,"NAND soft ECCn"); ?? ??? ?break; ?? ?case NAND_ECC_HW: ?? ??? ?dev_info(info->device,"NAND hardware ECCn"); ?? ??? ?break; ?? ?default: ?? ??? ?dev_info(info->device,"NAND ECC UNKNOWNn"); ?? ??? ?break; ?? ?} ?? ?/* If you use u-boot BBT creation code,specifying this flag will ?? ? * let the kernel fish out the BBT from the NAND,and also skip the ?? ? * full NAND scan that can take 1/2s or so. Little things... */ ?? ?if (set->flash_bbt) ?? ??? ?chip->options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读