mirror of
https://github.com/greatscottgadgets/hackrf.git
synced 2026-03-21 22:57:35 +01:00
Support customization of FPGA image loading mechanism.
This commit is contained in:
@@ -44,6 +44,19 @@ struct fpga_driver_t {
|
||||
uint8_t regs_dirty;
|
||||
};
|
||||
|
||||
struct fpga_loader_t {
|
||||
/* Start address added as an offset to all read() calls. */
|
||||
uint32_t start_addr;
|
||||
/* Any one-off setup needed before calling read(). May be NULL. */
|
||||
void (*setup)(void);
|
||||
/* Read data from the specified address. */
|
||||
void (*read)(uint32_t addr, uint32_t len, uint8_t* const data);
|
||||
/* Buffer to use for compressed data (4096 bytes). */
|
||||
uint8_t* in_buffer;
|
||||
/* Buffer to use for decompressed data (4096 bytes). */
|
||||
uint8_t* out_buffer;
|
||||
};
|
||||
|
||||
/* Initialize the loaded bitstream's registers to their default values. */
|
||||
extern void fpga_init(fpga_driver_t* const drv);
|
||||
|
||||
@@ -75,7 +88,7 @@ void fpga_set_prbs_enable(fpga_driver_t* const drv, const bool enable);
|
||||
void fpga_set_tx_nco_enable(fpga_driver_t* const drv, const bool enable);
|
||||
void fpga_set_tx_nco_pstep(fpga_driver_t* const drv, const uint8_t phase_increment);
|
||||
|
||||
bool fpga_image_load(unsigned int index);
|
||||
bool fpga_image_load(struct fpga_loader_t* loader, unsigned int index);
|
||||
bool fpga_spi_selftest(void);
|
||||
bool fpga_sgpio_selftest(void);
|
||||
bool fpga_if_xcvr_selftest(void);
|
||||
|
||||
@@ -21,31 +21,28 @@
|
||||
|
||||
#include "hackrf_core.h"
|
||||
#include "lz4_blk.h"
|
||||
#include "lz4_buf.h"
|
||||
#include "selftest.h"
|
||||
|
||||
// FPGA bitstreams blob.
|
||||
extern uint32_t _binary_fpga_bin_start;
|
||||
extern uint32_t _binary_fpga_bin_end;
|
||||
extern uint32_t _binary_fpga_bin_size;
|
||||
#include "fpga.h"
|
||||
|
||||
struct fpga_image_read_ctx {
|
||||
struct fpga_loader_t* loader;
|
||||
uint32_t addr;
|
||||
size_t next_block_sz;
|
||||
uint8_t init_flag;
|
||||
};
|
||||
|
||||
static size_t fpga_image_read_block_cb(void* _ctx, uint8_t* out_buffer)
|
||||
static size_t fpga_image_read_block_cb(void* _ctx)
|
||||
{
|
||||
// Assume out_buffer is 4KB
|
||||
struct fpga_image_read_ctx* ctx = _ctx;
|
||||
struct fpga_loader_t* loader = ctx->loader;
|
||||
size_t block_sz = ctx->next_block_sz;
|
||||
|
||||
uint8_t block_sz_buf[2];
|
||||
|
||||
// first iteration: read first block size
|
||||
if (ctx->init_flag == 0) {
|
||||
w25q80bv_read(&spi_flash, ctx->addr, 2, block_sz_buf);
|
||||
loader->read(ctx->addr, 2, block_sz_buf);
|
||||
block_sz = block_sz_buf[0] | block_sz_buf[1] << 8;
|
||||
ctx->addr += 2;
|
||||
ctx->init_flag = 1;
|
||||
@@ -56,48 +53,42 @@ static size_t fpga_image_read_block_cb(void* _ctx, uint8_t* out_buffer)
|
||||
return 0;
|
||||
|
||||
// Read compressed block (and the next block size) from flash.
|
||||
w25q80bv_read(&spi_flash, ctx->addr, block_sz, lz4_in_buf);
|
||||
loader->read(ctx->addr, block_sz, loader->in_buffer);
|
||||
ctx->addr += block_sz;
|
||||
w25q80bv_read(&spi_flash, ctx->addr, 2, block_sz_buf);
|
||||
loader->read(ctx->addr, 2, block_sz_buf);
|
||||
ctx->next_block_sz = block_sz_buf[0] | block_sz_buf[1] << 8;
|
||||
ctx->addr += 2;
|
||||
|
||||
// Decompress block.
|
||||
return lz4_blk_decompress(lz4_in_buf, out_buffer, block_sz);
|
||||
return lz4_blk_decompress(loader->in_buffer, loader->out_buffer, block_sz);
|
||||
}
|
||||
|
||||
bool fpga_image_load(unsigned int index)
|
||||
bool fpga_image_load(struct fpga_loader_t* loader, unsigned int index)
|
||||
{
|
||||
#if defined(DFU_MODE) || defined(RAM_MODE)
|
||||
selftest.fpga_image_load = SKIPPED;
|
||||
selftest.report.pass = false;
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// TODO: do SPI setup and read number of bitstreams once!
|
||||
|
||||
// Prepare for SPI flash access.
|
||||
spi_bus_start(spi_flash.bus, &ssp_config_w25q80bv);
|
||||
w25q80bv_setup(&spi_flash);
|
||||
if (loader->setup != NULL)
|
||||
loader->setup();
|
||||
|
||||
// Read number of bitstreams from flash.
|
||||
// Check the bitstream exists, and extract its offset.
|
||||
uint32_t addr = (uint32_t) &_binary_fpga_bin_start;
|
||||
uint32_t addr = loader->start_addr;
|
||||
uint32_t num_bitstreams, bitstream_offset;
|
||||
w25q80bv_read(&spi_flash, addr, 4, (uint8_t*) &num_bitstreams);
|
||||
loader->read(addr, 4, (uint8_t*) &num_bitstreams);
|
||||
if (index >= num_bitstreams)
|
||||
return false;
|
||||
w25q80bv_read(&spi_flash, addr + 4 * (index + 1), 4, (uint8_t*) &bitstream_offset);
|
||||
loader->read(addr + 4 * (index + 1), 4, (uint8_t*) &bitstream_offset);
|
||||
|
||||
// A callback function is used by the FPGA programmer
|
||||
// to obtain consecutive gateware chunks.
|
||||
ice40_spi_target_init(&ice40);
|
||||
ssp1_set_mode_ice40();
|
||||
struct fpga_image_read_ctx fpga_image_ctx = {
|
||||
.addr = (uint32_t) &_binary_fpga_bin_start + bitstream_offset,
|
||||
.loader = loader,
|
||||
.addr = loader->start_addr + bitstream_offset,
|
||||
};
|
||||
const bool success = ice40_spi_syscfg_program(
|
||||
&ice40,
|
||||
loader->out_buffer,
|
||||
fpga_image_read_block_cb,
|
||||
&fpga_image_ctx);
|
||||
ssp1_set_mode_max283x();
|
||||
|
||||
@@ -82,7 +82,8 @@ static uint32_t spi_ssp1_transfer_word(const uint32_t data)
|
||||
|
||||
bool ice40_spi_syscfg_program(
|
||||
ice40_spi_driver_t* const drv,
|
||||
size_t (*read_block_cb)(void* ctx, uint8_t* buffer),
|
||||
uint8_t* buf,
|
||||
size_t (*read_block_cb)(void* ctx),
|
||||
void* read_ctx)
|
||||
{
|
||||
// Drive CRESET_B = 0, SPI_SS = 0, SPI_SCK = 1.
|
||||
@@ -107,11 +108,11 @@ bool ice40_spi_syscfg_program(
|
||||
// first, on falling edge of SPI_SCK.
|
||||
gpio_clear(drv->gpio_select);
|
||||
for (;;) {
|
||||
size_t read_sz = read_block_cb(read_ctx, lz4_out_buf);
|
||||
size_t read_sz = read_block_cb(read_ctx);
|
||||
if (read_sz == 0)
|
||||
break;
|
||||
for (size_t j = 0; j < read_sz; j++) {
|
||||
spi_ssp1_transfer_word(lz4_out_buf[j]);
|
||||
spi_ssp1_transfer_word(buf[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ uint8_t ice40_spi_read(ice40_spi_driver_t* const drv, uint8_t r);
|
||||
void ice40_spi_write(ice40_spi_driver_t* const drv, uint8_t r, uint16_t v);
|
||||
bool ice40_spi_syscfg_program(
|
||||
ice40_spi_driver_t* const drv,
|
||||
size_t (*read_block_cb)(void* ctx, uint8_t* buffer),
|
||||
uint8_t* buf,
|
||||
size_t (*read_block_cb)(void* ctx),
|
||||
void* read_ctx);
|
||||
|
||||
#endif // __ICE40_SPI_H
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#include "fpga.h"
|
||||
#include "selftest.h"
|
||||
#include "delay.h"
|
||||
#include "lz4_buf.h"
|
||||
|
||||
extern uint32_t __m0_start__;
|
||||
extern uint32_t __m0_end__;
|
||||
@@ -256,6 +257,29 @@ static void m0_rom_to_ram(void)
|
||||
memcpy(dest, (uint32_t*) (base + src), len);
|
||||
}
|
||||
|
||||
#if defined(PRALINE) && !(defined(DFU_MODE) || defined(RAM_MODE))
|
||||
extern uint32_t _binary_fpga_bin_start;
|
||||
|
||||
void fpga_loader_setup(void)
|
||||
{
|
||||
spi_bus_start(spi_flash.bus, &ssp_config_w25q80bv);
|
||||
w25q80bv_setup(&spi_flash);
|
||||
}
|
||||
|
||||
void fpga_loader_read(uint32_t addr, uint32_t size, uint8_t* buf)
|
||||
{
|
||||
w25q80bv_read(&spi_flash, addr, size, buf);
|
||||
}
|
||||
|
||||
struct fpga_loader_t fpga_loader = {
|
||||
.start_addr = (uint32_t) &_binary_fpga_bin_start,
|
||||
.setup = fpga_loader_setup,
|
||||
.read = fpga_loader_read,
|
||||
.in_buffer = lz4_in_buf,
|
||||
.out_buffer = lz4_out_buf,
|
||||
};
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Copy M0 image from ROM before SPIFI is disabled
|
||||
@@ -315,7 +339,12 @@ int main(void)
|
||||
halt_and_flash(6000000);
|
||||
}
|
||||
#else
|
||||
fpga_image_load(0);
|
||||
#if defined(DFU_MODE) || defined(RAM_MODE)
|
||||
selftest.fpga_image_load = SKIPPED;
|
||||
selftest.report.pass = false;
|
||||
#else
|
||||
fpga_image_load(&fpga_loader, 0);
|
||||
#endif
|
||||
delay_us_at_mhz(100, 204);
|
||||
fpga_spi_selftest();
|
||||
fpga_sgpio_selftest();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "usb_api_praline.h"
|
||||
#include "usb_queue.h"
|
||||
#include <hackrf_core.h>
|
||||
#include <fpga.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -71,17 +72,23 @@ usb_request_status_t usb_vendor_request_set_narrowband_filter(
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
bool fpga_image_load(unsigned int index);
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_fpga_bitstream(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage)
|
||||
{
|
||||
#if defined(DFU_MODE) || defined(RAM_MODE)
|
||||
(void) endpoint;
|
||||
(void) stage;
|
||||
return USB_REQUEST_STATUS_STALL;
|
||||
#else
|
||||
extern struct fpga_loader_t fpga_loader;
|
||||
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
if (!fpga_image_load(endpoint->setup.value)) {
|
||||
if (!fpga_image_load(&fpga_loader, endpoint->setup.value)) {
|
||||
return USB_REQUEST_STATUS_STALL;
|
||||
}
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user