MTD系统架构和yaffs2使用、Nandflash驱动设计
来源:互联网 发布:手机淘宝抠图 编辑:程序博客网 时间:2024/06/05 16:46
一、MTD系统架构
1.MTD设备体验
FLASH在嵌入式系统中是必不可少的,它是bootloader、linux内核和文件系统的最佳载体。
在Linux内核中引入了MTD子系统为NORFLASH和NAND FLASH设备提供统一的接口,从而使得FLASH驱动的设计大为简化。
- cat /proc/mtd
- ls -l /dev/mtd*
- crw-rw---- 1 0 0 90, 0 Jan 1 00:00 /dev/mtd0
- crw-rw---- 1 0 0 90, 1 Jan 1 00:00 /dev/mtd0ro
- crw-rw---- 1 0 0 90, 2 Jan 1 00:00 /dev/mtd1
- crw-rw---- 1 0 0 90, 3 Jan 1 00:00 /dev/mtd1ro
- crw-rw---- 1 0 0 90, 4 Jan 1 00:00 /dev/mtd2
- crw-rw---- 1 0 0 90, 5 Jan 1 00:00 /dev/mtd2ro
- brw-rw---- 1 0 0 31, 0 Jan 1 00:00 /dev/mtdblock0
- brw-rw---- 1 0 0 31, 1 Jan 1 00:00 /dev/mtdblock1
- brw-rw---- 1 0 0 31, 2 Jan 1 00:00 /dev/mtdblock2
2.块设备驱动系统架构
二、YAFFS2文件系统应用
1.MTD分区设置
配置linux内核支持mtd,找到mtd接口文件,设置空间大小。
2.Yaffs2文件系统制作
将rootfs格式化生成yaffs文件系统。
- /home/win/mkyaffs2image ./rootfs/ rootfs.img
3.Uboot参数设置
在uboot_tq2440\include\configs\TQ2440.h中有uboot的启动配置选项
- #define CONFIG_BZIP2
- #define CONFIG_LZO
- #define CONFIG_LZMA
- #define CONFIG_CMD_NAND_YAFFS
- #define CONFIG_BOOTARGS "console=ttySAC0 root=/dev/mtdblock3"
- #define CONFIG_BOOTCOMMAND "nand read 0x30000000 kernel;bootm 0x30000000"
4.下载烧写与启动
在uboot中用dnw下载
三、Nandflash驱动设计
s3c2410.c/s3c24xx_nand_probe:
- static int s3c24xx_nand_probe(struct platform_device *pdev,
- enum s3c_cpu_type cpu_type)
- {
- struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
- 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", pdev);
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (info == NULL) {
- dev_err(&pdev->dev, "no memory for flash info\n");
- err = -ENOMEM;
- goto exit_error;
- }
- memset(info, 0, sizeof(*info));
- 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 clock\n");
- err = -ENOENT;
- goto exit_error;
- }
- clk_enable(info->clk);
- /* allocate and map the resource */
- /* currently we assume we have the one resource */
- res = pdev->resource;
- size = res->end - res->start + 1;
- info->area = request_mem_region(res->start, size, pdev->name); //地址转换
- if (info->area == NULL) {
- dev_err(&pdev->dev, "cannot reserve register region\n");
- err = -ENOENT;
- goto exit_error;
- }
- info->device = &pdev->dev;
- info->platform = plat;
- info->regs = ioremap(res->start, size);
- info->cpu_type = cpu_type;
- if (info->regs == NULL) {
- dev_err(&pdev->dev, "cannot reserve register region\n");
- err = -EIO;
- goto exit_error;
- }
- dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs);
- /* initialise the hardware */
- err = s3c2410_nand_inithw(info); //初始化硬件
- 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 */
- size = nr_sets * sizeof(*info->mtds);
- info->mtds = kmalloc(size, GFP_KERNEL);
- if (info->mtds == NULL) {
- dev_err(&pdev->dev, "failed to allocate mtd storage\n");
- err = -ENOMEM;
- goto exit_error;
- }
- memset(info->mtds, 0, 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); //里面有校验nandflash
- nmtd->scan_res = nand_scan_ident(&nmtd->mtd, //搜索nandflash
- (sets) ? sets->nr_chips : 1);
- if (nmtd->scan_res == 0) {
- s3c2410_nand_update_chip(info, nmtd);
- nand_scan_tail(&nmtd->mtd);
- s3c2410_nand_add_partition(info, nmtd, sets); //注册分区信息
- }
- if (sets != NULL)
- sets++;
- }
- err = s3c2410_nand_cpufreq_register(info);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to init cpufreq support\n");
- goto exit_error;
- }
- if (allow_clk_stop(info)) {
- dev_info(&pdev->dev, "clock idle support enabled\n");
- clk_disable(info->clk);
- }
- pr_debug("initialised ok\n");
- return 0;
- exit_error:
- s3c2410_nand_remove(pdev);
- if (err == 0)
- err = -EINVAL;
- return err;
- }
- static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, uint8_t *buf)
- {
- struct nand_chip *chip = mtd->priv;
- int ret;
- /* Do not allow reads past end of device */
- if ((from + len) > mtd->size)
- return -EINVAL;
- if (!len)
- return 0;
- nand_get_device(chip, mtd, FL_READING);
- chip->ops.len = len;
- chip->ops.datbuf = buf;
- chip->ops.oobbuf = NULL;
- ret = nand_do_read_ops(mtd, from, &chip->ops); //进行读操作的代码
- *retlen = chip->ops.retlen;
- nand_release_device(mtd);
- return ret;
- }
- /**
- * nand_do_read_ops - [Internal] Read data with ECC
- *
- * @mtd: MTD device structure
- * @from: offset to read from
- * @ops: oob ops structure
- *
- * Internal function. Called with chip held.
- */
- static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
- struct mtd_oob_ops *ops)
- {
- int chipnr, page, realpage, col, bytes, aligned;
- struct nand_chip *chip = mtd->priv;
- struct mtd_ecc_stats stats;
- int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
- int sndcmd = 1;
- int ret = 0;
- uint32_t readlen = ops->len;
- uint32_t oobreadlen = ops->ooblen;
- uint8_t *bufpoi, *oob, *buf;
- stats = mtd->ecc_stats;
- chipnr = (int)(from >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
- realpage = (int)(from >> chip->page_shift);
- page = realpage & chip->pagemask;
- col = (int)(from & (mtd->writesize - 1));
- buf = ops->datbuf;
- oob = ops->oobbuf;
- while(1) {
- bytes = min(mtd->writesize - col, readlen);
- aligned = (bytes == mtd->writesize);
- /* Is the current page in the buffer ? */
- if (realpage != chip->pagebuf || oob) {
- bufpoi = aligned ? buf : chip->buffers->databuf;
- if (likely(sndcmd)) {
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); //实际对应了nand_command_lp,cmd命令是0
- sndcmd = 0;
- }
- .........
- }
- static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
- int column, int page_addr)
- {
- register struct nand_chip *chip = mtd->priv;
- /* Emulate NAND_CMD_READOOB */
- if (command == NAND_CMD_READOOB) {
- column += mtd->writesize;
- command = NAND_CMD_READ0;
- }
- /* Command latch cycle */
- chip->cmd_ctrl(mtd, command & 0xff,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); //cmd_ctrl来源于底层驱动,在s3c2410_nand_init_chip中赋值了。
- .......
- }
- /* s3c2410_nand_hwcontrol
- *
- * Issue command and address cycles to the chip
- */
- static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
- unsigned int ctrl)
- {
- struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
- if (cmd == NAND_CMD_NONE)
- return;
- if (ctrl & NAND_CLE)
- writeb(cmd, info->regs + S3C2410_NFCMD); //往NFCONT寄存器中写入cmd,cmd来自于nand_command,往上回溯为nand_read.其实就是发送了命令0x00
- else
- writeb(cmd, info->regs + S3C2410_NFADDR);
- }
- ...............
- if (column != -1 || page_addr != -1) {
- int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (chip->options & NAND_BUSWIDTH_16)
- column >>= 1;
- chip->cmd_ctrl(mtd, column, ctrl); //紧接着发送列地址
- ctrl &= ~NAND_CTRL_CHANGE;
- chip->cmd_ctrl(mtd, column >> 8, ctrl);
- }
- if (page_addr != -1) {
- chip->cmd_ctrl(mtd, page_addr, ctrl); //发送行地址
- chip->cmd_ctrl(mtd, page_addr >> 8,
- NAND_NCE | NAND_ALE);
- /* One more address cycle for devices > 128MiB */
- if (chip->chipsize > (128 << 20))
- chip->cmd_ctrl(mtd, page_addr >> 16,
- NAND_NCE | NAND_ALE);
- }
- }
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
- /*
- * program and erase have their own busy handlers
- * status, sequential in, and deplete1 need no delay
- */
- switch (command) {
- case NAND_CMD_CACHEDPROG:
- case NAND_CMD_PAGEPROG:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_SEQIN:
- case NAND_CMD_RNDIN:
- case NAND_CMD_STATUS:
- case NAND_CMD_DEPLETE1:
- return;
- /*
- * read error status commands require only a short delay
- */
- case NAND_CMD_STATUS_ERROR:
- case NAND_CMD_STATUS_ERROR0:
- case NAND_CMD_STATUS_ERROR1:
- case NAND_CMD_STATUS_ERROR2:
- case NAND_CMD_STATUS_ERROR3:
- udelay(chip->chip_delay);
- return;
- case NAND_CMD_RESET:
- if (chip->dev_ready)
- break;
- udelay(chip->chip_delay);
- chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE,
- NAND_NCE | NAND_CTRL_CHANGE);
- while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
- return;
- case NAND_CMD_RNDOUT:
- /* No ready / busy check necessary */
- chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE,
- NAND_NCE | NAND_CTRL_CHANGE);
- return;
- case NAND_CMD_READ0:
- chip->cmd_ctrl(mtd, NAND_CMD_READSTART, //这里发送了0x30命令
- NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE,
- NAND_NCE | NAND_CTRL_CHANGE);
- /* This applies to read commands */
- default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay
- */
- if (!chip->dev_ready) {
- udelay(chip->chip_delay);
- return;
- }
- }
- /* Apply this short delay always to ensure that we do wait tWB in
- * any case on any machine. */
- ndelay(100);
- nand_wait_ready(mtd); //wait等待
- }
0
上一篇:块设备驱动系统架构和简单设计
下一篇:I2C学习
相关热门文章
- SHTML是什么_SSI有什么用...
- 查看linux中某个端口(port)...
- 卡尔曼滤波的原理说明...
- shell中字符串操作
- 关于java中的“错误:找不到或...
给主人留下些什么吧!~~
评论热议
阅读全文
0 0
- MTD系统架构和yaffs2使用、Nandflash驱动设计
- mtd,nandflash驱动知识
- Linux-Flash驱动(4)-MTD系统架构
- s5pv210开发板linux mtd驱动 Nandflash
- MTD NANDFLASH驱动相关知识介绍
- MTD NANDFLASH驱动相关知识介绍
- MTD NANDFLASH驱动相关知识介绍
- nandflash驱动设计
- NandFlash驱动设计
- tiny6410 nandflash驱动设计
- linux驱动移植(nand,yaffs2) MTD分区
- NandFLASH和NorFLASH接口设计和驱动开发 (转)
- MTD原始设备与NANDFLASH硬件驱动交互
- 基于MTD的NANDFLASH设备驱动底层实现原理分析
- 基于MTD的NANDFLASH设备驱动底层实现原理分析 .
- 学习笔记 --- LINUX MTD设备之NANDFLASH驱动分析
- nandflash驱动之添加MTD设备与测试
- 块设备驱动系统架构和简单设计
- 输入子系统模型解析和原理分析
- drawerlayout侧滑
- 触摸屏驱动分析和编程
- LCD驱动程序架构和分析
- 块设备驱动系统架构和简单设计
- MTD系统架构和yaffs2使用、Nandflash驱动设计
- I2C学习
- 蓝牙搜索
- I2C用户态驱动设计
- SpringBoot的热部署
- I2C自编设备驱动设计
- crontab执行shell脚本和直接运行的结果不一样
- SPI总线介绍和裸机编程分析
- SPI子系统
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
陇西 漳县
漳县人事网
漳县二手房
漳县人事局
漳县二中吧
漳县西安大酒店
漳县贵清山酒店
漳县属于哪个市
定西漳县房价
漳县遮阳山天华度假村
漳县公路管理段
甘肃漳县天紫大酒店
甘肃漳县招聘
漳县人力资源和社会保障厅
漳平
漳泽电力
000767漳泽电力
漳州立人学校
漳怎么读
山西漳泽电力电子商务系统
漳泽电力股票
开漳圣王
漳泽电力电子商务平台
龙岩漳平
福建漳平
漳泽水库
漳平水仙茶属于什么茶
漳大是什么学校
漳大
漳州
漳州龙海
漳州漳浦
漳州诏安
漳州火山岛
漳州人才网
漳州旅游
漳州市
漳州景点
福建漳州
漳州事业
漳州人才