MTD原始设备与FLASH硬件驱动的对话_luofuchong

  • 格式:pdf
  • 大小:208.24 KB
  • 文档页数:47

MTD原始设备与FLASH硬件驱动的对话luofuchong看了<<Linux MTD源代码分析>>后对以MTD的分层结构以及各层的分工情况有了大致的了解,然而各层之间是如何进行对话的呢,对于这个问题,<<Linux MTD源代码分析>>上没有详细的去说明。

小弟抽空研究了一下,打算从下到上,在从上到下,分两条主线来研究一下MTD原始设备与FLASH硬件驱动的对话(MTD原始设备与更上层的对话留待以后再研究)。

以下是第一部分,从下到上的介绍FLASH硬件驱动与MTD原始设备是如何建立联系的。

1、首先从入口函数开始:static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440){struct platform_device *pdev = to_platform_device(dev);struct s3c2410_platform_nand *plat = to_nand_plat(dev);//获取nand flash配置用结构体数据(dev.c中定义,详细见附录部分)struct s3c2410_nand_info *info;struct s3c2410_nand_mtd *nmtd;struct s3c2410_nand_set *sets;struct resource *res;int err = 0;int size;int nr_sets;int setno;pr_debug("s3c2410_nand_probe(%p)\n", dev);info = kmalloc(sizeof(*info), GFP_KERNEL);if (info == NULL) {printk(KERN_ERR PFX "no memory for flash info\n");err = -ENOMEM;goto exit_error;}memzero(info, sizeof(*info));dev_set_drvdata(dev, info); //以后有用spin_lock_init(&info->controller.lock); //初始化自旋锁init_waitqueue_head(&info->controller.wq); //初始化等待队列/* get the clock source and enable it */info->clk = clk_get(dev, "nand");if (IS_ERR(info->clk)) {printk(KERN_ERR PFX "failed to get clock");err = -ENOENT;goto exit_error;}clk_use(info->clk);clk_enable(info->clk);/* allocate and map the resource *//* currently we assume we have the one resource */res = pdev->resource; //提取dev.c中定义的与设备相关的资源size = res->end - res->start + 1;info->area = request_mem_region(res->start, size, pdev->name);if (info->area == NULL) {printk(KERN_ERR PFX "cannot reserve register region\n");err = -ENOENT;goto exit_error;}info->device = dev;info->platform = plat; //保存好struct s3c2410_platform_nand 结构数据info->regs = ioremap(res->start, size);//映射nand flash用到的寄存器info->is_s3c2440 = is_s3c2440;if (info->regs == NULL) {printk(KERN_ERR PFX "cannot reserve register region\n");err = -EIO;goto exit_error;}printk(KERN_INFO PFX "mapped registers at %p\n", info->regs);/* initialise the hardware */err = s3c2410_nand_inithw(info, dev);//初始化s3c2410 nand flash控制,主要是配置S3C2410_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;//我的板上只有一块nand flash,配置信息见plat-sets,数目为1。

/* allocate our information */size = nr_sets * sizeof(*info->mtds);info->mtds = kmalloc(size, GFP_KERNEL);if (info->mtds == NULL) {printk(KERN_ERR PFX "failed to allocate mtd storage\n");err = -ENOMEM;goto exit_error;}memzero(info->mtds, size);/* 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);s3c2410_nand_init_chip(info, nmtd, sets);nmtd->scan_res = nand_scan(&nmtd->mtd,(sets) ? sets->nr_chips : 1);//为什么使用set->nr_chips(还没配置的东西)?if (nmtd->scan_res == 0) {s3c2410_nand_add_partition(info, nmtd, sets);}if (sets != NULL)sets++;}pr_debug("initialised ok\n");return 0;exit_error:s3c2410_nand_remove(dev);if (err == 0)err = -EINVAL;return err;}//初始化代表一片flash的struct nand_chip结构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;chip->IO_ADDR_R = info->regs + S3C2410_NFDATA; //读地址chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; //写地址chip->hwcontrol = s3c2410_nand_hwcontrol;chip->dev_ready = s3c2410_nand_devready; //ready状态查询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;if (info->is_s3c2440) {chip->IO_ADDR_R = info->regs + S3C2440_NFDATA;chip->IO_ADDR_W = info->regs + S3C2440_NFDATA;chip->hwcontrol = s3c2440_nand_hwcontrol;}nmtd->info = info;nmtd->mtd.priv = chip;//nand_scan函数中会调用struct nand_chip *this = mtd->priv取出该struct nand_chip结构nmtd->set = set;if (hardware_ecc) {chip->correct_data = s3c2410_nand_correct_data;chip->enable_hwecc = s3c2410_nand_enable_hwecc;chip->calculate_ecc = s3c2410_nand_calculate_ecc;chip->eccmode = NAND_ECC_HW3_512;chip->autooob = &nand_hw_eccoob;if (info->is_s3c2440) {chip->enable_hwecc = s3c2440_nand_enable_hwecc;chip->calculate_ecc = s3c2440_nand_calculate_ecc;}} else {chip->eccmode = NAND_ECC_SOFT; //ECC的类型}}/* command and control functions** Note, these all use tglx's method of changing the IO_ADDR_W field * to make the code simpler, and use the nand layer's code to issue the * command and address sequences via the proper IO ports.**/static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) {struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);struct nand_chip *chip = mtd->priv;switch (cmd) {case NAND_CTL_SETNCE:case NAND_CTL_CLRNCE:printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__);break;case NAND_CTL_SETCLE:chip->IO_ADDR_W = info->regs + S3C2410_NFCMD;//写命令break;case NAND_CTL_SETALE:chip->IO_ADDR_W = info->regs + S3C2410_NFADDR;//写地址break;/* NAND_CTL_CLRCLE: *//* NAND_CTL_CLRALE: */default:chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;//写数据break;}}/* s3c2410_nand_devready()** returns 0 if the nand is busy, 1 if it is ready*/static int s3c2410_nand_devready(struct mtd_info *mtd){struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);if (info->is_s3c2440)return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;//返回nand flash都忙标志}static void s3c2410_nand_write_buf(struct mtd_info *mtd,const u_char *buf, int len){struct nand_chip *this = mtd->priv;writesb(this->IO_ADDR_W, buf, len);//写操作}static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) {struct nand_chip *this = mtd->priv;readsb(this->IO_ADDR_R, buf, len);//读操作}/* select chip *//** 根据chip都值设置nand flash都片选信号:* chip = -1 -- 禁用nand flash* chip !=-1 -- 选择对应的nand flash*/static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip){struct s3c2410_nand_info *info;struct s3c2410_nand_mtd *nmtd;struct nand_chip *this = mtd->priv;void __iomem *reg;unsigned long cur;unsigned long bit;nmtd = this->priv;info = nmtd->info;bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;reg = info->regs+((info->is_s3c2440) ? S3C2440_NFCONT:S3C2410_NFCONF);cur = readl(reg);if (chip == -1) {cur |= bit;} else {if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {printk(KERN_ERR PFX "chip %d out of range\n", chip);return;}if (info->platform != NULL) {if (info->platform->select_chip != NULL)(info->platform->select_chip)(nmtd->set, chip);}cur &= ~bit;}writel(cur, reg);}注:s3c2410_nand_init_chip填充struct nand_chip的一部分成员,nand_scan以通用nand flash的标准进行检测,并填充struct nand_chip的其它成员,必要时根据检测结果进行取舍。