Enable half_page write for STM32L
[fw/stlink] / src / stlink-common.c
index 2d495a852cc4e8c90a102c187d26bf1d66237f88..2ecddea3dd8bb1f7b93fc3ef71594a026d69703f 100644 (file)
@@ -61,6 +61,8 @@
 #define STM32L_FLASH_SR (STM32L_FLASH_REGS_ADDR + 0x18)
 #define STM32L_FLASH_OBR (STM32L_FLASH_REGS_ADDR + 0x1c)
 #define STM32L_FLASH_WRPR (STM32L_FLASH_REGS_ADDR + 0x20)
+#define FLASH_L1_FPRG 10
+#define FLASH_L1_PROG 3
 
 
 //STM32F4
@@ -537,6 +539,11 @@ void stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
 
 void stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
     DLOG("*** stlink_write_mem8 ***\n");
+    if (len > 0x40 ) { // !!! never ever: Writing more then 0x40 bytes gives unexpected behaviour
+        fprintf(stderr, "Error: Data length > 64: +%d byte.\n",
+                len);
+        return;
+    }
     sl->backend->write_mem8(sl, addr, len);
 }
 
@@ -859,8 +866,16 @@ on_error:
 
 int write_buffer_to_sram(stlink_t *sl, flash_loader_t* fl, const uint8_t* buf, size_t size) {
     /* write the buffer right after the loader */
-    memcpy(sl->q_buf, buf, size);
-    stlink_write_mem8(sl, fl->buf_addr, size);
+    size_t chunk = size & ~0x3;
+    size_t rem   = size & 0x3;
+    if (chunk) {
+        memcpy(sl->q_buf, buf, chunk);
+        stlink_write_mem32(sl, fl->buf_addr, chunk);
+    }
+    if (rem) {
+        memcpy(sl->q_buf, buf+chunk, rem);
+        stlink_write_mem8(sl, (fl->buf_addr)+chunk, rem);
+    }
     return 0;
 }
 
@@ -1199,6 +1214,57 @@ int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data,
 
 }
 
+int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned num_half_pages)
+{        
+    unsigned int count;
+    uint32_t val;
+    flash_loader_t fl;
+   
+    ILOG("Starting Half page flash write for STM32L core id\n");
+    /* flash loader initialization */
+    if (init_flash_loader(sl, &fl) == -1) {
+        WLOG("init_flash_loader() == -1\n");
+        return -1;
+    }
+    /* Unlock already done */
+    val = stlink_read_debug32(sl, STM32L_FLASH_PECR);
+    val |= (1 << FLASH_L1_FPRG);
+    stlink_write_debug32(sl, STM32L_FLASH_PECR, val);
+    
+    val |= (1 << FLASH_L1_PROG);
+    stlink_write_debug32(sl, STM32L_FLASH_PECR, val);
+    while ((stlink_read_debug32(sl, STM32L_FLASH_SR) & (1 << 0)) != 0) {}
+
+#define L1_WRITE_BLOCK_SIZE 0x80
+    for (count = 0; count  < num_half_pages; count ++) {
+        if (run_flash_loader(sl, &fl, addr + count * L1_WRITE_BLOCK_SIZE, base + count * L1_WRITE_BLOCK_SIZE, L1_WRITE_BLOCK_SIZE) == -1) {
+            WLOG("l1_run_flash_loader(%#zx) failed! == -1\n", addr + count * L1_WRITE_BLOCK_SIZE);
+            val = stlink_read_debug32(sl, STM32L_FLASH_PECR);
+            val &= ~((1 << FLASH_L1_FPRG) |(1 << FLASH_L1_PROG));
+            stlink_write_debug32(sl, STM32L_FLASH_PECR, val);
+            return -1;
+        }
+        /* wait for sr.busy to be cleared */
+        if (sl->verbose >= 1) {
+            /* show progress. writing procedure is slow
+               and previous errors are misleading */
+            fprintf(stdout, "\r%3u/%u halfpages written", count, num_half_pages);
+            fflush(stdout);
+        }
+        while ((stlink_read_debug32(sl, STM32L_FLASH_SR) & (1 << 0)) != 0) {
+        }
+    }
+    fprintf(stdout, "\n");
+    val = stlink_read_debug32(sl, STM32L_FLASH_PECR);
+    val &= ~(1 << FLASH_L1_PROG);
+    stlink_write_debug32(sl, STM32L_FLASH_PECR, val);
+    val = stlink_read_debug32(sl, STM32L_FLASH_PECR);
+    val &= ~(1 << FLASH_L1_FPRG);
+    stlink_write_debug32(sl, STM32L_FLASH_PECR, val);
+
+    return 0;
+}
+
 int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned len) {
     size_t off;
     flash_loader_t fl;
@@ -1319,24 +1385,19 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned
                fprintf(stderr, "pecr.prglock not clear\n");
                return -1;
        }
+        if (len > L1_WRITE_BLOCK_SIZE) {
+            if (stm32l1_write_half_pages(sl, addr, base, len/L1_WRITE_BLOCK_SIZE) == -1){
+                WLOG("\nwrite_half_pages failed == -1\n");
+                return -1;
+            }
+        }  
 
-       /* write word in program memory */
-       for (off = 0; off < len; off += sizeof(uint32_t)) {
+       /* write remainingword in program memory */
+       for (off = (len /L1_WRITE_BLOCK_SIZE)*L1_WRITE_BLOCK_SIZE; off < len; off += sizeof(uint32_t)) {
                uint32_t data;
                write_uint32((unsigned char*) &data, *(uint32_t*) (base + off));
                stlink_write_debug32(sl, addr + off, data);
 
-               if (sl->verbose >= 1) {
-                       if ((off & (sl->flash_pgsz - 1)) == 0) {
-                               /* show progress. writing procedure is slow
-                                  and previous errors are misleading */
-                               const uint32_t pgnum = off / sl->flash_pgsz;
-                               const uint32_t pgcount = len / sl->flash_pgsz;
-                               fprintf(stdout, "\r%3u/%u pages written", pgnum, pgcount);
-                                fflush(stdout);
-                       }
-               }
-
                /* wait for sr.busy to be cleared */
                while ((stlink_read_debug32(sl, STM32L_FLASH_SR) & (1 << 0)) != 0) {
                }
@@ -1457,6 +1518,7 @@ int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr) {
 int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size) {
 
     reg rr;
+    int i = 0;
     DLOG("Running flash loader, write address:%#x, size: %zd\n", target, size);
     // FIXME This can never return -1
     if (write_buffer_to_sram(sl, fl, buf, size) == -1) {
@@ -1474,7 +1536,6 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons
       stlink_write_reg(sl, target, 0); /* target */
       stlink_write_reg(sl, fl->buf_addr, 1); /* source */
       stlink_write_reg(sl, count, 2); /* count (32 bits words) */
-      stlink_write_reg(sl, 0, 3); /* output count */
       stlink_write_reg(sl, fl->loader_addr, 15); /* pc register */
 
     } else if (sl->core_id == STM32VL_CORE_ID) {
@@ -1498,8 +1559,16 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons
     stlink_run(sl);
 
     /* wait until done (reaches breakpoint) */
-    while (is_core_halted(sl) == 0) ;
+    while ((is_core_halted(sl) == 0) && (i <10000))
+    {
+        i++;
+    }
 
+    if ( i > 9999) {
+        fprintf(stderr, "run error\n");
+        return -1;
+    }
+        
     /* check written byte count */
     if (sl->core_id == STM32L_CORE_ID) {