四,移植uboot-支持NOR,NAND 操作
文档时间:2018-08-11
交叉编译器:arm-linux-gcc-4.3.2
Ubuntu版本:16.04
uboot版本:2013.10
1,修改代码支持 nor flash 操作
前面章节已经实现NOR,NAND 启动,但是还不支持nor,nand flash 操作,如下图打印信息所示:
Flash: *** failed ***,搜索发现,此段错误信息在第二阶段 board_init_r 函数中,此函数位于 arch/arm/lib/board.c 文件中,代码如下所示:
#if !defined(CONFIG_SYS_NO_FLASH) puts("Flash: "); flash_size = flash_init(); if (flash_size > 0) { # ifdef CONFIG_SYS_FLASH_CHECKSUM print_size(flash_size, ""); /* * Compute and print flash CRC if flashchecksum is set to 'y' * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */ if (getenv_yesno("flashchecksum") == 1) { printf(" CRC: %08X", crc32(0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)); } putc('\n'); # else /* !CONFIG_SYS_FLASH_CHECKSUM */ print_size(flash_size, "\n"); # endif /* CONFIG_SYS_FLASH_CHECKSUM */ } else { puts(failed); hang(); } #endif
从上面代码可以看出,如果nor flash 没有初始化成功,会执行红色部分代码,打印错误信息,陷入死循环,现更改代码,让其继续跑下去,代码更改如下(红色部分为修改代码):
# endif /* CONFIG_SYS_FLASH_CHECKSUM */ } else { //puts(failed); //hang(); puts("0 KB \n\r"); }
1)在 jz2440.h 中添加 DEBUG 的定义,使串口打印更多信息
#define DEBUG
然后,编译,烧写,串口打印信息如下图所示:
从图中可以看出已经读出厂家ID,设备ID了,但是不匹配,搜索 JEDEC PROBE 关键字,位于:
打开 drivers/mtd/cfi_flash.c 文件,定位到1798行,发现该字段位于 flash_detect_legacy 函数中,flash_detect_legacy 函数的调用关系如下:
board_init_r -> flash_init -> flash_detect_legacy,分析如下代码:
该函数会进入到 jedec_flash_match(位于drivers/mtd/jedec_flash.c文件中) 函数,打开该文件,定位到jedec_flash_match 函数:
该函数里会去匹配 jedec_table ,定位到 jedec_table 定义处,发现没有与我们所用nor flash 相匹配的定义,参照所用 nor flash(MT29LV160DB)手册,增加如下代码(红色部分为增加代码):
static const struct amd_flash_info jedec_table[] = { /*MX29LV160DB*/ { .mfr_id = (u16)MX_MANUFACT, .dev_id = AM29LV160DB, //0x2249 .name = "MX29LV160DB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* 数组[1]表示是16位nor,解锁地址为:0x555,0x2AA */ }, .DevSize = SIZE_2MiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 4, //4种不同的扇区规格 .regions = { ERASEINFO(16*1024, 1), ERASEINFO(8*1024, 2), ERASEINFO(32*1024, 1), ERASEINFO(64*1024, 31), } },
注释掉 jz2440.h 中定义的 DEBUG 宏,然后编译,烧写到 nor flash,出现如下图所示错误:
搜索这段字符串,发现该段字符串位于 drivers/mtd/jedec_flash.c 中,打开 jedec_flash.c 文件,定位到这里:
显然是宏 CONFIG_SYS_MAX_FLASH_SECT 小于我们的扇区数量,才会打印这个错误,修改 CONFIG_SYS_MAX_FLASH_SECT (位于 include/configs/jz2440.h 中):
#define CONFIG_SYS_MAX_FLASH_SECT (128)
重新编译烧写,打印如下信息:
输入 flinfo 命令,查看 flash 信息,如下图所示:
通过串口终端输入以下命令,来检查 nor flash 的读写是否满足我们的要求:
protect off all erase 10000 +7ffff cp.b 30000000 10000 80000 //烧写在另一个位置 cmp.b 30000000 10000 80000 //比较,是否读写正确
如果正确,则会打印如下信息:
2,修改代码,支持 nand flash 操作
在修改代码之前先把串口终端名称 SMDK2410 改为 JZ2440,在 include/configs/jz2440.h 中修改,修改代码如下:
#define CONFIG_SYS_PROMPT "JZ2440 # "
在之前的章节中,我们把支持 nand 的宏 CONFIG_CMD_NAND 给屏蔽了,现在取消屏蔽(在 jz2440.h 中),然后添加对2440 nand 宏的支持,修改代码如下:
#ifdef CONFIG_CMD_NAND //#define CONFIG_NAND_S3C2410 //#define CONFIG_SYS_S3C2410_NAND_HWECC #define CONFIG_NAND_S3C2440 #define CONFIG_SYS_S3C2440_NAND_HWECC
2410对于nand flash 的支持位于 drivers/mtd/nand/s3c2410_nand.c 中,仿照此文件,编写对2440 nand flash 的支持
在 Ubuntu 下,输入命令 cp drivers/mtd/nand/s3c2410_nand.c drivers/mtd/nand/s3c2440_nand.c 进行拷贝,然后修改Makefile,如下所示:
COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
分析 nand 流程:board_init_r -> nand_init -> nand_init_chip -> board_nand_init 和 nand_scan
1),进入 board_init_r 函数(arch/arm/lib/board.c里)
2),进入 nand_init 函数(drivers/mtd/nand/nand.c里)
3),进入 nand_init_chip 函数(drivers/mtd/nand/nand.c里)
调用 board_nand_init 和 nand_scan 函数
修改 drivers/mtd/nand/s3c2440_nand.c 支持我们所用的nand flash 芯片
首先将所有带有 2410 的变量 替换为 2440
然后参考以前裸机 nand 驱动程序或者S3C2440和所用nand 芯片手册修改 nand_board_init 函数,修改代码如下:
cfg = S3C2440_NFCONF_EN; cfg |= S3C2440_NFCONF_TACLS(tacls - 1); cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); writel(cfg, &nand_reg->nfconf); nand_reg->nfcont=(1<<1)|(1<<0); // bit1:关闭片选(), bit0:开启nand flash 控制器 /* initialize nand_chip data structure */ nand->IO_ADDR_R = (void *)&nand_reg->nfdata; nand->IO_ADDR_W = (void *)&nand_reg->nfdata; nand->select_chip=s3c2440_select_chip;
编写 s3c2440_select_chip 函数,代码如下(这里可以参考别的单板的例程):
static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr) { struct s3c2440_nand *nand_reg = s3c2440_get_base_nand(); if(chipnr==-1) //CE Disable { nand_reg->nfcont|=(0x01<<1); //bit1置1 } else //CE Enable { nand_reg->nfcont&=~(0x01<<1); //bit1置0 } }
修改 s3c2440_hwcontrol 函数,修改代码如下,(红色为修改部分):
static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *chip = mtd->priv; struct s3c2440_nand *nand = s3c2440_get_base_nand(); if (ctrl & NAND_CLE) // 传输的是命令 nand->nfcmd=cmd; else // 传输的是地址 nand->nfaddr=cmd; }
代码修改完毕,编译,烧写,观察现象:
nand flash已经识别出来,接下来测试 nand flash 读写是否正确,输入以下命令:
nand erase 100000 1000 //擦除 mw.b 30000000 0x55 1000 nand write 30000000 100000 1000 //将0x55写入nand nand dump 100000 1000 //打印
如下图所示,读写都没问题
到此为止,uboot 代码已经能够支持 jz2440 nor / nand flash 操作了,下一张移植 DM9000 网卡支持