Skip to content

Commit

Permalink
gowin: try again to fix gw5ast flash write
Browse files Browse the repository at this point in the history
  • Loading branch information
trabucayre committed Dec 22, 2023
1 parent cd40de3 commit a58f946
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 26 deletions.
87 changes: 65 additions & 22 deletions src/gowin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,12 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
_jtag->set_state(Jtag::TEST_LOGIC_RESET);
if (_verbose)
displayReadReg("Before disable SPI mode", readStatusReg());
disableCfg();
//disableCfg();
send_command(CONFIG_DISABLE); // BYPASS ?
send_command(0); // BYPASS ?
_jtag->set_state(Jtag::TEST_LOGIC_RESET);
gw5a_disable_spi();
idCode();
}
}

Expand Down Expand Up @@ -224,6 +226,7 @@ bool Gowin::send_command(uint8_t cmd)
{
_jtag->shiftIR(&cmd, nullptr, 8);
_jtag->toggleClk(6);
_jtag->flush();
return true;
}

Expand All @@ -249,6 +252,7 @@ uint32_t Gowin::readReg32(uint8_t cmd)
uint32_t reg = 0, tmp = 0xffffffffU;
send_command(cmd);
_jtag->shiftDR((uint8_t *)&tmp, (uint8_t *)&reg, 32);
_jtag->toggleClk(1);
return le32toh(reg);
}

Expand Down Expand Up @@ -769,6 +773,7 @@ bool Gowin::writeSRAM(const uint8_t *data, int length)
int remains = length;
const uint8_t *ptr = data;
static const unsigned pstep = 524288; // 0x80000, about 0.2 sec of bitstream at 2.5MHz
printf("length : %d\n", length);
while (remains) {
int chunk = pstep;
/* 2.2.6.5 */
Expand Down Expand Up @@ -876,9 +881,18 @@ bool Gowin::eraseFLASH()
void Gowin::sendClkUs(unsigned us)
{
uint64_t clocks = _jtag->getClkFreq();
printf("%d %d ", clocks, us);
clocks *= us;
printf("%lu ", clocks);
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:
Expand All @@ -890,10 +904,12 @@ bool Gowin::eraseSRAM()
if (_verbose)
displayReadReg("before erase sram", readStatusReg());

if (!enableCfg()) {
/*if (!enableCfg()) {
printError("FAIL");
return false;
}
}*/
send_command(0x11);
send_command(CONFIG_ENABLE);
send_command(ERASE_SRAM);
send_command(NOOP);

Expand All @@ -904,23 +920,27 @@ bool Gowin::eraseSRAM()
* this check seems enough
*/
if (_idcode == 0x0001081b) // seems required for GW5AST...
sendClkUs(10000);
if (pollFlag(STATUS_MEMORY_ERASE, STATUS_MEMORY_ERASE)) {
if (_verbose)
displayReadReg("after erase sram", readStatusReg());
} else {
printError("FAIL");
return false;
sendClkUs(750*9);
else {
if (pollFlag(STATUS_MEMORY_ERASE, STATUS_MEMORY_ERASE)) {
if (_verbose)
displayReadReg("after erase sram", readStatusReg());
} else {
printError("FAIL");
return false;
}
}

send_command(XFER_DONE);
send_command(NOOP);
if (!disableCfg()) {
send_command(CONFIG_DISABLE);
send_command(NOOP);
/*if (!disableCfg()) {
printError("FAIL");
return false;
}
}*/

if (_mode == Device::FLASH_MODE) {
/*if (_mode == Device::FLASH_MODE) {
uint32_t status_reg = readStatusReg();
if (_verbose)
displayReadReg("after erase sram", status_reg);
Expand All @@ -930,7 +950,7 @@ bool Gowin::eraseSRAM()
} else {
printSuccess("DONE");
}
}
}*/
return true;
}

Expand Down Expand Up @@ -1149,13 +1169,19 @@ bool Gowin::dumpFlash(uint32_t base_addr, uint32_t len)
bool Gowin::prepare_flash_access()
{
_jtag->setClkFreq(10000000);
//_jtag->setClkFreq(2500000);

if (!eraseSRAM()) {
printError("Error: fail to erase SRAM");
return false;
}

if (is_gw5a) {
if (!eraseSRAM()) {
printError("Error: fail to erase SRAM");
return false;
}
displayReadReg("toto", readStatusReg());
if (!gw5a_enable_spi()) {
printError("Error: fail to switch GW5A to SPI mode");
return false;
Expand Down Expand Up @@ -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))
return -1;
// set TMS/CS high by moving to a state where TMS == 1
_jtag->set_state(Jtag::TEST_LOGIC_RESET, curr_tdi);
_jtag->toggleClk(5); // Required ?
_jtag->flushTMS(true);
//_jtag->set_state(Jtag::TEST_LOGIC_RESET, 0/*curr_tdi*/);
_jtag->set_state(Jtag::SELECT_DR_SCAN, 0/*curr_tdi*/);
_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.
for (uint32_t i = 0; i < len; i++)
rx[i] = FsParser::reverseByte((jrx[i] >> 3) |
Expand All @@ -1255,6 +1286,7 @@ int Gowin::spi_wait_gw5a(uint8_t cmd, uint8_t mask, uint8_t cond,
}

count++;
//printf("%x %x %x %u\n", tmp, mask, cond, count);
if (count == timeout) {
printf("timeout: %x\n", tmp);
break;
Expand All @@ -1269,21 +1301,31 @@ int Gowin::spi_wait_gw5a(uint8_t cmd, uint8_t mask, uint8_t cond,

bool Gowin::gw5a_enable_spi()
{
enableCfg();
uint8_t dummy[625];
memset(dummy, 0, 625);
//enableCfg();
send_command(0x15);
send_command(0x3F);
disableCfg();
send_command(0x3A);
//disableCfg();
if (_verbose)
displayReadReg("toto", readStatusReg());

/* UG704 3.4.3 'ExtFlash Programming -> Program External Flash via JTAG-SPI' */
send_command(NOOP);
send_command(0x11);
send_command(0x02);
_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);
send_command(0x16);
send_command(0x00);
_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);
/* save current read/write edge cfg before switching to SPI mode0
* (rising edge: read / falling edge: write)
Expand Down Expand Up @@ -1327,5 +1369,6 @@ bool Gowin::gw5a_disable_spi()
// 2. 8 TCK clock cycle with TMS=1
_jtag->set_state(Jtag::TEST_LOGIC_RESET); // 5 cycles
_jtag->toggleClk(5);
idCode();
return true;
}
4 changes: 2 additions & 2 deletions src/jtag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Jtag::Jtag(const cable_t &cable, const jtag_pins_conf_t *pin_conf,
_tms_buffer_size(128), _num_tms(0),
_board_name("nope"), _user_misc_devs(user_misc_devs),
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) {
case MODE_ANLOGICCABLE:
Expand Down Expand Up @@ -347,7 +347,7 @@ void Jtag::go_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);
_jtag->writeTDI(tdi, tdo, len, last);
Expand Down
4 changes: 2 additions & 2 deletions src/jtag.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ class Jtag {
tapState_t end_state = RUN_TEST_IDLE);
int shiftDR(const uint8_t *tdi, unsigned char *tdo, int drlen,
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 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);
void flush() {flushTMS(); _jtag->flush();}
void setTMS(unsigned char tms);
Expand Down
51 changes: 51 additions & 0 deletions src/spiFlash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,57 @@ int SPIFlash::erase_and_prog(int base_addr, const uint8_t *data, int len)
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,
const int &len, int rd_burst)
{
Expand Down
1 change: 1 addition & 0 deletions src/spiFlash.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class SPIFlash {
const int &len, int rd_burst = 0);
/* combo flash + erase */
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
* data content
Expand Down

0 comments on commit a58f946

Please sign in to comment.