UBOOT中关于NAND FLASH的支持十分完善,从命令上可以看出来,关于NAND FLASH的操作专门有个子系统。在驱动层面,UBOOT使用了MTD驱动规范,这个规范中对NAND FLASH的各种操作实现都很规范,一般来说只改写些少量的代码(相对于MTD设备驱动来说)就可以支持起来。大大减轻了移植难度。
一般来说,各个主控芯片的NAND FALSH驱动都存放于drivers/mtd/nand/目录之下,就S3C24X0系列芯片来说,UBOOT现在只提供了S3C2410的NAND FLASH驱动,而S3C2410和S3C2440在NAND FALSH模块方面是有一定的差别的,所以需要修改。
既然这里没有现成的驱动程序,就来实现一个吧,由于S3C2410和S3C2440同属于一个系列的芯片,所以就以S3C2410的驱动为模板写S3C2440的NAND FLASH驱动。
S3C2410的驱动(drivers/mtd/nand/s3c2410_nand.c)
001 #include <common.h>
002
003 #include <nand.h>
004 #include <asm/arch/s3c24x0_cpu.h>
005 #include <asm/io.h>
006
007 #define S3C2410_NFCONF_EN (1<<15)
008 #define S3C2410_NFCONF_512BYTE (1<<14)
009 #define S3C2410_NFCONF_4STEP (1<<13)
010 #define S3C2410_NFCONF_INITECC (1<<12)
011 #define S3C2410_NFCONF_nFCE (1<<11)
012 #define S3C2410_NFCONF_TACLS(x) ((x)<<8)
013 #define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
014 #define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
015
016 #define S3C2410_ADDR_NALE 4
017 #define S3C2410_ADDR_NCLE 8
018
019 #ifdef CONFIG_NAND_SPL
020
021
022 #define printf(fmt, args...)
023
024 static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
025 {
026 int i;
027 struct nand_chip *this = mtd->priv;
028
029 for (i = 0; i < len; i++)
030 buf[i] = readb(this->IO_ADDR_R);
031 }
032 #endif
033
034 static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
035 {
036 struct nand_chip *chip = mtd->priv;
037 struct s3c2410_nand *nand = s3c2410_get_base_nand();
038
039 debugX(1, "hwcontrol(): 0xx 0xx\n", cmd, ctrl);
040
041 if (ctrl & NAND_CTRL_CHANGE)
042 {
043 ulong IO_ADDR_W = (ulong)nand;
044
045 if (!(ctrl & NAND_CLE))
046 IO_ADDR_W |= S3C2410_ADDR_NCLE;
047 if (!(ctrl & NAND_ALE))
048 IO_ADDR_W |= S3C2410_ADDR_NALE;
049
050 chip->IO_ADDR_W = (void *)IO_ADDR_W;
051
052 if (ctrl & NAND_NCE)
053 writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE,
054 &nand->NFCONF);
055 else
056 writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE,
057 &nand->NFCONF);
058 }
059
060 if (cmd != NAND_CMD_NONE)
061 writeb(cmd, chip->IO_ADDR_W);
062 }
063
064 static int s3c2410_dev_ready(struct mtd_info *mtd)
065 {
066 struct s3c2410_nand *nand = s3c2410_get_base_nand();
067 debugX(1, "dev_ready\n");
068 return readl(&nand->NFSTAT) & 0x01;
069 }
070
071 #ifdef CONFIG_S3C2410_NAND_HWECC
072 void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
073 {
074 struct s3c2410_nand *nand = s3c2410_get_base_nand();
075 debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
076 writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF);
077 }
078
079 static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
080 u_char *ecc_code)
081 {
082 struct s3c2410_nand *nand = s3c2410_get_base_nand();
083 ecc_code[0] = readb(&nand->NFECC);
084 ecc_code[1] = readb(&nand->NFECC + 1);
085 ecc_code[2] = readb(&nand->NFECC + 2);
086 debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0xx 0xx 0xx\n",
087 mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
088
089 return 0;
090 }
091
092 static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
093 u_char *read_ecc, u_char *calc_ecc)
094 {
095 if (read_ecc[0] == calc_ecc[0] &&
096 read_ecc[1] == calc_ecc[1] &&
097 read_ecc[2] == calc_ecc[2])
098 return 0;
099
100 printf("s3c2410_nand_correct_data: not implemented\n");
101 return -1;
102 }
103 #endif
104
105 int board_nand_init(struct nand_chip *nand)
106 {
107 u_int32_t cfg;
108 u_int8_t tacls, twrph0, twrph1;
109 struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
110 struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();
111
112 debugX(1, "board_nand_init()\n");
113
114 writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);
115
116
117 twrph0 = 3;
118 twrph1 = 0;
119 tacls = 0;
120
121 cfg = S3C2410_NFCONF_EN;
122 cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
123 cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
124 cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
125 writel(cfg, &nand_reg->NFCONF);
126
127
128 nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
129
130 nand->select_chip = NULL;
131
132
133
134 #ifdef CONFIG_NAND_SPL
135 nand->read_buf = nand_read_buf;
136 #endif
137
138
139 nand->cmd_ctrl = s3c2410_hwcontrol;
140
141 nand->dev_ready = s3c2410_dev_ready;
142
143 #ifdef CONFIG_S3C2410_NAND_HWECC
144 nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
145 nand->ecc.calculate = s3c2410_nand_calculate_ecc;
146 nand->ecc.correct = s3c2410_nand_correct_data;
147 nand->ecc.mode = NAND_ECC_HW;
148 nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
149 nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
150 #else
151 nand->ecc.mode = NAND_ECC_SOFT;
152 #endif
153
154 #ifdef CONFIG_S3C2410_NAND_BBT
155 nand->options = NAND_USE_FLASH_BBT;
156 #else
157 nand->options = 0;
158 #endif
159
160 debugX(1, "end of nand_init\n");
161
162 return 0;
163 }
可以看到在这个驱动中,为了让UBOOT在S3C2410下支持NAND FLASH实现了如下函数。
设备初始化功能部分
105 int board_nand_init(struct nand_chip *nand)
这个函数的主要作用是初始化主控芯片的NAND FLASH控制器,将设备相关的读写控制操作封装成特定的函数提供给MTD结构体以便在后面MTD提供的通用读写函数中进行调用。提供NAND FLASH的数据入口和命令入口地址以及校验方法的选择。
读写操作功能部分
064 static int s3c2410_dev_ready(struct mtd_info *mtd)
034 static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
这两个函数是驱动提供的和设备相关操作的封装。s3c2410_hwcontrol()函数是NAND芯片硬件操作方法的一个封装,虽然NAND FLASH的操作方法是唯一的,但是各个主控芯片在寄存器和功能安排上都有区别。这个函数屏蔽了这个区别。它解决的问题的是:当程序接收到了一个NAND FLASH的一个命令操作字的时候,如何控制硬件来完成该命令要求的工作(例如:选择芯片;将NAND FLASH切换到读数据的状态;将NAND FLASH切换到写数据的状态……)。s3c2410_dev_read()函数是NAND芯片操作等待方法的一个封装,NAND FLASH的操作需要通过读取一个状态来表明操作是否完成,而在S3C2410中这个操作是通过读取NFSTAT的值来完成,作为和设备密切相关的一个部分来说就必须要使用的一个函数将硬件部分屏蔽掉。
硬件校验功能部分
072 void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
079 static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
080 u_char *ecc_code)
092 static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
093 u_char *read_ecc, u_char *calc_ecc)
MTD驱动本身也提供了软件实现的校验方法,当然在S3C2410中也提供了硬件校验码的生成功能。它们两者生成的校验码是有区别的,如何使用需要根据具体的要求。
MTD对ecc的校验方法进行了归纳,提供了3个接口的用于实现相关的基础操作,这些操作可以用软件实现,也可以用硬件实现。
s3c2410_nand_enable_hwecc()函数是对ecc功能使能方法的一个封装,在S3C2410这类芯片中ecc硬件校验功能的开启需要配置相关的寄存器。特别对于S3C2410芯片来说,我们需要配置NFCONF寄存器。
s3c2410_nand_calculate_ecc()函数是对ecc如何计算的方法的一个封装。在读写数据的时候都需要将数据的ecc计算出来。可以看到S3C2410在使能了硬件ecc计算功能的时候,每次写完数据都会自动在NFECC寄存器里面产生校验数据,直接将其写入到相关缓冲即可。
s3c2410_nand_correct_data()函数是对ecc校验码比对的方法的一个封装,这个函数用于校验数据的一个比对(ecc的计算工作已经在s3c2410_nand_calculate_ecc()完成了)。不过在硬件校验中,在这个函数中只需要进行简单的比对工作就可以完成任务(在软件校验中,还可以帮助纠正1bit错误)。
到这里,一个驱动大概就已经完成了。可以看到,要求实现的代码并不多,只需要对相关的控制入口地址;数据入口地址和NAND FLASH寻址入口地址等基本参数和硬件的基本配置方法了解就行(从头理解一个芯片的某个部分的功能是件痛苦的事)。

TQ2440的学习——UBOOT移植(NAND FLASH的支持)——初步分析相关推荐

  1. TQ2440的学习——UBOOT移植(串口控制台的支持)

    这里让UBOOT使用串口作为控制台输出,必须要保证串口功能被完善的支持.不过在启动到初始化串口功能之前,我们必须保证前面的初始化功能能顺利走完. 先来看看UBOOT的一个启动流程: UBOOT起始代码 ...

  2. 用JLINK烧写U-boot到Nand Flash中

    很多同学使用笔记本作为自己的ARM开发和学习的平台,绝大多数笔记本都没有并口,也就是无法使用JTag调试和烧写程序到Nand Flash中,幸好我们还有JLINK,用JLINK烧写U-boot到Nor ...

  3. jlink烧写linux内核,如何利用JLINK烧写U-boot到NAND Flash中

    很多同学使用笔记本作为自己的ARM开发和学习的平台,绝大多数笔记本都没有并口,也就是无法使用JTag调试和烧写程序到Nand Flash中,幸好我们还有JLINK,用JLINK烧写U-boot到Nor ...

  4. JLINK烧写U-boot到NAND Flash中

    http://www.linuxidc.com/Linux/2 很多同学使用笔记本作为自己的ARM开发和学习的平台,绝大多数笔记本都没有并口,也就是无法使用JTag调试和烧写程序到Nand Flash ...

  5. 基于优龙FS2410开发板u-boot-1.1.6的移植(NAND FLASH) (二)

    本文实现u-boot的写操作,实验过程中,参考了网上资料,列举如下:          <uboot1.1.4移植>网址:      http://hi.baidu.com/edaworl ...

  6. Tiny210(S5PV210) U-BOOT(五)----Nand Flash源码分析

    1.u-boot参考源码  Nand Flash的初始化代码在board/samsung/tiny210/lowlevel_init.S 2.初始化Nand Flash 在u-boot中,Nand的低 ...

  7. NAND FLASH学习笔记之nand flash基础(一)

    我入职以来接触的第一个实践内容就是MTD下的NAND FLASH的驱动,下面我将从nand flash的基础和驱动程序两个方面来探讨该知识点,同时最后我会把自己的 动手实验也展示出来,我学习是基于jz ...

  8. s3c2440 uboot 移植 (四)支持环境变量在nandflash 存储

    上一篇调通uboot的网络功能以后,已经可以用来进行引导linux,进行linux的移植了,不过如果环境变量没有保存的话,调试起来有点麻烦,而且后面也需要在uboot 中用到nandflash,所以这 ...

  9. S3C2440与NAND FLASH(K9F1208)的接线分析

    NAND FLASH的接线方式和NOR FLASH,SDRAM都不一样.以TQ2440开发板用的K9F1208为例,分析NAND FLASH的接线方式. K9F1208结构如下图: K9F1208位宽 ...

  10. S3C2440 与 NAND FLASH(K9F1208)的接线分析

    NAND FLASH 的接线方式和 NOR FLASH,SDRAM 都不一样.以 TQ2440 开发板用的 K9F1208 为例,分析 NAND FLASH 的接线方式. K9F1208 结构如下图: ...

最新文章

  1. linux putty 标题栏显示ip putty本地设置 服务器设置
  2. 闪念-许久未来一切没变
  3. 如何将yolo的标注(annotations).txt 坐标转换成tensorflow-yolov3(YunYang1994)的.txt 标注坐标?
  4. 3D坦克大战游戏源码
  5. 剑指offer:45-48记录
  6. (转)淘淘商城系列——引用dubbo服务
  7. js <->java 时区处理
  8. 毕设日志——Linux服务器状态查询命令
  9. 5年5亿美金,一年送出 1000 张训练卡,华为昇腾如何吸引AI开发者?
  10. 计算机陕西高校保研排名,陕西高校保研率排行,西安交通大学超30%排第一,西北工业第二...
  11. BZOJ4659 Lcm
  12. OpenCV 网络视频传输 C++ 和 python实现
  13. Java中常用的几个操作redies的方法。
  14. 王阳明心学:无善无恶心之体,有善有恶意之动,知善知恶是良知,为善去恶是格物。...
  15. iPhone 14来了,苹果13和14区别,值不值得买
  16. iphone个系列尺寸_不同尺寸的iphone截图看起来一样大吗?
  17. 黄天不负有心人,拥有属于自己的LOGO
  18. Linux与数据库简要说明
  19. Google Earth Engine(GEE)填补缺失影像
  20. 微软提前发新版音乐播放器 阻击苹果新iPod

热门文章

  1. 免费DNS服务器地址,谁家速度快
  2. web第六课:div标签和span标签
  3. zookeeper羊群效应
  4. java gwt开发_java – 如何启动GWT超级开发模式
  5. LM2596/LM2596S多路降压稳压DC-DC开关电源芯片详解(第二部分:电路设计)(12V转5V、12V转3.3V、任意电压转任意电压)
  6. 金山词霸2009牛津版下载地址
  7. 服务器虚拟化的主要特点,网络虚拟化的七大特征
  8. LaTeX数学公式大全
  9. 原则与思维模型--《思维模型》0
  10. 六度分割理论和SNS