一、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_tq2440includeconfigsTQ2440.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 infon");
- 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 clockn");
- 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 regionn");
- 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 regionn");
- err = –EIO;
- goto exit_error;
- }
- dev_dbg(&pdev–>dev, "mapped registers at %pn", 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 storagen");
- 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 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:
- s3c2410_nand_remove(pdev);
- if (err == 0)
- err = –EINVAL;
- return err;
- }
MTD通用驱动部分nand_base.c(nand_read:
- 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:
- /**
- * 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;
- }
- ………
- }
nand_command_lp:
- 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:
- /* 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);
- }
继续回到nand_command_lp:
- ……………
- 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等待
- }
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script> 阅读(38) | 评论(0) | 转发(0) |
0
上一篇:块设备驱动系统架构和简单设计
下一篇:I2C学习
相关热门文章
- SHTML是什么_SSI有什么用…
- 查看linux中某个端口(port)…
- 卡尔曼滤波的原理说明…
- shell中字符串操作
- 关于java中的“错误:找不到或…
给主人留下些什么吧!~~ 评论热议