Merge pull request #305 from FrankBuss/master
adding support to flash an FBI image
This commit is contained in:
commit
2d6100bdbe
|
@ -8,6 +8,7 @@
|
||||||
// License: BSD
|
// License: BSD
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <console.h>
|
#include <console.h>
|
||||||
#include <uart.h>
|
#include <uart.h>
|
||||||
#include <system.h>
|
#include <system.h>
|
||||||
|
@ -23,6 +24,10 @@
|
||||||
#include <net/tftp.h>
|
#include <net/tftp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CSR_SPIFLASH_BASE
|
||||||
|
#include <spiflash.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "sfl.h"
|
#include "sfl.h"
|
||||||
#include "boot.h"
|
#include "boot.h"
|
||||||
|
|
||||||
|
@ -95,6 +100,14 @@ static int check_ack(void)
|
||||||
return ACK_TIMEOUT;
|
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
|
#define MAX_FAILED 5
|
||||||
|
|
||||||
/* Returns 1 if other boot methods should be tried */
|
/* Returns 1 if other boot methods should be tried */
|
||||||
|
@ -165,11 +178,7 @@ int serialboot(void)
|
||||||
char *writepointer;
|
char *writepointer;
|
||||||
|
|
||||||
failed = 0;
|
failed = 0;
|
||||||
writepointer = (char *)(
|
writepointer = (char *) get_uint32(&frame.payload[0]);
|
||||||
((unsigned long)frame.payload[0] << 24)
|
|
||||||
|((unsigned long)frame.payload[1] << 16)
|
|
||||||
|((unsigned long)frame.payload[2] << 8)
|
|
||||||
|((unsigned long)frame.payload[3] << 0));
|
|
||||||
for(i=4;i<frame.length;i++)
|
for(i=4;i<frame.length;i++)
|
||||||
*(writepointer++) = frame.payload[i];
|
*(writepointer++) = frame.payload[i];
|
||||||
if (frame.cmd == SFL_CMD_LOAD)
|
if (frame.cmd == SFL_CMD_LOAD)
|
||||||
|
@ -177,17 +186,39 @@ int serialboot(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SFL_CMD_JUMP: {
|
case SFL_CMD_JUMP: {
|
||||||
unsigned long addr;
|
uint32_t addr;
|
||||||
|
|
||||||
failed = 0;
|
failed = 0;
|
||||||
addr = ((unsigned long)frame.payload[0] << 24)
|
addr = get_uint32(&frame.payload[0]);
|
||||||
|((unsigned long)frame.payload[1] << 16)
|
|
||||||
|((unsigned long)frame.payload[2] << 8)
|
|
||||||
|((unsigned long)frame.payload[3] << 0);
|
|
||||||
uart_write(SFL_ACK_SUCCESS);
|
uart_write(SFL_ACK_SUCCESS);
|
||||||
boot(0, 0, 0, addr);
|
boot(0, 0, 0, addr);
|
||||||
break;
|
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:
|
default:
|
||||||
failed++;
|
failed++;
|
||||||
if(failed == MAX_FAILED) {
|
if(failed == MAX_FAILED) {
|
||||||
|
|
|
@ -20,6 +20,8 @@ struct sfl_frame {
|
||||||
#define SFL_CMD_LOAD 0x01
|
#define SFL_CMD_LOAD 0x01
|
||||||
#define SFL_CMD_JUMP 0x02
|
#define SFL_CMD_JUMP 0x02
|
||||||
#define SFL_CMD_LOAD_NO_CRC 0x03
|
#define SFL_CMD_LOAD_NO_CRC 0x03
|
||||||
|
#define SFL_CMD_FLASH 0x04
|
||||||
|
#define SFL_CMD_REBOOT 0x05
|
||||||
|
|
||||||
/* Replies */
|
/* Replies */
|
||||||
#define SFL_ACK_SUCCESS 'K'
|
#define SFL_ACK_SUCCESS 'K'
|
||||||
|
|
|
@ -59,6 +59,8 @@ sfl_cmd_abort = b"\x00"
|
||||||
sfl_cmd_load = b"\x01"
|
sfl_cmd_load = b"\x01"
|
||||||
sfl_cmd_load_no_crc = b"\x03"
|
sfl_cmd_load_no_crc = b"\x03"
|
||||||
sfl_cmd_jump = b"\x02"
|
sfl_cmd_jump = b"\x02"
|
||||||
|
sfl_cmd_flash = b"\x04"
|
||||||
|
sfl_cmd_reboot = b"\x05"
|
||||||
|
|
||||||
# Replies
|
# Replies
|
||||||
sfl_ack_success = b"K"
|
sfl_ack_success = b"K"
|
||||||
|
@ -127,7 +129,7 @@ class SFLFrame:
|
||||||
|
|
||||||
|
|
||||||
class LiteXTerm:
|
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
|
self.serial_boot = serial_boot
|
||||||
assert not (kernel_image is not None and json_images is not None)
|
assert not (kernel_image is not None and json_images is not None)
|
||||||
self.mem_regions = {}
|
self.mem_regions = {}
|
||||||
|
@ -140,6 +142,8 @@ class LiteXTerm:
|
||||||
self.boot_address = self.mem_regions[list(self.mem_regions.keys())[-1]]
|
self.boot_address = self.mem_regions[list(self.mem_regions.keys())[-1]]
|
||||||
f.close()
|
f.close()
|
||||||
self.no_crc = no_crc
|
self.no_crc = no_crc
|
||||||
|
self.flash = flash
|
||||||
|
self.ignore_download = False
|
||||||
|
|
||||||
self.reader_alive = False
|
self.reader_alive = False
|
||||||
self.writer_alive = False
|
self.writer_alive = False
|
||||||
|
@ -197,6 +201,10 @@ class LiteXTerm:
|
||||||
f.seek(0, 2)
|
f.seek(0, 2)
|
||||||
length = f.tell()
|
length = f.tell()
|
||||||
f.seek(0, 0)
|
f.seek(0, 0)
|
||||||
|
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))
|
print("[LXTERM] Uploading {} to 0x{:08x} ({} bytes)...".format(filename, address, length))
|
||||||
current_address = address
|
current_address = address
|
||||||
position = 0
|
position = 0
|
||||||
|
@ -209,6 +217,9 @@ class LiteXTerm:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
frame = SFLFrame()
|
frame = SFLFrame()
|
||||||
frame_data = f.read(min(remaining, sfl_payload_length))
|
frame_data = f.read(min(remaining, sfl_payload_length))
|
||||||
|
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.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 = current_address.to_bytes(4, "big")
|
||||||
frame.payload += frame_data
|
frame.payload += frame_data
|
||||||
|
@ -230,6 +241,12 @@ class LiteXTerm:
|
||||||
frame.payload = int(self.boot_address, 16).to_bytes(4, "big")
|
frame.payload = int(self.boot_address, 16).to_bytes(4, "big")
|
||||||
self.send_frame(frame)
|
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):
|
def detect_prompt(self, data):
|
||||||
if len(data):
|
if len(data):
|
||||||
self.prompt_detect_buffer = self.prompt_detect_buffer[1:] + data
|
self.prompt_detect_buffer = self.prompt_detect_buffer[1:] + data
|
||||||
|
@ -249,11 +266,19 @@ class LiteXTerm:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def answer_magic(self):
|
def answer_magic(self):
|
||||||
|
if self.ignore_download:
|
||||||
|
self.ignore_download = False
|
||||||
|
return
|
||||||
print("[LXTERM] Received firmware download request from the device.")
|
print("[LXTERM] Received firmware download request from the device.")
|
||||||
if(len(self.mem_regions)):
|
if(len(self.mem_regions)):
|
||||||
self.port.write(sfl_magic_ack)
|
self.port.write(sfl_magic_ack)
|
||||||
for filename, base in self.mem_regions.items():
|
for filename, base in self.mem_regions.items():
|
||||||
self.upload(filename, int(base, 16))
|
self.upload(filename, int(base, 16))
|
||||||
|
if self.flash:
|
||||||
|
# ignore next download request to do a reboot to the flashed image
|
||||||
|
self.ignore_download = True
|
||||||
|
self.reboot()
|
||||||
|
else:
|
||||||
self.boot()
|
self.boot()
|
||||||
print("[LXTERM] Done.");
|
print("[LXTERM] Done.");
|
||||||
|
|
||||||
|
@ -334,14 +359,16 @@ def _get_args():
|
||||||
parser.add_argument("--kernel-adr", default="0x40000000", help="kernel address")
|
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("--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("--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()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = _get_args()
|
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.open(args.port, int(float(args.speed)))
|
||||||
term.console.configure()
|
term.console.configure()
|
||||||
|
|
||||||
term.start()
|
term.start()
|
||||||
term.join(True)
|
term.join(True)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue