From c468a69fc91c899abd652b074678a3a98afafb22 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sun, 9 Jun 2024 09:28:52 +0200 Subject: [PATCH] all devices / spiInterface / main: added method / infra to detect flash chip with --detect -f --- src/altera.hpp | 6 ++++++ src/colognechip.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/colognechip.hpp | 1 + src/device.hpp | 2 ++ src/gowin.hpp | 4 ++++ src/lattice.hpp | 6 ++++++ src/main.cpp | 20 ++++++++++++++++++-- src/spiInterface.cpp | 29 +++++++++++++++++++++++++++++ src/spiInterface.hpp | 1 + src/xilinx.cpp | 15 +++++++++++++++ src/xilinx.hpp | 4 ++++ 11 files changed, 126 insertions(+), 2 deletions(-) diff --git a/src/altera.hpp b/src/altera.hpp index f63ccf683e..9a168ff7f8 100644 --- a/src/altera.hpp +++ b/src/altera.hpp @@ -46,6 +46,12 @@ class Altera: public Device, SPIInterface { /* spi interface */ /*************************/ + /*! + * \brief display SPI flash ID and status register + */ + bool detect_flash() override { + return SPIInterface::detect_flash(); + } /*! * \brief protect SPI flash blocks */ diff --git a/src/colognechip.cpp b/src/colognechip.cpp index 6bee1cb7ba..99369ebfe3 100644 --- a/src/colognechip.cpp +++ b/src/colognechip.cpp @@ -123,6 +123,46 @@ void CologneChip::waitCfgDone() } } +/** + * Dump flash contents to file. Works in both SPI and JTAG-SPI-bypass mode. + */ +bool CologneChip::detect_flash() +{ + if (_spi) { + /* enable output and hold reset */ + _spi->gpio_clear(_rstn_pin | _oen_pin); + } else if (_ftdi_jtag) { + /* enable output and disable reset */ + _ftdi_jtag->gpio_clear(_oen_pin); + _ftdi_jtag->gpio_set(_rstn_pin); + } + + /* prepare SPI access */ + printInfo("Read Flash ", false); + try { + std::unique_ptr flash(_spi ? + new SPIFlash(reinterpret_cast(_spi), false, _verbose): + new SPIFlash(this, false, _verbose)); + flash->read_id(); + flash->display_status_reg(); + } catch (std::exception &e) { + printError("Fail"); + printError(std::string(e.what())); + return false; + } + + if (_spi) { + /* disable output and release reset */ + _spi->gpio_set(_rstn_pin | _oen_pin); + } else if (_ftdi_jtag) { + /* disable output */ + _ftdi_jtag->gpio_set(_oen_pin); + } + usleep(SLEEP_US); + + return true; +} + /** * Dump flash contents to file. Works in both SPI and JTAG-SPI-bypass mode. */ diff --git a/src/colognechip.hpp b/src/colognechip.hpp index 7aef8ca679..a0a7cb2a8d 100644 --- a/src/colognechip.hpp +++ b/src/colognechip.hpp @@ -34,6 +34,7 @@ class CologneChip: public Device, SPIInterface { bool cfgDone(); void waitCfgDone(); + bool detect_flash() override; bool dumpFlash(uint32_t base_addr, uint32_t len) override; virtual bool protect_flash(uint32_t len) override { (void) len; diff --git a/src/device.hpp b/src/device.hpp index a9b14d7ce1..cb396dfd39 100644 --- a/src/device.hpp +++ b/src/device.hpp @@ -46,6 +46,8 @@ class Device { /**********************/ /* flash access */ /**********************/ + virtual bool detect_flash() { + printError("detect flash not supported"); return false;} virtual bool dumpFlash(uint32_t base_addr, uint32_t len) { (void) base_addr; (void) len; printError("dump flash not supported"); return false;} diff --git a/src/gowin.hpp b/src/gowin.hpp index 94649f0f41..67154a77b4 100644 --- a/src/gowin.hpp +++ b/src/gowin.hpp @@ -29,6 +29,10 @@ class Gowin: public Device, SPIInterface { bool connectJtagToMCU() override; /* spi interface */ + bool detect_flash() override { + if (is_gw5a) + return SPIInterface::detect_flash(); + printError("protect flash not supported"); return false;} bool protect_flash(uint32_t len) override { (void) len; printError("protect flash not supported"); return false;} diff --git a/src/lattice.hpp b/src/lattice.hpp index 1a74861df3..ae3e4f2e73 100644 --- a/src/lattice.hpp +++ b/src/lattice.hpp @@ -35,6 +35,12 @@ class Lattice: public Device, SPIInterface { return SPIInterface::dump(base_addr, len); } + /*! + * \brief display SPI flash ID and status register + */ + bool detect_flash() override { + return SPIInterface::detect_flash(); + } /*! * \brief protect SPI flash blocks */ diff --git a/src/main.cpp b/src/main.cpp index 573e2a4aab..28810d161b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,7 +44,7 @@ using namespace std; struct arguments { int8_t verbose; - bool reset, detect, verify, scan_usb; + bool reset, detect, detect_flash, verify, scan_usb; unsigned int offset; string bit_file; string secondary_bit_file; @@ -112,7 +112,10 @@ int main(int argc, char **argv) jtag_pins_conf_t pins_config = {0, 0, 0, 0}; /* command line args. */ - struct arguments args = {0, false, false, false, false, 0, "", "", "", "-", "", -1, + struct arguments args = {0, + //reset, detect, detect_flash, verify, scan_usb + false, false, false, false, false, + 0, "", "", "", "-", "", -1, -1, 0, false, "-", false, false, false, false, Device::PRG_NONE, false, /* spi dfu file_type fpga_part bridge_path probe_firmware */ false, false, "", "", "", "", @@ -633,6 +636,11 @@ int main(int argc, char **argv) fpga->protect_flash(args.protect_flash); } + /* detect/display flash */ + if (args.detect_flash != 0) { + fpga->detect_flash(); + } + if (args.prg_type == Device::RD_FLASH) { if (args.file_size == 0) { printError("Error: 0 size for dump"); @@ -1050,6 +1058,14 @@ int parse_opt(int argc, char **argv, struct arguments *args, cout << options.help() << endl; throw std::exception(); } + + // user ask detect with flash set + // detect/display flash CHIP informations instead + // of FPGA details + if (args->detect && args->prg_type == Device::WR_FLASH) { + args->detect = false; + args->detect_flash = true; + } } catch (const cxxopts::OptionException& e) { cerr << "Error parsing options: " << e.what() << endl; throw std::exception(); diff --git a/src/spiInterface.cpp b/src/spiInterface.cpp index 87423cce40..09f616b93a 100644 --- a/src/spiInterface.cpp +++ b/src/spiInterface.cpp @@ -23,6 +23,35 @@ SPIInterface::SPIInterface(const std::string &filename, int8_t verbose, {} /* spiFlash generic acces */ +bool SPIInterface::detect_flash() +{ + bool ret = true; + printInfo("protect_flash: ", false); + + /* move device to spi access */ + if (!prepare_flash_access()) { + printError("Fail"); + return false; + } + + /* spi flash access */ + try { + // instanciate call (display flash ID is automatic) + SPIFlash flash(this, false, _spif_verbose); + // display status register + flash.display_status_reg(); + + printSuccess("Done"); + } catch (std::exception &e) { + printError("Fail"); + printError(e.what()); + ret = false; + } + + /* reload bitstream */ + return post_flash_access() && ret; +} + bool SPIInterface::protect_flash(uint32_t len) { bool ret = true; diff --git a/src/spiInterface.hpp b/src/spiInterface.hpp index 24dd0697db..6566df2020 100644 --- a/src/spiInterface.hpp +++ b/src/spiInterface.hpp @@ -26,6 +26,7 @@ class SPIInterface { bool skip_reset = false); virtual ~SPIInterface() {} + bool detect_flash(); bool protect_flash(uint32_t len); bool unprotect_flash(); bool bulk_erase_flash(); diff --git a/src/xilinx.cpp b/src/xilinx.cpp index 050d739134..1ecc3427b4 100644 --- a/src/xilinx.cpp +++ b/src/xilinx.cpp @@ -1152,6 +1152,21 @@ bool Xilinx::dumpFlash(uint32_t base_addr, uint32_t len) return true; } +bool Xilinx::detect_flash() +{ + if (_flash_chips & PRIMARY_FLASH) { + select_flash_chip(PRIMARY_FLASH); + if (!SPIInterface::detect_flash()) + return false; + } + if (_flash_chips & SECONDARY_FLASH) { + select_flash_chip(SECONDARY_FLASH); + if (!SPIInterface::detect_flash()) + return false; + } + return true; +} + bool Xilinx::protect_flash(uint32_t len) { if (_flash_chips & PRIMARY_FLASH) { diff --git a/src/xilinx.hpp b/src/xilinx.hpp index 4e5e52d63d..ae4dfa518d 100644 --- a/src/xilinx.hpp +++ b/src/xilinx.hpp @@ -53,6 +53,10 @@ class Xilinx: public Device, SPIInterface { */ uint32_t dumpRegister(const std::string reg_name); + /*! + * \brief display SPI flash ID and status register + */ + bool detect_flash() override; /*! * \brief protect SPI flash blocks */