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 函数的代码解读如下:

  

 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中定义全局变量:

  

  

  此问题尚未解决,有解决方法了再修改此文件。

  

  

  

时间: 2024-11-05 18:02:24

u-boot移植(十)---代码修改---支持nor flash的相关文章

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

一.准备工作 1.1 原理图 CONFIG_DM9000_BASE 片选信号是接在nGCS4引脚,若要确定网卡的基地址,则要根据片选信号的接口去确定. 在三星2440的DATASHEET中memory control这一章的Figure 5-1. S3C2440A Memory Map after Reset 已经说明了片选4的地址,如下: 只要发出的信号在 0x20000000--0x28000000 之间,就会使得片选4引脚变为低电平.所以可以确定我们网卡的基地址为0x20000000. C

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

一.烧写文件系统 1.1 jffs2烧写 1.下载文件系统:tftp 30000000 fs_mini_mdev.jffs2 2.擦除文件的块:nand erase.part rootfs 3.烧入文件系统:nand write.jffs2 30000000 0x00260000 5b89a8 4.设置启动参数:set bootargs console=ttySAC0 root=/dev/mtdblock3 rootfstype=jffs2 5.重新启动 这个需要先烧写内核. 1.2 yaffs

js代码从页面移植到文件中失效或js代码修改后不起作用的解决办法

最近在做关于网站的项目,总是发生这样的问题 写的javascript代码在页面上没有问题,但是将js代码移植到.js的文件中,在页面上进行调用,总是出现失效等错误 另外修改后的js代码,重新刷新网页仍然不起作用 经过大量搜索并经过验证,可以用下面方法来解决 将js代码封装到js文件中失效的原因可能是js文件中存在中文注释,导致在执行的时候中断,在js文件尽量不要写中文注释 修改后的js代码刷新网页后不起效果可能是因为你所用的浏览器使用缓存的问题,可在浏览器中设置取消使用缓存,并删除临时文件,重启

开发人员建议阅读:Spring Boot 架构中的国际化支持实践

pring Boot 主要通过 Maven 或 Gradle 这样的构建系统以继承方式添加依赖,同时继承了 Spring 框架中的优秀元素,减少了 Spring MVC 架构中的复杂配置,内置 Tomcat,Jetty 容器,使用 Java application 运行程序,而不是传统地把 WAR 包置于 Tomcat 等容器中运行,从而简化加速开发流程.此外,Spring Boot 学习简单.轻量级.容易扩展.基于这些优秀的特点,Spring Boot 成为了蓬勃发展的快速应用开发领域的领导者

Spring Boot如何让某个Controller支持跨源请求,以及如何让Controller类某个成员方法支持跨源请求

在前面我们已经讨论了Spring Boot 如何全局支持跨源请求.如果你想了解可以查看这篇文章 下面我们讨论另一种场景.有些时候,你需要让你的应用在大部分的时候,仅仅支持当前域名下的请求.而仅仅在极其特殊的几个场合下,才支持跨源请求.这个时候,你需要把跨源请求仅仅缩小在几个Controller上,或者Controller类的几个成员方法上.这个时候你需要用到如下的注解:@CrossOrigin(origins = "*", maxAge = 3600) .把这个注解放到 Control

u-boot-2014.10移植第21天----添加nand flash命令支持(三)

硬件平台:tq2440 开发环境:Ubuntu-3.11 u-boot版本:2014.10 本文允许转载,请注明出处:http://blog.csdn.net/fulinus 虽说nand flash读写操作是可以了,但是我使用nand markbad命令将一个块标记为坏块时,再用nand scrub命令恢复出厂设置时,却出现了下面的错误: nand0: MTD Erase failure: -5 说明我们的nand flash移植是不完全正确的. 下面查找原因 在文件drivers/mtd/n

Android学习路线(十九)支持不同设备——支持不同(Android)平台版本

当最新的Android版本为你的应用提供着很棒的APIs时,你却要在更多的设备更新之前继续支持老的系统版本.这篇课程如何在继续支持低版本的系统的情况下使用新版本的高级API. Platform Versions 仪表板展示了最新的活跃设备上运行的Android系统版本的分布,基于设备访问Google Play商店的次数.通常情况下,支持90%的活跃设备同时使用最新版本作为target是一个好习惯. 贴士: 为了在不同的Android版本上提供最好的特性和功能,你应该在你的应用中使用Android

在使用shape的同时,用代码修改shape的颜色属性

Android里面经常会使用shape来定制一些View的背景 可以修改View的背景颜色,形状等属性 一般情况下,shape都是在xml文件里面写死了,今天遇到一个需求,View的形状是圆角的,但是颜色是在代码里面设置的 最开始的思路是先在代码里给View设置颜色,再在shape里面设置solid属性为透明色 <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="htt

一次js代码修改不更新问题的解决

今天遇到一个问题,虽说问题不大,但弄得本人脑袋发麻 我讲javascript修改后,刷新页面或者清除浏览器缓存,修改后的效果也不出现,害的我好苦啊 最后想到自己是新装的机子是不是是浏览器设置的原因 按以下方式完美解决 这应该是开发人员必须设置的 一次js代码修改不更新问题的解决,布布扣,bubuko.com