+ int retval;
+
+ /* Mark register R1 as dirty, to use for transferring data. */
+ arm_reg_current(arm, 1)->dirty = true;
+
+ /* Switch to non-blocking mode if not already in that mode. */
+ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Go through the objects. */
+ while (count) {
+ /* Write the value to store into DTRRX. */
+ uint32_t data, opcode;
+ if (size == 1)
+ data = *buffer;
+ else if (size == 2)
+ data = target_buffer_get_u16(target, buffer);
+ else
+ data = target_buffer_get_u32(target, buffer);
+ retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
+ armv7a->debug_base + CPUDBG_DTRRX, data);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Transfer the value from DTRRX to R1. */
+ retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Write the value transferred to R1 into memory. */
+ if (size == 1)
+ opcode = ARMV4_5_STRB_IP(1, 0);
+ else if (size == 2)
+ opcode = ARMV4_5_STRH_IP(1, 0);
+ else
+ opcode = ARMV4_5_STRW_IP(1, 0);
+ retval = cortex_a_exec_opcode(target, opcode, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Check for faults and return early. */
+ if (*dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE))
+ return ERROR_OK; /* A data fault is not considered a system failure. */
+
+ /* Wait until DTRRX is empty (according to ARMv7-A/-R architecture
+ * manual section C8.4.3, checking InstrCmpl_l is not sufficient; one
+ * must also check RXfull_l). Most of the time this will be free
+ * because RXfull_l will be cleared immediately and cached in dscr. */
+ retval = cortex_a_wait_dscr_bits(target, DSCR_DTRRX_FULL_LATCHED, 0, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Advance. */
+ buffer += size;
+ --count;
+ }
+
+ return ERROR_OK;
+}
+
+static int cortex_a_write_cpu_memory_fast(struct target *target,
+ uint32_t count, const uint8_t *buffer, uint32_t *dscr)
+{
+ /* Writes count objects of size 4 from *buffer. Old value of DSCR must be
+ * in *dscr; updated to new value. This is fast but only works for
+ * word-sized objects at aligned addresses.
+ * Preconditions:
+ * - Address is in R0 and must be a multiple of 4.
+ * - R0 is marked dirty.
+ */
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ int retval;
+
+ /* Switch to fast mode if not already in that mode. */
+ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_FAST_MODE, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Latch STC instruction. */
+ retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
+ armv7a->debug_base + CPUDBG_ITR, ARMV4_5_STC(0, 1, 0, 1, 14, 5, 0, 4));
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Transfer all the data and issue all the instructions. */
+ return mem_ap_write_buf_noincr(armv7a->debug_ap, buffer,
+ 4, count, armv7a->debug_base + CPUDBG_DTRRX);
+}
+
+static int cortex_a_write_cpu_memory(struct target *target,
+ uint32_t address, uint32_t size,
+ uint32_t count, const uint8_t *buffer)
+{
+ /* Write memory through the CPU. */
+ int retval, final_retval;
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm *arm = &armv7a->arm;
+ uint32_t dscr, orig_dfar, orig_dfsr, fault_dscr, fault_dfar, fault_dfsr;
+
+ LOG_DEBUG("Writing CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32,
+ address, size, count);