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