注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

Linux MTD子系统学习5—s3c24xx_nand_probe()函数之三  

2012-01-06 21:56:16|  分类: LINUX内核驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

Linux MTD子系统学习5—s3c24xx_nand_probe()函数之三

接着讲s3c24xx_nand_probe()这个函数,这个函数是相当的YD的,所以童鞋们真得不能着急,慢慢来。好,下面讲info->mtds = kmalloc(size, GFP_KERNEL);这行代码只要学过C语言的,知道一点点内核的都知道,这个是为mtds分配内存空间,这个结构体如下:

struct s3c2410_nand_mtd {

         struct mtd_info                           mtd;

         struct nand_chip               chip;

         struct s3c2410_nand_set                 *set;

         struct s3c2410_nand_info       *info;

         int                                scan_res;

};

后面还有一行代码把赋值给了nmtd,即:

nmtd = info->mtds;

看下面两行代码:

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

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

其中struct s3c2410_platform_nand *plat = to_nand_plat(pdev);后面的函数只是返回

static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)

{

         return dev->dev.platform_data;

}

而return的部分,就是在s3c_device_nand.dev.platform_data = &smdk_nand_info;这里赋值的,具体见下面的注解内容。大家可自己去查看,结合着“学习4”。

(注:代码和上“学习4”中末尾一样,在arch\arm\palt-sm3c24xx\common-smdk.c这个文件中的函数:void __init smdk_machine_init(void)中)

因为知道plat并不为NULL ,所以sets=plat->sets;关键是后面这句话,其实是这个意思,即:数量最少为1,否则即为plat->nr_sets(其实这个也为1,所以这里数量就是1)。关键仍然在上面的括号的注解内容中。

 

s3c2410_nand_init_chip(info, nmtd, sets);一些基本量的赋值。这个很重要。

/**

 * s3c2410_nand_init_chip - initialise a single instance of an chip

 * @info: The base NAND controller the chip is on.

 * @nmtd: The new controller MTD instance to fill in.

 * @set: The information passed from the board specific platform data.

 *

 * Initialise the given @nmtd from the information in @info and @set. This

 * readies the structure for use with the MTD layer functions by ensuring

 * all pointers are setup and the necessary control routines selected.

 */

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      = 0;

         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 NAND\n");

 

                   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 disabled\n");

                   break;

         case NAND_ECC_SOFT:

                   dev_info(info->device, "NAND soft ECC\n");

                   break;

         case NAND_ECC_HW:

                   dev_info(info->device, "NAND hardware ECC\n");

                   break;

         default:

                   dev_info(info->device, "NAND ECC UNKNOWN\n");

                   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;

}

//注意:下面还是引用了网友的资料,再次感谢。

从writebuf到controller是对chip初始化.这些值用到的时候我们再来说.我会时时提醒你.

而IO_ADDR_W 写地址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;

NFCONT有这么样一个位:

 

 

 

 

Linux MTD子系统学习5—s3c24xx_nand_probe()函数之三 - 还东国 - 还东国的博客

 

为0表示Enable chip select

s3c2410_nand_select_chip中我们会用上的.待得瞧.

回来看s3c2410_nand_init_chip:

chip->IO_ADDR_R = chip->IO_ADDR_W;

 

nmtd->info    = info;

nmtd->mtd.priv       = chip;

nmtd->mtd.owner    = THIS_MODULE;

nmtd->set    = set;

读地址与写地址是一样.

而从819行也就是if (hardware_ecc)判断开始,就是ECC的处理了,不要告诉我你不知道啥叫ECC,那你就回去好好查一下资料。

 

static int hardware_ecc = 1;表示要ECC.什么是ECC:就是对数据的保护.数据传送有没有出错.ECC有两种.一种是通过软件计算出的.一种是通过硬件算出来的.拿S3C2440来说它的ECC是硬件算出来的.怎么算????当写数据时:例如写512个数据到NAND中,当512写完以后ECC就会被算出,放在NFMCCD0-NFMCCD2中.这个过程是全自动的.

 Linux MTD子系统学习5—s3c24xx_nand_probe()函数之三 - 还东国 - 还东国的博客

 Linux MTD子系统学习5—s3c24xx_nand_probe()函数之三 - 还东国 - 还东国的博客

但有人就会问生成以后呢.??有没有注意到上面.拿512来说其实 1 page=528

多了16个.ECC就是放在这16个当中的.

NAND_ECC_SOFT表示软件生成ECC.

set->disable_ecc如果为1就表示是hi ECC你不用检测了..

我们顺便把s3c2410_nand_calculate_ecc也看了.

static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)

{

    struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);

 

    ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);

    ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);

    ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);

 

    pr_debug("%s: returning ecc %02x%02x%02x\n", __func__,

        ecc_code[0], ecc_code[1], ecc_code[2]);

 

    return 0;

}

这个函数就是读一下ECC寄存器.

s3c2410_nand_init_chip就这样完了.但chip还没有完.回s3c24xx_nand_probe中来

今天讲到这里,其实出现了一个问题,目前知道了驱动,但设备的注册呢,怎么办,所以下一章插入device的注册和操作流程以及与driver的联系。

最后一句话:由糊涂而清楚,由清楚再糊涂,如此往复,自然明白。

  评论这张
 
阅读(1072)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017