Browse Source

fw: propagate board_info from ESP32 to FPGA

H. Peter Anvin 2 years ago
parent
commit
969d145878

+ 5 - 0
common/boardinfo.h

@@ -20,6 +20,11 @@ struct board_info {
     uint8_t mac[IBLK_MAX_MAC_ADDR][6];
 };
 
+union board_info_block {
+    struct board_info i;
+    uint8_t b[BOARDINFO_SIZE];
+};
+
 extern_c struct board_info board_info;
 
 #endif

+ 3 - 0
common/esplink.h

@@ -90,6 +90,8 @@ struct esplink_head {
     } rb;
 
     char signature[MAX_SIGNATURE_LEN]; /* Human-readable signature string */
+
+    const void *board_info;	/* board_info structure pointer */
 };
 
 #define EL_DIRQ_UNDERRUN	0	/* Local interrupt/status bit */
@@ -97,6 +99,7 @@ struct esplink_head {
 #define EL_DIRQ_RINGBUF		2
 #define EL_DIRQ_TIME		3
 #define EL_DIRQ_DONE		4	/* Some operation completed */
+#define EL_DIRQ_BOARDINFO	5	/* board_info structure updated */
 
 #define EL_UIRQ_WREN		0	/* Remote write enable bit, not IRQ */
 #define EL_UIRQ_READY		1

+ 1 - 3
common/matchver.c

@@ -11,9 +11,7 @@
  * Any control character is treated as end of string.
  */
 
-#include <stdlib.h>
-#include <stdbool.h>
-#include <inttypes.h>
+#include "matchver.h"
 
 static int flag_val(char c)
 {

+ 10 - 0
common/matchver.h

@@ -0,0 +1,10 @@
+#ifndef MATCHVER_H
+#define MATCHVER_H
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+bool match_version(const char *version, const char *pattern);
+
+#endif /* MATCHVER_H */

+ 1 - 1
esp32/flashesp.pl

@@ -140,7 +140,7 @@ sub run_esptool($$$$@)
     my($port,$common_options,$cmd,$cmd_options,@args) = @_;
 
     my @espcmd = unquote_cmd($esptool);
-    push(@espcmd, '--p', $port);
+    push(@espcmd, '--port', $port);
     push(@espcmd, hash2opt($common_options));
     push(@espcmd, unquote_cmd($cmd));
     push(@espcmd, hash2opt($cmd_options));

+ 11 - 12
esp32/max80/boardinfo.c

@@ -9,11 +9,6 @@
 
 #define BOARDINFO_ADDR	0	/* Flash address on ESP */
 
-union board_info_block {
-    struct board_info i;
-    uint8_t b[BOARDINFO_SIZE];
-};
-
 static const union board_info_block *board_info_flash;
 struct board_info DRAM_ATTR board_info;
 
@@ -45,7 +40,7 @@ static void board_info_unmap(void)
 int board_info_init(void)
 {
     int err = -1;
-    uint32_t crc;
+    uint32_t crc, bif_crc;
     const union board_info_block *bif;
 
     bif = board_info_map();
@@ -60,16 +55,20 @@ int board_info_init(void)
 
     memcpy(&board_info, bif, sizeof board_info);
 
+    bif_crc = board_info.crc;
     board_info.crc = 0;
     crc = crc32_le(0, (const uint8_t *)&board_info, 16);
     crc = crc32_le(crc, &bif->b[16], bif->i.len - 16);
-    board_info.crc = bif->i.crc;
+    board_info.crc = bif_crc;
 
-    if (crc != bif->i.crc)
+    if (crc != bif_crc) {
+	printf("[PCB]  Bad board_info crc %08x calculated %08x\n",
+	       bif_crc, crc);
 	goto bad;
+    }
+
+    printf("[PCB]  Board ID/version: %s\n", board_info.version_str);
 
-    printf("Board ID/version: %s\n", board_info.version_str);
-    
     err = 0;
     goto done;
 
@@ -82,7 +81,7 @@ bad:
 	 * is allowed to simplify the initial programming.
 	 * Convert it to a proper structure and write it back.
 	 */
-	printf("NOTE: updating board information block in flash\n");
+	printf("[PCB]  updating board information block in flash\n");
 	return board_info_set((const char *)board_info_flash->b);
     }
 
@@ -103,7 +102,7 @@ static int board_info_generate(const char *board_id_string)
 {
     memset(&board_info, 0, sizeof board_info);
     board_info.magic[0] = BOARDINFO_MAGIC_1;
-    board_info.magic[1] = BOARDINFO_MAGIC_1;
+    board_info.magic[1] = BOARDINFO_MAGIC_2;
     board_info.len      = sizeof board_info;
 
     strncpy(board_info.version_str, board_id_string,

+ 8 - 1
esp32/max80/esplink.c

@@ -8,6 +8,7 @@
 #include "common.h"
 #include "esplink.h"
 #include "fpga.h"
+#include "boardinfo_esp.h"
 
 struct esplink_ringbuf_ptrs {
     const volatile struct esplink_ptrs_dstr *d;
@@ -86,7 +87,7 @@ void esplink_init(void)
  */
 void esplink_start(const struct esplink_head *head)
 {
-    struct fpga_iov iov[3];
+    struct fpga_iov iov[4];
     static unsigned int gen_count;
     static bool started = false;
 
@@ -127,6 +128,12 @@ void esplink_start(const struct esplink_head *head)
     iov[2].wdata = (void *)elink.rb.d; /* rb.d is correct */
     iov[2].len   = dptr_size;
 
+    /* Update board_info on the FPGA */
+    iov[3].cmd   = FPGA_CMD_WR | FPGA_CMD_IRQ(EL_DIRQ_BOARDINFO);
+    iov[3].addr  = head->board_info;
+    iov[3].wdata = &board_info;
+    iov[3].len   = sizeof board_info;
+
     fpga_iov(iov, ARRAY_SIZE(iov));
     memcpy((void *)elink.rb.u, (void *)elink.rb.d, dptr_size);
 

+ 3 - 3
esp32/max80/max80.ino

@@ -111,7 +111,6 @@ static void init_hw()
 
 void setup() {
     const char *fwdate = __DATE__ " " __TIME__;
-    printf("[START] MAX80 firmware compiled on %s\n", fwdate);
     init_hw();
 
     // Enable external PSRAM for heap
@@ -121,8 +120,9 @@ void setup() {
     TTY::init();
     heap_info();
 
-    printf("[PCB]  MAX80 board version: %u\n", max80_board_version);
-    setenv_ul("status.max80.hw.ver", max80_board_version);
+    printf("[FW]   MAX80 firmware compiled on %s\n", fwdate);
+    printf("[PCB]  MAX80 board version: %s\n", board_info.version_str);
+    setenv_cond("status.max80.hw.ver", board_info.version_str + 7);
     Serial.println("MAX80 start");
 
     init_config();

BIN
esp32/output/max80.ino.bin


+ 2 - 2
fpga/max80.qpf

@@ -19,12 +19,12 @@
 #
 # Quartus Prime
 # Version 21.1.0 Build 842 10/21/2021 SJ Lite Edition
-# Date created = 12:16:48  August 18, 2022
+# Date created = 17:39:42  August 18, 2022
 #
 # -------------------------------------------------------------------------- #
 
 QUARTUS_VERSION = "21.1"
-DATE = "12:16:48  August 18, 2022"
+DATE = "17:39:42  August 18, 2022"
 
 # Revisions
 

BIN
fpga/output/bypass.jic


BIN
fpga/output/bypass.rpd.gz


BIN
fpga/output/max80.fw


BIN
fpga/output/v1.fw


BIN
fpga/output/v1.jic


BIN
fpga/output/v1.rbf.gz


BIN
fpga/output/v1.rpd.gz


BIN
fpga/output/v1.sof


BIN
fpga/output/v1.svf.gz


BIN
fpga/output/v1.xsvf.gz


BIN
fpga/output/v2.fw


BIN
fpga/output/v2.jic


BIN
fpga/output/v2.rbf.gz


BIN
fpga/output/v2.rpd.gz


BIN
fpga/output/v2.sof


BIN
fpga/output/v2.svf.gz


BIN
fpga/output/v2.xsvf.gz


+ 1 - 1
fpga/usb/usb_desc.conf

@@ -11,7 +11,7 @@ my $vendor_id    = word(0x4680); # was: word(0x1d50); [OpenMoko]
 my $device_id    = word(0x0881); # was: word(0x6149); [free public allocations]
 my $version_id   = word(0x0100);
 
-my $serial       = usb_serial('SerialNumberHere'); # 16 characters
+my $serial       = usb_serial('XXXXXX-XXXXXX'); # 12 characters
 my $manufacturer = usb_string(''   => 'Peter & Per');
 my $product      = usb_string(''   => 'MAX80 I/O card for ABC');
 

+ 261 - 267
fpga/usb/usb_desc.v

@@ -18,340 +18,334 @@ module usb_desc_rom (
 	reg [7:0] rom [0:511];
 
 	initial begin
-		rom[9'h000] = 8'h22;
+		rom[9'h000] = 8'h1c;
 		rom[9'h001] = 8'h03;
-		rom[9'h002] = 8'h53;
+		rom[9'h002] = 8'h58;
 		rom[9'h003] = 8'h00;
-		rom[9'h004] = 8'h65;
+		rom[9'h004] = 8'h58;
 		rom[9'h005] = 8'h00;
-		rom[9'h006] = 8'h72;
+		rom[9'h006] = 8'h58;
 		rom[9'h007] = 8'h00;
-		rom[9'h008] = 8'h69;
+		rom[9'h008] = 8'h58;
 		rom[9'h009] = 8'h00;
-		rom[9'h00a] = 8'h61;
+		rom[9'h00a] = 8'h58;
 		rom[9'h00b] = 8'h00;
-		rom[9'h00c] = 8'h6c;
+		rom[9'h00c] = 8'h58;
 		rom[9'h00d] = 8'h00;
-		rom[9'h00e] = 8'h4e;
+		rom[9'h00e] = 8'h2d;
 		rom[9'h00f] = 8'h00;
-		rom[9'h010] = 8'h75;
+		rom[9'h010] = 8'h58;
 		rom[9'h011] = 8'h00;
-		rom[9'h012] = 8'h6d;
+		rom[9'h012] = 8'h58;
 		rom[9'h013] = 8'h00;
-		rom[9'h014] = 8'h62;
+		rom[9'h014] = 8'h58;
 		rom[9'h015] = 8'h00;
-		rom[9'h016] = 8'h65;
+		rom[9'h016] = 8'h58;
 		rom[9'h017] = 8'h00;
-		rom[9'h018] = 8'h72;
+		rom[9'h018] = 8'h58;
 		rom[9'h019] = 8'h00;
-		rom[9'h01a] = 8'h48;
+		rom[9'h01a] = 8'h58;
 		rom[9'h01b] = 8'h00;
-		rom[9'h01c] = 8'h65;
-		rom[9'h01d] = 8'h00;
-		rom[9'h01e] = 8'h72;
-		rom[9'h01f] = 8'h00;
-		rom[9'h020] = 8'h65;
+		rom[9'h01c] = 8'h12;
+		rom[9'h01d] = 8'h01;
+		rom[9'h01e] = 8'h01;
+		rom[9'h01f] = 8'h01;
+		rom[9'h020] = 8'h00;
 		rom[9'h021] = 8'h00;
-		rom[9'h022] = 8'h12;
-		rom[9'h023] = 8'h01;
-		rom[9'h024] = 8'h01;
-		rom[9'h025] = 8'h01;
-		rom[9'h026] = 8'h00;
-		rom[9'h027] = 8'h00;
+		rom[9'h022] = 8'h00;
+		rom[9'h023] = 8'h08;
+		rom[9'h024] = 8'h80;
+		rom[9'h025] = 8'h46;
+		rom[9'h026] = 8'h81;
+		rom[9'h027] = 8'h08;
 		rom[9'h028] = 8'h00;
-		rom[9'h029] = 8'h08;
-		rom[9'h02a] = 8'h80;
-		rom[9'h02b] = 8'h46;
-		rom[9'h02c] = 8'h81;
-		rom[9'h02d] = 8'h08;
-		rom[9'h02e] = 8'h00;
-		rom[9'h02f] = 8'h01;
-		rom[9'h030] = 8'h02;
-		rom[9'h031] = 8'h03;
-		rom[9'h032] = 8'h01;
+		rom[9'h029] = 8'h01;
+		rom[9'h02a] = 8'h02;
+		rom[9'h02b] = 8'h03;
+		rom[9'h02c] = 8'h01;
+		rom[9'h02d] = 8'h01;
+		rom[9'h02e] = 8'h09;
+		rom[9'h02f] = 8'h02;
+		rom[9'h030] = 8'h8d;
+		rom[9'h031] = 8'h00;
+		rom[9'h032] = 8'h04;
 		rom[9'h033] = 8'h01;
-		rom[9'h034] = 8'h09;
-		rom[9'h035] = 8'h02;
-		rom[9'h036] = 8'h8d;
-		rom[9'h037] = 8'h00;
-		rom[9'h038] = 8'h04;
-		rom[9'h039] = 8'h01;
-		rom[9'h03a] = 8'h04;
-		rom[9'h03b] = 8'hc0;
-		rom[9'h03c] = 8'hfa;
-		rom[9'h03d] = 8'h08;
-		rom[9'h03e] = 8'h0b;
-		rom[9'h03f] = 8'h00;
-		rom[9'h040] = 8'h02;
-		rom[9'h041] = 8'h02;
-		rom[9'h042] = 8'h02;
-		rom[9'h043] = 8'h00;
-		rom[9'h044] = 8'h05;
-		rom[9'h045] = 8'h09;
-		rom[9'h046] = 8'h04;
-		rom[9'h047] = 8'h00;
-		rom[9'h048] = 8'h00;
-		rom[9'h049] = 8'h01;
-		rom[9'h04a] = 8'h02;
-		rom[9'h04b] = 8'h02;
-		rom[9'h04c] = 8'h00;
+		rom[9'h034] = 8'h04;
+		rom[9'h035] = 8'hc0;
+		rom[9'h036] = 8'hfa;
+		rom[9'h037] = 8'h08;
+		rom[9'h038] = 8'h0b;
+		rom[9'h039] = 8'h00;
+		rom[9'h03a] = 8'h02;
+		rom[9'h03b] = 8'h02;
+		rom[9'h03c] = 8'h02;
+		rom[9'h03d] = 8'h00;
+		rom[9'h03e] = 8'h05;
+		rom[9'h03f] = 8'h09;
+		rom[9'h040] = 8'h04;
+		rom[9'h041] = 8'h00;
+		rom[9'h042] = 8'h00;
+		rom[9'h043] = 8'h01;
+		rom[9'h044] = 8'h02;
+		rom[9'h045] = 8'h02;
+		rom[9'h046] = 8'h00;
+		rom[9'h047] = 8'h05;
+		rom[9'h048] = 8'h05;
+		rom[9'h049] = 8'h24;
+		rom[9'h04a] = 8'h00;
+		rom[9'h04b] = 8'h20;
+		rom[9'h04c] = 8'h01;
 		rom[9'h04d] = 8'h05;
-		rom[9'h04e] = 8'h05;
-		rom[9'h04f] = 8'h24;
-		rom[9'h050] = 8'h00;
-		rom[9'h051] = 8'h20;
-		rom[9'h052] = 8'h01;
-		rom[9'h053] = 8'h05;
-		rom[9'h054] = 8'h24;
-		rom[9'h055] = 8'h01;
-		rom[9'h056] = 8'h03;
-		rom[9'h057] = 8'h01;
-		rom[9'h058] = 8'h04;
-		rom[9'h059] = 8'h24;
-		rom[9'h05a] = 8'h02;
-		rom[9'h05b] = 8'h06;
+		rom[9'h04e] = 8'h24;
+		rom[9'h04f] = 8'h01;
+		rom[9'h050] = 8'h03;
+		rom[9'h051] = 8'h01;
+		rom[9'h052] = 8'h04;
+		rom[9'h053] = 8'h24;
+		rom[9'h054] = 8'h02;
+		rom[9'h055] = 8'h06;
+		rom[9'h056] = 8'h05;
+		rom[9'h057] = 8'h24;
+		rom[9'h058] = 8'h06;
+		rom[9'h059] = 8'h00;
+		rom[9'h05a] = 8'h01;
+		rom[9'h05b] = 8'h07;
 		rom[9'h05c] = 8'h05;
-		rom[9'h05d] = 8'h24;
-		rom[9'h05e] = 8'h06;
-		rom[9'h05f] = 8'h00;
-		rom[9'h060] = 8'h01;
-		rom[9'h061] = 8'h07;
-		rom[9'h062] = 8'h05;
-		rom[9'h063] = 8'h82;
-		rom[9'h064] = 8'h03;
-		rom[9'h065] = 8'h40;
-		rom[9'h066] = 8'h00;
-		rom[9'h067] = 8'h02;
-		rom[9'h068] = 8'h09;
-		rom[9'h069] = 8'h04;
-		rom[9'h06a] = 8'h01;
-		rom[9'h06b] = 8'h00;
-		rom[9'h06c] = 8'h02;
-		rom[9'h06d] = 8'h0a;
-		rom[9'h06e] = 8'h00;
-		rom[9'h06f] = 8'h00;
-		rom[9'h070] = 8'h04;
-		rom[9'h071] = 8'h07;
-		rom[9'h072] = 8'h05;
-		rom[9'h073] = 8'h81;
-		rom[9'h074] = 8'h02;
-		rom[9'h075] = 8'h40;
-		rom[9'h076] = 8'h00;
+		rom[9'h05d] = 8'h82;
+		rom[9'h05e] = 8'h03;
+		rom[9'h05f] = 8'h40;
+		rom[9'h060] = 8'h00;
+		rom[9'h061] = 8'h02;
+		rom[9'h062] = 8'h09;
+		rom[9'h063] = 8'h04;
+		rom[9'h064] = 8'h01;
+		rom[9'h065] = 8'h00;
+		rom[9'h066] = 8'h02;
+		rom[9'h067] = 8'h0a;
+		rom[9'h068] = 8'h00;
+		rom[9'h069] = 8'h00;
+		rom[9'h06a] = 8'h04;
+		rom[9'h06b] = 8'h07;
+		rom[9'h06c] = 8'h05;
+		rom[9'h06d] = 8'h81;
+		rom[9'h06e] = 8'h02;
+		rom[9'h06f] = 8'h40;
+		rom[9'h070] = 8'h00;
+		rom[9'h071] = 8'h00;
+		rom[9'h072] = 8'h07;
+		rom[9'h073] = 8'h05;
+		rom[9'h074] = 8'h01;
+		rom[9'h075] = 8'h02;
+		rom[9'h076] = 8'h40;
 		rom[9'h077] = 8'h00;
-		rom[9'h078] = 8'h07;
-		rom[9'h079] = 8'h05;
-		rom[9'h07a] = 8'h01;
+		rom[9'h078] = 8'h00;
+		rom[9'h079] = 8'h08;
+		rom[9'h07a] = 8'h0b;
 		rom[9'h07b] = 8'h02;
-		rom[9'h07c] = 8'h40;
-		rom[9'h07d] = 8'h00;
-		rom[9'h07e] = 8'h00;
-		rom[9'h07f] = 8'h08;
-		rom[9'h080] = 8'h0b;
-		rom[9'h081] = 8'h02;
-		rom[9'h082] = 8'h02;
+		rom[9'h07c] = 8'h02;
+		rom[9'h07d] = 8'h02;
+		rom[9'h07e] = 8'h02;
+		rom[9'h07f] = 8'h00;
+		rom[9'h080] = 8'h06;
+		rom[9'h081] = 8'h09;
+		rom[9'h082] = 8'h04;
 		rom[9'h083] = 8'h02;
-		rom[9'h084] = 8'h02;
-		rom[9'h085] = 8'h00;
-		rom[9'h086] = 8'h06;
-		rom[9'h087] = 8'h09;
-		rom[9'h088] = 8'h04;
-		rom[9'h089] = 8'h02;
-		rom[9'h08a] = 8'h00;
-		rom[9'h08b] = 8'h01;
-		rom[9'h08c] = 8'h02;
-		rom[9'h08d] = 8'h02;
-		rom[9'h08e] = 8'h00;
-		rom[9'h08f] = 8'h06;
-		rom[9'h090] = 8'h05;
-		rom[9'h091] = 8'h24;
-		rom[9'h092] = 8'h00;
-		rom[9'h093] = 8'h20;
-		rom[9'h094] = 8'h01;
-		rom[9'h095] = 8'h05;
-		rom[9'h096] = 8'h24;
-		rom[9'h097] = 8'h01;
-		rom[9'h098] = 8'h03;
-		rom[9'h099] = 8'h03;
-		rom[9'h09a] = 8'h04;
-		rom[9'h09b] = 8'h24;
-		rom[9'h09c] = 8'h02;
-		rom[9'h09d] = 8'h06;
+		rom[9'h084] = 8'h00;
+		rom[9'h085] = 8'h01;
+		rom[9'h086] = 8'h02;
+		rom[9'h087] = 8'h02;
+		rom[9'h088] = 8'h00;
+		rom[9'h089] = 8'h06;
+		rom[9'h08a] = 8'h05;
+		rom[9'h08b] = 8'h24;
+		rom[9'h08c] = 8'h00;
+		rom[9'h08d] = 8'h20;
+		rom[9'h08e] = 8'h01;
+		rom[9'h08f] = 8'h05;
+		rom[9'h090] = 8'h24;
+		rom[9'h091] = 8'h01;
+		rom[9'h092] = 8'h03;
+		rom[9'h093] = 8'h03;
+		rom[9'h094] = 8'h04;
+		rom[9'h095] = 8'h24;
+		rom[9'h096] = 8'h02;
+		rom[9'h097] = 8'h06;
+		rom[9'h098] = 8'h05;
+		rom[9'h099] = 8'h24;
+		rom[9'h09a] = 8'h06;
+		rom[9'h09b] = 8'h02;
+		rom[9'h09c] = 8'h03;
+		rom[9'h09d] = 8'h07;
 		rom[9'h09e] = 8'h05;
-		rom[9'h09f] = 8'h24;
-		rom[9'h0a0] = 8'h06;
-		rom[9'h0a1] = 8'h02;
-		rom[9'h0a2] = 8'h03;
-		rom[9'h0a3] = 8'h07;
-		rom[9'h0a4] = 8'h05;
-		rom[9'h0a5] = 8'h84;
+		rom[9'h09f] = 8'h84;
+		rom[9'h0a0] = 8'h03;
+		rom[9'h0a1] = 8'h40;
+		rom[9'h0a2] = 8'h00;
+		rom[9'h0a3] = 8'h02;
+		rom[9'h0a4] = 8'h09;
+		rom[9'h0a5] = 8'h04;
 		rom[9'h0a6] = 8'h03;
-		rom[9'h0a7] = 8'h40;
-		rom[9'h0a8] = 8'h00;
-		rom[9'h0a9] = 8'h02;
-		rom[9'h0aa] = 8'h09;
-		rom[9'h0ab] = 8'h04;
-		rom[9'h0ac] = 8'h03;
-		rom[9'h0ad] = 8'h00;
-		rom[9'h0ae] = 8'h02;
-		rom[9'h0af] = 8'h0a;
-		rom[9'h0b0] = 8'h00;
-		rom[9'h0b1] = 8'h00;
-		rom[9'h0b2] = 8'h04;
-		rom[9'h0b3] = 8'h07;
-		rom[9'h0b4] = 8'h05;
-		rom[9'h0b5] = 8'h83;
-		rom[9'h0b6] = 8'h02;
-		rom[9'h0b7] = 8'h40;
-		rom[9'h0b8] = 8'h00;
+		rom[9'h0a7] = 8'h00;
+		rom[9'h0a8] = 8'h02;
+		rom[9'h0a9] = 8'h0a;
+		rom[9'h0aa] = 8'h00;
+		rom[9'h0ab] = 8'h00;
+		rom[9'h0ac] = 8'h04;
+		rom[9'h0ad] = 8'h07;
+		rom[9'h0ae] = 8'h05;
+		rom[9'h0af] = 8'h83;
+		rom[9'h0b0] = 8'h02;
+		rom[9'h0b1] = 8'h40;
+		rom[9'h0b2] = 8'h00;
+		rom[9'h0b3] = 8'h00;
+		rom[9'h0b4] = 8'h07;
+		rom[9'h0b5] = 8'h05;
+		rom[9'h0b6] = 8'h03;
+		rom[9'h0b7] = 8'h02;
+		rom[9'h0b8] = 8'h40;
 		rom[9'h0b9] = 8'h00;
-		rom[9'h0ba] = 8'h07;
-		rom[9'h0bb] = 8'h05;
+		rom[9'h0ba] = 8'h00;
+		rom[9'h0bb] = 8'h06;
 		rom[9'h0bc] = 8'h03;
-		rom[9'h0bd] = 8'h02;
-		rom[9'h0be] = 8'h40;
-		rom[9'h0bf] = 8'h00;
-		rom[9'h0c0] = 8'h00;
-		rom[9'h0c1] = 8'h06;
+		rom[9'h0bd] = 8'h09;
+		rom[9'h0be] = 8'h04;
+		rom[9'h0bf] = 8'h1d;
+		rom[9'h0c0] = 8'h04;
+		rom[9'h0c1] = 8'h18;
 		rom[9'h0c2] = 8'h03;
-		rom[9'h0c3] = 8'h09;
-		rom[9'h0c4] = 8'h04;
-		rom[9'h0c5] = 8'h1d;
-		rom[9'h0c6] = 8'h04;
-		rom[9'h0c7] = 8'h18;
-		rom[9'h0c8] = 8'h03;
-		rom[9'h0c9] = 8'h50;
+		rom[9'h0c3] = 8'h50;
+		rom[9'h0c4] = 8'h00;
+		rom[9'h0c5] = 8'h65;
+		rom[9'h0c6] = 8'h00;
+		rom[9'h0c7] = 8'h74;
+		rom[9'h0c8] = 8'h00;
+		rom[9'h0c9] = 8'h65;
 		rom[9'h0ca] = 8'h00;
-		rom[9'h0cb] = 8'h65;
+		rom[9'h0cb] = 8'h72;
 		rom[9'h0cc] = 8'h00;
-		rom[9'h0cd] = 8'h74;
+		rom[9'h0cd] = 8'h20;
 		rom[9'h0ce] = 8'h00;
-		rom[9'h0cf] = 8'h65;
+		rom[9'h0cf] = 8'h26;
 		rom[9'h0d0] = 8'h00;
-		rom[9'h0d1] = 8'h72;
+		rom[9'h0d1] = 8'h20;
 		rom[9'h0d2] = 8'h00;
-		rom[9'h0d3] = 8'h20;
+		rom[9'h0d3] = 8'h50;
 		rom[9'h0d4] = 8'h00;
-		rom[9'h0d5] = 8'h26;
+		rom[9'h0d5] = 8'h65;
 		rom[9'h0d6] = 8'h00;
-		rom[9'h0d7] = 8'h20;
+		rom[9'h0d7] = 8'h72;
 		rom[9'h0d8] = 8'h00;
-		rom[9'h0d9] = 8'h50;
-		rom[9'h0da] = 8'h00;
-		rom[9'h0db] = 8'h65;
+		rom[9'h0d9] = 8'h2e;
+		rom[9'h0da] = 8'h03;
+		rom[9'h0db] = 8'h4d;
 		rom[9'h0dc] = 8'h00;
-		rom[9'h0dd] = 8'h72;
+		rom[9'h0dd] = 8'h41;
 		rom[9'h0de] = 8'h00;
-		rom[9'h0df] = 8'h2e;
-		rom[9'h0e0] = 8'h03;
-		rom[9'h0e1] = 8'h4d;
+		rom[9'h0df] = 8'h58;
+		rom[9'h0e0] = 8'h00;
+		rom[9'h0e1] = 8'h38;
 		rom[9'h0e2] = 8'h00;
-		rom[9'h0e3] = 8'h41;
+		rom[9'h0e3] = 8'h30;
 		rom[9'h0e4] = 8'h00;
-		rom[9'h0e5] = 8'h58;
+		rom[9'h0e5] = 8'h20;
 		rom[9'h0e6] = 8'h00;
-		rom[9'h0e7] = 8'h38;
+		rom[9'h0e7] = 8'h49;
 		rom[9'h0e8] = 8'h00;
-		rom[9'h0e9] = 8'h30;
+		rom[9'h0e9] = 8'h2f;
 		rom[9'h0ea] = 8'h00;
-		rom[9'h0eb] = 8'h20;
+		rom[9'h0eb] = 8'h4f;
 		rom[9'h0ec] = 8'h00;
-		rom[9'h0ed] = 8'h49;
+		rom[9'h0ed] = 8'h20;
 		rom[9'h0ee] = 8'h00;
-		rom[9'h0ef] = 8'h2f;
+		rom[9'h0ef] = 8'h63;
 		rom[9'h0f0] = 8'h00;
-		rom[9'h0f1] = 8'h4f;
+		rom[9'h0f1] = 8'h61;
 		rom[9'h0f2] = 8'h00;
-		rom[9'h0f3] = 8'h20;
+		rom[9'h0f3] = 8'h72;
 		rom[9'h0f4] = 8'h00;
-		rom[9'h0f5] = 8'h63;
+		rom[9'h0f5] = 8'h64;
 		rom[9'h0f6] = 8'h00;
-		rom[9'h0f7] = 8'h61;
+		rom[9'h0f7] = 8'h20;
 		rom[9'h0f8] = 8'h00;
-		rom[9'h0f9] = 8'h72;
+		rom[9'h0f9] = 8'h66;
 		rom[9'h0fa] = 8'h00;
-		rom[9'h0fb] = 8'h64;
+		rom[9'h0fb] = 8'h6f;
 		rom[9'h0fc] = 8'h00;
-		rom[9'h0fd] = 8'h20;
+		rom[9'h0fd] = 8'h72;
 		rom[9'h0fe] = 8'h00;
-		rom[9'h0ff] = 8'h66;
+		rom[9'h0ff] = 8'h20;
 		rom[9'h100] = 8'h00;
-		rom[9'h101] = 8'h6f;
+		rom[9'h101] = 8'h41;
 		rom[9'h102] = 8'h00;
-		rom[9'h103] = 8'h72;
+		rom[9'h103] = 8'h42;
 		rom[9'h104] = 8'h00;
-		rom[9'h105] = 8'h20;
+		rom[9'h105] = 8'h43;
 		rom[9'h106] = 8'h00;
-		rom[9'h107] = 8'h41;
-		rom[9'h108] = 8'h00;
-		rom[9'h109] = 8'h42;
-		rom[9'h10a] = 8'h00;
-		rom[9'h10b] = 8'h43;
+		rom[9'h107] = 8'h02;
+		rom[9'h108] = 8'h03;
+		rom[9'h109] = 8'h1c;
+		rom[9'h10a] = 8'h03;
+		rom[9'h10b] = 8'h4d;
 		rom[9'h10c] = 8'h00;
-		rom[9'h10d] = 8'h02;
-		rom[9'h10e] = 8'h03;
-		rom[9'h10f] = 8'h1c;
-		rom[9'h110] = 8'h03;
-		rom[9'h111] = 8'h4d;
+		rom[9'h10d] = 8'h41;
+		rom[9'h10e] = 8'h00;
+		rom[9'h10f] = 8'h58;
+		rom[9'h110] = 8'h00;
+		rom[9'h111] = 8'h38;
 		rom[9'h112] = 8'h00;
-		rom[9'h113] = 8'h41;
+		rom[9'h113] = 8'h30;
 		rom[9'h114] = 8'h00;
-		rom[9'h115] = 8'h58;
+		rom[9'h115] = 8'h20;
 		rom[9'h116] = 8'h00;
-		rom[9'h117] = 8'h38;
+		rom[9'h117] = 8'h63;
 		rom[9'h118] = 8'h00;
-		rom[9'h119] = 8'h30;
+		rom[9'h119] = 8'h6f;
 		rom[9'h11a] = 8'h00;
-		rom[9'h11b] = 8'h20;
+		rom[9'h11b] = 8'h6e;
 		rom[9'h11c] = 8'h00;
-		rom[9'h11d] = 8'h63;
+		rom[9'h11d] = 8'h73;
 		rom[9'h11e] = 8'h00;
 		rom[9'h11f] = 8'h6f;
 		rom[9'h120] = 8'h00;
-		rom[9'h121] = 8'h6e;
+		rom[9'h121] = 8'h6c;
 		rom[9'h122] = 8'h00;
-		rom[9'h123] = 8'h73;
+		rom[9'h123] = 8'h65;
 		rom[9'h124] = 8'h00;
-		rom[9'h125] = 8'h6f;
-		rom[9'h126] = 8'h00;
-		rom[9'h127] = 8'h6c;
+		rom[9'h125] = 8'h1c;
+		rom[9'h126] = 8'h03;
+		rom[9'h127] = 8'h50;
 		rom[9'h128] = 8'h00;
-		rom[9'h129] = 8'h65;
+		rom[9'h129] = 8'h55;
 		rom[9'h12a] = 8'h00;
-		rom[9'h12b] = 8'h1c;
-		rom[9'h12c] = 8'h03;
-		rom[9'h12d] = 8'h50;
+		rom[9'h12b] = 8'h4e;
+		rom[9'h12c] = 8'h00;
+		rom[9'h12d] = 8'h38;
 		rom[9'h12e] = 8'h00;
-		rom[9'h12f] = 8'h55;
+		rom[9'h12f] = 8'h30;
 		rom[9'h130] = 8'h00;
-		rom[9'h131] = 8'h4e;
+		rom[9'h131] = 8'h20;
 		rom[9'h132] = 8'h00;
-		rom[9'h133] = 8'h38;
+		rom[9'h133] = 8'h6e;
 		rom[9'h134] = 8'h00;
-		rom[9'h135] = 8'h30;
+		rom[9'h135] = 8'h65;
 		rom[9'h136] = 8'h00;
-		rom[9'h137] = 8'h20;
+		rom[9'h137] = 8'h74;
 		rom[9'h138] = 8'h00;
-		rom[9'h139] = 8'h6e;
+		rom[9'h139] = 8'h77;
 		rom[9'h13a] = 8'h00;
-		rom[9'h13b] = 8'h65;
+		rom[9'h13b] = 8'h6f;
 		rom[9'h13c] = 8'h00;
-		rom[9'h13d] = 8'h74;
+		rom[9'h13d] = 8'h72;
 		rom[9'h13e] = 8'h00;
-		rom[9'h13f] = 8'h77;
+		rom[9'h13f] = 8'h6b;
 		rom[9'h140] = 8'h00;
-		rom[9'h141] = 8'h6f;
-		rom[9'h142] = 8'h00;
-		rom[9'h143] = 8'h72;
+		rom[9'h141] = 8'h00;
+		rom[9'h142] = 8'h96;
+		rom[9'h143] = 8'h00;
 		rom[9'h144] = 8'h00;
-		rom[9'h145] = 8'h6b;
+		rom[9'h145] = 8'h00;
 		rom[9'h146] = 8'h00;
-		rom[9'h147] = 8'h00;
-		rom[9'h148] = 8'h96;
-		rom[9'h149] = 8'h00;
-		rom[9'h14a] = 8'h00;
-		rom[9'h14b] = 8'h00;
-		rom[9'h14c] = 8'h00;
-		rom[9'h14d] = 8'h08;
+		rom[9'h147] = 8'h08;
 	end
 
 	always @(posedge clk) begin
@@ -377,22 +371,22 @@ module usb_desc_index (
 
 	always @(*)
        	if (additional)
-		{addr,len} = {9'h147,9'h007};
+		{addr,len} = {9'h141,9'h007};
 	else priority casez ({windex,dindex,dtype})
-		32'b??????00_00011101_00000010_00000011: {addr,len} = {9'h0c7,9'h018};
-		32'b??????00_00011101_00000011_00000011: {addr,len} = {9'h0df,9'h02e};
-		32'b??????00_00011101_00000100_00000011: {addr,len} = {9'h10d,9'h002};
-		32'b??????00_00011101_00000101_00000011: {addr,len} = {9'h10f,9'h01c};
-		32'b??????00_00011101_00000110_00000011: {addr,len} = {9'h12b,9'h01c};
-		32'b????????_????????_00000000_00000010: {addr,len} = {9'h034,9'h08d};
-		32'b????????_????????_00000000_00000011: {addr,len} = {9'h0c1,9'h006};
-		32'b????????_????????_00000001_00000011: {addr,len} = {9'h000,9'h022};
-		32'b????????_????????_00000010_00000011: {addr,len} = {9'h0c7,9'h018};
-		32'b????????_????????_00000011_00000011: {addr,len} = {9'h0df,9'h02e};
-		32'b????????_????????_00000100_00000011: {addr,len} = {9'h10d,9'h002};
-		32'b????????_????????_00000101_00000011: {addr,len} = {9'h10f,9'h01c};
-		32'b????????_????????_00000110_00000011: {addr,len} = {9'h12b,9'h01c};
-		32'b????????_????????_????????_00000001: {addr,len} = {9'h022,9'h012};
+		32'b??????00_00011101_00000010_00000011: {addr,len} = {9'h0c1,9'h018};
+		32'b??????00_00011101_00000011_00000011: {addr,len} = {9'h0d9,9'h02e};
+		32'b??????00_00011101_00000100_00000011: {addr,len} = {9'h107,9'h002};
+		32'b??????00_00011101_00000101_00000011: {addr,len} = {9'h109,9'h01c};
+		32'b??????00_00011101_00000110_00000011: {addr,len} = {9'h125,9'h01c};
+		32'b????????_????????_00000000_00000010: {addr,len} = {9'h02e,9'h08d};
+		32'b????????_????????_00000000_00000011: {addr,len} = {9'h0bb,9'h006};
+		32'b????????_????????_00000001_00000011: {addr,len} = {9'h000,9'h01c};
+		32'b????????_????????_00000010_00000011: {addr,len} = {9'h0c1,9'h018};
+		32'b????????_????????_00000011_00000011: {addr,len} = {9'h0d9,9'h02e};
+		32'b????????_????????_00000100_00000011: {addr,len} = {9'h107,9'h002};
+		32'b????????_????????_00000101_00000011: {addr,len} = {9'h109,9'h01c};
+		32'b????????_????????_00000110_00000011: {addr,len} = {9'h125,9'h01c};
+		32'b????????_????????_????????_00000001: {addr,len} = {9'h01c,9'h012};
 		32'b????????_????????_????????_????????: {addr,len} = {9'hxxx,9'h000};
 	endcase
 endmodule

+ 3 - 1
rv32/Makefile

@@ -27,6 +27,8 @@ LDFLAGS   = $(CFLAGS) \
 
 gendeps   = -MD -MF $(@D)/.$(@F).d -MT $@
 
+VPATH    := .:../common
+
 # Delete output files on error
 .DELETE_ON_ERROR:
 
@@ -46,7 +48,7 @@ ROMOBJS  = $(ROMS:.rom=.o)
 
 LIBOBJ   = head.o dummy.o die.o system.o \
 	   ioregsa.o irqasm.o irqtable.o spurious_irq.o \
-	   console.o rtc.o romcopy.o spiflash.o esp.o \
+	   console.o rtc.o romcopy.o spiflash.o esp.o matchver.o \
 	   sdcard.o \
 	   abcmem.o abcio.o abcdisk.o abcrtc.o abcpun80.o \
 	   memset.o memcpy.o \

+ 1 - 1
rv32/checksum.h

@@ -1,4 +1,4 @@
 #ifndef CHECKSUM_H
 #define CHECKSUM_H
-#define SDRAM_SUM 0x1ce2ddf4
+#define SDRAM_SUM 0x5cde6c34
 #endif

+ 37 - 0
rv32/console.c

@@ -39,3 +39,40 @@ void con_printf(const char *fmt, ...)
     con_vprintf(fmt, ap);
     va_end(ap);
 }
+
+void con_hexdump(const void *data, size_t len)
+{
+    const uint8_t *p = data;
+
+    if (!len)
+	return;
+
+    while (1) {
+	con_printf("%p", p);
+	for (size_t i = 0; i < 16; i++) {
+	    if (!(i & 7))
+		con_putc(' ');
+	    if (i >= len)
+		con_puts("   ");
+	    else
+		con_printf(" %02x", p[i]);
+	}
+	con_puts("  |");
+	for (size_t i = 0; i < 16; i++) {
+	    char c;
+	    if (i >= len)
+		break;
+	    c = p[i];
+	    if (c < ' ' || c > '~')
+		c = '.';
+	    con_putc(c);
+	}
+	con_puts("|\n");
+
+	if (len <= 16)
+	    break;
+
+	p += 16;
+	len -= 16;
+    }
+}

+ 1 - 0
rv32/console.h

@@ -77,5 +77,6 @@ static __always_inline void con_flush(void)
 }
 
 void con_print_hex(unsigned int); /* For pre-SDRAM capable code */
+void con_hexdump(const void *data, size_t len); /* For debugging */
 
 #endif /* CONSOLE_H */

+ 6 - 0
rv32/esp.c

@@ -3,11 +3,14 @@
 #include "io.h"
 #include "console.h"
 #include "esp.h"
+#include "boardinfo_fpga.h"
 
 struct esplink_head __esplink_head esplink_head;
 static volatile __esplink struct esplink_timesync tsync;
 static volatile __esplink struct esplink_ota ota;
 
+volatile __esplink char board_info_esp[BOARDINFO_SIZE];
+
 IRQHANDLER(esp,0)
 {
     uint32_t irqstatus = ESP_CPU_IRQ;
@@ -31,6 +34,8 @@ IRQHANDLER(esp,0)
 	    ESP_SPI_IRQ_SET = 1 << EL_UIRQ_TIME;
 	}
     }
+    if (irqstatus & (1 << EL_DIRQ_BOARDINFO))
+	do_update_boardinfo = true;
 
     if (irqstatus & (1 << EL_DIRQ_HELLO)) {
 	con_printf("[ESP] Got hello, sending ready...\n");
@@ -236,6 +241,7 @@ void esp_init(void)
     esplink_head.board.cfg     = SYS_BOARDCFG;
     memcpy(esplink_head.signature, esp_signature, sizeof esp_signature);
 
+    esplink_head.board_info    = &board_info_raw;
     esplink_head.tsync         = &tsync;
     esplink_head.ota           = &ota;
 

+ 0 - 1
rv32/jtagupd.c

@@ -36,7 +36,6 @@ void main(void)
     con_putc('\n');
 
     wait_romcopy_done();
-    rom_print_serial();
 
     while (1) {
 	uint32_t cmd;

+ 4 - 0
rv32/max80.c

@@ -3,6 +3,7 @@
 #include "abcio.h"
 #include "sys.h"
 #include "console.h"
+#include "boardinfo_fpga.h"
 
 void __hot main(void)
 {
@@ -17,6 +18,9 @@ void __hot main(void)
 	if (unlikely(do_write_rtc))
 	    write_rtc();
 
+	if (unlikely(do_update_boardinfo))
+	    rom_update_boardinfo();
+
 	abcdisk_io_poll();
 
 	abc_latency = ABC_LATENCY;

+ 106 - 53
rv32/romcopy.c

@@ -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);
+}

+ 56 - 15
rv32/spiflash.c

@@ -2,6 +2,7 @@
 #include "zlib.h"
 #include "spiflash.h"
 #include "esp.h"
+#include "matchver.h"
 
 #if 1
 # include "console.h"
@@ -110,7 +111,7 @@ static int spiflash_data_init(spz_stream *spz)
     for (int i = 0; i < NBUF; i++) {
 	spz->bufs[i] = spz_malloc(spz, SPIFLASH_BLOCK_SIZE);
 	if (!spz->bufs[i])
-	    goto err;
+		goto err;
     }
 
     spz->eoi = !spz->flash->read_data;
@@ -295,8 +296,6 @@ static int spiflash_erase(const struct spiflash *flash,
 	}
 
 	if (sector_mask & 1) {
-	    MSG("\rupdate: erasing %2uK at 0x%06x... ", erasesize >> 10, addr);
-
 	    rv = spiflash_write_enable(flash);
 	    if (rv)
 		return rv;
@@ -410,6 +409,7 @@ static int spiflash_flash_chunk(spz_stream *spz)
 	    post_padding = bytes - data_left;
 	    bytes = data_left;
 	}
+	addr -= pre_padding;
 
 	/* Read the current content of this block into vbuf */
 	rv = spiflash_read(spz->flash, addr, spz->vbuf, SPIFLASH_BLOCK_SIZE);
@@ -426,35 +426,36 @@ static int spiflash_flash_chunk(spz_stream *spz)
 
 	rv = spiflash_read_data(spz, spz->dbuf+pre_padding, bytes);
 	if (rv != (int)bytes) {
-	    MSG("needed %u bytes got %d\n", rv);
+	    MSG("needed %u bytes got %d, \n", bytes, rv);
 	    rv = Z_DATA_ERROR;
 	    goto err;
 	}
 
-	MSG("update: flash block at 0x%06x (%5u bytes):\n", addr, bytes);
-
-	addr -= pre_padding;
-
 	uint32_t erase_mask;
 	uint32_t prog_mask[SPIFLASH_BLOCK_SIZE >> (SPIFLASH_PAGE_SHIFT+5)];
 
 	spiflash_check_block(spz, addr, &erase_mask, prog_mask);
 	if (erase_mask) {
+	    MSG("flash: erasing at 0x%06x mask %04x... ", addr, erase_mask);
+
 	    rv = spiflash_erase(spz->flash, addr, erase_mask);
 	    if (rv)
 		goto err;
 
 	    /* Verify that the sector did erase */
 	    rv = spiflash_read(spz->flash, addr, spz->vbuf, SPIFLASH_BLOCK_SIZE);
-	    if (rv)
+	    if (rv) {
+		MSG("readback ");
 		goto err;
+	    }
 
 	    spiflash_check_block(spz, addr, &erase_mask, prog_mask);
 	    if (erase_mask) {
-		MSG("[erase mask = %04x] ", erase_mask);
 		spz->err = SPIFLASH_ERR_ERASE_FAILED;
+		MSG("%04x left, ", erase_mask);
 		goto err;
 	    }
+	    MSG("ok\n");
 	}
 
 	unsigned int page;
@@ -470,7 +471,7 @@ static int spiflash_flash_chunk(spz_stream *spz)
 	    programmed = true;
 
 	    udelay(100);
-	    MSG("\rupdate: writing at 0x%06x... ", addr + page_offs);
+	    MSG("flash: writing at 0x%06x... ", addr + page_offs);
 
 	    rv = spiflash_program(spz->flash, addr + page_offs,
 				  spz->dbuf + page_offs,
@@ -489,15 +490,16 @@ static int spiflash_flash_chunk(spz_stream *spz)
 
 	    if (memcmp(spz->dbuf + page_offs, spz->vbuf + page_offs,
 		       SPIFLASH_PAGE_SIZE)) {
-		MSG("verify @ 0x%06x ", addr + page_offs);
+		MSG("verify ");
 		spz->err = SPIFLASH_ERR_PROGRAM_FAILED;
 		goto err;
 	    }
+	    MSG("ok\n");
 	}
 	if (programmed)
 	    MSG("ok\n");
 	else
-	    MSG("update: nothing to write\n");
+	    MSG("unchanged\n");
 
 	addr += pre_padding + bytes;
 	data_left -= bytes;
@@ -505,6 +507,8 @@ static int spiflash_flash_chunk(spz_stream *spz)
     return spz->err;
 
 err:
+    MSG("failed\n");
+
     if (!spz->err)
 	spz->err = rv;
 
@@ -617,7 +621,7 @@ static int spiflash_process_chunk(spz_stream *spz)
 
     con_printf("update: chunk type %u size %u addr 0x%08x\n",
 	       spz->header.type, spz->header.len, spz->header.addr);
-    
+
     switch (spz->header.type) {
     case FDT_END:
 	return Z_STREAM_END;	/* End of data - not an error */
@@ -628,7 +632,7 @@ static int spiflash_process_chunk(spz_stream *spz)
     case FDT_TARGET:
 	str = spiflash_read_chunk_str(spz);
 	/* XXX: replace with proper matching algorithm */
-	if (!str || strcmp(str, spz->flash->target)) {
+	if (!str || !match_version(spz->flash->target, str)) {
 	    MSG("update: this firmware file targets \"%s\", need \"%s\"\n",
 		str, spz->flash->target);
 	    return spz->err = Z_DATA_ERROR;
@@ -712,3 +716,40 @@ int spiflash_read_vdid(const struct spiflash *flash, void *vdid)
 				sizeof read_vdid,
 				vdid, SPIFLASH_VDID_LEN, flash->param->tshsl);
 }
+
+/*
+ * Write an absolute region to flash
+ */
+int spiflash_flash_data(const struct spiflash *flash, uint32_t addr,
+			const void *data, size_t len)
+{
+    spz_stream _spz;
+    spz_stream * const spz = &_spz; /* For consistency in notation */
+    int err = 0;
+
+    memset(spz, 0, sizeof *spz);
+
+    /* No ibuf or obuf */
+    for (int i = 2; i < NBUF; i++) {
+	spz->bufs[i] = spz_malloc(spz, SPIFLASH_BLOCK_SIZE);
+	if (!spz->bufs[i])
+		goto err;
+    }
+
+    spz->flash       = flash;
+    spz->optr        = (uint8_t *)data; /* OK to lose const here */
+    spz->obuf        = (uint8_t *)data; /* OK to lose const here */
+    spz->zs.next_out = (uint8_t *)data + len;
+    spz->eoi         = true;
+    spz->header.len  = len;
+    spz->header.addr = addr;
+
+    spiflash_flash_chunk(spz);
+
+err:
+    for (int i = 2; i < NBUF; i++)
+	if (spz->bufs[i])
+	    free(spz->bufs[i]);
+
+    return spz->err;
+}

+ 6 - 0
rv32/spiflash.h

@@ -264,6 +264,12 @@ struct spiflash {
 int spiflash_flash_file(const struct spiflash *flash,
 			void *data, size_t datalen);
 
+/*
+ * Flash a single region of data to the SPI flash.
+ */
+int spiflash_flash_data(const struct spiflash *flash, uint32_t addr,
+			const void *data, size_t datalen);
+
 /*
  * Read identifying data from SPI flash.
  */

+ 4 - 3
rv32/system.c

@@ -127,7 +127,8 @@ void __hot init(void)
 	all_ones  = -1;
 	not_zero  = 0;
 
-	for (dp = __dram_init_start; dp < __dram_init_end; dp++) {
+	for (dp = (volatile uint32_t *)__dram_init_start;
+	     dp < (volatile uint32_t *)__dram_init_end; dp++) {
 	    uint32_t v1, v2;
 
 	    v1 = *dp;
@@ -168,7 +169,8 @@ void __hot init(void)
 	    con_puts(hotstr("SDRAM read/write error\n"));
 
 	v = 0;
-	for (dp = __dram_bss_start; dp < __dram_bss_end; dp++) {
+	for (dp = (volatile uint32_t *)__dram_bss_start;
+	     dp < (volatile uint32_t *)__dram_bss_end; dp++) {
 	    uint32_t x = *dp;
 	    v |= x;
 	}
@@ -234,7 +236,6 @@ static void __noinline late_init(void)
 	}
     }
     con_putc('\n');
-    rom_print_serial();
 
     if ( MINITESTS ) {
 	con_puts("Quick DRAM test:\n");