summaryrefslogtreecommitdiff
path: root/drivers/mtd/cfi_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/cfi_flash.c')
-rw-r--r--drivers/mtd/cfi_flash.c154
1 files changed, 132 insertions, 22 deletions
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 35294bc8c..43140f364 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -1077,7 +1077,38 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
for (sect = s_first; sect <= s_last; sect++) {
+ if (ctrlc()) {
+ printf("\n");
+ return 1;
+ }
+
if (info->protect[sect] == 0) { /* not protected */
+#ifdef CONFIG_SYS_FLASH_CHECK_BLANK_BEFORE_ERASE
+ int k;
+ int size;
+ int erased;
+ u32 *flash;
+
+ /*
+ * Check if whole sector is erased
+ */
+ size = flash_sector_size(info, sect);
+ erased = 1;
+ flash = (u32 *)info->start[sect];
+ /* divide by 4 for longword access */
+ size = size >> 2;
+ for (k = 0; k < size; k++) {
+ if (flash_read32(flash++) != 0xffffffff) {
+ erased = 0;
+ break;
+ }
+ }
+ if (erased) {
+ if (flash_verbose)
+ putc(',');
+ continue;
+ }
+#endif
switch (info->vendor) {
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
@@ -1353,6 +1384,9 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
src += i;
cnt -= i;
FLASH_SHOW_PROGRESS(scale, dots, digit, i);
+ /* Only check every once in a while */
+ if ((cnt & 0xFFFF) < buffered_size && ctrlc())
+ return ERR_ABORTED;
}
#else
while (cnt >= info->portwidth) {
@@ -1365,6 +1399,9 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
wp += info->portwidth;
cnt -= info->portwidth;
FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth);
+ /* Only check every once in a while */
+ if ((cnt & 0xFFFF) < info->portwidth && ctrlc())
+ return ERR_ABORTED;
}
#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
@@ -1391,6 +1428,40 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
*/
#ifdef CONFIG_SYS_FLASH_PROTECTION
+static int cfi_protect_bugfix(flash_info_t *info, long sector, int prot)
+{
+ if ((info->manufacturer_id == (uchar)INTEL_MANUFACT) &&
+ (info->device_id == NUMONYX_256MBIT)) {
+ /*
+ * see errata called
+ * "Numonyx Axcell P33/P30 Specification Update" :)
+ */
+ flash_write_cmd(info, sector, 0, FLASH_CMD_READ_ID);
+ if (!flash_isequal(info, sector, FLASH_OFFSET_PROTECT,
+ prot)) {
+ /*
+ * cmd must come before FLASH_CMD_PROTECT + 20us
+ * Disable interrupts which might cause a timeout here.
+ */
+ int flag = disable_interrupts();
+ unsigned short cmd;
+
+ if (prot)
+ cmd = FLASH_CMD_PROTECT_SET;
+ else
+ cmd = FLASH_CMD_PROTECT_CLEAR;
+ flash_write_cmd(info, sector, 0,
+ FLASH_CMD_PROTECT);
+ flash_write_cmd(info, sector, 0, cmd);
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+ }
+ return 1;
+ }
+ return 0;
+}
+
int flash_real_protect (flash_info_t * info, long sector, int prot)
{
int retcode = 0;
@@ -1399,31 +1470,18 @@ int flash_real_protect (flash_info_t * info, long sector, int prot)
case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
- /*
- * see errata called
- * "Numonyx Axcell P33/P30 Specification Update" :)
- */
- flash_write_cmd (info, sector, 0, FLASH_CMD_READ_ID);
- if (!flash_isequal (info, sector, FLASH_OFFSET_PROTECT,
- prot)) {
- /*
- * cmd must come before FLASH_CMD_PROTECT + 20us
- * Disable interrupts which might cause a timeout here.
- */
- int flag = disable_interrupts ();
- unsigned short cmd;
-
+ if (!cfi_protect_bugfix(info, sector, prot)) {
+ flash_write_cmd(info, sector, 0,
+ FLASH_CMD_CLEAR_STATUS);
+ flash_write_cmd(info, sector, 0,
+ FLASH_CMD_PROTECT);
if (prot)
- cmd = FLASH_CMD_PROTECT_SET;
+ flash_write_cmd(info, sector, 0,
+ FLASH_CMD_PROTECT_SET);
else
- cmd = FLASH_CMD_PROTECT_CLEAR;
+ flash_write_cmd(info, sector, 0,
+ FLASH_CMD_PROTECT_CLEAR);
- flash_write_cmd (info, sector, 0,
- FLASH_CMD_PROTECT);
- flash_write_cmd (info, sector, 0, cmd);
- /* re-enable interrupts if necessary */
- if (flag)
- enable_interrupts ();
}
break;
case CFI_CMDSET_AMD_EXTENDED:
@@ -1447,6 +1505,47 @@ int flash_real_protect (flash_info_t * info, long sector, int prot)
0, ATM_CMD_UNLOCK_SECT);
}
}
+ if (info->manufacturer_id == (uchar)AMD_MANUFACT) {
+ int flag = disable_interrupts();
+ int lock_flag;
+
+ flash_unlock_seq(info, 0);
+ flash_write_cmd(info, 0, info->addr_unlock1,
+ AMD_CMD_SET_PPB_ENTRY);
+ lock_flag = flash_isset(info, sector, 0, 0x01);
+ if (prot) {
+ if (lock_flag) {
+ flash_write_cmd(info, sector, 0,
+ AMD_CMD_PPB_LOCK_BC1);
+ flash_write_cmd(info, sector, 0,
+ AMD_CMD_PPB_LOCK_BC2);
+ }
+ debug("sector %ld %slocked\n", sector,
+ lock_flag ? "" : "already ");
+ } else {
+ if (!lock_flag) {
+ debug("unlock %ld\n", sector);
+ flash_write_cmd(info, 0, 0,
+ AMD_CMD_PPB_UNLOCK_BC1);
+ flash_write_cmd(info, 0, 0,
+ AMD_CMD_PPB_UNLOCK_BC2);
+ }
+ debug("sector %ld %sunlocked\n", sector,
+ !lock_flag ? "" : "already ");
+ }
+ if (flag)
+ enable_interrupts();
+
+ if (flash_status_check(info, sector,
+ info->erase_blk_tout,
+ prot ? "protect" : "unprotect"))
+ printf("status check error\n");
+
+ flash_write_cmd(info, 0, 0,
+ AMD_CMD_SET_PPB_EXIT_BC1);
+ flash_write_cmd(info, 0, 0,
+ AMD_CMD_SET_PPB_EXIT_BC2);
+ }
break;
#ifdef CONFIG_FLASH_CFI_LEGACY
case CFI_CMDSET_AMD_LEGACY:
@@ -1635,6 +1734,17 @@ static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
cmdset_amd_read_jedec_ids(info);
flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
+#ifdef CONFIG_SYS_FLASH_PROTECTION
+ if (info->ext_addr && info->manufacturer_id == (uchar)AMD_MANUFACT) {
+ ushort spus;
+
+ /* read sector protect/unprotect scheme */
+ spus = flash_read_uchar(info, info->ext_addr + 9);
+ if (spus == 0x8)
+ info->legacy_unlock = 1;
+ }
+#endif
+
return 0;
}