lattice: added SPI Flash access support for ECP3 family
This commit is contained in:
parent
b76840b20d
commit
432cdc2dd7
|
|
@ -183,7 +183,7 @@ Lattice:
|
||||||
Model: LFE3-70E
|
Model: LFE3-70E
|
||||||
URL: https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP3
|
URL: https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP3
|
||||||
Memory: OK
|
Memory: OK
|
||||||
Flash: TBD
|
Flash: OK
|
||||||
|
|
||||||
- Description: ECP5
|
- Description: ECP5
|
||||||
Model:
|
Model:
|
||||||
|
|
|
||||||
|
|
@ -746,6 +746,11 @@ bool Lattice::prepare_flash_access()
|
||||||
/* clear SRAM before SPI access */
|
/* clear SRAM before SPI access */
|
||||||
if (!clearSRAM())
|
if (!clearSRAM())
|
||||||
return false;
|
return false;
|
||||||
|
if (_fpga_family == ECP3_FAMILY) {
|
||||||
|
if (!wr_rd(0x3A, 0, 0, 0, 0, false))
|
||||||
|
return false;
|
||||||
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
||||||
|
} else {
|
||||||
/*IR = 0h3A, DR=0hFE,0h68. Enter RUNTESTIDLE.
|
/*IR = 0h3A, DR=0hFE,0h68. Enter RUNTESTIDLE.
|
||||||
* thank @GregDavill
|
* thank @GregDavill
|
||||||
* https://twitter.com/GregDavill/status/1251786406441086977
|
* https://twitter.com/GregDavill/status/1251786406441086977
|
||||||
|
|
@ -753,6 +758,7 @@ bool Lattice::prepare_flash_access()
|
||||||
_jtag->shiftIR(0x3A, 8, Jtag::EXIT1_IR);
|
_jtag->shiftIR(0x3A, 8, Jtag::EXIT1_IR);
|
||||||
uint8_t tmp[2] = {0xFE, 0x68};
|
uint8_t tmp[2] = {0xFE, 0x68};
|
||||||
_jtag->shiftDR(tmp, NULL, 16);
|
_jtag->shiftDR(tmp, NULL, 16);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -763,6 +769,10 @@ bool Lattice::post_flash_access()
|
||||||
printInfo("Skip resetting device");
|
printInfo("Skip resetting device");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (_fpga_family == ECP3_FAMILY) {
|
||||||
|
_jtag->shiftIR(0xFF, 8, Jtag::RUN_TEST_IDLE);
|
||||||
|
_jtag->shiftIR(0x23, 8, Jtag::RUN_TEST_IDLE);
|
||||||
|
} else {
|
||||||
/* ISC REFRESH 0x79 */
|
/* ISC REFRESH 0x79 */
|
||||||
if (loadConfiguration() == false) {
|
if (loadConfiguration() == false) {
|
||||||
/* when flash is blank status displays failure:
|
/* when flash is blank status displays failure:
|
||||||
|
|
@ -802,11 +812,12 @@ bool Lattice::post_flash_access()
|
||||||
/* bypass */
|
/* bypass */
|
||||||
wr_rd(0xff, NULL, 0, NULL, 0);
|
wr_rd(0xff, NULL, 0, NULL, 0);
|
||||||
_jtag->go_test_logic_reset();
|
_jtag->go_test_logic_reset();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void Lattice::reset()
|
void Lattice::reset()
|
||||||
{
|
{
|
||||||
if (_fpga_family == ECP5_FAMILY)
|
if (_fpga_family == ECP5_FAMILY || _fpga_family == ECP3_FAMILY)
|
||||||
post_flash_access();
|
post_flash_access();
|
||||||
else
|
else
|
||||||
printError("Lattice Reset only tested on ECP5 Family.");
|
printError("Lattice Reset only tested on ECP5 Family.");
|
||||||
|
|
@ -1670,10 +1681,14 @@ uint16_t Lattice::getUFMStartPageFromJEDEC(JedParser *_jed, int id)
|
||||||
|
|
||||||
int Lattice::spi_put(uint8_t cmd, const uint8_t *tx, uint8_t *rx, uint32_t len)
|
int Lattice::spi_put(uint8_t cmd, const uint8_t *tx, uint8_t *rx, uint32_t len)
|
||||||
{
|
{
|
||||||
int xfer_len = len + 1;
|
const uint32_t xfer_len = len + 1 + ((rx != NULL) && ((_fpga_family == ECP3_FAMILY)) ? 1 : 0);
|
||||||
|
const uint32_t xfer_bit_len = (len + 1) * 8 + ((rx != NULL) && ((_fpga_family == ECP3_FAMILY)) ? 1 : 0);
|
||||||
uint8_t jtx[xfer_len];
|
uint8_t jtx[xfer_len];
|
||||||
uint8_t jrx[xfer_len];
|
uint8_t jrx[xfer_len];
|
||||||
|
|
||||||
|
memset(jrx, 0, xfer_len);
|
||||||
|
memset(jtx, 0, xfer_len);
|
||||||
|
|
||||||
jtx[0] = LatticeBitParser::reverseByte(cmd);
|
jtx[0] = LatticeBitParser::reverseByte(cmd);
|
||||||
|
|
||||||
if (tx) {
|
if (tx) {
|
||||||
|
|
@ -1685,12 +1700,19 @@ int Lattice::spi_put(uint8_t cmd, const uint8_t *tx, uint8_t *rx, uint32_t len)
|
||||||
* in the same time store each byte
|
* in the same time store each byte
|
||||||
* to next
|
* to next
|
||||||
*/
|
*/
|
||||||
_jtag->shiftDR(jtx, (rx == NULL)? NULL: jrx, 8*xfer_len);
|
_jtag->shiftDR(jtx, (!rx)? NULL: jrx, xfer_bit_len);
|
||||||
|
|
||||||
if (rx != NULL) {
|
if (rx) {
|
||||||
|
if (_fpga_family == ECP3_FAMILY) {
|
||||||
|
for (uint32_t i = 0; i < len; ++i) {
|
||||||
|
const uint8_t tmp = LatticeBitParser::reverseByte((jrx[i+1] >> 1) & 0x7f);
|
||||||
|
rx[i] = tmp | (jrx[i + 2] & 0x01);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (uint32_t i=0; i < len; i++)
|
for (uint32_t i=0; i < len; i++)
|
||||||
rx[i] = LatticeBitParser::reverseByte(jrx[i+1]);
|
rx[i] = LatticeBitParser::reverseByte(jrx[i+1]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1725,11 +1747,12 @@ int Lattice::spi_put(const uint8_t *tx, uint8_t *rx, uint32_t len)
|
||||||
int Lattice::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
|
int Lattice::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
|
||||||
uint32_t timeout, bool verbose)
|
uint32_t timeout, bool verbose)
|
||||||
{
|
{
|
||||||
uint8_t rx;
|
uint8_t rx[2];
|
||||||
uint8_t dummy[2] = {0xff};
|
uint8_t dummy[2] = {0xff};
|
||||||
uint8_t tmp;
|
uint8_t tmp;
|
||||||
uint8_t tx = LatticeBitParser::reverseByte(cmd);
|
uint8_t tx = LatticeBitParser::reverseByte(cmd);
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
|
uint32_t nb_byte = (_fpga_family == ECP3_FAMILY) ? 2 : 1;
|
||||||
|
|
||||||
/* CS is low until state goes to EXIT1_IR
|
/* CS is low until state goes to EXIT1_IR
|
||||||
* so manually move to state machine to stay is this
|
* so manually move to state machine to stay is this
|
||||||
|
|
@ -1738,11 +1761,14 @@ int Lattice::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
|
||||||
_jtag->shiftDR(&tx, NULL, 8, Jtag::SHIFT_DR);
|
_jtag->shiftDR(&tx, NULL, 8, Jtag::SHIFT_DR);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
_jtag->shiftDR(dummy, &rx, 8, Jtag::SHIFT_DR);
|
_jtag->shiftDR(dummy, rx, 8 * nb_byte, Jtag::SHIFT_DR);
|
||||||
tmp = (LatticeBitParser::reverseByte(rx));
|
if (_fpga_family == ECP3_FAMILY)
|
||||||
|
tmp = LatticeBitParser::reverseByte(rx[0] >> 1) | (rx[1] & 0x01);
|
||||||
|
else
|
||||||
|
tmp = (LatticeBitParser::reverseByte(rx[0]));
|
||||||
count++;
|
count++;
|
||||||
if (count == timeout){
|
if (count == timeout){
|
||||||
printf("timeout: %x %x %u\n", tmp, rx, count);
|
printf("timeout: %x %x %u\n", tmp, rx[0], count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1750,7 +1776,7 @@ int Lattice::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
|
||||||
printf("%x %x %x %u\n", tmp, mask, cond, count);
|
printf("%x %x %x %u\n", tmp, mask, cond, count);
|
||||||
}
|
}
|
||||||
} while ((tmp & mask) != cond);
|
} while ((tmp & mask) != cond);
|
||||||
_jtag->shiftDR(dummy, &rx, 8, Jtag::RUN_TEST_IDLE);
|
_jtag->shiftDR(dummy, rx, 8, Jtag::RUN_TEST_IDLE);
|
||||||
if (count == timeout) {
|
if (count == timeout) {
|
||||||
printf("%x\n", tmp);
|
printf("%x\n", tmp);
|
||||||
std::cout << "wait: Error" << std::endl;
|
std::cout << "wait: Error" << std::endl;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue