gowin: try again to fix gw5ast flash write

This commit is contained in:
Gwenhael Goavec-Merou 2023-12-22 06:59:30 +01:00
parent cd40de37cb
commit a58f946ed5
5 changed files with 121 additions and 26 deletions

View File

@ -160,10 +160,12 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
_jtag->set_state(Jtag::TEST_LOGIC_RESET); _jtag->set_state(Jtag::TEST_LOGIC_RESET);
if (_verbose) if (_verbose)
displayReadReg("Before disable SPI mode", readStatusReg()); displayReadReg("Before disable SPI mode", readStatusReg());
disableCfg(); //disableCfg();
send_command(CONFIG_DISABLE); // BYPASS ?
send_command(0); // BYPASS ? send_command(0); // BYPASS ?
_jtag->set_state(Jtag::TEST_LOGIC_RESET); _jtag->set_state(Jtag::TEST_LOGIC_RESET);
gw5a_disable_spi(); gw5a_disable_spi();
idCode();
} }
} }
@ -224,6 +226,7 @@ bool Gowin::send_command(uint8_t cmd)
{ {
_jtag->shiftIR(&cmd, nullptr, 8); _jtag->shiftIR(&cmd, nullptr, 8);
_jtag->toggleClk(6); _jtag->toggleClk(6);
_jtag->flush();
return true; return true;
} }
@ -249,6 +252,7 @@ uint32_t Gowin::readReg32(uint8_t cmd)
uint32_t reg = 0, tmp = 0xffffffffU; uint32_t reg = 0, tmp = 0xffffffffU;
send_command(cmd); send_command(cmd);
_jtag->shiftDR((uint8_t *)&tmp, (uint8_t *)&reg, 32); _jtag->shiftDR((uint8_t *)&tmp, (uint8_t *)&reg, 32);
_jtag->toggleClk(1);
return le32toh(reg); return le32toh(reg);
} }
@ -769,6 +773,7 @@ bool Gowin::writeSRAM(const uint8_t *data, int length)
int remains = length; int remains = length;
const uint8_t *ptr = data; const uint8_t *ptr = data;
static const unsigned pstep = 524288; // 0x80000, about 0.2 sec of bitstream at 2.5MHz static const unsigned pstep = 524288; // 0x80000, about 0.2 sec of bitstream at 2.5MHz
printf("length : %d\n", length);
while (remains) { while (remains) {
int chunk = pstep; int chunk = pstep;
/* 2.2.6.5 */ /* 2.2.6.5 */
@ -876,9 +881,18 @@ bool Gowin::eraseFLASH()
void Gowin::sendClkUs(unsigned us) void Gowin::sendClkUs(unsigned us)
{ {
uint64_t clocks = _jtag->getClkFreq(); uint64_t clocks = _jtag->getClkFreq();
printf("%d %d ", clocks, us);
clocks *= us; clocks *= us;
printf("%lu ", clocks);
clocks /= 1000000; clocks /= 1000000;
_jtag->toggleClk(clocks); uint32_t kLen = (clocks + 7 ) / 8;
uint8_t dummy[kLen];
printf("%d %d\n", clocks, kLen);
memset(dummy, 0, kLen);
_jtag->read_write(dummy, NULL, clocks & 0xffffffff, 0);
if ((clocks > 0xffffffff))
_jtag->read_write(dummy, NULL, clocks - 0xffffffff, 0);
//_jtag->toggleClk(clocks);
} }
/* Erase SRAM: /* Erase SRAM:
@ -890,10 +904,12 @@ bool Gowin::eraseSRAM()
if (_verbose) if (_verbose)
displayReadReg("before erase sram", readStatusReg()); displayReadReg("before erase sram", readStatusReg());
if (!enableCfg()) { /*if (!enableCfg()) {
printError("FAIL"); printError("FAIL");
return false; return false;
} }*/
send_command(0x11);
send_command(CONFIG_ENABLE);
send_command(ERASE_SRAM); send_command(ERASE_SRAM);
send_command(NOOP); send_command(NOOP);
@ -904,23 +920,27 @@ bool Gowin::eraseSRAM()
* this check seems enough * this check seems enough
*/ */
if (_idcode == 0x0001081b) // seems required for GW5AST... if (_idcode == 0x0001081b) // seems required for GW5AST...
sendClkUs(10000); sendClkUs(750*9);
if (pollFlag(STATUS_MEMORY_ERASE, STATUS_MEMORY_ERASE)) { else {
if (_verbose) if (pollFlag(STATUS_MEMORY_ERASE, STATUS_MEMORY_ERASE)) {
displayReadReg("after erase sram", readStatusReg()); if (_verbose)
} else { displayReadReg("after erase sram", readStatusReg());
printError("FAIL"); } else {
return false; printError("FAIL");
return false;
}
} }
send_command(XFER_DONE); send_command(XFER_DONE);
send_command(NOOP); send_command(NOOP);
if (!disableCfg()) { send_command(CONFIG_DISABLE);
send_command(NOOP);
/*if (!disableCfg()) {
printError("FAIL"); printError("FAIL");
return false; return false;
} }*/
if (_mode == Device::FLASH_MODE) { /*if (_mode == Device::FLASH_MODE) {
uint32_t status_reg = readStatusReg(); uint32_t status_reg = readStatusReg();
if (_verbose) if (_verbose)
displayReadReg("after erase sram", status_reg); displayReadReg("after erase sram", status_reg);
@ -930,7 +950,7 @@ bool Gowin::eraseSRAM()
} else { } else {
printSuccess("DONE"); printSuccess("DONE");
} }
} }*/
return true; return true;
} }
@ -1149,6 +1169,7 @@ bool Gowin::dumpFlash(uint32_t base_addr, uint32_t len)
bool Gowin::prepare_flash_access() bool Gowin::prepare_flash_access()
{ {
_jtag->setClkFreq(10000000); _jtag->setClkFreq(10000000);
//_jtag->setClkFreq(2500000);
if (!eraseSRAM()) { if (!eraseSRAM()) {
printError("Error: fail to erase SRAM"); printError("Error: fail to erase SRAM");
@ -1156,6 +1177,11 @@ bool Gowin::prepare_flash_access()
} }
if (is_gw5a) { if (is_gw5a) {
if (!eraseSRAM()) {
printError("Error: fail to erase SRAM");
return false;
}
displayReadReg("toto", readStatusReg());
if (!gw5a_enable_spi()) { if (!gw5a_enable_spi()) {
printError("Error: fail to switch GW5A to SPI mode"); printError("Error: fail to switch GW5A to SPI mode");
return false; return false;
@ -1229,9 +1255,14 @@ int Gowin::spi_put_gw5a(const uint8_t cmd, const uint8_t *tx, uint8_t *rx,
if (0 != _jtag->read_write(jtx, (rx) ? jrx : NULL, bit_len, 0)) if (0 != _jtag->read_write(jtx, (rx) ? jrx : NULL, bit_len, 0))
return -1; return -1;
// set TMS/CS high by moving to a state where TMS == 1 // set TMS/CS high by moving to a state where TMS == 1
_jtag->set_state(Jtag::TEST_LOGIC_RESET, curr_tdi); //_jtag->set_state(Jtag::TEST_LOGIC_RESET, 0/*curr_tdi*/);
_jtag->toggleClk(5); // Required ? _jtag->set_state(Jtag::SELECT_DR_SCAN, 0/*curr_tdi*/);
_jtag->flushTMS(true); _jtag->flush();
_jtag->set_state(Jtag::TEST_LOGIC_RESET, 0/*curr_tdi*/);
const uint8_t dummy = 0;
_jtag->read_write(&dummy, NULL, 5, 0);
//_jtag->toggleClk(5); // Required ?
//_jtag->flush();
if (rx) { // Reconstruct read sequence and drop first 3bits. if (rx) { // Reconstruct read sequence and drop first 3bits.
for (uint32_t i = 0; i < len; i++) for (uint32_t i = 0; i < len; i++)
rx[i] = FsParser::reverseByte((jrx[i] >> 3) | rx[i] = FsParser::reverseByte((jrx[i] >> 3) |
@ -1255,6 +1286,7 @@ int Gowin::spi_wait_gw5a(uint8_t cmd, uint8_t mask, uint8_t cond,
} }
count++; count++;
//printf("%x %x %x %u\n", tmp, mask, cond, count);
if (count == timeout) { if (count == timeout) {
printf("timeout: %x\n", tmp); printf("timeout: %x\n", tmp);
break; break;
@ -1269,21 +1301,31 @@ int Gowin::spi_wait_gw5a(uint8_t cmd, uint8_t mask, uint8_t cond,
bool Gowin::gw5a_enable_spi() bool Gowin::gw5a_enable_spi()
{ {
enableCfg(); uint8_t dummy[625];
memset(dummy, 0, 625);
//enableCfg();
send_command(0x15);
send_command(0x3F); send_command(0x3F);
disableCfg(); send_command(0x3A);
//disableCfg();
if (_verbose) if (_verbose)
displayReadReg("toto", readStatusReg()); displayReadReg("toto", readStatusReg());
/* UG704 3.4.3 'ExtFlash Programming -> Program External Flash via JTAG-SPI' */ /* UG704 3.4.3 'ExtFlash Programming -> Program External Flash via JTAG-SPI' */
send_command(NOOP); send_command(NOOP);
send_command(0x11);
send_command(0x02);
_jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(126*8); //_jtag->toggleClk(126*8);
_jtag->read_write(dummy, NULL, 126 * 8, 0);
//sendClkUs(51);
_jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->set_state(Jtag::RUN_TEST_IDLE);
send_command(0x16); send_command(0x16);
send_command(0x00); send_command(0x00);
_jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(625*8); //_jtag->toggleClk(625*8);
//_jtag->read_write(dummy, NULL, 625 * 8, 0);
sendClkUs(250*9);
_jtag->set_state(Jtag::TEST_LOGIC_RESET); _jtag->set_state(Jtag::TEST_LOGIC_RESET);
/* save current read/write edge cfg before switching to SPI mode0 /* save current read/write edge cfg before switching to SPI mode0
* (rising edge: read / falling edge: write) * (rising edge: read / falling edge: write)
@ -1327,5 +1369,6 @@ bool Gowin::gw5a_disable_spi()
// 2. 8 TCK clock cycle with TMS=1 // 2. 8 TCK clock cycle with TMS=1
_jtag->set_state(Jtag::TEST_LOGIC_RESET); // 5 cycles _jtag->set_state(Jtag::TEST_LOGIC_RESET); // 5 cycles
_jtag->toggleClk(5); _jtag->toggleClk(5);
idCode();
return true; return true;
} }

View File

@ -84,7 +84,7 @@ Jtag::Jtag(const cable_t &cable, const jtag_pins_conf_t *pin_conf,
_tms_buffer_size(128), _num_tms(0), _tms_buffer_size(128), _num_tms(0),
_board_name("nope"), _user_misc_devs(user_misc_devs), _board_name("nope"), _user_misc_devs(user_misc_devs),
device_index(0), _dr_bits_before(0), _dr_bits_after(0), device_index(0), _dr_bits_before(0), _dr_bits_after(0),
_ir_bits_before(0), _ir_bits_after(0), _curr_tdi(1) _ir_bits_before(0), _ir_bits_after(0), _curr_tdi(0)
{ {
switch (cable.type) { switch (cable.type) {
case MODE_ANLOGICCABLE: case MODE_ANLOGICCABLE:
@ -347,7 +347,7 @@ void Jtag::go_test_logic_reset()
_state = TEST_LOGIC_RESET; _state = TEST_LOGIC_RESET;
} }
int Jtag::read_write(const uint8_t *tdi, unsigned char *tdo, int len, char last) int Jtag::read_write(const uint8_t *tdi, unsigned char *tdo, uint32_t len, char last)
{ {
flushTMS(false); flushTMS(false);
_jtag->writeTDI(tdi, tdo, len, last); _jtag->writeTDI(tdi, tdo, len, last);

View File

@ -117,11 +117,11 @@ class Jtag {
tapState_t end_state = RUN_TEST_IDLE); tapState_t end_state = RUN_TEST_IDLE);
int shiftDR(const uint8_t *tdi, unsigned char *tdo, int drlen, int shiftDR(const uint8_t *tdi, unsigned char *tdo, int drlen,
tapState_t end_state = RUN_TEST_IDLE); tapState_t end_state = RUN_TEST_IDLE);
int read_write(const uint8_t *tdi, unsigned char *tdo, int len, char last); int read_write(const uint8_t *tdi, unsigned char *tdo, uint32_t len, char last);
void toggleClk(int nb); void toggleClk(int nb);
void go_test_logic_reset(); void go_test_logic_reset();
void set_state(tapState_t newState, const uint8_t tdi = 1); void set_state(tapState_t newState, const uint8_t tdi = 0);
int flushTMS(bool flush_buffer = false); int flushTMS(bool flush_buffer = false);
void flush() {flushTMS(); _jtag->flush();} void flush() {flushTMS(); _jtag->flush();}
void setTMS(unsigned char tms); void setTMS(unsigned char tms);

View File

@ -457,6 +457,57 @@ int SPIFlash::erase_and_prog(int base_addr, const uint8_t *data, int len)
return 0; return 0;
} }
int SPIFlash::erase_and_prog2(int base_addr, const uint8_t *data, int len)
{
printf("len: %d base_addr %08x\n", len, base_addr);
/* Now we can erase sector and write new data */
ProgressBar progress("Writing", len, 50, _verbose < 0);
const uint8_t *ptr = data;
int size = 0;
uint8_t buffer[0x100];
for (int sect_addr = 0; sect_addr < len; sect_addr += 0x1000) {
bool must_erase = true;
bool must_write = true;
bool all_same = true;
size = (sect_addr + 0x1000 > len)?(len-sect_addr) : 0x1000;
uint8_t first_c = ptr[0];
for (int p = 1; p < size; p++) {
if (first_c != ptr[p]) {
all_same = false;
break;
}
}
if (all_same) {
must_erase = first_c == 0xff;
must_write = first_c == 0x00;
}
if (must_erase) {
/* erase 4K (ie 256B * 16 pages) */
sector_erase(sect_addr); // erase 4K
}
for (int page_addr = 0; page_addr < 0x1000; page_addr += 0x100) {
uint32_t addr = sect_addr + page_addr;
size = (addr + 256 > len)?(len-addr) : 256;
memset(buffer, 0xff, 0x100);
if (addr > len) {
memcpy(buffer, ptr, size);
ptr += size;
}
printf("sect_addr %08x page_addr %08x addr %08x\n", sect_addr, page_addr, addr+base_addr);
if (must_write) {
if (write_page(addr + base_addr, buffer, 0x100) == -1)
return -1;
}
}
progress.display(sect_addr);
}
progress.done();
return 0;
}
bool SPIFlash::verify(const int &base_addr, const uint8_t *data, bool SPIFlash::verify(const int &base_addr, const uint8_t *data,
const int &len, int rd_burst) const int &len, int rd_burst)
{ {

View File

@ -80,6 +80,7 @@ class SPIFlash {
const int &len, int rd_burst = 0); const int &len, int rd_burst = 0);
/* combo flash + erase */ /* combo flash + erase */
int erase_and_prog(int base_addr, const uint8_t *data, int len); int erase_and_prog(int base_addr, const uint8_t *data, int len);
int erase_and_prog2(int base_addr, const uint8_t *data, int len);
/*! /*!
* \brief check if area base_addr to base_addr + len match * \brief check if area base_addr to base_addr + len match
* data content * data content