+ /* 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;