移植uboot之修改代码支持NorFlash记录
2017-12-16 23:26
627 查看
今天我们的任务是修改uboot源码支持NorFlash。
上两篇关于uboot移植的文章,我们修改了uboot源代码,支持了串口的输出,以及nand启动(点击连接可以查看上两面文章的相关内容移植uboot支持串口输出,移植uboot支持NAND启动)
同时分享一个很好的书:Linux设备驱动开发详解-宋宝华
(注:写到后面发现没有告诉大家用的flash芯片的型号,我们用的flash芯片的型号是:MX29LV160DB,芯片手册大家可以自行到网上下载,从中可以查看芯片的厂家ID和设备ID等信息)
我们移植uboot,都是一步一步调试而来,所以会比较繁琐,但是我觉得记录这些,是一件很有意义的事,虽然很麻烦,但是对将来,会有莫大的影响!!!
上次移植支持NAND后,串口启动界面如下:
我们在source insight中搜索“Flash:”这个字符串出现在哪里,在Board.c中的board_init_r函数中,有这样几行代码:
课件代码是执行到了这两行:
查看hang()这个函数为:
void hang(void)
{
puts(“### ERROR ### Please RESET the board ###\n”);
for (;;);
}
很明显,代码进入了一个死循环,所以无法启动uboot了。
回过头看上面的board_init_r函数里的flash_size = flash_init();,应该是flash的一个初始化,初始化后成功后才执行下面的if语句,很明显我们这里没有初始化成功。进入flash_init。查看代码如下(在drivers/mtd/Cfi_flash.c中):
里面有一个if判断语句:
从字面意思看出flash_detect_legacy为旧的检测flash,flash_get_size就应该为新的检测flash机制,先看一下旧的,没看出什么,再看flash_get_size,发现有很多debug调试信息,有这么多调试信息,那就应该用起来:
在flash_get_size中的debug信息
搜索debug 查到:
在include/common.h中有下面的代码
很明显应该是用的_DEBUG,搜索_DEBUG,有:
好,那么我们就把
重新编译uboot烧写启动看一下:
打印的这句话:JEDEC PROBE: ID c2 2249 0
告诉我们读到的厂家ID,设备ID,我们查看datasheet,发现这个读到的ID是没有错的,厂家ID是c2,设备ID是2249,
根据打印信息,在源码中搜索字符串“JEDEC PROBE:”在Cfi_flash.c中的flash_detect_legacy函数中有如下代码片段:
看出设备ID时如何打印的,下面的jedec_flash_match还需要进行一下匹配,我们去jedec_flash_match函数里看看是实现的什么内容(在drivers/mtd/jeder_flash.c中):
发现一个数组jedec_table,匹配设备的ID用的应该就是这个数组里的内容了,查看数组如下:
这个结构体里的内容,定义了许多类型的flash,每一个定义就是一个flash芯片。我们在里面自己定义我们的芯片结构项。
里面涉及到 的硬件操作,我会在之后的讲解NOR FLASH 驱动时,讲解如何操作这个芯片里面涉及到,在这里,我们移植uboot,只需要这样做就可以,暂时不需要追根究底(无底洞啊!!!)。
然后就是最开始忘记了一件事,就是把board.中的board_init_r中的两行代码(自己回头看上面的代码)屏蔽掉:
然后重新编译uboot,烧写启动运行:
哈哈哈!!!!先庆祝一下,终于启动进去了,虽然还没有完善,但是得一步一步来嘛!
显示有错误:ERROR: too many flash sectors,在源码中搜索这个错误找到(Cfi_flash.c中):
跳转到CONFIG_SYS_MAX_FLASH_SECT这个定义(在smdk2440.h中),有:
将19改为128吧:
然后再把我们之前加的Debug调试信息去掉,因为我们已经不需要那些打印信息了,去掉的话会看起来简洁一些,去掉下面的两个宏定义:
重新编译烧写,看启动界面:
这次启动界面比较简洁,而且上面出现的错误也没有了!!!
那我们现在来测试一下NORFLASH能否擦除与读写。
串口中输入:protect off all,先解除写保护
输入:flinfo,打印输出正常:
输入:erase 80000 8ffff
输入:cp.b 30000000 80000 10000 (把内存中30000000位置的内容拷贝到flash80000地址)
到了这里,出现了一些问题,无法将内存的代码拷贝过来,无法写flash。。。。。。。。。啊,天哪,感觉又得花时间去看了!!!
放到下一篇博客吧,这篇已经写了很多了!!!
想获得各种学习资源以及交流学习的加我:
qq:1126137994
微信:liu1126137994
可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题!
上两篇关于uboot移植的文章,我们修改了uboot源代码,支持了串口的输出,以及nand启动(点击连接可以查看上两面文章的相关内容移植uboot支持串口输出,移植uboot支持NAND启动)
同时分享一个很好的书:Linux设备驱动开发详解-宋宝华
(注:写到后面发现没有告诉大家用的flash芯片的型号,我们用的flash芯片的型号是:MX29LV160DB,芯片手册大家可以自行到网上下载,从中可以查看芯片的厂家ID和设备ID等信息)
我们移植uboot,都是一步一步调试而来,所以会比较繁琐,但是我觉得记录这些,是一件很有意义的事,虽然很麻烦,但是对将来,会有莫大的影响!!!
上次移植支持NAND后,串口启动界面如下:
我们在source insight中搜索“Flash:”这个字符串出现在哪里,在Board.c中的board_init_r函数中,有这样几行代码:
#if !defined(CONFIG_SYS_NO_FLASH) puts("Flash: "); flash_size = flash_init(); if (flash_size > 0) { # ifdef CONFIG_SYS_FLASH_CHECKSUM char *s = getenv("flashchecksum"); 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 (s && (*s == 'y')) { 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("0 KB\n\r"); puts(failed); hang(); } #endif
课件代码是执行到了这两行:
puts(failed); hang();
查看hang()这个函数为:
void hang(void)
{
puts(“### ERROR ### Please RESET the board ###\n”);
for (;;);
}
很明显,代码进入了一个死循环,所以无法启动uboot了。
回过头看上面的board_init_r函数里的flash_size = flash_init();,应该是flash的一个初始化,初始化后成功后才执行下面的if语句,很明显我们这里没有初始化成功。进入flash_init。查看代码如下(在drivers/mtd/Cfi_flash.c中):
unsigned long flash_init (void) { unsigned long size = 0; int i; #ifdef CONFIG_SYS_FLASH_PROTECTION /* read environment from EEPROM */ char s[64]; getenv_f("unlock", s, sizeof(s)); #endif /* Init: no FLASHes known */ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) { flash_info[i].flash_id = FLASH_UNKNOWN; /* Optionally write flash configuration register */ cfi_flash_set_config_reg(cfi_flash_bank_addr(i), cfi_flash_config_reg(i)); if (!flash_detect_legacy(cfi_flash_bank_addr(i), i)) flash_get_size(cfi_flash_bank_addr(i), i); size += flash_info[i].size; if (flash_info[i].flash_id == FLASH_UNKNOWN) { #ifndef CONFIG_SYS_FLASH_QUIET_TEST printf ("## Unknown flash on Bank %d " "- Size = 0x%08lx = %ld MB\n", i+1, flash_info[i].size, flash_info[i].size >> 20); #endif /* CONFIG_SYS_FLASH_QUIET_TEST */ } #ifdef CONFIG_SYS_FLASH_PROTECTION else if ((s != NULL) && (strcmp(s, "yes") == 0)) { /* * Only the U-Boot image and it's environment * is protected, all other sectors are * unprotected (unlocked) if flash hardware * protection is used (CONFIG_SYS_FLASH_PROTECTION) * and the environment variable "unlock" is * set to "yes". */ if (flash_info[i].legacy_unlock) { int k; /* * Disable legacy_unlock temporarily, * since flash_real_protect would * relock all other sectors again * otherwise. */ flash_info[i].legacy_unlock = 0; /* * Legacy unlocking (e.g. Intel J3) -> * unlock only one sector. This will * unlock all sectors. */ flash_real_protect (&flash_info[i], 0, 0); flash_info[i].legacy_unlock = 1; /* * Manually mark other sectors as * unlocked (unprotected) */ for (k = 1; k < flash_info[i].sector_count; k++) flash_info[i].protect[k] = 0; } else { /* * No legancy unlocking -> unlock all sectors */ flash_protect (FLAG_PROTECT_CLEAR, flash_info[i].start[0], flash_info[i].start[0] + flash_info[i].size - 1, &flash_info[i]); } } #endif /* CONFIG_SYS_FLASH_PROTECTION */ } flash_protect_default(); #ifdef CONFIG_FLASH_CFI_MTD cfi_mtd_init(); #endif return (size); }
里面有一个if判断语句:
if (!flash_detect_legacy(cfi_flash_bank_addr(i), i)) flash_get_size(cfi_flash_bank_addr(i), i);
从字面意思看出flash_detect_legacy为旧的检测flash,flash_get_size就应该为新的检测flash机制,先看一下旧的,没看出什么,再看flash_get_size,发现有很多debug调试信息,有这么多调试信息,那就应该用起来:
在flash_get_size中的debug信息
debug ("manufacturer is %d\n", info->vendor); debug ("manufacturer id is 0x%x\n", info->manufacturer_id); debug ("device id is 0x%x\n", info f1ed ->device_id); debug ("device id2 is 0x%x\n", info->device_id2); debug ("cfi version is 0x%04x\n", info->cfi_version);
搜索debug 查到:
在include/common.h中有下面的代码
#define debug(fmt, args...) \ debug_cond(_DEBUG, fmt, ##args)
很明显应该是用的_DEBUG,搜索_DEBUG,有:
#ifdef DEBUG #define _DEBUG 1 #else #define _DEBUG 0 #endif
好,那么我们就把
#define _DEBUG 1给加上,在Cfi_flash.c中定义如下两行:
#define DEBUG 1 (不确定是哪个就都定义,反正也不会出错) #define _DEBUG 1
重新编译uboot烧写启动看一下:
打印的这句话:JEDEC PROBE: ID c2 2249 0
告诉我们读到的厂家ID,设备ID,我们查看datasheet,发现这个读到的ID是没有错的,厂家ID是c2,设备ID是2249,
根据打印信息,在源码中搜索字符串“JEDEC PROBE:”在Cfi_flash.c中的flash_detect_legacy函数中有如下代码片段:
debug("JEDEC PROBE: ID %x %x %x\n", info->manufacturer_id, info->device_id, info->device_id2); if (jedec_flash_match(info, info->start[0])) break; else unmap_physmem((void *)info->start[0], MAP_NOCACHE);
看出设备ID时如何打印的,下面的jedec_flash_match还需要进行一下匹配,我们去jedec_flash_match函数里看看是实现的什么内容(在drivers/mtd/jeder_flash.c中):
/*----------------------------------------------------------------------- * match jedec ids against table. If a match is found, fill flash_info entry */ int jedec_flash_match(flash_info_t *info, ulong base) { int ret = 0; int i; ulong mask = 0xFFFF; if (info->chipwidth == 1) mask = 0xFF; for (i = 0; i < ARRAY_SIZE(jedec_table); i++) { if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) && (jedec_table[i].dev_id & mask) == (info->device_id & mask)) { fill_info(info, &jedec_table[i], base); ret = 1; break; } } return ret; }
发现一个数组jedec_table,匹配设备的ID用的应该就是这个数组里的内容了,查看数组如下:
static const struct amd_flash_info jedec_table[] = { #ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8 { .mfr_id = (u16)SST_MANUFACT, .dev_id = SST39LF020, .name = "SST 39LF020", .uaddr = { [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ }, .DevSize = SIZE_256KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x01000,64), } }, 。。。。。 。。。。。 (还有很多跟上面相同的类型的内容,我这里给省略了)
这个结构体里的内容,定义了许多类型的flash,每一个定义就是一个flash芯片。我们在里面自己定义我们的芯片结构项。
/* jz2440使用的是MX29LV160DB芯片 */ { .mfr_id = (u16)MX_MANUFACT, /*厂家ID*/ .dev_id = 0x2249, /*设备ID*/ .name = "MXIC MX29LV160DB", .uaddr = { /*NOR FLASH看到的解锁地址*/ [0] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_2MiB, /* 总大小 */ .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 4, /* 擦除区域的数目 */ .regions = { /* 这些内容涉及芯片手册的阅读,之后的文章会单独写关于硬件的操作 */ ERASEINFO(16*1024, 1), ERASEINFO(8*1024, 2), ERASEINFO(32*1024, 1), ERASEINFO(64*1024, 31), } },
里面涉及到 的硬件操作,我会在之后的讲解NOR FLASH 驱动时,讲解如何操作这个芯片里面涉及到,在这里,我们移植uboot,只需要这样做就可以,暂时不需要追根究底(无底洞啊!!!)。
然后就是最开始忘记了一件事,就是把board.中的board_init_r中的两行代码(自己回头看上面的代码)屏蔽掉:
//puts(failed); //hang();
然后重新编译uboot,烧写启动运行:
哈哈哈!!!!先庆祝一下,终于启动进去了,虽然还没有完善,但是得一步一步来嘛!
显示有错误:ERROR: too many flash sectors,在源码中搜索这个错误找到(Cfi_flash.c中):
if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) { printf("ERROR: too many flash sectors\n"); break; }
跳转到CONFIG_SYS_MAX_FLASH_SECT这个定义(在smdk2440.h中),有:
#define CONFIG_SYS_MAX_FLASH_SECT (19)
将19改为128吧:
#define CONFIG_SYS_MAX_FLASH_SECT (128)
然后再把我们之前加的Debug调试信息去掉,因为我们已经不需要那些打印信息了,去掉的话会看起来简洁一些,去掉下面的两个宏定义:
//#define DEBUG 1 //#define _DEBUG 1
重新编译烧写,看启动界面:
这次启动界面比较简洁,而且上面出现的错误也没有了!!!
那我们现在来测试一下NORFLASH能否擦除与读写。
串口中输入:protect off all,先解除写保护
输入:flinfo,打印输出正常:
输入:erase 80000 8ffff
输入:cp.b 30000000 80000 10000 (把内存中30000000位置的内容拷贝到flash80000地址)
到了这里,出现了一些问题,无法将内存的代码拷贝过来,无法写flash。。。。。。。。。啊,天哪,感觉又得花时间去看了!!!
放到下一篇博客吧,这篇已经写了很多了!!!
想获得各种学习资源以及交流学习的加我:
qq:1126137994
微信:liu1126137994
可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题!
相关文章推荐
- 移植uboot之修改代码支持NorFlash记录续集二
- 移植u-boot-2015.07-rc3之修改代码支持NorFlash(四)
- 移植u-boot-2015.07-rc3之修改代码支持NorFlash启动并真正支持NorFlash读写(五)
- 移植u-boot-2015.07-rc3之修改代码支持DM9000网卡(七)
- 移植uboot之修改代码支持NorFlash记录续集
- 移植u-boot-2015.07-rc3之修改代码支持mtdparts命令(八)
- 移植u-boot学习笔记6-----修改代码支持nor flash
- 移植u-boot-2015.07-rc3之修改代码支持yaffs文件系统烧写(十)
- 移植u-boot-2015.07-rc3之修改代码支持SDRAM和SPL启动(二)
- u-boot移植(十)---代码修改---支持nor flash
- u-boot移植(十二)---代码修改---支持DM9000网卡
- 移植u-boot学习笔记7-----修改代码之支持nand flash
- 移植u-boot-2015.07-rc3之修改代码支持串口(三)
- 移植u-boot-2012.04.01到jz2440开发板之修改代码支持NAND启动
- u-boot移植(十三)---代码修改---支持文件系统及补丁制作
- jz2440开发板移植U-boot之修改代码支持DM9000网卡
- 移植u-boot学习笔记8-----修改代码之支持DM9000网卡
- 移植u-boot-2015.07-rc3之修改代码支持NandFlash(六)
- l 移植u-boot之修改代码支持DM9000网卡-3.5
- u-boot移植(十二)---代码修改---支持DM9000网卡