static int str9x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 32768; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct arm_algorithm arm_algo; int retval = ERROR_OK; /* see contib/loaders/flash/str9x.s for src */ static const uint32_t str9x_flash_write_code[] = { /* write: */ 0xe3c14003, /* bic r4, r1, #3 */ 0xe3a03040, /* mov r3, #0x40 */ 0xe1c430b0, /* strh r3, [r4, #0] */ 0xe0d030b2, /* ldrh r3, [r0], #2 */ 0xe0c130b2, /* strh r3, [r1], #2 */ 0xe3a03070, /* mov r3, #0x70 */ 0xe1c430b0, /* strh r3, [r4, #0] */ /* busy: */ 0xe5d43000, /* ldrb r3, [r4, #0] */ 0xe3130080, /* tst r3, #0x80 */ 0x0afffffc, /* beq busy */ 0xe3a05050, /* mov r5, #0x50 */ 0xe1c450b0, /* strh r5, [r4, #0] */ 0xe3a050ff, /* mov r5, #0xFF */ 0xe1c450b0, /* strh r5, [r4, #0] */ 0xe3130012, /* tst r3, #0x12 */ 0x1a000001, /* bne exit */ 0xe2522001, /* subs r2, r2, #1 */ 0x1affffed, /* bne write */ /* exit: */ 0xe1200070, /* bkpt #0 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(str9x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; uint8_t code[sizeof(str9x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(str9x_flash_write_code), str9x_flash_write_code); target_write_buffer(target, write_algorithm->address, sizeof(code), code); /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; target_write_buffer(target, source->address, thisrun_count * 2, buffer); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); retval = target_run_algorithm(target, 0, NULL, 4, reg_params, write_algorithm->address, 0, 10000, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing str9x flash write algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80) { retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); 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]); return retval; }
static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contib/loaders/flash/stm32x.s for src */ static const uint8_t stm32x_flash_write_code[] = { /* #define STM32_FLASH_CR_OFFSET 0x10 */ /* #define STM32_FLASH_SR_OFFSET 0x0C */ /* write: */ 0x08, 0x4c, /* ldr r4, STM32_FLASH_BASE */ 0x1c, 0x44, /* add r4, r3 */ /* write_half_word: */ 0x01, 0x23, /* movs r3, #0x01 */ 0x23, 0x61, /* str r3, [r4, #STM32_FLASH_CR_OFFSET] */ 0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */ 0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */ /* busy: */ 0xe3, 0x68, /* ldr r3, [r4, #STM32_FLASH_SR_OFFSET] */ 0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */ 0xfb, 0xd0, /* beq busy */ 0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */ 0x01, 0xd1, /* bne exit */ 0x01, 0x3a, /* subs r2, r2, #0x01 */ 0xf0, 0xd1, /* bne write_half_word */ /* exit: */ 0x00, 0xbe, /* bkpt #0x00 */ 0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &stm32x_info->write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), (uint8_t*)stm32x_flash_write_code)) != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* if we already allocated the writing code, but failed to get a * buffer, free the algorithm */ if (stm32x_info->write_algorithm) target_free_working_area(target, stm32x_info->write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; if ((retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer)) != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); buf_set_u32(reg_params[3].value, 0, 32, stm32x_info->register_offset); if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, 0, 10000, &armv7m_info)) != ERROR_OK) { LOG_ERROR("error executing stm32x flash write algorithm"); break; } if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR) { LOG_ERROR("flash memory not erased before writing"); /* Clear but report errors */ target_write_u32(target, STM32_FLASH_SR, FLASH_PGERR); retval = ERROR_FAIL; break; } if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR) { LOG_ERROR("flash memory write protected"); /* Clear but report errors */ target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR); retval = ERROR_FAIL; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, stm32x_info->write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; }
static int str7x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct str7x_flash_bank *str7x_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 32768; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct arm_algorithm arm_algo; int retval = ERROR_OK; /* see contib/loaders/flash/str7x.s for src */ static const uint32_t str7x_flash_write_code[] = { /* write: */ 0xe3a04201, /* mov r4, #0x10000000 */ 0xe5824000, /* str r4, [r2, #0x0] */ 0xe5821010, /* str r1, [r2, #0x10] */ 0xe4904004, /* ldr r4, [r0], #4 */ 0xe5824008, /* str r4, [r2, #0x8] */ 0xe4904004, /* ldr r4, [r0], #4 */ 0xe582400c, /* str r4, [r2, #0xc] */ 0xe3a04209, /* mov r4, #0x90000000 */ 0xe5824000, /* str r4, [r2, #0x0] */ /* busy: */ 0xe5924000, /* ldr r4, [r2, #0x0] */ 0xe1140005, /* tst r4, r5 */ 0x1afffffc, /* bne busy */ 0xe5924014, /* ldr r4, [r2, #0x14] */ 0xe31400ff, /* tst r4, #0xff */ 0x03140c01, /* tsteq r4, #0x100 */ 0x1a000002, /* bne exit */ 0xe2811008, /* add r1, r1, #0x8 */ 0xe2533001, /* subs r3, r3, #1 */ 0x1affffec, /* bne write */ /* exit: */ 0xeafffffe, /* b exit */ }; /* flash write code */ if (target_alloc_working_area_try(target, sizeof(str7x_flash_write_code), &write_algorithm) != ERROR_OK) { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } uint8_t code[sizeof(str7x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(str7x_flash_write_code), str7x_flash_write_code); target_write_buffer(target, write_algorithm->address, sizeof(code), code); /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_IN); init_reg_param(®_params[5], "r5", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count; target_write_buffer(target, source->address, thisrun_count * 8, buffer); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0)); buf_set_u32(reg_params[3].value, 0, 32, thisrun_count); buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits); retval = target_run_algorithm(target, 0, NULL, 6, reg_params, write_algorithm->address, write_algorithm->address + (sizeof(str7x_flash_write_code) - 4), 10000, &arm_algo); if (retval != ERROR_OK) break; if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00) { retval = str7x_result(bank); break; } buffer += thisrun_count * 8; address += thisrun_count * 8; count -= thisrun_count; } target_free_working_area(target, source); 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]); return retval; }
/* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall * back to another mechanism that does not require onboard RAM * * Caller should not check for other return values specifically */ static int aduc702x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 7000; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct arm_algorithm arm_algo; int retval = ERROR_OK; if (((count%2) != 0) || ((offset%2) != 0)) { LOG_ERROR("write block must be multiple of two bytes in offset & length"); return ERROR_FAIL; } /* parameters: r0 - address of source data (absolute) r1 - number of halfwords to be copied r2 - start address in flash (offset from beginning of flash memory) r3 - exit code r4 - base address of flash controller (0xFFFFF800) registers: r5 - scratch r6 - set to 2, used to write flash command */ static const uint32_t aduc702x_flash_write_code[] = { /* <_start>: */ 0xe3a05008, /* mov r5, #8 ; 0x8 */ 0xe5845004, /* str r5, [r4, #4] */ 0xe3a06002, /* mov r6, #2 ; 0x2 */ /* <next>: */ 0xe1c421b0, /* strh r2, [r4, #16] */ 0xe0d050b2, /* ldrh r5, [r0], #2 */ 0xe1c450bc, /* strh r5, [r4, #12] */ 0xe5c46008, /* strb r6, [r4, #8] */ /* <wait_complete>: */ 0xe1d430b0, /* ldrh r3, [r4] */ 0xe3130004, /* tst r3, #4 ; 0x4 */ 0x1afffffc, /* bne 1001c <wait_complete> */ 0xe2822002, /* add r2, r2, #2 ; 0x2 */ 0xe2511001, /* subs r1, r1, #1 ; 0x1 */ 0x0a000001, /* beq 1003c <done> */ 0xe3130001, /* tst r3, #1 ; 0x1 */ 0x1afffff3, /* bne 1000c <next> */ /* <done>: */ 0xeafffffe /* b 1003c <done> */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(aduc702x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } uint8_t code[sizeof(aduc702x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(aduc702x_flash_write_code), aduc702x_flash_write_code); retval = target_write_buffer(target, write_algorithm->address, sizeof(code), code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a buffer, *free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; retval = target_write_buffer(target, source->address, thisrun_count, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, thisrun_count/2); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[4].value, 0, 32, 0xFFFFF800); retval = target_run_algorithm(target, 0, NULL, 5, reg_params, write_algorithm->address, write_algorithm->address + sizeof(aduc702x_flash_write_code) - 4, 10000, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing aduc702x flash write algorithm"); break; } if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1) { /* FIX!!!! what does this mean??? replace w/sensible error message */ LOG_ERROR("aduc702x detected error writing flash"); retval = ERROR_FAIL; break; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } target_free_working_area(target, source); 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]); return retval; }
static int stm32lx_write_half_pages(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contib/loaders/flash/stm32lx.S for src */ static const uint8_t stm32lx_flash_write_code[] = { /* write_word: */ 0x00, 0x23, /* movs r3, #0 */ 0x04, 0xe0, /* b test_done */ /* write_word: */ 0x51, 0xf8, 0x04, 0xcb, /* ldr ip, [r1], #4 */ 0x40, 0xf8, 0x04, 0xcb, /* str ip, [r0], #4 */ 0x01, 0x33, /* adds r3, #1 */ /* test_done: */ 0x93, 0x42, /* cmp r3, r2 */ 0xf8, 0xd3, /* bcc write_word */ 0x00, 0xbe, /* bkpt 0 */ }; /* Check if there is an even number of half pages (128bytes) */ if (count % 128) { LOG_ERROR("there should be an even number " "of half pages = 128 bytes (count = %" PRIi32 " bytes)", count); return ERROR_FAIL; } /* flash write code */ if (target_alloc_working_area(target, sizeof(stm32lx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_DEBUG("no working area for block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; /* Write the flashing code */ retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32lx_flash_write_code), (uint8_t *)stm32lx_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* Allocate half pages memory */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { if (buffer_size > 1024) buffer_size -= 1024; else buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* Enable half-page write */ retval = stm32lx_enable_write_half_page(bank); if (retval != ERROR_OK) { target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; } struct armv7m_common *armv7m = target_to_armv7m(target); if (armv7m == NULL) { /* something is very wrong if armv7m is NULL */ LOG_ERROR("unable to get armv7m target"); return retval; } /* save any DEMCR flags and configure target to catch any Hard Faults */ uint32_t demcr_save = armv7m->demcr; armv7m->demcr = VC_HARDERR; /* Loop while there are bytes to write */ while (count > 0) { uint32_t this_count; this_count = (count > buffer_size) ? buffer_size : count; /* Write the next half pages */ retval = target_write_buffer(target, source->address, this_count, buffer); if (retval != ERROR_OK) break; /* 4: Store useful information in the registers */ /* the destination address of the copy (R0) */ buf_set_u32(reg_params[0].value, 0, 32, address); /* The source address of the copy (R1) */ buf_set_u32(reg_params[1].value, 0, 32, source->address); /* The length of the copy (R2) */ buf_set_u32(reg_params[2].value, 0, 32, this_count / 4); /* 5: Execute the bunch of code */ retval = target_run_algorithm(target, 0, NULL, sizeof(reg_params) / sizeof(*reg_params), reg_params, write_algorithm->address, 0, 10000, &armv7m_info); if (retval != ERROR_OK) break; /* check for Hard Fault */ if (armv7m->exception_number == 3) break; /* 6: Wait while busy */ retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) break; buffer += this_count; address += this_count; count -= this_count; } /* restore previous flags */ armv7m->demcr = demcr_save; if (armv7m->exception_number == 3) { /* the stm32l15x devices seem to have an issue when blank. * if a ram loader is executed on a blank device it will * Hard Fault, this issue does not happen for a already programmed device. * A related issue is described in the stm32l151xx errata (Doc ID 17721 Rev 6 - 2.1.3). * The workaround of handling the Hard Fault exception does work, but makes the * loader more complicated, as a compromise we manually write the pages, programming time * is reduced by 50% using this slower method. */ LOG_WARNING("couldn't use loader, falling back to page memory writes"); while (count > 0) { uint32_t this_count; this_count = (count > 128) ? 128 : count; /* Write the next half pages */ retval = target_write_buffer(target, address, this_count, buffer); if (retval != ERROR_OK) break; /* Wait while busy */ retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) break; buffer += this_count; address += this_count; count -= this_count; } } if (retval == ERROR_OK) retval = stm32lx_lock_program_memory(bank); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; }