Add supprt for STM32L4 flash driver
authorDave Vandervies <dj3vande@terse.ca>
Mon, 20 Jul 2015 02:58:43 +0000 (22:58 -0400)
committerDave Vandervies <dj3vande@terse.ca>
Sat, 1 Aug 2015 13:56:12 +0000 (09:56 -0400)
No loader yet, but we can erase!

src/stlink-common.c

index 343795aeb99731b96e237365eaa8b838315882f2..07b8d6765aedc7028c2dad397e8abb323aaf631c 100644 (file)
 #define FLASH_L1_FPRG 10
 #define FLASH_L1_PROG 3
 
+//32L4 register base is at FLASH_REGS_ADDR (0x40022000)
+#define STM32L4_FLASH_KEYR      (FLASH_REGS_ADDR + 0x08)
+#define STM32L4_FLASH_SR        (FLASH_REGS_ADDR + 0x10)
+#define STM32L4_FLASH_CR        (FLASH_REGS_ADDR + 0x14)
+#define STM32L4_FLASH_OPTR      (FLASH_REGS_ADDR + 0x20)
+
+#define STM32L4_FLASH_SR_BSY            16
+#define STM32L4_FLASH_SR_ERRMASK        0x3f8 /* SR [9:3] */
+
+#define STM32L4_FLASH_CR_LOCK   31      /* Lock control register */
+#define STM32L4_FLASH_CR_PG     0       /* Program */
+#define STM32L4_FLASH_CR_PER    1       /* Page erase */
+#define STM32L4_FLASH_CR_MER1   2       /* Bank 1 erase */
+#define STM32L4_FLASH_CR_MER2   15      /* Bank 2 erase */
+#define STM32L4_FLASH_CR_STRT   16      /* Start command */
+#define STM32L4_FLASH_CR_BKER   11      /* Bank select for page erase */
+#define STM32L4_FLASH_CR_PNB    3       /* Page number (8 bits) */
+// Page is fully specified by BKER and PNB
+#define STM32L4_FLASH_CR_PAGEMASK (0x1fflu << STM32L4_FLASH_CR_PNB)
+
+#define STM32L4_FLASH_OPTR_DUALBANK     21
+
 //STM32L0x flash register base and offsets
 //same as 32L1 above
 // RM0090 - DM00031020.pdf
@@ -156,6 +178,8 @@ static inline uint32_t read_flash_cr(stlink_t *sl) {
             (sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
             (sl->chip_id == STM32_CHIPID_F446))
         res = stlink_read_debug32(sl, FLASH_F4_CR);
+    else if (sl->chip_id == STM32_CHIPID_L4)
+        res = stlink_read_debug32(sl, STM32L4_FLASH_CR);
     else
         res = stlink_read_debug32(sl, FLASH_CR);
 #if DEBUG_FLASH
@@ -166,12 +190,16 @@ static inline uint32_t read_flash_cr(stlink_t *sl) {
 
 static inline unsigned int is_flash_locked(stlink_t *sl) {
     /* return non zero for true */
+    uint32_t cr = read_flash_cr(sl);
+
     if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4) || (sl->chip_id == STM32_CHIPID_F4_DE) ||
             (sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
             (sl->chip_id == STM32_CHIPID_F446))
-        return read_flash_cr(sl) & (1 << FLASH_F4_CR_LOCK);
+        return cr & (1 << FLASH_F4_CR_LOCK);
+    else if (sl->chip_id == STM32_CHIPID_L4)
+        return cr & (1lu << STM32L4_FLASH_CR_LOCK);
     else
-        return read_flash_cr(sl) & (1 << FLASH_CR_LOCK);
+        return cr & (1 << FLASH_CR_LOCK);
 }
 
 static void unlock_flash(stlink_t *sl) {
@@ -185,6 +213,9 @@ static void unlock_flash(stlink_t *sl) {
             (sl->chip_id == STM32_CHIPID_F446)) {
         stlink_write_debug32(sl, FLASH_F4_KEYR, FLASH_KEY1);
         stlink_write_debug32(sl, FLASH_F4_KEYR, FLASH_KEY2);
+    } else if (sl->chip_id == STM32_CHIPID_L4) {
+        stlink_write_debug32(sl, STM32L4_FLASH_KEYR, FLASH_KEY1);
+        stlink_write_debug32(sl, STM32L4_FLASH_KEYR, FLASH_KEY2);
     } else {
         stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY1);
         stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY2);
@@ -212,6 +243,9 @@ static void lock_flash(stlink_t *sl) {
             (sl->chip_id == STM32_CHIPID_F446)) {
         const uint32_t n = read_flash_cr(sl) | (1 << FLASH_F4_CR_LOCK);
         stlink_write_debug32(sl, FLASH_F4_CR, n);
+    } else if (sl->chip_id == STM32_CHIPID_L4) {
+        const uint32_t n = read_flash_cr(sl) | (1lu << STM32L4_FLASH_CR_LOCK);
+        stlink_write_debug32(sl, STM32L4_FLASH_CR, n);
     } else {
         /* write to 1 only. reset by hw at unlock sequence */
         const uint32_t n = read_flash_cr(sl) | (1 << FLASH_CR_LOCK);
@@ -227,6 +261,10 @@ static void set_flash_cr_pg(stlink_t *sl) {
         uint32_t x = read_flash_cr(sl);
         x |= (1 << FLASH_CR_PG);
         stlink_write_debug32(sl, FLASH_F4_CR, x);
+    } else if (sl->chip_id == STM32_CHIPID_L4) {
+        uint32_t x = read_flash_cr(sl);
+        x |= (1 << STM32L4_FLASH_CR_PG);
+        stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
     } else {
         const uint32_t n = 1 << FLASH_CR_PG;
         stlink_write_debug32(sl, FLASH_CR, n);
@@ -244,8 +282,14 @@ static void __attribute__((unused)) clear_flash_cr_pg(stlink_t *sl) {
 }
 
 static void set_flash_cr_per(stlink_t *sl) {
-    const uint32_t n = 1 << FLASH_CR_PER;
-    stlink_write_debug32(sl, FLASH_CR, n);
+    if (sl->chip_id == STM32_CHIPID_L4) {
+       uint32_t n = read_flash_cr(sl);
+       n |= (1lu << STM32L4_FLASH_CR_PER);
+       stlink_write_debug32(sl, STM32L4_FLASH_CR, n);
+    } else {
+       const uint32_t n = 1 << FLASH_CR_PER;
+       stlink_write_debug32(sl, FLASH_CR, n);
+    }
 }
 
 static void __attribute__((unused)) clear_flash_cr_per(stlink_t *sl) {
@@ -259,6 +303,11 @@ static void set_flash_cr_mer(stlink_t *sl) {
             (sl->chip_id == STM32_CHIPID_F446))
         stlink_write_debug32(sl, FLASH_F4_CR,
                 stlink_read_debug32(sl, FLASH_F4_CR) | (1 << FLASH_CR_MER));
+    else if (sl->chip_id == STM32_CHIPID_L4)
+       stlink_write_debug32(sl, STM32L4_FLASH_CR,
+               stlink_read_debug32(sl, STM32L4_FLASH_CR) |
+                       (1lu << STM32L4_FLASH_CR_MER1) |
+                       (1lu << STM32L4_FLASH_CR_MER2));
     else
         stlink_write_debug32(sl, FLASH_CR,
                 stlink_read_debug32(sl, FLASH_CR) | (1 << FLASH_CR_MER));
@@ -282,6 +331,10 @@ static void set_flash_cr_strt(stlink_t *sl) {
         uint32_t x = read_flash_cr(sl);
         x |= (1 << FLASH_F4_CR_STRT);
         stlink_write_debug32(sl, FLASH_F4_CR, x);
+    } else if (sl->chip_id == STM32_CHIPID_L4) {
+        uint32_t x = read_flash_cr(sl);
+        x |= (1lu << STM32L4_FLASH_CR_STRT);
+        stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
     } else {
         stlink_write_debug32(sl, FLASH_CR,
                 stlink_read_debug32(sl, FLASH_CR) | (1 << FLASH_CR_STRT) );
@@ -298,6 +351,8 @@ static inline uint32_t read_flash_sr(stlink_t *sl) {
             (sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
             (sl->chip_id == STM32_CHIPID_F446))
         res = stlink_read_debug32(sl, FLASH_F4_SR);
+    else if (sl->chip_id == STM32_CHIPID_L4)
+        res = stlink_read_debug32(sl, STM32L4_FLASH_SR);
     else
         res = stlink_read_debug32(sl, FLASH_SR);
     //fprintf(stdout, "SR:0x%x\n", *(uint32_t*) sl->q_buf);
@@ -309,6 +364,8 @@ static inline unsigned int is_flash_busy(stlink_t *sl) {
             (sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
             (sl->chip_id == STM32_CHIPID_F446))
         return read_flash_sr(sl) & (1 << FLASH_F4_SR_BSY);
+    else if (sl->chip_id == STM32_CHIPID_L4)
+        return read_flash_sr(sl) & (1 << STM32L4_FLASH_SR_BSY);
     else
         return read_flash_sr(sl) & (1 << FLASH_SR_BSY);
 }
@@ -375,6 +432,17 @@ static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n) {
     stlink_write_debug32(sl, FLASH_F4_CR, x);
 }
 
+static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) {
+    uint32_t x = read_flash_cr(sl);
+    x &=~ STM32L4_FLASH_CR_PAGEMASK;
+    x |= (n << STM32L4_FLASH_CR_PNB);
+    x |= (1lu << STM32L4_FLASH_CR_PER);
+#if DEBUG_FLASH
+    fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n);
+#endif
+    stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
+}
+
 // Delegates to the backends...
 
 void stlink_close(stlink_t *sl) {
@@ -1036,6 +1104,23 @@ uint32_t calculate_F4_sectornum(uint32_t flashaddr){
 
 }
 
+// Returns BKER:PNB for the given page address
+uint32_t calculate_L4_page(stlink_t *sl, uint32_t flashaddr) {
+    uint32_t bker = 0;
+    uint32_t flashopt = stlink_read_debug32(sl, STM32L4_FLASH_OPTR);
+    flashaddr -= STM32_FLASH_BASE;
+    if (flashopt & (1lu << STM32L4_FLASH_OPTR_DUALBANK)) {
+        uint32_t banksize = sl->flash_size / 2;
+        if (flashaddr > banksize) {
+            flashaddr -= banksize;
+            bker = 0x100;
+        }
+    }
+    // For 1MB chips without the dual-bank option set, the page address will
+    // overflow into the BKER bit, which gives us the correct bank:page value.
+    return bker | flashaddr/sl->flash_pgsz;
+}
+
 uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr){
     if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4) || (sl->chip_id == STM32_CHIPID_F4_DE) ||
             (sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
@@ -1061,7 +1146,7 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
 {
     if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4) ||  (sl->chip_id == STM32_CHIPID_F4_DE) ||
             (sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
-            (sl->chip_id == STM32_CHIPID_F446)) {
+            (sl->chip_id == STM32_CHIPID_F446) || (sl->chip_id == STM32_CHIPID_L4)) {
         /* wait for ongoing op to finish */
         wait_flash_busy(sl);
 
@@ -1069,15 +1154,22 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
         unlock_flash_if(sl);
 
         /* select the page to erase */
-        // calculate the actual page from the address
-        uint32_t sector=calculate_F4_sectornum(flashaddr);
+        if (sl->chip_id == STM32_CHIPID_L4) {
+            // calculate the actual bank+page from the address
+            uint32_t page = calculate_L4_page(sl, flashaddr);
 
-        fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x\n", sector, stlink_calculate_pagesize(sl, flashaddr));
+            write_flash_cr_bker_pnb(sl, page);
+        } else {
+            // calculate the actual page from the address
+            uint32_t sector=calculate_F4_sectornum(flashaddr);
+
+            fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x\n", sector, stlink_calculate_pagesize(sl, flashaddr));
         
-        //the SNB values for flash sectors in the second bank do not directly follow the values for the first bank on 2mb devices...
-        if (sector >= 12) sector += 4;
+            //the SNB values for flash sectors in the second bank do not directly follow the values for the first bank on 2mb devices...
+            if (sector >= 12) sector += 4;
 
-        write_flash_cr_snb(sl, sector);
+            write_flash_cr_snb(sl, sector);
+        }
 
         /* start erase operation */
         set_flash_cr_strt(sl);