|  | @@ -69,7 +69,73 @@ void __hot romcopy_bzero(void *dst, size_t len)
 | 
	
		
			
				|  |  |      ROMCOPY_DATALEN = len | ROMCOPY_ZERO_BUFFER | ROMCOPY_WRITE_RAM;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static __hot void romcopy_config_flash(void)
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * Read unique serial number programmed into ROM. Convert the serial
 | 
	
		
			
				|  |  | + * number to 12 characters in base32; we lose four bits but that is never
 | 
	
		
			
				|  |  | + * going to matter. It's more fun than plain hex... :)
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * This is run before the 64-bit division routines are available in SDRAM,
 | 
	
		
			
				|  |  | + * so it needs to be an encoding that can be generated with only plain
 | 
	
		
			
				|  |  | + * 32-bit instructions.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * 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.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +char __bss_hot rom_serial_str[16];
 | 
	
		
			
				|  |  | +qword_t __bss_hot rom_serial;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static __must_inline void rom_read_serial(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    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;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static __must_inline void rom_mangle_serial(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    rom_serial_str[12] = '\0';
 | 
	
		
			
				|  |  | +    uint64_t v = rom_serial.q;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    for (int i = 11; i >= 0; i--) {
 | 
	
		
			
				|  |  | +	unsigned char c;
 | 
	
		
			
				|  |  | +	unsigned int d = v & 31;
 | 
	
		
			
				|  |  | +	v >>= 5;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	c = d + '0';
 | 
	
		
			
				|  |  | +	if (c > '9')
 | 
	
		
			
				|  |  | +	    c += 'A'-'9'-1;
 | 
	
		
			
				|  |  | +	if (c >= 'I')
 | 
	
		
			
				|  |  | +	    c++;
 | 
	
		
			
				|  |  | +	if (c >= 'O')
 | 
	
		
			
				|  |  | +	    c++;
 | 
	
		
			
				|  |  | +	if (c >= 'S')
 | 
	
		
			
				|  |  | +	    c++;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* IOSZ not used to avoid confusion with 1052 */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	rom_serial_str[i] = c;
 | 
	
		
			
				|  |  | +	usbdesc_rom[2+2*i] = c;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void rom_print_serial(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    /* Print the ROM serial when we actually can */
 | 
	
		
			
				|  |  | +    con_printf("ROM serial: %08x-%08x (%s)\n",
 | 
	
		
			
				|  |  | +	       rom_serial.l[1], rom_serial.l[0], rom_serial_str);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static __must_inline void romcopy_config_flash(void)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      /* Enable writing volatile status register bits */
 | 
	
		
			
				|  |  |      ROMCOPY_ROMCMD = ROM_VOLATILE_SR_WRITE_ENABLE << 24;
 | 
	
	
		
			
				|  | @@ -82,24 +148,6 @@ static __hot void romcopy_config_flash(void)
 | 
	
		
			
				|  |  |      waitfor(ROMCOPY_IRQ);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      asm volatile("nop; nop");	/* Make extra sure tSHSL2 is OK */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if ( 1 ) {
 | 
	
		
			
				|  |  | -	con_puts(hotstr("ROM serial: "));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	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);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	con_print_hex(ROMCOPY_INPUT);
 | 
	
		
			
				|  |  | -	ROMCOPY_DATALEN = ROMCOPY_SPI_CMDLEN(4);
 | 
	
		
			
				|  |  | -	waitfor(ROMCOPY_IRQ);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	con_print_hex(ROMCOPY_INPUT);
 | 
	
		
			
				|  |  | -	con_putc('\n');
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  IRQHANDLER(romcopy,0)
 | 
	
	
		
			
				|  | @@ -109,11 +157,18 @@ IRQHANDLER(romcopy,0)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      switch (romcopy_state++) {
 | 
	
		
			
				|  |  |      case 0:
 | 
	
		
			
				|  |  | +	/* Condition flash ROM */
 | 
	
		
			
				|  |  |  	romcopy_config_flash();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	/* Copy DRAM data */
 | 
	
		
			
				|  |  | +	/* 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 1:
 | 
	
		
			
				|  |  |  	/* Zero .dram.bss */
 | 
	
	
		
			
				|  | @@ -125,49 +180,3 @@ IRQHANDLER(romcopy,0)
 | 
	
		
			
				|  |  |  	break;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/*
 | 
	
		
			
				|  |  | - * Read unique serial number programmed into ROM. Convert the serial
 | 
	
		
			
				|  |  | - * number to 12 characters in base36 (technically a wraparound that is
 | 
	
		
			
				|  |  | - * never going to matter.) It's more fun than plain hex... :)
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -char __bss_hot serial_str[16];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -uint64_t __hot rom_get_serial(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    union {
 | 
	
		
			
				|  |  | -	uint32_t l[2];
 | 
	
		
			
				|  |  | -	uint64_t q;
 | 
	
		
			
				|  |  | -    } o;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    waitfor(ROMCOPY_IRQ);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    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);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    o.l[1] = ROMCOPY_INPUT;
 | 
	
		
			
				|  |  | -    ROMCOPY_DATALEN = ROMCOPY_SPI_CMDLEN(4);
 | 
	
		
			
				|  |  | -    waitfor(ROMCOPY_IRQ);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    o.l[0] = ROMCOPY_INPUT;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    serial_str[12] = '\0';
 | 
	
		
			
				|  |  | -    uint64_t v = o.q;
 | 
	
		
			
				|  |  | -    for (int i = 11; i >= 0; i--) {
 | 
	
		
			
				|  |  | -	unsigned char c;
 | 
	
		
			
				|  |  | -	unsigned int d = v % 36;
 | 
	
		
			
				|  |  | -	v /= 36;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	c = d + '0' + ('A'-'0'-10)*(d >= 10);
 | 
	
		
			
				|  |  | -	serial_str[i] = c;
 | 
	
		
			
				|  |  | -	usbdesc_rom[2+2*i] = c;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    con_printf("ROM serial: %08x-%08x (%s)\n", o.l[1], o.l[0], serial_str);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return o.q;
 | 
	
		
			
				|  |  | -}
 |