From 45f7f72030f87023ab4e8231707ed18e1350afe7 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 22 Dec 2021 19:11:35 +0100 Subject: [PATCH] all devices: add support to (un)protect flash, implement pre/post flash access. Use new spiInterface methods --- src/altera.cpp | 61 ++--------- src/altera.hpp | 30 +++++- src/anlogic.cpp | 89 +++++++--------- src/anlogic.hpp | 37 ++++++- src/colognechip.cpp | 22 ++-- src/colognechip.hpp | 13 ++- src/efinix.cpp | 12 ++- src/efinix.hpp | 10 +- src/epcq.cpp | 11 +- src/epcq.hpp | 4 +- src/gowin.cpp | 5 +- src/gowin.hpp | 7 +- src/ice40.cpp | 69 +++++++++++-- src/ice40.hpp | 35 ++++++- src/lattice.cpp | 246 ++++++++++++++++++-------------------------- src/lattice.hpp | 37 ++++++- src/xilinx.cpp | 58 +++-------- src/xilinx.hpp | 32 +++++- 18 files changed, 431 insertions(+), 347 deletions(-) diff --git a/src/altera.cpp b/src/altera.cpp index 0da83ce..bd7e762 100644 --- a/src/altera.cpp +++ b/src/altera.cpp @@ -26,8 +26,9 @@ Altera::Altera(Jtag *jtag, const std::string &filename, const std::string &file_type, Device::prog_type_t prg_type, const std::string &device_package, bool verify, int8_t verbose): - Device(jtag, filename, file_type, verify, verbose), _svf(_jtag, _verbose), - _device_package(device_package), + Device(jtag, filename, file_type, verify, verbose), + SPIInterface(filename, verbose, 256, verify), + _svf(_jtag, _verbose), _device_package(device_package), _vir_addr(0x1000), _vir_length(14) { if (prg_type == Device::RD_FLASH) { @@ -177,7 +178,7 @@ bool Altera::load_bridge() return true; } -void Altera::program(unsigned int offset) +void Altera::program(unsigned int offset, bool unprotect_flash) { if (_mode == Device::NONE_MODE) return; @@ -197,14 +198,6 @@ void Altera::program(unsigned int offset) programMem(_bit); } } else if (_mode == Device::SPI_MODE) { - /* try to load spiOverJtag bridge - * to have an access to SPI flash - */ - if (!load_bridge()) { - printError("Fail to load bridge"); - return; - } - // reverse only bitstream raw binaries data no bool reverseOrder = false; if (_file_extension == "rbf" || _file_extension == "rpd") @@ -224,51 +217,11 @@ void Altera::program(unsigned int offset) throw std::runtime_error(e.what()); } - /* GGM: TODO: fix this issue */ - EPCQ epcq(this, 0); - - try { - epcq.reset(); - epcq.read_id(); - epcq.display_status_reg(epcq.read_status_reg()); - epcq.erase_and_prog(offset, data, length); - } catch (std::exception &e) { - printError(e.what()); - throw std::runtime_error(e.what()); - } - - if (_verify) - epcq.verify(offset, data, length, 256); - reset(); + if (!SPIInterface::write(offset, data, length, unprotect_flash)) + throw std::runtime_error("Fail to write data"); } } -bool Altera::dumpFlash(const std::string filename, uint32_t base_addr, - uint32_t len) -{ - int ret = true; - /* try to load spiOverJtag bridge - * to have an access to SPI flash - */ - if (!load_bridge()) { - printError("Fail to load bridge"); - return false; - } - - EPCQ epcq(this, 0); - - try { - epcq.reset(); - ret = epcq.dump(filename, base_addr, len, 256); - } catch (std::exception &e) { - printError(e.what()); - ret = false; - } - - reset(); - return ret; -} - int Altera::idCode() { unsigned char tx_data[4] = {IDCODE}; @@ -308,7 +261,7 @@ int Altera::spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint32_t len) } } - return len; + return 0; } int Altera::spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) { diff --git a/src/altera.hpp b/src/altera.hpp index 54eb027..4c527a6 100644 --- a/src/altera.hpp +++ b/src/altera.hpp @@ -24,7 +24,7 @@ class Altera: public Device, SPIInterface { ~Altera(); void programMem(RawParser &_bit); - void program(unsigned int offset = 0) override; + void program(unsigned int offset, bool unprotect_flash) override; /*! * \brief read len Byte starting at base_addr and store * into filename @@ -33,18 +33,40 @@ class Altera: public Device, SPIInterface { * \param[in] len: length (in Byte) * \return false if read fails or filename can't be open, true otherwise */ - bool dumpFlash(const std::string filename, uint32_t base_addr, - uint32_t len); + bool dumpFlash(uint32_t base_addr, uint32_t len) override { + return SPIInterface::dump(base_addr, len); + } + int idCode() override; void reset() override; - /* spi interface */ + /*************************/ + /* spi interface */ + /*************************/ + + /*! + * \brief protect SPI flash blocks + */ + bool protect_flash(uint32_t len) override { + return SPIInterface::protect_flash(len); + } + /*! + * \brief unprotect SPI flash blocks + */ + bool unprotect_flash() override { + return SPIInterface::unprotect_flash(); + } + int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint32_t len) override; int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override; int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, uint32_t timeout, bool verbose = false) override; + protected: + bool prepare_flash_access() override {return load_bridge();} + bool post_flash_access() override {reset(); return true;} + private: /*! * \brief with intel devices SPI flash direct access is not possible diff --git a/src/anlogic.cpp b/src/anlogic.cpp index 41349e7..d42d050 100644 --- a/src/anlogic.cpp +++ b/src/anlogic.cpp @@ -28,18 +28,23 @@ Anlogic::Anlogic(Jtag *jtag, const std::string &filename, const std::string &file_type, Device::prog_type_t prg_type, bool verify, int8_t verbose): - Device(jtag, filename, file_type, verify, verbose), _svf(_jtag, _verbose) + Device(jtag, filename, file_type, verify, verbose), + SPIInterface(filename, verbose, 0, verify), _svf(_jtag, _verbose) { - if (!_file_extension.empty()) { - if (_file_extension == "svf") + if (prg_type == Device::RD_FLASH) { + _mode = Device::READ_MODE; + } else if (!_file_extension.empty()) { + if (_file_extension == "svf") { _mode = Device::MEM_MODE; - else if (_file_extension == "bit") { - if (prg_type == Device::WR_SRAM) - _mode = Device::MEM_MODE; - else + } else if (_file_extension == "bit") { + _mode = (prg_type == Device::WR_SRAM)? Device::MEM_MODE: + Device::SPI_MODE; + } else { + if (prg_type == Device::WR_FLASH) _mode = Device::SPI_MODE; - } else - throw std::runtime_error("incompatible file format"); + else + throw std::runtime_error("incompatible file format"); + } } } Anlogic::~Anlogic() @@ -54,7 +59,7 @@ void Anlogic::reset() _jtag->toggleClk(200000); } -void Anlogic::program(unsigned int offset) +void Anlogic::program(unsigned int offset, bool unprotect_flash) { if (_mode == Device::NONE_MODE) return; @@ -70,10 +75,10 @@ void Anlogic::program(unsigned int offset) if (bit.parse() == EXIT_FAILURE) { printError("FAIL"); return; - } else { - printSuccess("DONE"); } + printSuccess("DONE"); + if (_verbose) bit.displayHeader(); @@ -81,47 +86,10 @@ void Anlogic::program(unsigned int offset) int len = bit.getLength() / 8; if (_mode == Device::SPI_MODE) { - SPIFlash flash(this, _verbose); - - for (int i = 0; i < 5; i++) - _jtag->shiftIR(BYPASS, IRLENGTH); - //Verify Device id. - //SIR 8 TDI (06) ; - //SDR 32 TDI (00000000) TDO (0a014c35) MASK (ffffffff) ; - //Boundary Scan Chain Contents - //Position 1: BG256 - //Loading device with 'refresh' instruction. - _jtag->shiftIR(REFRESH, IRLENGTH); - //Loading device with 'bypass' & 'spi_program' instruction. - _jtag->shiftIR(BYPASS, IRLENGTH); - _jtag->shiftIR(SPI_PROGRAM, IRLENGTH); - for (int i = 0; i < 4; i++) - _jtag->toggleClk(50000); - - flash.reset(); - flash.read_id(); - flash.display_status_reg(flash.read_status_reg()); - - flash.erase_and_prog(offset, data, len); - - if (_verify) - printWarn("writing verification not supported"); - - //Loading device with 'bypass' instruction. - _jtag->shiftIR(BYPASS, IRLENGTH); - ////Loading device with 'refresh' instruction. - _jtag->shiftIR(REFRESH, IRLENGTH); - _jtag->toggleClk(20); - ////Loading device with 'bypass' instruction. - for (int i = 0; i < 4; i++) { - _jtag->shiftIR(BYPASS, IRLENGTH); - _jtag->toggleClk(20); - } - _jtag->shiftIR(BYPASS, IRLENGTH); - _jtag->toggleClk(10000); - + SPIInterface::write(offset, data, len, unprotect_flash); return; } + if (_mode == Device::MEM_MODE) { // Loading device with 'bypass' instruction. @@ -196,6 +164,25 @@ int Anlogic::idCode() ((rx_data[3] << 24) & 0xff000000)); } +bool Anlogic::prepare_flash_access() +{ + for (int i = 0; i < 5; i++) + _jtag->shiftIR(BYPASS, IRLENGTH); + //Verify Device id. + //SIR 8 TDI (06) ; + //SDR 32 TDI (00000000) TDO (0a014c35) MASK (ffffffff) ; + //Boundary Scan Chain Contents + //Position 1: BG256 + //Loading device with 'refresh' instruction. + _jtag->shiftIR(REFRESH, IRLENGTH); + //Loading device with 'bypass' & 'spi_program' instruction. + _jtag->shiftIR(BYPASS, IRLENGTH); + _jtag->shiftIR(SPI_PROGRAM, IRLENGTH); + for (int i = 0; i < 4; i++) + _jtag->toggleClk(50000); + return true; +} + /* SPI wrapper * For read operation a delay of one bit is added * So add one bit more and move everything by one diff --git a/src/anlogic.hpp b/src/anlogic.hpp index fd7a9c0..3843ed0 100644 --- a/src/anlogic.hpp +++ b/src/anlogic.hpp @@ -21,16 +21,51 @@ class Anlogic: public Device, SPIInterface { Device::prog_type_t prg_type, bool verify, int8_t verbose); ~Anlogic(); - void program(unsigned int offset = 0) override; + void program(unsigned int offset, bool unprotect_flash) override; int idCode() override; void reset() override; /* spi interface */ + /*! + * \brief protect SPI flash blocks + */ + bool protect_flash(uint32_t len) override { + return SPIInterface::protect_flash(len); + } + + /*! + * \brief protect SPI flash blocks + */ + bool unprotect_flash() override { + return SPIInterface::unprotect_flash(); + } + + /*! + * \brief dump len byte from base_addr from SPI flash + * \param[in] base_addr: start offset + * \param[in] len: dump len + * \return false if something wrong + */ + virtual bool dumpFlash(uint32_t base_addr, uint32_t len) override { + return SPIInterface::dump(base_addr, len); + } + int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint32_t len) override; int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override; int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, uint32_t timeout, bool verbose=false) override; + + protected: + /*! + * \brief move device to SPI access + */ + virtual bool prepare_flash_access() override; + /*! + * \brief end of device to SPI access + */ + virtual bool post_flash_access() override {reset(); return true;} + private: SVF_jtag _svf; }; diff --git a/src/colognechip.cpp b/src/colognechip.cpp index 3d2ca88..f828993 100644 --- a/src/colognechip.cpp +++ b/src/colognechip.cpp @@ -136,9 +136,10 @@ bool CologneChip::dumpFlash(const std::string &filename, uint32_t base_addr, try { SPIFlash *flash; if (_spi) { - flash = new SPIFlash(reinterpret_cast(_spi), _verbose); + flash = new SPIFlash(reinterpret_cast(_spi), false, + _verbose); } else if (_ftdi_jtag) { - flash = new SPIFlash(this, _verbose); + flash = new SPIFlash(this, false, _verbose); } flash->reset(); flash->power_up(); @@ -165,7 +166,7 @@ bool CologneChip::dumpFlash(const std::string &filename, uint32_t base_addr, * Parse bitstream from *.bit or *.cfg and program FPGA in SPI or JTAG mode * or write configuration to external flash via SPI or JTAG-SPI-bypass. */ -void CologneChip::program(unsigned int offset) +void CologneChip::program(unsigned int offset, bool unprotect_flash) { ConfigBitstreamParser *cfg; if (_file_extension == "cfg") { @@ -188,9 +189,9 @@ void CologneChip::program(unsigned int offset) switch (_mode) { case Device::FLASH_MODE: if (_jtag != NULL) { - programJTAG_flash(offset, data, length); + programJTAG_flash(offset, data, length, unprotect_flash); } else if (_jtag == NULL) { - programSPI_flash(offset, data, length); + programSPI_flash(offset, data, length, unprotect_flash); } break; case Device::MEM_MODE: @@ -227,13 +228,15 @@ void CologneChip::programSPI_sram(uint8_t *data, int length) * done, release reset to start FPGA in active SPI mode (load from flash). * CFG_MD[3:0] must be set to 0x00 (SPI active). */ -void CologneChip::programSPI_flash(unsigned int offset, uint8_t *data, int length) +void CologneChip::programSPI_flash(unsigned int offset, uint8_t *data, + int length, bool unprotect_flash) { /* hold device in reset during flash write access */ _spi->gpio_clear(_rstn_pin | _oen_pin); usleep(SLEEP_US); - SPIFlash flash(reinterpret_cast(_spi), _verbose); + SPIFlash flash(reinterpret_cast(_spi), unprotect_flash, + _verbose); flash.reset(); flash.power_up(); @@ -294,12 +297,13 @@ void CologneChip::programJTAG_sram(uint8_t *data, int length) * Write configuration to flash via JTAG-SPI-bypass. The FPGA will not start * as it is in JTAG mode with CFG_MD[3:0] set to 0xF0 (JTAG). */ -void CologneChip::programJTAG_flash(unsigned int offset, uint8_t *data, int length) +void CologneChip::programJTAG_flash(unsigned int offset, uint8_t *data, + int length, bool unprotect_flash) { /* hold device in reset for a moment */ reset(); - SPIFlash flash(this, _verbose); + SPIFlash flash(this, unprotect_flash, _verbose); flash.reset(); flash.power_up(); diff --git a/src/colognechip.hpp b/src/colognechip.hpp index a5f860e..cb8ee7e 100644 --- a/src/colognechip.hpp +++ b/src/colognechip.hpp @@ -35,16 +35,23 @@ class CologneChip: public Device, SPIInterface { bool cfgDone(); void waitCfgDone(); bool dumpFlash(const std::string &filename, uint32_t base_addr, uint32_t len); - void program(unsigned int offset = 0) override; + virtual bool protect_flash(uint32_t len) override { + (void) len; + printError("protect flash not supported"); return false;} + virtual bool unprotect_flash() override { + printError("unprotect flash not supported"); return false;} + void program(unsigned int offset, bool unprotect_flash) override; int idCode() override {return 0;} void reset() override; private: void programSPI_sram(uint8_t *data, int length); - void programSPI_flash(unsigned int offset, uint8_t *data, int length); + void programSPI_flash(unsigned int offset, uint8_t *data, int length, + bool unprotect_flash); void programJTAG_sram(uint8_t *data, int length); - void programJTAG_flash(unsigned int offset, uint8_t *data, int length); + void programJTAG_flash(unsigned int offset, uint8_t *data, int length, + bool unprotect_flash); /* spi interface via jtag */ int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, diff --git a/src/efinix.cpp b/src/efinix.cpp index fbf4bce..c096e3b 100644 --- a/src/efinix.cpp +++ b/src/efinix.cpp @@ -101,7 +101,7 @@ void Efinix::reset() printSuccess("DONE"); } -void Efinix::program(unsigned int offset) +void Efinix::program(unsigned int offset, bool unprotect_flash) { if (_file_extension.empty()) return; @@ -140,7 +140,7 @@ void Efinix::program(unsigned int offset) if (_ftdi_jtag) programJTAG(data, length); else - programSPI(offset, data, length); + programSPI(offset, data, length, unprotect_flash); } bool Efinix::dumpFlash(const std::string &filename, @@ -152,7 +152,7 @@ bool Efinix::dumpFlash(const std::string &filename, /* prepare SPI access */ printInfo("Read Flash ", false); try { - SPIFlash flash(reinterpret_cast(_spi), _verbose); + SPIFlash flash(reinterpret_cast(_spi), false, _verbose); flash.reset(); flash.power_up(); flash.dump(filename, base_addr, len); @@ -179,13 +179,15 @@ bool Efinix::dumpFlash(const std::string &filename, return false; } -void Efinix::programSPI(unsigned int offset, uint8_t *data, int length) +void Efinix::programSPI(unsigned int offset, uint8_t *data, int length, + bool unprotect_flash) { uint32_t timeout = 1000; _spi->gpio_clear(_rst_pin | _oe_pin); - SPIFlash flash(reinterpret_cast(_spi), _verbose); + SPIFlash flash(reinterpret_cast(_spi), unprotect_flash, + _verbose); flash.reset(); flash.power_up(); diff --git a/src/efinix.hpp b/src/efinix.hpp index 8f5b848..7948735 100644 --- a/src/efinix.hpp +++ b/src/efinix.hpp @@ -25,15 +25,21 @@ class Efinix: public Device { bool verify, int8_t verbose); ~Efinix(); - void program(unsigned int offset = 0) override; + void program(unsigned int offset, bool unprotect_flash) override; bool dumpFlash(const std::string &filename, uint32_t base_addr, uint32_t len); + virtual bool protect_flash(uint32_t len) override { + (void) len; + printError("protect flash not supported"); return false;} + virtual bool unprotect_flash() override { + printError("unprotect flash not supported"); return false;} /* not supported in SPI Active mode */ int idCode() override {return 0;} void reset() override; private: - void programSPI(unsigned int offset, uint8_t *data, int length); + void programSPI(unsigned int offset, uint8_t *data, int length, + bool unprotect_flash); void programJTAG(uint8_t *data, int length); FtdiSpi *_spi; FtdiJtagMPSSE *_ftdi_jtag; diff --git a/src/epcq.cpp b/src/epcq.cpp index 7c2c004..1c7279a 100644 --- a/src/epcq.cpp +++ b/src/epcq.cpp @@ -62,8 +62,15 @@ void EPCQ::read_id() printf("silicon id 0x%x attendu 0x14\n", _silicon_id); } -EPCQ::EPCQ(SPIInterface *spi, int8_t verbose):SPIFlash(spi, verbose), - _device_id(0), _silicon_id(0) +void EPCQ::reset() +{ + printf("reset\n"); + _spi->spi_put(0x66, NULL, NULL, 0); + _spi->spi_put(0x99, NULL, NULL, 0); +} + +EPCQ::EPCQ(SPIInterface *spi, bool unprotect_flash, int8_t verbose): + SPIFlash(spi, unprotect_flash, verbose), _device_id(0), _silicon_id(0) {} EPCQ::~EPCQ() diff --git a/src/epcq.hpp b/src/epcq.hpp index fa749ec..652be5d 100644 --- a/src/epcq.hpp +++ b/src/epcq.hpp @@ -15,11 +15,13 @@ using namespace std; class EPCQ: public SPIFlash { public: - EPCQ(SPIInterface *spi, int8_t verbose); + EPCQ(SPIInterface *spi, bool unprotect_flash, int8_t verbose); ~EPCQ(); void read_id() override; + void reset() override; + /* not supported */ void power_up() override {} void power_down() override {} diff --git a/src/gowin.cpp b/src/gowin.cpp index de87a53..a4a5413 100644 --- a/src/gowin.cpp +++ b/src/gowin.cpp @@ -206,7 +206,7 @@ void Gowin::programFlash() displayReadReg(readStatusReg()); } -void Gowin::program(unsigned int offset) +void Gowin::program(unsigned int offset, bool unprotect_flash) { (void) offset; @@ -235,7 +235,8 @@ void Gowin::program(unsigned int offset) wr_rd(0x3D, NULL, 0, NULL, 0); - SPIFlash spiFlash(this, (_verbose ? 1 : (_quiet ? -1 : 0))); + SPIFlash spiFlash(this, unprotect_flash, + (_verbose ? 1 : (_quiet ? -1 : 0))); spiFlash.reset(); spiFlash.read_id(); spiFlash.display_status_reg(spiFlash.read_status_reg()); diff --git a/src/gowin.hpp b/src/gowin.hpp index 492d95b..8523ca0 100644 --- a/src/gowin.hpp +++ b/src/gowin.hpp @@ -24,10 +24,15 @@ class Gowin: public Device, SPIInterface { ~Gowin(); int idCode() override; void reset() override; - void program(unsigned int offset) override; + void program(unsigned int offset, bool unprotect_flash) override; void programFlash(); /* spi interface */ + virtual bool protect_flash(uint32_t len) override { + (void) len; + printError("protect flash not supported"); return false;} + virtual bool unprotect_flash() override { + printError("unprotect flash not supported"); return false;} int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint32_t len) override; int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override; diff --git a/src/ice40.cpp b/src/ice40.cpp index f797cc9..7076805 100644 --- a/src/ice40.cpp +++ b/src/ice40.cpp @@ -40,17 +40,18 @@ void Ice40::reset() usleep(1000); _spi->gpio_set(_rst_pin); printInfo("Reset ", false); + usleep(12000); do { timeout--; usleep(12000); - } while (((_spi->gpio_get(true) & _done_pin) == 0) || timeout > 0); + } while (((_spi->gpio_get(true) & _done_pin) == 0) && timeout > 0); if (timeout == 0) printError("FAIL"); else printSuccess("DONE"); } -void Ice40::program(unsigned int offset) +void Ice40::program(unsigned int offset, bool unprotect_flash) { uint32_t timeout = 1000; @@ -72,7 +73,8 @@ void Ice40::program(unsigned int offset) _spi->gpio_clear(_rst_pin); - SPIFlash flash(reinterpret_cast(_spi), _quiet); + SPIFlash flash(reinterpret_cast(_spi), unprotect_flash, + _quiet); flash.reset(); flash.power_up(); @@ -97,8 +99,7 @@ void Ice40::program(unsigned int offset) printSuccess("DONE"); } -bool Ice40::dumpFlash(const std::string &filename, - uint32_t base_addr, uint32_t len) +bool Ice40::dumpFlash(uint32_t base_addr, uint32_t len) { uint32_t timeout = 1000; _spi->gpio_clear(_rst_pin); @@ -106,10 +107,10 @@ bool Ice40::dumpFlash(const std::string &filename, /* prepare SPI access */ printInfo("Read Flash ", false); try { - SPIFlash flash(reinterpret_cast(_spi), _verbose); + SPIFlash flash(reinterpret_cast(_spi), false, _verbose); flash.reset(); flash.power_up(); - flash.dump(filename, base_addr, len); + flash.dump(_filename, base_addr, len); } catch (std::exception &e) { printError("Fail"); printError(std::string(e.what())); @@ -133,3 +134,57 @@ bool Ice40::dumpFlash(const std::string &filename, return false; } + +bool Ice40::protect_flash(uint32_t len) +{ + /* SPI access */ + prepare_flash_access(); + /* acess */ + try { + SPIFlash flash(reinterpret_cast(_spi), false, _verbose); + /* configure flash protection */ + if (flash.enable_protection(len) == -1) + return false; + } catch (std::exception &e) { + printError("Fail"); + printError(std::string(e.what())); + return false; + } + + /* reload */ + return post_flash_access(); +} + +bool Ice40::unprotect_flash() +{ + /* SPI access */ + prepare_flash_access(); + /* acess */ + try { + SPIFlash flash(reinterpret_cast(_spi), false, _verbose); + /* configure flash protection */ + if (flash.disable_protection() == -1) + return false; + } catch (std::exception &e) { + printError("Fail"); + printError(std::string(e.what())); + return false; + } + + /* reload */ + return post_flash_access(); +} + +bool Ice40::prepare_flash_access() +{ + /* SPI access: shutdown ICE40 */ + _spi->gpio_clear(_rst_pin); + usleep(1000); + return true; +} + +bool Ice40::post_flash_access() +{ + reset(); + return ((_spi->gpio_get(true) & _done_pin) == 0) ? false : true; +} diff --git a/src/ice40.hpp b/src/ice40.hpp index 11a5df8..93ac2d2 100644 --- a/src/ice40.hpp +++ b/src/ice40.hpp @@ -10,8 +10,9 @@ #include "device.hpp" #include "ftdispi.hpp" +#include "spiInterface.hpp" -class Ice40: public Device { +class Ice40: public Device, SPIInterface { public: Ice40(FtdiSpi *spi, const std::string &filename, const std::string &file_type, @@ -19,13 +20,39 @@ class Ice40: public Device { bool verify, int8_t verbose); ~Ice40(); - void program(unsigned int offset = 0) override; - bool dumpFlash(const std::string &filename, - uint32_t base_addr, uint32_t len); + void program(unsigned int offset, bool unprotect_flash) override; + bool dumpFlash(uint32_t base_addr, uint32_t len); + bool protect_flash(uint32_t len) override; + bool unprotect_flash() override; /* not supported in SPI Active mode */ int idCode() override {return 0;} void reset() override; + int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, + uint32_t len) { + (void)cmd; (void)tx; (void)rx; (void)len; + return 0; + } + int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) { + (void)tx; (void)rx; (void)len; + return 0; + } + int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, + uint32_t timeout, bool verbose = false) { + (void)cmd; (void)mask; (void)cond; (void)timeout; (void) verbose; + return 0; + } + + protected: + /*! + * \brief prepare SPI flash access + */ + bool prepare_flash_access() override; + /*! + * \brief end of SPI flash access + */ + bool post_flash_access() override; + private: FtdiSpi *_spi; uint16_t _rst_pin; diff --git a/src/lattice.cpp b/src/lattice.cpp index 8b165d6..e534480 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -139,6 +139,7 @@ using namespace std; Lattice::Lattice(Jtag *jtag, const string filename, const string &file_type, Device::prog_type_t prg_type, std::string flash_sector, bool verify, int8_t verbose): Device(jtag, filename, file_type, verify, verbose), + SPIInterface(filename, verbose, 0, verify), _fpga_family(UNKNOWN_FAMILY), _flash_sector(LATTICE_FLASH_UNDEFINED) { if (prg_type == Device::RD_FLASH) { @@ -512,46 +513,11 @@ bool Lattice::program_intFlash(JedParser& _jed) return true; } -bool Lattice::program_extFlash(unsigned int offset) +bool Lattice::prepare_flash_access() { - ConfigBitstreamParser *_bit; - if (_file_extension == "mcs") - _bit = new McsParser(_filename, true, _verbose); - else if (_file_extension == "bit") - _bit = new LatticeBitParser(_filename, _verbose); - else - _bit = new RawParser(_filename, false); - - printInfo("Open file ", false); - printSuccess("DONE"); - - int err = _bit->parse(); - - printInfo("Parse file ", false); - if (err == EXIT_FAILURE) { - printError("FAIL"); - delete _bit; + /* clear SRAM before SPI access */ + if (!clearSRAM()) return false; - } else { - printSuccess("DONE"); - } - - if (_verbose) - _bit->displayHeader(); - - if (_file_extension == "bit") { - uint32_t bit_idcode = std::stoul(_bit->getHeaderVal("idcode").c_str(), NULL, 16); - uint32_t idcode = idCode(); - if (idcode != bit_idcode) { - char mess[256]; - sprintf(mess, "mismatch between target's idcode and bitstream idcode\n" - "\tbitstream has 0x%08X hardware requires 0x%08x", bit_idcode, idcode); - printError(mess); - delete _bit; - return false; - } - } - /*IR = 0h3A, DR=0hFE,0h68. Enter RUNTESTIDLE. * thank @GregDavill * https://twitter.com/GregDavill/status/1251786406441086977 @@ -559,35 +525,31 @@ bool Lattice::program_extFlash(unsigned int offset) _jtag->shiftIR(0x3A, 8, Jtag::EXIT1_IR); uint8_t tmp[2] = {0xFE, 0x68}; _jtag->shiftDR(tmp, NULL, 16); - - uint8_t *data = _bit->getData(); - int length = _bit->getLength()/8; - - /* test SPI */ - SPIFlash flash(this, _verbose); - flash.reset(); - flash.read_id(); - flash.read_status_reg(); - flash.erase_and_prog(offset, data, length); - - int ret = true; - if (_verify) - ret = flash.verify(offset, data, length); - - delete _bit; - return ret; + return true; } -bool Lattice::program_flash(unsigned int offset) +bool Lattice::post_flash_access() +{ + /* ISC REFRESH 0x79 */ + printInfo("Refresh: ", false); + if (loadConfiguration() == false) { + printError("FAIL"); + displayReadReg(readStatusReg()); + return false; + } else { + printSuccess("DONE"); + } + + /* bypass */ + wr_rd(0xff, NULL, 0, NULL, 0); + _jtag->go_test_logic_reset(); + return true; +} + +bool Lattice::clearSRAM() { uint32_t erase_op; - /* read ID Code 0xE0 */ - if (_verbose) { - printf("IDCode : %x\n", idCode()); - displayReadReg(readStatusReg()); - } - /* preload 0x1C */ uint8_t tx_buf[26]; memset(tx_buf, 0xff, 26); @@ -620,7 +582,69 @@ bool Lattice::program_flash(unsigned int offset) printSuccess("DONE"); } - DisableISC(); + return DisableISC(); +} + +bool Lattice::program_extFlash(unsigned int offset, bool unprotect_flash) +{ + int ret; + ConfigBitstreamParser *_bit; + + printInfo("Open file ", false); + try { + if (_file_extension == "mcs") + _bit = new McsParser(_filename, true, _verbose); + else if (_file_extension == "bit") + _bit = new LatticeBitParser(_filename, _verbose); + else + _bit = new RawParser(_filename, false); + printSuccess("DONE"); + } catch (std::exception &e) { + printError("FAIL"); + printError(e.what()); + return false; + } + + + printInfo("Parse file ", false); + if (_bit->parse() == EXIT_FAILURE) { + printError("FAIL"); + delete _bit; + return false; + } else { + printSuccess("DONE"); + } + + if (_verbose) + _bit->displayHeader(); + + if (_file_extension == "bit") { + uint32_t bit_idcode = std::stoul(_bit->getHeaderVal("idcode").c_str(), NULL, 16); + uint32_t idcode = idCode(); + if (idcode != bit_idcode) { + char mess[256]; + sprintf(mess, "mismatch between target's idcode and bitstream idcode\n" + "\tbitstream has 0x%08X hardware requires 0x%08x", bit_idcode, idcode); + printError(mess); + delete _bit; + return false; + } + } + + ret = SPIInterface::write(offset, _bit->getData(), _bit->getLength() / 8, + unprotect_flash); + + delete _bit; + return ret; +} + +bool Lattice::program_flash(unsigned int offset, bool unprotect_flash) +{ + /* read ID Code 0xE0 */ + if (_verbose) { + printf("IDCode : %x\n", idCode()); + displayReadReg(readStatusReg()); + } bool retval; if (_file_extension == "jed") { @@ -641,113 +665,41 @@ bool Lattice::program_flash(unsigned int offset) if (_verbose) _jed.displayHeader(); + /* clear current SRAM content */ + clearSRAM(); + if (_fpga_family == MACHXO3D_FAMILY) retval = program_intFlash_MachXO3D(_jed); else retval = program_intFlash(_jed); + return post_flash_access() && retval; } else if (_file_extension == "fea") { + /* clear current SRAM content */ + clearSRAM(); retval = program_fea_MachXO3D(); + return post_flash_access() && retval; } else if (_file_extension == "pub") { + /* clear current SRAM content */ + clearSRAM(); retval = program_pubkey_MachXO3D(); } else { - retval = program_extFlash(offset); + return program_extFlash(offset, unprotect_flash); } - if (!retval) - return false; - - /* *************************** */ - /* reload bitstream from flash */ - /* *************************** */ - - /* ISC REFRESH 0x79 */ - printInfo("Refresh: ", false); - if (loadConfiguration() == false) { - printError("FAIL"); - displayReadReg(readStatusReg()); - return false; - } else { - printSuccess("DONE"); - } - - /* bypass */ - wr_rd(0xff, NULL, 0, NULL, 0); - _jtag->go_test_logic_reset(); return true; } -void Lattice::program(unsigned int offset) +void Lattice::program(unsigned int offset, bool unprotect_flash) { bool retval = true; if (_mode == FLASH_MODE) - retval = program_flash(offset); + retval = program_flash(offset, unprotect_flash); else if (_mode == MEM_MODE) retval = program_mem(); if (!retval) throw std::exception(); } -bool Lattice::dumpFlash(const string &filename, - uint32_t base_addr, uint32_t len) -{ - /* idem program */ - - /* preload 0x1C */ - uint8_t tx_buf[26]; - memset(tx_buf, 0xff, 26); - wr_rd(0x1C, tx_buf, 26, NULL, 0); - - wr_rd(0xFf, NULL, 0, NULL, 0); - - /* ISC Enable 0xC6 */ - printInfo("Enable configuration: ", false); - if (!EnableISC(0x00)) { - printError("FAIL"); - displayReadReg(readStatusReg()); - return false; - } else { - printSuccess("DONE"); - } - - /* ISC ERASE */ - printInfo("SRAM erase: ", false); - if (flashErase(FLASH_ERASE_SRAM) == false) { - printError("FAIL"); - displayReadReg(readStatusReg()); - return false; - } else { - printSuccess("DONE"); - } - - DisableISC(); - - /* switch to SPI mode */ - _jtag->shiftIR(0x3A, 8, Jtag::EXIT1_IR); - uint8_t tmp[2] = {0xFE, 0x68}; - _jtag->shiftDR(tmp, NULL, 16); - - /* prepare SPI access */ - SPIFlash flash(this, _verbose); - flash.reset(); - flash.dump(filename, base_addr, len); - - /* ISC REFRESH 0x79 */ - printInfo("Refresh: ", false); - if (loadConfiguration() == false) { - printError("FAIL"); - displayReadReg(readStatusReg()); - return false; - } else { - printSuccess("DONE"); - } - - /* bypass */ - wr_rd(0xff, NULL, 0, NULL, 0); - _jtag->go_test_logic_reset(); - - return true; -} - /* flash mode : */ bool Lattice::EnableISC(uint8_t flash_mode) diff --git a/src/lattice.hpp b/src/lattice.hpp index eb57575..0a40f98 100644 --- a/src/lattice.hpp +++ b/src/lattice.hpp @@ -26,13 +26,27 @@ class Lattice: public Device, SPIInterface { int idCode() override; int userCode(); void reset() override {} - void program(unsigned int offset) override; + void program(unsigned int offset, bool unprotect_flash) override; bool program_mem(); - bool program_flash(unsigned int offset); + bool program_flash(unsigned int offset, bool unprotect_flash); bool Verify(std::vector data, bool unlock = false, uint32_t flash_area = 0); - bool dumpFlash(const std::string &filename, - uint32_t base_addr, uint32_t len) override; + bool dumpFlash(uint32_t base_addr, uint32_t len) override { + return SPIInterface::dump(base_addr, len); + } + + /*! + * \brief protect SPI flash blocks + */ + bool protect_flash(uint32_t len) override { + return SPIInterface::protect_flash(len); + } + /*! + * \brief protect SPI flash blocks + */ + bool unprotect_flash() override { + return SPIInterface::unprotect_flash(); + } /* spi interface */ int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, @@ -54,9 +68,22 @@ class Lattice: public Device, SPIInterface { lattice_family_t _fpga_family; bool program_intFlash(JedParser& _jed); - bool program_extFlash(unsigned int offset); + bool program_extFlash(unsigned int offset, bool unprotect_flash); bool wr_rd(uint8_t cmd, uint8_t *tx, int tx_len, uint8_t *rx, int rx_len, bool verbose = false); + /*! + * \brief move device to SPI access + */ + bool prepare_flash_access() override; + /*! + * \brief end of device to SPI access + * reload btistream from flash + */ + bool post_flash_access() override; + /*! + * \brief erase SRAM + */ + bool clearSRAM(); void unlock(); bool EnableISC(uint8_t flash_mode); bool DisableISC(); diff --git a/src/xilinx.cpp b/src/xilinx.cpp index 7be446d..073dc5d 100644 --- a/src/xilinx.cpp +++ b/src/xilinx.cpp @@ -30,6 +30,7 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename, Device::prog_type_t prg_type, const std::string &device_package, bool verify, int8_t verbose): Device(jtag, filename, file_type, verify, verbose), + SPIInterface(filename, verbose, 256, verify), _device_package(device_package) { if (prg_type == Device::RD_FLASH) { @@ -160,7 +161,7 @@ int Xilinx::idCode() return id; } -void Xilinx::program(unsigned int offset) +void Xilinx::program(unsigned int offset, bool unprotect_flash) { ConfigBitstreamParser *bit; bool reverse = false; @@ -226,15 +227,14 @@ void Xilinx::program(unsigned int offset) if (_fpga_family == XCF_FAMILY) { xcf_program(bit); + delete bit; return; } - if (_mode == Device::SPI_MODE) { - program_spi(bit, offset); - reset(); - } else { + if (_mode == Device::SPI_MODE) + program_spi(bit, offset, unprotect_flash); + else program_mem(bit); - } delete bit; } @@ -264,29 +264,16 @@ bool Xilinx::load_bridge() return true; } -void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset) +void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset, + bool unprotect_flash) { - /* first need to have bridge in RAM */ - if (load_bridge() == false) - return; - uint8_t *data = bit->getData(); int length = bit->getLength() / 8; - - SPIFlash spiFlash(this, (_verbose ? 1 : (_quiet ? -1 : 0))); - spiFlash.reset(); - spiFlash.read_id(); - spiFlash.display_status_reg(spiFlash.read_status_reg()); - spiFlash.erase_and_prog(offset, data, length); - - /* verify write if required */ - if (_verify) - spiFlash.verify(offset, data, length, 256); + SPIInterface::write(offset, data, length, unprotect_flash); } void Xilinx::program_mem(ConfigBitstreamParser *bitfile) { - if (_file_extension.empty()) return; std::cout << "load program" << std::endl; unsigned char tx_buf, rx_buf; /* comment TDI TMS TCK @@ -393,8 +380,7 @@ void Xilinx::program_mem(ConfigBitstreamParser *bitfile) _jtag->go_test_logic_reset(); } -bool Xilinx::dumpFlash(const std::string &filename, - uint32_t base_addr, uint32_t len) +bool Xilinx::dumpFlash(uint32_t base_addr, uint32_t len) { if (_fpga_family == XC95_FAMILY || _fpga_family == XCF_FAMILY) { std::string buffer; @@ -412,7 +398,7 @@ bool Xilinx::dumpFlash(const std::string &filename, xcf_flow_disable(); } printInfo("Open dump file ", false); - FILE *fd = fopen(filename.c_str(), "wb"); + FILE *fd = fopen(_filename.c_str(), "wb"); if (!fd) { printError("FAIL"); return false; @@ -429,26 +415,8 @@ bool Xilinx::dumpFlash(const std::string &filename, return true; } - int ret = true; - /* first need to have bridge in RAM */ - if (load_bridge() == false) - return false; - - /* prepare SPI access */ - SPIFlash flash(this, _verbose); - - try { - flash.reset(); - ret = flash.dump(filename, base_addr, len, 256); - } catch (std::exception &e) { - printError(e.what()); - ret = false; - } - - /* reset device */ - reset(); - - return ret; + /* dump SPI Flash */ + return SPIInterface::dump(base_addr, len); } /* */ diff --git a/src/xilinx.hpp b/src/xilinx.hpp index 282319a..8a322c0 100644 --- a/src/xilinx.hpp +++ b/src/xilinx.hpp @@ -22,11 +22,25 @@ class Xilinx: public Device, SPIInterface { bool verify, int8_t verbose); ~Xilinx(); - void program(unsigned int offset = 0) override; - void program_spi(ConfigBitstreamParser * bit, unsigned int offset = 0); + void program(unsigned int offset, bool unprotect_flash) override; + void program_spi(ConfigBitstreamParser * bit, unsigned int offset, + bool unprotect_flash); void program_mem(ConfigBitstreamParser *bitfile); - bool dumpFlash(const std::string &filename, - uint32_t base_addr, uint32_t len) override; + bool dumpFlash(uint32_t base_addr, uint32_t len) override; + + /*! + * \brief protect SPI flash blocks + */ + bool protect_flash(uint32_t len) override { + return SPIInterface::protect_flash(len); + } + /*! + * \brief unprotect SPI flash blocks + */ + bool unprotect_flash() override { + return SPIInterface::unprotect_flash(); + } + int idCode() override; void reset() override; @@ -105,6 +119,16 @@ class Xilinx: public Device, SPIInterface { int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, uint32_t timeout, bool verbose = false) override; + protected: + /*! + * \brief prepare SPI flash access (need to have bridge in RAM) + */ + virtual bool prepare_flash_access() override {return load_bridge();} + /*! + * \brief end of SPI flash access + */ + virtual bool post_flash_access() override {reset(); return true;} + private: /* list of xilinx family devices */ enum xilinx_family_t {