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

      

      

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

      

      

      

  • 相关阅读:
    LeetCode 1110. Delete Nodes And Return Forest
    LeetCode 473. Matchsticks to Square
    LeetCode 886. Possible Bipartition
    LeetCode 737. Sentence Similarity II
    LeetCode 734. Sentence Similarity
    LeetCode 491. Increasing Subsequences
    LeetCode 1020. Number of Enclaves
    LeetCode 531. Lonely Pixel I
    LeetCode 1091. Shortest Path in Binary Matrix
    LeetCode 590. N-ary Tree Postorder Traversal
  • 原文地址:https://www.cnblogs.com/kele-dad/p/7044888.html
Copyright © 2011-2022 走看看