加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Uboot下的Nor Flash的驱动以及使用

发布时间:2020-12-15 17:27:28 所属栏目:百科 来源:网络整理
导读:Uboot 下 CFI Nor Flash 的使用 韩大卫@吉林师范大学 2015.1.23 Flash : Micron Technology. 32MB. Uboot: 2_3_0 CPU平台: Cavium Inc 交叉编译器: mips64-octeon-linux-gnu-gcc (Cavium Inc. Version: 2_3_0 build 128) 4.3.3 nor flash 的使用特点是 :? 读

Uboot 下 CFI Nor Flash 的使用

韩大卫@吉林师范大学

2015.1.23

Flash : Micron Technology. 32MB.

Uboot: 2_3_0

CPU平台: Cavium Inc

交叉编译器: mips64-octeon-linux-gnu-gcc (Cavium Inc. Version: 2_3_0 build 128) 4.3.3


nor flash 的使用特点是 :? 读操作可以按地址读,写之前必须进行擦除,一旦擦除必须擦除整个扇区.?

新型的flash 使用3V 的电压便可以进行整个扇区的擦除和写入操作


任何芯片的使用,都离不开驱动的支持. uboot下的nor flash的驱动逻辑非常简单. 而且,对于符合 CFI ( Common Flash Interface )规范的flash芯片,驱动有很大的通用性.?

uboot 提供了很好的 flash 驱动逻辑 和 flash的使用范例,这些基本的使用方法在linux里也是同样的逻辑,只不过linux下需要加上一层分区信息. 结合flash 芯片手册,可以对nor flash的使用逻辑有较为清晰的理解.?


nor flash的驱动初始化部分:

arch/mips/cpu/octeon/start.S

board_init_r? -> flash_init()

drivers/mtd/cfi_flash.c

unsigned long flash_init (void){?

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

? ? ? ? flash_info[i].flash_id = FLASH_UNKNOWN;

?? ? ? ? ? ? ? ? ?

? ? ? //由于使用的flash 是新型的CFI 规范的flash,没有使用 CONFIG_FLASH_CFI_LEGACY 这个宏,所以flash_detect_legacy直接返回0

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

? ? ? ? ? ? flash_get_size(cfi_flash_bank_addr(i),i);

? ? ? ? size += flash_info[i].size;


ulong flash_get_size (phys_addr_t base,int banknum)

{? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? flash_info_t *info = &flash_info[banknum];

? ? int i,j;? ? ? ? ? ? ? ? ?

? ? flash_sect_t sect_cnt;

? ? phys_addr_t sector;? ?

? ? unsigned long tmp; ? ?

? ? int size_ratio;? ? ? ? ? ?

? ? uchar num_erase_regions;

? ? int erase_region_size; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? int erase_region_count;

? ? struct cfi_qry qry;? ?

? ? unsigned long max_size;

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? memset(&qry,sizeof(qry));

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? info->ext_addr = 0;? ?

? ? info->cfi_version = 0;?

#ifdef CONFIG_SYS_FLASH_PROTECTION

? ? info->legacy_unlock = 0;?

#endif ? ? ? ? ? ? ? ? ? ? ? ?

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? info->start[0] = (ulong)map_physmem(base,info->portwidth,MAP_NOCACHE);

? ? ? ? ? ? ? ?

? ? //如果是CFI 接口,那么有统一的查询规范,将查询到的信息保存到 qry中? ? ? ? ? ? ? ?

? ? if (flash_detect_cfi (info,&qry)) {

? ? ? ? info->vendor = le16_to_cpu(qry.p_id);

? ? ? ? info->ext_addr = le16_to_cpu(qry.p_adr) * 2;?

? ? ? ? debug("extended address is 0x%xn",info->ext_addr);

? ? ? ? num_erase_regions = qry.num_erase_regions;

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? if (info->ext_addr) {

? ?

#define FLASH_OFFSET_CFI_RESP ? ? ? 0x20?

flash_detect_cfi ->

static int __flash_detect_cfi (flash_info_t * info,struct cfi_qry *qry)

{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? int cfi_offset; ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? for (cfi_offset=0;? ? ? ? ? ? ? ? ? ? ? ? ?

?? ? ? ? cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);

?? ? ? ? cfi_offset++) {? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? /* Issue FLASH reset command */ ? ? ? ?

? ? ? ? flash_cmd_reset(info);? ? ? ? ? ? ? ? ?

? ? ? ? flash_write_cmd (info,flash_offset_cfi[cfi_offset],

?? ? ? ? ? ? ? ? FLASH_CMD_CFI); ? ? ? ? ? ?

?? ? //向0x20 地址进行查询,? CFI 规定,前三个字符应该是 Q,R,Y? ?

? ? ? ? if (flash_isequal (info,FLASH_OFFSET_CFI_RESP,'Q')

? ? ? ? ? ? && flash_isequal (info,FLASH_OFFSET_CFI_RESP + 2,'R')

? ? ? ? ? ? && flash_isequal (info,FLASH_OFFSET_CFI_RESP + 4,'Y')) {


?? ? ? ? ? //如果确认为CFI 规范,那么就按照 struct cfi_qry数据结构进行查询?

? ? ? ? ? ? flash_read_cfi(info,qry,FLASH_OFFSET_CFI_RESP,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? sizeof(struct cfi_qry)); ??

? ? //在进行CFI 规范查询之后,还要将addr_unlock1,addr_unlock2 进行赋值,? 这两个地址分别表示8位宽的地址和16位宽的地址,可以实现byte和word的操作.?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //一般地,我们只使用addr_unlock1

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //在一些代码里,这两个数值就通过宏定义来实现的

? ? ? ? ? ? info->addr_unlock1 = 0xaaa;

? ? ? ? ? ? info->addr_unlock2 = 0x555;? ? ? ? ?

}

下面是flash 芯片手册里CFI 规范查询的信息:









cfi_qry 定义:

struct cfi_qry {

? ? u8? qry[3]; //保存 Q,Y

? ? u16 p_id; ? ? //Primary algorithm?

? ? u16 p_adr; ? //Address for primary algorithm?

? ? u16 a_id;? ? //Alternate?

? ? u16 a_adr;? ? //Address for alternate?

? ? u8? vcc_min;? // 最小Vcc

? ? u8? vcc_max;? //最大Vcc

? ? u8? vpp_min; ? //最小Vpp

? ? u8? vpp_max;? ? //最大Vpp

? ? u8? word_write_timeout_typ; ? //字节写典型超时

? ? u8? buf_write_timeout_typ;? ? //缓存写典型超时

? ? u8? block_erase_timeout_typ;? //块擦除典型超时

? ? u8? chip_erase_timeout_typ;? ? //整片擦除典型超时

? ? u8? word_write_timeout_max;? ? //字节写最大超时

? ? u8? buf_write_timeout_max;? ? ? //缓存写最大超时

? ? u8? block_erase_timeout_max;? ? //块写最大超时

? ? u8? chip_erase_timeout_max;? ? ? //整片擦除最大超时

? ? u8? dev_size; ? ? ? ? //芯片大小

? ? u16 interface_desc; //接口描述

? ? u16 max_buf_write_size; //最大缓存写长度

? ? u8? num_erase_regions; //擦除块扇区数量

? ? u32 erase_region_info[NUM_ERASE_REGIONS];? ? ? ? //4个块区的信息

} __attribute__((packed));

从上图可以看到,? 是获取了CFI query identification string?,System interface information,Device geometry definition? 信息,对照手册,? 就可以知道成员的数值

其中,最为重要的是擦写扇区信息?erase_region_info,对应手册的如下信息:



手册给出了扇区的信息,第一部分说明了扇区(block)的个数 : 0xff + 1 = 256 个,第二部分说明了一个扇区(block)大小: 0x200 * 256 =131072,即128K字节? ?


我们的flash,为00ff,和0200 .那么uint32_t的tmp 的数值应该为:? 0x020000ff


?? ? ? ? ? tmp = le32_to_cpu(qry.erase_region_info[i]); ?

? ? ? ? ? ? debug("erase region %u: 0x%08lxn",i,tmp); ?

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? erase_region_count = (tmp & 0xffff) + 1;? ? ?

? ? ? ? ? ? tmp >>= 16;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? erase_region_size =? (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; ?


tmp =? qry.erase_region_info[i] = 0x20000ff

tmp >>=16 后,tmp = 0x200

擦写扇区的大小 erase_region_size =? (tmp & 0xffff) * 256 = 0x20000,即一个扇区的大小为0x2000字节.

擦写扇区的个数 erase_region_count为0x201,即256个扇区

那么,可以知道,整个nor flash 总的容量为: 0x2000 * 256 = 33554432? 字节,?


验证一下: ? 33554432 / 1024 / 1024 = 32 M


? ? ? ? sect_cnt = 0;

? ? ? ? sector = base;//基地址为 0x1dc00000


那么会循环256次.


for (j = 0; j < erase_region_count; j++) {

..

? ? ? ? ? ? ? //在256次循环中,256个start成员保存各个扇区的地址

? ? ? ? ? ? ? ? info->start[sect_cnt] =

? ? ? ? ? ? ? ? ? ? (ulong)map_physmem(sector,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->portwidth,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MAP_NOCACHE);

? ? ? ? ? ? ? ? //计算各个扇区的地址,地址计算方法为,扇区的大小 * size_ratio(? 为 size_ratio = info->portwidth / info->chipwidth;,比值为1)?

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //可以看出,? 各个扇区的地址相隔一个扇区的大小

? ? ? ? ? ? ? ? sector += (erase_region_size * size_ratio);? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

… ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? sect_cnt++; ? ?

} ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? info->sector_count = sect_cnt;

? ? ? ? //buffer_size 为 1 << 8,256

info->buffer_size = 1 << (8 * info->portwidth);

}

循环结束后,? sect_cnt 的数值为 256

现在,所有扇区的地址都保存到了init->start数组里. 那么现在如果要向flash里烧写一个文件,? 在知道文件的大小的情况下,就可以计算出要使用几个扇区.?

include/flash.h:

#define CONFIG_SYS_MAX_FLASH_SECT ? (256) ? ? ? ? ?

typedef struct {

? ? ulong ? size; ? ? ? ? ? /* total bank size in bytes ? ? */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ushort? sector_count; ? ? ? /* number of erase units? ? ? ? */

? ? ulong ? flash_id; ? ? ? /* combined device & manufacturer code? */

? ? ulong ? start[CONFIG_SYS_MAX_FLASH_SECT]; ? /* virtual sector start address */

? ? uchar ? protect[CONFIG_SYS_MAX_FLASH_SECT]; /* sector protection status */

#ifdef CONFIG_SYS_FLASH_CFI

? ? uchar ? portwidth;? ? ? /* the width of the port? ? ? ? */

? ? uchar ? chipwidth;? ? ? /* the width of the chip? ? ? ? */

? ? ushort? buffer_size;? ? ? ? /* # of bytes in write buffer ? ? ? */

? ? ulong ? erase_blk_tout; ? ? /* maximum block erase timeout? ? ? */

? ? ulong ? write_tout; ? ? /* maximum write timeout? ? ? ? */

? ? ulong ? buffer_write_tout;? /* maximum buffer write timeout ? ? */

? ? ushort? vendor; ? ? ? ? /* the primary vendor id? ? ? ? */

? ? ushort? cmd_reset;? ? ? /* vendor specific reset command? ? */

? ? ushort? interface;? ? ? /* used for x8/x16 adjustments? ? ? */

? ? ushort? legacy_unlock;? ? ? /* support Intel legacy (un)locking */

? ? ushort? manufacturer_id;? ? /* manufacturer id? ? ? ? ? */

? ? ushort? device_id;? ? ? /* device id? ? ? ? ? ? ? ? */

? ? ushort? device_id2; ? ? /* extended device id ? ? ? ? ? */

? ? ushort? ext_addr; ? ? ? /* extended query table address ? ? */

? ? ushort? cfi_version;? ? ? ? /* cfi version? ? ? ? ? ? ? */

? ? ushort? cfi_offset; ? ? /* offset for cfi query ? ? ? ? */

? ? ulong ? addr_unlock1; ? ? ? /* unlock address 1 for AMD flash roms? */

? ? ulong ? addr_unlock2; ? ? ? /* unlock address 2 for AMD flash roms? */

? ? const char *name; ? ? ? /* human-readable name? ? ? ? ? ? ? ? ? */

#endif? ? ? ? ?

} flash_info_t;



uboot 就是按照如上的思路来实现uboot的更新,common/cmd_flash.c 有很好的flash使用范例:



int do_upgrade (cmd_tbl_t *cmdtp,int flag,int argc,char * const argv[])

{? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? int rcode = 0; ? ? ? ? ?

? ? ulong addr,addr_first,addr_last;

? ? const bootloader_header_t *header;

?? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? if (argc != 4) { ? ? ? ?

? ? ? ? if (argc == 2 || argc == 3) {

? ? ? ? ? ? if (strcmp(argv[1],"uboot") != 0)

? ? ? ? ? ? ? ? return cmd_usage(cmdtp);

?? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? //获取环境变量loadaddr的数值,这是要更新的文件在内存里的起始地址?

? ? ? ? ? ? if (getenv("loadaddr") != NULL)

? ? ? ? ? ? ? ? addr = simple_strtoul(getenv("loadaddr"),NULL,16);

? ? ? ? ? ? else ? ? ? ? ? ?

? ? ? ? ? ? ? ? return cmd_usage(cmdtp);

?? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? //(0x1fc00000 - CONFIG_SYS_FLASH_SIZE)? = 0x1dc00000

?? ? ? ? ? //计算出uboot的起始地址

? ? ? ? ? ? addr_first = CONFIG_SYS_FLASH_BASE;

? ? ? ? ? ? if (argc == 3 && strcmp(argv[2],"all") == 0) {

? ? ? ? ? ? ? ? addr_last = addr_first + CONFIG_BOOT_SIZE - 1;

? ? ? ? ? ? }else? ? ? ? ? ?

? ? ? ? ? ? //CONFIG_ENV_ADDR = 0x1fbe0000

? ? ? ? ? ? //addr_last = 0x1fbdffff

?? ? ? ? ? ? //计算出uboot的结束地址

? ? ? ? ? ? ? ? addr_last = CONFIG_ENV_ADDR - 1;

?? ? ? ? ? ? ? ? ? ? ? ? ? ?

?? ? ? ? ? // 验证下载的uboot 释放符合bootload 的格式.

? ? ? ? ? ? header = (void *)addr;

? ? ? ? ? ? if (validate_header(header)) {

? ? ? ? ? ? ? ? printf("Image does not have valid header form addr:0x%lxn",addr);

? ? ? ? ? ? ? ? return 1;

? ? ? ? ? ? }? ? ? ? ? ? ? ?

...

?? //知道了uboot的起始,结束地址,就可以知道uboot在flash 里要使用几个扇区.?

? ? /*

? ? 一,先取消要使用的扇区保护,参数0 表示取消保护

? ? */ ? ? ?

? ? if ((rcode = flash_sect_protect(0,addr_last)) != 0)

? ? ? ? return rcode; ? ? ? ? ? ? ? ?

? ? //擦除要使用到的扇区 ? ? ? ?

? ? if ((rcode = flash_sect_erase(addr_first,addr_last)) != 0)

? ? ? ? return rcode; ? ? ? ? ? ? ??

? ? //向要使用到的扇区写入数据 ? ? ? ? ? ?

? ? puts ("Copy to Flash... ");

? ? if ((rcode = flash_write((char *)addr,addr_last - addr_first)) != 0) {

? ? ? ? flash_perror(rcode);

? ? ? ? return 1;? ? ? ?

? ? }? ? ? ? ? ? ? ? ? ?

? ? puts ("donen"); ? ?

?? ? ? ? ? ? ? ? ? ? ? ?

? ? return 0;? ? ? ? ? ?

}

int flash_sect_protect (int p,ulong addr_first,ulong addr_last)

{? ?

? ? flash_info_t *info;

? ? ulong bank;

? ? int s_first[CONFIG_SYS_MAX_FLASH_BANKS],s_last[CONFIG_SYS_MAX_FLASH_BANKS];

? ? int protected,i;

? ? int planned;

? ? int rcode;

?? ?

? ? /*

? ? 通过flash的起始地址和结束地址,计算出起始扇区和结束扇区,以及要使用到的扇区个数,分别保存到s_first,s_last,planned 中.

? ? */

? ? rcode = flash_fill_sect_ranges( addr_first,addr_last,s_first,&planned );


static int ? ?

flash_fill_sect_ranges (ulong addr_first,ulong addr_last,

? ? ? ? ? ? int *s_first,int *s_last,

? ? ? ? ? ? int *s_count )

{? ? ? ? ? ? ?

? ? flash_info_t *info;

? ? ulong bank;

? ? int rcode = 0;

?? ? ? ? ? ? ?

? ? *s_count = 0;

? ? //初始化参数? ? ? ? ?

? ? for (bank=0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? s_first[bank] = -1; /* first sector to erase? ? */

? ? ? ? s_last [bank] = -1; /* last? sector to erase? ? */

? ? }? ? ? ? ?

?? ? ? ? ? ? ?

? ? //只有一次循环

? ? for (bank=0,info = &flash_info[0];

?? ? ? ? (bank < CONFIG_SYS_MAX_FLASH_BANKS) && (addr_first <= addr_last);

?? ? ? ? ++bank,++info) {

? ? ? ? ulong b_end;

? ? ? ? int sect;

? ? ? ? short s_end;

?? ? ? ? ? ? ?

? ? ? ? if (info->flash_id == FLASH_UNKNOWN) {

? ? ? ? ? ? continue;

? ? ? ? }? ? ?

?? ? ? ? ?

? ? ? //start[0]保存的是flash的起始地址,size是整个芯片的大小,那么info->start[0] + info->size - 1的 含义就是 整个芯片的结束地址

? ? ? ? b_end = info->start[0] + info->size - 1;? ? /* bank end addr */

?? ? ? //最后一个扇区的标号 ? ? ?

? ? ? ? s_end = info->sector_count - 1; ? ? ? ? /* last sector ? */

?? ? ? ? ? ? ?

? ? ? ? ? ? ? //遍历所有扇区,即256个扇区

? ? ? ? for (sect=0; sect < info->sector_count; ++sect) {

? ? ? ? ? ? ulong end;? /* last address in current sect */

?? ? ? ? ? ? ?

?? ? ? ? ? //当前扇区的最后地址

? ? ? ? ? ? end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;

?? ? ? ? ? ? ?

? ? ? ? ? ? if (addr_first > end)

? ? ? ? ? ? ? ? continue;


? ? ? ? ? //当uboot的结束地址小于当前扇区的地址时,直接判断下个扇区. 目的是快速找到uboot的结束地址所在flash的扇区.?

? ? ? ? ? ? if (addr_last < info->start[sect])

? ? ? ? ? ? ? ? continue;


?? ? ? ? ? ? ? //当文件起始地址等于扇区起始地址,将当前扇区地址保存到s_first[0] 中.

? ? ? ? ? ? if (addr_first == info->start[sect]) {

? ? ? ? ? ? ? ? s_first[bank] = sect;

? ? ? ? ? ? } ?

?? ? ? ? ? ? //当文件结束地址等于当前扇区结束地址时,将当前扇区标号保存到s_last[0]中.. 这个部分uboot的代码需要优化,正常的逻辑下,这个时候可以直接break了. 无须再进入循环. 本人已经验证通过

? ? ? ? ? ? if (addr_last? == end) {

? ? ? ? ? ? ? ? s_last[bank]? = sect;

? ? ? ? ? ? } ?

? ? ? ? }? ? ?

? ? ? ? //如果s_first[0]有数值,即查找成功的话,计算出占有了几个扇区. ?

? ? ? ? if (s_first[bank] >= 0) {

?? ? ? ? ? //如果没有找到s_last,有两种情况,如果目标文件大于flash的大小,那么设定s_last 为最后一个扇区. 否则是逻辑错误.?

? ? ? ? ? ? if (s_last[bank] < 0) {

? ? ? ? ? ? ? ? if (addr_last > b_end) {

? ? ? ? ? ? ? ? ? ? s_last[bank] = s_end;

? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? puts ("Error: end address"

? ? ? ? ? ? ? ? ? ? ? ? " not on sector boundaryn");

? ? ? ? ? ? ? ? ? ? rcode = 1;

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }? //如果得到的结果是结束的扇区标号小于起始扇区标号,也是逻辑错误

? ? ? ? ? ? if (s_last[bank] < s_first[bank]) {

? ? ? ? ? ? ? ? puts ("Error: end sector"

? ? ? ? ? ? ? ? ? ? " precedes start sectorn");

? ? ? ? ? ? ? ? rcode = 1;

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }?

?? ? ? ? ? //记录结束扇区的编号.

? ? ? ? ? ? sect = s_last[bank];

? ? ? ? ? ? addr_first = (sect == s_end) ? b_end + 1: info->start[sect + 1];

?? ? ? ? ? ? //s_last[bank] - s_first[bank]? + 1 就是中间的扇区个数

? ? ? ? ? ? (*s_count) += s_last[bank] - s_first[bank] + 1;

? ? ? ? } else if (addr_first >= info->start[0] && addr_first < b_end) {

? ? ? ? ? ? puts ("Error: start address not on sector boundaryn");

? ? ? ? ? ? rcode = 1;

? ? ? ? ? ? break;

? ? ? ? } else if (s_last[bank] >= 0) {

? ? ? ? ? ? puts ("Error: cannot span across banks when they are"

?? ? ? ? ? ? ? ? ? " mapped in reverse ordern");

? ? ? ? ? ? rcode = 1;

? ? ? ? ? ? break; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? }? ? ?

? ? }? ? ? ? ?

?? ? ? ? ? ? ?

? ? return rcode;

}

回到:


#ifndef CONFIG_SYS_NO_FLASH

int flash_sect_protect (int p,ulong addr_last)

{? ? ? ? ? ? ? ? ? ?

? ? flash_info_t *info;

? ? ulong bank; ?

? ? int s_first[CONFIG_SYS_MAX_FLASH_BANKS],s_last[CONFIG_SYS_MAX_FLASH_BANKS];

? ? int protected,i;

? ? int planned;?

? ? int rcode; ??? ? ? ? ? ? ? ? ??

? ? rcode = flash_fill_sect_ranges( addr_first,&planned );

??

? ? protected = 0;

?? ?

? ? if (planned && (rcode == 0)) {

? ? ? ? for (bank=0,info = &flash_info[0]; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank,++info) {

? ? ? ? ? ? if (info->flash_id == FLASH_UNKNOWN) {

? ? ? ? ? ? ? ? continue;

? ? ? ? ? ? }

?? ?

? ? ? ? ? ? if (s_first[bank]>=0 && s_first[bank]<=s_last[bank]) {

? ? ? ? ? ? ? ? debug ("%sProtecting sectors %d..%d in bank %ldn",

? ? ? ? ? ? ? ? ? ? p ? "" : "Un-",

? ? ? ? ? ? ? ? ? ? s_first[bank],s_last[bank],bank+1);

? ? ? ? ? ? ? ? protected += s_last[bank] - s_first[bank] + 1;


?? ? ? ? ? ? ? //为获取到的扇区取消保护

? ? ? ? ? ? ? ? for (i=s_first[bank]; i<=s_last[bank]; ++i) {

#if defined(CONFIG_SYS_FLASH_PROTECTION)

?? ? ? ? ? ? ? ? ? //就是? 改变 info->addr_unlock1 的标识和将info->protect 的对应成员置0,否则后面不能 erase 和write

? ? ? ? ? ? ? ? ? ? if (flash_real_protect(info,p))

? ? ? ? ? ? ? ? ? ? ? ? rcode = 1;

? ? ? ? ? ? ? ? ? ? putc ('.');

#else

? ? ? ? ? ? ? ? ? ? info->protect[i] = p;

#endif? /* CONFIG_SYS_FLASH_PROTECTION */

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

#if defined(CONFIG_SYS_FLASH_PROTECTION)

? ? ? ? puts (" donen");

#endif? /* CONFIG_SYS_FLASH_PROTECTION */

?? ?

? ? ? ? printf ("%sProtected %d sectorsn",

? ? ? ? ? ? p ? "" : "Un-",protected);

? ? } else if (rcode == 0) {

? ? ? ? puts ("Error: start and/or end address"

? ? ? ? ? ? " not on sector boundaryn");

? ? ? ? rcode = 1;

? ? }

? ? return rcode;

}

?? ? ? ? ? ? ? ? ? ?

#ifndef CONFIG_SYS_NO_FLASH

int flash_sect_erase (ulong addr_first,ulong addr_last)

{? ? ? ? ? ? ? ? ? ?

? ? flash_info_t *info;

? ? ulong bank;? ? ?

? ? int s_first[CONFIG_SYS_MAX_FLASH_BANKS],s_last[CONFIG_SYS_MAX_FLASH_BANKS];

? ? int erased = 0;?

? ? int planned; ? ?

? ? int rcode = 0; ?

?? ? ? ? ? ? ? ?

? ? //跟之前取消保护一样,也需要通过给定地址计算出要操作的扇区. 这个地方实在多余,完全可以使用之前已经获取到的数据作为参数传下来.?

?? ? ? ? //总之 flash_sect_erase 和 flash_sect_protect 的重复度太高? ?

? ? rcode = flash_fill_sect_ranges (addr_first,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? s_first,&planned );

?? ? ? ? ? ? ? ? ? ?

? ? if (planned && (rcode == 0)) {

? ? ? ? for (bank=0,info = &flash_info[0];

?? ? ? ? ? ? (bank < CONFIG_SYS_MAX_FLASH_BANKS) && (rcode == 0);

?? ? ? ? ? ? ++bank,++info) {

? ? ? ? ? ? if (s_first[bank]>=0) {

? ? ? ? ? ? ? ? erased += s_last[bank] - s_first[bank] + 1;

? ? ? ? ? ? ? ? debug ("Erase Flash from 0x%08lx to 0x%08lx "

? ? ? ? ? ? ? ? ? ? "in Bank # %ld ",

? ? ? ? ? ? ? ? ? ? info->start[s_first[bank]],

? ? ? ? ? ? ? ? ? ? (s_last[bank] == info->sector_count) ?

? ? ? ? ? ? ? ? ? ? ? ? info->start[0] + info->size - 1:

? ? ? ? ? ? ? ? ? ? ? ? info->start[s_last[bank]+1] - 1,

? ? ? ? ? ? ? ? ? ? bank+1);

?? ? ? ? ? ? ? //flash_erase 是drivers/mtd/cfi_flash.c 提供的flash 擦除接口.

? ? ? ? ? ? ? ? rcode = flash_erase (info,s_first[bank],s_last[bank]);

? ? ? ? ? ? }? ? ? ?

? ? ? ? }? ? ? ? ? ?

? ? ? ? printf ("Erased %d sectorsn",erased);

? ? } else if (rcode == 0) {

? ? ? ? puts ("Error: start and/or end address"

? ? ? ? ? ? " not on sector boundaryn");

? ? ? ? rcode = 1; ?

? ? }? ? ? ? ? ? ? ?

? ? return rcode;? ?

}? ? ? ? ? ? ? ? ? ?

#endi


int flash_erase (flash_info_t * info,int s_first,int s_last)

{? ?

?? ?

?? ?

? ? for (sect = s_first; sect <= s_last; sect++) {

? ? ? ? ////如果扇区处于保护状态,将无法擦除

? ? ? ? if (info->protect[sect] == 0) { /* not protected */

? ? ? ? ? ? switch (info->vendor) {

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case CFI_CMDSET_AMD_STANDARD:

? ? ? ? ? ? case CFI_CMDSET_AMD_EXTENDED:

? ? ? ? ? ? ? ? flash_write_cmd (info,AMD_CMD_RESET);? ? // (1)

? ? ? ? ? ? ? ? flash_unlock_seq (info,sect); //(2)

? ? ? ? ? ? ? ? flash_write_cmd (info,sect,? info->addr_unlock1,AMD_CMD_ERASE_START); //(3)

? ? ? ? ? ? ? ? flash_unlock_seq (info,sect);//(4)

? ? ? ? ? ? ? ? flash_write_cmd (info,AMD_CMD_ERASE_SECTOR);//(5)

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }


/*


根据手册,扇区的擦写动作指令为:





#define AMD_CMD_UNLOCK_START? ? ? ? 0xAA

#define AMD_CMD_UNLOCK_ACK? ? ? 0x55

static void flash_unlock_seq (flash_info_t * info,flash_sect_t sect){

? ? flash_write_cmd (info,info->addr_unlock1,AMD_CMD_UNLOCK_START);

? ? flash_write_cmd (info,info->addr_unlock2,AMD_CMD_UNLOCK_ACK);

}

?

全部擦写的操作是,?


__RESET?


1,? 向 0xaaa? 写入 aa ?

2,? 向 0x555 写入 55

3,? 向 0xaaa 写入80

4,向 0xaaa 写入aa

5,向0x555? 写入55

6,向扇区地址 写入30


__RESET 由(1) 完成


1,2 由 (2) 完成


3 由 (3)完成


4,5由(4)完成


6 由 (5)完成


*/


/*

指令的下发后,还要使用状态查询函数,等待指令的完成,即硬件的执行完成. 这个过程是最耗时的.?

*/


? ? ? ? ? ? if (use_flash_status_poll(info)) {

? ? ? ? ? ? ? ? cfiword_t cword = (cfiword_t)0xffffffffffffffffULL;

? ? ? ? ? ? ? ? void *dest;

?? ? ? //获取扇区的内存地址

? ? ? ? ? ? ? ? dest = flash_map(info,0);

?? ? ? ? ? ? ? //传入的超时时间为 info->erase_blk_tout,这个数值为:? (1 << qry.block_erase_timeout_typ) * (1 << qry.block_erase_timeout_max)

//根据手册,计算出扇区最大超时时间为: 4096s,? 意味着,如果4096s内扇区还没有擦写完成,那么就超时退出

? ? ? ? ? ? ? ? st = flash_status_poll(info,&cword,dest,info->erase_blk_tout,"erase");

? ? ? ? ? ? ? ? flash_unmap(info,dest);

? ? ? ? ? ? } else

? ? ? ? ? ? ? ? st = flash_full_status_check(info,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->erase_blk_tout,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "erase");

? ? ? ? ? ? if (st)

? ? ? ? ? ? ? ? rcode = 1;

? ? ? ? ? ? else if (flash_verbose)

? ? ? ? ? ? ? ? putc ('.');

? ? ? ? ? ? if (ctrlc()) {

? ? ? ? ? ? ? ? puts(" Interruptedn");

? ? ? ? ? ? ? ? return 1;

? ? ? ? ? ? }

? ? ? ? }

? ? }

?? ?

? ? if (flash_verbose)

? ? ? ? puts (" donen");

?? ?

? ? return rcode;

} ??? ?

static int flash_status_poll(flash_info_t *info,void *src,void *dst,

?? ? ? ? ? ? ? ? ulong tout,char *prompt)

{? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

#ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL? ?

? ? ulong start; ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? int ready; ? ? ? ? ? ? ? ? ? ? ? ? ? ?

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

… ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? start = get_timer(0);? ? ? ? ? ? ? ? ?

? ? WATCHDOG_RESET();? ? ? ? ? ? ? ? ? ? ?

? ? while (1) {? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? switch (info->portwidth) { ? ? ? ?

? ? ? ? case FLASH_CFI_8BIT:? ?

?? ? ? ? ? /*根据flash 的位宽(portwidth),判断目的地址的数值是否等于src地址的数值. 上面传下来src的数值为全f,dst地址是当前扇区的0地址,?

?? ? ? ? ? ? ? ? ? ? ? ? ? 那么flash_erase 的擦写指令完成的判断条件是:? 当前扇区的0地址的数值为0xff?

?? ? ? ? ? 如果判断条件成立后跳出循环,? 否则udelay后,再次进入循环 */ ? ? ? ?

? ? ? ? ? ? ready = flash_read8(dst) == flash_read8(src);

? ? ? ? ? ? break; ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? case FLASH_CFI_16BIT:? ? ? ? ? ? ?

? ? ? ? ? ? ready = flash_read16(dst) == flash_read16(src);

? ? ? ? ? ? break; ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? case FLASH_CFI_32BIT:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ready = flash_read32(dst) == flash_read32(src);

? ? ? ? ? ? break; ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? case FLASH_CFI_64BIT:? ? ? ? ? ? ?

? ? ? ? ? ? ready = flash_read64(dst) == flash_read64(src);

? ? ? ? ? ? break; ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? default: ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ready = 0; ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? break; ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? if (ready) ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? break; ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? if (get_timer(start) > tout) { ? ?

? ? ? ? ? ? printf("Flash %s timeout at address %lx data %lxn",

?? ? ? ? ? ? ? ? ? prompt,(ulong)dst,(ulong)flash_read8(dst));

? ? ? ? ? ? return ERR_TIMOUT; ? ? ? ? ? ?

? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? udelay(1);? ? ? /* also triggers watchdog */

? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

#endif /* CONFIG_SYS_CFI_FLASH_STATUS_POLL */

? ? return ERR_OK; ? ? ? ? ? ? ? ? ? ? ? ?

}

回到do_upgrade,? 扇区擦写完成后,调用flash_write 进行写入操作


code = flash_write((char *)addr,addr_last - addr_first)) != 0) {


src? 是要烧些的文件的起始,addr 是要烧写到flash的目的地址,cnt 是要烧写的长度

int flash_write (char *src,ulong addr,ulong cnt){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? int i; ? ? ? ? ? ? ? ? ? ? ?

? ? ulong ? ? ? ? end? ? ? ? = addr + cnt - 1;

? ? //在单个bank的flash里,只有一个info,info_first等于info_last

? ? flash_info_t *info_first = addr2info (addr);

? ? flash_info_t *info_last? = addr2info (end );

? ? flash_info_t *info; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? //在单个bank的flash里,只有一次循环 ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? for (info = info_first; info <= info_last; ++info) {

? ? ? ? ulong b_end = info->start[0] + info->size;? /* bank end addr */

? ? ? ? short s_end = info->sector_count - 1;

? ? ? ? for (i=0; i<info->sector_count; ++i) {

? ? ? ? ? ? ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];?

? ? ? ? ? ? //如果要操作的扇区没有取消保护,直接返回 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? if ((end >= info->start[i]) && (addr < e_addr) &&

? ? ? ? ? ? ? ? (info->protect[i] != 0) ) {

? ? ? ? ? ? ? ? return (ERR_PROTECTED);

? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ?

? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ?

? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ?

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? /* finally write data to flash */

? ? for (info = info_first; info <= info_last && cnt>0; ++info) {

? ? ? ? ulong len; ? ? ? ? ? ? ?

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? len = info->start[0] + info->size - addr;

? ? ? ? if (len > cnt) ? ? ? ? ?

? ? ? ? ? ? len = cnt;?

?? ? ? ? //单个bank的flash调用 write_buf后返回操作结果? ? ? ? ?

? ? ? ? if ((i = write_buff(info,(uchar *)src,addr,len)) != 0) {

? ? ? ? ? ? return (i);? ? ? ? ?

? ? ? ? }?

? ? ? ? //多个bank的情况 ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? cnt? -= len; ? ? ? ? ? ?

? ? ? ? addr += len; ? ? ? ? ? ?

? ? ? ? src? += len; ? ? ? ? ? ?

? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? return (ERR_OK);? ? ? ?

} ?



//info 为flash的数据结构,src为源文件的内存地址,addr 为目的flash 地址,cnt 为文件要写的长度 ?

int write_buff (flash_info_t * info,uchar * src,ulong cnt)

{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ulong wp; ? ? ? ? ? ? ? ? ? ?

? ? uchar *p; ? ? ? ? ? ? ? ? ? ?

? ? int aln;? ? ? ? ? ? ? ? ? ? ?

? ? cfiword_t cword;? ? ? ? ? ? ?

? ? int i,rc;? ? ? ? ? ? ? ? ? ?

#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE

? ? int buffered_size;? ? ? ? ? ?

#endif? ? ? ? ? ? ? ? ? ? ? ? ? ?

#ifdef CONFIG_FLASH_SHOW_PROGRESS

? ? int digit = CONFIG_FLASH_SHOW_PROGRESS;

? ? int scale = 0;? ? ? ? ? ? ? ?

? ? int dots? = 0;? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? /*? ? ? ? ? ? ? ? ? ? ? ? ? ?

?? ? * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes.

?? ? */ ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) {

? ? ? ? scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) /

? ? ? ? ? ? CONFIG_FLASH_SHOW_PROGRESS);

? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ?

#endif ? ? ? ? ? ?

?? ? ? //wp的数值为addr? ? ? ? ? ? ? ?

? ? ? ? wp = (addr & ~(info->portwidth - 1));? ? ? ? ? ? ? ? ? ? ? ? ? ?

…? ? ? ? ? ? ? ? ? ? ? ? ? ?


? ? buffered_size = (info->portwidth / info->chipwidth);

? ? buffered_size *= info->buffer_size;

? ? //buffered_size 为256

? ? while (cnt >= info->portwidth) {

? ? ? ? //buffer_size 长度为1的情况,就是按字节写的情况

? ? ? ? if (info->buffer_size == 1) {

? ? ? ? ? ? cword.l = 0;? ? ? ? ?

? ? ? ? ? ? for (i = 0; i < info->portwidth; i++)

? ? ? ? ? ? ? ? flash_add_byte (info,*src++);

? ? ? ? ? ? if ((rc = flash_write_cfiword (info,wp,cword)) != 0)

? ? ? ? ? ? ? ? return rc;? ? ? ?

? ? ? ? ? ? wp += info->portwidth;

? ? ? ? ? ? cnt -= info->portwidth;

? ? ? ? ? ? continue; ? ? ? ? ? ?

? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? //buffer_size 不为1,按buffer 写的情况

? ? ? ? ? ? ? ? ? ? //如果地址为buffer_size 的整数倍,那么i 就等于 buffer_size.256 字节.

? ? ? ? ? ? ? ? ? ? //可以看到,按缓存写的话,总共会执行 ? (文件长度? / 256 + 1 次) . 如果要写入的长度为 0xdffff,那么要执行的次数为 0xdffff / 256 + 1? = 3584 次.

? ? ? ? i = buffered_size - (wp % buffered_size);

? ? ? ? if (i > cnt)? ? ? ? ? ? ?

? ? ? ? ? ? i = cnt;? ? //如果缓存写长度大于剩余的要写入的文件长度,那么长度截为cnt? ? ? ? ?

? ? ? ? if ((rc = flash_write_cfibuffer (info,src,i)) != ERR_OK)

? ? ? ? ? ? return rc;? ? ? ? ? ?

? ? ? ? i -= i & (info->portwidth - 1);

? ? ? ? wp += i; ? //要写入的内容的地址移动 i 长度 ? ? ? ? ? ? ?

? ? ? ? src += i; //要写入的文件的地址向后移动 i 长度

? ? ? ? cnt -= i; ? //文件的剩余长度减去 i 长度? ? ? ? ? ? ?

? ? ? ? FLASH_SHOW_PROGRESS(scale,dots,digit,i);

? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? if (cnt == 0) { ? ? ? ? ? ? ?

? ? ? ? return (0); ? ? ? ? ? ? ?

? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? /*? ? ? ? ? ? ? ? ? ? ? ? ? ?

?? ? * handle unaligned tail bytes

?? ? */ ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? cword.l = 0;? ? ? ? ? ? ? ? ?

? ? p = (uchar *)wp;? ? ? ? ? ? ?

? ? for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {

? ? ? ? flash_add_byte (info,*src++);

? ? ? ? --cnt; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? for (; i < info->portwidth; ++i)

? ? ? ? flash_add_byte (info,flash_read8(p + i));

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? return flash_write_cfiword (info,cword);

}?



对于字节写和缓存写,分别 有flash_write_cfiword 和flash_write_cfibuffer 实现

static int flash_write_cfiword (flash_info_t * info,ulong dest,

? ? ? ? ? ? ? ? cfiword_t cword)

{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? void *dstaddr = (void *)dest;

? ? int flag; ? ? ? ? ? ? ? ? ?

? ? flash_sect_t sect = 0;? ? ?

? ? char sect_found = 0;? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? //根据端口宽度,判断要操作的地址上的数值是否为cword的数值.?

? ? ? ? //上面传的cword 为0,那么要判断要写的地址的数值是否为0,如果判断结果为假,那么退出,返回ERR_NOT_ERASE错误数值.提示没有经过擦写.

? ? switch (info->portwidth) {?

? ? case FLASH_CFI_8BIT:? ? ? ?

? ? ? ? flag = ((flash_read8(dstaddr) & cword.c) == cword.c);

? ? ? ? break;? ? ? ? ? ? ? ? ?

? ? case FLASH_CFI_16BIT: ? ? ?

? ? ? ? flag = ((flash_read16(dstaddr) & cword.w) == cword.w);

? ? ? ? break;? ? ? ? ? ? ? ? ?

? ? case FLASH_CFI_32BIT: ? ? ?

? ? ? ? flag = ((flash_read32(dstaddr) & cword.l) == cword.l);

? ? ? ? break;? ? ? ? ? ? ? ? ?

? ? case FLASH_CFI_64BIT: ? ? ?

? ? ? ? flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);

? ? ? ? break;? ? ? ? ? ? ? ? ?

? ? default:? ? ? ? ? ? ? ? ? ?

? ? ? ? flag = 0; ? ? ? ? ? ? ?

? ? ? ? break;? ? ? ? ? ? ? ? ?

? ? } ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? if (!flag)? ? ? ? ? ? ? ? ?

? ? ? ? return ERR_NOT_ERASED;?

?? //上面看到,flash在执行烧些前,要先取消保护,再进行擦除,当两者都成功后,才可以进行write?


? ? //在执行烧些过程中,关闭全部中断,所有的中断新号会被忽略

? ? flag = disable_interrupts ();

?? ? ? ? ? ? ? ? ? ? ? ?

? ? //根据不同厂商,执行对应的指令. ? ? ? ?

? ? switch (info->vendor) { ? ?

? ? case CFI_CMDSET_INTEL_PROG_REGIONS:

?? case CFI_CMDSET_INTEL_EXTENDED:

? ? case CFI_CMDSET_INTEL_STANDARD://intel 的规范

? ? ? ? flash_write_cmd (info,FLASH_CMD_CLEAR_STATUS);

? ? ? ? flash_write_cmd (info,FLASH_CMD_WRITE);

? ? ? ? break; ? ? ? ? ? ? ? ? ?

? ? case CFI_CMDSET_AMD_EXTENDED:

? ? case CFI_CMDSET_AMD_STANDARD: //AMD 的规范

? ? ? ? ? ? ? ? ? //根据目的地址找到要操作的扇区

? ? ? ? sect = find_sector(info,dest);

? ? ? ? //解锁扇区

? ? ? ? flash_unlock_seq (info,sect);

//输入write 指令

? ? ? ? flash_write_cmd (info,AMD_CMD_WRITE);

? ? ? ? sect_found = 1;? ? ? ? ?

? ? ? ? break; ? ? ? ? ? ? ? ? ?

…? ? ? ? ? ? ? ? ? ? ? ? ?

? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ?

?? ? ? ? ?

? ? //等待指令完成 ? ? ? ? ? ? ? ? ? ? ?

? ? switch (info->portwidth) { ?

? ? case FLASH_CFI_8BIT: ? ? ? ?

? ? ? ? flash_write8(cword.c,dstaddr);

? ? ? ? if (info->vendor != 1) {

? ? ? ? ? ? while (flash_read8(dstaddr) != cword.c)

? ? ? ? ? ? ? ? ;? ? ? ? ? ? ? ?

? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? break; ? ? ? ? ? ? ? ? ?

? ? case FLASH_CFI_16BIT:? ? ? ?

? ? ? ? flash_write16(cword.w,dstaddr);

? ? ? ? if (info->vendor != 1) {

? ? ? ? ? ? while (flash_read16(dstaddr) != cword.w)

? ? ? ? ? ? ? ? ;? ? ? ? ? ? ? ?

? ? ? ? }? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? break; ? ? ? ? ? ? ? ? ?

? ? case FLASH_CFI_32BIT:? ? ? ?

? ? ? ? flash_write32(cword.l,dstaddr); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?


? ? case FLASH_CFI_64BIT:? ?

? ? ? ? flash_write64(cword.ll,dstaddr);

? ? ? ? if (info->vendor != 1) {

? ? ? ? ? ? while (flash_read64(dstaddr) != cword.ll)

? ? ? ? ? ? ? ? ; ? ? ?

? ? ? ? } ? ? ? ? ? ? ?

? ? ? ? break;? ? ? ? ?

? ? } ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ?

? ? //恢复中断

? ? if (flag) ? ? ? ? ?

? ? ? ? enable_interrupts (); ?

? ? ? ? ? ? ? ? ? ? ? ?

? ? if (!sect_found)? ?

? ? ? ? sect = find_sector (info,dest);

? ? ? ? ? ? ? ? ? ? ? ?

? ? if (use_flash_status_poll(info))

? ? ? ? return flash_status_poll(info,dstaddr,

?? ? ? ? ? ? ? ? ? ? info->write_tout,"write");

? ? else? ? ? ? ? ? ? ?

? ? ? ? return flash_full_status_check(info,

?? ? ? ? ? ? ? ? ? ? ? ? ? info->write_tout,"write");

}?



flash_write_cfibuffer 使用了同样的逻辑,不同的指令

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读