diff options
| -rw-r--r-- | firmware/microblaze/usrp2p/Makefile.am | 1 | ||||
| -rw-r--r-- | firmware/microblaze/usrp2p/bootloader/Makefile.am | 2 | ||||
| -rw-r--r-- | firmware/microblaze/usrp2p/bootloader/init_bootloader.c | 53 | ||||
| -rw-r--r-- | firmware/microblaze/usrp2p/bootloader_utils.c | 18 | ||||
| -rw-r--r-- | firmware/microblaze/usrp2p/udp_fw_update.c | 2 | ||||
| -rw-r--r-- | firmware/microblaze/usrp2p/xilinx_s3_icap.c (renamed from firmware/microblaze/lib/xilinx_s3_icap.c) | 76 | ||||
| -rwxr-xr-x | host/utils/usrp2p_fw_update.py | 59 | 
7 files changed, 135 insertions, 76 deletions
| diff --git a/firmware/microblaze/usrp2p/Makefile.am b/firmware/microblaze/usrp2p/Makefile.am index e6bff2dbc..0d0b60437 100644 --- a/firmware/microblaze/usrp2p/Makefile.am +++ b/firmware/microblaze/usrp2p/Makefile.am @@ -51,6 +51,7 @@ libusrp2p_a_SOURCES = \  	spi_flash_read.c \  	bootloader_utils.c \  	ethernet.c \ +	xilinx_s3_icap.c \    udp_fw_update.c  noinst_PROGRAMS = \ diff --git a/firmware/microblaze/usrp2p/bootloader/Makefile.am b/firmware/microblaze/usrp2p/bootloader/Makefile.am index 1fc5daf9c..eb72d937d 100644 --- a/firmware/microblaze/usrp2p/bootloader/Makefile.am +++ b/firmware/microblaze/usrp2p/bootloader/Makefile.am @@ -30,7 +30,7 @@ LDADD = $(top_srcdir)/usrp2p/libusrp2p.a  noinst_PROGRAMS = \  	init_bootloader.elf -init_bootloader_elf_SOURCES = init_bootloader.c +init_bootloader_elf_SOURCES = init_bootloader.c i2c_sync.c  .bin.rmi:  	$(top_srcdir)/bin/bin_to_ram_macro_init.py $< $@ diff --git a/firmware/microblaze/usrp2p/bootloader/init_bootloader.c b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c index 15d719d73..8b513002d 100644 --- a/firmware/microblaze/usrp2p/bootloader/init_bootloader.c +++ b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c @@ -15,6 +15,12 @@  #include <bootloader_utils.h>  #include <string.h>  #include <hal_uart.h> +#include "i2c_sync.h" + +#define SAFE_FLAG_LOCATION 247 + +bool find_safe_booted_flag(void); +void set_safe_booted_flag(bool flag);  void pic_interrupt_handler() __attribute__ ((interrupt_handler)); @@ -23,6 +29,19 @@ void pic_interrupt_handler()    // nop stub  } +bool find_safe_booted_flag(void) { +	unsigned char flag_byte; +	i2c_read(SAFE_FLAG_LOCATION, &flag_byte, 1); +	 +	return (flag_byte != 0x5E); +} + +void set_safe_booted_flag(bool flag) { +	unsigned char flag_byte = flag ? 0x5E : 0xDC; +	i2c_write(SAFE_FLAG_LOCATION, &flag_byte, 1); +} + +  void load_ihex(void) { //simple IHEX parser to load proper records into RAM. loads program when it receives end of record.  	char buf[128]; //input data buffer  	uint8_t ihx[32]; //ihex data buffer @@ -51,19 +70,18 @@ void delay(uint32_t t) {  	while(t-- != 0) asm("NOP");  } -//let's clean up this logic. state machine? no, you only have to go through it once. - -//don't need else cases since all these are terminal cases -  int main(int argc, char *argv[]) {    hal_disable_ints();	// In case we got here via jmp 0x0  	output_regs->leds = 0xFF;  	delay(500000);  	output_regs->leds = 0x00; -  hal_uart_init(); +	hal_uart_init();  	spif_init(); -//	i2c_init(); //for EEPROM +	i2c_init(); //for EEPROM  	puts("USRP2+ bootloader\n"); +	 +	bool production_image = find_safe_booted_flag(); +	if(production_image) set_safe_booted_flag(0); //we're the production image, so we clear the flag for the next boot  	if(BUTTON_PUSHED) { //see memory_map.h  		puts("Starting USRP2+ in safe mode."); @@ -71,26 +89,31 @@ int main(int argc, char *argv[]) {  				spi_flash_read(SAFE_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE);  				start_program(RAM_BASE);  				puts("ERROR: return from main program! This should never happen!"); -				//icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); +				icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR);  			} else {  				puts("ERROR: no safe firmware image available. I am a brick. Feel free to load IHEX to RAM."); +				//puts("ERROR: no safe firmware image available. I am a brick.");  				load_ihex();  			}  	} -	puts("Checking for valid production FPGA image..."); -	if(is_valid_fpga_image(PROD_FPGA_IMAGE_LOCATION_ADDR)) { -		puts("Valid production FPGA image found. Attempting to boot."); -		//icap_reload_fpga(PROD_FPGA_IMAGE_LOCATION_ADDR); +	if(!production_image) { +		puts("Checking for valid production FPGA image..."); +		if(is_valid_fpga_image(PROD_FPGA_IMAGE_LOCATION_ADDR)) { +			puts("Valid production FPGA image found. Attempting to boot."); +			set_safe_booted_flag(1); +			delay(10000); +			icap_reload_fpga(PROD_FPGA_IMAGE_LOCATION_ADDR); +		} +		puts("No valid production FPGA image found.\nAttempting to load production firmware...");  	} -	puts("No valid production FPGA image found.\nAttempting to load production firmware...");  	if(is_valid_fw_image(PROD_FW_IMAGE_LOCATION_ADDR)) {  		puts("Valid production firmware found. Loading...");  		spi_flash_read(PROD_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE);  		start_program(RAM_BASE);  		puts("ERROR: Return from main program! This should never happen!");  		//if this happens, though, the safest thing to do is reboot the whole FPGA and start over. -		//icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); +		icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR);  		return 1;  	}  	puts("No valid production firmware found. Trying safe firmware..."); @@ -98,8 +121,8 @@ int main(int argc, char *argv[]) {  		spi_flash_read(SAFE_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE);  		start_program(RAM_BASE);  		puts("ERROR: return from main program! This should never happen!"); -		//icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); -		return 1; //_exit will trap in loop +		icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR); +		return 1;  	}  	puts("ERROR: no safe firmware image available. I am a brick. Feel free to load IHEX to RAM.");  	load_ihex(); diff --git a/firmware/microblaze/usrp2p/bootloader_utils.c b/firmware/microblaze/usrp2p/bootloader_utils.c index 00893db02..fadd225bb 100644 --- a/firmware/microblaze/usrp2p/bootloader_utils.c +++ b/firmware/microblaze/usrp2p/bootloader_utils.c @@ -5,16 +5,23 @@   */  //contains routines for loading programs from Flash. depends on Flash libraries. +//also contains routines for reading / writing EEPROM flags for the bootloader +#include <stdbool.h>  #include <string.h>  #include <bootloader_utils.h>  #include <spi_flash.h> -  int is_valid_fpga_image(uint32_t addr) { -	static const uint8_t fpgaheader[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0x99}; //AA 99 is the standard Xilinx sync sequence, and it's always prefixed with 0xFF padding -	uint8_t buf[10]; -	spi_flash_read(addr, 6, buf); -	return memcmp(buf, fpgaheader, 6) == 0; +	uint8_t imgbuf[64]; +	spi_flash_read(addr, 64, imgbuf); +	//we're just looking for leading 0xFF padding, followed by the sync bytes 0xAA 0x99 +	int i = 0; +	for(i; i<63; i++) { +		if(imgbuf[i] == 0xFF) continue; +		if(imgbuf[i] == 0xAA && imgbuf[i+1] == 0x99) return 1; +	} +	 +	return 0;  }  int is_valid_fw_image(uint32_t addr) { @@ -30,4 +37,3 @@ void start_program(uint32_t addr)  	typedef void (*fptr_t)(void);  	(*(fptr_t) 0x00000000)();	// most likely no return  } - diff --git a/firmware/microblaze/usrp2p/udp_fw_update.c b/firmware/microblaze/usrp2p/udp_fw_update.c index 9242242e7..55c206b1b 100644 --- a/firmware/microblaze/usrp2p/udp_fw_update.c +++ b/firmware/microblaze/usrp2p/udp_fw_update.c @@ -26,6 +26,7 @@  #include <string.h>  #include "ethernet.h"  #include "udp_fw_update.h" +#include "xilinx_s3_icap.h"  //Firmware update packet handler  void handle_udp_fw_update_packet(struct socket_address src, struct socket_address dst, @@ -94,6 +95,7 @@ void handle_udp_fw_update_packet(struct socket_address src, struct socket_addres      //should reset via icap_reload_fpga(uint32_t flash_address);      update_data_out.id = USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG;      //you should note that if you get a reply packet to this the reset has obviously failed +    icap_reload_fpga(0);      break;  //  case USRP2_FW_UPDATE_ID_KTHXBAI: //see ya diff --git a/firmware/microblaze/lib/xilinx_s3_icap.c b/firmware/microblaze/usrp2p/xilinx_s3_icap.c index 8aa7fd297..50c85231c 100644 --- a/firmware/microblaze/lib/xilinx_s3_icap.c +++ b/firmware/microblaze/usrp2p/xilinx_s3_icap.c @@ -19,7 +19,7 @@  /* Changes required to work for the Spartan-3A series:   * The ICAP interface on the 3A is 8 bits wide, instead of 32. - * Everything is Xilinx standard LSB-first. + * Everything is Xilinx standard LSBit-first.   * The operations are all different.   * Commands are 16 bits long, presented to the ICAP interface 8 bits at a time.  */ @@ -30,7 +30,7 @@  /* bit swap end-for-end */ -static unsigned char +static inline unsigned char  swap8(unsigned char x)  {    unsigned char r = 0; @@ -50,52 +50,50 @@ swap8(unsigned char x)  void  wr_icap(uint8_t x)  { -	uint8_t t = swap8(x); - -	icap_regs->icap = t; //DEBUG: does not swap bits +    icap_regs->icap = swap8(x);  }  uint8_t  rd_icap(void)  { -	return swap8(icap_regs->icap); +    return swap8(icap_regs->icap);  }  void  icap_reload_fpga(uint32_t flash_address) -//this DOES NOT WORK right now. reboot is not getting executed correctly.  { -	union { -		uint32_t i; -		uint8_t c[4]; -	} t; -	t.i = flash_address; - -	//note! t.c[0] MUST contain the byte-wide read command for the flash device used. -	//for the 25P64, and most other flash devices, this is 0x03. -	t.c[0] = READ_CMD; //legacy command, use FAST_READ_CMD 0x0B after testing - -	//TODO: look up the watchdog timer, ensure it won't fire too soon - -  //UG332 p279 -//	wr_icap(0xff); -//	wr_icap(0xff); //dummy word, probably unnecessary -	wr_icap(0xAA); -	wr_icap(0x99); //sync word -	wr_icap(0x32); -	wr_icap(0x61); //Type 1 write General 1 (1 word) -	wr_icap(t.c[2]); //bits 15-8 -	wr_icap(t.c[3]); //bits 7-0 -	wr_icap(0x32); -	wr_icap(0x81); //Type 1 write General 2 (1 word) -	wr_icap(t.c[0]); //C0-C8, the byte-wide read command -	wr_icap(t.c[1]); //Upper 8 bits of 24-bit address -	wr_icap(0x30); -	wr_icap(0xA1); //Type 1 write CMD (1 word) -	wr_icap(0x00); -	wr_icap(0x0E); //REBOOT command -	wr_icap(0x20); -	wr_icap(0x00); //Type 1 NOP - +    union { +        uint32_t i; +        uint8_t c[4]; +    } t; +    t.i = flash_address; + +    //note! t.c[0] MUST contain the byte-wide read command for the flash device used. +    //for the 25P64, and most other flash devices, this is 0x03. +    t.c[0] = FAST_READ_CMD; + +    //TODO: look up the watchdog timer, ensure it won't fire too soon + +    //UG332 p279 +    wr_icap(0xff); +    wr_icap(0xff); //dummy word, probably unnecessary +    wr_icap(0xAA); +    wr_icap(0x99); //sync word +    wr_icap(0x32); +    wr_icap(0x61); //Type 1 write General 1 (1 word) +    wr_icap(t.c[2]); //bits 15-8 +    wr_icap(t.c[3]); //bits 7-0 +    wr_icap(0x32); +    wr_icap(0x81); //Type 1 write General 2 (1 word) +    wr_icap(t.c[0]); //C0-C8, the byte-wide read command +    wr_icap(t.c[1]); //Upper 8 bits of 24-bit address +    wr_icap(0x30); +    wr_icap(0xA1); //Type 1 write CMD (1 word) +    wr_icap(0x00); +    wr_icap(0x0E); //REBOOT command +    wr_icap(0x20); +    wr_icap(0x00); //Type 1 NOP +    wr_icap(0x20); +    wr_icap(0x00);  } diff --git a/host/utils/usrp2p_fw_update.py b/host/utils/usrp2p_fw_update.py index 1cd735796..0c07c398d 100755 --- a/host/utils/usrp2p_fw_update.py +++ b/host/utils/usrp2p_fw_update.py @@ -146,25 +146,38 @@ def get_flash_info(ip):    return (memory_size_bytes, sector_size_bytes) -def burn_fw(ip, fw, fpga): +def burn_fw(ip, fw, fpga, reset, safe):    init_update(ip)    (flash_size, sector_size) = get_flash_info(ip)    print "Flash size: %i\nSector size: %i" % (flash_size, sector_size) -  if fpga:  +  if fpga: +    if safe: +        image_location = SAFE_FPGA_IMAGE_LOCATION_ADDR +    else: +        image_location = PROD_FPGA_IMAGE_LOCATION_ADDR +          fpga_file = open(fpga, 'rb')      fpga_image = fpga_file.read() -    erase_image(ip, SAFE_FPGA_IMAGE_LOCATION_ADDR, FPGA_IMAGE_SIZE_BYTES) -    write_image(ip, fpga_image, SAFE_FPGA_IMAGE_LOCATION_ADDR) #TODO: DO NOT WRITE SAFE IMAGE! this is only here because the bootloader isn't finished yet -    verify_image(ip, fpga_image, SAFE_FPGA_IMAGE_LOCATION_ADDR) +    erase_image(ip, image_location, FPGA_IMAGE_SIZE_BYTES) +    write_image(ip, fpga_image, image_location) +    verify_image(ip, fpga_image, image_location)    if fw: +    if safe: +        image_location = SAFE_FW_IMAGE_LOCATION_ADDR +    else: +        image_location = PROD_FW_IMAGE_LOCATION_ADDR +              fw_file = open(fw, 'rb')      fw_image = fw_file.read() -    erase_image(ip, PROD_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES) -    write_image(ip, fw_image, PROD_FW_IMAGE_LOCATION_ADDR) -    verify_image(ip, fw_image, PROD_FW_IMAGE_LOCATION_ADDR) +    erase_image(ip, image_location, FW_IMAGE_SIZE_BYTES) +    write_image(ip, fw_image, image_location) +    verify_image(ip, fw_image, image_location) +     +  if reset: +    reset_usrp(ip)  def write_image(ip, image, addr):  #we split the image into smaller (256B) bits and send them down the wire @@ -208,6 +221,14 @@ def verify_image(ip, image, addr):      print "Verify failed. Image did not write correctly."    else:      print "Success." +     +def reset_usrp(ip): +    out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL, seq(), 0, 0, "") +    in_pkt = send_and_recv(out_pkt, ip) +     +    (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) +    if pktid == update_id_t.USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG: +        raise Exception, "Device failed to reset."  def erase_image(ip, addr, length):    #get flash info first @@ -234,17 +255,17 @@ def erase_image(ip, addr, length):    print "\tFinished." -#def verify_image(ip, image, addr): -  ########################################################################  # command line options  ########################################################################  def get_options():      parser = optparse.OptionParser() -    parser.add_option("--ip",   type="string",       help="USRP2P firmware address",        default='') -    parser.add_option("--fw",   type="string",       help="firmware image path (optional)", default='') -    parser.add_option("--fpga", type="string",       help="fpga image path (optional)",     default='') +    parser.add_option("--ip",   type="string",                 help="USRP2P firmware address",        default='') +    parser.add_option("--fw",   type="string",                 help="firmware image path (optional)", default='') +    parser.add_option("--fpga", type="string",                 help="fpga image path (optional)",     default='') +    parser.add_option("--reset", action="store_true",          help="reset the device after writing", default=False) +    parser.add_option("--overwrite-safe", action="store_true", help="never ever use this option", default=False)      (options, args) = parser.parse_args()      return options @@ -256,5 +277,13 @@ if __name__=='__main__':      options = get_options()      if not options.ip: raise Exception, 'no ip address specified' -    if not options.fpga and not options.fw: raise Exception, 'Must specify either a firmware image or FPGA image.' -    burn_fw(ip=options.ip, fw=options.fw, fpga=options.fpga) +    if not options.fpga and not options.fw and not options.reset: raise Exception, 'Must specify either a firmware image or FPGA image, and/or reset.' +     +    if options.overwrite_safe: +        print("Are you REALLY, REALLY sure you want to overwrite the safe image? This is ALMOST ALWAYS a terrible idea.") +        print("If your image is faulty, your USRP2+ will become a brick until reprogrammed via JTAG.") +        response = raw_input("""Type "yes" to continue, or anything else to quit: """) +        if response != "yes": +            sys.exit(0) +     +    burn_fw(ip=options.ip, fw=options.fw, fpga=options.fpga, reset=options.reset, safe=options.overwrite_safe) | 
