u-boot移植(十)---代码修改---支持nor flash
一、问题定位
开发板重启后打印了2个提醒和一个错误,caches的提醒先不看,看看flash和nand下面的提醒,bad CRC,Using default enviroment,我们可以定位Using default enviroment定位到
代码位置,如下:
Env_common.c (common)
传入的参数应该是 !badCRC,再次定位函数set_default_env 看是在哪里调用此函数:
基本上文件都在common文件夹下,有common中的调用和 dataflash,nand,sf,ubi。暂且不知道是哪个,要看看u-boot.dis中哪里调用了这个函数,再来定位了。
通过u-boot.dis 可以知道,在几个函数中调用了 set_default_env 这个函数:
- env_import:Env_common.c (common)
- env_relocate:Env_common.c (common)
- do_env_default:Cmd_nvedit.c (common)
二、代码分析
搜索 Flash: 查看结果:
与此相匹配的为 board_r.c 文件中。
定位到 board_r.c(common)中的 initr_flash 函数。
此函数定义在第二阶段代码 board_init_r 函数中的 init_sequence_r 链表中:
2.1 initr_flash
initr_flash 函数的代码解读如下:
- #if !defined(CONFIG_SYS_NO_FLASH) //未定义CONFIG_SYS_NO_FLASH这个宏就执行此函数
- static int initr_flash(void)
- {
- ulong flash_size = ; //定义存储 flash 空间大小的变量
- bd_t *bd = gd->bd; //定义板信息结构体
- puts("Flash: "); //输出字符串 Flash:
- if (board_flash_wp_on()) //此为空函数,返回0值,直接执行 else后面的语句
- printf("Uninitialized - Write Protect On\n");
- else
- flash_size = flash_init(); //flash初始化
- print_size(flash_size, ""); //打印flash_size的大小
- #ifdef CONFIG_SYS_FLASH_CHECKSUM //此宏在 include/configs/jz2440.h 未定义 里面的一段代码不执行
- /*
- * Compute and print flash CRC if flashchecksum is set to 'y'
- *
- * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
- */
- if (getenv_yesno("flashchecksum") == ) {
- printf(" CRC: %08X", crc32(,
- (const unsigned char *) CONFIG_SYS_FLASH_BASE,
- flash_size));
- }
- #endif /* CONFIG_SYS_FLASH_CHECKSUM */
- putc('\n'); //换行
- /* update start of FLASH memory */
- /* CONFIG_SYS_FLASH_BASE 在 include/configs/jz2440.h中有定义
- * #define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1
- * #define PHYS_FLASH_1 0x00000000 // Flash Bank #0
- * 这里定义的宏的大小为0 则我们的CONFIG_SYS_FLASH_BASE 页的基地址为0
- */
- #ifdef CONFIG_SYS_FLASH_BASE
- bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; //bd->bi_flashstart = 0 从0地址开始执行
- #endif
- /* size of FLASH memory (final value) */
- bd->bi_flashsize = flash_size; //flash 的大小
- #if defined(CONFIG_SYS_UPDATE_FLASH_SIZE)
- /* Make a update of the Memctrl. */
- update_flash_size(flash_size); //更新flash 的大小
- #endif
- #if defined(CONFIG_OXC) || defined(CONFIG_RMU) //未定义,不执行
- /* flash mapped at end of memory map */
- bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size;
- /* #define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_FLASH_BASE
- * 从这里可以看出CONFIG_SYS_MONITOR_BASE与CONFIG_SYS_FLASH_BASE相等,
- * 则执行宏内语句
- */
- #elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
- bd->bi_flashoffset = monitor_flash_len; /* reserved area for monitor */
- #endif
- return ;
- }
- #endif
标记红色的语句就是我们在执行的语句。可以看出在flash 初始化后就打印出了 flash空间大小。
定位到 flash_init 中
2.2 flash_init
文件路径:Cfi_flash.c (drivers\mtd)
先去掉不必要的宏,代码精简一下。
- unsigned long flash_init (void)
- {
- unsigned long size = ;
- int i;
- /* Init: no FLASHes known */
- /* #define CONFIG_SYS_MAX_FLASH_BANKS 1 */
- /* include/configs/jz2440.h中有定义,为 1 */
- for (i = ; 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));
- /* 检测 flash
- * flash_detect_legacy 是旧的检测策略
- */
- 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) {
- }
- }
- flash_protect_default(); //flash的默认保护
- return (size);
- }
在第18行,看到 flash 检测,这里检测的是 flash 的信息和大小。可以进去看看源码
2.2.1 flash_detect_legacy
源码位置:Cfi_flash.c (drivers\mtd)
- #ifdef CONFIG_FLASH_CFI_LEGACY // include/configs/jz2440.h 中有定义
- /* 读取flash 的产品信息 */
- static void flash_read_jedec_ids (flash_info_t * info)
- {
- info->manufacturer_id = ;
- info->device_id = ;
- info->device_id2 = ;
- switch (info->vendor) {
- case CFI_CMDSET_INTEL_PROG_REGIONS:
- case CFI_CMDSET_INTEL_STANDARD:
- case CFI_CMDSET_INTEL_EXTENDED:
- cmdset_intel_read_jedec_ids(info);
- break;
- case CFI_CMDSET_AMD_STANDARD:
- case CFI_CMDSET_AMD_EXTENDED:
- cmdset_amd_read_jedec_ids(info);
- break;
- default:
- break;
- }
- }
- /*-----------------------------------------------------------------------
- * Call board code to request info about non-CFI flash.
- * board_flash_get_legacy needs to fill in at least:
- * info->portwidth, info->chipwidth and info->interface for Jedec probing.
- */
- static int flash_detect_legacy(phys_addr_t base, int banknum)
- {
- flash_info_t *info = &flash_info[banknum];
- /* 获得旧的 flash 信息,返回值为 0
- * info->portwidth = FLASH_CFI_16BIT; 0x02
- * info->chipwidth = FLASH_CFI_BY16; 0x02
- * info->interface = FLASH_CFI_X16; 0x01
- */
- if (board_flash_get_legacy(base, banknum, info)) {
- /* board code may have filled info completely. If not, we
- use JEDEC ID probing. */
- if (!info->vendor) {
- int modes[] = {
- CFI_CMDSET_AMD_STANDARD,
- CFI_CMDSET_INTEL_STANDARD
- };
- int i;
- for (i = ; i < ARRAY_SIZE(modes); i++) {
- info->vendor = modes[i];
- /* 映射物理地址 */
- info->start[] =
- (ulong)map_physmem(base,
- info->portwidth,
- MAP_NOCACHE);
- /* if中的语句不执行,前面已经设置 info->portwidth = FLASH_CFI_16BIT;*/
- if (info->portwidth == FLASH_CFI_8BIT
- && info->interface == FLASH_CFI_X8X16) {
- info->addr_unlock1 = 0x2AAA;
- info->addr_unlock2 = 0x5555;
- } else {/* 执行else 中的语句,发送 0x5555 0x2aaa命令 */
- info->addr_unlock1 = 0x5555;
- info->addr_unlock2 = 0x2AAA;
- }
- flash_read_jedec_ids(info);
- debug("JEDEC PROBE: ID %x %x %x\n",
- info->manufacturer_id,
- info->device_id,
- info->device_id2);
- /* 适配flash */
- if (jedec_flash_match(info, info->start[]))
- break;
- else
- unmap_physmem((void *)info->start[],
- info->portwidth);
- }
- }
- switch(info->vendor) {
- case CFI_CMDSET_INTEL_PROG_REGIONS:
- case CFI_CMDSET_INTEL_STANDARD:
- case CFI_CMDSET_INTEL_EXTENDED:
- info->cmd_reset = FLASH_CMD_RESET;
- break;
- case CFI_CMDSET_AMD_STANDARD:
- case CFI_CMDSET_AMD_EXTENDED:
- case CFI_CMDSET_AMD_LEGACY:
- info->cmd_reset = AMD_CMD_RESET;
- break;
- }
- info->flash_id = FLASH_MAN_CFI;
- return ;
- }
- return ; /* use CFI */
- }
- #else
- static inline int flash_detect_legacy(phys_addr_t base, int banknum)
- {
- return ; /* use CFI */
- }
- #endif
这里不知道是否执行,可以尝试debug 一下,要debug 首先要打开 debug 宏。在include/common.h的顶端加入debug 宏。 #define DEBUG 然后重新编译开机 打印的flash信息如下:
这里打印了两个 JEDEC PROBE,一个是在 flash_detect_legacy 中打印,还有是什么暂且不知道。
查看一下 norflash的ID,norflash的型号是MX29LV160DBTI 。
芯片手册的COMMAND OPERATIONS有如下几行:
上面这张图说明了如何去读ID,黄色部分为地址。即在555地址发出aa,在2AA地址发出55命令,在555地址发出90命令,则可以在00地址读出厂家ID c2。
2249 正好对应我们的设备ID号,看来是已经识别出来了 nor flash.
JEDEC PROBE在 flash_detect_legacy(Cfi_flash.c (drivers\mtd) )的debug 打印函数中,之后执行jedec_flash_match(info, info->start[0])去匹配。
在jedec_flash_match 会去匹配jedec_table数组,如果有,则返回1,没有则返回0。
2.2.2 jedec_flash_match
- int jedec_flash_match(flash_info_t *info, ulong base)
- {
- int ret = ;
- int i;
- ulong mask = 0xFFFF;
- if (info->chipwidth == )
- mask = 0xFF;
- for (i = ; 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 = ;
- break;
- }
- }
- return ret;
- }
查看 jedec_table (Jedec_flash.c (drivers\mtd) ),是否有 c2 2249 0 这些项。搜索后没有,则需要添加进设备信息。
厂家ID添加(Flash.h (include) ),已在头文件中存在。
搜索:
分别在两个地方引用了MX_MANUFACT的ID。
最上面的一个需要定义宏 CONFIG_SYS_FLASH_LEGACY_512Kx8 才可以引用
下面一个需要定义宏 CONFIG_SYS_FLASH_LEGACY_512Kx16 才能使用。CONFIG_SYS_FLASH_LEGACY_512Kx16 在jz2440中有定义。
两个可以匹配,但是dev_id 无匹配,仍需要添加。这两个宏也和我们的芯片不匹配,板子上所使用的芯片为 1M X 16的。
2.2.3 修改代码
jedec_table (Jedec_flash.c (drivers\mtd) )添加设备ID:
在jedec_table 添加设备信息:
- #ifdef CONFIG_SYS_FLASH_LEGACY_1Mx16
- /* JZ2440使用 */
- {
- .mfr_id = (u16)MX_MANUFACT, /* 厂家ID */
- .dev_id = MX29LV160DB, /* 设备ID */
- .name = "MXIC MX29LV160DB", /* 芯片名称 */
- .uaddr = { /* norflash看到的解锁地址,norflash可以像内存一样读,但写必须先解锁 */
- [] = MTD_UADDR_0x0555_0x02AA /* x16 */
- },
- .DevSize = SIZE_2MiB, /* 总空间大小 */
- .CmdSet = P_ID_AMD_STD,/* 命令集 */
- .NumEraseRegions= , /* norflash的擦除块 */
- .regions = {
- 14 ERASEINFO(0x04000, 1),
- 15 ERASEINFO(0x02000, 2),
- 16 ERASEINFO(0x08000, 1),
- 17 ERASEINFO(0x10000, 31),
- }
- },
- #endif
注意红色扇区部分按datesheet中的地址分布填写,不然显示的地址分布会不一样的。
在jz2440(include/configs)中修改CONFIG_SYS_FLASH_LEGACY_512Kx16宏为 CONFIG_SYS_FLASH_LEGACY_1Mx16
编译烧写测试,结果如下:
上面报了一个错:ERROR: too many flash sectors
搜索关键字定位到Jedec_flash.c (drivers\mtd)的fill_info函数,有如下打印调试信息:
定位CONFIG_SYS_MAX_FLASH_SECT(flash的最大扇区),Jz2440.h (include\configs):
这里扇区定义的是19个,但是我们的norflash的扇区有 1+ 2 + 1 + 31 = 35个,改成128:
重新编译,打印输出信息:
norflash打印正常,已经正确添加进来了。
2.3 调试
执行命令:flinfo
没问题了,就开始烧写字节进去测试数据是否完整(烧写之前,最好把DEBUG给关掉,然后重新编译烧写,否则会有大量的打印信息出来):
取消写保护:
擦除80000--90000之间的区域:
拷贝DRAM中的数据进norflash:
DRAM 30000000处的数据:
norflash 80000处的数据:
比较两者之间的数据:
里面有个问题, byte at 0x30000654 (0x20) != byte at 0x00080654 (0x0)
这里主要是在u-boot启动初始化后,栈未设置的原因,源代码位置为 crt0.S中。我们设置的栈指向0x30000f40,但是进行初始化后,未在设置栈,那么栈依然还是指向0x30000f40这快位置。
需要把栈改到指向gd->start_addr_sp,这个变量最后的值在reserve_stacks函数中,board_init_f 中。
reserve_stacks调用arch_reserve_stacks(Stack.c (arch\arm\lib) )函数进行栈设置,代码如下:
- int arch_reserve_stacks(void)
- {
- /* setup stack pointer for exceptions */
- gd->irq_sp = gd->start_addr_sp;
- # if !defined(CONFIG_ARM64)
- /* leave 3 words for abort-stack, plus 1 for alignment */
- gd->start_addr_sp -= ;
- # endif
- return ;
- }
我们要获得栈的值,就需要在crt0.S中修改代码,需要在第二阶段重新设置栈。
gd->start_addr_sp的值为gd->relocaddr
在crt0.S中定义全局变量:
此问题尚未解决,有解决方法了再修改此文件。
u-boot移植(十)---代码修改---支持nor flash的更多相关文章
- u-boot移植(十二)---代码修改---支持DM9000网卡
一.准备工作 1.1 原理图 CONFIG_DM9000_BASE 片选信号是接在nGCS4引脚,若要确定网卡的基地址,则要根据片选信号的接口去确定. 在三星2440的DATASHEET中memory ...
- -boot移植(十一)---代码修改---支持nandflash
一.移植前的修改 1.1 include/configs/jz2440修改 原来的定义: 可以看出,要先定义CONFIG_CMD_NAND才能使能NANDFlash. 这个在我们文件中的82行有定义, ...
- U-Boot在FL2440上移植(三)----支持NAND Flash
<一>支持NAND Flash 1. 首先在配置文件 include/config/fl2440.h 的宏 CONFIG_COMMANDS 中增加 CFG_CMD_NAND, #defin ...
- U-Boot在FL2440上移植(二)----支持NOR Flash
<一>选择NOR flash型号 我的开发板上的nor flash芯片是Intel的JS28F320(4MB)(1device=32blocks,1block=128MB fl2440默认 ...
- u-boot移植(十三)---代码修改---支持文件系统及补丁制作
一.烧写文件系统 1.1 jffs2烧写 1.下载文件系统:tftp 30000000 fs_mini_mdev.jffs2 2.擦除文件的块:nand erase.part rootfs 3.烧入文 ...
- spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法
spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法 前言 本篇接着<spring boot / cloud ...
- Spring Boot(二十):使用spring-boot-admin对spring-boot服务进行监控
Spring Boot(二十):使用spring-boot-admin对spring-boot服务进行监控 Spring Boot Actuator提供了对单个Spring Boot的监控,信息包含: ...
- 标题:u-boot 移植步骤详解
1 U-Boot简介U-Boot,全称Universal Boot Loader,是遵循GPL条款的开放源码项目.从FADSROM.8xxROM.PPCBOOT逐步发展演化而来.其源码目录.编译形式与 ...
- spring boot / cloud (十六) 分布式ID生成服务
spring boot / cloud (十六) 分布式ID生成服务 在几乎所有的分布式系统或者采用了分库/分表设计的系统中,几乎都会需要生成数据的唯一标识ID的需求, 常规做法,是使用数据库中的自动 ...
随机推荐
- SourceTree 如何下载git 管理的代码-如何创建分支,删除分支,提交代码,回退代码
把用户给的链接拿过来,然后输入浏览器,然后在左侧会有Actions 中有个Clone;点击Clone之后,有个 Clone in Source Tree 点击,打开你的本地Source Tree,然后 ...
- js 实现List
js 实现List 列表是一组有序的数据.每个列表中的数据项称为元素.在 JavaScript 中,列表中的元素可以是任意数据类型. 我们可以根据数组的特性来实现List. List 抽象数据类型定义 ...
- python 模块之-re
就其本质而言,正则表达式(或 RE)是一种小型的.高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现.正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹 ...
- BZOJ3963 WF2011MachineWorks(动态规划+斜率优化+cdq分治)
按卖出时间排序后,设f[i]为买下第i台机器后的当前最大收益,则显然有f[i]=max{f[j]+gj*(di-dj-1)+rj-pi},且若此值<0,应设为-inf以表示无法购买第i台机器. ...
- Leetcode 26.删除排序数组中的重复项 By Python
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成. 示例 1 ...
- emwin之点击窗口的无效部分来实现一些功能
@2018-07-27 触摸屏幕窗口的无效部分实现 Dropdown 部件的折叠操作 > 具体代码 case WM_TOUCH: if (pMsg->Data.p) // Somethin ...
- 修复Mysql主从不同步shell
使用第三方工具MySQL Enterprise Monitor,MySQL企业版监控工具.MONyog – MySQL Monior and Advisor,MONyog大家都不陌生,windows下 ...
- JS数组冒泡排序&去重
冒泡排序: var a = [2,1,4,3,6,5]; for(var d = 0 ; d< a.length; d++){ for(var b = d+1; b < a.length; ...
- 【UVA10140】Prime Distance
题目大意:求出一个给定区间 [l, r] 内相邻素数之间的最大距离和最小距离. 题解:由于 l, r 的范围太大,没法直接用筛法得出区间的素数.考虑筛出区间的素数等价于筛掉区间内的所有和数, 根据算术 ...
- (转)sublime text3简体中文版汉化教程
preferens——package controller——输入 install package——等待安装完成后输入 localizationChinese 请使用主菜单的 帮助/Language ...