Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1177330
  • 博文数量: 573
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 66
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-28 16:21
文章分类

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: LINUX

2015-12-04 15:57:29

nand.c文件

点击(此处)折叠或打开

  1. /*
  2. TQ2440开发板使用的nandflash芯片是 : K9F2G08U0A
  3. nandflash驱动的层次:

  4. 内核里面已经自带有nandflash的驱动程序,我们这里重新写一套。
  5. 参考源码:\kerner-2.6.30\drivers\mtd\nand\s3c2410.c
  6.         \kerner-2.6.30\drivers\mtd\nand\atmel_nand.c
  7. */

  8. #include <linux/module.h>
  9. #include <linux/types.h>
  10. #include <linux/init.h>
  11. #include <linux/kernel.h>
  12. #include <linux/string.h>
  13. #include <linux/ioport.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/delay.h>
  16. #include <linux/err.h>
  17. #include <linux/slab.h>
  18. #include <linux/clk.h>
  19. #include <linux/cpufreq.h>

  20. #include <linux/mtd/mtd.h>
  21. #include <linux/mtd/nand.h>
  22. #include <linux/mtd/nand_ecc.h>
  23. #include <linux/mtd/partitions.h>

  24. #include <asm/io.h>

  25. #include <plat/regs-nand.h>
  26. #include <plat/nand.h>

  27. /*定义一个nandflash相关的结构体
  28. 写成结构体的原因是:一次内存映射所有的寄存器。
  29. */
  30. struct nand_regs
  31. {
  32.         unsigned long nfconf ; /*0x4E000000*/
  33.         unsigned long nfcont ;
  34.         unsigned long nfcmd ;
  35.         unsigned long nfaddr ;
  36.         unsigned long nfdata ;
  37.         unsigned long nfeccd0 ;
  38.         unsigned long nfeccd1 ;
  39.         unsigned long nfeccd ;
  40.         unsigned long nfstat ;
  41.         unsigned long nfestat0;
  42.         unsigned long nfestat1;
  43.         unsigned long nfmecc0 ;
  44.         unsigned long nfmecc1 ;
  45.         unsigned long nfsecc ;
  46.         unsigned long nfsblk ;
  47.         unsigned long nfeblk ;
  48. };

  49. static struct nand_chip * my_nand_chip;        /*定义一个nand芯片 的结构体*/
  50. static struct mtd_info * my_mtd_info;            /*定义一个mtd信息 的结构体*/
  51. static struct nand_regs * s3c_nand_regs;    /*定义一个nandflash相关寄存器的结构体*/

  52. static struct mtd_partition my_nand_mtd_parts[] = /*分区表*/
  53. {
  54.     [0] = {
  55.         .name = "bootloader", /*分区名字*/
  56.         .size = 0x00040000,            /*分区大小:4*64K*/
  57.                 .offset    = 0,                            /*分区偏移值:相对nand的0地址*/
  58.                 /*上面表示:nandflash的0地址到256K的地址,是bootloader分区,是用来存储bootloader的*/
  59.     },
  60.     [1] = {
  61.         .name = "params",
  62.         .offset = MTDPART_OFS_APPEND, /*这个宏表示:偏移值紧跟着上面一个分区的大小*/
  63.         .size = 0x00020000,                    /* 2*64K */
  64.     },
  65.     [2] = {
  66.         .name = "kernel",
  67.         .offset = MTDPART_OFS_APPEND,
  68.         .size = 0x00300000,                    /* 3*1M */
  69.     },
  70.     [3] = {
  71.         .name = "root",                            /*根文件系统*/
  72.         .offset = MTDPART_OFS_APPEND,
  73.         .size = MTDPART_SIZ_FULL,     /*这个宏表示:nandflash剩下的所有的空间都是*/
  74.     }
  75. };

  76. /*
  77. 函数功能 : 片选函数
  78. */
  79. static void nand_select_chip(struct mtd_info *mtd, int chipnr)
  80. {
  81.         if (chipnr == -1)
  82.         {
  83.                 /* 取消选中: NFCONT[1]设为1 禁止NANDFLASH*/
  84.                 s3c_nand_regs->nfcont |= (1<<1);        
  85.         }
  86.         else
  87.         {
  88.                 /* 选中: NFCONT[1]设为0 使能NANDFLASH*/
  89.                 s3c_nand_regs->nfcont &= ~(1<<1);
  90.         }
  91. }

  92. /*
  93. 函数功能 : 发送命令,发送地址
  94. 函数参数 : ctrl : 用来区分是命令还是地址
  95. */
  96. static void nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
  97. {
  98.         if (ctrl & NAND_CLE)
  99.         {
  100.                 /* 发命令: 命令寄存器NFCMMD=dat */
  101.                 s3c_nand_regs->nfcmd = dat;
  102.         }
  103.         else
  104.         {
  105.                 /* 发地址: 地址寄存器NFADDR=dat */
  106.                 s3c_nand_regs->nfaddr = dat;
  107.         }
  108. }

  109. /*
  110. 函数功能 : 判断NandFlash是否准备就绪(即不忙)
  111. 函数参数 :
  112. 函数返回值 : 0: 1:
  113. */
  114. static int nand_dev_ready(struct mtd_info *mtd)
  115. {
  116.         /*状态寄存器NFSTAT*/
  117.         return (s3c_nand_regs->nfstat & (1<<0));
  118. }

  119. static int nand_init(void)
  120. {
  121.     struct clk *clk; /*时钟*/
  122.     
  123.     /* 1. 分配一个nand_chip结构体 */
  124.     my_nand_chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);

  125.     s3c_nand_regs = ioremap(0x4E000000, sizeof(struct nand_regs));

  126.     /* 2. 设置nand_chip */
  127.     /* 设置nand_chip是给nand_scan函数使用的, 如果不知道怎么设置, 先看nand_scan怎么使用
  128.      * 它应该提供:选中,发命令,发地址,发数据,读数据,判断状态的功能
  129.      */
  130.     my_nand_chip->select_chip = nand_select_chip;                    /*片选函数,选中*/
  131.     my_nand_chip->cmd_ctrl = nand_cmd_ctrl;                        /*发命令,发地址函数*/
  132.     my_nand_chip->IO_ADDR_R = &(s3c_nand_regs->nfdata);    /*读数据*/
  133.     my_nand_chip->IO_ADDR_W = &(s3c_nand_regs->nfdata);    /*发数据*/
  134.     my_nand_chip->dev_ready = nand_dev_ready;                        /*判断NandFlash是否准备就绪(即不忙)*/
  135.     my_nand_chip->ecc.mode = NAND_ECC_SOFT;                        /*使用软件生成,ECC校验码*/
  136.     /*nand为什么要进行ECC校验?
  137.     因为nandflash有个缺点:易位反转,所以要引入ECC校验,ECC校验码保存在OOB(out of bank)中,即bank 2K编址区域之外的 64字节区域。
  138.     1,写一页数据时,生成ECC码,把ECC码写入OOB区域。
  139.     2,读一页数据时,读OOB里面的校验码ECC,从读取的一页数据中也算出一个ECC码,再比较这2个ECC码(读出的ECC|算出的ECC)
  140.     2个ECC比较结果:若相等:则表示读取的数据正确;若不相等:则表示发生了位反转错误。
  141.     */

  142.     /* 3. 硬件相关的设置: 根据NAND FLASH的手册设置时间参数 */
  143.     /* 为了省电,内核会把用不到的模块都关掉,所以,要使能NAND FLASH控制器的时钟
  144.     可以不使用下面的函数,直接ioremap之后,设置寄存器CLKCON的BIT4的值,来开启时钟
  145.     */
  146.     clk = clk_get(NULL, "nand");
  147.     clk_enable(clk); /* CLKCON'bit[4] */
  148.     /*注意 : 只有时钟打开了,才能设置,/写下面的寄存器*/

  149.     /* HCLK=100MHz,所以一个周期的时间是10ns。
  150.      * TACLS: 发出CLE/ALE之后多长时间才发出nWE信号, 从NAND手册可知CLE/ALE与nWE可以同时发出,所以TACLS=0
  151.      * TWRPH0: nWE的脉冲宽度, HCLK x ( TWRPH0 + 1 ), 从NAND手册可知它要>=12ns, 所以TWRPH0>=1
  152.      * TWRPH1: nWE变为高电平后多长时间CLE/ALE才能变为低电平, 从NAND手册可知它要>=5ns, 所以TWRPH1>=0
  153.      */
  154. #define TACLS 1
  155. #define TWRPH0 3
  156. #define TWRPH1 0
  157.     s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);

  158.     /* NFCONT:
  159.      * BIT1-设为1, 取消片选, 刚开始时,是禁止片选
  160.      * BIT0-设为1, 使能NAND FLASH控制器
  161.      */
  162.     s3c_nand_regs->nfcont = (1<<1) | (1<<0);

  163.     /* 4. 使用: nand_scan */
  164.     my_mtd_info = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
  165.     my_mtd_info->owner = THIS_MODULE;
  166.     my_mtd_info->priv = my_nand_chip; /*我们定义的nand芯片 赋值给 这里的私有数据*/

  167.     /*nand_scan函数功能 : 扫描,识别内存技术设备nand芯片,第2个参数:最大芯片个数,我们这里只有一个芯片*/
  168.     nand_scan(my_mtd_info, 1); /* 识别NAND FLASH, 构造mtd_info */

  169.     /* 5. 添加分区 */
  170.     /*函数功能 : 通知字符设备,通知块设备;最终,块设备中会分配/注册一个块设备结构体 struct gendisk
  171.     函数参数:第3个参数:表示第2个结构体参数有多少项
  172.     */
  173.     add_mtd_partitions(my_mtd_info, my_nand_mtd_parts, 4);

  174.     /*下面这个函数功能:就是把整个nandflash的空间,当做一个分区。可以部分替代上面的函数。*/
  175.     //add_mtd_device(my_mtd_info);
  176.     return 0;
  177. }

  178. static void nand_exit(void)
  179. {
  180.         del_mtd_partitions(my_mtd_info);    /*对应 : add_mtd_partitions*/
  181.         kfree(my_mtd_info);                                /*对应 : kzalloc my_mtd_info*/
  182.         iounmap(s3c_nand_regs);                        /*对应 : ioremap*/
  183.         kfree(my_nand_chip);                            /*对应 : kzalloc my_nand_chip*/
  184. }

  185. module_init(nand_init);
  186. module_exit(nand_exit);
  187. MODULE_AUTHOR("wangxiancai"); //代码的作者
  188. MODULE_DESCRIPTION("nand driver"); //代码的描述,功能
  189. MODULE_LICENSE("GPL"); //开源协议
  190. MODULE_ALIAS("nand");

  191. /*
  192. 测试 :
  193. 1,未添加分区,只是识别nand芯片的时候,还不需要把内核自带的nand驱动去掉。
  194. # insmod nand.ko
  195. NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
  196. NAND_ECC_NONE selected by board driver. This is not recommended !! //这个表示:没有使用ECC校验
  197. Scanning device for bad blocks
  198. Bad eraseblock 41 at 0x000000520000 //扫描,识别坏块,确保不再使用它们
  199. Bad eraseblock 42 at 0x000000540000
  200. ...................................
  201. Bad eraseblock 363 at 0x000002d60000
  202. Bad eraseblock 364 at 0x000002d80000
  203. Bad eraseblock 750 at 0x000005dc0000
  204. Bad eraseblock 1290 at 0x00000a140000
  205. Bad eraseblock 1816 at 0x00000e300000

  206. 2,使用软件生成的ECC校验之后,再测
  207. # insmod nand.ko
  208. NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
  209. Scanning device for bad blocks
  210. Bad eraseblock 41 at 0x000000520000
  211. Bad eraseblock 42 at 0x000000540000
  212. ...................................
  213. Bad eraseblock 363 at 0x000002d60000
  214. Bad eraseblock 364 at 0x000002d80000
  215. Bad eraseblock 750 at 0x000005dc0000
  216. Bad eraseblock 1290 at 0x00000a140000
  217. Bad eraseblock 1816 at 0x00000e300000

  218. 3,加入nand分区的代码之后,再测
  219. 要去掉内核本身自带的nandflash驱动
  220. # make menuconfig
  221.   Device Drivers --->
  222.           <*> Memory Technology Device (MTD) support --->
  223.                       <*> NAND Device Support --->
  224.                                   <*> NAND Flash support for S3C2410/S3C2440 SoC //这个星号要去掉
  225. # make zImage
  226. # ./mkimage.sh
  227. # chmod 777 *

  228. 4,使用新内核,启动开发板
  229. # tftp 0x32000000 uImage;
  230. # bootm
  231. 开发板启动之后:在开发板目录下:
  232. # ls -lrt /dev/mtd* //说明新内核已经没有nand驱动了
  233. ls: /dev/mtd*: No such file or directory

  234. 5,插入模块
  235. # insmod nand.ko
  236. NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
  237. Scanning device for bad blocks
  238. Bad eraseblock 41 at 0x000000520000
  239. Bad eraseblock 42 at 0x000000540000
  240. ...................................
  241. Bad eraseblock 363 at 0x000002d60000
  242. Bad eraseblock 364 at 0x000002d80000
  243. Bad eraseblock 750 at 0x000005dc0000
  244. Bad eraseblock 1290 at 0x00000a140000
  245. Bad eraseblock 1816 at 0x00000e300000
  246. Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":
  247. 0x000000000000-0x000000040000 : "bootloader"
  248. 0x000000040000-0x000000060000 : "params"
  249. 0x000000060000-0x000000360000 : "kernel"
  250. 0x000000360000-0x000010000000 : "root"

  251. # ls -lrt /dev/mtd* //说明我们写的nand驱动成功了
  252. brw-rw---- 1 root root 31, 1 Jan 1 00:02 /dev/mtdblock1
  253. brw-rw---- 1 root root 31, 0 Jan 1 00:02 /dev/mtdblock0
  254. crw-rw---- 1 root root 90, 7 Jan 1 00:02 /dev/mtd3ro
  255. crw-rw---- 1 root root 90, 4 Jan 1 00:02 /dev/mtd2
  256. crw-rw---- 1 root root 90, 3 Jan 1 00:02 /dev/mtd1ro
  257. crw-rw---- 1 root root 90, 2 Jan 1 00:02 /dev/mtd1
  258. crw-rw---- 1 root root 90, 1 Jan 1 00:02 /dev/mtd0ro
  259. crw-rw---- 1 root root 90, 0 Jan 1 00:02 /dev/mtd0
  260. brw-rw---- 1 root root 31, 3 Jan 1 00:02 /dev/mtdblock3
  261. brw-rw---- 1 root root 31, 2 Jan 1 00:02 /dev/mtdblock2
  262. crw-rw---- 1 root root 90, 6 Jan 1 00:02 /dev/mtd3
  263. crw-rw---- 1 root root 90, 5 Jan 1 00:02 /dev/mtd2ro

  264. 说明:创建了4个分区,每个分区又创建了1个只读的字符设备(带ro的)文件+1个可读可写的字符设备文件+1个块设备文件

  265. 6,在ubuntu目录下
  266. # tar -xjvf mtd-utils-05.07.23.tar.bz2 //需要使用mtd工具
  267. # cd /home/wangxc/linux/rootfs/mtd-utils-05.07.23
  268. # cd /home/wangxc/linux/rootfs/mtd-utils-05.07.23/util
  269. 修改makefile
  270. #CROSS=arm-linux-
  271. 修改为
  272. CROSS=arm-linux-

  273. # export PATH=$PATH:/home/wangxc/linux/toolchain/crosstools_4.4.3_softfloat/bin
  274. # make
  275. # ls
  276. # cp /home/wangxc/linux/rootfs/mtd-utils-05.07.23/util/flash_erase /home/wangxc/linux/rootfs/nfs_2.6.30/wxc/driver/blockdriver/nand/
  277. # cp /home/wangxc/linux/rootfs/mtd-utils-05.07.23/util/flash_eraseall /home/wangxc/linux/rootfs/nfs_2.6.30/wxc/driver/blockdriver/nand/
  278. 注意:
  279. flash_erase 功能 : 擦除一个扇区
  280. flash_eraseall 功能 : 擦除整个分区
  281. 都是操作字符设备的

  282. 在开发板目录下,格式化磁盘空间,格式化的时候,用字符设备。
  283. # flash_eraseall /dev/mtd3 //擦除完成之后,它本身就会被格式化成 yaffs 文件系统
  284. Bad eraseblock 41 at 0x000000520000
  285. Bad eraseblock 42 at 0x000000540000
  286. ...................................
  287. Bad eraseblock 363 at 0x000002d60000
  288. Bad eraseblock 364 at 0x000002d80000
  289. Bad eraseblock 750 at 0x000005dc0000
  290. Bad eraseblock 1290 at 0x00000a140000
  291. Bad eraseblock 1816 at 0x00000e300000
  292. 以上说明:我的nandflash有很多坏块,第1个坏块的编号从41号开始,
  293. 因为每一块就有128K字节的空间,之前做nand_read的时候,没有判断坏块,其实是厂家确保了第0块是好块。
  294. 正式的代码:nand_read,nand_write,nand_erase的时候,遇到坏块,都会跳过这个坏块。

  295. 7, 在开发板目录,挂接 : 挂接的时候用块设备。
  296. # mount -t yaffs /dev/mtdblock3 /mnt/ //把磁盘设备 挂接到 /tmp目录下
  297. yaffs: dev is 32505859 name is "mtdblock3"
  298. yaffs: passed flags ""
  299. yaffs: Attempting MTD mount on 31.3, "mtdblock3"
  300. yaffs: auto selecting yaffs2
  301. yaffs: restored from checkpoint
  302. yaffs_read_super: isCheckpointed 1

  303. # cd /mnt
  304. # ls -lrt
  305. drwx------ 1 root root 2048 Jan 1 01:00 lost+found //出现这个,表示正常了

  306. 8,/mnt目录下来创建文件
  307. 相当于在分区3,来操作
  308. # mkdir test
  309. # echo “wangxiancai” >> 1.txt
  310. 上面的文件数据,都会保存在nandflash的分区3中。
  311. 再重新启动内核,不擦除nandflash的时候,重新把nandflash的分区3挂接到/mnt目录,则可以再次看见这写文件数据。

  312. */
makefile文件

点击(此处)折叠或打开

  1. # File: Makefile
  2. # wangxiancai

  3. MODEXT = ko
  4. # INSTALLDIR=/home/wangxc/linux/rootfs/nfs_2.6.13/wxc/driver/chardriver/ko
  5. INSTALLDIR=/home/wangxc/linux/rootfs/nfs_2.6.30/wxc/driver/blockdriver/ko
  6. # CROSS=/home/wangxc/linux/toolchain/crosstools_3.4.1_softfloat/arm-linux/gcc-3.4.1-glibc-2.3.3/bin/arm-linux-
  7. CROSS=/home/wangxc/linux/toolchain/crosstools_4.4.3_softfloat/bin/arm-linux-
  8. # KERNELDIR=/home/wangxc/linux/kernel/kernel-2.6.13
  9. KERNELDIR=/home/wangxc/linux/kernel/kerner-2.6.30

  10. CC= $(CROSS)gcc
  11. LD= $(CROSS)ld

  12. #############################################################################
  13. # Compiler Flags
  14. #############################################################################
  15. EXTRA_CFLAGS += -I$(KERNELDIR)/include
  16. #############################################################################
  17. # Make Targets
  18. #############################################################################
  19. obj-m := nand.o
  20. default:
  21.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  22. # Otherwise we were called directly from the command line; invoke the kernel build system.

  23. install: default
  24.     rm -rf $(INSTALLDIR)/nand.$(MODEXT)
  25.     cp -rf $(PWD)/nand.$(MODEXT) $(INSTALLDIR)

  26. clean:
  27.     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.bak modules.order Module.symvers

阅读(764) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~