adding support to flash an FBI image
authorfb@frank-buss.de <fb@frank-buss.de>
Fri, 8 Nov 2019 16:16:28 +0000 (17:16 +0100)
committerfb@frank-buss.de <fb@frank-buss.de>
Fri, 8 Nov 2019 16:16:28 +0000 (17:16 +0100)
litex/soc/software/bios/boot.c
litex/soc/software/bios/sfl.h
litex/tools/litex_term.py

index af05c3c1de58322d040ed784a99549f58c61e0eb..f1b22966d0e458f3c0a567dd7ca595c543dfe10b 100644 (file)
@@ -8,6 +8,7 @@
 // License: BSD
 
 #include <stdio.h>
+#include <stdint.h>
 #include <console.h>
 #include <uart.h>
 #include <system.h>
 #include <net/tftp.h>
 #endif
 
+#ifdef CSR_SPIFLASH_BASE
+#include <spiflash.h>
+#endif
+
 #include "sfl.h"
 #include "boot.h"
 
@@ -95,6 +100,14 @@ static int check_ack(void)
        return ACK_TIMEOUT;
 }
 
+static uint32_t get_uint32(unsigned char* data)
+{
+       return ((uint32_t) data[0] << 24) |
+        ((uint32_t) data[1] << 16) |
+               ((uint32_t) data[2] << 8) |
+               (uint32_t) data[3];
+}
+
 #define MAX_FAILED 5
 
 /* Returns 1 if other boot methods should be tried */
@@ -165,11 +178,7 @@ int serialboot(void)
                                char *writepointer;
 
                                failed = 0;
-                               writepointer = (char *)(
-                                        ((unsigned long)frame.payload[0] << 24)
-                                       |((unsigned long)frame.payload[1] << 16)
-                                       |((unsigned long)frame.payload[2] <<  8)
-                                       |((unsigned long)frame.payload[3] <<  0));
+                               writepointer = (char *) get_uint32(&frame.payload[0]);
                                for(i=4;i<frame.length;i++)
                                        *(writepointer++) = frame.payload[i];
                                if (frame.cmd == SFL_CMD_LOAD)
@@ -177,17 +186,39 @@ int serialboot(void)
                                break;
                        }
                        case SFL_CMD_JUMP: {
-                               unsigned long addr;
+                               uint32_t addr;
 
                                failed = 0;
-                               addr =   ((unsigned long)frame.payload[0] << 24)
-                                       |((unsigned long)frame.payload[1] << 16)
-                                       |((unsigned long)frame.payload[2] <<  8)
-                                       |((unsigned long)frame.payload[3] <<  0);
+                               addr = get_uint32(&frame.payload[0]);
                                uart_write(SFL_ACK_SUCCESS);
                                boot(0, 0, 0, addr);
                                break;
                        }
+                       case SFL_CMD_FLASH: {
+#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE)
+                               uint32_t addr;
+
+                               failed = 0;
+                               addr = get_uint32(&frame.payload[0]);
+                
+                               for (i = 4; i < frame.length; i++) {
+                                       // erase page at sector boundaries before writing
+                                       if ((addr & (SPIFLASH_SECTOR_SIZE - 1)) == 0) {
+                                               erase_flash_sector(addr);
+                                       }
+                                       write_to_flash(addr, &frame.payload[i], 1);
+                                       addr++;
+                               }
+                               uart_write(SFL_ACK_SUCCESS);
+#endif
+                               break;
+                       }
+                       case SFL_CMD_REBOOT:
+#ifdef CSR_CTRL_BASE
+                               uart_write(SFL_ACK_SUCCESS);
+                               ctrl_reset_write(1);
+#endif
+                               break;
                        default:
                                failed++;
                                if(failed == MAX_FAILED) {
index 32041bd5bbb4ed26920831b1409703ad5ca65f87..cca67f6f1911fbd2efc6c731cc17047e7ec9b408 100644 (file)
@@ -20,6 +20,8 @@ struct sfl_frame {
 #define SFL_CMD_LOAD           0x01
 #define SFL_CMD_JUMP           0x02
 #define SFL_CMD_LOAD_NO_CRC    0x03
+#define SFL_CMD_FLASH          0x04
+#define SFL_CMD_REBOOT         0x05
 
 /* Replies */
 #define SFL_ACK_SUCCESS                'K'
index 39fb60aa185a0d9976f7f75bbe25ca45186bf9bc..9e20530a36420082e9f5c9d1f4ba4b2ddd4d775b 100755 (executable)
@@ -59,6 +59,8 @@ sfl_cmd_abort       = b"\x00"
 sfl_cmd_load        = b"\x01"
 sfl_cmd_load_no_crc = b"\x03"
 sfl_cmd_jump        = b"\x02"
+sfl_cmd_flash       = b"\x04"
+sfl_cmd_reboot      = b"\x05"
 
 # Replies
 sfl_ack_success  = b"K"
@@ -127,7 +129,7 @@ class SFLFrame:
 
 
 class LiteXTerm:
-    def __init__(self, serial_boot, kernel_image, kernel_address, json_images, no_crc):
+    def __init__(self, serial_boot, kernel_image, kernel_address, json_images, no_crc, flash):
         self.serial_boot = serial_boot
         assert not (kernel_image is not None and json_images is not None)
         self.mem_regions = {}
@@ -140,6 +142,8 @@ class LiteXTerm:
             self.boot_address = self.mem_regions[list(self.mem_regions.keys())[-1]]
             f.close()
         self.no_crc = no_crc
+        self.flash = flash
+        self.ignore_download = False
 
         self.reader_alive = False
         self.writer_alive = False
@@ -197,8 +201,12 @@ class LiteXTerm:
         f.seek(0, 2)
         length = f.tell()
         f.seek(0, 0)
-        print("[LXTERM] Uploading {} to 0x{:08x} ({} bytes)...".format(filename, address, length))
-        current_address = address
+        if self.flash:
+            print("[LXTERM] Flashing {} ({} bytes)...".format(filename, length))
+            current_address = 0
+        else:
+            print("[LXTERM] Uploading {} to 0x{:08x} ({} bytes)...".format(filename, address, length))
+            current_address = address
         position = 0
         start = time.time()
         remaining = length
@@ -209,7 +217,10 @@ class LiteXTerm:
             sys.stdout.flush()
             frame = SFLFrame()
             frame_data = f.read(min(remaining, sfl_payload_length))
-            frame.cmd = sfl_cmd_load if not self.no_crc else sfl_cmd_load_no_crc
+            if self.flash:
+                frame.cmd = sfl_cmd_flash
+            else:
+                frame.cmd = sfl_cmd_load if not self.no_crc else sfl_cmd_load_no_crc
             frame.payload = current_address.to_bytes(4, "big")
             frame.payload += frame_data
             if self.send_frame(frame) == 0:
@@ -230,6 +241,12 @@ class LiteXTerm:
         frame.payload = int(self.boot_address, 16).to_bytes(4, "big")
         self.send_frame(frame)
 
+    def reboot(self):
+        print("[LXTERM] Rebooting the device.")
+        frame = SFLFrame()
+        frame.cmd = sfl_cmd_reboot
+        self.send_frame(frame)
+
     def detect_prompt(self, data):
         if len(data):
             self.prompt_detect_buffer = self.prompt_detect_buffer[1:] + data
@@ -249,12 +266,20 @@ class LiteXTerm:
             return False
 
     def answer_magic(self):
+        if self.ignore_download:
+            self.ignore_download = False
+            return
         print("[LXTERM] Received firmware download request from the device.")
         if(len(self.mem_regions)):
             self.port.write(sfl_magic_ack)
         for filename, base in self.mem_regions.items():
             self.upload(filename, int(base, 16))
-        self.boot()
+        if self.flash:
+            # ignore next download request to do a reboot to the flashed image
+            self.ignore_download = True
+            self.reboot()
+        else:
+            self.boot()
         print("[LXTERM] Done.");
 
     def reader(self):
@@ -334,14 +359,16 @@ def _get_args():
     parser.add_argument("--kernel-adr", default="0x40000000", help="kernel address")
     parser.add_argument("--images", default=None, help="json description of the images to load to memory")
     parser.add_argument("--no-crc", default=False, action='store_true', help="disable CRC check (speedup serialboot)")
+    parser.add_argument("--flash", default=False, action='store_true', help="flash data with serialboot command")
     return parser.parse_args()
 
 
 def main():
     args = _get_args()
-    term = LiteXTerm(args.serial_boot, args.kernel, args.kernel_adr, args.images, args.no_crc)
+    term = LiteXTerm(args.serial_boot, args.kernel, args.kernel_adr, args.images, args.no_crc, args.flash)
     term.open(args.port, int(float(args.speed)))
     term.console.configure()
+
     term.start()
     term.join(True)