diff options
Diffstat (limited to 'firmware')
-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 |
6 files changed, 91 insertions, 61 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); } |