十u-boot 调试-- NOR FLASH 支持

Posted kele-dad

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了十u-boot 调试-- NOR FLASH 支持相关的知识,希望对你有一定的参考价值。

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

  技术分享图片

  移植完成。

以上是关于十u-boot 调试-- NOR FLASH 支持的主要内容,如果未能解决你的问题,请参考以下文章

u-boot移植---代码修改---支持nor flash

支持百问网T113 D1-H D1s V853 V851s 等开发板 使用 Tina Linux NOR Flash文件系统 开发指南

支持百问网T113 D1-H D1s V853 V851s 等开发板 使用 Tina Linux NOR Flash文件系统 开发指南

U-Boot驱动篇 | 增加不同型号的Nor-Flash

Spansion S25HS512T NOR Flash 无法在 linux 或 u-boot 上运行

u-boot之NAND启动与NOR启动的区别