Skip to content

Commit

Permalink
gowin: TODO
Browse files Browse the repository at this point in the history
  • Loading branch information
trabucayre committed Oct 31, 2023
1 parent f66f945 commit f26e90f
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 54 deletions.
232 changes: 178 additions & 54 deletions src/gowin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,19 @@ using namespace std;
Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::string mcufw,
Device::prog_type_t prg_type, bool external_flash,
bool verify, int8_t verbose): Device(jtag, filename, file_type,
verify, verbose), is_gw1n1(false), is_gw2a(false), is_gw1n4(false), is_gw5a(false),
_external_flash(external_flash),
verify, verbose), _idcode(0), is_gw1n1(false), is_gw2a(false),
is_gw1n4(false), is_gw5a(false), _external_flash(external_flash),
_spi_sck(BSCAN_SPI_SCK), _spi_cs(BSCAN_SPI_CS),
_spi_di(BSCAN_SPI_DI), _spi_do(BSCAN_SPI_DO),
_spi_msk(BSCAN_SPI_MSK)
{
_fs = NULL;
_mcufw = NULL;

uint32_t idcode = _jtag->get_target_device_id();
detectFamily();

_prev_wr_edge = _jtag->getWriteEdge();
_prev_rd_edge = _jtag->getReadEdge();

if (prg_type == Device::WR_FLASH)
_mode = Device::FLASH_MODE;
Expand All @@ -102,8 +105,10 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
throw std::runtime_error(e.what());
}
} else {
printf("external_flash %d\n", _external_flash);

/* non fs file is only allowed with external flash */
if (!external_flash)
if (!_external_flash)
throw std::runtime_error("incompatible file format");
try {
_fs = new RawParser(_filename, false);
Expand All @@ -128,24 +133,71 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
if (_file_extension == "fs") {
string idcode_str = _fs->getHeaderVal("idcode");
uint32_t fs_idcode = std::stoul(idcode_str.c_str(), NULL, 16);
if ((fs_idcode & 0x0fffffff) != idcode) {
if ((fs_idcode & 0x0fffffff) != _idcode) {
char mess[256];
snprintf(mess, 256, "mismatch between target's idcode and bitstream idcode\n"
"\tbitstream has 0x%08X hardware requires 0x%08x", fs_idcode, idcode);
"\tbitstream has 0x%08X hardware requires 0x%08x", fs_idcode, _idcode);
throw std::runtime_error(mess);
}
}
}

if (mcufw.size() > 0) {
if (_idcode != 0x0100981b)
throw std::runtime_error("Microcontroller firmware flashing only supported on GW1NSR-4C");

_mcufw = new RawParser(mcufw, false);

if (_mcufw->parse() == EXIT_FAILURE) {
printError("FAIL");
delete _mcufw;
throw std::runtime_error("can't parse file");
} else {
printSuccess("DONE");
}
}

if (is_gw5a) {
_jtag->setClkFreq(2500000);
disableCfg();
send_command(0x00); // BYPASS ?
_jtag->set_state(Jtag::TEST_LOGIC_RESET);
uint32_t tmp = readStatusReg();
printf("%08x %08x\n", tmp, tmp & (1 << 17));
displayReadReg("plop", tmp);
if (0) {
//if (readStatusReg() & (1 << 17)) {
printf("try to reboot FPGA\n");
disableCfg();
send_command(0);
_jtag->set_state(Jtag::TEST_LOGIC_RESET);
post_flash_access();
}
}

}

Gowin::~Gowin()
{
if (_fs)
delete _fs;
if (_mcufw)
delete _mcufw;
}

bool Gowin::detectFamily()
{
_idcode = _jtag->get_target_device_id();

/* erase and program flash differ for GW1N1 */
if (idcode == 0x0900281B)
if (_idcode == 0x0900281B)
is_gw1n1 = true;
/* erase and program flash differ for GW1N4, GW1N1Z-1 */
if (idcode == 0x0100381B || idcode == 0x100681b)
if (_idcode == 0x0100381B || _idcode == 0x100681b)
is_gw1n4 = true;

/* bscan spi external flash differ for GW1NSR-4C */
if (idcode == 0x0100981b) {
if (_idcode == 0x0100981b) {
_spi_sck = BSCAN_GW1NSR_4C_SPI_SCK;
_spi_cs = BSCAN_GW1NSR_4C_SPI_CS;
_spi_di = BSCAN_GW1NSR_4C_SPI_DI;
Expand All @@ -157,7 +209,7 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
* GW2 series has no internal flash and uses new bitstream checksum
* algorithm that is not yet supported.
*/
switch (idcode) {
switch (_idcode) {
case 0x0000081b: /* GW2A(R)-18(C) */
case 0x0000281b: /* GW2A(R)-55(C) */
_external_flash = true;
Expand All @@ -175,28 +227,7 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
break;
}

if (mcufw.size() > 0) {
if (idcode != 0x0100981b)
throw std::runtime_error("Microcontroller firmware flashing only supported on GW1NSR-4C");

_mcufw = new RawParser(mcufw, false);

if (_mcufw->parse() == EXIT_FAILURE) {
printError("FAIL");
delete _mcufw;
throw std::runtime_error("can't parse file");
} else {
printSuccess("DONE");
}
}
}

Gowin::~Gowin()
{
if (_fs)
delete _fs;
if (_mcufw)
delete _mcufw;
return true;
}

bool Gowin::send_command(uint8_t cmd)
Expand Down Expand Up @@ -279,6 +310,8 @@ void Gowin::programExtFlash(unsigned int offset, bool unprotect_flash)
{
_jtag->setClkFreq(10000000);

displayReadReg("after program flash", readStatusReg());

if (is_gw5a) {
if (!prepare_flash_access()) {
throw std::runtime_error("Error: fail to switch GW5A to SPI mode");
Expand All @@ -301,22 +334,42 @@ void Gowin::programExtFlash(unsigned int offset, bool unprotect_flash)
const uint8_t *data = _fs->getData();
int length = _fs->getLength();

//if (spiFlash.erase_and_prog(offset, data, length / 8) != 0)
// throw std::runtime_error("Error: write to flash failed");
//if (_verify)
// if (!spiFlash.verify(offset, data, length / 8, 256))
// throw std::runtime_error("Error: flash vefication failed");
char mess[256];
bool ret = true;

if (spiFlash.erase_and_prog(offset, data, length / 8) != 0) {
snprintf(mess, 256, "Error: write to flash failed");
printError(mess);
ret = false;
}
if (ret && _verify)
if (!spiFlash.verify(offset, data, length / 8, 256)) {
snprintf(mess, 256, "Error: flash vefication failed");
printError(mess);
ret = false;
}

if (is_gw5a) {
if (!post_flash_access())
throw std::runtime_error("Error: fail to disable SPI mode");
if (!post_flash_access()) {
snprintf(mess, 256, "Error: fail to disable SPI mode");
printError(mess);
ret = false;
}

} else if (!is_gw2a) {
if (!disableCfg())
throw std::runtime_error("Error: fail to disable configuration");
if (!disableCfg()) {
snprintf(mess, 256, "Error: fail to disable configuration");
printError(mess);
ret = false;
}
}

reset();
if (!is_gw5a)
reset();

if (!ret) {
throw std::runtime_error(mess);
}
}

void Gowin::programSRAM()
Expand Down Expand Up @@ -427,10 +480,63 @@ void Gowin::displayReadReg(const char *prefix, uint32_t reg)
"Gowin VLD", "Done Final", "Security Final", "Ready",
"POR", "FLASH lock", "FLASH2 lock",
};

static const char *gw5a_desc[32] = {
"CRC Error", "Bad Command", "ID Verify Failed", "Timeout",
"auto_boot_2nd_fail", "Memory Erase", "Preamble", "System Edit Mode",
"Program SPI FLASH directly", "auto_boot_1st_fail",
"Non-JTAG configuration is active", "Bypass", "i2c_sram_f",
"Done Final", "Security Final", "encrypted_format",
"key_right", "sspi_mode", "CRC Comparison Done", "CRC Error",
"ECC Error", "ECC Error Uncorrectable", "CMSER IDLE",
"CPU Bus Width", "", "Retry time sync pattern detect", "",
"Decompression Failed", "OTP Reading Done", "Init Done",
"Wakeup Done", "Auto Erase",
};

/* Bits 26:25 */
static const char *gw5a_sync_det_retry[4] = {
"no retry",
"retry one time",
"retry two times",
"no \"sync pattern\" is found after three times detection",
};

/* Bits 24:23 */
static const char *gw5a_cpu_bus_width[4] = {
"no BWD pattern is detected",
"8-bit mode",
"16-bit mode",
"32-bit mode",
};

printf("%s: displayReadReg %08x\n", prefix, reg);
for (unsigned i = 0, bm = 1; i < 19; ++i, bm <<= 1) {
if (reg & bm) {
printf("\t%s\n", desc[i]);

if (_idcode == 0x0001281b) {
for (unsigned i = 0, bm = 1; i < 32; ++i, bm <<= 1) {
switch (i) {
case 23:
printf("\t[%d:%d] %s: %s\n", i + 1, i, gw5a_desc[i],
gw5a_cpu_bus_width[(reg >> i)&0x3]);
bm++;
i++;
break;
case 25:
printf("\t[%d:%d] %s: %s\n", i + 1, i, gw5a_desc[i],
gw5a_sync_det_retry[(reg >> i)&0x3]);
bm++;
i++;
break;
default:
if (reg & bm)
printf("\t [%2d] %s\n", i, gw5a_desc[i]);
}
}
} else {
for (unsigned i = 0, bm = 1; i < 19; ++i, bm <<= 1) {
if (reg & bm) {
printf("\t%s\n", gw5a_desc[i]);
}
}
}
}
Expand Down Expand Up @@ -1012,12 +1118,23 @@ bool Gowin::prepare_flash_access()
eraseSRAM();
//wr_rd(XFER_DONE, NULL, 0, NULL, 0);
//wr_rd(NOOP, NULL, 0, NULL, 0);

enableCfg();
send_command(0x3F);
disableCfg();
displayReadReg("toto", readStatusReg());
printf("%08x\n", idCode());

/* UG704 3.4.3 'ExtFlash Programming -> Program External Flash via JTAG-SPI' */
//DisableCfg();
//wr_rd(NOOP, NULL, 0, NULL, 0);
send_command(NOOP);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(126*8);
_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->set_state(Jtag::TEST_LOGIC_RESET);
/* save current read/write edge cfg before switching to SPI mode0
* (rising edge: read / falling edge: write)
Expand All @@ -1040,25 +1157,32 @@ bool Gowin::post_flash_access()
*/
_jtag->setWriteEdge(_prev_wr_edge);
_jtag->setReadEdge(_prev_rd_edge);
//_jtag->setEndianness(JtagInterface::ENDIAN_LSB);
_jtag->flushTMS(true);
_jtag->flush();
// 1. sent 15 TMS pulse
// TEST_LOGIC_RESET to EXIT2_DR: 010101 6 pulses
// TEST_LOGIC_RESET to SELECT_DR_SCAN: 01
_jtag->set_state(Jtag::SELECT_DR_SCAN);
// SELECT_DR_SCAN to CAPTURE_DR: 0
_jtag->set_state(Jtag::CAPTURE_DR);
// EXIT2_DR to PAUSE_DR: 010 3 pulses
_jtag->set_state(Jtag::PAUSE_DR);
// PAUSE_DR to EXIT1_DR: 101 3 pulses
// CAPTURE_DR to EXIT1_DR: 1
_jtag->set_state(Jtag::EXIT1_DR);
// EXIT1_DR to SHIFT_DR: 010 3 pulses
_jtag->set_state(Jtag::SHIFT_DR);
// SHIFT_DR to EXIT2_DR: 101 3 pulses
// EXIT1_DR to EXIT2_DR: 01
_jtag->set_state(Jtag::EXIT2_DR);
// Now we have 3 pulses
for (int i = 0; i < 6; i++) { // 2 each loop: 12 pulses + 3 before
_jtag->set_state(Jtag::PAUSE_DR); // 010
_jtag->set_state(Jtag::EXIT2_DR); // 1
}
_jtag->set_state(Jtag::EXIT1_DR); // 01 : 16
_jtag->set_state(Jtag::PAUSE_DR); // 0

_jtag->flushTMS(true);
_jtag->flush();
// 2. 8 TCK clock cycle with TMS=1
_jtag->set_state(Jtag::TEST_LOGIC_RESET); // 5 cycles
_jtag->toggleClk(5);

reset();

return true;
}
4 changes: 4 additions & 0 deletions src/gowin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class Gowin: public Device, SPIInterface {
bool unprotect_flash() override {
printError("unprotect flash not supported"); return false;}
bool bulk_erase_flash() override {
if (is_gw5a)
return SPIInterface::bulk_erase_flash();
printError("bulk erase flash not supported"); return false;}
virtual bool dumpFlash(uint32_t base_addr, uint32_t len) override;
int spi_put(uint8_t cmd, const uint8_t *tx, uint8_t *rx,
Expand All @@ -60,6 +62,7 @@ class Gowin: public Device, SPIInterface {
virtual bool post_flash_access() override;

private:
bool detectFamily();
bool send_command(uint8_t cmd);
void spi_gowin_write(const uint8_t *wr, uint8_t *rd, unsigned len);
uint32_t readReg32(uint8_t cmd);
Expand All @@ -83,6 +86,7 @@ class Gowin: public Device, SPIInterface {
*/
void checkCRC();
ConfigBitstreamParser *_fs;
uint32_t _idcode;
bool is_gw1n1;
bool is_gw2a;
bool is_gw1n4;
Expand Down

0 comments on commit f26e90f

Please sign in to comment.