Skip to content

Commit

Permalink
core: added option/methods to enable/disable quad mode on SPI Flash
Browse files Browse the repository at this point in the history
  • Loading branch information
trabucayre committed Aug 23, 2024
1 parent baa9edd commit b82cb6a
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 22 deletions.
3 changes: 3 additions & 0 deletions src/device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
26 changes: 25 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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<bool>(args->bulk_erase_flash))
("enable-quad", "Enable quad mode for SPI Flash",
cxxopts::value<bool>(args->enable_quad))
("disable-quad", "Disable quad mode for SPI Flash",
cxxopts::value<bool>(args->disable_quad))
("target-flash",
"for boards with multiple flash chips (some Xilinx UltraScale"
" boards), select the target flash: primary (default), secondary or both",
Expand Down
61 changes: 48 additions & 13 deletions src/spiFlash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ void SPIFlash::display_status_reg(uint8_t reg)
printf("BUSY : %d\n", (reg >> 7) & 0x01);
}

/* function register */
/* function and/or configuration register */
switch (dev_id) {
case 0x9d60:
_spi->spi_put(FLASH_RDFR, NULL, &reg, 1);
Expand All @@ -631,6 +631,20 @@ void SPIFlash::display_status_reg(uint8_t reg)
printf("BPNV : %d\n", ((reg >> 3) & 0x01));
printf("TBPROT : %d\n", ((reg >> 5) & 0x01));
break;
case 0x20BA:
uint16_t nv_reg;
_spi->spi_put(FLASH_RDNVCR, NULL, (uint8_t*)&nv_reg, 2);
printf("\nNonvolatile Configuration Register\n");
printf("RDNVCR : %02x\n", nv_reg);
printf("Dummy Clock Cycles : %d\n", ((nv_reg >> 12) & 0x0f));
printf("XIP mode at power-on/rst : %d\n", ((nv_reg >> 9) & 0x07));
printf("Output Driver strength : %d\n", ((nv_reg >> 6) & 0x07));
/* 5: reserved */
printf("RST/HLD : %d\n", ((nv_reg >> 4) & 0x01));
printf("QUAD : %d\n", ((nv_reg >> 3) & 0x01));
printf("DUAL : %d\n", ((nv_reg >> 2) & 0x01));
/* 1:0: reserved */
break;
}
}

Expand Down Expand Up @@ -867,13 +881,18 @@ 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;
uint16_t reg_val, reg_val_verif;
uint32_t nb_byte = 1;

if (!_flash_model) {
printError("spiFlash Error: can't configure Quad mode on unknown SPI Flash");
return false;
}

printf("%08x %02x %04x\n", _jedec_id, _flash_model->quad_offset, _flash_model->quad_register);
printf("%08x\n", _jedec_id >> 16);

if (_flash_model->quad_offset == 0 || _flash_model->quad_register == NONER) {
printError("spiFlash Error: SPI Flash has no Quad bit (or spiFlashdb must be updated)");
return false;
Expand All @@ -885,21 +904,29 @@ bool SPIFlash::set_quad_bit(bool set_quad)
reg_rd = FLASH_RDSR;
break;
case CONFR:
reg_wr = FLASH_WRSR;
reg_rd = FLASH_RDCR;
if ((_jedec_id >> 16) == 0x20BA) {
reg_wr = FLASH_WRNVCR;
reg_rd = FLASH_RDNVCR;
nb_byte = 2;
} else {
reg_wr = FLASH_WRSR;
reg_rd = FLASH_RDCR;
}
break;
default:
printError("spiFlash Error: Unsupported register for Quad Enable bit configuration");
return false;
}

/* Read current register value */
_spi->spi_put(reg_rd, NULL, &reg_val, 1);
_spi->spi_put(reg_rd, NULL, (uint8_t *)&reg_val, nb_byte);
printf("reg val : %04x\n", reg_val);
/* Only update Quad bit */
if (set_quad)
reg_val |= _flash_model->quad_offset;
else
reg_val &= ~_flash_model->quad_offset;
printf("reg val : %04x\n", reg_val);

/* enable write access */
if (write_enable() != 0) {
Expand All @@ -908,22 +935,30 @@ bool SPIFlash::set_quad_bit(bool set_quad)
}

/* 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);
switch (_flash_model->quad_register) {
case STATR:
_spi->spi_put(reg_wr, (uint8_t *)&reg_val, NULL, 1);
break;
case CONFR:
if ((_jedec_id >> 16) == 0x20BA) {
_spi->spi_put(reg_wr, (uint8_t*)&reg_val, NULL, 2);
} else {
uint8_t status = read_status_reg();
uint8_t write_val[2] = {status, (uint8_t)(reg_val & 0xff)};
_spi->spi_put(reg_wr, write_val, NULL, 2);
}
break;
} else {
_spi->spi_put(reg_wr, &reg_val, NULL, 1);
}

/* disable write access (wait for completion) */
if (write_enable() != 0) {
printError("SPIFlash Error: failed to enable write");
if (write_disable() != 0) {
printError("SPIFlash Error: failed to disable write");
return false;
}

/* Check if current value match written value */
_spi->spi_put(reg_rd, NULL, &reg_val_verif, 1);
_spi->spi_put(reg_rd, NULL, (uint8_t *)&reg_val_verif, nb_byte);

if ((reg_val_verif & _flash_model->quad_offset) == (reg_val & _flash_model->quad_offset)) {
printError("SPIFlash Error: failed to update Quad bit");
Expand Down
17 changes: 9 additions & 8 deletions src/spiFlashdb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ static std::map <uint32_t, flash_t> flash_list = {
.tb_register = STATR,
.bp_len = 3,
.bp_offset = {(1 << 2), (1 << 3), (1 << 4), 0},
.quad_register = NONER,
.quad_offset = 0,
.quad_register = CONFR,
.quad_offset = (1 << 3),
}},
{0x20ba17, {
.manufacturer = "micron",
Expand All @@ -203,8 +203,8 @@ static std::map <uint32_t, flash_t> flash_list = {
.tb_register = STATR,
.bp_len = 4,
.bp_offset = {(1 << 2), (1 << 3), (1 << 4), (1 << 6)},
.quad_register = NONER,
.quad_offset = 0,
.quad_register = CONFR,
.quad_offset = (1 << 3),
}},
{0x20ba18, {
/* https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/nor-flash/serial-nor/n25q/n25q_128mb_3v_65nm.pdf */
Expand All @@ -219,10 +219,11 @@ static std::map <uint32_t, flash_t> flash_list = {
.tb_register = STATR,
.bp_len = 4,
.bp_offset = {(1 << 2), (1 << 3), (1 << 4), (1 << 6)},
.quad_register = NONER,
.quad_offset = 0,
.quad_register = CONFR,
.quad_offset = (1 << 3),
}},
{0x20ba19, {
/* https://datasheet.octopart.com/N25Q256A13E1241F-Micron-datasheet-11552757.pdf */
.manufacturer = "micron",
.model = "N25Q256",
.nr_sector = 512,
Expand All @@ -234,8 +235,8 @@ static std::map <uint32_t, flash_t> flash_list = {
.tb_register = STATR,
.bp_len = 4,
.bp_offset = {(1 << 2), (1 << 3), (1 << 4), (1 << 6)},
.quad_register = NONER,
.quad_offset = 0,
.quad_register = CONFR,
.quad_offset = (1 << 3),
}},
{0x20bb18, {
/* https://www.micron.com/-/media/client/global/documents/products/data-sheet/nor-flash/serial-nor/n25q/n25q_128mb_1_8v_65nm.pdf */
Expand Down
31 changes: 31 additions & 0 deletions src/spiInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/spiInterface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;}

Expand Down
15 changes: 15 additions & 0 deletions src/xilinx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions src/xilinx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down

0 comments on commit b82cb6a

Please sign in to comment.