Flash 存储器接口还有两个标准:CFI和JEDEC。
CFI为公共Flash接口[Common Flash Interface], 用来帮助程序从Flash芯片中获取操作方式信息,而不用在程序中硬编码Flash的ID。
JEDEC用来帮助程序读取Flash的制造商ID和设备ID,以确定Flash的大小和算法,如果芯片不支持CFI,就需使用JEDEC了。
CFI Flash
自从Intel公司于1988年推出了可快速擦写的非易失性存储器Flash Memory以来,快速擦写存储器Flash Memory技术就得到了非常迅速的发展。这主要是由于Flash Memory具有不需要存储电容器、集成度更高、制造成本低于DRAM、使用方便,读写灵活、访问速度快、断电后不丢失信息等特点。
虽然Flash Memory应用越来越广泛,但由于生产Flash Memory的半导体制造商众 多,不同厂商Flash Memory产品的操作命令集和电气参数又千差万别,这给Flash Memory的开发设计人员和OEM制造商带来许多不便。为了对现有的Flash Memory的产品进行升级或使用其它公司的Flash Memory产品替换,必须对原有的程序代码和硬件结构进行修改。为解决上述原因所引发的问题,迫切需要Flash Memory制造商提出一个公共的标准解决方案,在这样的背景下,公共闪存接口(Common Flash Interface),简称CFI 诞生了,CFI是一个公开的标准的从Flash Memory器件中读取数据的接口。它可以使系统软件查询已安装的Flash Memory器件的各种参数,包括器件阵列结构参数、电气和时间参数以及器件支持的功能等。利用CFI可以不用修改系统软件就可以用新型的和改进的产品代替旧版本的产品。例如:如果新型的Flash Memory的擦除时间只有旧版本的一半,系统软件只要通过CFI读取新器件的擦除时间等参数,修改一下定时器的时间参数即可。
JEDEC
Joint Electron Device Engineering Council 即电子元件工业联合会。JEDEC是由生产厂商们制定的国际性协议,主要为计算机内存制定。工业标准的内存通常指的是符合JEDEC标准的一组内存。
以u-boot-2009.03为例U-Boot本身支持CFI接口规范的闪存涉及到的文件主要包括drivers/mtd/cfi-flash.c,comrhand/cmd_flash.c。
假设要使用两片Intel 28F128K18C的兼容CFI标准的NOR型闪存,单片容量为16MB,数据线宽度为16-bit,两片并作一个32MB容量的数据宽度为32-bit的BANK来使用。在头文件include/flash.h中没有定义该芯片的相关信息,可以手动添加;这并不是必须的,如果你并不需要使用这些信息的话(例如将CFI驱动所检测到的Device Id与头文件中定义的Device ID进行比对与验证)。
/* file : include/flash.h */
#define INTEL_ID_28F128K18 0x88068806 /* added by aaron */
#define FLASH_28F128K18 0x00BA /*Intel 28F128K18 (128M=8Mx16)*/
要使用U-Boot自带的CFI闪存驱动,必须要作的是在include/configs/ xxxx.h中添加:
#define CFG_FLASH_CFI
#define CFG_FLASH_CFI_DRIVER 1
/* avoid long time detection, added by aaron ,see include/flash.h */
#define CFG_FLASH_CFI_WIDTH FLASH_CFI_32BIT
#define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */
#define CFG_MAX_FLASH_SECT 128 /*max number of sectors on one chip*/
/* timeout values are in ticks */
#define CFG_FLASH_ERASE_TOUT (25*CFG_HZ) /*Timeout for Flash Erase */
#define CFG_FLASH_WRITE_TOUT (25*CFG_HZ) /*Timeout for Flash Write */
/* write flash less slowly */
#define CFG_FLASH_USE_BUFFER_WRITE 1
另外,如果把环境变量保存在FLASH中,还有如下相关定义:
/* NOTE: many default partitioning schemes assume the kernel starts at
* the second sector, not an environment. You have been warned!
*/
#define CFG_MONITOR_BASE 0
#define CFG_MONITOR_LEN PHYS_FLASH_SECT_SIZE
#define CFG_ENV_IS_IN_FLASH 1
#define CFG_ENV_ADDR (PHYS_FLASH_1 + PHYS_FLASH_SECT_SIZE)
#define CFG_ENV_SECT_SIZE PHYS_FLASH_SECT_SIZE
#define CFG_ENV_SIZE (PHYS_FLASH_SECT_SIZE / 16)
/* If defined, hardware flash sectors protection is used instead of
* U-Boot software protection. */
#define CFG_FLASH_PROTECTION
手头有一块板子采用1片NOR型闪存 s29gl064N,数据线宽度为16 bit, 容量8 MB。下面分析了u-boot和flash相关的驱动代码,并在u-boot 下将cfi_flash.c 的调试开关打开,记录了一些调试打印信息。
初始化cfi_flash.c/ flash_init ()代码分析
flash_init (void)
{
flash_get_size (BANK_BASE(i), i);
--->flash_detect_cfi
--->flash_printqry (&qry);
--->cmdset_amd_init
--->cmdset_amd_read_jedec_ids
}
u-boot的调试打印
flash detect cfi
__flash_detect_cfi()函数 先确认模式 8bit x 8 bit 16bit x 8 bit发送 16bit x 16 bit 依次发送'Q' 'R' 'Y'
fwc addr 60000000 cmd f0 f0 8bit x 8 bit 调用了
fwc addr 60000000 cmd ff ff 8bit x 8 bit
fwc addr 60000055 cmd 98 98 8bit x 8 bit
is= cmd 51(Q) addr 60000010 is= 0 51
fwc addr 60000555 cmd 98 98 8bit x 8 bit
is= cmd 51(Q) addr 60000010 is= 0 51
fwc addr 60000000 cmd f0 f0f0 16bit x 8 bit
fwc addr 60000000 cmd ff ffff 16bit x 8 bit
fwc addr 600000aa cmd 98 9898 16bit x 8 bit
is= cmd 51(Q) addr 60000020 is= 0051 5151
fwc addr 60000aaa cmd 98 9898 16bit x 8 bit
is= cmd 51(Q) addr 60000020 is= 0051 5151
fwc addr 60000000 cmd f0 00f0 16bit x 16 bit
fwc addr 60000000 cmd ff 00ff 16bit x 16 bit
fwc addr 600000aa cmd 98 0098 16bit x 16 bit
is= cmd 51(Q) addr 60000020 is= 0051 0051
is= cmd 52(R) addr 60000022 is= 0052 0052
is= cmd 59(Y) addr 60000024 is= 0059 0059
device interface is 2
found port 2 chip 2 port 16 bits chip 16 bits
函数flash_printqry (&qry);打印信息
00 : 51 52 59 02 00 40 00 00 00 00 00 27 36 00 00 07 QRY..@.....'6...
10 : 07 0a 00 03 05 04 00 17 02 00 05 00 01 7f 00 00 ................
20 : 01 00 00 00 00 00 00 00 00 00 00 00 00 55 55 55 .............UUU
函数cmdset_amd_init打印信息
fwc addr 60000000 cmd f0 00f0 16bit x 16 bit
fwc addr 60000aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60000554 cmd 55 0055 16bit x 16 bit
fwc addr 60000aaa cmd 90 0090 16bit x 16 bit
fwc addr 60000000 cmd f0 00f0 16bit x 16 bit
fwc addr 600000aa cmd 98 0098 16bit x 16 bit
manufacturer is 2
manufacturer id is 0x1
device id is 0x227e
device id2 is 0x0
cfi version is 0x3133
size_ratio 1 port 16 bits chip 16 bits
found 1 erase regions
erase region 0: 0x0100007f
erase_region_count = 128 erase_region_size = 65536
fwc addr 60000000 cmd f0 00f0 16bit x 16 bit
flash擦出cfi_flash.c/flash_erase()函数代码分析
int flash_erase (flash_info_t * info, int s_first, int s_last)
{
case CFI_CMDSET_AMD_STANDARD:
case CFI_CMDSET_AMD_EXTENDED:
flash_unlock_seq (info, sect);
flash_write_cmd (info, sect,
info->addr_unlock1,
AMD_CMD_ERASE_START);
flash_unlock_seq (info, sect);
flash_write_cmd (info, sect, 0,
AMD_CMD_ERASE_SECTOR);
}
u-boot的调试打印
NPU3CR => erase 60600000 +50000
.fwc addr 60640aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60600554 cmd 55 0055 16bit x 16 bit
fwc addr 60600aaa cmd 80 0080 16bit x 16 bit
fwc addr 60600aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60600554 cmd 55 0055 16bit x 16 bit
fwc addr 60600000 cmd 30 0030 16bit x 16 bit
flash_is_busy: 0
.fwc addr 60610aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60610554 cmd 55 0055 16bit x 16 bit
fwc addr 60610aaa cmd 80 0080 16bit x 16 bit
fwc addr 60610aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60610554 cmd 55 0055 16bit x 16 bit
fwc addr 60610000 cmd 30 0030 16bit x 16 bit
flash_is_busy: 0
.fwc addr 60620aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60620554 cmd 55 0055 16bit x 16 bit
fwc addr 60620aaa cmd 80 0080 16bit x 16 bit
fwc addr 60620aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60620554 cmd 55 0055 16bit x 16 bit
fwc addr 60620000 cmd 30 0030 16bit x 16 bit
flash_is_busy: 0
.fwc addr 60630aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60630554 cmd 55 0055 16bit x 16 bit
fwc addr 60630aaa cmd 80 0080 16bit x 16 bit
fwc addr 60630aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60630554 cmd 55 0055 16bit x 16 bit
fwc addr 60630000 cmd 30 0030 16bit x 16 bit
flash_is_busy: 0
.fwc addr 60640aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60640554 cmd 55 0055 16bit x 16 bit
fwc addr 60640aaa cmd 80 0080 16bit x 16 bit
fwc addr 60640aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60640554 cmd 55 0055 16bit x 16 bit
fwc addr 60640000 cmd 30 0030 16bit x 16 bit
. done
Erased 5 sectors
写flash函数分析
static int flash_write_cfiword (flash_info_t * info, ulong dest, cfiword_t cword)
{
switch (info->vendor) {
case CFI_CMDSET_AMD_EXTENDED:
case CFI_CMDSET_AMD_STANDARD:
flash_unlock_seq (info, sect);
flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE);
switch (info->portwidth) {
case FLASH_CFI_8BIT:
flash_write8(cword.c, dstaddr);
break;
case FLASH_CFI_16BIT:
flash_write16(cword.w, dstaddr);
break;
return flash_full_status_check (info, sect, info->write_tout, "write");
}
u-boot的调试打印
Copy to Flash...
fwc addr 60600aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60600554 cmd 55 0055 16bit x 16 bit
fwc addr 60600aaa cmd a0 00a0 16bit x 16 bit
flash_is_busy: 0
fwc addr 60600aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60600554 cmd 55 0055 16bit x 16 bit
fwc addr 60600aaa cmd a0 00a0 16bit x 16 bit
flash_is_busy: 0
fwc addr 60600aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60600554 cmd 55 0055 16bit x 16 bit
fwc addr 60600aaa cmd a0 00a0 16bit x 16 bit
flash_is_busy: 0
fwc addr 60600aaa cmd aa 00aa 16bit x 16 bit
fwc addr 60600554 cmd 55 0055 16bit x 16 bit
fwc addr 60600aaa cmd a0 00a0 16bit x 16 bit
flash_is_busy: 0
...
另外u-boot 和flash相关的命令的代码调用顺序如下分析:
cmd_flash.c中实现了三个功能:
flinfo命令
cmd_flash.c/do_flinfo
---->> cfi_flash.c/flash_print_info()
erase命令
cmd_flash.c/do_flerase
---->> cfi_flash.c/flash_erase()函数。
protect命令
cmd_flash.c/do_protect
---->> flash_sect_erase
---->cfi_flash.c/flash_real_protect()前提定义了CONFIG_SYS_FLASH_PROTECTION
cmd_mem.c中实现了cp命令将内存中的内容cp到flash中
do_mem_cp()
---->common/flash.c/flash_write(char *)env_buffer, flash_sect_addr, len);
---->cfi_flash.c/write_buff();
---->cfi_flash.c/flash_write_cfiword();
cmd_envedit.c 实现了env对flash的操作
cmd_envedit.c/do_saveenv()
--->_do_setenv()
--->env_flash.c/saveenv()
--->cfi_flash.c/flash_sect_protect (0, flash_sect_addr, end_addr));
cfi_flash.c/flash_sect_erase (flash_sect_addr, end_addr));
common/flash.c/flash_write(char *)env_buffer, flash_sect_addr, len);
---->cfi_flash.c/write_buff();
---->cfi_flash.c/flash_write_cfiword();