Эх сурвалжийг харах

Add back the ability to flash firmware via SD card

Added sector erase for the GD32F450 because it lacks page erase.
Morio 2 жил өмнө
parent
commit
12a00d1159

+ 62 - 28
lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform.cpp

@@ -367,7 +367,6 @@ static void usb_log_poll()
 
         // Update log position by the actual number of bytes sent
         // If USB CDC buffer is full, this may be 0
-        uint32_t actual = 0;
         usb_hs_send((uint8_t*)data, len);
         logpos -= available - len;
     }
@@ -563,8 +562,42 @@ uint8_t platform_get_buttons()
 /***********************/
 /* Flash reprogramming */
 /***********************/
+#define SECTOR_NUMBER_TO_ID_ERROR 0xFFFFFFFF
 
-bool platform_rewrite_flash_page(uint32_t offset, uint8_t buffer[PLATFORM_FLASH_PAGE_SIZE])
+static uint32_t sector_number_to_id(uint32_t sector_number)
+{
+    if(11 >= sector_number){
+        return CTL_SN(sector_number);
+    }else if(23 >= sector_number){
+        return CTL_SN(sector_number + 4);
+    }else if(27 >= sector_number){
+        return CTL_SN(sector_number - 12);
+    }
+    return SECTOR_NUMBER_TO_ID_ERROR;
+}
+
+bool platform_erase_flash_sector(uint32_t sector)
+{
+    fmc_unlock();
+    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
+    uint32_t sector_id = sector_number_to_id(sector);
+    if (sector_id == SECTOR_NUMBER_TO_ID_ERROR)
+    {
+        logmsg("Sector ", (int) sector, " does not exist");
+        return false;
+    }
+
+    if (FMC_READY != fmc_sector_erase(sector_id))
+    {
+        logmsg("Failed flash failed to erase sector, ", (int) sector);
+        LED_OFF();
+        return false;
+    }
+    fmc_lock();
+    return true;
+}
+
+bool platform_write_flash(uint32_t offset, uint32_t length, uint8_t buffer[PLATFORM_FLASH_WRITE_BUFFER_SIZE])
 {
     if (offset == 0)
     {
@@ -573,50 +606,51 @@ bool platform_rewrite_flash_page(uint32_t offset, uint8_t buffer[PLATFORM_FLASH_
             logmsg("Invalid firmware file, starts with: ", bytearray(buffer, 16));
             return false;
         }
+
     }
 
-    dbgmsg("Writing flash at offset ", offset, " data ", bytearray(buffer, 4));
-    assert(offset % PLATFORM_FLASH_PAGE_SIZE == 0);
-    assert(offset >= PLATFORM_BOOTLOADER_SIZE);
-    
-    //TODO rewrite for sector erase , full bank erase, or full chip erase
-    /*
+    dbgmsg("Writing flash at firmware offset ", offset, " data ", bytearray(buffer, 4));
+    assert(offset % PLATFORM_FLASH_WRITE_BUFFER_SIZE == 0);
+    //assert(offset >= PLATFORM_BOOTLOADER_SIZE);
+        
     fmc_unlock();
-    fmc_bank0_unlock();
-
+    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
     fmc_state_enum status;
-    status = fmc_page_erase(FLASH_BASE + offset);
-    if (status != FMC_READY)
-    {
-        logmsg("Erase failed: ", (int)status);
-        return false;
-    }
-
     uint32_t *buf32 = (uint32_t*)buffer;
-    uint32_t num_words = PLATFORM_FLASH_PAGE_SIZE / 4;
-    for (int i = 0; i < num_words; i++)
+    uint32_t memory_address = FLASH_BASE + PLATFORM_BOOTLOADER_SIZE + offset;
+    uint32_t num_words = length / 4;
+    if (length % 4 == 0)
     {
-        status = fmc_word_program(FLASH_BASE + offset + i * 4, buf32[i]);
-        if (status != FMC_READY)
+        for (int i = 0; i < num_words; i++)
         {
-            logmsg("Flash write failed: ", (int)status);
-            return false;
-        }   
+            status = fmc_word_program(memory_address, buf32[i]);
+            if (status != FMC_READY)
+            {
+                logmsg("Flash write failed at address: ", memory_address, " with code ", (int)status);
+                return false;
+            }
+            memory_address += 4;   
+        }
+    }
+    else
+    {
+       logmsg("Firmware size expected to be word (4byte) aligned");
     }
 
     fmc_lock();
-
+    memory_address = FLASH_BASE + PLATFORM_BOOTLOADER_SIZE + offset;
     for (int i = 0; i < num_words; i++)
     {
         uint32_t expected = buf32[i];
-        uint32_t actual = *(volatile uint32_t*)(FLASH_BASE + offset + i * 4);
+        uint32_t actual = *(volatile uint32_t*)(memory_address);
         if (actual != expected)
         {
-            logmsg("Flash verify failed at offset ", offset + i * 4, " got ", actual, " expected ", expected);
+            logmsg("Flash word verify failed memory address ", memory_address, " got ", actual, " expected ", expected);
             return false;
         }
+        memory_address += 4;
     }
-    */
+
     return true;
 }
 

+ 19 - 3
lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform.h

@@ -43,6 +43,7 @@ extern const char *g_platform_name;
 #   define PLATFORM_OPTIMAL_MIN_SD_WRITE_SIZE 4096
 #   define PLATFORM_OPTIMAL_MAX_SD_WRITE_SIZE 65536
 #   define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 8192
+#   define PLATFORM_FLASH_SECTOR_ERASE
 #   include "ZuluSCSI_v1_4_gpio.h"
 #endif
 
@@ -119,9 +120,24 @@ void SysTick_Handle_PreEmptively();
 
 // Reprogram firmware in main program area.
 #define PLATFORM_BOOTLOADER_SIZE 32768
-#define PLATFORM_FLASH_TOTAL_SIZE (256 * 1024)
-#define PLATFORM_FLASH_PAGE_SIZE 2048
-bool platform_rewrite_flash_page(uint32_t offset, uint8_t buffer[PLATFORM_FLASH_PAGE_SIZE]);
+#define PLATFORM_FLASH_TOTAL_SIZE (512 * 1024)
+
+// must be a factor of each sector map size
+#define PLATFORM_FLASH_WRITE_BUFFER_SIZE 2048
+// From GD32F4xx user manual
+const uint32_t platform_flash_sector_map[] =
+    {
+         16 * 1024,
+         16 * 1024,
+         16 * 1024,
+         16 * 1024,
+         64 * 1024,
+        128 * 1024,
+        128 * 1024, 
+        128 * 1024
+    };
+bool platform_erase_flash_sector(uint32_t sector);
+bool platform_write_flash(uint32_t sector_index, uint32_t offset, uint8_t buffer[PLATFORM_FLASH_WRITE_BUFFER_SIZE]);
 void platform_boot_to_main_firmware();
 
 // Configuration customizations based on DIP switch settings

+ 124 - 0
src/ZuluSCSI_bootloader.cpp

@@ -59,6 +59,7 @@ bool find_firmware_image(FsFile &file, char name[MAX_FILE_PATH + 1])
     return false;
 }
 
+#ifndef PLATFORM_FLASH_SECTOR_ERASE
 bool program_firmware(FsFile &file)
 {
     uint32_t fwsize = file.size() - PLATFORM_BOOTLOADER_SIZE;
@@ -102,6 +103,129 @@ bool program_firmware(FsFile &file)
 
     return true;
 }
+#else // PLATFORM_FLASH_SECTOR_ERASE
+bool program_firmware(FsFile &file)
+{
+    uint32_t bootloader_sector_index = 0;
+    uint32_t bootloader_sector_byte_count = 0;
+    const uint32_t map_length = sizeof(platform_flash_sector_map)/sizeof(platform_flash_sector_map[0]);
+    // Find at which sector the bootloader ends so it isn't overwritten
+    for(;;)
+    {
+        if (bootloader_sector_index < map_length)
+        {
+            bootloader_sector_byte_count += platform_flash_sector_map[bootloader_sector_index];
+            if (bootloader_sector_byte_count < PLATFORM_BOOTLOADER_SIZE)
+            {
+                bootloader_sector_index++;
+            }
+            else
+            {
+                break;
+            }    
+        }
+        else
+        {
+            logmsg("Bootloader does not fit in flash");
+            return false;
+        }
+                
+    }
+
+    uint32_t fwsize = file.size();
+    if (fwsize <=  PLATFORM_BOOTLOADER_SIZE )
+    {
+        logmsg("Firmware file size too small: ", fwsize, " bootloader fits in the first : ", PLATFORM_BOOTLOADER_SIZE, " bytes");
+        return false;
+    }
+    fwsize -= PLATFORM_BOOTLOADER_SIZE;
+    
+    // find the last sector the mainline firmware ends
+    uint32_t firmware_sector_start = bootloader_sector_index + 1;
+    uint32_t last_sector_index = firmware_sector_start;
+    uint32_t last_sector_byte_count = 0;
+    for(;;)
+    {
+        if (last_sector_index < map_length)
+        {
+            last_sector_byte_count += platform_flash_sector_map[last_sector_index];
+            if (fwsize > last_sector_byte_count)
+            {
+                last_sector_index++;
+            }
+            else
+            {
+                break;
+            }
+        }
+        else
+        {
+            logmsg("Firmware too large: ", (int) fwsize, 
+                    " space left after the bootloader ",  last_sector_byte_count,
+                    " total flash size ", (int)PLATFORM_FLASH_TOTAL_SIZE);
+            return false;
+        }
+    }
+
+    // Make sure the buffer is aligned to word boundary
+    static uint32_t buffer32[PLATFORM_FLASH_WRITE_BUFFER_SIZE / 4];
+    uint8_t *buffer = (uint8_t*)buffer32;
+
+    if (!file.seek(PLATFORM_BOOTLOADER_SIZE))
+    {
+        logmsg("Seek failed");
+        return false;
+    }
+
+    // Erase the sectors the mainline firmware will be written to
+    for (int i = firmware_sector_start; i <= last_sector_index; i++)
+    {
+        LED_ON();
+        if (!platform_erase_flash_sector(i))
+        {
+            logmsg("Flash failed to erase sector ", i);
+            return false;
+        }
+        LED_OFF();
+    }
+
+    // write the mainline firmware to flash
+    int32_t bytes_read = 0;
+    uint32_t address_offset = 0;
+    for(;;)
+    {
+        if (address_offset / PLATFORM_FLASH_WRITE_BUFFER_SIZE % 2)
+        {
+            LED_ON();
+        }
+        else
+        {
+            LED_OFF();
+        }
+        
+        bytes_read = file.read(buffer, PLATFORM_FLASH_WRITE_BUFFER_SIZE);
+        if ( bytes_read < 0)
+        {
+            logmsg("Firmware file read failed, error code ", (int) bytes_read);
+            return false;
+        }
+        if (!platform_write_flash(address_offset, bytes_read, buffer))
+        {
+            logmsg("Failed to write flash at offset: ", address_offset, " bytes read: ",(int) bytes_read);
+            return false;
+        }
+        if (bytes_read < PLATFORM_FLASH_WRITE_BUFFER_SIZE)
+        {
+            break;
+        }
+        address_offset += bytes_read;
+        
+    }
+    LED_OFF();
+    return true;
+}
+
+#endif // PLATFORM_FLASH_SECTOR_ERASE
 
 static bool mountSDCard()
 {