gowin: try again to fix gw5ast flash write
This commit is contained in:
parent
cd40de37cb
commit
a58f946ed5
|
|
@ -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 *)®, 32);
|
_jtag->shiftDR((uint8_t *)&tmp, (uint8_t *)®, 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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue