+ buffer += thisrun_count;
+ address += thisrun_count;
+ count -= thisrun_count;
+ }
+
+ target_free_all_working_areas(target);
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+ destroy_reg_param(®_params[4]);
+ destroy_reg_param(®_params[5]);
+ destroy_reg_param(®_params[6]);
+ destroy_reg_param(®_params[7]);
+ destroy_reg_param(®_params[8]);
+ destroy_reg_param(®_params[9]);
+
+ return retval;
+}
+
+static int cfi_spansion_write_block(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t address, uint32_t count)
+{
+ struct cfi_flash_bank *cfi_info = bank->driver_priv;
+ struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
+ struct target *target = bank->target;
+ struct reg_param reg_params[10];
+ void *arm_algo;
+ struct arm_algorithm armv4_5_algo;
+ struct armv7m_algorithm armv7m_algo;
+ struct working_area *write_algorithm;
+ struct working_area *source;
+ uint32_t buffer_size = 32768;
+ uint32_t status;
+ int retval = ERROR_OK;
+
+ /* input parameters -
+ * R0 = source address
+ * R1 = destination address
+ * R2 = number of writes
+ * R3 = flash write command
+ * R4 = constant to mask DQ7 bits (also used for Dq5 with shift)
+ * output parameters -
+ * R5 = 0x80 ok 0x00 bad
+ * temp registers -
+ * R6 = value read from flash to test status
+ * R7 = holding register
+ * unlock registers -
+ * R8 = unlock1_addr
+ * R9 = unlock1_cmd
+ * R10 = unlock2_addr
+ * R11 = unlock2_cmd */
+
+ /* see contib/loaders/flash/armv4_5_cfi_span_32.s for src */
+ static const uint32_t armv4_5_word_32_code[] = {
+ /* 00008100 <sp_32_code>: */
+ 0xe4905004, /* ldr r5, [r0], #4 */
+ 0xe5889000, /* str r9, [r8] */
+ 0xe58ab000, /* str r11, [r10] */
+ 0xe5883000, /* str r3, [r8] */
+ 0xe5815000, /* str r5, [r1] */
+ 0xe1a00000, /* nop */
+ /* 00008110 <sp_32_busy>: */
+ 0xe5916000, /* ldr r6, [r1] */
+ 0xe0257006, /* eor r7, r5, r6 */
+ 0xe0147007, /* ands r7, r4, r7 */
+ 0x0a000007, /* beq 8140 <sp_32_cont> ; b if DQ7 == Data7 */
+ 0xe0166124, /* ands r6, r6, r4, lsr #2 */
+ 0x0afffff9, /* beq 8110 <sp_32_busy> ; b if DQ5 low */
+ 0xe5916000, /* ldr r6, [r1] */
+ 0xe0257006, /* eor r7, r5, r6 */
+ 0xe0147007, /* ands r7, r4, r7 */
+ 0x0a000001, /* beq 8140 <sp_32_cont> ; b if DQ7 == Data7 */
+ 0xe3a05000, /* mov r5, #0 ; 0x0 - return 0x00, error */
+ 0x1a000004, /* bne 8154 <sp_32_done> */
+ /* 00008140 <sp_32_cont>: */
+ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */
+ 0x03a05080, /* moveq r5, #128 ; 0x80 */
+ 0x0a000001, /* beq 8154 <sp_32_done> */
+ 0xe2811004, /* add r1, r1, #4 ; 0x4 */
+ 0xeaffffe8, /* b 8100 <sp_32_code> */
+ /* 00008154 <sp_32_done>: */
+ 0xeafffffe /* b 8154 <sp_32_done> */
+ };
+
+ /* see contib/loaders/flash/armv4_5_cfi_span_16.s for src */
+ static const uint32_t armv4_5_word_16_code[] = {
+ /* 00008158 <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) */
+ /* 00008168 <sp_16_busy>: */
+ 0xe1d160b0, /* ldrh r6, [r1] */
+ 0xe0257006, /* eor r7, r5, r6 */
+ 0xe0147007, /* ands r7, r4, r7 */
+ 0x0a000007, /* beq 8198 <sp_16_cont> */
+ 0xe0166124, /* ands r6, r6, r4, lsr #2 */
+ 0x0afffff9, /* beq 8168 <sp_16_busy> */
+ 0xe1d160b0, /* ldrh r6, [r1] */
+ 0xe0257006, /* eor r7, r5, r6 */
+ 0xe0147007, /* ands r7, r4, r7 */
+ 0x0a000001, /* beq 8198 <sp_16_cont> */
+ 0xe3a05000, /* mov r5, #0 ; 0x0 */
+ 0x1a000004, /* bne 81ac <sp_16_done> */
+ /* 00008198 <sp_16_cont>: */
+ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */
+ 0x03a05080, /* moveq r5, #128 ; 0x80 */
+ 0x0a000001, /* beq 81ac <sp_16_done> */
+ 0xe2811002, /* add r1, r1, #2 ; 0x2 */
+ 0xeaffffe8, /* b 8158 <sp_16_code> */
+ /* 000081ac <sp_16_done>: */
+ 0xeafffffe /* b 81ac <sp_16_done> */
+ };
+
+ /* see contrib/loaders/flash/armv7m_cfi_span_16.s for src */
+ static const uint32_t armv7m_word_16_code[] = {
+ 0x5B02F830,
+ 0x9000F8A8,
+ 0xB000F8AA,
+ 0x3000F8A8,
+ 0xBF00800D,
+ 0xEA85880E,
+ 0x40270706,
+ 0xEA16D00A,
+ 0xD0F70694,
+ 0xEA85880E,
+ 0x40270706,
+ 0xF04FD002,
+ 0xD1070500,
+ 0xD0023A01,
+ 0x0102F101,
+ 0xF04FE7E0,
+ 0xE7FF0580,
+ 0x0000BE00
+ };
+
+ /* see contrib/loaders/flash/armv7m_cfi_span_16_dq7.s for src */
+ static const uint32_t armv7m_word_16_code_dq7only[] = {
+ /* 00000000 <code>: */
+ 0x5B02F830, /* ldrh.w r5, [r0], #2 */
+ 0x9000F8A8, /* strh.w r9, [r8] */
+ 0xB000F8AA, /* strh.w fp, [sl] */
+ 0x3000F8A8, /* strh.w r3, [r8] */
+ 0xBF00800D, /* strh r5, [r1, #0] */
+ /* nop */
+
+ /* 00000014 <busy>: */
+ 0xEA85880E, /* ldrh r6, [r1, #0] */
+ /* eor.w r7, r5, r6 */
+ 0x40270706, /* ands r7, r4 */
+ 0x3A01D1FA, /* bne.n 14 <busy> */
+ /* subs r2, #1 */
+ 0xF101D002, /* beq.n 28 <success> */
+ 0xE7EB0102, /* add.w r1, r1, #2 */
+ /* b.n 0 <code> */
+
+ /* 00000028 <success>: */
+ 0x0580F04F, /* mov.w r5, #128 */
+ 0xBF00E7FF, /* b.n 30 <done> */
+ /* nop (for alignment purposes) */
+
+ /* 00000030 <done>: */
+ 0x0000BE00 /* bkpt 0x0000 */
+ };
+
+ /* see contrib/loaders/flash/armv4_5_cfi_span_16_dq7.s for src */
+ static const uint32_t armv4_5_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> */
+ };
+
+ /* see contrib/loaders/flash/armv4_5_cfi_span_8.s for src */
+ static const uint32_t armv4_5_word_8_code[] = {
+ /* 000081b0 <sp_16_code_end>: */
+ 0xe4d05001, /* ldrb r5, [r0], #1 */
+ 0xe5c89000, /* strb r9, [r8] */
+ 0xe5cab000, /* strb r11, [r10] */
+ 0xe5c83000, /* strb r3, [r8] */
+ 0xe5c15000, /* strb r5, [r1] */
+ 0xe1a00000, /* nop (mov r0,r0) */
+ /* 000081c0 <sp_8_busy>: */
+ 0xe5d16000, /* ldrb r6, [r1] */
+ 0xe0257006, /* eor r7, r5, r6 */
+ 0xe0147007, /* ands r7, r4, r7 */
+ 0x0a000007, /* beq 81f0 <sp_8_cont> */
+ 0xe0166124, /* ands r6, r6, r4, lsr #2 */
+ 0x0afffff9, /* beq 81c0 <sp_8_busy> */
+ 0xe5d16000, /* ldrb r6, [r1] */
+ 0xe0257006, /* eor r7, r5, r6 */
+ 0xe0147007, /* ands r7, r4, r7 */
+ 0x0a000001, /* beq 81f0 <sp_8_cont> */
+ 0xe3a05000, /* mov r5, #0 ; 0x0 */
+ 0x1a000004, /* bne 8204 <sp_8_done> */
+ /* 000081f0 <sp_8_cont>: */
+ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */
+ 0x03a05080, /* moveq r5, #128 ; 0x80 */
+ 0x0a000001, /* beq 8204 <sp_8_done> */
+ 0xe2811001, /* add r1, r1, #1 ; 0x1 */
+ 0xeaffffe8, /* b 81b0 <sp_16_code_end> */
+ /* 00008204 <sp_8_done>: */
+ 0xeafffffe /* b 8204 <sp_8_done> */
+ };
+
+ if (strncmp(target_type_name(target), "mips_m4k", 8) == 0)
+ return cfi_spansion_write_block_mips(bank, buffer, address, count);
+
+ if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
+ armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
+ armv7m_algo.core_mode = ARM_MODE_THREAD;
+ arm_algo = &armv7m_algo;
+ } else if (is_arm(target_to_arm(target))) {
+ /* All other ARM CPUs have 32 bit instructions */
+ armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
+ armv4_5_algo.core_mode = ARM_MODE_SVC;
+ armv4_5_algo.core_state = ARM_STATE_ARM;
+ arm_algo = &armv4_5_algo;
+ } else {
+ LOG_ERROR("Unknown architecture");
+ return ERROR_FAIL;
+ }
+
+ int target_code_size = 0;
+ const uint32_t *target_code_src = NULL;
+
+ switch (bank->bus_width) {
+ case 1:
+ if (is_armv7m(target_to_armv7m(target))) {
+ LOG_ERROR("Unknown ARM architecture");
+ return ERROR_FAIL;
+ }
+ target_code_src = armv4_5_word_8_code;
+ target_code_size = sizeof(armv4_5_word_8_code);
+ break;
+ case 2:
+ /* Check for DQ5 support */
+ if (cfi_info->status_poll_mask & (1 << 5)) {
+ if (is_armv7m(target_to_armv7m(target))) {
+ /* armv7m target */
+ target_code_src = armv7m_word_16_code;
+ target_code_size = sizeof(armv7m_word_16_code);
+ } else { /* armv4_5 target */
+ target_code_src = armv4_5_word_16_code;
+ target_code_size = sizeof(armv4_5_word_16_code);
+ }
+ } else {
+ /* No DQ5 support. Use DQ7 DATA# polling only. */
+ if (is_armv7m(target_to_armv7m(target))) {
+ /* armv7m target */
+ target_code_src = armv7m_word_16_code_dq7only;
+ target_code_size = sizeof(armv7m_word_16_code_dq7only);
+ } else { /* armv4_5 target */
+ target_code_src = armv4_5_word_16_code_dq7only;
+ target_code_size = sizeof(armv4_5_word_16_code_dq7only);
+ }
+ }
+ break;
+ case 4:
+ if (is_armv7m(target_to_armv7m(target))) {
+ LOG_ERROR("Unknown ARM architecture");
+ return ERROR_FAIL;
+ }
+ target_code_src = armv4_5_word_32_code;
+ target_code_size = sizeof(armv4_5_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 */
+ uint8_t *target_code;
+
+ /* convert bus-width dependent algorithm code to correct endianness */
+ target_code = malloc(target_code_size);
+ if (target_code == NULL) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ target_buffer_set_u32_array(target, target_code, target_code_size / 4, target_code_src);
+
+ /* allocate working area */
+ retval = target_alloc_working_area(target, target_code_size,
+ &write_algorithm);
+ if (retval != ERROR_OK) {