flash: add stellaris async flash loader
authorSpencer Oliver <spen@spen-soft.co.uk>
Fri, 10 Feb 2012 15:27:27 +0000 (15:27 +0000)
committerAndreas Fritiofson <andreas.fritiofson@gmail.com>
Sun, 26 Feb 2012 00:46:48 +0000 (00:46 +0000)
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>
contrib/loaders/flash/stellaris.s
src/flash/nor/stellaris.c

index 166dd52..4249493 100644 (file)
        .cpu cortex-m3
        .thumb
        .thumb_func
-       .align  2
 
 /*
-       Call with :     
-       r0 = buffer address
-       r1 = destination address
-       r2 = bytecount (in) - endaddr (work) 
-       
-       Used registers: 
-       r3 = pFLASH_CTRL_BASE
-       r4 = FLASHWRITECMD
-       r5 = #1
-       r6 = bytes written
-       r7 = temp reg
-*/
+ * Params :
+ * r0 = workarea start
+ * r1 = workarea end
+ * r2 = target address
+ * r3 = count (32bit words)
+ *
+ * Clobbered:
+ * r4 = pFLASH_CTRL_BASE
+ * r5 = FLASHWRITECMD
+ * r7 - rp
+ * r8 - wp, tmp
+ */
 
 write:
-       ldr     r3,pFLASH_CTRL_BASE
-       ldr     r4,FLASHWRITECMD
-       movs    r5, 1
-       movs    r6, #0
+       ldr     r4, pFLASH_CTRL_BASE
+       ldr     r5, FLASHWRITECMD
+
+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:
-       str             r1, [r3, #0]
-       ldr             r7, [r0, r6]
-       str             r7, [r3, #4]
-       str             r4, [r3, #8]
-waitloop:
-       ldr             r7, [r3, #8]
-       tst             r7, r5
-       bne             waitloop
-       adds    r1, r1, #4
-       adds    r6, r6, #4
-       cmp             r6, r2
-       bne             mainloop
-       bkpt    #0
+       str             r2, [r4, #0]    /* FMA - write address */
+       add             r2, r2, #4              /* increment target address */
+       ldr             r8, [r7], #4
+       str             r8, [r4, #4]    /* FMD - write data */
+       str             r5, [r4, #8]    /* FMC - enable write */
+busy:
+       ldr             r8, [r4, #8]
+       tst             r8, #1
+       bne             busy
+
+       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 word count */
+       cbz     r3, exit                /* loop if not done */
+       b               wait_fifo
+exit:
+       bkpt    #0
 
 pFLASH_CTRL_BASE: .word 0x400FD000
 FLASHWRITECMD: .word 0xA4420001
index 712077d..0c4169c 100644 (file)
@@ -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 */
 
 static const uint8_t stellaris_write_code[] = {
-/*
-       Call with :
-       r0 = buffer address
-       r1 = destination address
-       r2 = bytecount (in) - endaddr (work)
-
-       Used registers:
-       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: */
+                                                               /* write: */
+       0xDF, 0xF8, 0x40, 0x40,         /* ldr          r4, pFLASH_CTRL_BASE */
+       0xDF, 0xF8, 0x40, 0x50,         /* ldr          r5, FLASHWRITECMD */
+                                                               /* wait_fifo: */
+       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 */
+
+       /* pFLASH_CTRL_BASE: */
        0x00, 0xD0, 0x0F, 0x40, /* .word        0x400FD000 */
-/* FLASHWRITECMD: */
+       /* FLASHWRITECMD: */
        0x01, 0x00, 0x42, 0xA4  /* .word        0xA4420001 */
 };
-
 static int stellaris_write_block(struct flash_bank *bank,
                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 *write_algorithm;
        uint32_t address = bank->base + offset;
-       struct reg_param reg_params[3];
+       struct reg_param reg_params[4];
        struct armv7m_algorithm armv7m_info;
        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) {
                buffer_size /= 2;
                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;
                }
                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(&reg_params[0], "r0", 32, PARAM_OUT);
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
        init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
 
-       while (wcount > 0) {
-               uint32_t thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
-
-               target_write_buffer(target, source->address, thisrun_count * 4, 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, 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;
-               }
+       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, wcount);
 
-               buffer += thisrun_count * 4;
-               address += thisrun_count * 4;
-               wcount -= thisrun_count;
-       }
+       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);
 
-       /* REVISIT we could speed up writing multi-section images by
-        * not freeing the initialized write_algorithm this way.
-        */
+       if (retval == ERROR_FLASH_OPERATION_FAILED)
+               LOG_ERROR("error %d executing stellaris flash write algorithm", retval);
 
        target_free_working_area(target, write_algorithm);
        target_free_working_area(target, source);
@@ -1089,6 +1071,7 @@ static int stellaris_write_block(struct flash_bank *bank,
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
        destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
 
        return retval;
 }