+
+ /* make sure we have a working area */
+ if (target_alloc_working_area(target, ((sizeof(erase_check_code)+3)/4)*4, &erase_check_algorithm) != ERROR_OK)
+ {
+ erase_check_algorithm = NULL;
+ }
+
+ if (erase_check_algorithm)
+ {
+ u8 erase_check_code_buf[((sizeof(erase_check_code)+3)/4)*4];
+ LOG_DEBUG("Running fast flash erase check");
+
+ for (i = 0; i < sizeof(erase_check_code)/sizeof(*erase_check_code); i++)
+ target_buffer_set_u16(target, erase_check_code_buf + (i*2), erase_check_code[i]);
+
+ /* write algorithm code to working area */
+ if ((retval=target->type->write_memory(target, erase_check_algorithm->address, 2, sizeof(erase_check_code)/sizeof(*erase_check_code), erase_check_code_buf))==ERROR_OK)
+ {
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ u32 address = bank->base + bank->sectors[i].offset;
+ u32 size = bank->sectors[i].size;
+
+ reg_param_t reg_params[3];
+ armv7m_algorithm_t arm_info;
+
+ arm_info.common_magic = ARMV7M_COMMON_MAGIC;
+ arm_info.core_mode = ARMV7M_MODE_ANY;
+ arm_info.core_state = ARMV7M_STATE_THUMB;
+
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
+ buf_set_u32(reg_params[0].value, 0, 32, address);
+
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ buf_set_u32(reg_params[1].value, 0, 32, size);
+
+ init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[2].value, 0, 32, 0xff);
+
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address,
+ erase_check_algorithm->address + sizeof(erase_check_code) - 2, 10000, &arm_info)) != ERROR_OK)
+ break;
+
+ if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff)
+ bank->sectors[i].is_erased = 1;
+ else
+ bank->sectors[i].is_erased = 0;
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ }
+ if (i == bank->num_sectors)
+ {
+ fast_check = 1;
+ }
+ }
+ target_free_working_area(target, erase_check_algorithm);
+ }
+#endif
+ if (!fast_check)
+ {
+ /* try ARM7 instead */
+
+ u32 erase_check_code[] =
+ {
+ 0xe4d03001, /* ldrb r3, [r0], #1 */
+ 0xe0022003, /* and r2, r2, r3 */
+ 0xe2511001, /* subs r1, r1, #1 */
+ 0x1afffffb, /* b -4 */
+ 0xeafffffe /* b 0 */
+ };
+
+ /* make sure we have a working area */
+ if (target_alloc_working_area(target, 20, &erase_check_algorithm) == ERROR_OK)
+ {
+ u8 erase_check_code_buf[5 * 4];
+
+ for (i = 0; i < 5; i++)
+ target_buffer_set_u32(target, erase_check_code_buf + (i*4), erase_check_code[i]);
+
+ /* write algorithm code to working area */
+ if ((retval=target->type->write_memory(target, erase_check_algorithm->address, 4, 5, erase_check_code_buf))==ERROR_OK)
+ {
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ u32 address = bank->base + bank->sectors[i].offset;
+ u32 size = bank->sectors[i].size;
+
+ reg_param_t reg_params[3];
+ armv4_5_algorithm_t armv4_5_info;
+
+ armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+ armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+ armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
+ buf_set_u32(reg_params[0].value, 0, 32, address);
+
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ buf_set_u32(reg_params[1].value, 0, 32, size);
+
+ init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[2].value, 0, 32, 0xff);
+
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params,
+ erase_check_algorithm->address, erase_check_algorithm->address + 0x10, 10000, &armv4_5_info)) != ERROR_OK)
+ break;
+
+ if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff)
+ bank->sectors[i].is_erased = 1;
+ else
+ bank->sectors[i].is_erased = 0;
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ }
+ if (i == bank->num_sectors)
+ {
+ fast_check = 1;
+ }
+ }
+ target_free_working_area(target, erase_check_algorithm);
+ }
+ }
+
+
+ if (!fast_check)
+ {
+ LOG_USER("Running slow fallback erase check - add working memory");
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ int j;
+ bank->sectors[i].is_erased = 1;
+
+ for (j=0; j<bank->sectors[i].size; j+=buffer_size)
+ {
+ int chunk;
+ int retval;
+ chunk=buffer_size;
+ if (chunk>(j-bank->sectors[i].size))
+ {
+ chunk=(j-bank->sectors[i].size);
+ }
+
+ retval=target->type->read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer);
+ if (retval!=ERROR_OK)
+ return retval;
+
+ for (nBytes = 0; nBytes < chunk; nBytes++)
+ {
+ if (buffer[nBytes] != 0xFF)
+ {
+ bank->sectors[i].is_erased = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ERROR_OK;
+}