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

转载 2015年11月21日 11:12:03
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的支持)——初步分析

UBOOT中关于NAND FLASH的支持十分完善,从命令上可以看出来,关于NAND FLASH的操作专门有个子系统。在驱动层面,UBOOT使用了MTD驱动规范,这个规范中对NAND FLASH的...

TQ2440的学习——UBOOT移植(NOR FLASH相关操作支持)

UBOOT中可以对NOR FLASH进行操作,默认情况下是开启了CONFIG_CMD_FLASH这个宏的。这个宏支持flinfo(打印flash信息)、erase(擦除数据)和protect(保护)这...

TQ2440的学习——UBOOT移植(网络设备的支持)

转载:http://blog.sina.com.cn/s/blog_640029b30100ubzg.html

TQ2440 学习笔记—— 20、NAND Flash 控制器

(韦东山——嵌入式Linux 应用开发完全手册) 一、NAND Flash控制器 1、地址空间 SRAM,DM9000 的地址总线接到了S3C2440的地址总线上;而NAND Flash 没有地...
  • Cowena
  • Cowena
  • 2015年09月04日 09:46
  • 376

TQ2440 学习笔记—— 7、NOR Flash 和 NAND Flash

非易失闪速存储器Flash 具有速度快、成本低、密度大的特点。 Flash 存储器主要有 NOR Flash 和 NAND Flash两种类型,总的来说, NOR 型比较适合存储程序代码,NAND 型...
  • Cowena
  • Cowena
  • 2015年08月26日 10:26
  • 1150

JZ2440学习笔记,第三部分,移植uboot2015支持JZ2440的nand flash

JZ2440学习笔记 Chili 2015.5 第三部分,移植uboot2015支持JZ2440的nand flash 6,修改uboot支持nand flash  与nor f...

TX2440 ARM开发板Uboot移植(三、添加Nand Flash的有关操作支持)

在上一节中我们说过,通常在嵌入式bootloader中,有两种方式来引导启动内核:从Nor Flash启动和从Nand Flash启动,但不管是从Nor启动或者从Nand启动,进入第二阶段以后,两者的...

Uboot移植之<一>------S3C2440平台搭建(支持Norflash和nand flash)

此文章参考天祥电子uboot移植文档和网上各位大侠优秀移植文章,在此感谢他们。 一、    环境 硬件信息 软件环境 开发板:TX2440A 操作系统:ubuntu 12.04 CP...

基于TQ2440的u-boot 1.1.6移植(二)(支持nor flash nand flash )

1.修改在u-boot 中的提示符“SMDK2410 #”, 可以在/include/configshang2440.h 中修改成  ,操作如下:#define CFG_PROMPT "[dong24...

uImage在内存中无法正常启动——UBoot-2010.06在TQ2440上的移植--机器码配对

这几天在进行内核的移植实验的时候,遇到了一个问题,利用uboot下载内核镜像无法正常运行。出现这些代码: [u-boot@jxboylj2440] # bootm 31000000 ## ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:TQ2440的学习——UBOOT移植(NAND FLASH的支持)——初步分析
举报原因:
原因补充:

(最多只允许输入30个字)