📄 cfi_flash.c
字号:
} 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 ("CFI conformant FLASH (%d x %d)", (info->portwidth << 3), (info->chipwidth << 3)); printf (" Size: %ld MB in %d Sectors\n", info->size >> 20, info->sector_count); printf (" Erase timeout %ld ms, write timeout %ld ms, buffer write timeout %ld ms, buffer size %d\n", info->erase_blk_tout, info->write_tout, info->buffer_write_tout, info->buffer_size); puts (" Sector Start Addresses:"); for (i = 0; i < info->sector_count; ++i) {#ifdef CFG_FLASH_EMPTY_INFO int k; int size; int erased; volatile unsigned long *flash; /* * Check if whole sector is erased */ if (i != (info->sector_count - 1)) size = info->start[i + 1] - info->start[i]; else size = info->start[0] + info->size - info->start[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; } } if ((i % 5) == 0) printf ("\n"); /* print empty and read-only info */ printf (" %08lX%s%s", info->start[i], erased ? " E" : " ", info->protect[i] ? "RO " : " ");#else if ((i % 5) == 0) printf ("\n "); printf (" %08lX%s", info->start[i], info->protect[i] ? " (RO) " : " ");#endif } putc ('\n'); return;}/*----------------------------------------------------------------------- * 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; ulong cp; int aln; cfiword_t cword; int i, rc;#ifdef CFG_FLASH_USE_BUFFER_WRITE int buffered_size;#endif /* get lower aligned address */ /* get lower aligned address */ wp = (addr & ~(info->portwidth - 1)); /* handle unaligned start */ if ((aln = addr - wp) != 0) { cword.l = 0; cp = wp; for (i = 0; i < aln; ++i, ++cp) flash_add_byte (info, &cword, (*(uchar *) cp)); for (; (i < info->portwidth) && (cnt > 0); i++) { flash_add_byte (info, &cword, *src++); cnt--; cp++; } for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp) flash_add_byte (info, &cword, (*(uchar *) cp)); if ((rc = flash_write_cfiword (info, wp, cword)) != 0) return rc; wp = cp; } /* 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) { i = buffered_size > cnt ? cnt : buffered_size; if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) return rc; i -= (i % info->portwidth); wp += i; src += i; cnt -= 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; }#endif /* CFG_FLASH_USE_BUFFER_WRITE */ if (cnt == 0) { return (0); } /* * handle unaligned tail bytes */ cword.l = 0; for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) { flash_add_byte (info, &cword, *src++); --cnt; } for (; i < info->portwidth; ++i, ++cp) { flash_add_byte (info, &cword, (*(uchar *) cp)); } 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; 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); if ((retcode = flash_full_status_check (info, sector, info->erase_blk_tout, prot ? "protect" : "unprotect")) == 0) { info->protect[sector] = prot; /* Intel's unprotect unprotects all locking */ if (prot == 0) { 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_make_addr (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, FLASH_CMD_RESET);}/* * 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_make_addr (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, FLASH_CMD_RESET);}#endif /* CFG_FLASH_PROTECTION *//* * flash_is_busy - check to see if the flash is busy * This routine checks the status of the chip and returns true if the chip is busy */static int flash_is_busy (flash_info_t * info, flash_sect_t sect){ int retval; switch (info->vendor) { case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); break; case CFI_CMDSET_AMD_STANDARD: case CFI_CMDSET_AMD_EXTENDED: retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); break; default: retval = 0; } debug ("flash_is_busy: %d\n", retval); return retval;}/*----------------------------------------------------------------------- * wait for XSR.7 to be set. Time out with an error if it does not. * This routine does not set the flash to read-array mode. */static int flash_status_check (flash_info_t * info, flash_sect_t sector, ulong tout, char *prompt){ ulong start; /* Wait for command completion */ start = get_timer (0); while (flash_is_busy (info, sector)) { if (get_timer (start) > info->erase_blk_tout * CFG_HZ) { printf ("Flash %s timeout at address %lx data %lx\n", prompt, info->start[sector], flash_read_long (info, sector, 0)); flash_write_cmd (info, sector, 0, info->cmd_reset); return ERR_TIMOUT; } } return ERR_OK;}/*----------------------------------------------------------------------- * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check. * This routine sets the flash to read-array mode. */static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, ulong tout, char *prompt){ int retcode; retcode = flash_status_check (info, sector, tout, prompt); switch (info->vendor) { case CFI_CMDSET_INTEL_EXTENDED: case CFI_CMDSET_INTEL_STANDARD: if ((retcode != ERR_OK) && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { retcode = ERR_INVAL; printf ("Flash %s error at address %lx\n", prompt, info->start[sector]); if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) { puts ("Command Sequence Error.\n"); } else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) { puts ("Block Erase Error.\n"); retcode = ERR_NOT_ERASED; } else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) { puts ("Locking Error\n"); } if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { puts ("Block locked.\n"); retcode = ERR_PROTECTED; } if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) puts ("Vpp Low Error.\n"); } flash_write_cmd (info, sector, 0, FLASH_CMD_RESET); break; default: break; } return retcode;}/*----------------------------------------------------------------------- */static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c){#if defined(__LITTLE_ENDIAN) unsigned short w; unsigned int l; unsigned long long ll;#endif switch (info->portwidth) { case FLASH_CFI_8BIT: cword->c = c; break; case FLASH_CFI_16BIT:#if defined(__LITTLE_ENDIAN) w = c; w <<= 8; cword->w = (cword->w >> 8) | w;#else cword->w = (cword->w << 8) | c;#endif break; case FLASH_CFI_32BIT:#if defined(__LITTLE_ENDIAN) l = c; l <<= 24; cword->l = (cword->l >> 8) | l;#else cword->l = (cword->l << 8) | c;#endif break; case FLASH_CFI_64BIT:#if defined(__LITTLE_ENDIAN) ll = c; ll <<= 56; cword->ll = (cword->ll >> 8) | ll;#else cword->ll = (cword->ll << 8) | c;#endif break; }}/*----------------------------------------------------------------------- * make a proper sized command based on the port and chip widths */static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf){ int i;#if defined(__LITTLE_ENDIAN) ushort stmpw; uint stmpi;#endif uchar *cp = (uchar *) cmdbuf; for (i = 0; i < info->portwidth; i++) *cp++ = ((i + 1) % info->chipwidth) ? '\0' : cmd;#if defined(__LITTLE_ENDIAN) switch (info->portwidth) { case FLASH_CFI_8BIT: break; case FLASH_CFI_16BIT: stmpw = *(ushort *) cmdbuf; *(ushort *) cmdbuf = __swab16 (stmpw); break; case FLASH_CFI_32BIT: stmpi = *(uint *) cmdbuf; *(uint *) cmdbuf = __swab32 (stmpi); break; default: puts ("WARNING: flash_make_cmd: unsuppported LittleEndian mode\n"); break; }#endif}/* * Write a proper sized command to the correct address */static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd){ volatile cfiptr_t addr; cfiword_t cword; addr.cp = flash_make_addr (info, sect, offset); flash_make_cmd (info, cmd, &cword); switch (info->portwidth) { case FLASH_CFI_8BIT: debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr.cp, cmd, cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); *addr.cp = cword.c; break; case FLASH_CFI_16BIT: debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr.wp, cmd, cword.w, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); *addr.wp = cword.w; break; case FLASH_CFI_32BIT: debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr.lp, cmd, cword.l, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); *addr.lp = cword.l; break; case FLASH_CFI_64BIT:#ifdef DEBUG {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -