In the previous section, I wonder if you noticed that after starting u-boot, there is a line of information running:
The code for outputting Flash information is located on the board_init_r phase, execute Initr_ The output of the Flash() function.
Our development board is equipped with a 2MB(1M*16bit) NOR FLASH with the model S29AL016D70TF102. The output nor false size is 0 bytes. Obviously, 2M NOR FLASH can not be correctly recognized.
In this section, we will introduce how u-boot supports our NOR FLASH, so that we can read and write nor false through the command line.
1, NOR FLASH support
1.1 analyze startup information
When NOR starts, we print debugging information:
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
Print out the manufacturer ID of NOR FLASH = 0x01 (produced by AMD) and device ID=0x2249. We check the datasheet of S29AL016D70TF102 chip and find that the two IDs are correct, but they are not detected. It indicates that the underlying driver of the program is correct, but the board does not support this nor:
We located 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 function in drivers \ MTD \ CFI_ Defined in 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), // Nothing. It's empty 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); }
Where CONFIG_SYS_MAX_FLASH_BANKS is defined as 1, FLASH_UNKNOWN is defined as 0xFFFF:
#define CONFIG_SYS_MAX_FLASH_BANKS 1 #define FLASH_UNKNOWN 0xFFFF /* unknown flash type */
flash_info is defined as follows:
#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;
Here we focus on flash_detect_legacy and flash_get_size function.
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 */ }
Enter jedec_flash_match function at 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; }
Enter jedec_table array view:
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 };
After query, it is found that there is no NOR FLASH model S29AL016D70TF102 we use.
Enter the macro definition code of the machine ID and find this:
#define AMD_MANUFACT 0x00010001 /* AMD manuf. ID in D23..D16, D7..D0 */
01 is the NOR FLASH manufacturer ID we use, which indicates that u-boot can be supported, but it is not written in the array. Change the array and add our own NOR FLASH to support it.
1.3 modification jedec_table array (drivers/mtd/jedec_flash.c)
Because there is a macro definition in the array, I don't intend to destroy its structure. I just copied one and pasted it to the last end of the array.
{ .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), } },
- Manufacturer ID: mfr_id changed to AMD_MANUFACT;
- Device ID: dev_ The ID is modified to 0x2249, i.e. AM29LV160DB;
- Name: name is modified to AMD AM29LV160DB;
- uaddr: the unlocking address is changed to [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ /*NOR flash unlock address * /. [0] indicates that NOR is 8 bits. I use 16 bits, so it is changed to 1. NORFlash will be locked when it is used, so it must be unlocked when writing, and it can only be unlocked when writing values in some addresses. The unlocking address can be found in the manual.
- Size: modify DevSize to SIZE_2MiB;
- NumEraseRegions: erasure blocks are different due to different structures of NOR. You can refer to the manual and write as many blocks as there are.
- regions: describe the distribution of erasure blocks. From top to bottom, the addresses in NOR are arranged from low to high;
I use four types of NOR: one 8K word, one 4K byte, one 16K word and 31 32K words. The 1K word size is 2048 bytes.
Therefore, regions are configured as follows:
.regions = { ERASEINFO(64*1024, 31), ERASEINFO(32*1024, 1), ERASEINFO(8*1024, 2), ERASEINFO(16*1024, 1), }
Modify the include / config / smdk2440. H file, and use config here_ SYS_ MAX_ FLASH_ SEC defines the maximum number of NOR FLASH sectors, which we modify to 128. In fact, this value can be any number, as long as it is greater than the erase block used.
#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, Compile download run
2.1 compilation
make distclean
make smdk2440_config
make ARCH=arm CROSS_COMPILE=arm-linux- V=1
2.2 download to nor false
We download and run again, and the output of NOR FLASH is as follows:
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
Enter the flinfo command (flash info) on the console to view the flash information:
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
Then, use the u-boot command to check whether the reading and writing of NOR FLASH is correct. First, remove the write protection:
SMDK2440 # protect off all Un-Protect Flash Bank # 1
View the Flash content. Here we view the data of NOR FLASH start address:
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 ....@...........
Since we downloaded the u-boot to NOR FLASH, we can directly view the u-boot.dis file and make a comparison:
It can be seen that the data is the same. The low address data is in the low position and the high address data is in the high position. The small end storage mode is adopted.
Reference articles
[1]S3C2440 supports NORFLASH for porting uboot
[3]Step 5 of porting uboot: support NORFlash
[5]mini2440 Hardware: Nor Flash