summaryrefslogtreecommitdiff
path: root/src/flash
diff options
context:
space:
mode:
authordrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2007-05-29 11:23:42 +0000
committerdrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2007-05-29 11:23:42 +0000
commit237e894805dd757cc24029af1b4b1e824c51712b (patch)
treeabe2187fa53c3ba2e51201df0a60a6e10af6cc0f /src/flash
parente8af4de0a7d224e1aa28e72f0de1ddf0bec5beb8 (diff)
downloadopenocd+libswd-237e894805dd757cc24029af1b4b1e824c51712b.tar.gz
openocd+libswd-237e894805dd757cc24029af1b4b1e824c51712b.tar.bz2
openocd+libswd-237e894805dd757cc24029af1b4b1e824c51712b.tar.xz
openocd+libswd-237e894805dd757cc24029af1b4b1e824c51712b.zip
- split fileio handling into fileio part and image handling
- reworked etm/etb into a generic etm part with trace capture drivers (currently only etb supported) - added XScale debug handler binary to repository - added Thumb disassembling (thanks to Vincent Palatin for this patch) - added support for non-CFI compatible flashes to cfi driver (currently only SST39VFxxx devices supported) This checkin is experimental, not suitable for general use git-svn-id: svn://svn.berlios.de/openocd/trunk@155 b42882b7-edfa-0310-969c-e2dbd0fdcd60
Diffstat (limited to 'src/flash')
-rw-r--r--src/flash/Makefile.am4
-rw-r--r--src/flash/cfi.c410
-rw-r--r--src/flash/cfi.h18
-rw-r--r--src/flash/flash.c28
-rw-r--r--src/flash/nand.c58
-rw-r--r--src/flash/non_cfi.c175
-rw-r--r--src/flash/non_cfi.h41
7 files changed, 535 insertions, 199 deletions
diff --git a/src/flash/Makefile.am b/src/flash/Makefile.am
index 6368f626..8f99e05e 100644
--- a/src/flash/Makefile.am
+++ b/src/flash/Makefile.am
@@ -1,5 +1,5 @@
INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target $(all_includes)
METASOURCES = AUTO
noinst_LIBRARIES = libflash.a
-libflash_a_SOURCES = flash.c lpc2000.c cfi.c at91sam7.c str7x.c str9x.c nand.c lpc3180_nand_controller.c
-noinst_HEADERS = flash.h lpc2000.h cfi.h at91sam7.h str7x.h str9x.h nand.h lpc3180_nand_controller.h
+libflash_a_SOURCES = flash.c lpc2000.c cfi.c non_cfi.c at91sam7.c str7x.c str9x.c nand.c lpc3180_nand_controller.c
+noinst_HEADERS = flash.h lpc2000.h cfi.h non_cfi.h at91sam7.h str7x.h str9x.h nand.h lpc3180_nand_controller.h
diff --git a/src/flash/cfi.c b/src/flash/cfi.c
index 83a8120a..69494b5f 100644
--- a/src/flash/cfi.c
+++ b/src/flash/cfi.c
@@ -66,17 +66,33 @@ flash_driver_t cfi_flash =
.info = cfi_info
};
+cfi_unlock_addresses_t cfi_unlock_addresses[] =
+{
+ [CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa },
+ [CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa },
+};
+
/* CFI fixups foward declarations */
+void cfi_fixup_non_cfi(flash_bank_t *flash, void *param);
void cfi_fixup_0002_erase_regions(flash_bank_t *flash, void *param);
+void cfi_fixup_0002_unlock_addresses(flash_bank_t *flash, void *param);
void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *flash, void *param);
/* fixup after identifying JEDEC manufactuer and ID */
cfi_fixup_t cfi_jedec_fixups[] = {
+ {CFI_MFR_SST, 0x00D4, cfi_fixup_non_cfi, NULL},
+ {CFI_MFR_SST, 0x00D5, cfi_fixup_non_cfi, NULL},
+ {CFI_MFR_SST, 0x00D6, cfi_fixup_non_cfi, NULL},
+ {CFI_MFR_SST, 0x00D7, cfi_fixup_non_cfi, NULL},
{0, 0, NULL, NULL}
};
/* fixup after reading cmdset 0002 primary query table */
cfi_fixup_t cfi_0002_fixups[] = {
+ {CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+ {CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+ {CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
+ {CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
{CFI_MFR_ATMEL, 0x00C8, cfi_fixup_atmel_reversed_erase_regions, NULL},
{CFI_MFR_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL},
{0, 0, NULL, NULL}
@@ -421,6 +437,11 @@ int cfi_read_spansion_pri_ext(flash_bank_t *bank)
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;
}
@@ -594,7 +615,9 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **
cfi_info = malloc(sizeof(cfi_flash_bank_t));
bank->driver_priv = cfi_info;
- cfi_info->x16_as_x8 = 1;
+ cfi_info->x16_as_x8 = 0;
+ cfi_info->jedec_probe = 0;
+ cfi_info->not_cfi = 0;
cfi_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
if (!cfi_info->target)
@@ -605,9 +628,13 @@ int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **
for (i = 6; i < argc; i++)
{
- if (strcmp(args[i], "x16_as_x8") != 0)
+ if (strcmp(args[i], "x16_as_x8") == 0)
{
- cfi_info->x16_as_x8 = 0;
+ cfi_info->x16_as_x8 = 1;
+ }
+ else if (strcmp(args[i], "jedec_probe") == 0)
+ {
+ cfi_info->jedec_probe = 1;
}
}
@@ -665,19 +692,19 @@ int cfi_spansion_erase(struct flash_bank_s *bank, int first, int last)
for (i = first; i <= last; i++)
{
cfi_command(bank, 0xaa, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, 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, 0x2aa), bank->bus_width, 1, 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, 0x555), bank->bus_width, 1, 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, 0x555), bank->bus_width, 1, 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, 0x2aa), bank->bus_width, 1, 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);
@@ -891,9 +918,10 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
armv4_5_algorithm_t armv4_5_info;
working_area_t *source;
u32 buffer_size = 32768;
- u8 write_command[CFI_MAX_BUS_WIDTH];
- u8 busy_pattern[CFI_MAX_BUS_WIDTH];
- u8 error_pattern[CFI_MAX_BUS_WIDTH];
+ u8 write_command_buf[CFI_MAX_BUS_WIDTH];
+ u8 busy_pattern_buf[CFI_MAX_BUS_WIDTH];
+ u8 error_pattern_buf[CFI_MAX_BUS_WIDTH];
+ u32 write_command_val, busy_pattern_val, error_pattern_val;
int retval;
/* algorithm register usage:
@@ -906,7 +934,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
* r6: error test pattern
*/
- u32 word_32_code[] = {
+ static const u32 word_32_code[] = {
0xe4904004, /* loop: ldr r4, [r0], #4 */
0xe5813000, /* str r3, [r1] */
0xe5814000, /* str r4, [r1] */
@@ -923,7 +951,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
0xeafffffe, /* done: b -2 */
};
- u32 word_16_code[] = {
+ static const u32 word_16_code[] = {
0xe0d040b2, /* loop: ldrh r4, [r0], #2 */
0xe1c130b0, /* strh r3, [r1] */
0xe1c140b0, /* strh r4, [r1] */
@@ -940,7 +968,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
0xeafffffe, /* done: b -2 */
};
- u32 word_8_code[] = {
+ static const u32 word_8_code[] = {
0xe4d04001, /* loop: ldrb r4, [r0], #1 */
0xe5c13000, /* strb r3, [r1] */
0xe5c14000, /* strb r4, [r1] */
@@ -966,29 +994,37 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
/* 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)
{
- target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_8_code);
+ for (i = 0; i < 14; i++)
+ target_buffer_set_u32(target, write_code_buf + (i*4), word_8_code[i]);
}
else if (bank->bus_width == 2)
{
- target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_16_code);
+ 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)
{
- target_write_buffer(target, cfi_info->write_algorithm->address, 14 * 4, (u8*)word_32_code);
+ for (i = 0; i < 14; i++)
+ target_buffer_set_u32(target, write_code_buf + (i*4), word_32_code[i]);
}
else
{
return ERROR_FLASH_OPERATION_FAILED;
}
+
+ 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)
@@ -1013,10 +1049,30 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);
init_reg_param(&reg_params[6], "r6", 32, PARAM_OUT);
- cfi_command(bank, 0x40, write_command);
- cfi_command(bank, 0x80, busy_pattern);
- cfi_command(bank, 0x7e, error_pattern);
-
+ /* prepare command and status register patterns */
+ 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];
+ busy_pattern_val = busy_pattern_buf[0];
+ error_pattern_val = error_pattern_buf[0];
+ }
+ else if (bank->bus_width == 2)
+ {
+ write_command_val = target_buffer_get_u16(target, write_command_buf);
+ busy_pattern_val = target_buffer_get_u16(target, busy_pattern_buf);
+ error_pattern_val = target_buffer_get_u16(target, error_pattern_buf);
+ }
+ else if (bank->bus_width == 4)
+ {
+ write_command_val = target_buffer_get_u32(target, write_command_buf);
+ 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;
@@ -1026,11 +1082,9 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
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, target_buffer_get_u32(target, write_command));
- buf_set_u32(reg_params[5].value, 0, 32, target_buffer_get_u32(target, busy_pattern));
- buf_set_u32(reg_params[6].value, 0, 32, target_buffer_get_u32(target, error_pattern));
- buf_set_u32(reg_params[5].value, 0, 32, buf_get_u32(busy_pattern, 0, 32));
- buf_set_u32(reg_params[6].value, 0, 32, buf_get_u32(error_pattern, 0, 32));
+ 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)
{
@@ -1038,7 +1092,7 @@ int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u3
return ERROR_FLASH_OPERATION_FAILED;
}
- if (buf_get_u32(reg_params[4].value, 0, 32) & target_buffer_get_u32(target, error_pattern))
+ if (buf_get_u32(reg_params[4].value, 0, 32) & error_pattern_val)
{
/* read status register (outputs debug inforation) */
cfi_intel_wait_status_busy(bank, 100);
@@ -1078,8 +1132,6 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
int i;
int retval;
int exit_code = ERROR_OK;
- int code_size;
- void *code_p;
/* input parameters - */
/* R0 = source address */
@@ -1095,8 +1147,8 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
/* unlock registers - */
/* R8 = unlock1_addr */
/* R9 = unlock1_cmd */
- /* R10 = unlock1_addr */
- /* R11 = unlock1_cmd */
+ /* R10 = unlock2_addr */
+ /* R11 = unlock2_cmd */
u32 word_32_code[] = {
/* 00008100 <sp_32_code>: */
@@ -1207,36 +1259,47 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
/* flash write code */
if (!cfi_info->write_algorithm)
{
- /* write algorithm code to working area */
+ u8 *code_p;
+
+ /* convert bus-width dependent algorithm code to correct endiannes */
if (bank->bus_width == 1)
{
- code_size = sizeof(word_8_code);
- code_p = word_8_code;
+ 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_size = sizeof(word_16_code);
- code_p = word_16_code;
- }
+ 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_size = sizeof(word_32_code);
- code_p = word_32_code;
+ code_p = malloc(24 * 4);
+
+ for (i = 0; i < 24; i++)
+ target_buffer_set_u32(target, code_p + (i*4), word_32_code[i]);
}
else
{
return ERROR_FLASH_OPERATION_FAILED;
}
-
- if (target_alloc_working_area(target, code_size,
- &cfi_info->write_algorithm) != ERROR_OK)
+
+ /* allocate working area */
+ if (target_alloc_working_area(target, 24 * 4,
+ &cfi_info->write_algorithm) != ERROR_OK)
{
WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
-
- target_write_buffer(target, cfi_info->write_algorithm->address,
- code_size, code_p);
+
+ /* 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)
@@ -1277,14 +1340,14 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
buf_set_u32(reg_params[3].value, 0, 32, buf_get_u32(write_command, 0, 32));
cfi_command(bank, 0x80, write_command);
buf_set_u32(reg_params[4].value, 0, 32, buf_get_u32(write_command, 0, 32));
- buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, 0x555));
+ buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1));
buf_set_u32(reg_params[7].value, 0, 32, 0xaa);
- buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, 0xaaa));
+ 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 + (code_size - 4),
+ cfi_info->write_algorithm->address + ((24 * 4) - 4),
10000, &armv4_5_info);
status = buf_get_u32(reg_params[5].value, 0, 32);
@@ -1301,6 +1364,8 @@ int cfi_spansion_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address,
count -= thisrun_count;
}
+ target_free_working_area(target, source);
+
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
@@ -1347,13 +1412,13 @@ int cfi_spansion_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
u8 command[8];
cfi_command(bank, 0xaa, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, 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, 0x2aa), bank->bus_width, 1, 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, 0x555), bank->bus_width, 1, 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);
@@ -1554,6 +1619,16 @@ void cfi_fixup_0002_erase_regions(flash_bank_t *bank, void *param)
}
}
+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;
+}
+
int cfi_probe(struct flash_bank_s *bank)
{
cfi_flash_bank_t *cfi_info = bank->driver_priv;
@@ -1563,14 +1638,25 @@ int cfi_probe(struct flash_bank_s *bank)
int i;
int sector = 0;
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
+ */
+ if (cfi_info->jedec_probe)
+ {
+ 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, 0x555), bank->bus_width, 1, command);
+ target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command);
cfi_command(bank, 0x55, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x2aa), bank->bus_width, 1, command);
+ target->type->write_memory(target, flash_address(bank, 0, unlock2), bank->bus_width, 1, command);
cfi_command(bank, 0x90, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, command);
+ target->type->write_memory(target, flash_address(bank, 0, unlock1), bank->bus_width, 1, command);
if (bank->chip_width == 1)
{
@@ -1594,105 +1680,132 @@ int cfi_probe(struct flash_bank_s *bank)
cfi_fixup(bank, cfi_jedec_fixups);
- /* enter CFI query mode
- * 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
+ /* query only if this is a CFI compatible flash,
+ * otherwise the relevant info has already been filled in
*/
- 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'))
+ if (cfi_info->not_cfi == 0)
{
+ /* enter CFI query mode
+ * 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);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+ cfi_command(bank, 0xff, command);
+ 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);
+ cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e);
+ cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f);
+ cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20);
+ cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21);
+ cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22);
+ cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23);
+ 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,
+ (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
+ (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
+ DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 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);
+ DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (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));
+
+ 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);
+ for (i = 0; i < cfi_info->num_erase_regions; i++)
+ {
+ cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
+ DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256);
+ }
+ }
+ else
+ {
+ 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) */
+ case 0x0001:
+ case 0x0003:
+ cfi_read_intel_pri_ext(bank);
+ break;
+ /* AMD/Spansion, Atmel, ... command set */
+ case 0x0002:
+ cfi_read_0002_pri_ext(bank);
+ break;
+ default:
+ 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
+ */
cfi_command(bank, 0xf0, command);
target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
cfi_command(bank, 0xff, command);
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);
- cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e);
- cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f);
- cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20);
- cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21);
- cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22);
- cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23);
- 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,
- (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
- (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
- DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 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);
- DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (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));
-
- 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);
- for (i = 0; i < cfi_info->num_erase_regions; i++)
- {
- cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
- DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256);
-
- num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
- }
- }
- else
- {
- 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
- */
+ /* apply fixups depending on the primary command set */
switch(cfi_info->pri_id)
{
/* Intel command set (standard and extended) */
case 0x0001:
case 0x0003:
- cfi_read_intel_pri_ext(bank);
cfi_fixup(bank, cfi_0001_fixups);
break;
/* AMD/Spansion, Atmel, ... command set */
- case 0x0002:
- cfi_read_0002_pri_ext(bank);
+ case 0x0002:
cfi_fixup(bank, cfi_0002_fixups);
break;
default:
@@ -1713,6 +1826,11 @@ int cfi_probe(struct flash_bank_s *bank)
}
else
{
+ for (i = 0; i < cfi_info->num_erase_regions; i++)
+ {
+ num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
+ }
+
bank->num_sectors = num_sectors;
bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
@@ -1731,14 +1849,6 @@ int cfi_probe(struct flash_bank_s *bank)
}
}
- /* return to read array mode
- * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command
- */
- cfi_command(bank, 0xf0, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
- cfi_command(bank, 0xff, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
-
return ERROR_OK;
}
@@ -1893,13 +2003,13 @@ int cfi_spansion_protect_check(struct flash_bank_s *bank)
int i;
cfi_command(bank, 0xaa, command);
- target->type->write_memory(target, flash_address(bank, 0, 0x555), bank->bus_width, 1, 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, 0x2aa), bank->bus_width, 1, 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, 0x555), bank->bus_width, 1, 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++)
{
diff --git a/src/flash/cfi.h b/src/flash/cfi.h
index fa53f0d8..b4e3ab22 100644
--- a/src/flash/cfi.h
+++ b/src/flash/cfi.h
@@ -30,10 +30,12 @@ typedef struct cfi_flash_bank_s
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 */
@@ -108,6 +110,8 @@ typedef struct cfi_spansion_pri_ext_s
u8 VppMax;
u8 TopBottom;
int _reversed_geometry;
+ u32 _unlock1;
+ u32 _unlock2;
} cfi_spansion_pri_ext_t;
/* Atmel primary extended query table as defined for and used by
@@ -124,6 +128,17 @@ typedef struct cfi_atmel_pri_ext_s
u8 page_mode;
} cfi_atmel_pri_ext_t;
+enum {
+ CFI_UNLOCK_555_2AA,
+ CFI_UNLOCK_5555_2AAA,
+};
+
+typedef struct cfi_unlock_addresses_s
+{
+ u32 unlock1;
+ u32 unlock2;
+} cfi_unlock_addresses_t;
+
typedef struct cfi_fixup_s
{
u16 mfr;
@@ -135,6 +150,7 @@ typedef struct cfi_fixup_s
#define CFI_MFR_AMD 0x0001
#define CFI_MFR_ATMEL 0x001F
#define CFI_MFR_ST 0x0020 /* STMicroelectronics */
+#define CFI_MFR_SST 0x00BF
#define CFI_MFR_ANY 0xffff
#define CFI_ID_ANY 0xffff
diff --git a/src/flash/flash.c b/src/flash/flash.c
index f5c83f80..6af29825 100644
--- a/src/flash/flash.c
+++ b/src/flash/flash.c
@@ -35,6 +35,7 @@
#include <errno.h>
#include <fileio.h>
+#include <image.h>
/* command handlers */
int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -493,9 +494,7 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
u8 *buffer;
u32 buf_cnt;
- fileio_t file;
- fileio_image_t image_info;
- enum fileio_sec_type sec_type;
+ image_t image;
duration_t duration;
char *duration_text;
@@ -511,7 +510,12 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
duration_start_measure(&duration);
- fileio_identify_image_type(&sec_type, (argc == 4) ? args[3] : NULL);
+ identify_image_type(&image.type, (argc == 4) ? args[3] : NULL);
+
+ image.base_address_set = 1;
+ image.base_address = strtoul(args[1], NULL, 0);
+
+ image.start_address_set = 0;
offset = strtoul(args[2], NULL, 0);
p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
@@ -521,20 +525,16 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
return ERROR_OK;
}
- image_info.base_address = strtoul(args[2], NULL, 0);
- image_info.has_start_address = 0;
-
- if (fileio_open(&file, args[1], FILEIO_READ,
- FILEIO_IMAGE, &image_info, sec_type) != ERROR_OK)
+ if (image_open(&image, args[1], FILEIO_READ) != ERROR_OK)
{
- command_print(cmd_ctx, "flash write error: %s", file.error_str);
+ command_print(cmd_ctx, "flash write error: %s", image.error_str);
return ERROR_OK;
}
- binary_size = file.size;
+ binary_size = image.size;
buffer = malloc(binary_size);
- fileio_read(&file, binary_size, buffer, &buf_cnt);
+ image_read(&image, binary_size, buffer, &buf_cnt);
if ((retval = p->driver->write(p, buffer, offset, buf_cnt)) != ERROR_OK)
{
@@ -571,12 +571,12 @@ int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, cha
{
duration_stop_measure(&duration, &duration_text);
command_print(cmd_ctx, "wrote file %s to flash bank %i at offset 0x%8.8x in %s",
- file.url, strtoul(args[0], NULL, 0), offset, duration_text);
+ args[1], strtoul(args[0], NULL, 0), offset, duration_text);
free(duration_text);
}
free(buffer);
- fileio_close(&file);
+ image_close(&image);
return ERROR_OK;
}
diff --git a/src/flash/nand.c b/src/flash/nand.c
index e0dfa22f..38a70749 100644
--- a/src/flash/nand.c
+++ b/src/flash/nand.c
@@ -38,6 +38,7 @@
#include "flash.h"
#include "time_support.h"
#include "fileio.h"
+#include "image.h"
int nand_register_commands(struct command_context_s *cmd_ctx);
int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -1163,10 +1164,8 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
u32 buf_cnt;
enum oob_formats oob_format = NAND_OOB_NONE;
- fileio_t file;
- fileio_image_t image_info;
- int sec_type_identified = 0;
- enum fileio_sec_type sec_type;
+ image_t image;
+ int image_type_identified = 0;
duration_t duration;
char *duration_text;
@@ -1201,9 +1200,9 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
else
{
- if (fileio_identify_image_type(&sec_type, args[i]) == ERROR_OK)
+ if (identify_image_type(&image.type, args[i]) == ERROR_OK)
{
- sec_type_identified = 1;
+ image_type_identified = 1;
}
else
{
@@ -1214,27 +1213,27 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
}
/* if no image type option was encountered, set the default */
- if (!sec_type_identified)
+ if (!image_type_identified)
{
- fileio_identify_image_type(&sec_type, NULL);
- sec_type_identified = 1;
+ identify_image_type(&image.type, NULL);
+ image_type_identified = 1;
}
- image_info.base_address = strtoul(args[2], NULL, 0);
- image_info.has_start_address = 0;
+ image.base_address_set = 1;
+ image.base_address = strtoul(args[2], NULL, 0);
+ image.start_address_set = 0;
- if (fileio_open(&file, args[1], FILEIO_READ,
- FILEIO_IMAGE, &image_info, sec_type) != ERROR_OK)
+ if (image_open(&image, args[1], FILEIO_READ) != ERROR_OK)
{
- command_print(cmd_ctx, "flash write error: %s", file.error_str);
+ command_print(cmd_ctx, "flash write error: %s", image.error_str);
return ERROR_OK;
}
/* the offset might have been overwritten by the image base address */
- offset = image_info.base_address;
+ offset = image.base_address;
- buf_cnt = binary_size = file.size;
+ buf_cnt = binary_size = image.size;
if (!(oob_format & NAND_OOB_ONLY))
{
@@ -1263,7 +1262,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
if (page)
{
- fileio_read(&file, page_size, page, &size_read);
+ image_read(&image, page_size, page, &size_read);
buf_cnt -= size_read;
if (size_read < page_size)
{
@@ -1273,7 +1272,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
if (oob)
{
- fileio_read(&file, oob_size, oob, &size_read);
+ image_read(&image, oob_size, oob, &size_read);
buf_cnt -= size_read;
if (size_read < oob_size)
{
@@ -1284,7 +1283,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
if (nand_write_page(p, offset / p->page_size, page, page_size, oob, oob_size) != ERROR_OK)
{
command_print(cmd_ctx, "failed writing file %s to NAND flash %s at offset 0x%8.8x",
- file.url, args[0], offset);
+ args[1], args[0], offset);
return ERROR_OK;
}
offset += page_size;
@@ -1292,7 +1291,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
duration_stop_measure(&duration, &duration_text);
command_print(cmd_ctx, "wrote file %s to NAND flash %s at offset 0x%8.8x in %s",
- file.url, args[0], image_info.base_address, duration_text);
+ args[1], args[0], image.base_address, duration_text);
free(duration_text);
}
else
@@ -1318,8 +1317,7 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
{
if (p->device)
{
- fileio_t file;
- fileio_image_t image_info;
+ fileio_t fileio;
duration_t duration;
char *duration_text;
int retval;
@@ -1367,14 +1365,10 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
oob_size = 64;
oob = malloc(oob_size);
}
-
- image_info.base_address = address;
- image_info.has_start_address = 0;
- if (fileio_open(&file, args[1], FILEIO_WRITE,
- FILEIO_IMAGE, &image_info, FILEIO_PLAIN) != ERROR_OK)
+ if (fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
{
- command_print(cmd_ctx, "dump_image error: %s", file.error_str);
+ command_print(cmd_ctx, "dump_image error: %s", fileio.error_str);
return ERROR_OK;
}
@@ -1391,13 +1385,13 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
if (page)
{
- fileio_write(&file, page_size, page, &size_written);
+ fileio_write(&fileio, page_size, page, &size_written);
bytes_done += page_size;
}
if (oob)
{
- fileio_write(&file, oob_size, oob, &size_written);
+ fileio_write(&fileio, oob_size, oob, &size_written);
bytes_done += oob_size;
}
@@ -1411,10 +1405,10 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
if (oob)
free(oob);
- fileio_close(&file);
+ fileio_close(&fileio);
duration_stop_measure(&duration, &duration_text);
- command_print(cmd_ctx, "dumped %lli byte in %s", file.size, duration_text);
+ command_print(cmd_ctx, "dumped %lli byte in %s", fileio.size, duration_text);
free(duration_text);
}
else
diff --git a/src/flash/non_cfi.c b/src/flash/non_cfi.c
new file mode 100644
index 00000000..3a74ff92
--- /dev/null
+++ b/src/flash/non_cfi.c
@@ -0,0 +1,175 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "log.h"
+
+#include "flash.h"
+#include "cfi.h"
+#include "non_cfi.h"
+
+/* non-CFI compatible flashes */
+non_cfi_t non_cfi_flashes[] = {
+ {
+ .mfr = CFI_MFR_SST,
+ .id = 0xd4,
+ .pri_id = 0x02,
+ .dev_size = 0x10,
+ .interface_desc = 0x0,
+ .max_buf_write_size = 0x0,
+ .num_erase_regions = 1,
+ .erase_region_info =
+ {
+ 0x0010000f,
+ 0x00000000
+ }
+ },
+ {
+ .mfr = CFI_MFR_SST,
+ .id = 0xd5,
+ .pri_id = 0x02,
+ .dev_size = 0x11,
+ .interface_desc = 0x0,
+ .max_buf_write_size = 0x0,
+ .num_erase_regions = 1,
+ .erase_region_info =
+ {
+ 0x0010001f,
+ 0x00000000
+ }
+ },
+ {
+ .mfr = CFI_MFR_SST,
+ .id = 0xd6,
+ .pri_id = 0x02,
+ .dev_size = 0x12,
+ .interface_desc = 0x0,
+ .max_buf_write_size = 0x0,
+ .num_erase_regions = 1,
+ .erase_region_info =
+ {
+ 0x0010003f,
+ 0x00000000
+ }
+ },
+ {
+ .mfr = CFI_MFR_SST,
+ .id = 0xd7,
+ .pri_id = 0x02,
+ .dev_size = 0x13,
+ .interface_desc = 0x0,
+ .max_buf_write_size = 0x0,
+ .num_erase_regions = 1,
+ .erase_region_info =
+ {
+ 0x0010007f,
+ 0x00000000
+ }
+ },
+ {
+ .mfr = 0,
+ .id = 0,
+ }
+};
+
+void cfi_fixup_non_cfi(flash_bank_t *bank, void *param)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ non_cfi_t *non_cfi = non_cfi_flashes;
+
+ while (non_cfi->mfr)
+ {
+ if ((cfi_info->manufacturer == non_cfi->mfr)
+ && (cfi_info->device_id == non_cfi->id))
+ {
+ break;
+ }
+ non_cfi++;
+ }
+
+ cfi_info->not_cfi = 1;
+
+ /* fill in defaults for non-critical data */
+ cfi_info->vcc_min = 0x0;
+ cfi_info->vcc_max = 0x0;
+ cfi_info->vpp_min = 0x0;
+ cfi_info->vpp_max = 0x0;
+ cfi_info->word_write_timeout_typ = 0x0;
+ cfi_info->buf_write_timeout_typ = 0x0;
+ cfi_info->block_erase_timeout_typ = 0x0;
+ cfi_info->chip_erase_timeout_typ = 0x0;
+ cfi_info->word_write_timeout_max = 0x0;
+ cfi_info->buf_write_timeout_max = 0x0;
+ cfi_info->block_erase_timeout_max = 0x0;
+ cfi_info->chip_erase_timeout_max = 0x0;
+
+ cfi_info->qry[0] = 'Q';
+ cfi_info->qry[1] = 'R';
+ cfi_info->qry[2] = 'Y';
+
+ cfi_info->pri_id = non_cfi->pri_id;
+ cfi_info->pri_addr = 0x0;
+ cfi_info->alt_id = 0x0;
+ cfi_info->alt_addr = 0x0;
+ cfi_info->alt_ext = NULL;
+
+ cfi_info->interface_desc = non_cfi->interface_desc;
+ cfi_info->max_buf_write_size = non_cfi->max_buf_write_size;
+ cfi_info->num_erase_regions = non_cfi->num_erase_regions;
+ cfi_info->erase_region_info = non_cfi->erase_region_info;
+
+ if (cfi_info->pri_id == 0x2)
+ {
+ cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t));
+
+ pri_ext->pri[0] = 'P';
+ pri_ext->pri[1] = 'R';
+ pri_ext->pri[2] = 'I';
+
+ pri_ext->major_version = '1';
+ pri_ext->minor_version = '0';
+
+ pri_ext->SiliconRevision = 0x0;
+ pri_ext->EraseSuspend = 0x0;
+ pri_ext->EraseSuspend = 0x0;
+ pri_ext->BlkProt = 0x0;
+ pri_ext->TmpBlkUnprotect = 0x0;
+ pri_ext->BlkProtUnprot = 0x0;
+ pri_ext->SimultaneousOps = 0x0;
+ pri_ext->BurstMode = 0x0;
+ pri_ext->PageMode = 0x0;
+ pri_ext->VppMin = 0x0;
+ pri_ext->VppMax = 0x0;
+ pri_ext->TopBottom = 0x0;
+
+ pri_ext->_reversed_geometry = 0;
+
+ cfi_info->pri_ext = pri_ext;
+ } else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3))
+ {
+ ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported");
+ exit(-1);
+ }
+}
+
diff --git a/src/flash/non_cfi.h b/src/flash/non_cfi.h
new file mode 100644
index 00000000..e91b2098
--- /dev/null
+++ b/src/flash/non_cfi.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef NON_CFI_H
+#define NON_CFI_H
+
+#include "types.h"
+
+typedef struct non_cfi_s
+{
+ u16 mfr;
+ u16 id;
+ u16 pri_id;
+ u8 dev_size;
+ u16 interface_desc;
+ u16 max_buf_write_size;
+ u8 num_erase_regions;
+ u32 erase_region_info[6];
+} non_cfi_t;
+
+extern non_cfi_t non_cfi_flashes[];
+extern void cfi_fixup_non_cfi(flash_bank_t *bank, void *param);
+
+#endif /* NON_CFI_H */
+