/* -*- 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; }