U-boot-2014.04移植到MINI2440(5) Nor FLASH 读写支持移植

时间:2022-09-30 16:35:48

MINI2440有一个2M的NOR FLASH,NOR FLASH在MINI2440上其实是一个容量较小的ROM,不过它比NAND要好的地方在于可以执行代码。当开关打在nor的时候,就选择从NOR FLASH启动,NOR FLASH是直接映射到0x00000000地址上开始工作的。关于nor和nand的区别以及在mini2440上启动时候的差别请参看CSDN上的帖子,分析的挺好,这里不赘述了。

 

一.追踪cfi_flash.cjedec_flash.c找出nor型号

后面的移植工作参照网上大牛对tq2440的u-boot-2014.04的移植方法,在此对他们的工作表示感谢。

因为我们现在要在u-boot里面添加进去对我们板子上的nor flash的读写支持,

根据文件名,我查了下什么是cfi,什么是jedec,找到如下描述:

CFI为公共Flash接口[CommonFlash Interface], 用来帮助程序从Flash芯片中获取操作方式信息。

       JEDEC用来帮助程序读取Flash的制造商ID和设备ID,以确定Flash的大小和算法。

       首先在jedec_flash.c中添加mini2440的nor flash型号的内容。查阅mini2440用户手册知道mini2440使用的的nor flash型号为:SST39VF1602(AMD29LV160DB)与此引脚兼容。我们看到在jedec_flash.c的第47行:

#define SST39LF160    0x2782

#define SST39VF1601 0x234b

#define SST39LF512    0x00D4

       同时与之兼容的AMD29LV160DB在第34行:

#define AM29LV160DT      0x22C4

#define AM29LV160DB     0x2249

#define AM29F017D    0x003D

       但是我们在第一篇帖子启动的时候,最后出现的错误提示:

       FLASH:***failed***

       这里应该是FLASH部分出错了,我们在这两个文件里面追踪一下错误,打开DEBUG调试宏,可以看到调试信息。在两个文件头文件之前,记住一定要是头文件之前,打开DEBUG宏。

       /* The DEBUG define must be before commonto enable debugging */

/*#define DEBUG*/

       加入当前在u-boot的源码目录下,执行以下指令:

       cd drivers/mtd/

       vim jedec_flash.c

       在头文件之前:defineDEBUG

       另一个文件也是同样的操作,然后保存退出。重新回到源码目录重新编译。

生成的u-boot拷贝到tftpboot下。

tftp 0x30008000 u-boot.bin

go 0x30008000

结果出现如下信息:

U-Boot 2014.04 (Aug 24 2015 - 14:19:35)

 

CPUID: 32440001

FCLK:      400MHz

HCLK:      100MHz

PCLK:       50MHz

DRAM:  64 MiB

WARNING: Caches not enabled

Flash: fwc addr 00000000 cmd f0 00f0 16bit x16 bit

fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit

fwc addr 00005554 cmd 55 0055 16bit x 16 bit

fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit

fwc addr 00000000 cmd f0 00f0 16bit x 16 bit

JEDEC PROBE: ID f0 ea00 0

fwc addr 00000000 cmd ff 00ff 16bit x 16 bit

fwc addr 00000000 cmd 90 0090 16bit x 16 bit

fwc addr 00000000 cmd ff 00ff 16bit x 16 bit

JEDEC PROBE: ID 90 ea00 0

*** failed ***

### ERROR ### Please RESET the board ###

       u-boot探测到的 norflash型号我们的列表里没有,ea00。难道是因为没有从norflash启动的原因,为此我在自己的nor flash里面烧写一个u-boot,然后从nor 启动再将编译好的u-boot按照上面的方法下载进去试试。

       这时候打印信息如下:

U-Boot 2014.04 (Aug 24 2015 - 14:19:35)

 

CPUID: 32440001

FCLK:     400 MHz

HCLK:     100 MHz

PCLK:      50 MHz

DRAM: 64 MiB

WARNING: Caches not enabled

Flash: fwc addr 00000000 cmd f0 00f0 16bit x 16 bit

fwc addr 0000aaaa cmd aa 00aa 16bit x 16bit

fwc addr 00005554 cmd 55 0055 16bit x 16bit

fwc addr 0000aaaa cmd 90 0090 16bit x 16bit

fwc addr 00000000 cmd f0 00f0 16bit x 16bit

JEDEC PROBE: ID 1 2249 0

fwc addr 00000000 cmd ff 00ff 16bit x 16bit

fwc addr 00000000 cmd 90 0090 16bit x 16bit

fwc addr 00000000 cmd ff 00ff 16bit x 16bit

JEDEC PROBE: ID 14 ea00 0

*** failed ***

### ERROR ### Please RESET the board ###

       我们探测到了自己的norflash的device_id为2249,和我们的AM29LV160DB是匹配的。但是他还是提示出错误,FLASH:***failed****

使用grep “FLASH:”* -nR搜索,程序定位在arch/arm/lib/board.c

第557行:

puts("Flash: ");

 

flash_size = flash_init();

if (flash_size > 0)

{

******

} else {           //557行

              puts(failed);

              hang();

       }

       也就是说,如果flash_size>0,才会进去,否则就输出failed,而flash_size=flash_init(),也就是说flash_init()出了问题,切过去。

       flash_init()函数在文件cfi_flash.c里面,在第2332行:

      

unsignedlong  flash_init (void)

{

       unsigned long size = 0;

       int i;

 

#ifdefCONFIG_SYS_FLASH_PROTECTION

       /* read environment from EEPROM */

       char s[64];

       getenv_f("unlock", s,sizeof(s));

#endif

 

       /* Init: no FLASHes known */

       for (i = 0; i <CONFIG_SYS_MAX_FLASH_BANKS; ++i) {

              flash_info[i].flash_id =FLASH_UNKNOWN;

 

              /* Optionally write flashconfiguration register */

              cfi_flash_set_config_reg(cfi_flash_bank_addr(i),

                                    cfi_flash_config_reg(i));

 

              if(!flash_detect_legacy(cfi_flash_bank_addr(i), i))

                     flash_get_size(cfi_flash_bank_addr(i),i);

              size += flash_info[i].size;

              if (flash_info[i].flash_id ==FLASH_UNKNOWN) {

#ifndef CONFIG_SYS_FLASH_QUIET_TEST

                     printf ("## Unknownflash on Bank %d "

                            "- Size =0x%08lx = %ld MB\n",

                            i+1,flash_info[i].size,

                            flash_info[i].size>> 20);

#endif /*CONFIG_SYS_FLASH_QUIET_TEST */

              }

#ifdefCONFIG_SYS_FLASH_PROTECTION

              else if ((s != NULL) &&(strcmp(s, "yes") == 0)) {

                     /*

                      * Only the U-Boot image and it's environment

                      * is protected, all other sectors are

                      * unprotected (unlocked) if flash hardware

                      * protection is used(CONFIG_SYS_FLASH_PROTECTION)

                      * and the environment variable"unlock" is

                      * set to "yes".

                      */

                     if(flash_info[i].legacy_unlock) {

                            int k;

 

                            /*

                             * Disable legacy_unlock temporarily,

                             * since flash_real_protect would

                             * relock all other sectors again

                             * otherwise.

                             */

                            flash_info[i].legacy_unlock= 0;

 

                            /*

                             * Legacy unlocking (e.g. Intel J3) ->

                             * unlock only one sector. This will

                             * unlock all sectors.

                             */

                            flash_real_protect(&flash_info[i], 0, 0);

 

                            flash_info[i].legacy_unlock= 1;

 

                            /*

                             * Manually mark other sectors as

                             * unlocked (unprotected)

                             */

                            for (k = 1; k <flash_info[i].sector_count; k++)

                                   flash_info[i].protect[k]= 0;

                     } else {

                            /*

                             * No legancy unlocking -> unlock allsectors

                             */

                            flash_protect(FLAG_PROTECT_CLEAR,

                                          flash_info[i].start[0],

                                          flash_info[i].start[0]

                                          + flash_info[i].size - 1,

                                          &flash_info[i]);

                     }

              }

#endif /*CONFIG_SYS_FLASH_PROTECTION */

       }

       这个函数看起来很长,其实分析起来很简单,根据几个CONFIG,就可以截取很大一段,最后在这一行:if(!flash_detect_legacy(cfi_flash_bank_addr(i), i)),我们进入flash_detect_legacy查看,找到如下信息:

       flash_read_jedec_ids(info);

                            debug("JEDECPROBE: ID %x %x %x\n",

                                          info->manufacturer_id,

                                          info->device_id,

                                          info->device_id2);

                            if (jedec_flash_match(info, info->start[0]))

                                   break;

说明我们这里不成功是因为没有匹配成功,为什么没有成功,是因为在jedec_table的表中没有定义,要添加进去,就可以了。

       修改jedec_flash.c,在函数amd_flash_info jedec_table[]添加AM29LV160DB的信息,这个信息在哪里找呢,可以打开j-flash就是我们用j-link烧写u-boot的时候,选择nor flash型号的时候,有相关的信息,尤其是这里的Num sectors。

       打开软件j-flash,在options->project settings->flash->selectflash device里面可以看到如下图的信息:

      U-boot-2014.04移植到MINI2440(5) Nor FLASH 读写支持移植

二.修改jedec_flash.c,mini2440.h,cfi_flash.c

根据这部分的信息我们去修改,因为里面已经有相似的代码,可以拷贝512K*16部分的进行修改,添加代码如下:

       #ifdef CONFIG_SYS_FLASH_LEGACY_1024Kx16

       {

              .mfr_id         = (u16)AMD_MANUFACT,

              .dev_id         = AM29LV160DB,

              .name            = "AMD AM29LV160DB,migrated by Deep_l_zh",

              .uaddr           = {

                     [1] =MTD_UADDR_0x0555_0x02AA /* x16 */

              },

              .DevSize       = SIZE_2MiB,

              .CmdSet              = P_ID_AMD_STD,

              .NumEraseRegions= 4,

              .regions  = {

                     ERASEINFO(0x04000, 1),

                     ERASEINFO(0x02000, 2),

                     ERASEINFO(0x08000, 1),

                     ERASEINFO(0x10000, 7),

              }

       },

#endif

      

       接着,要在mini2440.h里面将这个配置加进去,在第153行,更改如下:

//#define CONFIG_SYS_FLASH_LEGACY_512Kx16

#define CONFIG_SYS_FLASH_LEGACY_1024Kx16

       在下面,因为我们的sectors也要设置,所以还在mini2440.h里面第160行,更改如下:

//#define CONFIG_SYS_MAX_FLASH_SECT      (19)

#define CONFIG_SYS_MAX_FLASH_SECT (35)

最后编译,拷贝到tftpboot目录,从nor flash启动,利用tftp0x30008000 u-boot.bin以及go 0x30008000启动,得到如下信息:

[u-boot@SMDK2440A]# go 0x30008000

## Starting application at 0x30008000 ...

 

 

U-Boot 2014.04 (Aug 24 2015 - 16:44:29)

 

CPUID: 32440001

FCLK:      400MHz

HCLK:      100MHz

PCLK:       50MHz

DRAM:  64 MiB

WARNING: Caches not enabled

Flash: fwc addr 00000000 cmd f0 00f0 16bit x 16 bit

fwc addr 0000aaaa cmd aa 00aa 16bit x 16 bit

fwc addr 00005554 cmd 55 0055 16bit x 16 bit

fwc addr 0000aaaa cmd 90 0090 16bit x 16 bit

fwc addr 00000000 cmd f0 00f0 16bit x 16 bit

JEDEC PROBE: ID 1 2249 0

Found JEDEC Flash: AMD AM29LV160DB,migratedby Deep_l_zh

unlock address index 1

unlock addresses are 0x555/0x2aa

erase_region_count = 1 erase_region_size = 16384

erase_region_count = 2 erase_region_size = 8192

erase_region_count = 1 erase_region_size = 32768

erase_region_count = 7 erase_region_size = 65536

512 KiB   这里出问题了

*** Warning - bad CRC, using default environment

 

In:    serial

Out:   serial

Err:   serial

Net:   Noethernet found.

MINI2440 #

       说明我们已经成功了,红色是我们修改希望看到的信息。下面根据u-boot的nor flash命令来测试一下是否成功,参考友善之臂2010的手册里面U-boot的命令熟悉,输入flinfo,看到如下信息:

MINI2440 # flinfo

 

Bank # 1: AMDAM29LV160DB,migrated by Deep_l_zh flash (16 x 16) Size: 512 kB in 11 Sectors

  AMD Legacy command set, Manufacturer ID:0x01, Device ID: 0x2249

  Erase timeout: 30000 ms, write timeout: 100ms

 

  Sector Start Addresses:

  00000000  RO   00004000   RO  00006000   RO   00008000  RO   00010000   RO

  00020000  RO   00030000        00040000        00050000        00060000     

  00070000  RO

       三.粗心大意绕弯子

这里发现一个错误,我们的nor应该是2M的,为什么这里打印的是512kB的,回去看之前的信息也是512K,这里首先关闭DEBUG宏,看一下编译输出的信息还是显示FLASH是512KB。这时候我从nor启动之后,直接在原先就有的u-boot里面输入flinfo,出现如下消息:

[u-boot@SMDK2440A]#flinfo

 

Bank #1: SST: 1x SST39VF1601 (2MB)

  Size: 2 MB in 32 Sectors

  Sector Start Addresses:

    00000000 (RO) 00010000 (RO) 00020000 (RO)00030000 (RO) 00040000 (RO)

    00050000 (RO) 00060000      00070000      00080000      00090000    

    000A0000      000B0000      000C0000      000D0000      000E0000    

    000F0000      00100000      00110000      00120000      00130000    

    00140000      00150000      00160000      00170000      00180000    

    00190000      001A0000      001B0000      001C0000      001D0000    

    001E0000      001F0000    

       这里的nor 型号居然变成了SST39VF1601,再回去修改。在jedec_flash.c里面,有SST39VF1601的device_id,如下#define SST39VF1601     0x234b,可是前面我们调试出来的是2249,由于SST39VF1601和AM29LV160DB的引脚相同,所以这里其实还是SST39VF1601,我一开始看到打印出来是AM29LV160DB的ID就认为是这个了,具体原因还不清楚,返回去修改jedec_flash.c。

       将添加进去的代码修改如下:

#ifdef CONFIG_SYS_FLASH_LEGACY_1024Kx16

       {

              .mfr_id         = (u16)SST_MANUFACT,

              .dev_id         = SST39VF1601,

              .name            = "SST SST39VF1601,migrated byDeep_l_zh",

              .uaddr           = {

                     [1]= MTD_UADDR_0x0555_0x02AA /* x16 */

              },

              .DevSize       = SIZE_2MiB,

              .CmdSet              = P_ID_AMD_STD,

              .NumEraseRegions=4,

              .regions  = {

                     ERASEINFO(0x04000,1),

                     ERASEINFO(0x02000,2),

                     ERASEINFO(0x08000,1),

                     ERASEINFO(0x10000,7),

              }

       },

#endif

重新编译,报错,FLASH:failed.仔细一看,自己的这一行里面的代码没有修改,              ERASEINFO(0x04000, 1),

                     ERASEINFO(0x02000,2),

                     ERASEINFO(0x08000,1),

                     ERASEINFO(0x10000,7),

这里应该是ERASEINFO(0x10000, 31),就是这么粗心的一个小错误让自己绕了一大圈,我将这部分写下来也是为了告诉各位同道,也许有时候错误就是这样子,细心细心再细心。

 

四.最终修改的jedec_flash.c

最终这部分修改成这样:

#ifdefCONFIG_SYS_FLASH_LEGACY_1024Kx16

       {

              .mfr_id         = (u16)AMD_MANUFACT,

              .dev_id         = AM29LV160DB,

              .name            = "AMD AM29LV160DB,migrated by Deep_l_zh",

              .uaddr           = {

                     [1] = MTD_UADDR_0x0555_0x02AA/* x16 */

              },

              .DevSize       = SIZE_2MiB,

              .CmdSet              = P_ID_AMD_STD,

              .NumEraseRegions= 4,

              .regions  = {

                     ERASEINFO(0x04000, 1),

                     ERASEINFO(0x02000, 2),

                     ERASEINFO(0x08000, 1),

                     ERASEINFO(0x10000, 31),

              }

       },

#endif

编译,下载,运行,通过后如下:

 

U-Boot 2014.04 (Aug 24 2015 - 19:20:06)

 

CPUID: 32440001

FCLK:     400 MHz

HCLK:     100 MHz

PCLK:      50 MHz

DRAM: 64 MiB

WARNING: Caches not enabled

Flash: fwc addr 00000000 cmd f0 00f0 16bitx 16 bit

fwc addr 0000aaaa cmd aa 00aa 16bit x 16bit

fwc addr 00005554 cmd 55 0055 16bit x 16bit

fwc addr 0000aaaa cmd 90 0090 16bit x 16bit

fwc addr 00000000 cmd f0 00f0 16bit x 16bit

JEDEC PROBE: ID 1 2249 0

Found JEDEC Flash: AMDAM29LV160DB,migrated by Deep_l_zh

unlock address index 1

unlock addresses are 0x555/0x2aa

erase_region_count = 1 erase_region_size =16384

erase_region_count = 2 erase_region_size =8192

erase_region_count = 1 erase_region_size =32768

erase_region_count = 31 erase_region_size =65536

2 MiB

*** Warning - bad CRC, using defaultenvironment

 

In:   serial

Out:  serial

Err:  serial

Net:  No ethernet found.

 

五.读写测试

说明成功了,再进行测试,输入:flsinfo,输出如下信息:

Bank # 1: AMD AM29LV160DB,migrated byDeep_l_zh flash (16 x 16)  Size: 2 MB in35 Sectors

  AMDLegacy command set, Manufacturer ID: 0x01, Device ID: 0x2249

 Erase timeout: 30000 ms, write timeout: 100 ms

 

 Sector Start Addresses:

 00000000   RO   00004000  RO   00006000   RO  00008000   RO   00010000  RO

 00020000   RO   00030000       00040000        00050000        00060000     

 00070000   RO   00080000        00090000        000A0000        000B0000     

 000C0000        000D0000        000E0000        000F0000        00100000     

 00110000        00120000        00130000        00140000        00150000     

 00160000        00170000        00180000        00190000        001A0000     

 001B0000        001C0000        001D0000        001E0000        001F0000

 

测试flash读:

md.b 0x0 20

00000000: 14 00 00 ea 14 f0 9f e5 14 f0 9fe5 14 f0 9f e5    ................

00000010: 14 f0 9f e5 14 f0 9f e5 14 f0 9fe5 14 f0 9f e5    ................

成功。

测试写数据对比:

先解保护,protect on/off start end,这里读R0从0地址开始一段,所以:

protect off 0x0 0x00003fff

会提示:Un-Protected 1 sectors

我们只把R0解保护了,后面的这个end地址必须是sector的边缘地址,否则会报错。因为R1的起始地址是0x00004000,所以r1就是0x00003fff。

MINI2440 Deep_l_zh # cp.b 30008000 0 10

Copy to Flash... Flash not Erased

MINI2440 Deep_l_zh # cmp.b 0 30008000 10

byte at 0x00000000 (0x14) != byte at0x30008000 (0xf)

Total of 0 byte(s) were the same

       说明写没有问题。

       再来把刚才写的读出来对比:

       MINI2440 Deep_l_zh # md.b 30008000 10

30008000: 0f 00 00ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5   ................

MINI2440 Deep_l_zh# md.b 0 10

00000000: 14 00 00ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5   ................

       和刚才一样,两分数据相同,说明nor flash的读写移植已经成功。

       就这样吧,如有不正的地方还请指出,共同进步!