在上一节中,不知道你有没有注意到,启动u-boot后,运行有一行信息:
输出Flash信息这一部分代码是位于board_init_r阶段,执行initr_flash()函数的输出结果。
我们开发板上搭载了型号为S29AL016D70TF102的2MB(1M*16bit)大小的NOR FLASH,这里输出NOR FALSH大小为0字节,很明显没有能正确识别 2M的NOR FLASH了。
这一节我们将会介绍u-boot如何支持我们的NOR FLASH,这样我们后续就可以通过命令行对NOR FALSH进行读写操作。
一、NOR FLASH支持
1.1 分析启动信息
在NOR启动时,我们打印调试信息:
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 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 be ea00 0 0 Bytes
打印出NOR FLASH的厂家ID=0x01(AMD生产),,设备ID=0x2249,我们查看S29AL016D70TF102芯片的datasheet,发现这两个ID是正确的,但是没有检测到,说明程序底层驱动是对的,但是板子没支持这个NOR:
我们定位到 initr_flash(common/board_r.c):
static int initr_flash(void) { ulong flash_size = 0; bd_t *bd = gd->bd; puts("Flash: "); if (board_flash_wp_on()) printf("Uninitialized - Write Protect On\n"); else flash_size = flash_init(); print_size(flash_size, ""); #ifdef CONFIG_SYS_FLASH_CHECKSUM /* * Compute and print flash CRC if flashchecksum is set to 'y' * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */ if (getenv_yesno("flashchecksum") == 1) { printf(" CRC: %08X", crc32(0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)); } #endif /* CONFIG_SYS_FLASH_CHECKSUM */ putc('\n'); /* update start of FLASH memory */ #ifdef CONFIG_SYS_FLASH_BASE bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; #endif /* size of FLASH memory (final value) */ bd->bi_flashsize = flash_size; #if defined(CONFIG_SYS_UPDATE_FLASH_SIZE) /* Make a update of the Memctrl. */ update_flash_size(flash_size); #endif #if defined(CONFIG_OXC) || defined(CONFIG_RMU) /* flash mapped at end of memory map */ bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size; #elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE bd->bi_flashoffset = monitor_flash_len; /* reserved area for monitor */ #endif return 0; }
flash_init函数在drivers\mtd\cfi_flash.c中定义:
unsigned long flash_init (void) { unsigned long size = 0; int i; #ifdef CONFIG_SYS_FLASH_PROTECTION /* read environment from EEPROM */ char s[64]; getenv_f("unlock", s, sizeof(s)); #endif #ifdef CONFIG_CFI_FLASH /* for driver model */ cfi_flash_init_dm(); #endif /* Init: no FLASHes known */ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) { flash_info[i].flash_id = FLASH_UNKNOWN; //0xFFFF /* Optionally write flash configuration 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 ("## Unknown flash 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 */ } #ifdef CONFIG_SYS_FLASH_PROTECTION else if (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 all sectors */ 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 */ } flash_protect_default(); #ifdef CONFIG_FLASH_CFI_MTD cfi_mtd_init(); #endif return (size); }
其中CONFIG_SYS_MAX_FLASH_BANKS定义为1,FLASH_UNKNOWN 定义为0xFFFF:
#define CONFIG_SYS_MAX_FLASH_BANKS 1 #define FLASH_UNKNOWN 0xFFFF /* unknown flash type */
flash_info定义如下:
#define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS flash_info_t flash_info[CFI_MAX_FLASH_BANKS]; /* FLASH chips info */
/*----------------------------------------------------------------------- * FLASH Info: contains chip specific data, per FLASH bank */ 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 */ uchar cmd_erase_sector; /* vendor specific erase sect. 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 #ifdef CONFIG_MTD struct mtd_info *mtd; #endif } flash_info_t;View Code
这里我们重点分析flash_detect_legacy和flash_get_size函数。
1.2 flash_detect_legacy
/*----------------------------------------------------------------------- * Call board code to request info about non-CFI flash. * board_flash_get_legacy needs to fill in at least: * info->portwidth, info->chipwidth and info->interface for Jedec probing. */ static int flash_detect_legacy(phys_addr_t base, int banknum) { flash_info_t *info = &flash_info[banknum]; if (board_flash_get_legacy(base, banknum, info)) { /* board code may have filled info completely. If not, we use JEDEC ID probing. */ if (!info->vendor) { int modes[] = { CFI_CMDSET_AMD_STANDARD, CFI_CMDSET_INTEL_STANDARD }; int i; for (i = 0; i < ARRAY_SIZE(modes); i++) { info->vendor = modes[i]; info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE); if (info->portwidth == FLASH_CFI_8BIT && info->interface == FLASH_CFI_X8X16) { info->addr_unlock1 = 0x2AAA; info->addr_unlock2 = 0x5555; } else { info->addr_unlock1 = 0x5555; info->addr_unlock2 = 0x2AAA; } flash_read_jedec_ids(info); debug("JEDEC PROBE: ID %x %x %x\n", info->manufacturer_id, info->device_id, info->device_id2); if (jedec_flash_match(info, info->start[0])) break; else unmap_physmem((void *)info->start[0], info->portwidth); } } switch(info->vendor) { case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: info->cmd_reset = FLASH_CMD_RESET; break; case CFI_CMDSET_AMD_STANDARD: case CFI_CMDSET_AMD_EXTENDED: case CFI_CMDSET_AMD_LEGACY: info->cmd_reset = AMD_CMD_RESET; break; } info->flash_id = FLASH_MAN_CFI; return 1; } return 0; /* use CFI */ }
进入jedec_flash_match函数,位于drivers/mtd/jedec_flash.c:
/*----------------------------------------------------------------------- * match jedec ids against table. If a match is found, fill flash_info entry */ int jedec_flash_match(flash_info_t *info, ulong base) { int ret = 0; int i; ulong mask = 0xFFFF; if (info->chipwidth == 1) mask = 0xFF; for (i = 0; i < ARRAY_SIZE(jedec_table); i++) { if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) && (jedec_table[i].dev_id & mask) == (info->device_id & mask)) { fill_info(info, &jedec_table[i], base); ret = 1; break; } } return ret; }
进入jedec_table数组查看:
static const struct amd_flash_info jedec_table[] = { #ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8 { .mfr_id = (u16)SST_MANUFACT, .dev_id = SST39LF020, .name = "SST 39LF020", .uaddr = { [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ }, .DevSize = SIZE_256KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x01000,64), } }, #endif #ifdef CONFIG_SYS_FLASH_LEGACY_512Kx8 { .mfr_id = (u16)AMD_MANUFACT, .dev_id = AM29LV040B, .name = "AMD AM29LV040B", .uaddr = { [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000,8), } }, { .mfr_id = (u16)SST_MANUFACT, .dev_id = SST39LF040, .name = "SST 39LF040", .uaddr = { [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x01000,128), } }, { .mfr_id = (u16)STM_MANUFACT, .dev_id = STM_ID_M29W040B, .name = "ST Micro M29W040B", .uaddr = { [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000,8), } }, { .mfr_id = (u16)MX_MANUFACT, .dev_id = MX29LV040, .name = "MXIC MX29LV040", .uaddr = { [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000, 8), } }, { .mfr_id = (u16)WINB_MANUFACT, .dev_id = W39L040A, .name = "WINBOND W39L040A", .uaddr = { [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000, 8), } }, { .mfr_id = (u16)AMIC_MANUFACT, .dev_id = A29L040, .name = "AMIC A29L040", .uaddr = { [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000, 8), } }, { .mfr_id = (u16)EON_MANUFACT, .dev_id = EN29LV040A, .name = "EON EN29LV040A", .uaddr = { [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ }, .DevSize = SIZE_512KiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions= 1, .regions = { ERASEINFO(0x10000, 8), } }, #endif #ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16 { .mfr_id = (u16)AMD_MANUFACT, .dev_id = AM29F400BB, .name = "AMD AM29F400BB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_512KiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions= 4, .regions = { ERASEINFO(0x04000, 1), ERASEINFO(0x02000, 2), ERASEINFO(0x08000, 1), ERASEINFO(0x10000, 7), } }, { .mfr_id = (u16)AMD_MANUFACT, .dev_id = AM29LV400BB, .name = "AMD AM29LV400BB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_512KiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions= 4, .regions = { ERASEINFO(0x04000,1), ERASEINFO(0x02000,2), ERASEINFO(0x08000,1), ERASEINFO(0x10000,7), } }, { .mfr_id = (u16)AMD_MANUFACT, .dev_id = AM29LV800BB, .name = "AMD AM29LV800BB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_1MiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions= 4, .regions = { ERASEINFO(0x04000, 1), ERASEINFO(0x02000, 2), ERASEINFO(0x08000, 1), ERASEINFO(0x10000, 15), } }, { .mfr_id = (u16)AMD_MANUFACT, .dev_id = AM29LV800BT, .name = "AMD AM29LV800BT", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_1MiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions= 4, .regions = { ERASEINFO(0x10000, 15), ERASEINFO(0x08000, 1), ERASEINFO(0x02000, 2), ERASEINFO(0x04000, 1), } }, { .mfr_id = (u16)MX_MANUFACT, .dev_id = AM29LV800BT, .name = "MXIC MX29LV800BT", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_1MiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions= 4, .regions = { ERASEINFO(0x10000, 15), ERASEINFO(0x08000, 1), ERASEINFO(0x02000, 2), ERASEINFO(0x04000, 1), } }, { .mfr_id = (u16)EON_ALT_MANU, .dev_id = AM29LV800BT, .name = "EON EN29LV800BT", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_1MiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions= 4, .regions = { ERASEINFO(0x10000, 15), ERASEINFO(0x08000, 1), ERASEINFO(0x02000, 2), ERASEINFO(0x04000, 1), } }, { .mfr_id = (u16)STM_MANUFACT, .dev_id = STM29F400BB, .name = "ST Micro M29F400BB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_512KiB, .CmdSet = CFI_CMDSET_AMD_LEGACY, .NumEraseRegions = 4, .regions = { ERASEINFO(0x04000, 1), ERASEINFO(0x02000, 2), ERASEINFO(0x08000, 1), ERASEINFO(0x10000, 7), } }, #endif };
查询以后发现,确实是这里面没有我们所使用的NOR FLASH型号S29AL016D70TF102。
进入机器ID的宏定义代码,里面找到了这个:
#define AMD_MANUFACT 0x00010001 /* AMD manuf. ID in D23..D16, D7..D0 */
01就是我们使用的NOR FLASH厂家ID,说明u-boot是能够支持的,只是数组中没有将其写入。更改数组,加入我们自己的NOR FLASH,使其能够支持。
1.3 修改jedec_table数组(drivers/mtd/jedec_flash.c)
因为数组中有宏定义,我也不打算破坏它的结构了,随便复制了一个将其粘贴到数组的最后端。
{ .mfr_id = (u16)AMD_MANUFACT, .dev_id = AM29LV160DB, .name = "AMD AM29LV160DB", .uaddr = { [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ }, .DevSize = SIZE_2MiB, .CmdSet = P_ID_AMD_STD, .NumEraseRegions = 4, .regions = { ERASEINFO(64*1024, 31), ERASEINFO(32*1024, 1), ERASEINFO(8*1024, 2), ERASEINFO(16*1024, 1), } },
- 厂家ID:mfr_id修改为AMD_MANUFACT;
- 设备ID:dev_id修改为0x2249,即AM29LV160DB;
- 名字:name修改为AMD AM29LV160DB;
- uaddr:解锁地址改为[1] = MTD_UADDR_0x0555_0x02AA /* x16 */ /*NOR flash 解锁地址 */。[0]表示NOR是8位的,我使用的是16位的,因此改为1。NORFlash使用的时候会锁定,因此写的时候要先解锁,在一些地址中写入值才能解锁。解锁地址可以查阅手册。
- 大小:DevSize修改为SIZE_2MiB;
- NumEraseRegions:NOR的结构不同,擦除块是不同的。可以查阅手册,有多少种块,就写几。
- regions:说明擦除块的分布情况,从上往下分别是NOR中地址从低到高排布;
我使用的NOR有4种,分别8K字1块,4K字节1块,16K字1块,32K字31块。1K字大小为2048字节。
所以regions配置如下:
.regions = { ERASEINFO(64*1024, 31), ERASEINFO(32*1024, 1), ERASEINFO(8*1024, 2), ERASEINFO(16*1024, 1), }
修改include/configs/smdk2440.h文件,这里使用CONFIG_SYS_MAX_FLASH_SECT定义了我们NOR FLASH最大扇区数量,我们修改为128。 其实这个值多少都可以,只要大于使用的擦除块就行了。
#define CONFIG_SYS_MAX_FLASH_SECT (128)
1.4 flash_get_size
/* * The following code cannot be run from FLASH! * */ 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, 0, 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); if (flash_detect_cfi (info, &qry)) { info->vendor = le16_to_cpu(get_unaligned(&(qry.p_id))); info->ext_addr = le16_to_cpu(get_unaligned(&(qry.p_adr))); num_erase_regions = qry.num_erase_regions; if (info->ext_addr) { info->cfi_version = (ushort) flash_read_uchar (info, info->ext_addr + 3) << 8; info->cfi_version |= (ushort) flash_read_uchar (info, info->ext_addr + 4); } #ifdef DEBUG flash_printqry (&qry); #endif switch (info->vendor) { case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: cmdset_intel_init(info, &qry); break; case CFI_CMDSET_AMD_STANDARD: case CFI_CMDSET_AMD_EXTENDED: cmdset_amd_init(info, &qry); break; default: printf("CFI: Unknown command set 0x%x\n", info->vendor); /* * Unfortunately, this means we don't know how * to get the chip back to Read mode. Might * as well try an Intel-style reset... */ flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); return 0; } /* Do manufacturer-specific fixups */ switch (info->manufacturer_id) { case 0x0001: /* AMD */ case 0x0037: /* AMIC */ flash_fixup_amd(info, &qry); break; case 0x001f: flash_fixup_atmel(info, &qry); break; case 0x0020: flash_fixup_stm(info, &qry); break; case 0x00bf: /* SST */ flash_fixup_sst(info, &qry); break; case 0x0089: /* Numonyx */ flash_fixup_num(info, &qry); break; } debug ("manufacturer is %d\n", info->vendor); debug ("manufacturer id is 0x%x\n", info->manufacturer_id); debug ("device id is 0x%x\n", info->device_id); debug ("device id2 is 0x%x\n", info->device_id2); debug ("cfi version is 0x%04x\n", info->cfi_version); size_ratio = info->portwidth / info->chipwidth; /* if the chip is x8/x16 reduce the ratio by half */ if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) { size_ratio >>= 1; } debug ("size_ratio %d port %d bits chip %d bits\n", size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); info->size = 1 << qry.dev_size; /* multiply the size by the number of chips */ info->size *= size_ratio; max_size = cfi_flash_bank_size(banknum); if (max_size && (info->size > max_size)) { debug("[truncated from %ldMiB]", info->size >> 20); info->size = max_size; } debug ("found %d erase regions\n", num_erase_regions); sect_cnt = 0; sector = base; for (i = 0; i < num_erase_regions; i++) { if (i > NUM_ERASE_REGIONS) { printf ("%d erase regions found, only %d used\n", num_erase_regions, NUM_ERASE_REGIONS); break; } tmp = le32_to_cpu(get_unaligned( &(qry.erase_region_info[i]))); debug("erase region %u: 0x%08lx\n", i, tmp); erase_region_count = (tmp & 0xffff) + 1; tmp >>= 16; erase_region_size = (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; debug ("erase_region_count = %d erase_region_size = %d\n", erase_region_count, erase_region_size); for (j = 0; j < erase_region_count; j++) { if (sector - base >= info->size) break; if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) { printf("ERROR: too many flash sectors\n"); break; } info->start[sect_cnt] = (ulong)map_physmem(sector, info->portwidth, MAP_NOCACHE); sector += (erase_region_size * size_ratio); /* * Only read protection status from * supported devices (intel...) */ switch (info->vendor) { case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_EXTENDED: case CFI_CMDSET_INTEL_STANDARD: /* * Set flash to read-id mode. Otherwise * reading protected status is not * guaranteed. */ flash_write_cmd(info, sect_cnt, 0, FLASH_CMD_READ_ID); info->protect[sect_cnt] = flash_isset (info, sect_cnt, FLASH_OFFSET_PROTECT, FLASH_STATUS_PROTECT); flash_write_cmd(info, sect_cnt, 0, FLASH_CMD_RESET); break; case CFI_CMDSET_AMD_EXTENDED: case CFI_CMDSET_AMD_STANDARD: if (!info->legacy_unlock) { /* default: not protected */ info->protect[sect_cnt] = 0; break; } /* Read protection (PPB) from sector */ flash_write_cmd(info, 0, 0, info->cmd_reset); flash_unlock_seq(info, 0); flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); info->protect[sect_cnt] = flash_isset( info, sect_cnt, FLASH_OFFSET_PROTECT, FLASH_STATUS_PROTECT); break; default: /* default: not protected */ info->protect[sect_cnt] = 0; } sect_cnt++; } } info->sector_count = sect_cnt; info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size); tmp = 1 << qry.block_erase_timeout_typ; info->erase_blk_tout = tmp * (1 << qry.block_erase_timeout_max); tmp = (1 << qry.buf_write_timeout_typ) * (1 << qry.buf_write_timeout_max); /* round up when converting to ms */ info->buffer_write_tout = (tmp + 999) / 1000; tmp = (1 << qry.word_write_timeout_typ) * (1 << qry.word_write_timeout_max); /* round up when converting to ms */ info->write_tout = (tmp + 999) / 1000; info->flash_id = FLASH_MAN_CFI; if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) { /* XXX - Need to test on x8/x16 in parallel. */ info->portwidth >>= 1; } flash_write_cmd (info, 0, 0, info->cmd_reset); } return (info->size); }
二、 编译下载运行
2.1 编译
make distclean make smdk2440_config make ARCH=arm CROSS_COMPILE=arm-linux- V=1
2.2 下载到NOR FALSH
我们再次下载运行,其中NOR FLASH输出如下:
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 unlock address index 1 unlock addresses are 0x555/0x2aa erase_region_count = 31 erase_region_size = 65536 erase_region_count = 1 erase_region_size = 32768 erase_region_count = 2 erase_region_size = 8192 erase_region_count = 1 erase_region_size = 16384 flash_protect ON: from 0x00000000 to 0x0008931B protect on 0 protect on 1 protect on 2 protect on 3 protect on 4 protect on 5 protect on 6 protect on 7 protect on 8 flash_protect ON: from 0x00070000 to 0x0007FFFF protect on 7 2 MiB
在控制台输入flinfo命令(flash info),就能查看flash的信息了:
SMDK2440 # flinfo Bank # 1: AMD AM29LV160DB flash (16 x 16) Size: 2 MB in 35 Sectors AMD Legacy command set, Manufacturer ID: 0x01, Device ID: 0x2249 Erase timeout: 30000 ms, write timeout: 100 ms Sector Start Addresses: 00000000 RO 00010000 RO 00020000 RO 00030000 RO 00040000 RO 00050000 RO 00060000 RO 00070000 RO 00080000 RO 00090000 000A0000 000B0000 000C0000 000D0000 000E0000 000F0000 00100000 00110000 00120000 00130000 00140000 00150000 00160000 00170000 00180000 00190000 001A0000 001B0000 001C0000 001D0000 001E0000 001F0000 001F8000 001FA000 001FC000
然后通过u-boot命令,检测NOR FLASH的读写是否正确,首先去除写保护:
SMDK2440 # protect off all Un-Protect Flash Bank # 1
查看Flash内容,这里我们查看NOR FLASH起始地址的数据:
SMDK2440 # md.b 0000 00000000: be 00 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 ................ 00000010: 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 ................ 00000020: 60 00 00 00 c0 00 00 00 20 01 00 00 80 01 00 00 `....... ....... 00000030: e0 01 00 00 40 02 00 00 a0 02 00 00 ef be ad de ....@...........
由于我们将u-boot下载到了NOR FLASH中,因此我们直接查看u-boot.dis文件,做一个对比即可:
可以看到数据是一样的,低地址数据在低位,高地址数据在高位,采用的小端存储模式。
参考文章