diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 6aa24d4..fec3fec 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -17,5 +17,6 @@ obj-y += altera.o obj-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o obj-$(CONFIG_FPGA_CYCLON2) += cyclon2.o obj-$(CONFIG_FPGA_STRATIX_II) += stratixII.o +obj-$(CONFIG_FPGA_STRATIX_V) += stratixv.o obj-$(CONFIG_FPGA_SOCFPGA) += socfpga.o endif diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c index a5bfe5d..135a357 100644 --- a/drivers/fpga/altera.c +++ b/drivers/fpga/altera.c @@ -37,6 +37,9 @@ static const struct altera_fpga { { Altera_StratixII, "StratixII", StratixII_load, StratixII_dump, StratixII_info }, #endif +#if defined(CONFIG_FPGA_STRATIX_V) + { Altera_StratixV, "StratixV", stratixv_load, NULL, NULL }, +#endif #if defined(CONFIG_FPGA_SOCFPGA) { Altera_SoCFPGA, "SoC FPGA", socfpga_load, NULL, NULL }, #endif diff --git a/drivers/fpga/stratixv.c b/drivers/fpga/stratixv.c new file mode 100644 index 0000000..cc035eb --- /dev/null +++ b/drivers/fpga/stratixv.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +/* Write the RBF data to FPGA via SPI */ +static int program_write(int spi_bus, int spi_dev, const void *rbf_data, + unsigned long rbf_size) +{ + struct spi_slave *slave; + int ret; + + debug("%s (%d): data=%p size=%ld\n", + __func__, __LINE__, rbf_data, rbf_size); + + /* FIXME: How to get the max. SPI clock and SPI mode? */ + slave = spi_setup_slave(spi_bus, spi_dev, 27777777, SPI_MODE_3); + if (!slave) + return -1; + + if (spi_claim_bus(slave)) + return -1; + + ret = spi_xfer(slave, rbf_size * 8, rbf_data, (void *)rbf_data, + SPI_XFER_BEGIN | SPI_XFER_END); + + spi_release_bus(slave); + + return ret; +} + +/* + * This is the interface used by FPGA driver. + * Return 0 for sucess, non-zero for error. + */ +int stratixv_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) +{ + altera_board_specific_func *pfns = desc->iface_fns; + int cookie = desc->cookie; + int spi_bus; + int spi_dev; + int ret = 0; + + if ((u32)rbf_data & 0x3) { + puts("FPGA: Unaligned data, realign to 32bit boundary.\n"); + return -EINVAL; + } + + /* Run the pre configuration function if there is one */ + if (pfns->pre) + (pfns->pre)(cookie); + + /* Establish the initial state */ + if (pfns->config) { + /* De-assert nCONFIG */ + (pfns->config)(false, true, cookie); + + /* nConfig minimum low pulse width is 2us */ + udelay(200); + + /* Assert nCONFIG */ + (pfns->config)(true, true, cookie); + + /* nCONFIG high to first rising clock on DCLK min 1506 us */ + udelay(1600); + } + + /* Write the RBF data to FPGA */ + if (pfns->write) { + /* + * Use board specific data function to write bitstream + * into the FPGA + */ + ret = (pfns->write)(rbf_data, rbf_size, true, cookie); + } else { + /* + * Use common SPI functions to write bitstream into the + * FPGA + */ + spi_bus = COOKIE2SPI_BUS(cookie); + spi_dev = COOKIE2SPI_DEV(cookie); + ret = program_write(spi_bus, spi_dev, rbf_data, rbf_size); + } + if (ret) + return ret; + + /* Check done pin */ + if (pfns->done) { + ret = (pfns->done)(cookie); + + if (ret) + printf("Error: DONE not set (ret=%d)!\n", ret); + } + + return ret; +} diff --git a/include/altera.h b/include/altera.h index c2991ad..48d3eb7 100644 --- a/include/altera.h +++ b/include/altera.h @@ -10,6 +10,19 @@ #ifndef _ALTERA_H_ #define _ALTERA_H_ +/* + * For the StratixV FPGA programming via SPI, the following + * information is coded in the 32bit cookie: + * Bit 31 ... Bit 0 + * SPI-Bus | SPI-Dev | Config-Pin | Done-Pin + */ +#define FPGA_COOKIE(bus, dev, config, done) \ + (((bus) << 24) | ((dev) << 16) | ((config) << 8) | (done)) +#define COOKIE2SPI_BUS(c) (((c) >> 24) & 0xff) +#define COOKIE2SPI_DEV(c) (((c) >> 16) & 0xff) +#define COOKIE2CONFIG(c) (((c) >> 8) & 0xff) +#define COOKIE2DONE(c) ((c) & 0xff) + enum altera_iface { /* insert all new types after this */ min_altera_iface_type, @@ -40,6 +53,8 @@ enum altera_family { Altera_CYC2, /* StratixII Family */ Altera_StratixII, + /* StratixV Family */ + Altera_StratixV, /* SoCFPGA Family */ Altera_SoCFPGA, @@ -89,6 +104,7 @@ typedef struct { Altera_done_fn done; Altera_clk_fn clk; Altera_data_fn data; + Altera_write_fn write; Altera_abort_fn abort; Altera_post_fn post; } altera_board_specific_func; @@ -97,4 +113,8 @@ typedef struct { int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size); #endif +#ifdef CONFIG_FPGA_STRATIX_V +int stratixv_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size); +#endif + #endif /* _ALTERA_H_ */