From 649554f3fd07916d57f7705a998bb57fa41c18bc Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sat, 23 Oct 2021 08:44:23 +0200 Subject: [PATCH] efinix: add jtag support, introduce oe_pin in board configuration, add xyloni jtag interface --- src/board.hpp | 21 +++--- src/cable.hpp | 2 + src/efinix.cpp | 180 ++++++++++++++++++++++++++++++++++++++++--------- src/efinix.hpp | 13 +++- src/main.cpp | 6 +- src/part.hpp | 5 ++ 6 files changed, 183 insertions(+), 44 deletions(-) diff --git a/src/board.hpp b/src/board.hpp index 97942d6..eac7d6d 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -77,6 +77,7 @@ typedef struct { std::string fpga_part; /*! provide full fpga model name with package */ uint16_t reset_pin; /*! reset pin value */ uint16_t done_pin; /*! done pin value */ + uint16_t oe_pin; /*! output enable pin value */ uint16_t mode; /*! communication type (JTAG or SPI) */ jtag_pins_conf_t jtag_pins_config; /*! for bitbang, provide struct with pins value */ spi_pins_conf_t spi_pins_config; /*! for SPI, provide struct with pins value */ @@ -90,15 +91,15 @@ typedef struct { #define CABLE_MHZ(_m) ((_m) * 1000000) #define JTAG_BOARD(_name, _fpga_part, _cable, _rst, _done, _freq) \ - {_name, {"", _cable, _fpga_part, _rst, _done, COMM_JTAG, {}, {}, _freq, 0, 0, -1}} + {_name, {"", _cable, _fpga_part, _rst, _done, 0, COMM_JTAG, {}, {}, _freq, 0, 0, -1}} #define JTAG_BITBANG_BOARD(_name, _fpga_part, _cable, _rst, _done, _tms, _tck, _tdi, _tdo, _freq) \ - {_name, {"", _cable, _fpga_part, _rst, _done, COMM_JTAG, { _tms, _tck, _tdi, _tdo }, {}, \ + {_name, {"", _cable, _fpga_part, _rst, _done, 0, COMM_JTAG, { _tms, _tck, _tdi, _tdo }, {}, \ _freq, 0, 0, -1}} -#define SPI_BOARD(_name, _manufacturer, _cable, _rst, _done, _cs, _sck, _si, _so, _holdn, _wpn, _freq) \ - {_name, {_manufacturer, _cable, "", _rst, _done, COMM_SPI, {}, \ +#define SPI_BOARD(_name, _manufacturer, _cable, _rst, _done, _oe, _cs, _sck, _si, _so, _holdn, _wpn, _freq) \ + {_name, {_manufacturer, _cable, "", _rst, _done, _oe, COMM_SPI, {}, \ {_cs, _sck, _so, _si, _holdn, _wpn}, _freq, 0, 0, -1}} #define DFU_BOARD(_name, _fpga_part, _cable, _vid, _pid, _alt) \ - {_name, {"", _cable, _fpga_part, 0, 0, COMM_DFU, {}, {}, 0, _vid, _pid, _alt}} + {_name, {"", _cable, _fpga_part, 0, 0, 0, COMM_DFU, {}, {}, 0, _vid, _pid, _alt}} static std::map board_list = { JTAG_BOARD("acornCle215", "xc7a200tsbg484", "", 0, 0, CABLE_DEFAULT), @@ -117,11 +118,11 @@ static std::map board_list = { JTAG_BOARD("de10nano", "", "usb-blasterII",0, 0, CABLE_DEFAULT), JTAG_BOARD("ecp5_evn", "", "ft2232", 0, 0, CABLE_DEFAULT), SPI_BOARD("fireant", "efinix", "ft232", - DBUS4, DBUS5, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT), + DBUS4, DBUS5, 0, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT), DFU_BOARD("fomu", "", "dfu", 0x1209, 0x5bf0, 0), /* most ice40 boards uses the same pinout */ SPI_BOARD("ice40_generic", "lattice", "ft2232", - DBUS7, DBUS6, + DBUS7, DBUS6, 0, DBUS4, DBUS0, DBUS1, DBUS2, 0, 0, CABLE_DEFAULT), DFU_BOARD("icebreaker-bitsy", "", "dfu", 0x1d50, 0x6146, 0), @@ -146,10 +147,12 @@ static std::map board_list = { FT232RL_DCD, FT232RL_DSR, FT232RL_RI, FT232RL_CTS, CABLE_DEFAULT), JTAG_BOARD("ecpix5", "", "ecpix5-debug", 0, 0, CABLE_DEFAULT), JTAG_BOARD("xtrx", "xc7a50tcpg236", "" , 0, 0, CABLE_DEFAULT), + JTAG_BOARD("xyloni_jtag", "", "efinix_jtag_ft4232" , 0, 0, CABLE_DEFAULT), SPI_BOARD("xyloni_spi", "efinix", "efinix_spi_ft4232", - DBUS4 | DBUS7, DBUS5, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT), + DBUS4, DBUS5, DBUS7, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT), SPI_BOARD("trion_t120_bga576","efinix", "efinix_spi_ft2232", - DBUS4 | DBUS7, DBUS5, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT), + DBUS4, DBUS5, DBUS7, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT), + JTAG_BOARD("trion_t120_bga576_jtag", "", "ft2232_b", 0, 0, CABLE_DEFAULT), JTAG_BOARD("zedboard", "xc7z020-clg484", "digilent_hs2", 0, 0, CABLE_DEFAULT), }; diff --git a/src/cable.hpp b/src/cable.hpp index 0f20a4a..3d90c74 100644 --- a/src/cable.hpp +++ b/src/cable.hpp @@ -44,8 +44,10 @@ static std::map cable_list = { {"digilent_ad", {MODE_FTDI_SERIAL, {0x0403, 0x6014, INTERFACE_A, 0x08, 0x0B, 0x80, 0x80}}}, {"dirtyJtag", {MODE_DIRTYJTAG, {}}}, {"efinix_spi_ft4232", {MODE_FTDI_SERIAL, {0x0403, 0x6011, INTERFACE_A, 0x08, 0x8B, 0x00, 0x00}}}, + {"efinix_jtag_ft4232", {MODE_FTDI_SERIAL, {0x0403, 0x6011, INTERFACE_B, 0x08, 0x8B, 0x00, 0x00}}}, {"efinix_spi_ft2232", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_A, 0x08, 0x8B, 0x00, 0x00}}}, {"ft2232", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_A, 0x08, 0x0B, 0x08, 0x0B}}}, + {"ft2232_b", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_B, 0x08, 0x0B, 0x00, 0x00}}}, {"ft231X", {MODE_FTDI_BITBANG, {0x0403, 0x6015, INTERFACE_A, 0x00, 0x00, 0x00, 0x00}}}, {"ft232", {MODE_FTDI_SERIAL, {0x0403, 0x6014, INTERFACE_A, 0x08, 0x0B, 0x08, 0x0B}}}, {"ft232RL", {MODE_FTDI_BITBANG, {0x0403, 0x6001, INTERFACE_A, 0x08, 0x0B, 0x08, 0x0B}}}, diff --git a/src/efinix.cpp b/src/efinix.cpp index 0433f55..2d0daf5 100644 --- a/src/efinix.cpp +++ b/src/efinix.cpp @@ -15,6 +15,8 @@ #include "efinixHexParser.hpp" #include "ftdispi.hpp" #include "device.hpp" +#include "ftdiJtagMPSSE.hpp" +#include "jtag.hpp" #include "progressBar.hpp" #include "rawParser.hpp" #include "spiFlash.hpp" @@ -22,13 +24,57 @@ Efinix::Efinix(FtdiSpi* spi, const std::string &filename, const std::string &file_type, uint16_t rst_pin, uint16_t done_pin, + uint16_t oe_pin, bool verify, int8_t verbose): - Device(NULL, filename, file_type, verify, verbose), _rst_pin(rst_pin), - _done_pin(done_pin) + Device(NULL, filename, file_type, verify, verbose), _ftdi_jtag(NULL), + _rst_pin(rst_pin), _done_pin(done_pin), _cs_pin(0), _oe_pin(oe_pin) { _spi = spi; _spi->gpio_set_input(_done_pin); - _spi->gpio_set_output(_rst_pin); + _spi->gpio_set_output(_rst_pin | _oe_pin); +} + +Efinix::Efinix(Jtag* jtag, const std::string &filename, + const std::string &file_type, + const std::string &board_name, + bool verify, int8_t verbose): + Device(jtag, filename, file_type, verify, verbose), + _spi(NULL), _rst_pin(0), _done_pin(0), _cs_pin(0), + _oe_pin(0) +{ + /* WA: before using JTAG, device must restart with cs low + * but cs and rst for xyloni are connected to interfaceA (ie SPI) + * TODO: some boards have cs, reset and done in both interface + */ + + /* 1: need to find SPI board definition based on JTAG board def */ + std::string spi_board_name = ""; + if (board_name == "xyloni_jtag") { + spi_board_name = "xyloni_spi"; + } else if (board_name == "trion_t120_bga576_jtag") { + spi_board_name = "trion_t120_bga576"; + } else { + throw std::runtime_error("Error: unknown board name"); + } + + /* 2: retrieve spi board */ + target_board_t *spi_board = &(board_list[spi_board_name]); + + /* 3: SPI cable */ + cable_t *spi_cable = &(cable_list[spi_board->cable_name]); + + /* 4: get pinout (cs, oe, rst) */ + _cs_pin = spi_board->spi_pins_config.cs_pin; + _rst_pin = spi_board->reset_pin; + _oe_pin = spi_board->oe_pin; + + /* 5: open SPI interface */ + _spi = new FtdiSpi(spi_cable->config, spi_board->spi_pins_config, + jtag->getClkFreq(), verbose > 0); + _ftdi_jtag = reinterpret_cast(jtag); + + /* 6: configure pins direction and default state */ + _spi->gpio_set_output(_oe_pin | _rst_pin | _cs_pin); } Efinix::~Efinix() @@ -36,10 +82,12 @@ Efinix::~Efinix() void Efinix::reset() { + if (_ftdi_jtag) // not supported + return; uint32_t timeout = 1000; - _spi->gpio_clear(_rst_pin); + _spi->gpio_clear(_rst_pin | _oe_pin); usleep(1000); - _spi->gpio_set(_rst_pin); + _spi->gpio_set(_rst_pin | _oe_pin); printInfo("Reset ", false); do { timeout--; @@ -53,8 +101,6 @@ void Efinix::reset() void Efinix::program(unsigned int offset) { - uint32_t timeout = 1000; - if (_file_extension.empty()) return; @@ -89,32 +135,10 @@ void Efinix::program(unsigned int offset) if (_verbose) bit->displayHeader(); - _spi->gpio_clear(_rst_pin); - - SPIFlash flash(reinterpret_cast(_spi), _verbose); - flash.reset(); - flash.power_up(); - - printf("%02x\n", flash.read_status_reg()); - flash.read_id(); - flash.erase_and_prog(offset, data, length); - - /* verify write if required */ - if (_verify) - flash.verify(offset, data, length); - - _spi->gpio_set(_rst_pin); - usleep(12000); - - printInfo("Wait for CDONE ", false); - do { - timeout--; - usleep(12000); - } while (((_spi->gpio_get(true) & _done_pin) == 0) && timeout > 0); - if (timeout == 0) - printError("FAIL"); + if (_ftdi_jtag) + programJTAG(data, length); else - printSuccess("DONE"); + programSPI(offset, data, length); } bool Efinix::dumpFlash(const std::string &filename, @@ -137,7 +161,7 @@ bool Efinix::dumpFlash(const std::string &filename, } /* release SPI access */ - _spi->gpio_set(_rst_pin); + _spi->gpio_set(_rst_pin | _oe_pin); usleep(12000); printInfo("Wait for CDONE ", false); @@ -152,3 +176,93 @@ bool Efinix::dumpFlash(const std::string &filename, return false; } + +void Efinix::programSPI(unsigned int offset, uint8_t *data, int length) +{ + uint32_t timeout = 1000; + + _spi->gpio_clear(_rst_pin | _oe_pin); + + SPIFlash flash(reinterpret_cast(_spi), _verbose); + flash.reset(); + flash.power_up(); + + printf("%02x\n", flash.read_status_reg()); + flash.read_id(); + flash.erase_and_prog(offset, data, length); + + /* verify write if required */ + if (_verify) + flash.verify(offset, data, length); + + _spi->gpio_set(_rst_pin | _oe_pin); + usleep(12000); + + printInfo("Wait for CDONE ", false); + do { + timeout--; + usleep(12000); + } while (((_spi->gpio_get(true) & _done_pin) == 0) && timeout > 0); + if (timeout == 0) + printError("FAIL"); + else + printSuccess("DONE"); +} + +#define SAMPLE_PRELOAD 0x02 +#define EXTEST 0x00 +#define BYPASS 0x0f +#define IDCODE 0x03 +#define PROGRAM 0x04 +#define ENTERUSER 0x07 +#define IRLENGTH 4 + +void Efinix::programJTAG(uint8_t *data, int length) +{ + int xfer_len = 512, tx_end; + uint8_t tx[512]; + + /* trion has to be reseted with cs low */ + _spi->gpio_clear(_oe_pin | _cs_pin | _rst_pin); + usleep(30000); + _spi->gpio_set(_rst_pin); // assert RST + usleep(50000); + _spi->gpio_set(_oe_pin | _rst_pin); // release OE + usleep(50000); + + /* force run_test_idle state */ + _jtag->set_state(Jtag::RUN_TEST_IDLE); + usleep(100000); + + /* send PROGRAM state and stay in SHIFT_DR until + * full configuration data has been sent + */ + _jtag->shiftIR(PROGRAM, IRLENGTH, Jtag::EXIT1_IR); + _jtag->shiftIR(PROGRAM, IRLENGTH, Jtag::EXIT1_IR); // T20 fix + + ProgressBar progress("Load SRAM", length, 50, _quiet); + + for (int i = 0; i < length; i+=xfer_len) { + if (i + xfer_len > length) { // last packet + xfer_len = (length - i); + tx_end = Jtag::EXIT1_DR; + } else { + tx_end = Jtag::SHIFT_DR; + } + for (int pos = 0; pos < xfer_len; pos++) + tx[pos] = EfinixHexParser::reverseByte(data[i+pos]); + + _jtag->shiftDR(tx, NULL, xfer_len*8, tx_end); + progress.display(i); + } + + progress.done(); + + usleep(10000); + + _jtag->shiftIR(ENTERUSER, IRLENGTH, Jtag::EXIT1_IR); + + memset(tx, 0, 512); + _jtag->shiftDR(tx, NULL, 100); + _jtag->shiftIR(IDCODE, IRLENGTH); +} diff --git a/src/efinix.hpp b/src/efinix.hpp index 8f3f96f..8f5b848 100644 --- a/src/efinix.hpp +++ b/src/efinix.hpp @@ -9,13 +9,19 @@ #include #include "device.hpp" +#include "ftdiJtagMPSSE.hpp" #include "ftdispi.hpp" +#include "jtag.hpp" class Efinix: public Device { public: Efinix(FtdiSpi *spi, const std::string &filename, const std::string &file_type, - uint16_t rst_pin, uint16_t done_pin, + uint16_t rst_pin, uint16_t done_pin, uint16_t oe_pin, + bool verify, int8_t verbose); + Efinix(Jtag* jtag, const std::string &filename, + const std::string &file_type, + const std::string &board_name, bool verify, int8_t verbose); ~Efinix(); @@ -27,9 +33,14 @@ class Efinix: public Device { void reset() override; private: + void programSPI(unsigned int offset, uint8_t *data, int length); + void programJTAG(uint8_t *data, int length); FtdiSpi *_spi; + FtdiJtagMPSSE *_ftdi_jtag; uint16_t _rst_pin; uint16_t _done_pin; + uint16_t _cs_pin; + uint16_t _oe_pin; }; #endif // SRC_EFINIX_HPP_ diff --git a/src/main.cpp b/src/main.cpp index 1675710..5fb5ca0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -198,7 +198,8 @@ int main(int argc, char **argv) if (board->manufacturer == "efinix") { Efinix target(spi, args.bit_file, args.file_type, - board->reset_pin, board->done_pin, args.verify, args.verbose); + board->reset_pin, board->done_pin, board->oe_pin, + args.verify, args.verbose); if (args.prg_type == Device::RD_FLASH) { if (args.file_size == 0) { printError("Error: 0 size for dump"); @@ -427,6 +428,9 @@ int main(int argc, char **argv) } else if (fab == "anlogic") { fpga = new Anlogic(jtag, args.bit_file, args.file_type, args.prg_type, args.verify, args.verbose); + } else if (fab == "efinix") { + fpga = new Efinix(jtag, args.bit_file, args.file_type, + /*DBUS4 | DBUS7, DBUS5*/args.board, args.verify, args.verbose); } else if (fab == "Gowin") { fpga = new Gowin(jtag, args.bit_file, args.file_type, args.prg_type, args.external_flash, args.verify, args.verbose); diff --git a/src/part.hpp b/src/part.hpp index 1769421..5a905a5 100644 --- a/src/part.hpp +++ b/src/part.hpp @@ -60,6 +60,11 @@ static std::map fpga_list = { {0x02d020dd, {"altera", "cyclone V Soc", "5CSEBA6", 10}}, {0x02d010dd, {"altera", "cyclone V Soc", "5CSEMA4", 10}}, + {0x00000001, {"efinix", "Trion", "T4/T8", 4}}, + {0x00210a79, {"efinix", "Trion", "T8QFP144/T13/T20", 4}}, + {0x00220a79, {"efinix", "Trion", "T55/T85/T120", 4}}, + {0x00240a79, {"efinix", "Trion", "T20BGA324/T35", 4}}, + {0x010F0043, {"lattice", "CrosslinkNX", "LIFCL-17", 8}}, {0x010F1043, {"lattice", "CrosslinkNX", "LIFCL-40", 8}},