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 <spen@spen-soft.co.uk> Reviewed-on: http://openocd.zylin.com/460 Tested-by: jenkins__archive__
parent
90cee35696
commit
94db77a0e6
|
@ -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*/
|
||||
|
|
|
@ -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 <write>: */
|
||||
0x4b07, /* ldr r3, [pc, #28] (20 <STM32_PROG16>) */
|
||||
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 <busy>: */
|
||||
0x68e3, /* ldr r3, [r4, #12] */
|
||||
0xf413, 0x3f80, /* tst.w r3, #65536 ; 0x10000 */
|
||||
0xd0fb, /* beq.n c <busy> */
|
||||
0xf013, 0x0ff0, /* tst.w r3, #240 ; 0xf0 */
|
||||
0xd101, /* bne.n 1e <exit> */
|
||||
0x3a01, /* subs r2, #1 */
|
||||
0xd1f0, /* bne.n 0 <write> */
|
||||
/* 0000001e <exit>: */
|
||||
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 <STM32_PROG16>: */
|
||||
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 */
|
||||
|
||||
/* <STM32_PROG16>: */
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue