diff --git a/src/device.hpp b/src/device.hpp index cb396df..d4dd21b 100644 --- a/src/device.hpp +++ b/src/device.hpp @@ -53,6 +53,9 @@ class Device { printError("dump flash not supported"); return false;} virtual bool protect_flash(uint32_t len) = 0; virtual bool unprotect_flash() = 0; + virtual bool set_quad_bit(bool set_quad) { + (void)set_quad; + printError("Error: SPI Flash Quad mode configuration unsupported"); return false;} virtual bool bulk_erase_flash() = 0; virtual uint32_t idCode() = 0; diff --git a/src/main.cpp b/src/main.cpp index 3b0b89c..8707da3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -81,6 +81,8 @@ struct arguments { string ip_adr; uint32_t protect_flash; bool unprotect_flash; + bool enable_quad; + bool disable_quad; bool bulk_erase_flash; string flash_sector; bool skip_load_bridge; @@ -123,7 +125,7 @@ int main(int argc, char **argv) -1, 0, "primary", false, -1, /* vid, pid, index bus_addr, device_addr */ 0, 0, -1, 0, 0, - "127.0.0.1", 0, false, false, "", false, false, + "127.0.0.1", 0, false, false, false, false, "", false, false, /* xvc server */ false, 3721, "-", "", false, {}, // mcufw conmcu, user_misc_dev_list @@ -636,6 +638,24 @@ int main(int argc, char **argv) fpga->protect_flash(args.protect_flash); } + /* Enable/disable SPI Flash quad mode */ + if (args.enable_quad || args.disable_quad) { + bool ret = true; + if (args.enable_quad && args.disable_quad) { + printError("Error: can't set enable and disable Quad mode at same time"); + ret = false; + } else if (!fpga->set_quad_bit(args.enable_quad)) { + printError("Error: Failed to enable/disable Quad mode"); + ret = false; + } + + if (!ret) { + delete(fpga); + delete(jtag); + return EXIT_FAILURE; + } + } + /* detect/display flash */ if (args.detect_flash != 0) { fpga->detect_flash(); @@ -769,6 +789,10 @@ int parse_opt(int argc, char **argv, struct arguments *args, ("dump-flash", "Dump flash mode") ("bulk-erase", "Bulk erase flash", cxxopts::value(args->bulk_erase_flash)) + ("enable-quad", "Enable quad mode for SPI Flash", + cxxopts::value(args->enable_quad)) + ("disable-quad", "Disable quad mode for SPI Flash", + cxxopts::value(args->disable_quad)) ("target-flash", "for boards with multiple flash chips (some Xilinx UltraScale" " boards), select the target flash: primary (default), secondary or both", diff --git a/src/spiFlash.cpp b/src/spiFlash.cpp index ddd8a13..f3a28d1 100644 --- a/src/spiFlash.cpp +++ b/src/spiFlash.cpp @@ -891,26 +891,36 @@ int SPIFlash::enable_protection(uint32_t length) bool SPIFlash::set_quad_bit(bool set_quad) { - uint8_t reg_wr, reg_rd, reg_val, reg_val_verif; + uint8_t reg_wr, reg_rd; // read/write registers code + uint16_t reg_val; + uint32_t nb_rd_byte = 1; // Number of bytes to read (may differ from Flash models). + uint32_t nb_wr_byte = 1; // Number of bytes to write. + uint16_t quad_bit = 0; // quad_mask copy when bit must be set if (!_flash_model) { printError("spiFlash Error: can't configure Quad mode on unknown SPI Flash"); return false; } - if (_flash_model->quad_offset == 0 || _flash_model->quad_register == NONER) { + if (_flash_model->quad_mask == 0 || _flash_model->quad_register == NONER) { printError("spiFlash Error: SPI Flash has no Quad bit (or spiFlashdb must be updated)"); return false; } switch (_flash_model->quad_register) { case STATR: - reg_wr = FLASH_WRSR; reg_rd = FLASH_RDSR; + reg_wr = FLASH_WRSR; + break; + case NVCONFR: + reg_rd = FLASH_RDNVCR; + reg_wr = FLASH_WRNVCR; + nb_rd_byte = nb_wr_byte = 2; break; case CONFR: - reg_wr = FLASH_WRSR; reg_rd = FLASH_RDCR; + reg_wr = FLASH_WRSR; + nb_wr_byte = 2; break; default: printError("spiFlash Error: Unsupported register for Quad Enable bit configuration"); @@ -918,12 +928,17 @@ bool SPIFlash::set_quad_bit(bool set_quad) } /* Read current register value */ - _spi->spi_put(reg_rd, NULL, ®_val, 1); - /* Only update Quad bit */ - if (set_quad) - reg_val |= _flash_model->quad_offset; - else - reg_val &= ~_flash_model->quad_offset; + _spi->spi_put(reg_rd, NULL, (uint8_t *)®_val, nb_rd_byte); + reg_val &= ~_flash_model->quad_mask; // mask quad bit + + /* Micron: enable 0, disable 1 */ + if (_jedec_id == 0x20BA) + set_quad = ~set_quad; + if (set_quad) // set quad_bit when required + quad_bit = _flash_model->quad_mask; + + /* update Quad bit */ + reg_val |= quad_bit; /* enable write access */ if (write_enable() != 0) { @@ -931,25 +946,31 @@ bool SPIFlash::set_quad_bit(bool set_quad) return false; } - /* Write register with the updated value */ - if (_flash_model->quad_register == CONFR) { - uint8_t status = read_status_reg(); - uint8_t write_val[2] = {status, reg_val}; - _spi->spi_put(reg_wr, write_val, NULL, 2); - } else { - _spi->spi_put(reg_wr, ®_val, NULL, 1); + /* Configuration register has no dedicated write instruction + * -> a 16bits sequence must be sent to status register + */ + switch (_flash_model->quad_register) { + case CONFR: + uint8_t status = read_status_reg(); + reg_val = ((reg_val & 0xff) << 8) | status; + _spi->spi_put(reg_wr, (uint8_t*) ®_val, NULL, nb_wr_byte); + break; } - /* disable write access (wait for completion) */ - if (write_enable() != 0) { - printError("SPIFlash Error: failed to enable write"); + /* Write register with the updated value */ + _spi->spi_put(reg_wr, (uint8_t *)®_val, NULL, nb_wr_byte); + + /* Wait for completion */ + if (_spi->spi_wait(FLASH_RDSR, FLASH_RDSR_WEL, 0x00, 1000) != 0) { + printError("SPIFlash Error: failed to disable write"); return false; } - /* Check if current value match written value */ - _spi->spi_put(reg_rd, NULL, ®_val_verif, 1); + /* Check if register is correctly updated */ + _spi->spi_put(reg_rd, NULL, (uint8_t *)®_val, nb_rd_byte); - if ((reg_val_verif & _flash_model->quad_offset) == (reg_val & _flash_model->quad_offset)) { + if ((reg_val & _flash_model->quad_mask) == quad_bit) { + printf("%04x %04x %04x\n", reg_val, reg_val & _flash_model->quad_mask, quad_bit); printError("SPIFlash Error: failed to update Quad bit"); return false; } diff --git a/src/spiInterface.cpp b/src/spiInterface.cpp index 09f616b..571b6ec 100644 --- a/src/spiInterface.cpp +++ b/src/spiInterface.cpp @@ -114,6 +114,37 @@ bool SPIInterface::unprotect_flash() return post_flash_access() && ret; } +bool SPIInterface::set_quad_bit(bool set_quad) +{ + bool ret = true; + + /* move device to spi access */ + if (!prepare_flash_access()) { + printError("SPI Flash prepare access failed"); + return false; + } + + /* spi flash access */ + try { + SPIFlash flash(this, false, _spif_verbose); + + /* configure flash protection */ + printInfo("set_quad_bit: ", false); + ret = flash.set_quad_bit(set_quad); + if (!ret) + printError("Fail"); + else + printSuccess("Done"); + } catch (std::exception &e) { + printError("SPI Flash access failed: ", false); + printError(e.what()); + ret = false; + } + + /* reload bitstream */ + return post_flash_access() && ret; +} + bool SPIInterface::bulk_erase_flash() { bool ret = true; diff --git a/src/spiInterface.hpp b/src/spiInterface.hpp index 6566df2..c502d99 100644 --- a/src/spiInterface.hpp +++ b/src/spiInterface.hpp @@ -29,6 +29,7 @@ class SPIInterface { bool detect_flash(); bool protect_flash(uint32_t len); bool unprotect_flash(); + bool set_quad_bit(bool set_quad); bool bulk_erase_flash(); void set_filename(const std::string &filename) {_spif_filename = filename;} diff --git a/src/xilinx.cpp b/src/xilinx.cpp index 1ecc342..7e5332d 100644 --- a/src/xilinx.cpp +++ b/src/xilinx.cpp @@ -1197,6 +1197,21 @@ bool Xilinx::unprotect_flash() return true; } +bool Xilinx::set_quad_bit(bool set_quad) +{ + if (_flash_chips & PRIMARY_FLASH) { + select_flash_chip(PRIMARY_FLASH); + if (!SPIInterface::set_quad_bit(set_quad)) + return false; + } + if (_flash_chips & SECONDARY_FLASH) { + select_flash_chip(SECONDARY_FLASH); + if (!SPIInterface::set_quad_bit(set_quad)) + return false; + } + return true; +} + bool Xilinx::bulk_erase_flash() { if (_flash_chips & PRIMARY_FLASH) { diff --git a/src/xilinx.hpp b/src/xilinx.hpp index ae4dfa5..8993fb4 100644 --- a/src/xilinx.hpp +++ b/src/xilinx.hpp @@ -65,6 +65,10 @@ class Xilinx: public Device, SPIInterface { * \brief unprotect SPI flash blocks */ bool unprotect_flash() override; + /*! + * \brief configure Quad mode for SPI Flash + */ + bool set_quad_bit(bool set_quad) override; /*! * \brief erase SPI flash blocks */