|
@@ -4,11 +4,19 @@
|
|
|
#include "io.h"
|
|
|
#include "spiflash.h"
|
|
|
#include "ff.h"
|
|
|
+#include "boardinfo_fpga.h"
|
|
|
#include <stdio.h>
|
|
|
|
|
|
#define SPIROM_DUAL_MODE 1
|
|
|
|
|
|
-void __hot romcopy_download(void *dst, size_t offset, size_t len)
|
|
|
+struct board_info board_info;
|
|
|
+__dram_noinit union board_info_block board_info_raw;
|
|
|
+static __dram_noinit union board_info_block board_info_rom;
|
|
|
+volatile bool do_update_boardinfo;
|
|
|
+
|
|
|
+static void boardinfo_init(void);
|
|
|
+
|
|
|
+static void __hot romcopy_download_absolute(void *dst, size_t offset, size_t len)
|
|
|
{
|
|
|
unsigned int cmd;
|
|
|
unsigned int flags = ROMCOPY_SPI_CMDLEN(5) | ROMCOPY_WRITE_RAM;
|
|
@@ -24,10 +32,15 @@ void __hot romcopy_download(void *dst, size_t offset, size_t len)
|
|
|
}
|
|
|
|
|
|
ROMCOPY_RAMADDR = (size_t)dst;
|
|
|
- ROMCOPY_ROMCMD = __rom_offset + offset + (cmd << 24);
|
|
|
+ ROMCOPY_ROMCMD = offset + (cmd << 24);
|
|
|
ROMCOPY_DATALEN = len | flags;
|
|
|
}
|
|
|
|
|
|
+void __hot romcopy_download(void *dst, size_t offset, size_t len)
|
|
|
+{
|
|
|
+ romcopy_download_absolute(dst, __rom_offset + offset, len);
|
|
|
+}
|
|
|
+
|
|
|
void __hot romcopy_bzero(void *dst, size_t len)
|
|
|
{
|
|
|
if (!len)
|
|
@@ -38,45 +51,22 @@ void __hot romcopy_bzero(void *dst, size_t len)
|
|
|
ROMCOPY_DATALEN = len | ROMCOPY_ZERO_BUFFER | ROMCOPY_WRITE_RAM;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Read unique serial number programmed into ROM
|
|
|
- *
|
|
|
- */
|
|
|
-char __bss_hot rom_serial_str[16];
|
|
|
-qword_t __bss_hot rom_serial;
|
|
|
-
|
|
|
-static __must_inline void rom_read_serial(void)
|
|
|
+static void __hot romcopy_download_boardinfo(void *dst)
|
|
|
{
|
|
|
- ROMCOPY_ROMCMD = ROM_READ_UNIQUE_ID << 24;
|
|
|
- ROMCOPY_DATALEN = ROMCOPY_SPI_CMDLEN(5) | ROMCOPY_SPI_MORE;
|
|
|
- waitfor(ROMCOPY_IRQ);
|
|
|
-
|
|
|
- ROMCOPY_DATALEN = ROMCOPY_SPI_CMDLEN(4) | ROMCOPY_SPI_MORE;
|
|
|
- waitfor(ROMCOPY_IRQ);
|
|
|
-
|
|
|
- rom_serial.l[1] = ROMCOPY_INPUT;
|
|
|
- ROMCOPY_DATALEN = ROMCOPY_SPI_CMDLEN(4);
|
|
|
- waitfor(ROMCOPY_IRQ);
|
|
|
-
|
|
|
- rom_serial.l[0] = ROMCOPY_INPUT;
|
|
|
+ romcopy_download_absolute(dst, BOARDINFO_ADDR, BOARDINFO_SIZE);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Convert the ROM serial number to a hex string and poke it into the
|
|
|
- * USB descriptor "ROM". Used to use base36, but this has to be done
|
|
|
- * very early, and it has turned out that making it consistent with
|
|
|
- * what one can easily get out of a debugger is really useful.
|
|
|
- *
|
|
|
- * Doing this as early as possible means a much better chance to see
|
|
|
- * the proper serial number during USB enumeration, so doing it
|
|
|
- * immediately after SPI ROM conditioning is a great time.
|
|
|
+ * Convert the MAC address in board_info_raw into a hexadecimal string
|
|
|
+ * and set it as the USB serial number.
|
|
|
*/
|
|
|
-static __must_inline void rom_mangle_serial(void)
|
|
|
+static inline void rom_mangle_serial(void)
|
|
|
{
|
|
|
volatile uint32_t *udp = &usbdesc_rom[2];
|
|
|
+ const uint8_t *mac = board_info.mac[0];
|
|
|
|
|
|
- for (int i = 7; i >= 0; i--) {
|
|
|
- unsigned int v = rom_serial.b[i];
|
|
|
+ for (int i = 0; i < 6; i++) {
|
|
|
+ unsigned int v = *mac++;
|
|
|
unsigned int c;
|
|
|
|
|
|
c = (v >> 4)+'0';
|
|
@@ -91,19 +81,12 @@ static __must_inline void rom_mangle_serial(void)
|
|
|
|
|
|
udp[2] = c;
|
|
|
|
|
|
- udp += 4;
|
|
|
+ /* Skip dash between third and fourth byte */
|
|
|
+ udp += (i == 2) ? 6 : 4;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void rom_print_serial(void)
|
|
|
-{
|
|
|
- /* Print the ROM serial when we actually can */
|
|
|
- con_printf("ROM serial: %08X%08X (%08x-%08x)\n",
|
|
|
- rom_serial.l[1], rom_serial.l[0],
|
|
|
- rom_serial.l[1], rom_serial.l[0]);
|
|
|
-}
|
|
|
-
|
|
|
-static __must_inline void romcopy_config_flash(void)
|
|
|
+static inline __hot void romcopy_config_flash(void)
|
|
|
{
|
|
|
/* Enable writing volatile status register bits */
|
|
|
ROMCOPY_ROMCMD = ROM_VOLATILE_SR_WRITE_ENABLE << 24;
|
|
@@ -132,18 +115,25 @@ IRQHANDLER(romcopy,0)
|
|
|
/* Condition flash ROM */
|
|
|
romcopy_config_flash();
|
|
|
|
|
|
- /* Read serial number */
|
|
|
- rom_read_serial();
|
|
|
-
|
|
|
/* Start copy DRAM data */
|
|
|
len = __dram_init_end - __dram_init_start;
|
|
|
romcopy_download(__dram_init_start, 0, len);
|
|
|
-
|
|
|
- /* Convert serial number and export to USB */
|
|
|
- rom_mangle_serial();
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
+ /* Copy board_info from ROM into board_info_raw */
|
|
|
+ romcopy_download_boardinfo(&board_info_raw);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3:
|
|
|
+ /* Copy reference copy of board_info ROM block into board_info_rom */
|
|
|
+ romcopy_download_boardinfo(&board_info_rom);
|
|
|
+
|
|
|
+ /* Create sanitized board_info structure */
|
|
|
+ boardinfo_init();
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4:
|
|
|
/* Zero .dram.bss */
|
|
|
len = __dram_bss_end - __dram_bss_start;
|
|
|
romcopy_bzero(__dram_bss_start, len);
|
|
@@ -303,12 +293,10 @@ static const struct spiflash_param max80_spiflash_param = {
|
|
|
|
|
|
static void rom_spiflash_init(struct spiflash *flash)
|
|
|
{
|
|
|
- static char target[] = "MAX80 v?";
|
|
|
-
|
|
|
memset(flash, 0, sizeof *flash);
|
|
|
- target[sizeof target - 2] = SYS_BOARDFPGA + '0';
|
|
|
- flash->target = target;
|
|
|
+ flash->target = board_info.version_str;
|
|
|
flash->param = &max80_spiflash_param;
|
|
|
+ flash->ops = &max80_spiflash_ops;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -423,3 +411,68 @@ void rom_flash_from_sdcard(void)
|
|
|
|
|
|
reset(SYS_RESET_RECONFIG);
|
|
|
}
|
|
|
+
|
|
|
+static bool boardinfo_valid(const struct board_info *bi)
|
|
|
+{
|
|
|
+ size_t len = bi->len;
|
|
|
+
|
|
|
+ /* XXX: check CRC */
|
|
|
+
|
|
|
+ return len >= 16 && len <= BOARDINFO_SIZE &&
|
|
|
+ bi->magic[0] == BOARDINFO_MAGIC_1 &&
|
|
|
+ bi->magic[1] == BOARDINFO_MAGIC_2;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Initialize the board_info structure from board_info_raw
|
|
|
+ */
|
|
|
+static void boardinfo_init(void)
|
|
|
+{
|
|
|
+ const struct board_info *src = &board_info_raw.i;
|
|
|
+ size_t len = src->len;
|
|
|
+
|
|
|
+ if (!boardinfo_valid(src))
|
|
|
+ len = 0; /* Bad structure */
|
|
|
+
|
|
|
+ size_t rlen = Min(len, sizeof board_info);
|
|
|
+ memcpy(&board_info, src, rlen);
|
|
|
+
|
|
|
+ /* Erase any fields not included in ROM */
|
|
|
+ if (rlen < len)
|
|
|
+ memset((char *)&board_info + rlen, 0, sizeof board_info - rlen);
|
|
|
+
|
|
|
+ /* Convert serial number and export to USB */
|
|
|
+ rom_mangle_serial();
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Update board_info if board_info_raw has changed, and write it to flash
|
|
|
+ * in that case.
|
|
|
+ */
|
|
|
+void rom_update_boardinfo(void)
|
|
|
+{
|
|
|
+ struct spiflash max80_flash;
|
|
|
+ union board_info_block *src = &board_info_raw;
|
|
|
+
|
|
|
+ do_update_boardinfo = false;
|
|
|
+
|
|
|
+ if (!boardinfo_valid(&src->i)) {
|
|
|
+ con_printf("[ROM] bad board_info received\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!memcmp(&board_info_rom, src, src->i.len)) {
|
|
|
+ con_printf("[ROM] board_info in flash unchanged\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ con_printf("[ROM] updating board_info in flash\n");
|
|
|
+
|
|
|
+ memset(&src->b[src->i.len], 0xff, BOARDINFO_SIZE - src->i.len);
|
|
|
+
|
|
|
+ rom_spiflash_init(&max80_flash);
|
|
|
+ spiflash_flash_data(&max80_flash, BOARDINFO_ADDR, src, BOARDINFO_SIZE);
|
|
|
+ romcopy_download_boardinfo(&board_info_rom);
|
|
|
+ boardinfo_init();
|
|
|
+ waitfor(ROMCOPY_IRQ);
|
|
|
+}
|