色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > NAND FLASH驅(qū)動(dòng)程序

          NAND FLASH驅(qū)動(dòng)程序

          作者: 時(shí)間:2016-11-21 來源:網(wǎng)絡(luò) 收藏
          // 參考
          * driversmtdnands3c2410.c
          * driversmtdnandat91_nand.c
          //
          #include "linux/module.h"
          #include "linux/types.h"
          #include "linux/init.h"
          #include "linux/kernel.h"
          #include "linux/string.h"
          #include "linux/ioport.h"
          #include "linux/platform_device.h
          #include "linux/delay.h"
          #include "linux/err.h"
          #include "linux/slab.h"
          #include "linux/clk.h"
          #include "linux/mtd/mtd.h"
          #include "linux/mtd/nand.h"
          #include "linux/mtd/nand_ecc.h"
          #include "linux/mtd/partitions.h"
          #include "asm/io.h"
          #include "asm/arch/regs-nand.h"
          #include "asm/arch/nand.h"
          struct s3c_nand_regs {
          unsigned long nfconf ;
          unsigned long nfcont ;
          unsigned long nfcmd ;
          unsigned long nfaddr ;
          unsigned long nfdata ;
          unsigned long nfeccd0 ;
          unsigned long nfeccd1 ;
          unsigned long nfeccd ;
          unsigned long nfstat ;
          unsigned long nfestat0;
          unsigned long nfestat1;
          unsigned long nfmecc0 ;
          unsigned long nfmecc1 ;
          unsigned long nfsecc ;
          unsigned long nfsblk ;
          unsigned long nfeblk ;
          };
          static struct nand_chip *s3c_nand;
          static struct mtd_info *s3c_mtd;
          static struct s3c_nand_regs *s3c_nand_regs;
          static struct mtd_partition s3c_nand_parts[] = {
          [0] = {
          .name = "bootloader",
          .size = 0x00040000,
          .offset = 0,
          },
          [1] = {
          .name = "params",
          .offset = MTDPART_OFS_APPEND, //緊跟著上一個(gè)分區(qū)
          .size = 0x00020000,
          },
          [2] = {
          .name = "kernel",
          .offset = MTDPART_OFS_APPEND,
          .size = 0x00200000,
          },
          [3] = {
          .name = "root",
          .offset = MTDPART_OFS_APPEND,
          .size = MTDPART_SIZ_FULL, //剩下的所有空間都是"root"分區(qū)
          }
          };
          static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)
          {
          if (chipnr == -1)
          {
          //取消選中: NFCONT[1]設(shè)為1
          s3c_nand_regs->nfcont |= (1<<1);
          }
          else
          {
          // 選中: NFCONT[1]設(shè)為0
          s3c_nand_regs->nfcont &= ~(1<<1);
          }
          }
          static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
          {
          if (ctrl & NAND_CLE)
          {
          // 發(fā)命令: NFCMMD=dat
          s3c_nand_regs->nfcmd = dat;
          }
          else
          {
          // 發(fā)地址: NFADDR=dat
          s3c_nand_regs->nfaddr = dat;
          }
          }
          static int s3c2440_dev_ready(struct mtd_info *mtd)
          {
          return (s3c_nand_regs->nfstat & (1<<0));
          }
          static int s3c_nand_init(void)
          {
          struct clk *clk;
          // 1. 分配一個(gè)nand_chip結(jié)構(gòu)體
          s3c_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
          s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs));
          // 2. 設(shè)置nand_chip */
          / 設(shè)置nand_chip是給nand_scan函數(shù)使用的, 如果不知道怎么設(shè)置, 先看nand_scan怎么使用
          / 它應(yīng)該提供:選中,發(fā)命令,發(fā)地址,發(fā)數(shù)據(jù),讀數(shù)據(jù),判斷狀態(tài)的功能
          //
          s3c_nand->select_chip = s3c2440_select_chip;
          s3c_nand->cmd_ctrl = s3c2440_cmd_ctrl;
          s3c_nand->IO_ADDR_R = &s3c_nand_regs->nfdata;
          s3c_nand->IO_ADDR_W = &s3c_nand_regs->nfdata;
          s3c_nand->dev_ready = s3c2440_dev_ready;
          s3c_nand->ecc.mode = NAND_ECC_SOFT;
          // 3. 硬件相關(guān)的設(shè)置: 根據(jù)NAND FLASH的手冊(cè)設(shè)置時(shí)間參數(shù)
          // 使能NAND FLASH控制器的時(shí)鐘
          clk = clk_get(NULL, "nand");
          clk_enable(clk);
          // HCLK=100MHz
          * TACLS: 發(fā)出CLE/ALE之后多長(zhǎng)時(shí)間才發(fā)出nWE信號(hào), 從NAND手冊(cè)可知CLE/ALE與nWE可以同時(shí)發(fā)出,所以TACLS=0
          * TWRPH0: nWE的脈沖寬度, HCLK x ( TWRPH0 + 1 ), 從NAND手冊(cè)可知它要>=12ns, 所以TWRPH0>=1
          * TWRPH1: nWE變?yōu)楦唠娖胶蠖嚅L(zhǎng)時(shí)間CLE/ALE才能變?yōu)榈碗娖? 從NAND手冊(cè)可知它要>=5ns, 所以TWRPH1>=0
          //
          #define TACLS 0
          #define TWRPH0 1
          #define TWRPH1 0
          s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
          // NFCONT:
          * BIT1-設(shè)為1, 取消片選
          * BIT0-設(shè)為1, 使能NAND FLASH控制器
          //
          s3c_nand_regs->nfcont = (1<<1) | (1<<0);
          // 4. 使用: nand_scan
          s3c_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
          s3c_mtd->owner = THIS_MODULE;
          s3c_mtd->priv = s3c_nand;
          nand_scan(s3c_mtd, 1); // 識(shí)別NAND FLASH, 構(gòu)造mtd_info ,最大芯片個(gè)數(shù)1
          // 5. add_mtd_partitions
          add_mtd_partitions(s3c_mtd, s3c_nand_parts, 4); //分區(qū)數(shù)4
          //add_mtd_device(s3c_mtd); //整個(gè)nand flash 作為一個(gè)分區(qū)使用
          return 0;
          }
          static void s3c_nand_exit(void)
          {
          del_mtd_partitions(s3c_mtd);
          kfree(s3c_mtd);
          iounmap(s3c_nand_regs);
          kfree(s3c_nand);
          }
          module_init(s3c_nand_init);
          module_exit(s3c_nand_exit);
          MODULE_LICENSE("GPL");
          =================================================================
          NAND FLASH是一個(gè)存儲(chǔ)芯片
          那么: 這樣的操作很合理"讀地址A的數(shù)據(jù),把數(shù)據(jù)B寫到地址A"
          問1. 原理圖上NAND FLASH和S3C2440之間只有數(shù)據(jù)線,
          怎么傳輸?shù)刂罚?/div>
          答1.在DATA0~DATA7上既傳輸數(shù)據(jù),又傳輸?shù)刂?/div>
          當(dāng)ALE為高電平時(shí)傳輸?shù)氖堑刂罚?/div>
          問2. 從NAND FLASH芯片手冊(cè)可知,要操作NAND FLASH需要先發(fā)出命令
          怎么傳入命令?
          答2.在DATA0~DATA7上既傳輸數(shù)據(jù),又傳輸?shù)刂罚矀鬏斆?/div>
          當(dāng)ALE為高電平時(shí)傳輸?shù)氖堑刂罚?/div>
          當(dāng)CLE為高電平時(shí)傳輸?shù)氖敲?/div>
          當(dāng)ALE和CLE都為低電平時(shí)傳輸?shù)氖菙?shù)據(jù)
          問3. 數(shù)據(jù)線既接到NAND FLASH,也接到NOR FLASH,還接到SDRAM、DM9000等等
          那么怎么避免干擾?
          答3. 這些設(shè)備,要訪問之必須"選中",
          沒有選中的芯片不會(huì)工作,相當(dāng)于沒接一樣
          問4. 假設(shè)燒寫NAND FLASH,把命令、地址、數(shù)據(jù)發(fā)給它之后,
          NAND FLASH肯定不可能瞬間完成燒寫的,
          怎么判斷燒寫完成?
          答4. 通過狀態(tài)引腳RnB來判斷:它為高電平表示就緒,它為低電平表示正忙
          問5. 怎么操作NAND FLASH呢?
          答5. 根據(jù)NAND FLASH的芯片手冊(cè),一般的過程是:
          發(fā)出命令
          發(fā)出地址
          發(fā)出數(shù)據(jù)/讀數(shù)據(jù)
          NAND FLASH S3C2440
          發(fā)命令 選中芯片
          CLE設(shè)為高電平 NFCMMD=命令值
          在DATA0~DATA7上輸出命令值
          發(fā)出一個(gè)寫脈沖
          發(fā)地址 選中芯片 NFADDR=地址值
          ALE設(shè)為高電平
          在DATA0~DATA7上輸出地址值
          發(fā)出一個(gè)寫脈沖
          發(fā)數(shù)據(jù) 選中芯片 NFDATA=數(shù)據(jù)值
          ALE,CLE設(shè)為低電平
          在DATA0~DATA7上輸出數(shù)據(jù)值
          發(fā)出一個(gè)寫脈沖
          讀數(shù)據(jù) 選中芯片 val=NFDATA
          發(fā)出讀脈沖
          讀DATA0~DATA7的數(shù)據(jù)
          用UBOOT來體驗(yàn)NAND FLASH的操作:
          1. 讀ID
          S3C2440 u-boot
          選中 NFCONT的bit1設(shè)為0 md.l 0x4E000004 1; mw.l 0x4E000004 1
          發(fā)出命令0x90 NFCMMD=0x90 mw.b 0x4E000008 0x90
          發(fā)出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
          讀數(shù)據(jù)得到0xEC val=NFDATA md.b 0x4E000010 1
          讀數(shù)據(jù)得到device code val=NFDATA md.b 0x4E000010 1
          0xda
          退出讀ID的狀態(tài) NFCMMD=0xff mw.b 0x4E000008 0xff
          2. 讀內(nèi)容: 讀0地址的數(shù)據(jù)
          使用UBOOT命令:
          nand dump 0
          Page 00000000 dump:
          17 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5
          S3C2440 u-boot
          選中 NFCONT的bit1設(shè)為0 md.l 0x4E000004 1; mw.l 0x4E000004 1
          發(fā)出命令0x00 NFCMMD=0x00 mw.b 0x4E000008 0x00
          發(fā)出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
          發(fā)出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
          發(fā)出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
          發(fā)出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
          發(fā)出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
          發(fā)出命令0x30 NFCMMD=0x30 mw.b 0x4E000008 0x30
          讀數(shù)據(jù)得到0x17 val=NFDATA md.b 0x4E000010 1
          讀數(shù)據(jù)得到0x00 val=NFDATA md.b 0x4E000010 1
          讀數(shù)據(jù)得到0x00 val=NFDATA md.b 0x4E000010 1
          讀數(shù)據(jù)得到0xea val=NFDATA md.b 0x4E000010 1
          退出讀狀態(tài) NFCMMD=0xff mw.b 0x4E000008 0xff
          NAND FLASH驅(qū)動(dòng)程序層次
          看內(nèi)核啟動(dòng)信息
          S3C24XX NAND Driver, (c) 2004 Simtec Electronics
          s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30ns
          NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
          Scanning device for bad blocks
          Bad eraseblock 256 at 0x02000000
          Bad eraseblock 257 at 0x02020000
          Bad eraseblock 319 at 0x027e0000
          Bad eraseblock 606 at 0x04bc0000
          Bad eraseblock 608 at 0x04c00000
          Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":
          0x00000000-0x00040000 : "bootloader"
          0x00040000-0x00060000 : "params"
          0x00060000-0x00260000 : "kernel"
          0x00260000-0x10000000 : "root"
          搜"S3C24XX NAND Driver"
          S3c2410.c (driversmtdnand)
          s3c2410_nand_inithw
          s3c2410_nand_init_chip
          nand_scan // drivers/mtd/nand/nand_base.c 根據(jù)nand_chip的底層操作函數(shù)識(shí)別NAND FLASH,構(gòu)造mtd_info
          nand_scan_ident
          nand_set_defaults
          if (!chip->select_chip)
          chip->select_chip = nand_select_chip; // 默認(rèn)值不適用
          if (chip->cmdfunc == NULL)
          chip->cmdfunc = nand_command;
          chip->cmd_ctrl(mtd, command, ctrl);
          if (!chip->read_byte)
          chip->read_byte = nand_read_byte;
          readb(chip->IO_ADDR_R);
          if (chip->waitfunc == NULL)
          chip->waitfunc = nand_wait;
          chip->dev_ready
          nand_get_flash_type
          chip->select_chip(mtd, 0);
          chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
          *maf_id = chip->read_byte(mtd);
          dev_id = chip->read_byte(mtd);
          nand_scan_tail
          mtd->erase = nand_erase;
          mtd->read = nand_read;
          mtd->write = nand_write;
          s3c2410_nand_add_partition
          add_mtd_partitions
          add_mtd_device
          list_for_each(this, &mtd_notifiers) { // 問. mtd_notifiers在哪設(shè)置
          // 答. drivers/mtd/mtdchar.c,mtd_blkdev.c調(diào)用register_mtd_user
          struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
          not->add(mtd);
          // mtd_notify_add 和 blktrans_notify_add
          先看字符設(shè)備的mtd_notify_add
          class_device_create
          class_device_create
          再看塊設(shè)備的blktrans_notify_add
          list_for_each(this, &blktrans_majors) { // 問. blktrans_majors在哪設(shè)置
          // 答. driversmtdmdblock.c或mtdblock_ro.c register_mtd_blktrans
          struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
          tr->add_mtd(tr, mtd);
          mtdblock_add_mtd (driversmtdmdblock.c)
          add_mtd_blktrans_dev
          alloc_disk
          gd->queue = tr->blkcore_priv->rq; // tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
          add_disk
          測(cè)試4th:
          1. make menuconfig去掉內(nèi)核自帶的NAND FLASH驅(qū)動(dòng)
          -> Device Drivers
          -> Memory Technology Device (MTD) support
          -> NAND Device Support
          < > NAND Flash support for S3C2410/S3C2440 SoC
          2. make uImage
          使用新內(nèi)核啟動(dòng), 并且使用NFS作為根文件系統(tǒng),因?yàn)橹案募到y(tǒng)在nand flash上面,現(xiàn)在內(nèi)核去除了nand flash的驅(qū)動(dòng),內(nèi)核就無法訪問根文件系統(tǒng)了。
          3. insmod s3c_nand.ko
          4. 格式化 (參考下面編譯工具)
          flash_eraseall /dev/mtd3 //擦除后本身就格式化成 yaffs文件系統(tǒng),所以不用再格式化了
          5. 掛接
          mount -t yaffs /dev/mtdblock3 /mnt
          6. 在/mnt目錄下建文件
          編譯工具:
          1. tar xjf mtd-utils-05.07.23.tar.bz2
          2. cd mtd-utils-05.07.23/util
          修改Makefile:
          #CROSS=arm-linux-
          改為
          CROSS=arm-linux-
          3. make
          4. cp flash_erase flash_eraseall /work/nfs_root/first_fs/bin/
          flash_erase:只擦除一個(gè)扇區(qū)
          flash_eraseall:整個(gè)分區(qū)都擦除掉



          關(guān)鍵詞: NANDFLASH驅(qū)動(dòng)程

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉