关键词:
一、问题定位
开发板重启后打印了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 函数的代码解读如下:
1 #if !defined(CONFIG_SYS_NO_FLASH) //未定义CONFIG_SYS_NO_FLASH这个宏就执行此函数
2 static int initr_flash(void)
3 {
4 ulong flash_size = 0; //定义存储 flash 空间大小的变量
5 bd_t *bd = gd->bd; //定义板信息结构体
6
7 puts("Flash: "); //输出字符串 Flash:
8
9 if (board_flash_wp_on()) //此为空函数,返回0值,直接执行 else后面的语句
10 printf("Uninitialized - Write Protect On\n");
11 else
12 flash_size = flash_init(); //flash初始化
13
14 print_size(flash_size, ""); //打印flash_size的大小
15 #ifdef CONFIG_SYS_FLASH_CHECKSUM //此宏在 include/configs/jz2440.h 未定义 里面的一段代码不执行
16 /*
17 * Compute and print flash CRC if flashchecksum is set to 'y'
18 *
19 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
20 */
21 if (getenv_yesno("flashchecksum") == 1) {
22 printf(" CRC: %08X", crc32(0,
23 (const unsigned char *) CONFIG_SYS_FLASH_BASE,
24 flash_size));
25 }
26 #endif /* CONFIG_SYS_FLASH_CHECKSUM */
27 putc('\n'); //换行
28
29 /* update start of FLASH memory */
30 /* CONFIG_SYS_FLASH_BASE 在 include/configs/jz2440.h中有定义
31 * #define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1
32 * #define PHYS_FLASH_1 0x00000000 // Flash Bank #0
33 * 这里定义的宏的大小为0 则我们的CONFIG_SYS_FLASH_BASE 页的基地址为0
34 */
35 #ifdef CONFIG_SYS_FLASH_BASE
36 bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; //bd->bi_flashstart = 0 从0地址开始执行
37 #endif
38 /* size of FLASH memory (final value) */
39 bd->bi_flashsize = flash_size; //flash 的大小
40
41 #if defined(CONFIG_SYS_UPDATE_FLASH_SIZE)
42 /* Make a update of the Memctrl. */
43 update_flash_size(flash_size); //更新flash 的大小
44 #endif
45
46
47 #if defined(CONFIG_OXC) || defined(CONFIG_RMU) //未定义,不执行
48 /* flash mapped at end of memory map */
49 bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size;
50 /* #define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_FLASH_BASE
51 * 从这里可以看出CONFIG_SYS_MONITOR_BASE与CONFIG_SYS_FLASH_BASE相等,
52 * 则执行宏内语句
53 */
54 #elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
55 bd->bi_flashoffset = monitor_flash_len; /* reserved area for monitor */
56 #endif
57 return 0;
58 }
59 #endif
标记红色的语句就是我们在执行的语句。可以看出在flash 初始化后就打印出了 flash空间大小。
定位到 flash_init 中
2.2 flash_init
文件路径:Cfi_flash.c (drivers\mtd)
先去掉不必要的宏,代码精简一下。
1 unsigned long flash_init (void)
2 {
3 unsigned long size = 0;
4 int i;
5
6 /* Init: no FLASHes known */
7 /* #define CONFIG_SYS_MAX_FLASH_BANKS 1 */
8 /* include/configs/jz2440.h中有定义,为 1 */
9 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
10 flash_info[i].flash_id = FLASH_UNKNOWN;
11
12 /* Optionally write flash configuration register */
13 cfi_flash_set_config_reg(cfi_flash_bank_addr(i),
14 cfi_flash_config_reg(i));
15 /* 检测 flash
16 * flash_detect_legacy 是旧的检测策略
17 */
18 if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
19 flash_get_size(cfi_flash_bank_addr(i), i);
20 size += flash_info[i].size;
21 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
22 }
23 }
24
25 flash_protect_default(); //flash的默认保护
26 return (size);
27 }
在第18行,看到 flash 检测,这里检测的是 flash 的信息和大小。可以进去看看源码
2.2.1 flash_detect_legacy
源码位置:Cfi_flash.c (drivers\mtd)
1 #ifdef CONFIG_FLASH_CFI_LEGACY // include/configs/jz2440.h 中有定义
2 /* 读取flash 的产品信息 */
3 static void flash_read_jedec_ids (flash_info_t * info)
4 {
5 info->manufacturer_id = 0;
6 info->device_id = 0;
7 info->device_id2 = 0;
8
9 switch (info->vendor) {
10 case CFI_CMDSET_INTEL_PROG_REGIONS:
11 case CFI_CMDSET_INTEL_STANDARD:
12 case CFI_CMDSET_INTEL_EXTENDED:
13 cmdset_intel_read_jedec_ids(info);
14 break;
15 case CFI_CMDSET_AMD_STANDARD:
16 case CFI_CMDSET_AMD_EXTENDED:
17 cmdset_amd_read_jedec_ids(info);
18 break;
19 default:
20 break;
21 }
22 }
23
24 /*-----------------------------------------------------------------------
25 * Call board code to request info about non-CFI flash.
26 * board_flash_get_legacy needs to fill in at least:
27 * info->portwidth, info->chipwidth and info->interface for Jedec probing.
28 */
29 static int flash_detect_legacy(phys_addr_t base, int banknum)
30 {
31 flash_info_t *info = &flash_info[banknum];
32
33 /* 获得旧的 flash 信息,返回值为 0
34 * info->portwidth = FLASH_CFI_16BIT; 0x02
35 * info->chipwidth = FLASH_CFI_BY16; 0x02
36 * info->interface = FLASH_CFI_X16; 0x01
37 */
38 if (board_flash_get_legacy(base, banknum, info)) {
39 /* board code may have filled info completely. If not, we
40 use JEDEC ID probing. */
41 if (!info->vendor) {
42 int modes[] = {
43 CFI_CMDSET_AMD_STANDARD,
44 CFI_CMDSET_INTEL_STANDARD
45 };
46 int i;
47
48 for (i = 0; i < ARRAY_SIZE(modes); i++) {
49 info->vendor = modes[i];
50 /* 映射物理地址 */
51 info->start[0] =
52 (ulong)map_physmem(base,
53 info->portwidth,
54 MAP_NOCACHE);
55 /* if中的语句不执行,前面已经设置 info->portwidth = FLASH_CFI_16BIT;*/
56 if (info->portwidth == FLASH_CFI_8BIT
57 && info->interface == FLASH_CFI_X8X16) {
58 info->addr_unlock1 = 0x2AAA;
59 info->addr_unlock2 = 0x5555;
60 } else {/* 执行else 中的语句,发送 0x5555 0x2aaa命令 */
61 info->addr_unlock1 = 0x5555;
62 info->addr_unlock2 = 0x2AAA;
63 }
64 flash_read_jedec_ids(info);
65 debug("JEDEC PROBE: ID %x %x %x\n",
66 info->manufacturer_id,
67 info->device_id,
68 info->device_id2);
69 /* 适配flash */
70 if (jedec_flash_match(info, info->start[0]))
71 break;
72 else
73 unmap_physmem((void *)info->start[0],
74 info->portwidth);
75 }
76 }
77
78 switch(info->vendor) {
79 case CFI_CMDSET_INTEL_PROG_REGIONS:
80 case CFI_CMDSET_INTEL_STANDARD:
81 case CFI_CMDSET_INTEL_EXTENDED:
82 info->cmd_reset = FLASH_CMD_RESET;
83 break;
84 case CFI_CMDSET_AMD_STANDARD:
85 case CFI_CMDSET_AMD_EXTENDED:
86 case CFI_CMDSET_AMD_LEGACY:
87 info->cmd_reset = AMD_CMD_RESET;
88 break;
89 }
90 info->flash_id = FLASH_MAN_CFI;
91 return 1;
92 }
93 return 0; /* use CFI */
94 }
95 #else
96 static inline int flash_detect_legacy(phys_addr_t base, int banknum)
97 {
98 return 0; /* use CFI */
99 }
100 #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
1 int jedec_flash_match(flash_info_t *info, ulong base)
2 {
3 int ret = 0;
4 int i;
5 ulong mask = 0xFFFF;
6 if (info->chipwidth == 1)
7 mask = 0xFF;
8
9 for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {
10 if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&
11 (jedec_table[i].dev_id & mask) == (info->device_id & mask)) {
12 fill_info(info, &jedec_table[i], base);
13 ret = 1;
14 break;
15 }
16 }
17 return ret;
18 }
查看 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 添加设备信息:
1 #ifdef CONFIG_SYS_FLASH_LEGACY_1Mx16
2 /* JZ2440使用 */
3 {
4 .mfr_id = (u16)MX_MANUFACT, /* 厂家ID */
5 .dev_id = MX29LV160DB, /* 设备ID */
6 .name = "MXIC MX29LV160DB", /* 芯片名称 */
7 .uaddr = { /* norflash看到的解锁地址,norflash可以像内存一样读,但写必须先解锁 */
8 [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
9 },
10 .DevSize = SIZE_2MiB, /* 总空间大小 */
11 .CmdSet = P_ID_AMD_STD,/* 命令集 */
12 .NumEraseRegions= 4, /* norflash的擦除块 */
13 .regions = {
14 ERASEINFO(0x04000, 1),
15 ERASEINFO(0x02000, 2),
16 ERASEINFO(0x08000, 1),
17 ERASEINFO(0x10000, 31),
18 }
19 },
20 #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) )函数进行栈设置,代码如下:
1 int arch_reserve_stacks(void)
2 {
3 /* setup stack pointer for exceptions */
4 gd->irq_sp = gd->start_addr_sp;
5
6 # if !defined(CONFIG_ARM64)
7 /* leave 3 words for abort-stack, plus 1 for alignment */
8 gd->start_addr_sp -= 16;
9 # endif
10 return 0;
11 }
我们要获得栈的值,就需要在crt0.S中修改代码,需要在第二阶段重新设置栈。
gd->start_addr_sp的值为gd->relocaddr
在crt0.S中定义全局变量:
此问题尚未解决,有解决方法了再修改此文件。
u-boot移植(十三)---代码修改---支持文件系统及补丁制作
一、烧写文件系统1.1jffs2烧写 1.下载文件系统:tftp30000000fs_mini_mdev.jffs2 2.擦除文件的块:nanderase.partrootfs 3.烧入文件系统:nandwrite.jffs2300000000x00260000 5b89a8 4.设置启动参数:setbootargsconsole=ttySAC0root=/d... 查看详情
u-boot移植---代码修改---时钟修改sdram
...现在就需要做的是代码的修改,配置成适合目标板使用的u-boot。一、时钟修改 在代码流程分析中,我们知道,系统的启动是:设置CPU为管理员模式关闭看门狗屏蔽中断设置启动参数:时钟 FCLK:HCLK:PCLK=1:2:4 FCLK... 查看详情
u-boot移植---修改前工作:代码流程分析1
一、代码执行总体流程图1.1代码路径 U-boot.lds(archarmcpu) vectors.S(archarmlib) start.S(archarmcpuarm920t) lowlevel_init.S(boardsamsungjz2440) crt0.S(archarmlib)relocate.S(archarmlib) 查看详情
u-boot移植---修改前工作:代码流程分析3---代码重定位
...链接时候的地址就会生成,然后存储在段里面,如下段(u-boot.lds): 查看详情
u-boot移植---代码修改---nand
一、NAND原理 NAND无地址空间,地址和数据的发送都依赖于LDATA[0:7]这一串数据总线。 不看随机页编程,看到从高位到低位的页,总共分为64个页面,每个页的组成是2K+64 个byte,一个块的大小是(128K+4K)b... 查看详情
u-boot移植(十三)---代码修改---裁剪及环境变量一
一、内核裁剪 内核的裁剪首先就是修改我们的配置文件,即include/configs/jz2440.h文件,里面定义的很多宏,我们也许用不上的就要去掉。1/*2*(C)Copyright20023*SysgoReal-TimeSolutions,GmbH<www.elinos.com>4*MariusGroeger<[email protected]>... 查看详情
u-boot移植---修改前工作:代码流程分析2
一、vectors.S1.1代码地址 vectors.S(archarmlib) 1.2流程跳转 跳转符号B为start.S中的reset执行代码,暂且先不看,先看看vector.S中的执行。1.3代码分析 ldr{条件}目的寄存器<存储器地址>1_start:23#ifdefCONFIG_SYS_DV_NOR_B... 查看详情
u-boot-2014.10移植支持nand(代码片段)
在smdk2440.h里面加上NAND的配置选项 #defineCONFIG_CMD_NAND编译出错drivers/mtd/nand/s3c2410_nand.c:Infunction‘s3c2410_hwcontrol‘:drivers/mtd/nand/s3c2410_nand.c:44:warning:implicitdeclarationoffunction‘s3c2410_g 查看详情
u-boot移植---代码修改---存储控制器
一、CPU访问芯片的条件 CPU通过访问存储控制器,来读取外部设备的数据。 CPU想访问一个芯片,需要如下条件(配置信息):地址线数据线:8位/16位/32位数据宽度时钟/频率 其他芯片相关的特性:比如SDRAM,有行地... 查看详情
u-boot-2014.10移植重定位,支持nand启动(代码片段)
...统。现在把链接地址改成0x33f00000一旦更改了链接地址,u-boot从norflash加载时,串口没有任何输出 添加文件boot_init.c#defineNFCONF(*((volatileunsignedlong*)0x4E000000))#defineNFCONT(*((volatileunsignedlong*)0x4 查看详情
u-boot-2014.10移植修改环境变量的存储位置(代码片段)
原来环境变量存储在norflash里,前面mtdparts分区第二个分区就是params现在修改环境变量到nand里, 搜索defaultenvironment在Env_common.c函数里面:default_environment结构体default_environment结构体定义在env_common.c里面其中有:#ifdefCONFIG_BOOTARG... 查看详情
移植最新u-boot之裁剪和修改默认参数
...ceinsight工程、编译、烧写、如果无运行分析原因 tarxjfu-boot-2012.04.01.tar.bz2 cdu-boot-2012.04.01 makesmdk2410_config make2.分析u-boot:通过链接命令分析组成文件、阅读代码分析启动过程 a.初始化硬件:关看门狗、设置时钟、... 查看详情
tiny4412-1312__uboot移植(代码片段)
...inaro提供的gcc-linaro-6.1.1-2016.08-x86_64_arm-linux-gnueabi要移植的u-boot版本:u-boot-2016-11Tiny4412开发板硬件版本为: 底板: Tiny4412SDK1312B 核心板:Tiny4412-1306 1.获取U-BOOT源码从FTP站点下载: ftp://ftp.denx.de/pub/... 查看详情
u-boot-2014.10移植设置时钟/sdram(代码片段)
时钟修改vimarch/arm/cpu/arm920t/start.S#ifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)ldrr1,=0x3ffldrr0,=INTSUBMSKstrr1,[r0]/*FCLK:HCLK:PCLK=1:2:4*//*defaultFCLKis120MHz!*/ldrr0,=CLKDIVNmovr1,#5strr1, 查看详情
六,移植uboot-设置默认环境变量,完善u-boot(代码片段)
文档时间:2018-08-14交叉编译器:arm-linux-gcc-4.3.2Ubuntu版本:16.04uboot版本:2013.10 1,修改uboot默认环境变量前面章节得到的uboot串口打印信息如下:可以看出,读出的是坏的CRC,使用默认的环境变量,搜索"usingdefaultenvironment",... 查看详情
u-boot-1.1.6移植
...smdk2410.h直接复制为my2440.h)②修改两个Makefile u-boot-1.1.6/Makefile 在 smd 查看详情
u-boot-2014.10移植(代码片段)
1/***************************************************23*u-boot版本:u-boot-2014.1045*gcc版本:/home/flinn/tools/4.4.3/bin/arm-none-linux-gnueabi-67*89*服务器:ubuntu14.051011*1213*编译命令:makesmdk2440_config;make1 查看详情
linux系统移植:u-boot工程创建(代码片段)
文章目录Linux系统移植:U-Boot工程创建一、U-Boot文件目录二、U-Boot目录解析2.1arch文件夹2.2board文件夹2.3config文件夹2.4.u-boot.xxx_cmd文件2.5顶层Makefile文件2.6u-boot.xxx文件2.7.config文件2.8README文件三、U-Boot过程创建3.1打开工程文件夹3... 查看详情