From f72ad02f5ec370f45995ecd2b3e8b322e9a7e4dc Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Mon, 26 Jul 2010 15:33:30 -0700 Subject: New branch with firmware dir from USRP2P branch. --- firmware/microblaze/usrp2p/bootloader/.gitignore | 11 ++ firmware/microblaze/usrp2p/bootloader/Makefile.am | 39 ++++ .../microblaze/usrp2p/bootloader/fpga_bootloader.c | 202 +++++++++++++++++++++ .../microblaze/usrp2p/bootloader/fw_bootloader.c | 50 +++++ firmware/microblaze/usrp2p/bootloader/icap_test.c | 31 ++++ .../microblaze/usrp2p/bootloader/init_bootloader.c | 108 +++++++++++ .../usrp2p/bootloader/serial_loader_burner.c | 49 +++++ .../microblaze/usrp2p/bootloader/spi_bootloader.c | 134 ++++++++++++++ firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld | 190 +++++++++++++++++++ 9 files changed, 814 insertions(+) create mode 100644 firmware/microblaze/usrp2p/bootloader/.gitignore create mode 100644 firmware/microblaze/usrp2p/bootloader/Makefile.am create mode 100644 firmware/microblaze/usrp2p/bootloader/fpga_bootloader.c create mode 100644 firmware/microblaze/usrp2p/bootloader/fw_bootloader.c create mode 100644 firmware/microblaze/usrp2p/bootloader/icap_test.c create mode 100644 firmware/microblaze/usrp2p/bootloader/init_bootloader.c create mode 100644 firmware/microblaze/usrp2p/bootloader/serial_loader_burner.c create mode 100644 firmware/microblaze/usrp2p/bootloader/spi_bootloader.c create mode 100644 firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld (limited to 'firmware/microblaze/usrp2p/bootloader') diff --git a/firmware/microblaze/usrp2p/bootloader/.gitignore b/firmware/microblaze/usrp2p/bootloader/.gitignore new file mode 100644 index 000000000..17b0f82f3 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/.gitignore @@ -0,0 +1,11 @@ +/*.ihx +/*.rmi +/*_rom +/*.elf +/*.bin +/*.dump +/*.log +/*.rom +/*.map +/Makefile +/Makefile.in diff --git a/firmware/microblaze/usrp2p/bootloader/Makefile.am b/firmware/microblaze/usrp2p/bootloader/Makefile.am new file mode 100644 index 000000000..1fc5daf9c --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/Makefile.am @@ -0,0 +1,39 @@ +# +# Copyright 2007,2008,2009 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +include $(top_srcdir)/Makefile.common + +ROM_LINKER_SCRIPT = u2p2-rom.ld + +# loads into 8K boot ram located at 0x0000_0000 +AM_CFLAGS = $(COMMON_CFLAGS) -I$(top_srcdir)/usrp2p +AM_LDFLAGS = -Wl,-T,$(ROM_LINKER_SCRIPT) $(COMMON_LFLAGS) -Wl,-defsym -Wl,_STACK_SIZE=1024 + +EXTRA_DIST = $(ROM_LINKER_SCRIPT) + +LDADD = $(top_srcdir)/usrp2p/libusrp2p.a + +noinst_PROGRAMS = \ + init_bootloader.elf + +init_bootloader_elf_SOURCES = init_bootloader.c + +.bin.rmi: + $(top_srcdir)/bin/bin_to_ram_macro_init.py $< $@ + +_generated_from_elf += \ + $(noinst_PROGRAMS:.elf=.rmi) diff --git a/firmware/microblaze/usrp2p/bootloader/fpga_bootloader.c b/firmware/microblaze/usrp2p/bootloader/fpga_bootloader.c new file mode 100644 index 000000000..9feff6ecd --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/fpga_bootloader.c @@ -0,0 +1,202 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * This code is bootloader f/w for the slot 0 fpga image. It's job is + * to figure out which fpga image should be loaded, and then to load + * that image from the SPI flash. (FIXME handle retries, errors, + * etc.) + * + * If the center button is down during boot, it loads firwmare + * from 0:0 instead of its normal action. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERBOSE 1 + +#define OUR_FPGA_IMAGE_NUMBER 0 // this code only runs in slot 0 + +void hal_uart_init(void); +void spif_init(void); +void i2c_init(void); +void bootconfig_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // nop stub +} + +static int +flash_addr_of_fpga_slot(unsigned int fpga_slot) +{ + const struct flashdir *fd = get_flashdir(); + return fd->slot[fpga_slot + fd->fpga_slot0].start << spi_flash_log2_sector_size(); +} + + +/* + * If the first 256 bytes of the image contain the string of bytes, + * ff ff ff ff aa 99 55 66, we consider it a likely bitstream. + */ +static bool +looks_like_a_bitstream(unsigned int fpga_slot) +{ + unsigned char buf[256]; + static const unsigned char pattern[] = { + 0xff, 0xff, 0xff, 0xff, 0xaa, 0x99, 0x55, 0x66 + }; + + // Read the first 256 bytes of the bitstream + spi_flash_read(flash_addr_of_fpga_slot(fpga_slot), sizeof(buf), buf); + + for (int i = 0; i <= sizeof(buf) - sizeof(pattern); i++) + if (memcmp(pattern, &buf[i], sizeof(pattern)) == 0) + return true; + + return false; +} + +static bool +plausible_bootconfig(bootconfig_t bc) +{ + // Are the fields in range? + if (!validate_bootconfig(bc)) + return false; + + if (!looks_like_a_bitstream(map_fpga_image_number_to_fpga_slot(bc.fpga_image_number))) + return false; + + return true; +} + +// Attempt to boot the fpga image specified in next_boot +static void +initial_boot_attempt(eeprom_boot_info_t *ee) +{ + if (ee->next_boot.fpga_image_number == OUR_FPGA_IMAGE_NUMBER){ + load_firmware(); + return; + } + + ee->nattempts = 1; + _bc_write_eeprom_shadow(); + + unsigned int target_slot = + map_fpga_image_number_to_fpga_slot(ee->next_boot.fpga_image_number); + int flash_addr = flash_addr_of_fpga_slot(target_slot); + + putstr("fpga_bootloader: chaining to "); + puthex4(ee->next_boot.fpga_image_number); + putchar(':'); + puthex4(ee->next_boot.firmware_image_number); + newline(); + mdelay(100); + + while (1){ + icap_reload_fpga(flash_addr); + } +} + +int +main(int argc, char **argv) +{ + hal_disable_ints(); // In case we got here via jmp 0x0 + hal_uart_init(); + i2c_init(); + bootconfig_init(); // Must come after i2c_init. + spif_init(); // Needed for get_flashdir. + + sr_leds->leds = 0xAAAA; + + putstr("\n\n>>> fpga_bootloader <<<\n"); + + putstr("\nBOOTSTS "); + int bootsts = icap_read_config_reg(rBOOTSTS); + puthex32_nl(bootsts); + putstr("STAT "); + int stat = icap_read_config_reg(rSTAT); + puthex32_nl(stat); + + bool fallback = + ((bootsts & (BOOTSTS_VALID_0 | BOOTSTS_FALLBACK_0)) + == (BOOTSTS_VALID_0 | BOOTSTS_FALLBACK_0)); + + if (fallback){ + puts("FALLBACK_0 is set"); + // FIXME handle fallback condition. + } + + const struct flashdir *fd = get_flashdir(); + if (fd == 0) + abort(); + + eeprom_boot_info_t *ee = _bc_get_eeprom_shadow(); + + if (VERBOSE){ + putstr("nattempts: "); + puthex8_nl(ee->nattempts); + } + + mdelay(500); // wait for low-pass on switches + putstr("switches: "); puthex32_nl(readback->switches); + + bool center_btn_down = (readback->switches & BTN_CENTER) != 0; + if (center_btn_down){ + putstr("Center button is down!\n"); + // Force boot of image 0:0 + ee->next_boot = make_bootconfig(0, 0); + } + + // if next_boot is valid, try it + if (plausible_bootconfig(ee->next_boot)) + initial_boot_attempt(ee); // no return + + // if default_boot is valid, try it + if (plausible_bootconfig(ee->default_boot)){ + ee->next_boot = ee->default_boot; + initial_boot_attempt(ee); // no return + } + + // If we're here, we're in trouble. Try all of them... + for (int i = 0; i < 4; i++){ + bootconfig_t bc = make_bootconfig(i, 0); + if (plausible_bootconfig(bc)){ + ee->next_boot = bc; + initial_boot_attempt(ee); // no return + } + } + + // FIXME, try to find something we can load + puts("\n!!! Failed to find a valid FPGA bitstream!\n\n"); + + return 0; +} diff --git a/firmware/microblaze/usrp2p/bootloader/fw_bootloader.c b/firmware/microblaze/usrp2p/bootloader/fw_bootloader.c new file mode 100644 index 000000000..a2c32bf8e --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/fw_bootloader.c @@ -0,0 +1,50 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + + +void hal_uart_init(void); +void spif_init(void); +void i2c_init(void); +void bootconfig_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // nop stub +} + +int +main(int argc, char **argv) +{ + hal_disable_ints(); // In case we got here via jmp 0x0 + hal_uart_init(); + i2c_init(); + bootconfig_init(); // Must come after i2c_init. + spif_init(); // Needed for get_flashdir. + + load_firmware(); +} diff --git a/firmware/microblaze/usrp2p/bootloader/icap_test.c b/firmware/microblaze/usrp2p/bootloader/icap_test.c new file mode 100644 index 000000000..5feb9d014 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/icap_test.c @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include +#include +#include +#include + +void delay(uint32_t t) { + while(t-- != 0) asm("NOP"); +} + + +int main(int argc, char *argv[]) { + pic_init(); + hal_uart_init(); + puts("\nStarting delay...\n"); + + output_regs->leds = 0xFF; + delay(4000000); + output_regs->leds = 0x00; + delay(4000000); + + puts("Rebooting FPGA to 0x00000000\n"); + icap_reload_fpga((uint32_t)0x00000000); + + return 0; +} diff --git a/firmware/microblaze/usrp2p/bootloader/init_bootloader.c b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c new file mode 100644 index 000000000..15d719d73 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c @@ -0,0 +1,108 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + */ + +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // nop stub +} + +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 + + ihex_record_t ihex_record; + ihex_record.data = ihx; + + while(1) { + gets(buf); + + if(!ihex_parse(buf, &ihex_record)) { //RAM data record is valid + if(ihex_record.addr >= RAM_BASE) { //it's expecting to see FULLY RELOCATED IHX RECORDS. every address referenced to 0x8000, including vectors. + memcpy((void *) (ihex_record.addr), ihex_record.data, ihex_record.length); + puts("OK"); + } else if(ihex_record.type == 1) { //end of record + puts("OK"); + //load main firmware + start_program(RAM_BASE); + puts("ERROR: main image returned! Back in IHEX load mode."); + } else puts("NOK"); //RAM loads do not support extended segment address records (04) -- upper 16 bits are always "0". + } else puts("NOK"); + } +} + +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(); + spif_init(); +// i2c_init(); //for EEPROM + puts("USRP2+ bootloader\n"); + + if(BUTTON_PUSHED) { //see memory_map.h + puts("Starting USRP2+ in safe mode."); + if(is_valid_fw_image(SAFE_FW_IMAGE_LOCATION_ADDR)) { + 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); + } else { + puts("ERROR: no safe firmware image available. I am a brick. Feel free to load IHEX to RAM."); + 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); + } + 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); + return 1; + } + puts("No valid production firmware found. Trying safe firmware..."); + if(is_valid_fw_image(SAFE_FW_IMAGE_LOCATION_ADDR)) { + 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 + } + puts("ERROR: no safe firmware image available. I am a brick. Feel free to load IHEX to RAM."); + load_ihex(); + + return 0; +} diff --git a/firmware/microblaze/usrp2p/bootloader/serial_loader_burner.c b/firmware/microblaze/usrp2p/bootloader/serial_loader_burner.c new file mode 100644 index 000000000..4ac4df454 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/serial_loader_burner.c @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +void hal_uart_init(void); +void spif_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // nop stub +} + +int +main(int argc, char **argv) +{ + hal_uart_init(); + spif_init(); + + sr_leds->leds = 0; + mdelay(100); + sr_leds->leds = ~0; + mdelay(100); + sr_leds->leds = 0; + + puts("\n\n>>> stage1: serial_loader_burner <<<"); + + gdbstub2_main_loop(); +} diff --git a/firmware/microblaze/usrp2p/bootloader/spi_bootloader.c b/firmware/microblaze/usrp2p/bootloader/spi_bootloader.c new file mode 100644 index 000000000..678e66cf7 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/spi_bootloader.c @@ -0,0 +1,134 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + + +void hal_uart_init(void); +void spif_init(void); + +void pic_interrupt_handler() __attribute__ ((interrupt_handler)); + +void pic_interrupt_handler() +{ + // nop stub +} + +static void +error(int e) +{ + putstr("ERR"); + puthex8(e); + newline(); +} + +static void +load(uint32_t flash_addr, uint32_t ram_addr, uint32_t size) +{ + spi_flash_read(flash_addr, size, (void *) ram_addr); +} + +static bool +load_from_slot(const struct flashdir *fd, int fw_slot) +{ + putstr("Loading f/w image "); + putchar('0' + fw_slot); + putstr("... "); + + if (fw_slot >= fd->fw_nslots){ + error(1); + return false; + } + + int slot = fw_slot + fd->fw_slot0; + if (fd->slot[slot].start == 0 || fd->slot[slot].start == 0xffff + || fd->slot[slot].len == 0 || fd->slot[slot].len == 0xffff){ + error(2); + return false; + } + + uint32_t sbf_base = fd->slot[slot].start << spi_flash_log2_sector_size(); + uint32_t sbf_len = fd->slot[slot].len << spi_flash_log2_sector_size(); + uint32_t sbf_offset = 0; + + struct sbf_header sbf; + spi_flash_read(sbf_base, sizeof(struct sbf_header), &sbf); + if (sbf.magic != SBF_MAGIC || sbf.nsections > SBF_MAX_SECTIONS){ + error(3); + return false; + } + sbf_offset += sizeof(struct sbf_header); + + unsigned int i; + for (i = 0; i < sbf.nsections; i++){ + if (sbf_offset + sbf.sec_desc[i].length > sbf_len){ + error(4); + return false; + } + load(sbf_offset + sbf_base, + sbf.sec_desc[i].target_addr, + sbf.sec_desc[i].length); + sbf_offset += sbf.sec_desc[i].length; + } + putstr("Done!"); + + typedef void (*fptr_t)(void); + (*(fptr_t) sbf.entry)(); // almost certainly no return + + return true; +} + +int +main(int argc, char **argv) +{ + hal_uart_init(); + spif_init(); + + sr_leds->leds = 0; + mdelay(100); + sr_leds->leds = ~0; + mdelay(100); + sr_leds->leds = 0; + + putstr("\n>>> spi_bootloader <<<\n"); + + const struct flashdir *fd = get_flashdir(); + if (fd == 0) + abort(); + + while(1){ + int sw; + int fw_slot; + + sw = readback->switches; + fw_slot = sw & 0x7; + + if (!load_from_slot(fd, fw_slot)){ + if (fw_slot != 0){ + putstr("Falling back to slot 0\n"); + load_from_slot(fd, 0); + } + } + } +} diff --git a/firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld b/firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld new file mode 100644 index 000000000..4c9eaa8e5 --- /dev/null +++ b/firmware/microblaze/usrp2p/bootloader/u2p2-rom.ld @@ -0,0 +1,190 @@ +/* + * Same as default, but with bss and stack moved to top 2K of main ram + * Copied from qr-rom.ld + */ + +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-microblaze", "", "") +/*SEARCH_DIR("/home/eb/build/Xilinx_EDK_GNU_10.1i/mb/release/lin/mb/microblaze-xilinx-elf/lib");*/ + + +ENTRY(_start) +_TEXT_START_ADDR = DEFINED(_TEXT_START_ADDR) ? _TEXT_START_ADDR : 0x50; +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x0; +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x400; +_BSS_START_ADDR = DEFINED(_BSS_START_ADDR) ? _BSS_START_ADDR : 0xF800; +SECTIONS +{ + .vectors.reset 0x0 : { KEEP (*(.vectors.reset)) } = 0 + .vectors.sw_exception 0x8 : { KEEP (*(.vectors.sw_exception)) } = 0 + .vectors.interrupt 0x10 : { KEEP (*(.vectors.interrupt)) } = 0 + .vectors.debug_sw_break 0x18 : { KEEP (*(.vectors.debug_sw_break)) } = 0 + .vectors.hw_exception 0x20 : { KEEP (*(.vectors.hw_exception)) } = 0 + . = _TEXT_START_ADDR; + _ftext = .; + .text : { + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + } + _etext = .; + .init : { KEEP (*(.init)) } =0 + .fini : { KEEP (*(.fini)) } =0 + PROVIDE (__CTOR_LIST__ = .); + PROVIDE (___CTOR_LIST__ = .); + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + PROVIDE (__CTOR_END__ = .); + PROVIDE (___CTOR_END__ = .); + PROVIDE (__DTOR_LIST__ = .); + PROVIDE (___DTOR_LIST__ = .); + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + PROVIDE (__DTOR_END__ = .); + PROVIDE (___DTOR_END__ = .); + . = ALIGN(4); + _frodata = . ; + .rodata : { + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + CONSTRUCTORS; /* Is this needed? */ + } + _erodata = .; + /* Alignments by 8 to ensure that _SDA2_BASE_ on a word boundary */ + /* Note that .sdata2 and .sbss2 must be contiguous */ + . = ALIGN(8); + _ssrw = .; + .sdata2 : { + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + } + . = ALIGN(4); + .sbss2 : { + PROVIDE (__sbss2_start = .); + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + PROVIDE (__sbss2_end = .); + } + . = ALIGN(8); + _essrw = .; + _ssrw_size = _essrw - _ssrw; + PROVIDE (_SDA2_BASE_ = _ssrw + (_ssrw_size / 2 )); + . = ALIGN(4); + _fdata = .; + .data : { + *(.data) + *(.gnu.linkonce.d.*) + CONSTRUCTORS; /* Is this needed? */ + } + _edata = . ; + /* Added to handle pic code */ + .got : { + *(.got) + } + .got1 : { + *(.got1) + } + .got2 : { + *(.got2) + } + /* Added by Sathya to handle C++ exceptions */ + .eh_frame : { + *(.eh_frame) + } + .jcr : { + *(.jcr) + } + .gcc_except_table : { + *(.gcc_except_table) + } + /* Alignments by 8 to ensure that _SDA_BASE_ on a word boundary */ + /* Note that .sdata and .sbss must be contiguous */ + . = ALIGN(8); + _ssro = .; + .sdata : { + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + } + . = ALIGN(4); + .sbss : { + PROVIDE (__sbss_start = .); + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + PROVIDE (__sbss_end = .); + } + . = ALIGN(8); + _essro = .; + _ssro_size = _essro - _ssro; + PROVIDE (_SDA_BASE_ = _ssro + (_ssro_size / 2 )); + . = _BSS_START_ADDR; + . = ALIGN(4); + _fbss = .; + .bss : { + PROVIDE (__bss_start = .); + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + PROVIDE (__bss_end = .); + } + . = ALIGN(4); + .heap : { + _heap = .; + _heap_start = .; + . += _HEAP_SIZE; + _heap_end = .; + } + _end = .; + . = ALIGN(4); + . = 0xFFF0; + .stack : { + /* + _stack_end = .; + . += _STACK_SIZE; + . = ALIGN(8); + _stack = .; + _end = .; + */ + _stack_end = .; + _stack = .; + } + .tdata : { + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + } + .tbss : { + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + } +} -- cgit v1.2.3 From c205cd329b37f24060ff20c23bc91249969502a1 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Thu, 7 Oct 2010 18:09:53 -0700 Subject: U2P: Bootloader/ICAP updates. 2-stage bootloader works. Uses EEPROM for state info. --- firmware/microblaze/lib/xilinx_s3_icap.c | 101 --------------------- firmware/microblaze/usrp2p/Makefile.am | 1 + firmware/microblaze/usrp2p/bootloader/Makefile.am | 2 +- .../microblaze/usrp2p/bootloader/init_bootloader.c | 53 ++++++++--- firmware/microblaze/usrp2p/bootloader_utils.c | 18 ++-- firmware/microblaze/usrp2p/udp_fw_update.c | 2 + firmware/microblaze/usrp2p/xilinx_s3_icap.c | 99 ++++++++++++++++++++ host/utils/usrp2p_fw_update.py | 59 +++++++++--- 8 files changed, 197 insertions(+), 138 deletions(-) delete mode 100644 firmware/microblaze/lib/xilinx_s3_icap.c create mode 100644 firmware/microblaze/usrp2p/xilinx_s3_icap.c (limited to 'firmware/microblaze/usrp2p/bootloader') diff --git a/firmware/microblaze/lib/xilinx_s3_icap.c b/firmware/microblaze/lib/xilinx_s3_icap.c deleted file mode 100644 index 8aa7fd297..000000000 --- a/firmware/microblaze/lib/xilinx_s3_icap.c +++ /dev/null @@ -1,101 +0,0 @@ -/* -*- c -*- */ -/* - * Copyright 2009 Ettus Research LLC - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -/* 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. - * The operations are all different. - * Commands are 16 bits long, presented to the ICAP interface 8 bits at a time. -*/ - -#include -#include -#include //for READ_CMD - - -/* bit swap end-for-end */ -static unsigned char -swap8(unsigned char x) -{ - unsigned char r = 0; - r |= (x >> 7) & 0x01; - r |= (x >> 5) & 0x02; - r |= (x >> 3) & 0x04; - r |= (x >> 1) & 0x08; - - r |= (x << 1) & 0x10; - r |= (x << 3) & 0x20; - r |= (x << 5) & 0x40; - r |= (x << 7) & 0x80; - - return r; -} - -void -wr_icap(uint8_t x) -{ - uint8_t t = swap8(x); - - icap_regs->icap = t; //DEBUG: does not swap bits -} - -uint8_t -rd_icap(void) -{ - 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 - -} 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 #include #include +#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 #include #include #include - 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 #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/usrp2p/xilinx_s3_icap.c b/firmware/microblaze/usrp2p/xilinx_s3_icap.c new file mode 100644 index 000000000..50c85231c --- /dev/null +++ b/firmware/microblaze/usrp2p/xilinx_s3_icap.c @@ -0,0 +1,99 @@ +/* -*- c -*- */ +/* + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +/* 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 LSBit-first. + * The operations are all different. + * Commands are 16 bits long, presented to the ICAP interface 8 bits at a time. +*/ + +#include +#include +#include //for READ_CMD + + +/* bit swap end-for-end */ +static inline unsigned char +swap8(unsigned char x) +{ + unsigned char r = 0; + r |= (x >> 7) & 0x01; + r |= (x >> 5) & 0x02; + r |= (x >> 3) & 0x04; + r |= (x >> 1) & 0x08; + + r |= (x << 1) & 0x10; + r |= (x << 3) & 0x20; + r |= (x << 5) & 0x40; + r |= (x << 7) & 0x80; + + return r; +} + +void +wr_icap(uint8_t x) +{ + icap_regs->icap = swap8(x); +} + +uint8_t +rd_icap(void) +{ + return swap8(icap_regs->icap); +} + + +void +icap_reload_fpga(uint32_t flash_address) +{ + 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) -- cgit v1.2.3 From 4ed75835c8c1b7b633223cd7ad11269e84c41701 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Thu, 7 Oct 2010 18:12:51 -0700 Subject: U2P: Whoops. --- firmware/microblaze/usrp2p/bootloader/init_bootloader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'firmware/microblaze/usrp2p/bootloader') diff --git a/firmware/microblaze/usrp2p/bootloader/init_bootloader.c b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c index 8b513002d..3571313ff 100644 --- a/firmware/microblaze/usrp2p/bootloader/init_bootloader.c +++ b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c @@ -33,7 +33,7 @@ bool find_safe_booted_flag(void) { unsigned char flag_byte; i2c_read(SAFE_FLAG_LOCATION, &flag_byte, 1); - return (flag_byte != 0x5E); + return (flag_byte == 0x5E); } void set_safe_booted_flag(bool flag) { -- cgit v1.2.3 From 7db726e9b45b972c8fcb0c1dc366919e11256cc1 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Fri, 8 Oct 2010 12:50:00 -0700 Subject: U2P: Bootloader works, successfully loads production image. Split I2C into async and sync halves to keep the size of the bootloader small. --- firmware/microblaze/apps/txrx_uhd.c | 1 + firmware/microblaze/lib/Makefile.inc | 1 + firmware/microblaze/lib/i2c.c | 177 +----------------- firmware/microblaze/lib/i2c.h | 21 --- firmware/microblaze/lib/i2c_async.c | 206 +++++++++++++++++++++ firmware/microblaze/lib/i2c_async.h | 50 +++++ firmware/microblaze/lib/u2_init.c | 2 + firmware/microblaze/usrp2p/bootloader/Makefile.am | 2 +- .../microblaze/usrp2p/bootloader/init_bootloader.c | 10 +- host/lib/usrp/usrp2/fw_common.h | 2 + 10 files changed, 270 insertions(+), 202 deletions(-) create mode 100644 firmware/microblaze/lib/i2c_async.c create mode 100644 firmware/microblaze/lib/i2c_async.h (limited to 'firmware/microblaze/usrp2p/bootloader') diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index 44be2cc9c..482332f7c 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -42,6 +42,7 @@ #include #include "clocks.h" #include "usrp2/fw_common.h" +#include #include #include #include diff --git a/firmware/microblaze/lib/Makefile.inc b/firmware/microblaze/lib/Makefile.inc index ae123f531..349ff2cd0 100644 --- a/firmware/microblaze/lib/Makefile.inc +++ b/firmware/microblaze/lib/Makefile.inc @@ -32,6 +32,7 @@ COMMON_SRCS = \ $(top_srcdir)/lib/hal_io.c \ $(top_srcdir)/lib/hal_uart.c \ $(top_srcdir)/lib/i2c.c \ + $(top_srcdir)/lib/i2c_async.c \ $(top_srcdir)/lib/mdelay.c \ $(top_srcdir)/lib/memcpy_wa.c \ $(top_srcdir)/lib/memset_wa.c \ diff --git a/firmware/microblaze/lib/i2c.c b/firmware/microblaze/lib/i2c.c index 177341267..d230f462c 100644 --- a/firmware/microblaze/lib/i2c.c +++ b/firmware/microblaze/lib/i2c.c @@ -20,7 +20,6 @@ #include "memory_map.h" #include "stdint.h" #include -#include "pic.h" #include "nonstdio.h" #define MAX_WB_DIV 4 // maximum wishbone divisor (from 100 MHz MASTER_CLK) @@ -37,18 +36,6 @@ static uint16_t prescaler_values[MAX_WB_DIV+1] = { PRESCALER(4), // 4: 25 MHz }; -//asynchronous (interrupt-driven) i2c state variables -volatile uint8_t i2c_buf[17]; //tx/rx data transfer buffer -volatile uint8_t *volatile i2c_bufptr = i2c_buf; //ptr to current position -volatile uint8_t i2c_len = 0; //length remaining in current transfer -volatile i2c_state_t i2c_state = I2C_STATE_IDLE; //current I2C transfer state -i2c_dir_t i2c_dir; //I2C transfer direction - -void (*volatile i2c_callback)(void); //function pointer to i2c callback to be called when transaction is complete - -static void i2c_irq_handler(unsigned irq); -inline void i2c_async_err(void); - void i2c_init(void) { @@ -64,8 +51,8 @@ i2c_init(void) i2c_regs->ctrl = I2C_CTRL_EN; //| I2C_CTRL_IE; // enable core - // FIXME interrupt driven? - pic_register_handler(IRQ_I2C, i2c_irq_handler); + //now this is done separately to maintain common code for async and sync + //pic_register_handler(IRQ_I2C, i2c_irq_handler); } static inline void @@ -140,163 +127,3 @@ i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len) return false; } -static void i2c_irq_handler(unsigned irq) { -//i2c state machine. - - //printf("I2C irq handler\n"); - //first let's make sure nothing is f'ed up - //TODO: uncomment this error checking when we have some way to handle errors -// if(((i2c_regs->cmd_status & I2C_ST_RXACK) != 0) && i2c_dir == I2C_DIR_WRITE) { //we got a NACK and we didn't send it -// printf("\tNACK received\n"); -// i2c_async_err(); -// return; -// }// else printf("\tACK received, proceeding\n"); - - if(i2c_regs->cmd_status & I2C_ST_AL) { - printf("\tArbitration lost!\n"); - i2c_async_err(); - return; - } - - if(i2c_regs->cmd_status & I2C_ST_TIP) { - //printf("\tI2C still busy in interrupt\n"); - return; - } - - //now decide what to do - switch(i2c_state) { - - case I2C_STATE_IDLE: - //this is an error. in idle state, we shouldn't be transferring data, and the fact that the IRQ fired is terrible bad. - printf("AAAAAHHHHH INTERRUPT IN THE IDLE STATE AAAHHHHHHHHH\n"); - i2c_async_err(); - break; - - case I2C_STATE_CONTROL_BYTE_SENT: //here we've sent the control byte, and we're either clocking data in or out now, but we haven't received a byte yet. - case I2C_STATE_DATA: //here we're sending/receiving data and if we're receiving there's data in the data reg - - //if(i2c_state == I2C_STATE_DATA) printf("\tI2C in state DATA with dir=%d and len=%d\n", i2c_dir, i2c_len); - //else printf("\tI2C in state CONTROL_BYTE_SENT with dir=%d and len=%d\n", i2c_dir, i2c_len); - - if(i2c_dir == I2C_DIR_READ) { - if(i2c_state == I2C_STATE_DATA) *(i2c_bufptr++) = i2c_regs->data; - //printf("\tRead %x\n", *(i2c_bufptr-1)); - //set up another data byte - if(i2c_len > 1) //only one more byte to transfer - i2c_regs->cmd_status = I2C_CMD_RD; - else - i2c_regs->cmd_status = I2C_CMD_RD | I2C_CMD_NACK | I2C_CMD_STOP; - } - else if(i2c_dir == I2C_DIR_WRITE) { - //write a byte - //printf("\tWriting %x\n", *i2c_bufptr); - i2c_regs->data = *(i2c_bufptr++); - if(i2c_len > 1) - i2c_regs->cmd_status = I2C_CMD_WR; - else { - //printf("\tGenerating STOP\n"); - i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_STOP; - } - }; - i2c_len--; - if(i2c_len == 0) i2c_state = I2C_STATE_LAST_BYTE; - else i2c_state = I2C_STATE_DATA; //takes care of the addr_sent->data transition - break; - - - case I2C_STATE_LAST_BYTE: //here we've already sent the last read request and the last data is waiting for us. - //printf("\tI2C in state LAST BYTE\n"); - - if(i2c_dir == I2C_DIR_READ) { - *(i2c_bufptr++) = i2c_regs->data; - //printf("\tRead %x\n", *(i2c_bufptr-1)); - i2c_state = I2C_STATE_DATA_READY; - } else { - i2c_state = I2C_STATE_IDLE; - } - i2c_regs->ctrl &= ~I2C_CTRL_IE; //disable interrupts until next time - - if(i2c_callback) { - i2c_callback(); //if we registered a callback, call it! - } - - break; - - - default: //terrible things have happened. - break; - } - -} - -void i2c_register_callback(void (*volatile callback)(void)) { - i2c_callback = callback; -} - -inline void i2c_async_err(void) { - i2c_state = I2C_STATE_IDLE; - i2c_regs->ctrl &= ~I2C_CTRL_IE; - printf("I2C error\n"); -//TODO: set an error flag instead of just dropping things on the floor - i2c_regs->cmd_status = I2C_CMD_STOP; -} - -bool i2c_async_read(uint8_t addr, unsigned int len) { - //printf("Starting async read\n"); - if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle - if(len == 0) return true; //just idiot-proofing - if(len > sizeof(i2c_buf)) return false; - - //disable I2C interrupts and clear pending interrupts on the I2C device - i2c_regs->ctrl &= ~I2C_CTRL_IE; - i2c_regs->cmd_status |= I2C_CMD_IACK; - - i2c_len = len; - i2c_dir = I2C_DIR_READ; - i2c_bufptr = i2c_buf; - //then set up the transfer by issuing the control byte - i2c_regs->ctrl |= I2C_CTRL_IE; - i2c_regs->data = (addr << 1) | 0x01; //7 bit addr and read bit - i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr - //update the state so the irq handler knows what's going on - i2c_state = I2C_STATE_CONTROL_BYTE_SENT; - return true; -} - -bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len) { - //printf("Starting async write\n"); - if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle - if(len > sizeof(i2c_buf)) return false; - - //disable I2C interrupts and clear pending interrupts on the I2C device - i2c_regs->ctrl &= ~I2C_CTRL_IE; - i2c_regs->cmd_status |= I2C_CMD_IACK; - - //copy the buffer into our own if writing - memcpy((void *)i2c_buf, buf, len); - - i2c_len = len; - i2c_dir = I2C_DIR_WRITE; - i2c_bufptr = i2c_buf; - //then set up the transfer by issuing the control byte - i2c_regs->ctrl |= I2C_CTRL_IE; - i2c_regs->data = (addr << 1) | 0x00; //7 bit addr and read bit - i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr - //update the state so the irq handler knows what's going on - i2c_state = I2C_STATE_CONTROL_BYTE_SENT; - - return true; -} - -//TODO: determine if it's better to read sequentially into the user's buffer, copy on transfer complete, or copy on request (shown below). probably best to copy on request. -bool i2c_async_data_ready(void *buf) { - if(i2c_state == I2C_STATE_DATA_READY) { - i2c_state = I2C_STATE_IDLE; - memcpy(buf, (void *)i2c_buf, (i2c_bufptr - i2c_buf)); //TODO: not really comfortable with this - //printf("Copying %d bytes to user buffer\n", i2c_bufptr-i2c_buf); - return true; - } - return false; -} - - diff --git a/firmware/microblaze/lib/i2c.h b/firmware/microblaze/lib/i2c.h index 77129e922..6ff0e6982 100644 --- a/firmware/microblaze/lib/i2c.h +++ b/firmware/microblaze/lib/i2c.h @@ -22,36 +22,15 @@ #include #include "stdint.h" -typedef enum { I2C_STATE_IDLE, - I2C_STATE_CONTROL_BYTE_SENT, - I2C_STATE_DATA, - I2C_STATE_LAST_BYTE, - I2C_STATE_DATA_READY, - I2C_STATE_ERROR - } i2c_state_t; - -typedef enum { I2C_DIR_WRITE=0, I2C_DIR_READ=1 } i2c_dir_t; - void i2c_init(void); bool i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len); bool i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len); -bool i2c_async_read(uint8_t addr, unsigned int len); -bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len); -bool i2c_async_data_ready(void *); -//static void i2c_irq_handler(unsigned irq); -void i2c_register_callback(void (*callback)(void)); - -// Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. -// Which EEPROM is determined by i2c_addr. See i2c_addr.h - bool eeprom_write (int i2c_addr, int eeprom_offset, const void *buf, int len); -bool eeprom_write_async (int i2c_addr, int eeprom_offset, const void *buf, int len, void (*callback)(void)); // Read 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. // Which EEPROM is determined by i2c_addr. See i2c_addr.h bool eeprom_read (int i2c_addr, int eeprom_offset, void *buf, int len); -bool eeprom_read_async(int i2c_addr, int eeprom_offset, void *buf, int len, void (*callback)(void)); #endif /* INCLUDED_I2C_H */ diff --git a/firmware/microblaze/lib/i2c_async.c b/firmware/microblaze/lib/i2c_async.c new file mode 100644 index 000000000..05c4c3a09 --- /dev/null +++ b/firmware/microblaze/lib/i2c_async.c @@ -0,0 +1,206 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + //i2c_async.c: asynchronous (interrupt-driven) routines for I2C. + //separated out here so we can have a small I2C lib for bootloader and + //retain interrupt-driven I2C for the main app. + +#include "memory_map.h" +#include "stdint.h" +#include +#include "pic.h" +#include "nonstdio.h" +#include "i2c_async.h" + + //asynchronous (interrupt-driven) i2c state variables +volatile uint8_t i2c_buf[17]; //tx/rx data transfer buffer +volatile uint8_t *volatile i2c_bufptr = i2c_buf; //ptr to current position +volatile uint8_t i2c_len = 0; //length remaining in current transfer +volatile i2c_state_t i2c_state = I2C_STATE_IDLE; //current I2C transfer state +i2c_dir_t i2c_dir; //I2C transfer direction + +void (*volatile i2c_callback)(void); //function pointer to i2c callback to be called when transaction is complete +static void i2c_irq_handler(unsigned irq); +inline void i2c_async_err(void); + +void i2c_register_handler(void) { + pic_register_handler(IRQ_I2C, i2c_irq_handler); +} + + +static void i2c_irq_handler(unsigned irq) { +//i2c state machine. + + //printf("I2C irq handler\n"); + //first let's make sure nothing is f'ed up + //TODO: uncomment this error checking when we have some way to handle errors +// if(((i2c_regs->cmd_status & I2C_ST_RXACK) != 0) && i2c_dir == I2C_DIR_WRITE) { //we got a NACK and we didn't send it +// printf("\tNACK received\n"); +// i2c_async_err(); +// return; +// }// else printf("\tACK received, proceeding\n"); + + if(i2c_regs->cmd_status & I2C_ST_AL) { + printf("\tArbitration lost!\n"); + i2c_async_err(); + return; + } + + if(i2c_regs->cmd_status & I2C_ST_TIP) { + //printf("\tI2C still busy in interrupt\n"); + return; + } + + //now decide what to do + switch(i2c_state) { + + case I2C_STATE_IDLE: + //this is an error. in idle state, we shouldn't be transferring data, and the fact that the IRQ fired is terrible bad. + printf("AAAAAHHHHH INTERRUPT IN THE IDLE STATE AAAHHHHHHHHH\n"); + i2c_async_err(); + break; + + case I2C_STATE_CONTROL_BYTE_SENT: //here we've sent the control byte, and we're either clocking data in or out now, but we haven't received a byte yet. + case I2C_STATE_DATA: //here we're sending/receiving data and if we're receiving there's data in the data reg + + //if(i2c_state == I2C_STATE_DATA) printf("\tI2C in state DATA with dir=%d and len=%d\n", i2c_dir, i2c_len); + //else printf("\tI2C in state CONTROL_BYTE_SENT with dir=%d and len=%d\n", i2c_dir, i2c_len); + + if(i2c_dir == I2C_DIR_READ) { + if(i2c_state == I2C_STATE_DATA) *(i2c_bufptr++) = i2c_regs->data; + //printf("\tRead %x\n", *(i2c_bufptr-1)); + //set up another data byte + if(i2c_len > 1) //only one more byte to transfer + i2c_regs->cmd_status = I2C_CMD_RD; + else + i2c_regs->cmd_status = I2C_CMD_RD | I2C_CMD_NACK | I2C_CMD_STOP; + } + else if(i2c_dir == I2C_DIR_WRITE) { + //write a byte + //printf("\tWriting %x\n", *i2c_bufptr); + i2c_regs->data = *(i2c_bufptr++); + if(i2c_len > 1) + i2c_regs->cmd_status = I2C_CMD_WR; + else { + //printf("\tGenerating STOP\n"); + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_STOP; + } + }; + i2c_len--; + if(i2c_len == 0) i2c_state = I2C_STATE_LAST_BYTE; + else i2c_state = I2C_STATE_DATA; //takes care of the addr_sent->data transition + break; + + + case I2C_STATE_LAST_BYTE: //here we've already sent the last read request and the last data is waiting for us. + //printf("\tI2C in state LAST BYTE\n"); + + if(i2c_dir == I2C_DIR_READ) { + *(i2c_bufptr++) = i2c_regs->data; + //printf("\tRead %x\n", *(i2c_bufptr-1)); + i2c_state = I2C_STATE_DATA_READY; + } else { + i2c_state = I2C_STATE_IDLE; + } + i2c_regs->ctrl &= ~I2C_CTRL_IE; //disable interrupts until next time + + if(i2c_callback) { + i2c_callback(); //if we registered a callback, call it! + } + + break; + + + default: //terrible things have happened. + break; + } + +} + +void i2c_register_callback(void (*volatile callback)(void)) { + i2c_callback = callback; +} + +inline void i2c_async_err(void) { + i2c_state = I2C_STATE_IDLE; + i2c_regs->ctrl &= ~I2C_CTRL_IE; + printf("I2C error\n"); +//TODO: set an error flag instead of just dropping things on the floor + i2c_regs->cmd_status = I2C_CMD_STOP; +} + +bool i2c_async_read(uint8_t addr, unsigned int len) { + //printf("Starting async read\n"); + if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle + if(len == 0) return true; //just idiot-proofing + if(len > sizeof(i2c_buf)) return false; + + //disable I2C interrupts and clear pending interrupts on the I2C device + i2c_regs->ctrl &= ~I2C_CTRL_IE; + i2c_regs->cmd_status |= I2C_CMD_IACK; + + i2c_len = len; + i2c_dir = I2C_DIR_READ; + i2c_bufptr = i2c_buf; + //then set up the transfer by issuing the control byte + i2c_regs->ctrl |= I2C_CTRL_IE; + i2c_regs->data = (addr << 1) | 0x01; //7 bit addr and read bit + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr + //update the state so the irq handler knows what's going on + i2c_state = I2C_STATE_CONTROL_BYTE_SENT; + return true; +} + +bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len) { + //printf("Starting async write\n"); + if(i2c_state != I2C_STATE_IDLE) return false; //sorry mario but your i2c is in another castle + if(len > sizeof(i2c_buf)) return false; + + //disable I2C interrupts and clear pending interrupts on the I2C device + i2c_regs->ctrl &= ~I2C_CTRL_IE; + i2c_regs->cmd_status |= I2C_CMD_IACK; + + //copy the buffer into our own if writing + memcpy((void *)i2c_buf, buf, len); + + i2c_len = len; + i2c_dir = I2C_DIR_WRITE; + i2c_bufptr = i2c_buf; + //then set up the transfer by issuing the control byte + i2c_regs->ctrl |= I2C_CTRL_IE; + i2c_regs->data = (addr << 1) | 0x00; //7 bit addr and read bit + i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; //generate start & start writing addr + //update the state so the irq handler knows what's going on + i2c_state = I2C_STATE_CONTROL_BYTE_SENT; + + return true; +} + +//TODO: determine if it's better to read sequentially into the user's buffer, copy on transfer complete, or copy on request (shown below). probably best to copy on request. +bool i2c_async_data_ready(void *buf) { + if(i2c_state == I2C_STATE_DATA_READY) { + i2c_state = I2C_STATE_IDLE; + memcpy(buf, (void *)i2c_buf, (i2c_bufptr - i2c_buf)); //TODO: not really comfortable with this + //printf("Copying %d bytes to user buffer\n", i2c_bufptr-i2c_buf); + return true; + } + return false; +} + diff --git a/firmware/microblaze/lib/i2c_async.h b/firmware/microblaze/lib/i2c_async.h new file mode 100644 index 000000000..e6095fca6 --- /dev/null +++ b/firmware/microblaze/lib/i2c_async.h @@ -0,0 +1,50 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INCLUDED_I2C_ASYNC_H +#define INCLUDED_I2C_ASYNC_H + +#include +#include "stdint.h" + +typedef enum { I2C_STATE_IDLE, + I2C_STATE_CONTROL_BYTE_SENT, + I2C_STATE_DATA, + I2C_STATE_LAST_BYTE, + I2C_STATE_DATA_READY, + I2C_STATE_ERROR + } i2c_state_t; + +typedef enum { I2C_DIR_WRITE=0, I2C_DIR_READ=1 } i2c_dir_t; + +bool i2c_async_read(uint8_t addr, unsigned int len); +bool i2c_async_write(uint8_t addr, const uint8_t *buf, unsigned int len); +bool i2c_async_data_ready(void *); +//static void i2c_irq_handler(unsigned irq); +void i2c_register_callback(void (*callback)(void)); +void i2c_register_handler(void); + +// Write 24LC024 / 24LC025 EEPROM on motherboard or daughterboard. +// Which EEPROM is determined by i2c_addr. See i2c_addr.h + +bool eeprom_write_async (int i2c_addr, int eeprom_offset, const void *buf, int len, void (*callback)(void)); +bool eeprom_read_async(int i2c_addr, int eeprom_offset, void *buf, int len, void (*callback)(void)); + +#endif /* INCLUDED_I2C_ASYNC_H */ diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c index 8d666b76b..099aafe83 100644 --- a/firmware/microblaze/lib/u2_init.c +++ b/firmware/microblaze/lib/u2_init.c @@ -23,6 +23,7 @@ #include "buffer_pool.h" #include "hal_uart.h" #include "i2c.h" +#include "i2c_async.h" #include "mdelay.h" #include "clocks.h" #include "usrp2/fw_common.h" @@ -59,6 +60,7 @@ u2_init(void) // init i2c so we can read our rev pic_init(); // progammable interrupt controller i2c_init(); + i2c_register_handler(); //for using async I2C hal_enable_ints(); get_hw_rev(); diff --git a/firmware/microblaze/usrp2p/bootloader/Makefile.am b/firmware/microblaze/usrp2p/bootloader/Makefile.am index eb72d937d..1fc5daf9c 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 i2c_sync.c +init_bootloader_elf_SOURCES = init_bootloader.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 3571313ff..e6c808f37 100644 --- a/firmware/microblaze/usrp2p/bootloader/init_bootloader.c +++ b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c @@ -15,7 +15,8 @@ #include #include #include -#include "i2c_sync.h" +#include +#include "usrp2/fw_common.h" #define SAFE_FLAG_LOCATION 247 @@ -31,14 +32,13 @@ void pic_interrupt_handler() bool find_safe_booted_flag(void) { unsigned char flag_byte; - i2c_read(SAFE_FLAG_LOCATION, &flag_byte, 1); - + eeprom_read(USRP2_I2C_ADDR_MBOARD, 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); + eeprom_write(USRP2_I2C_ADDR_MBOARD, SAFE_FLAG_LOCATION, &flag_byte, 1); } @@ -102,7 +102,7 @@ int main(int argc, char *argv[]) { 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); + delay(30000); //so serial output can finish icap_reload_fpga(PROD_FPGA_IMAGE_LOCATION_ADDR); } puts("No valid production FPGA image found.\nAttempting to load production firmware..."); diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 12ff1a76f..59e223e75 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -59,6 +59,8 @@ extern "C" { #define USRP2_EE_MBOARD_REV_MSB 0x01 //1 byte #define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes #define USRP2_EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian +#define USRP2_EE_MBOARD_SERIAL_NUM 0xF8 +#define USRP2_EE_MBOARD_BOOTLOADER_FLAGS 0xF7 typedef enum{ USRP2_CTRL_ID_HUH_WHAT = ' ', -- cgit v1.2.3 From 4a6990c5d3019ca6881464f135a315e3ec022b93 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Fri, 8 Oct 2010 13:38:55 -0700 Subject: USRP2P: Little bit of commonality in the include files. No functional change. --- firmware/microblaze/usrp2p/bootloader/init_bootloader.c | 6 ++---- host/lib/usrp/usrp2/fw_common.h | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'firmware/microblaze/usrp2p/bootloader') diff --git a/firmware/microblaze/usrp2p/bootloader/init_bootloader.c b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c index e6c808f37..2bbbd405e 100644 --- a/firmware/microblaze/usrp2p/bootloader/init_bootloader.c +++ b/firmware/microblaze/usrp2p/bootloader/init_bootloader.c @@ -18,8 +18,6 @@ #include #include "usrp2/fw_common.h" -#define SAFE_FLAG_LOCATION 247 - bool find_safe_booted_flag(void); void set_safe_booted_flag(bool flag); @@ -32,13 +30,13 @@ void pic_interrupt_handler() bool find_safe_booted_flag(void) { unsigned char flag_byte; - eeprom_read(USRP2_I2C_ADDR_MBOARD, SAFE_FLAG_LOCATION, &flag_byte, 1); + eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1); return (flag_byte == 0x5E); } void set_safe_booted_flag(bool flag) { unsigned char flag_byte = flag ? 0x5E : 0xDC; - eeprom_write(USRP2_I2C_ADDR_MBOARD, SAFE_FLAG_LOCATION, &flag_byte, 1); + eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1); } diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 59e223e75..67955c831 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -59,7 +59,6 @@ extern "C" { #define USRP2_EE_MBOARD_REV_MSB 0x01 //1 byte #define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes #define USRP2_EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian -#define USRP2_EE_MBOARD_SERIAL_NUM 0xF8 #define USRP2_EE_MBOARD_BOOTLOADER_FLAGS 0xF7 typedef enum{ -- cgit v1.2.3