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

时间:2022-01-17 09:04:25

方便起见,本节以上一节中生成的以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的时序:

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



通过时序图可以知道读取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,NAND_CMD_RESET, -1, -1);

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

3、  发送列地址00h                                             chip->cmdfunc(mtd,NAND_CMD_READID, 0x00, -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, NAND_CMD_READID, 0x00, -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, ctrl);//发送命令

chip->cmd_ctrl(mtd, 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的定义如下:

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


所以这些宏都是错误的,并且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支持