zoukankan      html  css  js  c++  java
  • 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
    ");
    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('
    ');                        //换行
    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 (driversmtd)

      先去掉不必要的宏,代码精简一下。

     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 (driversmtd) 

      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
    ",
     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 (driversmtd) )的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 (driversmtd) ),是否有 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 (driversmtd) )添加设备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 (driversmtd)的fill_info函数,有如下打印调试信息:

      

      定位CONFIG_SYS_MAX_FLASH_SECT(flash的最大扇区),Jz2440.h (includeconfigs):

      

      这里扇区定义的是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 (archarmlib) )函数进行栈设置,代码如下:

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

      

      

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

      

      

      

  • 相关阅读:
    sublime c/c++ 环境
    sublime编写markdownm
    第八次课程作业
    第七次课程作业
    第六次作业
    第五次课程作业
    Arithmatic项目修改总结
    第四次课程作业
    第三次课程作业
    课程作业二
  • 原文地址:https://www.cnblogs.com/kele-dad/p/7044888.html
Copyright © 2011-2022 走看看