aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/zpu/usrp2p/bootloader
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/zpu/usrp2p/bootloader')
-rw-r--r--firmware/zpu/usrp2p/bootloader/CMakeLists.txt12
-rw-r--r--firmware/zpu/usrp2p/bootloader/fpga_bootloader.c202
-rw-r--r--firmware/zpu/usrp2p/bootloader/fw_bootloader.c50
-rw-r--r--firmware/zpu/usrp2p/bootloader/icap_test.c31
-rw-r--r--firmware/zpu/usrp2p/bootloader/init_bootloader.c29
-rw-r--r--firmware/zpu/usrp2p/bootloader/serial_loader_burner.c49
-rw-r--r--firmware/zpu/usrp2p/bootloader/udp_bootloader.c200
7 files changed, 224 insertions, 349 deletions
diff --git a/firmware/zpu/usrp2p/bootloader/CMakeLists.txt b/firmware/zpu/usrp2p/bootloader/CMakeLists.txt
index 2c7efb43a..07f234302 100644
--- a/firmware/zpu/usrp2p/bootloader/CMakeLists.txt
+++ b/firmware/zpu/usrp2p/bootloader/CMakeLists.txt
@@ -33,8 +33,10 @@ MACRO(GEN_RMI target)
ENDMACRO(GEN_RMI)
########################################################################
-ADD_EXECUTABLE(init_bootloader.elf init_bootloader.c)
-TARGET_LINK_LIBRARIES(init_bootloader.elf libusrp2pfw)
-SET(GEN_OUTPUTS_BIN_SIZE 0x1fff)
-GEN_OUTPUTS(init_bootloader.elf)
-GEN_RMI(init_bootloader.bin)
+ADD_EXECUTABLE(bootloader.elf ${CMAKE_SOURCE_DIR}/apps/txrx_uhd.c)
+ADD_DEFINITIONS(-DUSRP2P)
+ADD_DEFINITIONS(-DBOOTLOADER)
+TARGET_LINK_LIBRARIES(bootloader.elf libusrp2pfw)
+SET(GEN_OUTPUTS_BIN_SIZE 0x3fff)
+GEN_OUTPUTS(bootloader.elf)
+GEN_RMI(bootloader.bin)
diff --git a/firmware/zpu/usrp2p/bootloader/fpga_bootloader.c b/firmware/zpu/usrp2p/bootloader/fpga_bootloader.c
deleted file mode 100644
index f5a71a8bb..000000000
--- a/firmware/zpu/usrp2p/bootloader/fpga_bootloader.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/* -*- c -*- */
-/*
- * Copyright 2009-2011 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 <http://www.gnu.org/licenses/>.
- */
-
-/*
- * 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 <stdlib.h>
-#include <hal_io.h>
-#include <nonstdio.h>
-#include <mdelay.h>
-#include <quadradio/flashdir.h>
-#include <xilinx_v5_icap.h>
-#include <bootconfig.h>
-#include <bootconfig_private.h>
-#include <spi_flash.h>
-#include <string.h>
-#include <bootloader_utils.h>
-#include <hal_interrupts.h>
-
-#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/zpu/usrp2p/bootloader/fw_bootloader.c b/firmware/zpu/usrp2p/bootloader/fw_bootloader.c
deleted file mode 100644
index de561cf22..000000000
--- a/firmware/zpu/usrp2p/bootloader/fw_bootloader.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- c -*- */
-/*
- * Copyright 2009-2011 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <memory_map.h>
-#include <nonstdio.h>
-#include <stdlib.h>
-#include <bootconfig.h>
-#include <bootconfig_private.h>
-#include <bootloader_utils.h>
-#include <hal_interrupts.h>
-
-
-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/zpu/usrp2p/bootloader/icap_test.c b/firmware/zpu/usrp2p/bootloader/icap_test.c
deleted file mode 100644
index 5feb9d014..000000000
--- a/firmware/zpu/usrp2p/bootloader/icap_test.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2010 Ettus Research LLC
- *
- */
-
-#include <memory_map.h>
-#include <hal_io.h>
-#include <xilinx_s3_icap.h>
-#include <nonstdio.h>
-
-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/zpu/usrp2p/bootloader/init_bootloader.c b/firmware/zpu/usrp2p/bootloader/init_bootloader.c
index 66481eb25..d797edce4 100644
--- a/firmware/zpu/usrp2p/bootloader/init_bootloader.c
+++ b/firmware/zpu/usrp2p/bootloader/init_bootloader.c
@@ -1,8 +1,19 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2010-2011 Ettus Research LLC
- *
- */
+//
+// Copyright 2010-2011 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 <http://www.gnu.org/licenses/>.
+//
#include <memory_map.h>
#include <nonstdio.h>
@@ -10,7 +21,6 @@
#include <xilinx_s3_icap.h>
#include <spi_flash.h>
#include <spi_flash_private.h>
-//#include <clocks.h>
#include <mdelay.h>
#include <ihex.h>
#include <bootloader_utils.h>
@@ -19,12 +29,7 @@
#include <i2c.h>
#include "usrp2/fw_common.h"
-//void pic_interrupt_handler() __attribute__ ((interrupt_handler));
-
-void pic_interrupt_handler()
-{
- // nop stub
-}
+#define BUTTON_PUSHED ((router_status->irqs & PIC_BUTTON) ? 0 : 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
diff --git a/firmware/zpu/usrp2p/bootloader/serial_loader_burner.c b/firmware/zpu/usrp2p/bootloader/serial_loader_burner.c
deleted file mode 100644
index 6d5d135ab..000000000
--- a/firmware/zpu/usrp2p/bootloader/serial_loader_burner.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2009-2011 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <hal_io.h>
-#include <nonstdio.h>
-#include <mdelay.h>
-#include <gdbstub2.h>
-
-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/zpu/usrp2p/bootloader/udp_bootloader.c b/firmware/zpu/usrp2p/bootloader/udp_bootloader.c
new file mode 100644
index 000000000..118de2ae9
--- /dev/null
+++ b/firmware/zpu/usrp2p/bootloader/udp_bootloader.c
@@ -0,0 +1,200 @@
+//
+// Copyright 2010-2011 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <lwip/ip.h>
+#include <lwip/udp.h>
+#include "u2_init.h"
+#include "memory_map.h"
+#include "spi.h"
+#include "hal_io.h"
+#include "pic.h"
+#include <stdbool.h>
+#include "ethernet.h"
+#include "nonstdio.h"
+#include <net/padded_eth_hdr.h>
+#include <net_common.h>
+#include "memcpy_wa.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include "clocks.h"
+#include "usrp2/fw_common.h"
+#include <i2c.h>
+#include <ethertype.h>
+#include <arp_cache.h>
+#include "udp_fw_update.h"
+#include "pkt_ctrl.h"
+#include "banal.h"
+#include <bootloader_utils.h>
+#include <spi_flash.h>
+#include <xilinx_s3_icap.h>
+#include <mdelay.h>
+
+#define BUTTON_PUSHED ((router_status->irqs & PIC_BUTTON) ? 0 : 1)
+
+static void handle_inp_packet(uint32_t *buff, size_t num_lines){
+
+ //test if its an ip recovery packet
+ typedef struct{
+ padded_eth_hdr_t eth_hdr;
+ char code[4];
+ union {
+ struct ip_addr ip_addr;
+ } data;
+ }recovery_packet_t;
+ recovery_packet_t *recovery_packet = (recovery_packet_t *)buff;
+ if (recovery_packet->eth_hdr.ethertype == 0xbeee && strncmp(recovery_packet->code, "addr", 4) == 0){
+ printf("Got ip recovery packet: "); print_ip_addr(&recovery_packet->data.ip_addr); newline();
+ set_ip_addr(&recovery_packet->data.ip_addr);
+ return;
+ }
+
+ //pass it to the slow-path handler
+ handle_eth_packet(buff, num_lines);
+}
+
+
+//------------------------------------------------------------------
+
+/*
+ * Called when eth phy state changes (w/ interrupts disabled)
+ */
+void link_changed_callback(int speed){
+ printf("\neth link changed: speed = %d\n", speed);
+ if (speed != 0){
+ hal_set_leds(LED_RJ45, LED_RJ45);
+ pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_MASTER);
+ send_gratuitous_arp();
+ }
+ else{
+ hal_set_leds(0x0, LED_RJ45);
+ pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_SLAVE);
+ }
+}
+
+static void do_the_bootload_thing(void) {
+
+ bool production_image = find_safe_booted_flag();
+ set_safe_booted_flag(0); //haven't booted yet
+
+ if(BUTTON_PUSHED) { //see memory_map.h
+ puts("Starting USRP2+ in safe mode. I am a brick. Feel free to reprogram me via the UDP burner.");
+ return;
+ //no longer necessary since we can just burn from UDP via the bootloader now
+/*
+ if(is_valid_fw_image(SAFE_FW_IMAGE_LOCATION_ADDR)) {
+ set_safe_booted_flag(1); //let the firmware know it's the safe image
+ spi_flash_read(SAFE_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE);
+ start_program();
+ 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 reprogram me via the UDP burner.");
+ return;
+ }
+*/
+ }
+
+ 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);
+ mdelay(300); //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...");
+ }
+ 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);
+ puts("Finished loading. Starting image.");
+ mdelay(300);
+ start_program();
+ 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.
+ mdelay(300);
+ icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR);
+ return;
+ }
+ 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);
+ puts("Finished loading. Starting image.");
+ mdelay(300);
+ start_program();
+ puts("ERROR: return from main program! This should never happen!");
+ mdelay(300);
+ icap_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR);
+ return;
+ }
+ puts("ERROR: no safe firmware image available. I am a brick. Feel free to reprogram me via the UDP burner.");
+}
+
+int
+main(void)
+{
+ u2_init();
+ spif_init();
+
+ set_default_mac_addr();
+ set_default_ip_addr();
+
+ putstr("\nN210 bootloader, UDP edition\n");
+ print_mac_addr(ethernet_mac_addr()); newline();
+ print_ip_addr(get_ip_addr()); newline();
+ printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM);
+ printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM);
+
+ do_the_bootload_thing();
+
+ //if we reach this point, the bootloader has fallen through, so we initalize the UDP handler for updating
+
+ //1) register the addresses into the network stack
+ //TODO: make this a fixed IP address, don't depend on EEPROM
+ register_addrs(ethernet_mac_addr(), get_ip_addr());
+ pkt_ctrl_program_inspector(get_ip_addr(), USRP2_UDP_DSP0_PORT);
+
+ //2) register callbacks for udp ports we service
+ init_udp_listeners();
+ register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet);
+
+ pkt_ctrl_set_routing_mode(PKT_CTRL_ROUTING_MODE_SLAVE);
+
+ //4) setup ethernet hardware to bring the link up
+ ethernet_register_link_changed_callback(link_changed_callback);
+ ethernet_init();
+
+ while(true){
+
+ size_t num_lines;
+ void *buff = pkt_ctrl_claim_incoming_buffer(&num_lines);
+ if (buff != NULL){
+ handle_inp_packet((uint32_t *)buff, num_lines);
+ pkt_ctrl_release_incoming_buffer();
+ }
+
+ pic_interrupt_handler();
+ }
+}