一、问题定位

  

  开发板重启后打印了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的更多相关文章

  1. u-boot移植(十二)---代码修改---支持DM9000网卡

    一.准备工作 1.1 原理图 CONFIG_DM9000_BASE 片选信号是接在nGCS4引脚,若要确定网卡的基地址,则要根据片选信号的接口去确定. 在三星2440的DATASHEET中memory ...

  2. -boot移植(十一)---代码修改---支持nandflash

    一.移植前的修改 1.1 include/configs/jz2440修改 原来的定义: 可以看出,要先定义CONFIG_CMD_NAND才能使能NANDFlash. 这个在我们文件中的82行有定义, ...

  3. U-Boot在FL2440上移植(三)----支持NAND Flash

    <一>支持NAND Flash 1. 首先在配置文件 include/config/fl2440.h 的宏 CONFIG_COMMANDS 中增加 CFG_CMD_NAND, #defin ...

  4. U-Boot在FL2440上移植(二)----支持NOR Flash

    <一>选择NOR flash型号 我的开发板上的nor flash芯片是Intel的JS28F320(4MB)(1device=32blocks,1block=128MB fl2440默认 ...

  5. u-boot移植(十三)---代码修改---支持文件系统及补丁制作

    一.烧写文件系统 1.1 jffs2烧写 1.下载文件系统:tftp 30000000 fs_mini_mdev.jffs2 2.擦除文件的块:nand erase.part rootfs 3.烧入文 ...

  6. spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法

    spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法 前言 本篇接着<spring boot / cloud ...

  7. Spring Boot(二十):使用spring-boot-admin对spring-boot服务进行监控

    Spring Boot(二十):使用spring-boot-admin对spring-boot服务进行监控 Spring Boot Actuator提供了对单个Spring Boot的监控,信息包含: ...

  8. 标题:u-boot 移植步骤详解

    1 U-Boot简介U-Boot,全称Universal Boot Loader,是遵循GPL条款的开放源码项目.从FADSROM.8xxROM.PPCBOOT逐步发展演化而来.其源码目录.编译形式与 ...

  9. spring boot / cloud (十六) 分布式ID生成服务

    spring boot / cloud (十六) 分布式ID生成服务 在几乎所有的分布式系统或者采用了分库/分表设计的系统中,几乎都会需要生成数据的唯一标识ID的需求, 常规做法,是使用数据库中的自动 ...

随机推荐

  1. PP学习笔记02

    SPRO SAP参考IMG MM03 物料视图 生产计划编制 需求管理 已计划的独立需求 需求类型 策略组 定义策略 策略组 主要策略(独立需求 ) 客户需求类型 需求类 (计划标识符.消耗标识.需求 ...

  2. notepad编写html

    notepad写代码的过程: 1.打开notepad,新建一个文档,然后保存,文件的后缀名为.html,代码保存前界面上文件名称为红色,保存后蓝色: 2.保存为html后,进行代码的输入,如果设置好自 ...

  3. selenium之下载

    # 测试下载功能,保存文件到指定的目录 # 不同的浏览器配置是不同的,本例使用chrome浏览器 # author:gongxr # date:2017-07-25 import time from ...

  4. ACM-ICPC 2018 焦作赛区网络预赛 E Jiu Yuan Wants to Eat (树链剖分+线段树)

    题目链接:https://nanti.jisuanke.com/t/31714 题意:给你一棵树,初始全为0,有四种操作: 1.u-v乘x    2.u-v加x   3. u-v取反  4.询问u-v ...

  5. python numpy 数组拼接

    我就写一下我遇到的,更多具体的请看Python之Numpy数组拼接,组合,连接 >>> aarray([0, 1, 2],       [3, 4, 5],       [6, 7, ...

  6. Python的单向链表实现

    思路 链表由节点组成,先规定节点(Node),包含data和指向下个节点的next 初始化 data当然就是传入的data了,next指向None 添加 分两种情况: 链表为空,那么头节点和尾节点都指 ...

  7. SQLITE在IIS中使用问题

    在WEB中使用这个数据库时,System.Data.SQLite.dll 这个经常会出问题 主要是版本问题,sqlite.DLL的版本要和Framework版本匹配 这是下载地址 http://www ...

  8. [AHOI2014/JSOI2014] 解题报告

    [AHOI2014/JSOI2014] 奇怪的计算器 一个很关键的结论,任何时候每个数的相对大小是不变的. 于是可以把这个相对大小当成线段树的权值,每次只需要维护一下区间极值和tag就好了,关于操作四 ...

  9. 洛谷 P2587 [ZJOI2008]泡泡堂 解题报告

    P2587 [ZJOI2008]泡泡堂 题目描述 第XXXX届NOI期间,为了加强各省选手之间的交流,组委会决定组织一场省际电子竞技大赛,每一个省的代表队由n名选手组成,比赛的项目是老少咸宜的网络游戏 ...

  10. [Cqoi2014]数三角形——组合数

    Description: 给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个.下图为4x4的网格上的一个三角形. 注意三角形的三点不能共线. Hint: 1<=m,n<=1000 ...