AM335x uboot中Nand Flash调试

目前手头有两块AM335x的板子,硬件上除了nand flash型号不同外,其它硬件状态相同。u-boot版本2019.01,为了方便NAND的调试,需要提前先把SDCard引导启动调通,然后在从SDCard启动,这里先不用kernel,直接在uboot中来测试NAND flash的读写。
  另外如果要想从NAND中启动uboot,还需要硬件上设置sysboot可以从NAND引导。sysboot详情可以参见《AM335x and AMIC110 Sitara™ Processors.pdf》的SYSBOOT Configuration Pins章节,主要是sysboot[9],sysboot[4:0]。
  1.修改pinmux并在初始化时调用gpmc_init(),修改位于board.c和mux.c中,再就是根据情况添加所需要的宏。
mux.c

/*定义引脚功能*/
#ifdef CONFIG_NAND

static struct module_pin_mux nand_pin_mux[] = {
{ OFFSET(gpmc_ad0), (MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD0 /
{ OFFSET(gpmc_ad1), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD1 /
{ OFFSET(gpmc_ad2), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD2 /
{ OFFSET(gpmc_ad3), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD3 /
{ OFFSET(gpmc_ad4), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD4 /
{ OFFSET(gpmc_ad5), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD5 /
{ OFFSET(gpmc_ad6), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD6 /
{ OFFSET(gpmc_ad7), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD7 /
#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
{ OFFSET(gpmc_ad8), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD8 /
{ OFFSET(gpmc_ad9), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD9 /
{ OFFSET(gpmc_ad10), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD10 /
{ OFFSET(gpmc_ad11), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD11 /
{ OFFSET(gpmc_ad12), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD12 /
{ OFFSET(gpmc_ad13), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD13 /
{ OFFSET(gpmc_ad14), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD14 /
{ OFFSET(gpmc_ad15), (MODE(0) | PULLUDDIS | RXACTIVE)}, / AD15 /
#endif
{ OFFSET(gpmc_wait0), (MODE(0) | PULLUP_EN | RXACTIVE)}, / nWAIT /
{ OFFSET(gpmc_wpn), (MODE(7) | PULLUP_EN)}, / nWP /
{ OFFSET(gpmc_csn0), (MODE(0) | PULLUP_EN)}, / nCS /
{ OFFSET(gpmc_wen), (MODE(0) | PULLDOWN_EN)}, / WEN /
{ OFFSET(gpmc_oen_ren), (MODE(0) | PULLDOWN_EN)}, / OE /
{ OFFSET(gpmc_advn_ale), (MODE(0) | PULLDOWN_EN)}, / ADV_ALE /
{ OFFSET(gpmc_be0n_cle), (MODE(0) | PULLDOWN_EN)}, / BE_CLE */
{ -1},
};
#endif

/中间代码省略/

void enable_board_pin_mux(void)
{
// configure_module_pin_mux(rgmii1_pin_mux);
configure_module_pin_mux(mmc0_pin_mux);
#if defined(CONFIG_NAND)
configure_module_pin_mux(nand_pin_mux);
#else
configure_module_pin_mux(mmc1_pin_mux);
#endif

}

board.c

/*board_init中添加对gpmc_init调用*/
/*
 * Basic board specific setup.  Pinmux has been handled already.
 */
int board_init(void)
{
#if defined(CONFIG_HW_WATCHDOG)
	hw_watchdog_init();
#endif
gd<span class="token operator">-&gt;</span>bd<span class="token operator">-&gt;</span>bi_boot_params <span class="token operator">=</span> CONFIG_SYS_SDRAM_BASE <span class="token operator">+</span> <span class="token number">0x100</span><span class="token punctuation">;</span>

#if defined(CONFIG_NOR) || defined(CONFIG_NAND)
gpmc_init();
#endif
return 0;
}

配置相关的宏,这里面整理一下NAND中可能会用到的宏。

CONFIG_CMD_SPL_NAND_OFS=0x00080000
CONFIG_CMD_NAND=y
CONFIG_ENV_IS_IN_NAND=y
CONFIG_MTDPARTS_DEFAULT="mtdparts=nand.0:512k(NAND.SPL),512k(NAND.SPL.backup1),512k(NAND.SPL.backup2),512k(NAND.SPL.backup3),2m(NAND.u-boot),1m(NAND.u-boot-env),1m(NAND.u-boot-spl-os),8m(NAND.kernel),-(NAND.file-system)"
CONFIG_DFU_NAND=y
CONFIG_NAND=y
CONFIG_NAND_BOOT=y						//没有这个宏无法从NAND引导启动,刚开始没配置导致折腾了半天才发现这个问题。
CONFIG_SPL_NAND_SUPPORT=y
CONFIG_LZO=y

修改头文件,配置NAND参数:

#define CONFIG_SYS_NAND_PAGE_SIZE	2048
#define CONFIG_SYS_NAND_OOBSIZE		64
#define CONFIG_SYS_NAND_BLOCK_SIZE	(128*1024)

/* NAND: driver related configs */
#define CONFIG_SYS_NAND_BAD_BLOCK_POS NAND_LARGE_BADBLOCK_POS
#define CONFIG_SYS_NAND_ECCPOS { 2, 3, 4, 5, 6, 7, 8, 9, </span>
10, 11, 12, 13, 14, 15, 16, 17, </span>
18, 19, 20, 21, 22, 23, 24, 25, </span>
26, 27, 28, 29, 30, 31, 32, 33, </span>
34, 35, 36, 37, 38, 39, 40, 41, </span>
42, 43, 44, 45, 46, 47, 48, 49, </span>
50, 51, 52, 53, 54, 55, 56, 57, }

#define CONFIG_SYS_NAND_ECCSIZE 512
#define CONFIG_SYS_NAND_ECCBYTES 14
#define CONFIG_SYS_NAND_ONFI_DETECTION
#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_BCH8_CODE_HW
#endif
#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x00200000
/* NAND: SPL related configs /
#ifdef CONFIG_SPL_OS_BOOT
#define CONFIG_SYS_NAND_SPL_KERNEL_OFFS 0x00600000 / kernel offset /
#endif
#endif / !CONFIG_NAND */

2.重新编译uboot将MLO和u-boot.img烧写到SDCard中,设置从SDCard启动uboot,在uboot的命令行中输入mtdparts来查看nand的分区情况,对比下分区信息应该和CONFIG_MTDPARTS_DEFAULT宏中定义的分区信息相同。其次就是利用nand命令查看nand信息和测试nand读写是否正常,如果提示什么ECC 错误可以尝试把整个芯片擦除一下重新写(如果还是不行后面找答案),下面列出几个nand命令,其它的可以参考nand的帮助信息。

/*写MLO文件到NAND中*/
fatload mmc 0:1 82000000 MLO;
nand erase.part NAND.SPL;
nand write 82000000 NAND.SPL 80000;
/*写u-boot.img文件NAND中*/
fatload mmc 0:1 82000000 u-boot.img;
nand erase.part NAND.u-boot;
nand write 82000000 NAND.u-boot 100000;

3.可以利用上面的命令将MLO文件和u-boot.img烧写到相应的nand分区。烧写完成后设置sysboot从nand引导启动一下看能不能启动起来,如果不行参考下面的介绍在继续修改。
  文初提到手头有两块NAND型号不同的板子,起初调试用的是ti划分的分区( CONFIG_MTDPARTS_DEFAULT=“mtdparts=nand.0:128k(NAND.SPL),128k(NAND.SPL.backup1),128k(NAND.SPL.backup2),128k(NAND.SPL.backup3),256k(NAND.u-boot-spl-os),1m(NAND.u-boot),128k(NAND.u-boot-env),128k(NAND.u-boot-env.backup1),8m(NAND.kernel),-(NAND.file-system)”
),其中一块的NAND型号MX60LF8G18AC已经可以正常启动了。但是另一块NAND型号MT29F8G08ABABAWP就一直无法启动,串口打印“CCCC”。并且用mtdparts查看分区时提示“nand0: partition (NAND.SPL) size alignment incorrect”。对比两个芯片的手册发现:MX60LF8G18AC的 page size:(2048+64)byte Block size:(128K+4K)byte 而MT29F8G08ABABAWP的page size:(4096+224)byte Block size:(512K+28K)byte,可以看到两个芯片的block size是不同的,在nand中最小的操作单元是block,显然这个128k的分区不能满足MT29F8G08ABABAWP中block是512K的要求,所以需要调整所有分区大小使同时满足128K和512K的整数倍,这样的话就可以同时支持两种型号的NAND。

nand0: partition (NAND.SPL) size alignment incorrect
  因为CONFIG_MTDPARTS_DEFAULT的分区信息做了调整,所以u-boot.img,环境变量、内核等的存放地址也发生了变化,在头文件中也需要做相应的调整;下面代码中后面的地址如果不想自己算的话,可以先编译烧写SDCard中利用mtdparts查看。

#define CONFIG_SYS_NAND_U_BOOT_OFFS     0x00100000   //u-boot.img的偏移地址(NAND.u-boot)
#define CONFIG_SYS_NAND_SPL_KERNEL_OFFS 0x00500000 		//* kernel offset(NAND.kernel) */
#define CONFIG_ENV_OFFSET               0x00300000       //环境变量存放位置

其次因两个NAND的分页和块信息不一样,所以头文件中的NAND参数也要做相应改动。下面是两种nand的修改后的参数:

#ifdef CONFIG_NAND
/* NAND: device related configs */
#define CONFIG_SYS_NAND_5_ADDR_CYCLE
#define CONFIG_SYS_NAND_PAGE_COUNT	(CONFIG_SYS_NAND_BLOCK_SIZE / \
					 CONFIG_SYS_NAND_PAGE_SIZE)
#ifdef CONFIG_NAND_MT29F8G08ABABAWP   //自己添加的宏,需要用时请在Kconfig和deconfig中增加。
/*MT29F8G08ABABAWP配置*/
#define CONFIG_SYS_NAND_PAGE_SIZE       4096
#define CONFIG_SYS_NAND_OOBSIZE         224
#define CONFIG_SYS_NAND_BLOCK_SIZE      (512*1024)
/* NAND: driver related configs */
#define CONFIG_SYS_NAND_BAD_BLOCK_POS   NAND_LARGE_BADBLOCK_POS
#define CONFIG_SYS_NAND_ECCPOS  { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\
                                        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, \
                                        28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,\
					40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,\
                                        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\
                                        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,\
                                        76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,\
                                        88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,\
                                        100, 101, 102, 103, 104, 105, 106, 107, 108, 109,\
                                        110, 111, 112, 113, 114, 115, 116, 117, 118, 119,\
                                        120, 121, 122, 123, 124, 125, 126, 127, 128, 129,\
                                        130, 131, 132, 133, 134, 135, 136, 137, 138, 139,\
                                        140, 141, 142, 143, 144, 145, 146, 147, 148, 149,\
                                        150, 151, 152, 153, 154, 155, 156, 157, 158, 159,\
                                        160, 161, 162, 163, 164, 165, 166, 167, 168, 169,\
                                        170, 171, 172, 173, 174, 175, 176, 177, 178, 179,\
                                        180, 181, 182, 183, 184, 185, 186, 187, 188, 189,\
                                        190, 191, 192, 193, 194, 195, 196, 197, 198, 199,\
                                        200, 201, 202, 203, 204, 205, 206, 207, 208, 209, }

#define CONFIG_SYS_NAND_ECCSIZE 512
#define CONFIG_SYS_NAND_ECCBYTES 26
#define CONFIG_SYS_NAND_ONFI_DETECTION
#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_BCH16_CODE_HW

#else
/MX60LF8G18AC配置/
#define CONFIG_SYS_NAND_PAGE_SIZE 2048
#define CONFIG_SYS_NAND_OOBSIZE 64
#define CONFIG_SYS_NAND_BLOCK_SIZE (128*1024)

/* NAND: driver related configs */
#define CONFIG_SYS_NAND_BAD_BLOCK_POS NAND_LARGE_BADBLOCK_POS
#define CONFIG_SYS_NAND_ECCPOS { 2, 3, 4, 5, 6, 7, 8, 9, </span>
10, 11, 12, 13, 14, 15, 16, 17, </span>
18, 19, 20, 21, 22, 23, 24, 25, </span>
26, 27, 28, 29, 30, 31, 32, 33, </span>
34, 35, 36, 37, 38, 39, 40, 41, </span>
42, 43, 44, 45, 46, 47, 48, 49, </span>
50, 51, 52, 53, 54, 55, 56, 57, }

#define CONFIG_SYS_NAND_ECCSIZE 512
#define CONFIG_SYS_NAND_ECCBYTES 14
#define CONFIG_SYS_NAND_ONFI_DETECTION
#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_BCH8_CODE_HW
#endif
#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x00200000
/* NAND: SPL related configs /
#ifdef CONFIG_SPL_OS_BOOT
#define CONFIG_SYS_NAND_SPL_KERNEL_OFFS 0x00600000 / kernel offset /
#endif
#endif / !CONFIG_NAND */

做完上面修改后可以重新烧写,我的两块板子都可以正常启动。
4.下面以MT29F8G08ABABAWP为例,介绍一下如何通过芯片手册获取到上面头文件中宏的值及意义。
先看一下MT29F8G08ABABAWP的存储结构:

存储结构
可以看到单颗芯片的总容量是8640Mb=1080MB(为啥是1080MB呢?后面再说),里面有包含了两个plane(plane0,plane1),每个plane中又包含1024个blocks,每个block中又包含128个page。按照NAND读、写、擦出的操作要求,擦操作最小单位为一个block,读写操作最小单位为一个page,且写操作之前必须要先进行擦除操作。因此一个最小的操作单位是一个block(这里就解释了上面为啥NAND.SPL分区是128K时在MT29F8G08ABABAWP会提示对齐错误的原因了),整个block中产生任何一处不可修复的位错误,我们就认为这个块是坏块。

Page:MT29F8G08ABABAWP中一个page的大小为4K+224B,其中4K是数据区,224B是OOB区。其中oob区域的前两个字节用户坏块管理。

Block:MT29F8G08ABABAWP中一个block的大小为512K+28K,其中512K是所有页数据区的总和,28K是所有oob区的总和。

因为MT29F8G08ABABAWP每一个页都包含224B的OOB区域,所以最终所有的oob去加起来就是为啥1GB的nand最后算出来的总空间却是1080MB的原因。

宏参数的确定:

#define CONFIG_SYS_NAND_PAGE_SIZE       4096 //page中不包含OOB区域的大小 4K
#define CONFIG_SYS_NAND_OOBSIZE         224 //page中OOB区域的大小 224Bytes
#define CONFIG_SYS_NAND_BLOCK_SIZE      (512*1024) //block的大小,不包含OOB区域, 512K
#define CONFIG_SYS_NAND_BAD_BLOCK_POS   NAND_LARGE_BADBLOCK_POS //OOB区中标识是否坏块的位置,一般位于前两个字节。
/*下面CONFIG_SYS_NAND_ECCPOS定义的是一个数组,记录OOB区中用于存放ECC校验结果的位置,
因前两个字节被用于坏块标识,所以这里从2开始,只有为啥没到224(oob size)后面还留了几个字节,我也不清楚,晓得的伙伴评论区留言。*/
#define CONFIG_SYS_NAND_ECCPOS  { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\
                                        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, \
                                        28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,\
					40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,\
                                        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\
                                        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,\
                                        76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,\
                                        88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,\
                                        100, 101, 102, 103, 104, 105, 106, 107, 108, 109,\
                                        110, 111, 112, 113, 114, 115, 116, 117, 118, 119,\
                                        120, 121, 122, 123, 124, 125, 126, 127, 128, 129,\
                                        130, 131, 132, 133, 134, 135, 136, 137, 138, 139,\
                                        140, 141, 142, 143, 144, 145, 146, 147, 148, 149,\
                                        150, 151, 152, 153, 154, 155, 156, 157, 158, 159,\
                                        160, 161, 162, 163, 164, 165, 166, 167, 168, 169,\
                                        170, 171, 172, 173, 174, 175, 176, 177, 178, 179,\
                                        180, 181, 182, 183, 184, 185, 186, 187, 188, 189,\
                                        190, 191, 192, 193, 194, 195, 196, 197, 198, 199,\
                                        200, 201, 202, 203, 204, 205, 206, 207, 208, 209, }
#define CONFIG_NAND_OMAP_ECCSCHEME      OMAP_ECC_BCH16_CODE_HW //校验方式

#define CONFIG_SYS_NAND_ECCSIZE 512 //标识多长字节进行一次ECC校验

#define CONFIG_SYS_NAND_ECCBYTES 26 //是每次计算ECC产生校验码的字节数,取值参考下表:

在这里插入图片描述
这里说一下CONFIG_NAND_OMAP_ECCSCHEME宏,这个宏是根据什么选择是那种校验方式的呢?在am35x的手册中关于sysboot[9]的作用做了以下描述“for ANND and NANDI2C boot:NAND ECC For fast external boot:must be 0b”,“0=ECC done by ROM 1=handled by NAND”,可以看出当sysboot[9]设置下拉时(我的硬件就是下拉)当ROM中的固件读取NAND中MLO阶段程序时,会采用ROM固件中定义的校验方式来进行校验。而MT29F8G08ABABAWP采用的是BCH16,MX60LF8G18AC采用的是BCH8。另外在uboot中读NAND的数据,如果选择的校验方式和之前写入是的校验方式不同,就会提示ECC的错误。
另外测试验证过程中在给NAND.SPL写入MLO文件的时候,提示“Size of write exceeds partition or device limit 0 bytes written: ERROR”,这个情况是因为NAND.SPL大小刚好分配的是一个block的大小,当这个block内有地址不能读写时会被标记为坏块,从而导致NAND.SPL分区不能被读写,导致上面写错误。这一点也刚好验证nand是以block为最小操作单元的事实,对于nand坏块的查看可以通过nand bad或者nand erase.chip查看,注意第二个命令会擦除芯片。另外NAND读写时在遇到坏块会自动避开,所以如果NAND.SPL坏块就会自动跳到下一个分区NAND.SPL.backup1中读取,鉴于这一点可以多定义几个备份区,当有坏块是可以从下一个备份区启动。
在这里插入图片描述

注意:这里修改了分区校验方式,在内核移植过程中也需要在dts中修改分区和校验方式。

5.最后就是配置头文件中的环境变量信息,使其启动后能自动拉起内核不运行。这里在不做分析,具体的照着官方给的copy过来就行。到此uboot中NAND的移植过程完成。

下面是一些移植过程中参考的文档,还有部分文档未一一列出,再次对这些无私的贡献者表示感谢。
参考文档:
https://blog.csdn.net/ccwzhu/article/details/109605076
https://blog.csdn.net/qq_41882586/article/details/123232813

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值