armv4_5_info.core_state = ARMV4_5_STATE_ARM;
/* If we are setting up the write_algorith, we need target_code_src */
- /* if not we only need target_code_size. */
- /* */
- /* However, we don't want to create multiple code paths, so we */
- /* do the unecessary evaluation of target_code_src, which the */
- /* compiler will probably nicely optimize away if not needed */
+ /* if not we only need target_code_size. */
+
+ /* However, we don't want to create multiple code paths, so we */
+ /* do the unecessary evaluation of target_code_src, which the */
+ /* compiler will probably nicely optimize away if not needed */
/* prepare algorithm code for target endian */
switch (bank->bus_width)
0xeafffffe /* b 81ac <sp_16_done> */
};
+ static const uint32_t word_16_code_dq7only[] = {
+ /* <sp_16_code>: */
+ 0xe0d050b2, /* ldrh r5, [r0], #2 */
+ 0xe1c890b0, /* strh r9, [r8] */
+ 0xe1cab0b0, /* strh r11, [r10] */
+ 0xe1c830b0, /* strh r3, [r8] */
+ 0xe1c150b0, /* strh r5, [r1] */
+ 0xe1a00000, /* nop (mov r0,r0) */
+ /* */
+ /* <sp_16_busy>: */
+ 0xe1d160b0, /* ldrh r6, [r1] */
+ 0xe0257006, /* eor r7, r5, r6 */
+ 0xe2177080, /* ands r7, #0x80 */
+ 0x1afffffb, /* bne 8168 <sp_16_busy> */
+ /* */
+ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */
+ 0x03a05080, /* moveq r5, #128 ; 0x80 */
+ 0x0a000001, /* beq 81ac <sp_16_done> */
+ 0xe2811002, /* add r1, r1, #2 ; 0x2 */
+ 0xeafffff0, /* b 8158 <sp_16_code> */
+ /* */
+ /* 000081ac <sp_16_done>: */
+ 0xeafffffe /* b 81ac <sp_16_done> */
+ };
+
static const uint32_t word_8_code[] = {
/* 000081b0 <sp_16_code_end>: */
0xe4d05001, /* ldrb r5, [r0], #1 */
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+ int target_code_size;
+ const uint32_t *target_code_src;
+
+ switch (bank->bus_width)
+ {
+ case 1 :
+ target_code_src = word_8_code;
+ target_code_size = sizeof(word_8_code);
+ break;
+ case 2 :
+ /* Check for DQ5 support */
+ if( cfi_info->status_poll_mask & (1 << 5) )
+ {
+ target_code_src = word_16_code;
+ target_code_size = sizeof(word_16_code);
+ }
+ else
+ {
+ /* No DQ5 support. Use DQ7 DATA# polling only. */
+ target_code_src = word_16_code_dq7only;
+ target_code_size = sizeof(word_16_code_dq7only);
+ }
+ break;
+ case 4 :
+ target_code_src = word_32_code;
+ target_code_size = sizeof(word_32_code);
+ break;
+ default:
+ LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
/* flash write code */
if (!cfi_info->write_algorithm)
{
uint8_t *target_code;
- int target_code_size;
- const uint32_t *src;
/* convert bus-width dependent algorithm code to correct endiannes */
- switch (bank->bus_width)
- {
- case 1:
- src = word_8_code;
- target_code_size = sizeof(word_8_code);
- break;
- case 2:
- src = word_16_code;
- target_code_size = sizeof(word_16_code);
- break;
- case 4:
- src = word_32_code;
- target_code_size = sizeof(word_32_code);
- break;
- default:
- LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
- return ERROR_FLASH_OPERATION_FAILED;
- }
target_code = malloc(target_code_size);
- cfi_fix_code_endian(target, target_code, src, target_code_size / 4);
+ cfi_fix_code_endian(target, target_code, target_code_src, target_code_size / 4);
/* allocate working area */
retval = target_alloc_working_area(target, target_code_size,
retval = target_run_algorithm(target, 0, NULL, 10, reg_params,
cfi_info->write_algorithm->address,
- cfi_info->write_algorithm->address + ((24 * 4) - 4),
+ cfi_info->write_algorithm->address + ((target_code_size) - 4),
10000, &armv4_5_info);
status = buf_get_u32(reg_params[5].value, 0, 32);
count -= thisrun_count;
}
- target_free_working_area(target, source);
+ target_free_all_working_areas(target);
destroy_reg_param(®_params[0]);
destroy_reg_param(®_params[1]);
pri_ext->_unlock2 = unlock_addresses->unlock2;
}
+
+static int cfi_query_string(struct flash_bank_s *bank, int address)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = bank->target;
+ int retval;
+ uint8_t command[8];
+
+ cfi_command(bank, 0x98, command);
+ if ((retval = target_write_memory(target, flash_address(bank, 0, address), bank->bus_width, 1, command)) != ERROR_OK)
+ {
+ return retval;
+ }
+
+ 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);
+
+ LOG_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);
+ if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+ {
+ return retval;
+ }
+ cfi_command(bank, 0xff, command);
+ if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+ {
+ return retval;
+ }
+ LOG_ERROR("Could not probe bank: no QRY");
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ return ERROR_OK;
+}
+
static int cfi_probe(struct flash_bank_s *bank)
{
cfi_flash_bank_t *cfi_info = bank->driver_priv;
*/
if (cfi_info->not_cfi == 0)
{
+ int retval;
+
/* enter CFI query mode
* according to JEDEC Standard No. 68.01,
* a single bus sequence with address = 0x55, data = 0x98 should put
*
* SST flashes clearly violate this, and we will consider them incompatbile for now
*/
- cfi_command(bank, 0x98, command);
- if ((retval = target_write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK)
- {
- return retval;
- }
- 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);
-
- LOG_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'))
+ retval = cfi_query_string(bank, 0x55);
+ if (retval != ERROR_OK)
{
- cfi_command(bank, 0xf0, command);
- if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
- {
- return retval;
- }
- cfi_command(bank, 0xff, command);
- if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
- {
- return retval;
- }
- LOG_ERROR("Could not probe bank: no QRY");
- return ERROR_FLASH_BANK_INVALID;
+ /*
+ * Spansion S29WS-N CFI query fix is to try 0x555 if 0x55 fails. Should
+ * be harmless enough:
+ *
+ * http://www.infradead.org/pipermail/linux-mtd/2005-September/013618.html
+ */
+ LOG_USER("Try workaround w/0x555 instead of 0x55 to get QRY.");
+ retval = cfi_query_string(bank, 0x555);
}
+ if (retval != ERROR_OK)
+ return retval;
cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);