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