📄 cfi_flash.c
字号:
{ int rcode = 0; int prot; flash_sect_t sect; if (info->flash_id != FLASH_MAN_CFI) { puts ("Can't erase unknown flash type - aborted\n"); return 1; } if ((s_first < 0) || (s_first > s_last)) { puts ("- no sectors to erase\n"); return 1; } prot = 0; for (sect = s_first; sect <= s_last; ++sect) { if (info->protect[sect]) { prot++; } } if (prot) { printf ("- Warning: %d protected sectors will not be erased!\n", prot); } else { putc ('\n'); } for (sect = s_first; sect <= s_last; sect++) { if (info->protect[sect] == 0) { /* not protected */ switch (info->vendor) { case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS); flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE); flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM); break; 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); break;#ifdef CONFIG_FLASH_CFI_LEGACY case CFI_CMDSET_AMD_LEGACY: flash_unlock_seq (info, 0); flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_ERASE_START); flash_unlock_seq (info, 0); flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR); break;#endif default: debug ("Unkown flash vendor %d\n", info->vendor); break; } if (flash_full_status_check (info, sect, info->erase_blk_tout, "erase")) { rcode = 1; } else putc ('.'); } } puts (" done\n"); return rcode;}/*----------------------------------------------------------------------- */void flash_print_info (flash_info_t * info){ int i; if (info->flash_id != FLASH_MAN_CFI) { puts ("missing or unknown FLASH type\n"); return; } printf ("%s FLASH (%d x %d)", info->name, (info->portwidth << 3), (info->chipwidth << 3)); if (info->size < 1024*1024) printf (" Size: %ld kB in %d Sectors\n", info->size >> 10, info->sector_count); else printf (" Size: %ld MB in %d Sectors\n", info->size >> 20, info->sector_count); printf (" "); switch (info->vendor) { case CFI_CMDSET_INTEL_PROG_REGIONS: printf ("Intel Prog Regions"); break; case CFI_CMDSET_INTEL_STANDARD: printf ("Intel Standard"); break; case CFI_CMDSET_INTEL_EXTENDED: printf ("Intel Extended"); break; case CFI_CMDSET_AMD_STANDARD: printf ("AMD Standard"); break; case CFI_CMDSET_AMD_EXTENDED: printf ("AMD Extended"); break;#ifdef CONFIG_FLASH_CFI_LEGACY case CFI_CMDSET_AMD_LEGACY: printf ("AMD Legacy"); break;#endif default: printf ("Unknown (%d)", info->vendor); break; } printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X", info->manufacturer_id, info->device_id); if (info->device_id == 0x7E) { printf("%04X", info->device_id2); } printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", info->erase_blk_tout, info->write_tout); if (info->buffer_size > 1) { printf (" Buffer write timeout: %ld ms, " "buffer size: %d bytes\n", info->buffer_write_tout, info->buffer_size); } puts ("\n Sector Start Addresses:"); for (i = 0; i < info->sector_count; ++i) { if ((i % 5) == 0) printf ("\n");#ifdef CFG_FLASH_EMPTY_INFO int k; int size; int erased; volatile unsigned long *flash; /* * Check if whole sector is erased */ size = flash_sector_size(info, i); erased = 1; flash = (volatile unsigned long *) info->start[i]; size = size >> 2; /* divide by 4 for longword access */ for (k = 0; k < size; k++) { if (*flash++ != 0xffffffff) { erased = 0; break; } } /* print empty and read-only info */ printf (" %08lX %c %s ", info->start[i], erased ? 'E' : ' ', info->protect[i] ? "RO" : " ");#else /* ! CFG_FLASH_EMPTY_INFO */ printf (" %08lX %s ", info->start[i], info->protect[i] ? "RO" : " ");#endif } putc ('\n'); return;}/*----------------------------------------------------------------------- * This is used in a few places in write_buf() to show programming * progress. Making it a function is nasty because it needs to do side * effect updates to digit and dots. Repeated code is nasty too, so * we define it once here. */#ifdef CONFIG_FLASH_SHOW_PROGRESS#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub) \ dots -= dots_sub; \ if ((scale > 0) && (dots <= 0)) { \ if ((digit % 5) == 0) \ printf ("%d", digit / 5); \ else \ putc ('.'); \ digit--; \ dots += scale; \ }#else#define FLASH_SHOW_PROGRESS(scale, dots, digit, dots_sub)#endif/*----------------------------------------------------------------------- * Copy memory to flash, returns: * 0 - OK * 1 - write timeout * 2 - Flash not erased */int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt){ ulong wp; uchar *p; int aln; cfiword_t cword; int i, rc;#ifdef CFG_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 /* get lower aligned address */ wp = (addr & ~(info->portwidth - 1)); /* handle unaligned start */ if ((aln = addr - wp) != 0) { cword.l = 0; p = map_physmem(wp, info->portwidth, MAP_NOCACHE); for (i = 0; i < aln; ++i) flash_add_byte (info, &cword, flash_read8(p + i)); for (; (i < info->portwidth) && (cnt > 0); i++) { flash_add_byte (info, &cword, *src++); cnt--; } for (; (cnt == 0) && (i < info->portwidth); ++i) flash_add_byte (info, &cword, flash_read8(p + i)); rc = flash_write_cfiword (info, wp, cword); unmap_physmem(p, info->portwidth); if (rc != 0) return rc; wp += i; FLASH_SHOW_PROGRESS(scale, dots, digit, i); } /* handle the aligned part */#ifdef CFG_FLASH_USE_BUFFER_WRITE buffered_size = (info->portwidth / info->chipwidth); buffered_size *= info->buffer_size; while (cnt >= info->portwidth) { /* prohibit buffer write when buffer_size is 1 */ if (info->buffer_size == 1) { cword.l = 0; for (i = 0; i < info->portwidth; i++) flash_add_byte (info, &cword, *src++); if ((rc = flash_write_cfiword (info, wp, cword)) != 0) return rc; wp += info->portwidth; cnt -= info->portwidth; continue; } /* write buffer until next buffered_size aligned boundary */ i = buffered_size - (wp % buffered_size); if (i > cnt) i = cnt; if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) return rc; i -= i & (info->portwidth - 1); wp += i; src += i; cnt -= i; FLASH_SHOW_PROGRESS(scale, dots, digit, i); }#else while (cnt >= info->portwidth) { cword.l = 0; for (i = 0; i < info->portwidth; i++) { flash_add_byte (info, &cword, *src++); } if ((rc = flash_write_cfiword (info, wp, cword)) != 0) return rc; wp += info->portwidth; cnt -= info->portwidth; FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth); }#endif /* CFG_FLASH_USE_BUFFER_WRITE */ if (cnt == 0) { return (0); } /* * handle unaligned tail bytes */ cword.l = 0; p = map_physmem(wp, info->portwidth, MAP_NOCACHE); for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) { flash_add_byte (info, &cword, *src++); --cnt; } for (; i < info->portwidth; ++i) flash_add_byte (info, &cword, flash_read8(p + i)); unmap_physmem(p, info->portwidth); return flash_write_cfiword (info, wp, cword);}/*----------------------------------------------------------------------- */#ifdef CFG_FLASH_PROTECTIONint flash_real_protect (flash_info_t * info, long sector, int prot){ int retcode = 0; switch (info->vendor) { case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); if (prot) flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); else flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR); break; case CFI_CMDSET_AMD_EXTENDED: case CFI_CMDSET_AMD_STANDARD: /* U-Boot only checks the first byte */ if (info->manufacturer_id == (uchar)ATM_MANUFACT) { if (prot) { flash_unlock_seq (info, 0); flash_write_cmd (info, 0, info->addr_unlock1, ATM_CMD_SOFTLOCK_START); flash_unlock_seq (info, 0); flash_write_cmd (info, sector, 0, ATM_CMD_LOCK_SECT); } else { flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_UNLOCK_START); if (info->device_id == ATM_ID_BV6416) flash_write_cmd (info, sector, 0, ATM_CMD_UNLOCK_SECT); } } break;#ifdef CONFIG_FLASH_CFI_LEGACY case CFI_CMDSET_AMD_LEGACY: flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT); if (prot) flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET); else flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);#endif }; if ((retcode = flash_full_status_check (info, sector, info->erase_blk_tout, prot ? "protect" : "unprotect")) == 0) { info->protect[sector] = prot; /* * On some of Intel's flash chips (marked via legacy_unlock) * unprotect unprotects all locking. */ if ((prot == 0) && (info->legacy_unlock)) { flash_sect_t i; for (i = 0; i < info->sector_count; i++) { if (info->protect[i]) flash_real_protect (info, i, 1); } } } return retcode;}/*----------------------------------------------------------------------- * flash_read_user_serial - read the OneTimeProgramming cells */void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, int len){ uchar *src; uchar *dst; dst = buffer; src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION); flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); memcpy (dst, src + offset, len); flash_write_cmd (info, 0, 0, info->cmd_reset); flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);}/* * flash_read_factory_serial - read the device Id from the protection area */void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, int len){ uchar *src; src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION); flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID); memcpy (buffer, src + offset, len); flash_write_cmd (info, 0, 0, info->cmd_reset); flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);}#endif /* CFG_FLASH_PROTECTION *//*----------------------------------------------------------------------- * Reverse the order of the erase regions in the CFI QRY structure. * This is needed for chips that are either a) correctly detected as * top-boot, or b) buggy. */static void cfi_reverse_geometry(struct cfi_qry *qry){ unsigned int i, j; u32 tmp; for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) { tmp = qry->erase_region_info[i]; qry->erase_region_info[i] = qry->erase_region_info[j]; qry->erase_region_info[j] = tmp; }}/*----------------------------------------------------------------------- * read jedec ids from device and set corresponding fields in info struct * * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct * */static void cmdset_intel_read_jedec_ids(flash_info_t *info){ flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); udelay(1000); /* some flash are slow to respond */ info->manufacturer_id = flash_read_uchar (info, FLASH_OFFSET_MANUFACTURER_ID); info->device_id = flash_read_uchar (info, FLASH_OFFSET_DEVICE_ID); flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);}static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry){ info->cmd_reset = FLASH_CMD_RESET; cmdset_intel_read_jedec_ids(info); flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);#ifdef CFG_FLASH_PROTECTION /* read legacy lock/unlock bit from intel flash */ if (info->ext_addr) { info->legacy_unlock = flash_read_uchar (info, info->ext_addr + 5) & 0x08; }#endif return 0;}static void cmdset_amd_read_jedec_ids(flash_info_t *info){ flash_write_cmd(info, 0, 0, AMD_CMD_RESET); flash_unlock_seq(info, 0); flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); udelay(1000); /* some flash are slow to respond */ info->manufacturer_id = flash_read_uchar (info, FLASH_OFFSET_MANUFACTURER_ID); switch (info->chipwidth){ case FLASH_CFI_8BIT: info->device_id = flash_read_uchar (info, FLASH_OFFSET_DEVICE_ID); if (info->device_id == 0x7E) { /* AMD 3-byte (expanded) device ids */ info->device_id2 = flash_read_uchar (info, FLASH_OFFSET_DEVICE_ID2); info->device_id2 <<= 8; info->device_id2 |= flash_read_uchar (info, FLASH_OFFSET_DEVICE_ID3); } break; case FLASH_CFI_16BIT: info->device_id = flash_read_word (info, FLASH_OFFSET_DEVICE_ID); break; default: break; } flash_write_cmd(info, 0, 0, AMD_CMD_RESET);}static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -