diff options
Diffstat (limited to 'src/flash')
-rw-r--r-- | src/flash/cfi.c | 500 | ||||
-rw-r--r-- | src/flash/cfi.h | 16 |
2 files changed, 258 insertions, 258 deletions
diff --git a/src/flash/cfi.c b/src/flash/cfi.c index 4f2375de..b952bb7f 100644 --- a/src/flash/cfi.c +++ b/src/flash/cfi.c @@ -142,7 +142,7 @@ inline u32 flash_address(flash_bank_t *bank, int sector, u32 offset) void cfi_command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf) { int i; - + /* clear whole buffer, to ensure bits that exceed the bus_width * are set to zero */ @@ -173,9 +173,9 @@ u8 cfi_query_u8(flash_bank_t *bank, int sector, u32 offset) { target_t *target = bank->target; u8 data[CFI_MAX_BUS_WIDTH]; - + target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data); - + if (bank->target->endianness == TARGET_LITTLE_ENDIAN) return data[0]; else @@ -191,14 +191,14 @@ u8 cfi_get_u8(flash_bank_t *bank, int sector, u32 offset) target_t *target = bank->target; u8 data[CFI_MAX_BUS_WIDTH]; int i; - + target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data); - + if (bank->target->endianness == TARGET_LITTLE_ENDIAN) { for (i = 0; i < bank->bus_width / bank->chip_width; i++) data[0] |= data[i]; - + return data[0]; } else @@ -206,7 +206,7 @@ u8 cfi_get_u8(flash_bank_t *bank, int sector, u32 offset) u8 value = 0; for (i = 0; i < bank->bus_width / bank->chip_width; i++) value |= data[bank->bus_width - 1 - i]; - + return value; } } @@ -215,7 +215,7 @@ u16 cfi_query_u16(flash_bank_t *bank, int sector, u32 offset) { target_t *target = bank->target; u8 data[CFI_MAX_BUS_WIDTH * 2]; - + target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data); if (bank->target->endianness == TARGET_LITTLE_ENDIAN) @@ -228,13 +228,13 @@ u32 cfi_query_u32(flash_bank_t *bank, int sector, u32 offset) { target_t *target = bank->target; u8 data[CFI_MAX_BUS_WIDTH * 4]; - + target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data); - + if (bank->target->endianness == TARGET_LITTLE_ENDIAN) return data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24; else - return data[bank->bus_width - 1] | data[(2* bank->bus_width) - 1] << 8 | + return data[bank->bus_width - 1] | data[(2* bank->bus_width) - 1] << 8 | data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24; } @@ -242,13 +242,13 @@ void cfi_intel_clear_status_register(flash_bank_t *bank) { target_t *target = bank->target; u8 command[8]; - + if (target->state != TARGET_HALTED) { ERROR("BUG: attempted to clear status register while target wasn't halted"); exit(-1); } - + cfi_command(bank, 0x50, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); } @@ -256,7 +256,7 @@ void cfi_intel_clear_status_register(flash_bank_t *bank) u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout) { u8 status; - + while ((!((status = cfi_get_u8(bank, 0, 0x0)) & 0x80)) && (timeout-- > 0)) { DEBUG("status: 0x%x", status); @@ -267,7 +267,7 @@ u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout) status = status & 0xfe; DEBUG("status: 0x%x", status); - + if ((status & 0x80) != 0x80) { ERROR("timeout while waiting for WSM to become ready"); @@ -287,17 +287,17 @@ u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout) ERROR("Error in Block Erasure or Clear Lock-Bits"); if (status & 0x40) ERROR("Block Erase Suspended"); - + cfi_intel_clear_status_register(bank); } - + return status; } int cfi_spansion_wait_status_busy(flash_bank_t *bank, int timeout) { u8 status, oldstatus; - + oldstatus = cfi_get_u8(bank, 0, 0x0); do { @@ -318,11 +318,11 @@ int cfi_spansion_wait_status_busy(flash_bank_t *bank, int timeout) DEBUG("status: 0x%x", status); return(ERROR_OK); } - + oldstatus = status; usleep(1000); } while (timeout-- > 0); - + ERROR("timeout, status: 0x%x", status); return(ERROR_FLASH_BUSY); @@ -334,13 +334,13 @@ int cfi_read_intel_pri_ext(flash_bank_t *bank) cfi_intel_pri_ext_t *pri_ext = malloc(sizeof(cfi_intel_pri_ext_t)); target_t *target = bank->target; u8 command[8]; - + cfi_info->pri_ext = pri_ext; - + pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0); pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1); pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2); - + if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) { cfi_command(bank, 0xf0, command); @@ -349,37 +349,37 @@ int cfi_read_intel_pri_ext(flash_bank_t *bank) target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); return ERROR_FLASH_BANK_INVALID; } - + pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3); pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4); - + DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); - + pri_ext->feature_support = cfi_query_u32(bank, 0, cfi_info->pri_addr + 5); pri_ext->suspend_cmd_support = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9); pri_ext->blk_status_reg_mask = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xa); - + DEBUG("feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask); - + pri_ext->vcc_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xc); pri_ext->vpp_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xd); - + DEBUG("Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x", (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f, (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f); - + pri_ext->num_protection_fields = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xe); if (pri_ext->num_protection_fields != 1) { WARNING("expected one protection register field, but found %i", pri_ext->num_protection_fields); } - + pri_ext->prot_reg_addr = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xf); pri_ext->fact_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x11); pri_ext->user_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x12); DEBUG("protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size); - + return ERROR_OK; } @@ -391,21 +391,21 @@ int cfi_read_spansion_pri_ext(flash_bank_t *bank) u8 command[8]; cfi_info->pri_ext = pri_ext; - + pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0); pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1); pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2); - + if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) { cfi_command(bank, 0xf0, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); return ERROR_FLASH_BANK_INVALID; } - + pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3); pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4); - + DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); pri_ext->SiliconRevision = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5); @@ -428,18 +428,18 @@ int cfi_read_spansion_pri_ext(flash_bank_t *bank) DEBUG("Burst Mode: 0x%x, Page Mode: 0x%x, ", pri_ext->BurstMode, pri_ext->PageMode); - + DEBUG("Vpp min: %2.2d.%1.1d, Vpp max: %2.2d.%1.1x", (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f, (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f); - + DEBUG("WP# protection 0x%x", pri_ext->TopBottom); - + /* default values for implementation specific workarounds */ pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2; pri_ext->_reversed_geometry = 0; - + return ERROR_OK; } @@ -450,39 +450,39 @@ int cfi_read_atmel_pri_ext(flash_bank_t *bank) cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t)); target_t *target = bank->target; u8 command[8]; - + /* ATMEL devices use the same CFI primary command set (0x2) as AMD/Spansion, * but a different primary extended query table. * We read the atmel table, and prepare a valid AMD/Spansion query table. */ - + memset(pri_ext, 0, sizeof(cfi_spansion_pri_ext_t)); - + cfi_info->pri_ext = pri_ext; - + atmel_pri_ext.pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0); atmel_pri_ext.pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1); atmel_pri_ext.pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2); - + if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R') || (atmel_pri_ext.pri[2] != 'I')) { cfi_command(bank, 0xf0, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); return ERROR_FLASH_BANK_INVALID; } - + pri_ext->pri[0] = atmel_pri_ext.pri[0]; pri_ext->pri[1] = atmel_pri_ext.pri[1]; pri_ext->pri[2] = atmel_pri_ext.pri[2]; - + atmel_pri_ext.major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3); atmel_pri_ext.minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4); - + DEBUG("pri: '%c%c%c', version: %c.%c", atmel_pri_ext.pri[0], atmel_pri_ext.pri[1], atmel_pri_ext.pri[2], atmel_pri_ext.major_version, atmel_pri_ext.minor_version); - + pri_ext->major_version = atmel_pri_ext.major_version; pri_ext->minor_version = atmel_pri_ext.minor_version; - + atmel_pri_ext.features = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5); atmel_pri_ext.bottom_boot = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6); atmel_pri_ext.burst_mode = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7); @@ -490,7 +490,7 @@ int cfi_read_atmel_pri_ext(flash_bank_t *bank) DEBUG("features: 0x%2.2x, bottom_boot: 0x%2.2x, burst_mode: 0x%2.2x, page_mode: 0x%2.2x", atmel_pri_ext.features, atmel_pri_ext.bottom_boot, atmel_pri_ext.burst_mode, atmel_pri_ext.page_mode); - + if (atmel_pri_ext.features & 0x02) pri_ext->EraseSuspend = 2; @@ -498,14 +498,14 @@ int cfi_read_atmel_pri_ext(flash_bank_t *bank) pri_ext->TopBottom = 2; else pri_ext->TopBottom = 3; - + return ERROR_OK; } int cfi_read_0002_pri_ext(flash_bank_t *bank) { cfi_flash_bank_t *cfi_info = bank->driver_priv; - + if (cfi_info->manufacturer == CFI_MFR_ATMEL) { return cfi_read_atmel_pri_ext(bank); @@ -521,29 +521,29 @@ int cfi_spansion_info(struct flash_bank_s *bank, char *buf, int buf_size) int printed; cfi_flash_bank_t *cfi_info = bank->driver_priv; cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; - + printed = snprintf(buf, buf_size, "\nSpansion primary algorithm extend information:\n"); buf += printed; buf_size -= printed; - - printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], - pri_ext->pri[1], pri_ext->pri[2], + + printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], + pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); buf += printed; buf_size -= printed; - - printed = snprintf(buf, buf_size, "Silicon Rev.: 0x%x, Address Sensitive unlock: 0x%x\n", + + printed = snprintf(buf, buf_size, "Silicon Rev.: 0x%x, Address Sensitive unlock: 0x%x\n", (pri_ext->SiliconRevision) >> 2, (pri_ext->SiliconRevision) & 0x03); buf += printed; buf_size -= printed; - - printed = snprintf(buf, buf_size, "Erase Suspend: 0x%x, Sector Protect: 0x%x\n", + + printed = snprintf(buf, buf_size, "Erase Suspend: 0x%x, Sector Protect: 0x%x\n", pri_ext->EraseSuspend, pri_ext->BlkProt); buf += printed; buf_size -= printed; - + printed = snprintf(buf, buf_size, "VppMin: %2.2d.%1.1x, VppMax: %2.2d.%1.1x\n", (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f, (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f); @@ -556,34 +556,34 @@ int cfi_intel_info(struct flash_bank_s *bank, char *buf, int buf_size) int printed; cfi_flash_bank_t *cfi_info = bank->driver_priv; cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext; - + printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n"); buf += printed; buf_size -= printed; - + printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); buf += printed; buf_size -= printed; - + printed = snprintf(buf, buf_size, "feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask); buf += printed; buf_size -= printed; - + printed = snprintf(buf, buf_size, "Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x\n", (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f, (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f); buf += printed; buf_size -= printed; - + printed = snprintf(buf, buf_size, "protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i\n", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size); - + return ERROR_OK; } int cfi_register_commands(struct command_context_s *cmd_ctx) { /*command_t *cfi_cmd = */register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, NULL); - /* + /* register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC, "print part id of cfi flash bank <num>"); */ @@ -596,27 +596,27 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char ** { cfi_flash_bank_t *cfi_info; int i; - + if (argc < 6) { WARNING("incomplete flash_bank cfi configuration"); return ERROR_FLASH_BANK_INVALID; } - + if ((strtoul(args[4], NULL, 0) > CFI_MAX_CHIP_WIDTH) || (strtoul(args[3], NULL, 0) > CFI_MAX_BUS_WIDTH)) { ERROR("chip and bus width have to specified in byte"); return ERROR_FLASH_BANK_INVALID; } - + cfi_info = malloc(sizeof(cfi_flash_bank_t)); bank->driver_priv = cfi_info; - + cfi_info->x16_as_x8 = 0; cfi_info->jedec_probe = 0; cfi_info->not_cfi = 0; - + for (i = 6; i < argc; i++) { if (strcmp(args[i], "x16_as_x8") == 0) @@ -628,12 +628,12 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char ** cfi_info->jedec_probe = 1; } } - + cfi_info->write_algorithm = NULL; /* bank wasn't probed yet */ cfi_info->qry[0] = -1; - + return ERROR_OK; } @@ -643,35 +643,35 @@ int cfi_intel_erase(struct flash_bank_s *bank, int first, int last) target_t *target = bank->target; u8 command[8]; int i; - + cfi_intel_clear_status_register(bank); for (i = first; i <= last; i++) { cfi_command(bank, 0x20, command); target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); - + cfi_command(bank, 0xd0, command); target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); - + if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == 0x80) bank->sectors[i].is_erased = 1; else { cfi_command(bank, 0xff, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); - + ERROR("couldn't erase block %i of flash bank at base 0x%x", i, bank->base); return ERROR_FLASH_OPERATION_FAILED; } } - + cfi_command(bank, 0xff, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); - + return ERROR_OK; } - + int cfi_spansion_erase(struct flash_bank_s *bank, int first, int last) { cfi_flash_bank_t *cfi_info = bank->driver_priv; @@ -679,24 +679,24 @@ int cfi_spansion_erase(struct flash_bank_s *bank, int first, int last) target_t *target = bank->target; u8 command[8]; int i; - + for (i = first; i <= last; i++) { cfi_command(bank, 0xaa, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); - + cfi_command(bank, 0x55, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); - + cfi_command(bank, 0x80, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); cfi_command(bank, 0xaa, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); - + cfi_command(bank, 0x55, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); - + cfi_command(bank, 0x30, command); target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); @@ -706,27 +706,27 @@ int cfi_spansion_erase(struct flash_bank_s *bank, int first, int last) { cfi_command(bank, 0xf0, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); - + ERROR("couldn't erase block %i of flash bank at base 0x%x", i, bank->base); return ERROR_FLASH_OPERATION_FAILED; } } - + cfi_command(bank, 0xf0, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); - + return ERROR_OK; } - + int cfi_erase(struct flash_bank_s *bank, int first, int last) { cfi_flash_bank_t *cfi_info = bank->driver_priv; - + if (bank->target->state != TARGET_HALTED) { return ERROR_TARGET_NOT_HALTED; } - + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { return ERROR_FLASH_SECTOR_INVALID; @@ -734,7 +734,7 @@ int cfi_erase(struct flash_bank_s *bank, int first, int last) if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; - + switch(cfi_info->pri_id) { case 1: @@ -748,7 +748,7 @@ int cfi_erase(struct flash_bank_s *bank, int first, int last) ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } - + return ERROR_OK; } @@ -760,13 +760,13 @@ int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last) u8 command[8]; int retry = 0; int i; - + /* if the device supports neither legacy lock/unlock (bit 3) nor * instant individual block locking (bit 5). */ if (!(pri_ext->feature_support & 0x28)) return ERROR_FLASH_OPERATION_FAILED; - + cfi_intel_clear_status_register(bank); for (i = first; i <= last; i++) @@ -802,25 +802,25 @@ int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last) cfi_command(bank, 0x90, command); target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); block_status = cfi_get_u8(bank, i, 0x2); - + if ((block_status & 0x1) != set) { ERROR("couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status); cfi_command(bank, 0x70, command); target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); cfi_intel_wait_status_busy(bank, 10); - + if (retry > 10) return ERROR_FLASH_OPERATION_FAILED; else { i--; - retry++; + retry++; } - } + } } } - + /* if the device doesn't support individual block lock bits set/clear, * all blocks have been unlocked in parallel, so we set those that should be protected */ @@ -836,34 +836,34 @@ int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last) cfi_command(bank, 0x01, command); target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command); } - + cfi_intel_wait_status_busy(bank, 100); } } - + cfi_command(bank, 0xff, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); - + return ERROR_OK; } int cfi_protect(struct flash_bank_s *bank, int set, int first, int last) { cfi_flash_bank_t *cfi_info = bank->driver_priv; - + if (bank->target->state != TARGET_HALTED) { return ERROR_TARGET_NOT_HALTED; } - + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { return ERROR_FLASH_SECTOR_INVALID; } - + if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; - + switch(cfi_info->pri_id) { case 1: @@ -874,7 +874,7 @@ int cfi_protect(struct flash_bank_s *bank, int set, int first, int last) ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } - + return ERROR_OK; } @@ -883,7 +883,7 @@ void cfi_add_byte(struct flash_bank_s *bank, u8 *word, u8 byte) target_t *target = bank->target; int i; - + if (target->endianness == TARGET_LITTLE_ENDIAN) { /* shift bytes */ @@ -923,7 +923,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 * r5: busy test pattern * r6: error test pattern */ - + static const u32 word_32_code[] = { 0xe4904004, /* loop: ldr r4, [r0], #4 */ 0xe5813000, /* str r3, [r1] */ @@ -940,7 +940,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 0xeafffff2, /* b loop */ 0xeafffffe, /* done: b -2 */ }; - + static const u32 word_16_code[] = { 0xe0d040b2, /* loop: ldrh r4, [r0], #2 */ 0xe1c130b0, /* strh r3, [r1] */ @@ -957,7 +957,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 0xeafffff2, /* b loop */ 0xeafffffe, /* done: b -2 */ }; - + static const u32 word_8_code[] = { 0xe4d04001, /* loop: ldrb r4, [r0], #1 */ 0xe5c13000, /* strb r3, [r1] */ @@ -974,25 +974,25 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 0xeafffff2, /* b loop */ 0xeafffffe, /* done: b -2 */ }; - + cfi_intel_clear_status_register(bank); - + armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC; armv4_5_info.core_mode = ARMV4_5_MODE_SVC; armv4_5_info.core_state = ARMV4_5_STATE_ARM; - + /* flash write code */ if (!cfi_info->write_algorithm) { u8 write_code_buf[14 * 4]; int i; - + if (target_alloc_working_area(target, 4 * 14, &cfi_info->write_algorithm) != ERROR_OK) { WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; - + /* write algorithm code to working area */ if (bank->bus_width == 1) { @@ -1003,7 +1003,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 { for (i = 0; i < 14; i++) target_buffer_set_u32(target, write_code_buf + (i*4), word_16_code[i]); - } + } else if (bank->bus_width == 4) { for (i = 0; i < 14; i++) @@ -1016,7 +1016,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, write_code_buf); } - + while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; @@ -1025,7 +1025,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */ if (cfi_info->write_algorithm) target_free_working_area(target, cfi_info->write_algorithm); - + WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1043,7 +1043,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 cfi_command(bank, 0x40, write_command_buf); cfi_command(bank, 0x80, busy_pattern_buf); cfi_command(bank, 0x7e, error_pattern_buf); - + if (bank->bus_width == 1) { write_command_val = write_command_buf[0]; @@ -1062,26 +1062,26 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 busy_pattern_val = target_buffer_get_u32(target, busy_pattern_buf); error_pattern_val = target_buffer_get_u32(target, error_pattern_buf); } - + while (count > 0) { u32 thisrun_count = (count > buffer_size) ? buffer_size : count; - + target_write_buffer(target, source->address, thisrun_count, buffer); - + buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, write_command_val); buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val); buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val); - + if ((retval = target->type->run_algorithm(target, 0, NULL, 7, reg_params, cfi_info->write_algorithm->address, cfi_info->write_algorithm->address + (13 * 4), 10000, &armv4_5_info)) != ERROR_OK) { cfi_intel_clear_status_register(bank); return ERROR_FLASH_OPERATION_FAILED; } - + if (buf_get_u32(reg_params[4].value, 0, 32) & error_pattern_val) { /* read status register (outputs debug inforation) */ @@ -1089,14 +1089,14 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 cfi_intel_clear_status_register(bank); return ERROR_FLASH_OPERATION_FAILED; } - + buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } - + target_free_working_area(target, source); - + destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); @@ -1104,7 +1104,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3 destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); destroy_reg_param(®_params[6]); - + return ERROR_OK; } @@ -1173,7 +1173,7 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, /* 00008154 <sp_32_done>: */ 0xeafffffe /* b 8154 <sp_32_done> */ }; - + u32 word_16_code[] = { /* 00008158 <sp_16_code>: */ 0xe0d050b2, /* ldrh r5, [r0], #2 */ @@ -1205,9 +1205,9 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, 0xeaffffe8, /* b 8158 <sp_16_code> */ /* */ /* 000081ac <sp_16_done>: */ - 0xeafffffe /* b 81ac <sp_16_done> */ + 0xeafffffe /* b 81ac <sp_16_done> */ }; - + u32 word_8_code[] = { /* 000081b0 <sp_16_code_end>: */ 0xe4d05001, /* ldrb r5, [r0], #1 */ @@ -1241,11 +1241,11 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, /* 00008204 <sp_8_done>: */ 0xeafffffe /* b 8204 <sp_8_done> */ }; - + armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC; armv4_5_info.core_mode = ARMV4_5_MODE_SVC; armv4_5_info.core_state = ARMV4_5_STATE_ARM; - + /* flash write code */ if (!cfi_info->write_algorithm) { @@ -1255,21 +1255,21 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, if (bank->bus_width == 1) { code_p = malloc(24 * 4); - + for (i = 0; i < 24; i++) target_buffer_set_u32(target, code_p + (i*4), word_8_code[i]); } else if (bank->bus_width == 2) { code_p = malloc(24 * 4); - + for (i = 0; i < 24; i++) target_buffer_set_u32(target, code_p + (i*4), word_16_code[i]); - } + } else if (bank->bus_width == 4) { code_p = malloc(24 * 4); - + for (i = 0; i < 24; i++) target_buffer_set_u32(target, code_p + (i*4), word_32_code[i]); } @@ -1277,7 +1277,7 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, { return ERROR_FLASH_OPERATION_FAILED; } - + /* allocate working area */ if (target_alloc_working_area(target, 24 * 4, &cfi_info->write_algorithm) != ERROR_OK) @@ -1285,13 +1285,13 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - + /* write algorithm code to working area */ target_write_buffer(target, cfi_info->write_algorithm->address, 24 * 4, code_p); - + free(code_p); } - + while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; @@ -1300,7 +1300,7 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */ if (cfi_info->write_algorithm) target_free_working_area(target, cfi_info->write_algorithm); - + WARNING("not enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1320,9 +1320,9 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, while (count > 0) { u32 thisrun_count = (count > buffer_size) ? buffer_size : count; - + target_write_buffer(target, source->address, thisrun_count, buffer); - + buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); @@ -1334,28 +1334,28 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, buf_set_u32(reg_params[7].value, 0, 32, 0xaa); buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2)); buf_set_u32(reg_params[9].value, 0, 32, 0x55); - - retval = target->type->run_algorithm(target, 0, NULL, 10, reg_params, - cfi_info->write_algorithm->address, - cfi_info->write_algorithm->address + ((24 * 4) - 4), + + retval = target->type->run_algorithm(target, 0, NULL, 10, reg_params, + cfi_info->write_algorithm->address, + cfi_info->write_algorithm->address + ((24 * 4) - 4), 10000, &armv4_5_info); status = buf_get_u32(reg_params[5].value, 0, 32); - + if ((retval != ERROR_OK) || status != 0x80) { DEBUG("status: 0x%x", status); exit_code = ERROR_FLASH_OPERATION_FAILED; break; } - + buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } - + target_free_working_area(target, source); - + destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); @@ -1375,22 +1375,22 @@ int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address) cfi_flash_bank_t *cfi_info = bank->driver_priv; target_t *target = bank->target; u8 command[8]; - + cfi_intel_clear_status_register(bank); cfi_command(bank, 0x40, command); target->type->write_memory(target, address, bank->bus_width, 1, command); - + target->type->write_memory(target, address, bank->bus_width, 1, word); - + if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != 0x80) { cfi_command(bank, 0xff, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); - + ERROR("couldn't write word at base 0x%x, address %x", bank->base, address); return ERROR_FLASH_OPERATION_FAILED; } - + return ERROR_OK; } @@ -1400,34 +1400,34 @@ int cfi_spansion_write_word(struct flash_bank_s *bank, u8 *word, u32 address) cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; target_t *target = bank->target; u8 command[8]; - + cfi_command(bank, 0xaa, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); - + cfi_command(bank, 0x55, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); - + cfi_command(bank, 0xa0, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); target->type->write_memory(target, address, bank->bus_width, 1, word); - + if (cfi_spansion_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != ERROR_OK) { cfi_command(bank, 0xf0, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); - + ERROR("couldn't write word at base 0x%x, address %x", bank->base, address); return ERROR_FLASH_OPERATION_FAILED; } - + return ERROR_OK; } int cfi_write_word(struct flash_bank_s *bank, u8 *word, u32 address) { cfi_flash_bank_t *cfi_info = bank->driver_priv; - + switch(cfi_info->pri_id) { case 1: @@ -1441,7 +1441,7 @@ int cfi_write_word(struct flash_bank_s *bank, u8 *word, u32 address) ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } - + return ERROR_FLASH_OPERATION_FAILED; } @@ -1455,15 +1455,15 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) u8 current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being programmed */ int i; int retval; - + if (bank->target->state != TARGET_HALTED) { return ERROR_TARGET_NOT_HALTED; } - + if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; - + if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; @@ -1498,13 +1498,13 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) target->type->read_memory(target, copy_p, 1, 1, &byte); cfi_add_byte(bank, current_word, byte); } - + retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; write_p = copy_p; } - + /* handle blocks of bus_size aligned bytes */ switch(cfi_info->pri_id) { @@ -1530,12 +1530,12 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) { for (i = 0; i < bank->bus_width; i++) current_word[i] = 0; - + for (i = 0; i < bank->bus_width; i++) { cfi_add_byte(bank, current_word, *buffer++); } - + retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; @@ -1546,14 +1546,14 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) else return retval; } - + /* handle unaligned tail bytes */ if (count > 0) { copy_p = write_p; for (i = 0; i < bank->bus_width; i++) current_word[i] = 0; - + for (i = 0; (i < bank->bus_width) && (count > 0); ++i, ++copy_p) { cfi_add_byte(bank, current_word, *buffer++); @@ -1569,13 +1569,13 @@ int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count) if (retval != ERROR_OK) return retval; } - + /* return to read array mode */ cfi_command(bank, 0xf0, current_word); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word); cfi_command(bank, 0xff, current_word); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word); - + return ERROR_OK; } @@ -1583,7 +1583,7 @@ void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *bank, void *param) { cfi_flash_bank_t *cfi_info = bank->driver_priv; cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; - + pri_ext->_reversed_geometry = 1; } @@ -1592,16 +1592,16 @@ void cfi_fixup_0002_erase_regions(flash_bank_t *bank, void *param) int i; cfi_flash_bank_t *cfi_info = bank->driver_priv; cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; - + if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3)) { DEBUG("swapping reversed erase region information on cmdset 0002 device"); - + for (i = 0; i < cfi_info->num_erase_regions / 2; i++) { int j = (cfi_info->num_erase_regions - 1) - i; u32 swap; - + swap = cfi_info->erase_region_info[i]; cfi_info->erase_region_info[i] = cfi_info->erase_region_info[j]; cfi_info->erase_region_info[j] = swap; @@ -1614,7 +1614,7 @@ void cfi_fixup_0002_unlock_addresses(flash_bank_t *bank, void *param) cfi_flash_bank_t *cfi_info = bank->driver_priv; cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext; cfi_unlock_addresses_t *unlock_addresses = param; - + pri_ext->_unlock1 = unlock_addresses->unlock1; pri_ext->_unlock2 = unlock_addresses->unlock2; } @@ -1630,7 +1630,7 @@ int cfi_probe(struct flash_bank_s *bank) u32 offset = 0; u32 unlock1 = 0x555; u32 unlock2 = 0x2aa; - + /* JEDEC standard JESD21C uses 0x5555 and 0x2aaa as unlock addresses, * while CFI compatible AMD/Spansion flashes use 0x555 and 0x2aa */ @@ -1639,7 +1639,7 @@ int cfi_probe(struct flash_bank_s *bank) unlock1 = 0x5555; unlock2 = 0x2aaa; } - + /* switch to read identifier codes mode ("AUTOSELECT") */ cfi_command(bank, 0xaa, command); target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command); @@ -1661,7 +1661,7 @@ int cfi_probe(struct flash_bank_s *bank) target_read_u16(target, bank->base + 0x0, &cfi_info->manufacturer); target_read_u16(target, bank->base + 0x2, &cfi_info->device_id); } - + /* switch back to read array mode */ cfi_command(bank, 0xf0, command); target->type->write_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, command); @@ -1679,18 +1679,18 @@ int cfi_probe(struct flash_bank_s *bank) * according to JEDEC Standard No. 68.01, * a single bus sequence with address = 0x55, data = 0x98 should put * the device into CFI query mode. - * + * * SST flashes clearly violate this, and we will consider them incompatbile for now */ cfi_command(bank, 0x98, command); target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command); - + cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10); cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11); cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12); - + DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]); - + if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y')) { cfi_command(bank, 0xf0, command); @@ -1699,14 +1699,14 @@ int cfi_probe(struct flash_bank_s *bank) target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); return ERROR_FLASH_BANK_INVALID; } - + cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13); cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15); cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17); cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19); - + DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); - + cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b); cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c); cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d); @@ -1719,7 +1719,7 @@ int cfi_probe(struct flash_bank_s *bank) cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24); cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25); cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26); - + DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, @@ -1731,19 +1731,19 @@ int cfi_probe(struct flash_bank_s *bank) (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ), (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ), (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); - + cfi_info->dev_size = cfi_query_u8(bank, 0, 0x27); cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28); cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a); cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c); - + DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size)); - + if (((1 << cfi_info->dev_size) * bank->bus_width / bank->chip_width) != bank->size) { WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size); } - + if (cfi_info->num_erase_regions) { cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions); @@ -1757,10 +1757,10 @@ int cfi_probe(struct flash_bank_s *bank) { cfi_info->erase_region_info = NULL; } - + /* We need to read the primary algorithm extended query table before calculating * the sector layout to be able to apply fixups - */ + */ switch(cfi_info->pri_id) { /* Intel command set (standard and extended) */ @@ -1776,7 +1776,7 @@ int cfi_probe(struct flash_bank_s *bank) ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } - + /* return to read array mode * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command */ @@ -1785,7 +1785,7 @@ int cfi_probe(struct flash_bank_s *bank) cfi_command(bank, 0xff, command); target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command); } - + /* apply fixups depending on the primary command set */ switch(cfi_info->pri_id) { @@ -1802,13 +1802,13 @@ int cfi_probe(struct flash_bank_s *bank) ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } - + if (cfi_info->num_erase_regions == 0) { - /* a device might have only one erase block, spanning the whole device */ + /* a device might have only one erase block, spanning the whole device */ bank->num_sectors = 1; bank->sectors = malloc(sizeof(flash_sector_t)); - + bank->sectors[sector].offset = 0x0; bank->sectors[sector].size = bank->size; bank->sectors[sector].is_erased = -1; @@ -1820,10 +1820,10 @@ int cfi_probe(struct flash_bank_s *bank) { num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1; } - + bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors); - + for (i = 0; i < cfi_info->num_erase_regions; i++) { int j; @@ -1838,7 +1838,7 @@ int cfi_probe(struct flash_bank_s *bank) } } } - + return ERROR_OK; } @@ -1848,7 +1848,7 @@ int cfi_erase_check(struct flash_bank_s *bank) target_t *target = bank->target; int i; int retval; - + if (!cfi_info->erase_check_algorithm) { u32 erase_check_code[] = @@ -1859,7 +1859,7 @@ int cfi_erase_check(struct flash_bank_s *bank) 0x1afffffb, /* b -4 */ 0xeafffffe /* b 0 */ }; - + /* make sure we have a working area */ if (target_alloc_working_area(target, 20, &cfi_info->erase_check_algorithm) != ERROR_OK) { @@ -1868,53 +1868,53 @@ int cfi_erase_check(struct flash_bank_s *bank) else { u8 erase_check_code_buf[5 * 4]; - + for (i = 0; i < 5; i++) target_buffer_set_u32(target, erase_check_code_buf + (i*4), erase_check_code[i]); - + /* write algorithm code to working area */ target->type->write_memory(target, cfi_info->erase_check_algorithm->address, 4, 5, erase_check_code_buf); } } - + if (!cfi_info->erase_check_algorithm) { u32 *buffer = malloc(4096); - + for (i = 0; i < bank->num_sectors; i++) { u32 address = bank->base + bank->sectors[i].offset; u32 size = bank->sectors[i].size; u32 check = 0xffffffffU; int erased = 1; - + while (size > 0) { u32 thisrun_size = (size > 4096) ? 4096 : size; int j; - + target->type->read_memory(target, address, 4, thisrun_size / 4, (u8*)buffer); - + for (j = 0; j < thisrun_size / 4; j++) check &= buffer[j]; - + if (check != 0xffffffff) { erased = 0; break; } - + size -= thisrun_size; address += thisrun_size; } - + bank->sectors[i].is_erased = erased; } - + free(buffer); } else - { + { for (i = 0; i < bank->num_sectors; i++) { u32 address = bank->base + bank->sectors[i].offset; @@ -1922,34 +1922,34 @@ int cfi_erase_check(struct flash_bank_s *bank) reg_param_t reg_params[3]; armv4_5_algorithm_t armv4_5_info; - + armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC; armv4_5_info.core_mode = ARMV4_5_MODE_SVC; armv4_5_info.core_state = ARMV4_5_STATE_ARM; - + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); - + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, size); - + init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); - + if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, cfi_info->erase_check_algorithm->address, cfi_info->erase_check_algorithm->address + 0x10, 10000, &armv4_5_info)) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; - + if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff) bank->sectors[i].is_erased = 1; else bank->sectors[i].is_erased = 0; - + destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); } } - + return ERROR_OK; } @@ -1960,7 +1960,7 @@ int cfi_intel_protect_check(struct flash_bank_s *bank) target_t *target = bank->target; u8 command[CFI_MAX_BUS_WIDTH]; int i; - + /* check if block lock bits are supported on this device */ if (!(pri_ext->blk_status_reg_mask & 0x1)) return ERROR_FLASH_OPERATION_FAILED; @@ -1971,7 +1971,7 @@ int cfi_intel_protect_check(struct flash_bank_s *bank) for (i = 0; i < bank->num_sectors; i++) { u8 block_status = cfi_get_u8(bank, i, 0x2); - + if (block_status & 1) bank->sectors[i].is_protected = 1; else @@ -1991,20 +1991,20 @@ int cfi_spansion_protect_check(struct flash_bank_s *bank) target_t *target = bank->target; u8 command[8]; int i; - + cfi_command(bank, 0xaa, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); - + cfi_command(bank, 0x55, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock2), bank->bus_width, 1, command); - + cfi_command(bank, 0x90, command); target->type->write_memory(target, flash_address(bank, 0, pri_ext->_unlock1), bank->bus_width, 1, command); for (i = 0; i < bank->num_sectors; i++) { u8 block_status = cfi_get_u8(bank, i, 0x2); - + if (block_status & 1) bank->sectors[i].is_protected = 1; else @@ -2023,7 +2023,7 @@ int cfi_protect_check(struct flash_bank_s *bank) if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; - + switch(cfi_info->pri_id) { case 1: @@ -2037,7 +2037,7 @@ int cfi_protect_check(struct flash_bank_s *bank) ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } - + return ERROR_OK; } @@ -2045,13 +2045,13 @@ int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size) { int printed; cfi_flash_bank_t *cfi_info = bank->driver_priv; - + if (cfi_info->qry[0] == -1) { printed = snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n"); return ERROR_OK; } - + printed = snprintf(buf, buf_size, "\ncfi information:\n"); buf += printed; buf_size -= printed; @@ -2060,34 +2060,34 @@ int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size) cfi_info->manufacturer, cfi_info->device_id); buf += printed; buf_size -= printed; - + printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); buf += printed; buf_size -= printed; - + printed = snprintf(buf, buf_size, "Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x\n", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f, (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f); buf += printed; buf_size -= printed; - + printed = snprintf(buf, buf_size, "typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u\n", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ, 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ); buf += printed; buf_size -= printed; - + printed = snprintf(buf, buf_size, "max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u\n", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ), (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ), (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ), (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); buf += printed; buf_size -= printed; - + printed = snprintf(buf, buf_size, "size: 0x%x, interface desc: %i, max buffer write size: %x\n", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size); buf += printed; buf_size -= printed; - + switch(cfi_info->pri_id) { case 1: @@ -2101,6 +2101,6 @@ int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size) ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } - + return ERROR_OK; } diff --git a/src/flash/cfi.h b/src/flash/cfi.h index bf58522b..9572c83a 100644 --- a/src/flash/cfi.h +++ b/src/flash/cfi.h @@ -27,22 +27,22 @@ typedef struct cfi_flash_bank_s { working_area_t *write_algorithm; working_area_t *erase_check_algorithm; - + int x16_as_x8; int jedec_probe; int not_cfi; - + u16 manufacturer; u16 device_id; - + char qry[3]; - + /* identification string */ u16 pri_id; u16 pri_addr; u16 alt_id; u16 alt_addr; - + /* device-system interface */ u8 vcc_min; u8 vcc_max; @@ -56,19 +56,19 @@ typedef struct cfi_flash_bank_s u8 buf_write_timeout_max; u8 block_erase_timeout_max; u8 chip_erase_timeout_max; - + /* flash geometry */ u8 dev_size; u16 interface_desc; u16 max_buf_write_size; u8 num_erase_regions; u32 *erase_region_info; - + void *pri_ext; void *alt_ext; } cfi_flash_bank_t; -/* Intel primary extended query table +/* Intel primary extended query table * as defined for the Advanced+ Boot Block Flash Memory (C3) * and used by the linux kernel cfi driver (as of 2.6.14) */ |