13.1 问题现象
在烧写进去的u-boot 中 Flash 并没有显示实际大小,需要进行修改。
13.2 问题定位过程
13.2.1 关键字搜索 Flash:
此关键字在 Board_r.c (common) 文件中的 initr_flash 函数,此函数用 CONFIG_MTD_NOR_FLASH 宏控制,去掉不相关的代码:
1 #if defined(CONFIG_MTD_NOR_FLASH) //味ㄒ錍ONFIG_SYS_NOR_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 putc('\n'); //换行
16
17 /* update start of FLASH memory */
18 #ifdef CONFIG_SYS_FLASH_BASE
19 bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; //bd->bi_flashstart = 0 从0地址开始执行
20 #endif
21 /* size of FLASH memory (final value) */
22 bd->bi_flashsize = flash_size; //flash 的大小
23
24 #if defined(CONFIG_OXC) || defined(CONFIG_RMU)
25 /* flash mapped at end of memory map */
26 bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size;
27 #elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
28 bd->bi_flashoffset = monitor_flash_len; /* reserved area for monitor */
29 #endif
30 return 0;
31 }
32 #endif
红色字体部分代码已经很明显的显示了打印过程。
首先是,flash_init 初始化flash ,然后调用 print_size 打印处 flash 的大小。flash_init 函数执行完后,会返回 flash_size 变量,即为 flash 的大小。
13.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
16 /* 检测 flash
17 * flash_detect_legacy 是旧的检测策略
18 */
19 if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
20 flash_get_size(cfi_flash_bank_addr(i), i);
21 size += flash_info[i].size;
22 if (flash_info[i].flash_id == FLASH_UNKNOWN) {
23 #ifndef CONFIG_SYS_FLASH_QUIET_TEST
24 printf("## Unknown flash on Bank %d ", i + 1);
25 printf("- Size = 0x%08lx = %ld MB\n",
26 flash_info[i].size,
27 flash_info[i].size >> 20);
28 #endif /* CONFIG_SYS_FLASH_QUIET_TEST */
29 }
30 }
31
32 flash_protect_default(); //flash的默认保护
33
34 return (size);
35 }
分析到当前,已经可以看见一些端倪了,size 变量是在 检测到flash 之后,才有正确的值,当前我们无法保证是否检测到了 flash。
当前我们可以开一下 debug 宏进行调试。
13.2.3 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 宏进行调试。
13.2.3 debug 调试
当前我们可以开一下 debug 宏进行调试。
在include/common.h的顶端加入debug 宏。 #define DEBUG 然后重新编译开机
这里打印了两个 JEDEC PROBE,一个是在 flash_detect_legacy 中打印,还有是什么暂且不知道。
芯片手册的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。
13.2.4 jedec_flash_match
代码中会去与 jedec_table 表去匹配。
1 /*----------------------------------------------------------------------- 2 * match jedec ids against table. If a match is found, fill flash_info entry 3 */ 4 int jedec_flash_match(flash_info_t *info, ulong base) 5 { 6 int ret = 0; 7 int i; 8 ulong mask = 0xFFFF; 9 if (info->chipwidth == 1) 10 mask = 0xFF; 11 12 for (i = 0; i < ARRAY_SIZE(jedec_table); i++) { 13 if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) && 14 (jedec_table[i].dev_id & mask) == (info->device_id & mask)) { 15 fill_info(info, &jedec_table[i], base); 16 ret = 1; 17 break; 18 } 19 } 20 return ret; 21 }
13.2.5 jedec_table
Jedec_flash.c (drivers\mtd)
这个表中定义了 flash 的所有信息,如果可以匹配到我们的 flash 则会显示信息,提取处 flash 大小值。
查看 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的。
13.3 代码修改
13.3.1 添加设备
Jedec_flash.c (drivers\mtd)
在 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
13.3.2 修改扇区大小
include/config/jz2440.h 中
13.3.3 调试
编译烧写测试,结果如下:
上面报了一个错: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,或者改成35也可以,最大扇区定义:
执行命令:flinfo
取消写保护:protect off all
擦除80000--90000之间的区域:erase 80000 8ffff
拷贝DRAM中的数据进norflash:cp.b 30000000 80000 10000
DRAM 30000000处的数据:md.b 30000000
norflash 80000处的数据:md.b 80000
比较两者之间的数据:cmp.b 30000000 80000 10000
移植完成。