anlogic: add SPI flash support

This commit is contained in:
Gwenhael Goavec-Merou 2020-08-24 08:54:45 +02:00
parent bfd7e9b6ed
commit 3349e65079
2 changed files with 161 additions and 13 deletions

View File

@ -21,6 +21,7 @@
#include "jtag.hpp"
#include "device.hpp"
#include "progressBar.hpp"
#include "spiFlash.hpp"
#define REFRESH 0x01
#define IDCODE 0x06
@ -32,13 +33,19 @@
#define IRLENGTH 8
Anlogic::Anlogic(Jtag *jtag, const std::string &filename, bool verbose):
Anlogic::Anlogic(Jtag *jtag, const std::string &filename,
bool flash_wr, bool sram_wr, bool verbose):
Device(jtag, filename, verbose), _svf(_jtag, _verbose)
{
if (_filename != "") {
if (_file_extension == "svf" || _file_extension == "bit")
if (_file_extension == "svf")
_mode = Device::MEM_MODE;
else
else if (_file_extension == "bit") {
if (sram_wr)
_mode = Device::MEM_MODE;
else
_mode = Device::SPI_MODE;
} else
throw std::exception();
}
}
@ -58,13 +65,57 @@ void Anlogic::program(unsigned int offset)
{
if (_mode == Device::NONE_MODE)
return;
if (_mode == Device::MEM_MODE) {
if (_file_extension == "svf") {
_svf.parse(_filename);
return;
if (_file_extension == "svf") {
_svf.parse(_filename);
return;
}
AnlogicBitParser bit(_filename, (_mode == Device::MEM_MODE), _verbose);
bit.parse();
uint8_t *data = bit.getData();
int len = bit.getLength() / 8;
if (_mode == Device::SPI_MODE) {
SPIFlash flash(this, _verbose);
for (int i = 0; i < 5; i++)
_jtag->shiftIR(BYPASS, IRLENGTH);
//Verify Device id.
//SIR 8 TDI (06) ;
//SDR 32 TDI (00000000) TDO (0a014c35) MASK (ffffffff) ;
//Boundary Scan Chain Contents
//Position 1: BG256
//Loading device with 'refresh' instruction.
_jtag->shiftIR(REFRESH, IRLENGTH);
//Loading device with 'bypass' & 'spi_program' instruction.
_jtag->shiftIR(BYPASS, IRLENGTH);
_jtag->shiftIR(SPI_PROGRAM, IRLENGTH);
for (int i = 0; i < 4; i++)
_jtag->toggleClk(50000);
flash.reset();
flash.read_id();
flash.read_status_reg();
flash.erase_and_prog(offset, data, len);
//Loading device with 'bypass' instruction.
_jtag->shiftIR(BYPASS, IRLENGTH);
////Loading device with 'refresh' instruction.
_jtag->shiftIR(REFRESH, IRLENGTH);
_jtag->toggleClk(20);
////Loading device with 'bypass' instruction.
for (int i = 0; i < 4; i++) {
_jtag->shiftIR(BYPASS, IRLENGTH);
_jtag->toggleClk(20);
}
AnlogicBitParser bit(_filename, _verbose);
bit.parse();
_jtag->shiftIR(BYPASS, IRLENGTH);
_jtag->toggleClk(10000);
return;
}
if (_mode == Device::MEM_MODE) {
// Loading device with 'bypass' instruction.
_jtag->shiftIR(BYPASS, IRLENGTH);
@ -87,8 +138,6 @@ void Anlogic::program(unsigned int offset)
_jtag->shiftIR(CFG_IN, IRLENGTH);
_jtag->toggleClk(15);
uint8_t *data = bit.getData();
int len = bit.getLength() / 8;
_jtag->set_state(Jtag::SHIFT_DR);
ProgressBar progress("Loading", len, 50);
int pos = 0;
@ -136,3 +185,93 @@ int Anlogic::idCode()
((rx_data[2] << 16) & 0x00ff0000) |
((rx_data[3] << 24) & 0xff000000));
}
/* SPI wrapper
* For read operation a delay of one bit is added
* So add one bit more and move everything by one
* In write only operations to care about this delay
*/
int Anlogic::spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint32_t len)
{
int xfer_len = len + 1;
if (rx)
xfer_len++;
uint8_t jtx[xfer_len];
uint8_t jrx[xfer_len];
jtx[0] = AnlogicBitParser::reverseByte(cmd);
if (tx != NULL) {
for (int i = 0; i < len; i++)
jtx[i+1] = AnlogicBitParser::reverseByte(tx[i]);
}
/* write anlogic command before sending packet */
uint8_t op = 0x60;
_jtag->shiftDR(&op, NULL, 8);
_jtag->shiftDR(jtx, (rx == NULL)? NULL: jrx, 8*xfer_len);
if (rx != NULL) {
for (int i=0; i < len; i++)
rx[i] = AnlogicBitParser::reverseByte(jrx[i+1]>>1)
| (jrx[i+2]&0x01);
}
return 0;
}
int Anlogic::spi_put(uint8_t *tx, uint8_t *rx, uint32_t len)
{
int xfer_len = len;
if (rx)
xfer_len++;
uint8_t jtx[xfer_len];
uint8_t jrx[xfer_len];
if (tx != NULL) {
for (int i = 0; i < len; i++)
jtx[i] = AnlogicBitParser::reverseByte(tx[i]);
}
/* write anlogic command before sending packet */
uint8_t op = 0x60;
_jtag->shiftDR(&op, NULL, 8);
_jtag->shiftDR(jtx, (rx == NULL)? NULL: jrx, 8*xfer_len);
if (rx != NULL) {
for (int i=0; i < len; i++)
rx[i] = AnlogicBitParser::reverseByte(jrx[i]>>1) |
(jrx[i+1]&0x01);
}
return 0;
}
int Anlogic::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
uint32_t timeout, bool verbose)
{
uint8_t rx[3];
uint8_t tx[3];
tx[0] = AnlogicBitParser::reverseByte(cmd);
uint8_t op = 0x60;
uint8_t tmp;
uint32_t count = 0;
do {
_jtag->shiftDR(&op, NULL, 8);
_jtag->shiftDR(tx, rx, 8 * 3);
tmp = (AnlogicBitParser::reverseByte(rx[1]>>1)) | (0x01 & rx[2]);
count ++;
if (count == timeout) {
printf("timeout: %x %x %x\n", tmp, rx[0], rx[1]);
break;
}
if (verbose) {
printf("%x %x %x %u\n", tmp, mask, cond, count);
}
} while ((tmp & mask) != cond);
if (count == timeout) {
printf("%02x\n", tmp);
std::cout << "wait: Error" << std::endl;
return -ETIME;
}
return 0;
}

View File

@ -23,16 +23,25 @@
#include "bitparser.hpp"
#include "device.hpp"
#include "jtag.hpp"
#include "spiInterface.hpp"
#include "svf_jtag.hpp"
class Anlogic: public Device {
class Anlogic: public Device, SPIInterface {
public:
Anlogic(Jtag *jtag, const std::string &filename, bool verbose);
Anlogic(Jtag *jtag, const std::string &filename,
bool flash_wr, bool sram_wr, bool verbose);
~Anlogic();
void program(unsigned int offset = 0) override;
int idCode() override;
void reset() override;
/* spi interface */
int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx,
uint32_t len) override;
int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override;
int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
uint32_t timeout, bool verbose=false) override;
private:
SVF_jtag _svf;
};