From 94db77a0e612c7f4802668ad67d41f6414f04abf Mon Sep 17 00:00:00 2001 From: Spencer Oliver Date: Thu, 16 Feb 2012 09:42:06 +0000 Subject: [PATCH] flash: add stm32f2x async flash loader This enable the stm32f2x flash driver to use the asynchronous algorithm support. Speed increase is as follows: before - wrote 1048576 bytes from file stm32f4x.bin in 30.453804s (33.625 KiB/s) after - wrote 1048576 bytes from file stm32f4x.bin in 23.679497s (43.244 KiB/s) This also fixes a bug that was in the old flash loader. The old loader waited while bit16 of the status reg was 0, the new loader waits until this bit is 0 as stated in the flash spec. Bizarrely this bug did not effect programming on any tested parts. Change-Id: I3efc94d42cbe81283673a8f4203700638080af6e Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/460 Tested-by: jenkins --- contrib/loaders/flash/stm32f2x.S | 67 ++++++++++++------- src/flash/nor/stm32f2x.c | 111 +++++++++++++++---------------- 2 files changed, 95 insertions(+), 83 deletions(-) diff --git a/contrib/loaders/flash/stm32f2x.S b/contrib/loaders/flash/stm32f2x.S index 49c821b60..7ac5e3c06 100644 --- a/contrib/loaders/flash/stm32f2x.S +++ b/contrib/loaders/flash/stm32f2x.S @@ -21,43 +21,60 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ - -// Build : arm-eabi-gcc -c stm32f2xxx.S .text .syntax unified .cpu cortex-m3 .thumb .thumb_func - .global write /* - r0 - source address - r1 - target address - r2 - count (halfword-16bit) - r3 - result out - r4 - flash base -*/ + * Params : + * r0 = workarea start, status (out) + * r1 = workarea end + * r2 = target address + * r3 = count (16bit words) + * r4 = flash base + * + * Clobbered: + * r6 - temp + * r7 - rp + * r8 - wp, tmp + */ #define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */ -#define STM32_FLASH_SR_OFFSET 0x0c /* offset of CR register in FLASH struct */ +#define STM32_FLASH_SR_OFFSET 0x0c /* offset of SR register in FLASH struct */ -write: +wait_fifo: + ldr r8, [r0, #0] /* read wp */ + cmp r8, #0 /* abort if wp == 0 */ + beq exit + ldr r7, [r0, #4] /* read rp */ + cmp r7, r8 /* wait until rp != wp */ + beq wait_fifo -write_half_word: - ldr r3, STM32_PROG16 - str r3, [r4, #STM32_FLASH_CR_OFFSET] - ldrh r3, [r0], #0x02 /* read one half-word from src, increment ptr */ - strh r3, [r1], #0x02 /* write one half-word from src, increment ptr */ + ldr r6, STM32_PROG16 + str r6, [r4, #STM32_FLASH_CR_OFFSET] + ldrh r6, [r7], #0x02 /* read one half-word from src, increment ptr */ + strh r6, [r2], #0x02 /* write one half-word from src, increment ptr */ busy: - ldr r3, [r4, #STM32_FLASH_SR_OFFSET] - tst r3, #0x10000 /* BSY (bit0) == 1 => operation in progress */ - beq busy /* wait more... */ - tst r3, #0xf0 /* PGSERR | PGPERR | PGAERR | WRPERR */ - bne exit /* fail... */ - subs r2, r2, #0x01 /* decrement counter */ - bne write_half_word /* write next half-word if anything left */ + ldr r6, [r4, #STM32_FLASH_SR_OFFSET] + tst r6, #0x10000 /* BSY (bit16) == 1 => operation in progress */ + bne busy /* wait more... */ + tst r6, #0xf0 /* PGSERR | PGPERR | PGAERR | WRPERR */ + bne error /* fail... */ + + cmp r7, r1 /* wrap rp at end of buffer */ + it cs + addcs r7, r0, #8 /* skip loader args */ + str r7, [r0, #4] /* store rp */ + subs r3, r3, #1 /* decrement halfword count */ + cbz r3, exit /* loop if not done */ + b wait_fifo +error: + movs r1, #0 + str r1, [r0, #4] /* set rp = 0 on error */ exit: + mov r0, r6 /* return status in r0 */ bkpt #0x00 - -STM32_PROG16: .word 0x101 /* PG | PSIZE_16*/ +STM32_PROG16: .word 0x101 /* PG | PSIZE_16*/ diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 367465a05..daa254651 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -327,35 +327,44 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, /* see contrib/loaders/flash/stm32f2x.S for src */ - static const uint16_t stm32x_flash_write_code_16[] = { - /* 00000000 : */ - 0x4b07, /* ldr r3, [pc, #28] (20 ) */ - 0x6123, /* str r3, [r4, #16] */ - 0xf830, 0x3b02, /* ldrh.w r3, [r0], #2 */ - 0xf821, 0x3b02, /* strh.w r3, [r1], #2 */ + static const uint8_t stm32x_flash_write_code[] = { + /* wait_fifo: */ + 0xD0, 0xF8, 0x00, 0x80, /* ldr r8, [r0, #0] */ + 0xB8, 0xF1, 0x00, 0x0F, /* cmp r8, #0 */ + 0x1A, 0xD0, /* beq exit */ + 0x47, 0x68, /* ldr r7, [r0, #4] */ + 0x47, 0x45, /* cmp r7, r8 */ + 0xF7, 0xD0, /* beq wait_fifo */ - /* 0000000c : */ - 0x68e3, /* ldr r3, [r4, #12] */ - 0xf413, 0x3f80, /* tst.w r3, #65536 ; 0x10000 */ - 0xd0fb, /* beq.n c */ - 0xf013, 0x0ff0, /* tst.w r3, #240 ; 0xf0 */ - 0xd101, /* bne.n 1e */ - 0x3a01, /* subs r2, #1 */ - 0xd1f0, /* bne.n 0 */ - /* 0000001e : */ - 0xbe00, /* bkpt 0x0000 */ + 0xDF, 0xF8, 0x30, 0x60, /* ldr r6, STM32_PROG16 */ + 0x26, 0x61, /* str r6, [r4, #STM32_FLASH_CR_OFFSET] */ + 0x37, 0xF8, 0x02, 0x6B, /* ldrh r6, [r7], #0x02 */ + 0x22, 0xF8, 0x02, 0x6B, /* strh r6, [r2], #0x02 */ + /* busy: */ + 0xE6, 0x68, /* ldr r6, [r4, #STM32_FLASH_SR_OFFSET] */ + 0x16, 0xF4, 0x80, 0x3F, /* tst r6, #0x10000 */ + 0xFB, 0xD1, /* bne busy */ + 0x16, 0xF0, 0xF0, 0x0F, /* tst r6, #0xf0 */ + 0x07, 0xD1, /* bne error */ - /* 00000020 : */ - 0x0101, 0x0000, /* .word 0x00000101 */ + 0x8F, 0x42, /* cmp r7, r1 */ + 0x28, 0xBF, /* it cs */ + 0x00, 0xF1, 0x08, 0x07, /* addcs r7, r0, #8 */ + 0x47, 0x60, /* str r7, [r0, #4] */ + 0x01, 0x3B, /* subs r3, r3, #1 */ + 0x13, 0xB1, /* cbz r3, exit */ + 0xE1, 0xE7, /* b wait_fifo */ + /* error: */ + 0x00, 0x21, /* movs r1, #0 */ + 0x41, 0x60, /* str r1, [r0, #4] */ + /* exit: */ + 0x30, 0x46, /* mov r0, r6 */ + 0x00, 0xBE, /* bkpt #0x00 */ + + /* : */ + 0x01, 0x01, 0x00, 0x00, /* .word 0x00000101 */ }; - /* Flip endian */ - uint8_t stm32x_flash_write_code[sizeof(stm32x_flash_write_code_16)*2]; - for (unsigned i = 0; i < sizeof(stm32x_flash_write_code_16) / 2; i++) { - stm32x_flash_write_code[i*2 + 0] = stm32x_flash_write_code_16[i] & 0xff; - stm32x_flash_write_code[i*2 + 1] = (stm32x_flash_write_code_16[i] >> 8) & 0xff; - } - 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"); @@ -385,38 +394,29 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, 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); - init_reg_param(®_params[4], "r4", 32, PARAM_OUT); + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash base */ - while (count > 0) { - uint32_t thisrun_count = (count > (buffer_size / 2)) ? - (buffer_size / 2) : count; + buf_set_u32(reg_params[0].value, 0, 32, source->address); + buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); + buf_set_u32(reg_params[2].value, 0, 32, address); + buf_set_u32(reg_params[3].value, 0, 32, count); + buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE); - retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer); - if (retval != ERROR_OK) - break; + retval = target_run_flash_async_algorithm(target, buffer, count, 2, + 0, NULL, + 5, reg_params, + source->address, source->size, + stm32x_info->write_algorithm->address, 0, + &armv7m_info); - 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); - /* R3 is a return value only */ - buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE); + if (retval == ERROR_FLASH_OPERATION_FAILED) { + LOG_ERROR("error executing stm32x flash write algorithm"); - retval = target_run_algorithm(target, 0, NULL, - sizeof(reg_params) / sizeof(*reg_params), - reg_params, - stm32x_info->write_algorithm->address, - 0, - 10000, &armv7m_info); - if (retval != ERROR_OK) { - LOG_ERROR("error executing stm32x flash write algorithm"); - break; - } - - uint32_t error = buf_get_u32(reg_params[3].value, 0, 32) & FLASH_ERROR; + uint32_t error = buf_get_u32(reg_params[0].value, 0, 32) & FLASH_ERROR; if (error & FLASH_WRPERR) LOG_ERROR("flash memory write protected"); @@ -426,12 +426,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, /* Clear but report errors */ target_write_u32(target, STM32_FLASH_SR, error); retval = ERROR_FAIL; - break; } - - buffer += thisrun_count * 2; - address += thisrun_count * 2; - count -= thisrun_count; } target_free_working_area(target, source);