flash: add stellaris async flash loader
This enable the Stellaris flash driver to use the asynchronous algorithm support. Speed increase is as follows: before - wrote 65536 bytes from file test.bin in 5.486040s (11.666 KiB/s) after - wrote 65536 bytes from file test.bin in 2.274001s (28.144 KiB/s) Change-Id: I9004c9aadffa1ae3b0cbf908e6549b5b1f794508 Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk> Reviewed-on: http://openocd.zylin.com/403 Tested-by: jenkins Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>__archive__
parent
bee7184ce4
commit
90cee35696
|
@ -26,41 +26,53 @@
|
||||||
.cpu cortex-m3
|
.cpu cortex-m3
|
||||||
.thumb
|
.thumb
|
||||||
.thumb_func
|
.thumb_func
|
||||||
.align 2
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Call with :
|
* Params :
|
||||||
r0 = buffer address
|
* r0 = workarea start
|
||||||
r1 = destination address
|
* r1 = workarea end
|
||||||
r2 = bytecount (in) - endaddr (work)
|
* r2 = target address
|
||||||
|
* r3 = count (32bit words)
|
||||||
Used registers:
|
*
|
||||||
r3 = pFLASH_CTRL_BASE
|
* Clobbered:
|
||||||
r4 = FLASHWRITECMD
|
* r4 = pFLASH_CTRL_BASE
|
||||||
r5 = #1
|
* r5 = FLASHWRITECMD
|
||||||
r6 = bytes written
|
* r7 - rp
|
||||||
r7 = temp reg
|
* r8 - wp, tmp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
write:
|
write:
|
||||||
ldr r3,pFLASH_CTRL_BASE
|
ldr r4, pFLASH_CTRL_BASE
|
||||||
ldr r4,FLASHWRITECMD
|
ldr r5, FLASHWRITECMD
|
||||||
movs r5, 1
|
|
||||||
movs r6, #0
|
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
|
||||||
|
|
||||||
mainloop:
|
mainloop:
|
||||||
str r1, [r3, #0]
|
str r2, [r4, #0] /* FMA - write address */
|
||||||
ldr r7, [r0, r6]
|
add r2, r2, #4 /* increment target address */
|
||||||
str r7, [r3, #4]
|
ldr r8, [r7], #4
|
||||||
str r4, [r3, #8]
|
str r8, [r4, #4] /* FMD - write data */
|
||||||
waitloop:
|
str r5, [r4, #8] /* FMC - enable write */
|
||||||
ldr r7, [r3, #8]
|
busy:
|
||||||
tst r7, r5
|
ldr r8, [r4, #8]
|
||||||
bne waitloop
|
tst r8, #1
|
||||||
adds r1, r1, #4
|
bne busy
|
||||||
adds r6, r6, #4
|
|
||||||
cmp r6, r2
|
cmp r7, r1 /* wrap rp at end of buffer */
|
||||||
bne mainloop
|
it cs
|
||||||
bkpt #0
|
addcs r7, r0, #8 /* skip loader args */
|
||||||
|
str r7, [r0, #4] /* store rp */
|
||||||
|
subs r3, r3, #1 /* decrement word count */
|
||||||
|
cbz r3, exit /* loop if not done */
|
||||||
|
b wait_fifo
|
||||||
|
exit:
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
pFLASH_CTRL_BASE: .word 0x400FD000
|
pFLASH_CTRL_BASE: .word 0x400FD000
|
||||||
FLASHWRITECMD: .word 0xA4420001
|
FLASHWRITECMD: .word 0xA4420001
|
||||||
|
|
|
@ -958,43 +958,41 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
|
||||||
/* see contib/loaders/flash/stellaris.s for src */
|
/* see contib/loaders/flash/stellaris.s for src */
|
||||||
|
|
||||||
static const uint8_t stellaris_write_code[] = {
|
static const uint8_t stellaris_write_code[] = {
|
||||||
/*
|
/* write: */
|
||||||
Call with :
|
0xDF, 0xF8, 0x40, 0x40, /* ldr r4, pFLASH_CTRL_BASE */
|
||||||
r0 = buffer address
|
0xDF, 0xF8, 0x40, 0x50, /* ldr r5, FLASHWRITECMD */
|
||||||
r1 = destination address
|
/* wait_fifo: */
|
||||||
r2 = bytecount (in) - endaddr (work)
|
0xD0, 0xF8, 0x00, 0x80, /* ldr r8, [r0, #0] */
|
||||||
|
0xB8, 0xF1, 0x00, 0x0F, /* cmp r8, #0 */
|
||||||
|
0x17, 0xD0, /* beq exit */
|
||||||
|
0x47, 0x68, /* ldr r7, [r0, #4] */
|
||||||
|
0x47, 0x45, /* cmp r7, r8 */
|
||||||
|
0xF7, 0xD0, /* beq wait_fifo */
|
||||||
|
/* mainloop: */
|
||||||
|
0x22, 0x60, /* str r2, [r4, #0] */
|
||||||
|
0x02, 0xF1, 0x04, 0x02, /* add r2, r2, #4 */
|
||||||
|
0x57, 0xF8, 0x04, 0x8B, /* ldr r8, [r7], #4 */
|
||||||
|
0xC4, 0xF8, 0x04, 0x80, /* str r8, [r4, #4] */
|
||||||
|
0xA5, 0x60, /* str r5, [r4, #8] */
|
||||||
|
/* busy: */
|
||||||
|
0xD4, 0xF8, 0x08, 0x80, /* ldr r8, [r4, #8] */
|
||||||
|
0x18, 0xF0, 0x01, 0x0F, /* tst r8, #1 */
|
||||||
|
0xFA, 0xD1, /* bne busy */
|
||||||
|
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 */
|
||||||
|
0x03, 0xB1, /* cbz r3, exit */
|
||||||
|
0xE2, 0xE7, /* b wait_fifo */
|
||||||
|
/* exit: */
|
||||||
|
0x00, 0xBE, /* bkpt #0 */
|
||||||
|
|
||||||
Used registers:
|
/* pFLASH_CTRL_BASE: */
|
||||||
r3 = pFLASH_CTRL_BASE
|
|
||||||
r4 = FLASHWRITECMD
|
|
||||||
r5 = #1
|
|
||||||
r6 = bytes written
|
|
||||||
r7 = temp reg
|
|
||||||
*/
|
|
||||||
0x07, 0x4B, /* ldr r3,pFLASH_CTRL_BASE */
|
|
||||||
0x08, 0x4C, /* ldr r4,FLASHWRITECMD */
|
|
||||||
0x01, 0x25, /* movs r5, 1 */
|
|
||||||
0x00, 0x26, /* movs r6, #0 */
|
|
||||||
/* mainloop: */
|
|
||||||
0x19, 0x60, /* str r1, [r3, #0] */
|
|
||||||
0x87, 0x59, /* ldr r7, [r0, r6] */
|
|
||||||
0x5F, 0x60, /* str r7, [r3, #4] */
|
|
||||||
0x9C, 0x60, /* str r4, [r3, #8] */
|
|
||||||
/* waitloop: */
|
|
||||||
0x9F, 0x68, /* ldr r7, [r3, #8] */
|
|
||||||
0x2F, 0x42, /* tst r7, r5 */
|
|
||||||
0xFC, 0xD1, /* bne waitloop */
|
|
||||||
0x04, 0x31, /* adds r1, r1, #4 */
|
|
||||||
0x04, 0x36, /* adds r6, r6, #4 */
|
|
||||||
0x96, 0x42, /* cmp r6, r2 */
|
|
||||||
0xF4, 0xD1, /* bne mainloop */
|
|
||||||
0x00, 0xBE, /* bkpt #0 */
|
|
||||||
/* pFLASH_CTRL_BASE: */
|
|
||||||
0x00, 0xD0, 0x0F, 0x40, /* .word 0x400FD000 */
|
0x00, 0xD0, 0x0F, 0x40, /* .word 0x400FD000 */
|
||||||
/* FLASHWRITECMD: */
|
/* FLASHWRITECMD: */
|
||||||
0x01, 0x00, 0x42, 0xA4 /* .word 0xA4420001 */
|
0x01, 0x00, 0x42, 0xA4 /* .word 0xA4420001 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int stellaris_write_block(struct flash_bank *bank,
|
static int stellaris_write_block(struct flash_bank *bank,
|
||||||
uint8_t *buffer, uint32_t offset, uint32_t wcount)
|
uint8_t *buffer, uint32_t offset, uint32_t wcount)
|
||||||
{
|
{
|
||||||
|
@ -1003,7 +1001,7 @@ static int stellaris_write_block(struct flash_bank *bank,
|
||||||
struct working_area *source;
|
struct working_area *source;
|
||||||
struct working_area *write_algorithm;
|
struct working_area *write_algorithm;
|
||||||
uint32_t address = bank->base + offset;
|
uint32_t address = bank->base + offset;
|
||||||
struct reg_param reg_params[3];
|
struct reg_param reg_params[4];
|
||||||
struct armv7m_algorithm armv7m_info;
|
struct armv7m_algorithm armv7m_info;
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
|
@ -1032,7 +1030,8 @@ static int stellaris_write_block(struct flash_bank *bank,
|
||||||
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
|
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
|
||||||
buffer_size /= 2;
|
buffer_size /= 2;
|
||||||
if (buffer_size <= buf_min) {
|
if (buffer_size <= buf_min) {
|
||||||
target_free_working_area(target, write_algorithm);
|
if (write_algorithm)
|
||||||
|
target_free_working_area(target, write_algorithm);
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)",
|
LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)",
|
||||||
|
@ -1049,39 +1048,22 @@ static int stellaris_write_block(struct flash_bank *bank,
|
||||||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||||
init_reg_param(®_params[1], "r1", 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[2], "r2", 32, PARAM_OUT);
|
||||||
|
init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
|
||||||
|
|
||||||
while (wcount > 0) {
|
buf_set_u32(reg_params[0].value, 0, 32, source->address);
|
||||||
uint32_t thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
|
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, wcount);
|
||||||
|
|
||||||
target_write_buffer(target, source->address, thisrun_count * 4, buffer);
|
retval = target_run_flash_async_algorithm(target, buffer, wcount, 4,
|
||||||
|
0, NULL,
|
||||||
|
4, reg_params,
|
||||||
|
source->address, source->size,
|
||||||
|
write_algorithm->address, 0,
|
||||||
|
&armv7m_info);
|
||||||
|
|
||||||
buf_set_u32(reg_params[0].value, 0, 32, source->address);
|
if (retval == ERROR_FLASH_OPERATION_FAILED)
|
||||||
buf_set_u32(reg_params[1].value, 0, 32, address);
|
LOG_ERROR("error %d executing stellaris flash write algorithm", retval);
|
||||||
buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count);
|
|
||||||
LOG_DEBUG("Algorithm flash write %u words to 0x%" PRIx32
|
|
||||||
", %u remaining",
|
|
||||||
(unsigned) thisrun_count, address,
|
|
||||||
(unsigned) (wcount - thisrun_count));
|
|
||||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
|
||||||
write_algorithm->address,
|
|
||||||
0,
|
|
||||||
10000, &armv7m_info);
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
LOG_ERROR("error %d executing stellaris "
|
|
||||||
"flash write algorithm",
|
|
||||||
retval);
|
|
||||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer += thisrun_count * 4;
|
|
||||||
address += thisrun_count * 4;
|
|
||||||
wcount -= thisrun_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* REVISIT we could speed up writing multi-section images by
|
|
||||||
* not freeing the initialized write_algorithm this way.
|
|
||||||
*/
|
|
||||||
|
|
||||||
target_free_working_area(target, write_algorithm);
|
target_free_working_area(target, write_algorithm);
|
||||||
target_free_working_area(target, source);
|
target_free_working_area(target, source);
|
||||||
|
@ -1089,6 +1071,7 @@ static int stellaris_write_block(struct flash_bank *bank,
|
||||||
destroy_reg_param(®_params[0]);
|
destroy_reg_param(®_params[0]);
|
||||||
destroy_reg_param(®_params[1]);
|
destroy_reg_param(®_params[1]);
|
||||||
destroy_reg_param(®_params[2]);
|
destroy_reg_param(®_params[2]);
|
||||||
|
destroy_reg_param(®_params[3]);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue