+ target_free_working_area(target, write_algorithm);
+
+ 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]);
+
+ return retval;
+}
+
+static int cfi_spansion_write_block_mips(struct flash_bank *bank, 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];
+ struct mips32_algorithm mips32_info;
+ struct working_area *write_algorithm;
+ struct working_area *source;
+ uint32_t buffer_size = 32768;
+ uint32_t status;
+ int retval = ERROR_OK;
+
+ /* input parameters -
+ * 4 A0 = source address
+ * 5 A1 = destination address
+ * 6 A2 = number of writes
+ * 7 A3 = flash write command
+ * 8 T0 = constant to mask DQ7 bits (also used for Dq5 with shift)
+ * output parameters -
+ * 9 T1 = 0x80 ok 0x00 bad
+ * temp registers -
+ * 10 T2 = value read from flash to test status
+ * 11 T3 = holding register
+ * unlock registers -
+ * 12 T4 = unlock1_addr
+ * 13 T5 = unlock1_cmd
+ * 14 T6 = unlock2_addr
+ * 15 T7 = unlock2_cmd */
+
+ static const uint32_t mips_word_16_code[] = {
+ /* start: */
+ MIPS32_LHU(9, 0, 4), /* lhu $t1, ($a0) ; out = &saddr */
+ MIPS32_ADDI(4, 4, 2), /* addi $a0, $a0, 2 ; saddr += 2 */
+ MIPS32_SH(13, 0, 12), /* sh $t5, ($t4) ; *fl_unl_addr1 = fl_unl_cmd1 */
+ MIPS32_SH(15, 0, 14), /* sh $t7, ($t6) ; *fl_unl_addr2 = fl_unl_cmd2 */
+ MIPS32_SH(7, 0, 12), /* sh $a3, ($t4) ; *fl_unl_addr1 = fl_write_cmd */
+ MIPS32_SH(9, 0, 5), /* sh $t1, ($a1) ; *daddr = out */
+ MIPS32_NOP, /* nop */
+ /* busy: */
+ MIPS32_LHU(10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */
+ MIPS32_XOR(11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */
+ MIPS32_AND(11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */
+ MIPS32_BNE(11, 8, 13), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */
+ MIPS32_NOP, /* nop */
+
+ MIPS32_SRL(10, 8, 2), /* srl $t2,$t0,2 ; temp1 = DQ7mask >> 2 */
+ MIPS32_AND(11, 10, 11), /* and $t3, $t2, $t3 ; temp2 = temp2 & temp1 */
+ MIPS32_BNE(11, 10, NEG16(8)), /* bne $t3, $t2, busy ; if (temp2 != temp1) goto busy */
+ MIPS32_NOP, /* nop */
+
+ MIPS32_LHU(10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */
+ MIPS32_XOR(11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */
+ MIPS32_AND(11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */
+ MIPS32_BNE(11, 8, 4), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */
+ MIPS32_NOP, /* nop */
+
+ MIPS32_XOR(9, 9, 9), /* xor $t1, $t1, $t1 ; out = 0 */
+ MIPS32_BEQ(9, 0, 11), /* beq $t1, $zero, done ; if (out == 0) goto done */
+ MIPS32_NOP, /* nop */
+ /* cont: */
+ MIPS32_ADDI(6, 6, NEG16(1)), /* addi, $a2, $a2, -1 ; numwrites-- */
+ MIPS32_BNE(6, 0, 5), /* bne $a2, $zero, cont2 ; if (numwrite != 0) goto cont2 */
+ MIPS32_NOP, /* nop */
+
+ MIPS32_LUI(9, 0), /* lui $t1, 0 */
+ MIPS32_ORI(9, 9, 0x80), /* ori $t1, $t1, 0x80 ; out = 0x80 */
+
+ MIPS32_B(4), /* b done ; goto done */
+ MIPS32_NOP, /* nop */
+ /* cont2: */
+ MIPS32_ADDI(5, 5, 2), /* addi $a0, $a0, 2 ; daddr += 2 */
+ MIPS32_B(NEG16(33)), /* b start ; goto start */
+ MIPS32_NOP, /* nop */
+ /* done: */
+ MIPS32_SDBBP, /* sdbbp ; break(); */
+ };
+
+ mips32_info.common_magic = MIPS32_COMMON_MAGIC;
+ mips32_info.isa_mode = MIPS32_ISA_MIPS32;
+
+ int target_code_size = 0;
+ const uint32_t *target_code_src = NULL;
+
+ switch (bank->bus_width) {
+ case 2:
+ /* Check for DQ5 support */
+ if (cfi_info->status_poll_mask & (1 << 5)) {
+ target_code_src = mips_word_16_code;
+ target_code_size = sizeof(mips_word_16_code);
+ } else {
+ LOG_ERROR("Need DQ5 support");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ /* target_code_src = mips_word_16_code_dq7only; */
+ /* target_code_size = sizeof(mips_word_16_code_dq7only); */
+ }
+ break;
+ default:
+ LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes",
+ bank->bus_width);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;