加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

移植u-boot-2015.07-rc3之修改代码支持NandFlash(六)

发布时间:2020-12-15 20:07:33 所属栏目:百科 来源:网络整理
导读:方便起见,本节以上一节中生成的以Nor启动的u-boot作为修改目标,在以后的修改中,不管是SPL启动的u-boot还是Nor启动的u-boot修改的内容和方法都是一样的。如果你对NandFlash的操作不是很熟悉,请先移步到本博客博文《NandFlash操作详解》,熟悉了NandFlash

方便起见,本节以上一节中生成的以Nor启动的u-boot作为修改目标,在以后的修改中,不管是SPL启动的u-boot还是Nor启动的u-boot修改的内容和方法都是一样的。如果你对NandFlash的操作不是很熟悉,请先移步到本博客博文《NandFlash操作详解》,熟悉了NandFlash的操作后移植u-boot的NandFlash部分就会很轻松了。

启动u-boot后提示“NAND:? 0 MiB”,所以使用grep “NAND:” *-nR 搜索这个提示信息,最后可以定位到common/board_r.c中的initr_nand函数,在initr_nand函数中有对NandFlash进行初始化的函数nand_init(),下面追踪进这个初始化函数中分析代码。

board_init_r

???????? initr_nand

?????????????????? nand_init(drivers/mtd/nand/nand.c)

??????????????????????????? nand_init_chip

???????????????????????????????????? board_nand_init(drivers/mtd/nand/s3c2410_nand.c)

追踪到板级支持函数board_nand_init时发现这个函数位于drivers/mtd/nand/s3c2410_nand.c,所以需要复制s3c2410_nand.c文件为s3c2440_nand.c:

root@ubuntu:/home/uboot/u-boot-2015.07-rc3# cp drivers/mtd/nand/s3c2410_nand.c drivers/mtd/nand/s3c2440_nand.c ? ??? ? ? ? ? ? ? ???? ? ? ? ? ? ? ??? ?

?

修改Makefile支持s3c2440_nand.c:

root@ubuntu:/home/uboot/u-boot-2015.07-rc3# vim drivers/mtd/nand/Makefile

drivers/mtd/nand/Makefile中:

61 obj-$(CONFIG_NAND_NOMADIK) += nomadik.o

?62 obj-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o? ? ? ? ?

?63 obj-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o

?64 obj-$(CONFIG_NAND_SPEAR) += spr_nand.o

?

可以看到s3c2410_nand.o是否编译取决于CONFIG_NAND_S3C2410,所以需要在smdk2440中把NandFlash相关的宏修改过来:

smdk2440.h中:

177 #ifdef CONFIG_CMD_NAND? ? ? ??

178 #if 0

179 #define CONFIG_NAND_S3C2410

180 #define CONFIG_SYS_S3C2410_NAND_HWECC

181 #else

182 #define CONFIG_NAND_S3C2440

183 #define CONFIG_SYS_S3C2440_NAND_HWECC

184 #endif

185

186 #define CONFIG_SYS_MAX_NAND_DEVICE????? 1

187 #define CONFIG_SYS_NAND_BASE??????????? 0x4E000000

在smdk2440_nand.c中使用替换功能吧全部的2410替换成2440.make编译测试是否通过。

make

编译通过。

C语言是自顶向下执行的,结合执行顺序追踪initr_nand函数可以整理出如下执行结构:

board_init_r

???????? initr_nand

?????????????????? nand_init(drivers/mtd/nand/nand.c)

??????????????????????????? nand_init_chip//设置nand_chip结构体,提供底层的操作函数

???????????????????????????????????? board_nand_init(drivers/mtd/nand/s3c2440_nand.c)

?????????????????????????????????????????????? nand->select_chip = NULL;

?????????????????????????????????????????????? nand->cmd_ctrl = s3c24x0_hwcontrol;

?????????????????????????????????????????????? nand->dev_ready = s3c24x0_dev_ready;

???????????????????????????????????? nand_scan(drivers/mtd/nand/nand_base.c)

?????????????????????????????????????????????? nand_scan_ident

??????????????????????????????????????????????????????? nand_set_defaults//设置nand_chip结构体的默认值

???????????????????????????????????????????????????????????????? chip->cmdfunc = nand_command

???????????????????????????????????????????????????????????????? chip->waitfunc = nand_wait

???????????????????????????????????????????????????????????????? chip->select_chip = nand_select_chip

???????????????????????????????????????????????????????????????? chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;

??????????????????????????????????????????????????????? nand_get_flash_type

???????????????????????????????????????????????????????????????? chip->select_chip(mtd,0);//片选

???????????????????????????????????????????????????????????????? chip->cmdfunc(mtd,NAND_CMD_RESET,-1,-1);

???????????????????????????????????????????????????????????????? chip->cmdfunc(mtd,NAND_CMD_READID,0x00,-1);

???????????????????????????????????????????????????????????????? *maf_id = chip->read_byte(mtd);

???????????????????????????????????????????????????????????????? *dev_id = chip->read_byte(mtd);?? ? ? ? ? ? ? ??

在nand_scan_ident函数中会调用nand_get_flash_type函数,阅读代码和注释可以知道nand_get_flash_type的功能是获取厂商ID和设备ID,打开NandFlash手册找到获取ID的时序:




通过时序图可以知道读取ID的操作步骤应该是:

1、? 片选

2、? 发送命令0x90h

3、? 发送列地址00h

4、? 读厂商ID

5、? 读设备ID

6、? 读取3rd、4th、5th Cycle

7、? 取消片选

对照注释和代码后:

?

1、? 片选?????????????????????????????????????????????????????????????????? select_chip(mtd,0);

1.1?? 复位???????????????????????????????????????????????????????????????? chip->cmdfunc(mtd,-1);

2、? 发送命令0x90h???????????????????????????????????????????? chip->cmdfunc(mtd,-1);

3、? 发送列地址00h???????????????????????????????????????????? chip->cmdfunc(mtd,-1);

4、? 读厂商ID???????????????????????????????????????????????????????? *maf_id= chip->read_byte(mtd);

5、? 读设备ID???????????????????????????????????????????????????????? *dev_id= chip->read_byte(mtd);

6、? 读取3rd、4th、5th Cycle

7、? 取消片选

?

片选函数select_chip在nand_set_defaults函数中被设置为nand_select_chip,追踪到nand_select_chip函数为(drivers/mtd/nand/nand_base.c):

static void nand_select_chip(struct mtd_info *mtd,int chipnr)?? ? ? ? ? ? ? ??

struct nand_chip *chip = mtd->priv;

?

switch (chipnr) {

case -1:

chip->cmd_ctrl(mtd,NAND_CMD_NONE,0 | NAND_CTRL_CHANGE);

break;

case 0:

break;

?

default:

BUG();

}

}

可以看到在case 0的情况是什么也没做,而分析代码可以知道case 0是选中的情况,正确的选中是需要操作NFCONT寄存器的[1]位的,而这里什么也没做。这个片选函数位于drivers/mtd/nand/nand_base.c中,而这个文件不是s3c2440独有的文件,所以不建议在这哥文件中修改,我们仿造这个片选函数在s3c2440_nand.c中新建一个函数s3c2440_nand_select():

drivers/mtd/nand/s3c2440_nand.c中:

112 static void s3c2440_nand_select(struct mtd_info *mtd,int chipnr)

113 {

114???????? struct s3c24x0_nand *nand = s3c24x0_get_base_nand();? ? ? ? ? ?

115

116???????? switch (chipnr) {

117???????? case -1:

118???????????????? nand->nfcont |= (1<<1);

119???????????????? break;

120? ???????case 0:

121???????????????? nand->nfcont &= ~(1<<1);

122???????????????? break;

123

124???????? default:

125???????????????? BUG();

126???????? }

127 }

128

129

130 int board_nand_init(struct nand_chip *nand)

131 {

132???????? u_int32_t cfg;

?

新增s3c2440_nand_select函数后在board_nand_init中赋值使s3c2440_nand_select有效:

drivers/mtd/nand/s3c2440_nand.c中:? ? ? ? ? ? ? ? ? ? ? ? ? ?

159???????? nand->IO_ADDR_R = (void *)&nand_reg->nfdata;

160???????? nand->IO_ADDR_W = (void *)&nand_reg->nfdata;

161

162???????? nand->select_chip = s3c2440_nand_select;

163

164???????? /* read_buf and write_buf are default */

165???????? /* read_byte and write_byte are default */

可以看出,chip->cmdfunc(mtd,-1)函数即负责发送命令90h,也负责发送地址00h。而chip->cmdfunc函数在nand_set_defaults函数中被赋值为nand_command函数。nand_command函数追踪为:(位于drivers/mtd/nand/nand_base.c中)

nand_command(struct mtd_info *mtd,unsigned int command,int column,int page_addr)?? ? ? ? ? ? ? ? ? ?

chip->cmd_ctrl(mtd,readcmd,ctrl);//发送命令

chip->cmd_ctrl(mtd,command,column,ctrl);//发送列号

chip->cmd_ctrl(mtd,page_addr,ctrl)//;发送行号

chip->cmd_ctrl(mtd,NAND_CMD_STATUS,NAND_CTRL_CLE | NAND_CTRL_CHANGE);

?

可以在代码中看出nand_command的工作都是调用chip->cmd_ctrl来完成的,而chip->cmd_ctrl函数在board_nand_init函数中被赋值为s3c24x0_hwcontrol,也就是说s3c24x0_hwcontrol函数负责发送命令和地址,发送地址还是发送命令由chip->cmd_ctrl传入的ctrl参数决定!

???? 现在知道了s3c24x0_hwcontrol的作用,原来的s3c24x0_hwcontrol函数代码过于复杂,修改s3c24x0_hwcontrol函数代码为:

drivers/mtd/nand/s3c2440_nand.c文件中:? ?

41 static void s3c24x0_hwcontrol(struct mtd_info *mtd,int dat,unsigned int ctrl)

?42 {

?43???????? struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

?44

?45???????? if (ctrl & NAND_CLE)

?46???????? {

?47???????????????? writeb(dat,&nand->nfcmd);

?48???????? }

?49

?50???????? else if (ctrl & NAND_ALE)

?51???????? {

?52?????????????? ??writeb(dat,&nand->nfaddr);

?53???????? }

?54 }

?55

?56 static int s3c24x0_dev_ready(struct mtd_info *mtd)

?

是否还记得NandFlash裸机操作时是需要先做NandFlash的初始化的,而u-boot的NandFlash初始化位于board_nand_init函数中,如下:

drivers/mtd/nand/s3c2440_nand.c文件中:? ?

136 #endif

137

138

139???????? cfg = S3C2440_NFCONF_EN;

140???????? cfg |= S3C2440_NFCONF_TACLS(tacls - 1);

141???????? cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);

142???????? cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);

143???????? writel(cfg,&nand_reg->nfconf);

144

145???????? /* initialize nand_chip data structure */

146???????? nand->IO_ADDR_R = (void *)&nand_reg->nfdata;

147???????? nand->IO_ADDR_W = (void *)&nand_reg->nfdata;

148

149???????? nand->select_chip = s3c2440_nand_select;

?

追踪S3C2440_NFCONF_EN等宏可以看到:

#define S3C2440_NFCONF_EN????????? (1<<15)

#define S3C2440_NFCONF_TACLS(x)??? ((x)<<8)

#define S3C2440_NFCONF_TWRPH0(x)?? ((x)<<4)

#define S3C2440_NFCONF_TWRPH1(x)?? ((x)<<0)

而s3c2440手册中对NFCONT的定义如下:



所以这些宏都是错误的,并且board_nand_init函数中没有配置NFCONT寄存器,反正是做初始化,就把原来的部分代码注释,使用自己写的初始化代码:

修改drivers/mtd/nand/s3c2440_nand.c中的board_nand_init函数:?? ? ? ? ? ? ? ??

116 int board_nand_init(struct nand_chip *nand)

117 {

118???????? u_int32_t cfg;

119???????? u_int8_t tacls,twrph0,twrph1;

120???????? struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();

121???????? struct s3c24x0_nand *nand_reg = s3c24x0_get_base_nand();

122

123???????? debug("board_nand_init()n");

124

125???????? writel(readl(&clk_power->clkcon) | (1 << 4),&clk_power->clkcon);

126

127???????? /* initialize hardware */

128 #if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)

129???????? tacls? = CONFIG_S3C24XX_TACLS;

130???????? twrph0 = CONFIG_S3C24XX_TWRPH0;

131???????? twrph1 =? CONFIG_S3C24XX_TWRPH1;

132 #else

133???????? tacls = 4;

134???????? twrph0 = 8;

135???????? twrph1 = 8;

136 #endif

137

138 /*

139???????? cfg = S3C2440_NFCONF_EN;

140???????? cfg |= S3C2440_NFCONF_TACLS(tacls - 1);

141???????? cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);

142???????? cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);

143 */

144

145???????? cfg = ((tacls - 1)<<12) | ((twrph0 - 1)<<8) | ((twrph1 - 1)<<4);

146???????? writel(cfg,&nand_reg->nfconf);

147

148???????? writel((1<<4)|(1<<1)|(1<<0),&nand_reg->nfcont);

149

150???????? /* initialize nand_chip data structure */

151???????? nand->IO_ADDR_R = (void *)&nand_reg->nfdata;

152???????? nand->IO_ADDR_W = (void *)&nand_reg->nfdata;

153

154???????? nand->select_chip = s3c2440_nand_select;

?

???????? 经过上面的修改,u-boot已经正常支持NandFlash了,测试思路:往内存中写入特定值,再使用nand write命令把内存中的内容写入到NandFlash,使用nand dump命令或nand read查看NandFlash中的值。

SMDK2410 # md.b 32000000 20? //查看内存0x32000000中连续0x20字节的内容

32000000: f7 8c 33 cc 33 ec 3b 45 f3 cc 72 cc 33 dc b3 dc??? ..3.3.;E..r.3...

32000010: 73 c4 33 cc 37 cd 33 fc 31 fc 37 c4 27 cc 33 cc??? s.3.7.3.1.7.'.3.

SMDK2410 # mw.b 32000000 0x11 10? //向0x32000000中重复写入16个0x11

SMDK2410 # md.b 32000000 20???? //再次查看0x32000000中的内容,确保成功写入

32000000: 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11??? ................

32000010: 73 c4 33 cc 37 cd 33 fc 31 fc 37 c4 27 cc 33 cc??? s.3.7.3.1.7.'.3.

SMDK2410 # nand write 32000000 20000 10?? //内存32000000处连续16字节内容写入//NandFlash的0x20000处

?

NAND write: device 0 offset 0x20000,size 0x10

?16 bytes written: OK

SMDK2410 # md.b 33000000 20??????????? //查看0x33000000中连续0x20字节的内容

33000000: ed 37 8c 33 cc 37 cc b7 de 3b ec 33 cc b3 4c 33??? .7.3.7...;.3..L3

33000010: ec 3f dc 3b ec 3b dc 33 c8 3b cc b3 cc 33 ce 33??? .?.;.;.3.;...3.3

SMDK2410 # nand read 33000000 20000 10? //把NandFlash中0x20000处连续16字节的

//内容读入内存0x33000000

?

NAND read: device 0 offset 0x20000,size 0x10

?16 bytes read: OK

SMDK2410 # md.b 33000000 20?????????? //查看从NandFlash中读到的内容?? ? ? ? ? ? ? ??

33000000: 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11??? ................

33000010: ec 3f dc 3b ec 3b dc 33 c8 3b cc b3 cc 33 ce 33??? .?.;.;.3.;...3.3

SMDK2410 # nand dump 20000

Page 00020000 dump:

??????? 11 11 11 11 11 11 11 11? 11 11 11 11 11 11 11 11

??????? ff ff ff ff ff ff ff ff? ff ff ff ff ff ff ff ff

经过上述测试,确定以及肯定NandFlash移植成功!

?

下一节,DM9000支持

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读