altera: added sectors erase and UFM write
- updated max10_mem_t to have sectors erase addresses - updated max10_flow_erase to perform a full erase or sectors per sectors - added a dedicated method to perform UFM erase and write without full internal flash erase and with arbitrary file instead of POF
This commit is contained in:
parent
703af08c91
commit
1abb1c2453
158
src/altera.cpp
158
src/altera.cpp
|
|
@ -38,6 +38,15 @@ Altera::Altera(Jtag *jtag, const std::string &filename,
|
|||
_device_package(device_package), _spiOverJtagPath(spiOverJtagPath),
|
||||
_vir_addr(0x1000), _vir_length(14), _clk_period(1)
|
||||
{
|
||||
/* check device family */
|
||||
_idcode = _jtag->get_target_device_id();
|
||||
string family = fpga_list[_idcode].family;
|
||||
if (family == "MAX 10") {
|
||||
_fpga_family = MAX10_FAMILY;
|
||||
} else {
|
||||
_fpga_family = CYCLONE_MISC; // FIXME
|
||||
}
|
||||
|
||||
if (prg_type == Device::RD_FLASH) {
|
||||
_mode = Device::READ_MODE;
|
||||
} else {
|
||||
|
|
@ -52,6 +61,8 @@ Altera::Altera(Jtag *jtag, const std::string &filename,
|
|||
_mode = Device::SPI_MODE;
|
||||
} else if (_file_extension == "pof") { // MAX10
|
||||
_mode = Device::FLASH_MODE;
|
||||
} else if (_fpga_family == MAX10_FAMILY) {
|
||||
_mode = Device::FLASH_MODE;
|
||||
} else { // unknown type -> sanity check
|
||||
if (prg_type == Device::WR_SRAM) {
|
||||
printError("file has an unknown type:");
|
||||
|
|
@ -65,15 +76,6 @@ Altera::Altera(Jtag *jtag, const std::string &filename,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check device family */
|
||||
_idcode = _jtag->get_target_device_id();
|
||||
string family = fpga_list[_idcode].family;
|
||||
if (family == "MAX 10") {
|
||||
_fpga_family = MAX10_FAMILY;
|
||||
} else {
|
||||
_fpga_family = CYCLONE_MISC; // FIXME
|
||||
}
|
||||
}
|
||||
|
||||
Altera::~Altera()
|
||||
|
|
@ -235,7 +237,7 @@ void Altera::program(unsigned int offset, bool unprotect_flash)
|
|||
|
||||
/* Specific case for MAX10 */
|
||||
if (_fpga_family == MAX10_FAMILY) {
|
||||
max10_program();
|
||||
max10_program(offset);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -296,41 +298,101 @@ uint32_t Altera::idCode()
|
|||
#define MAX10_ISC_ENABLE {0xcc, 0x02}
|
||||
#define MAX10_ISC_DISABLE {0x01, 0x02}
|
||||
#define MAX10_ISC_ADDRESS_SHIFT {0x03, 0x02}
|
||||
#define MAX10_ISC_ERASE {0xf2, 0x02}
|
||||
#define MAX10_ISC_PROGRAM {0xf4, 0x02}
|
||||
#define MAX10_DSM_ICB_PROGRAM {0xF4, 0x03}
|
||||
#define MAX10_DSM_VERIFY {0x07, 0x03}
|
||||
#define MAX10_DSM_CLEAR {0xf2, 0x03}
|
||||
#define MAX10_BYPASS {0xFF, 0x03}
|
||||
|
||||
typedef struct {
|
||||
struct Altera::max10_mem_t {
|
||||
uint32_t check_addr0; // something to check before sequence
|
||||
uint32_t dsm_addr;
|
||||
uint32_t dsm_len; // 32bits
|
||||
uint32_t ufm_addr; // UFM1 addr
|
||||
uint32_t ufm_len[2];
|
||||
uint32_t ufm_len[2]; // 32bits
|
||||
uint32_t cfm_addr; // CFM2 addr
|
||||
uint32_t cfm_len[3];
|
||||
uint32_t cfm_len[3]; // 32bits
|
||||
uint32_t sectors_erase_addr[5]; // UFM1, UFM0, CFM2, CFM1, CFM0
|
||||
uint32_t done_bit_addr;
|
||||
uint32_t pgm_success_addr;
|
||||
} max10_mem_t;
|
||||
};
|
||||
|
||||
static const std::map<uint32_t, max10_mem_t> max10_memory_map = {
|
||||
{0x031820dd, {
|
||||
0x80005, // check_addr0
|
||||
0x0000, 512, // DSM
|
||||
0x0200, {4096, 4096}, // UFM
|
||||
0x2200, {35840, 14848, 20992}, // CFM
|
||||
0x0009, // done bit
|
||||
0x000b} // program success addr
|
||||
const std::map<uint32_t, Altera::max10_mem_t> Altera::max10_memory_map = {
|
||||
{0x031820dd, { // 10M08SAU
|
||||
.check_addr0 = 0x80005, // check_addr0
|
||||
.dsm_addr = 0x0000, 512, // DSM
|
||||
.ufm_addr = 0x0200, .ufm_len = {4096, 4096}, // UFM
|
||||
.cfm_addr = 0x2200, .cfm_len = {35840, 14848, 20992}, // CFM
|
||||
.sectors_erase_addr = {0x17ffff, 0x27ffff, 0x37ffff, 0x47ffff, 0x57ffff}, // sectors erase address
|
||||
.done_bit_addr = 0x0009, // done bit
|
||||
.pgm_success_addr = 0x000b} // program success addr
|
||||
},
|
||||
};
|
||||
|
||||
void Altera::max10_program()
|
||||
/* Write an arbitrary file in UFM1 and UFM0
|
||||
* FIXME: in some mode its also possible to uses CFM2 & CFM1
|
||||
*/
|
||||
bool Altera::max10_program_ufm(const Altera::max10_mem_t *mem, unsigned int offset)
|
||||
{
|
||||
POFParser _bit(_filename, _verbose);
|
||||
RawParser _bit(_filename, true);
|
||||
_bit.parse();
|
||||
_bit.displayHeader();
|
||||
const uint8_t *data = _bit.getData();
|
||||
const uint32_t length = _bit.getLength() / 8;
|
||||
const uint32_t base_addr = mem->ufm_addr + offset;
|
||||
|
||||
uint8_t *buff = (uint8_t *)malloc(length);
|
||||
if (!buff) {
|
||||
printError("max10_program_ufm: Failed to allocate buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* check */
|
||||
const uint32_t ufmx_len = 4 * (mem->ufm_len[0] + mem->ufm_len[1]);
|
||||
if (base_addr > length) {
|
||||
printError("Error: start offset is out of UFM region");
|
||||
return false;
|
||||
}
|
||||
if (base_addr + length > ufmx_len) {
|
||||
printError("Error: end address is out of UFM region");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* data needs to be re-ordered */
|
||||
for (uint32_t i = 0; i < length; i+=4) {
|
||||
for (int b = 0; b < 4; b++) {
|
||||
buff[i + b] = data[i + (3-b)];
|
||||
}
|
||||
}
|
||||
|
||||
// Start!
|
||||
max10_flow_enable();
|
||||
|
||||
/* Erase UFM1 & UFM0 */
|
||||
printInfo("Erase UFM ", false);
|
||||
max10_flow_erase(mem, 0x3);
|
||||
printInfo("Done");
|
||||
|
||||
/* Program UFM1 & UFM0 */
|
||||
// Simplify code:
|
||||
// UFM0 follows UFM1, so we don't need to iterate
|
||||
printInfo("Write UFM");
|
||||
writeXFM(buff, base_addr, 0, length / 4);
|
||||
|
||||
/* Verify */
|
||||
if (_verify)
|
||||
verifyxFM(buff, base_addr, 0, length / 4);
|
||||
|
||||
max10_flow_disable();
|
||||
|
||||
free(buff);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Altera::max10_program(unsigned int offset)
|
||||
{
|
||||
uint32_t base_addr;
|
||||
|
||||
/* Needs to have some specifics informations about internal flash size/organisation
|
||||
|
|
@ -341,7 +403,16 @@ void Altera::max10_program()
|
|||
printError("Model not supported. Please update max10_memory_map.");
|
||||
throw std::runtime_error("Model not supported. Please update max10_memory_map.");
|
||||
}
|
||||
const max10_mem_t mem = mem_map->second;
|
||||
const Altera::max10_mem_t mem = mem_map->second;
|
||||
|
||||
if (_file_extension != "pof") {
|
||||
max10_program_ufm(&mem, offset);
|
||||
return;
|
||||
}
|
||||
|
||||
POFParser _bit(_filename, _verbose);
|
||||
_bit.parse();
|
||||
_bit.displayHeader();
|
||||
|
||||
/*
|
||||
* MAX10 memory map differs according to internal configuration mode
|
||||
|
|
@ -402,7 +473,7 @@ void Altera::max10_program()
|
|||
// Start!
|
||||
max10_flow_enable();
|
||||
|
||||
max10_flow_erase();
|
||||
max10_flow_erase(&mem, 0x1F);
|
||||
max10_dsm_verify();
|
||||
|
||||
/* Write */
|
||||
|
|
@ -464,16 +535,39 @@ static void word_to_array(uint32_t in, uint8_t *out) {
|
|||
out[3] = (in >> 24) & 0xff;
|
||||
}
|
||||
|
||||
void Altera::max10_flow_erase()
|
||||
/* Two possibilities:
|
||||
* - full internal flash must be erased (to write a POF file): DSM_CLEAR must be used to
|
||||
* perform a full erase
|
||||
* - only a sub-set of sectors must be erased (to update a CPU firmware): only specified
|
||||
* sectors have to be erased using MAX10_ISC_ERASE instruction after moving to a specific
|
||||
* erase address
|
||||
*/
|
||||
void Altera::max10_flow_erase(const Altera::max10_mem_t *mem, const uint8_t erase_sectors)
|
||||
{
|
||||
const uint32_t dsm_clear_delay = 350000120 / _clk_period;
|
||||
const uint8_t dsm_clear[2] = MAX10_DSM_CLEAR;
|
||||
/* All sectors must be erased: DSM_CLEAR is better/faster */
|
||||
if (erase_sectors == 0x1f) {
|
||||
const uint8_t dsm_clear[2] = MAX10_DSM_CLEAR;
|
||||
|
||||
max10_addr_shift(0x000000);
|
||||
max10_addr_shift(0x000000);
|
||||
|
||||
_jtag->shiftIR((unsigned char *)dsm_clear, NULL, IRLENGTH);
|
||||
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
||||
_jtag->toggleClk(dsm_clear_delay);
|
||||
_jtag->shiftIR((unsigned char *)dsm_clear, NULL, IRLENGTH);
|
||||
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
||||
_jtag->toggleClk(dsm_clear_delay);
|
||||
} else {
|
||||
//const uint32_t isc_clear_delay = 5120 / _clk_period;
|
||||
const uint8_t isc_erase[2] = MAX10_ISC_ERASE;
|
||||
|
||||
/* each bit is a sector to erase */
|
||||
for (int sect = 0; sect < 5; sect++) {
|
||||
if ((erase_sectors >> sect) & 0x01) {
|
||||
max10_addr_shift(mem->sectors_erase_addr[sect]);
|
||||
_jtag->shiftIR((unsigned char *)isc_erase, NULL, IRLENGTH);
|
||||
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
||||
_jtag->toggleClk(dsm_clear_delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Altera::writeXFM(const uint8_t *cfg_data, uint32_t base_addr, uint32_t offset, uint32_t len)
|
||||
|
|
|
|||
|
|
@ -91,13 +91,21 @@ class Altera: public Device, SPIInterface {
|
|||
CYCLONE10_FAMILY = 3,
|
||||
STRATIXV_FAMILY = 3,
|
||||
CYCLONE_MISC = 10, // Fixme: idcode shared
|
||||
UNKNOWN_FAMILY = 999
|
||||
UNKNOWN_FAMILY = 999
|
||||
};
|
||||
/*************************/
|
||||
/* max10 specific */
|
||||
/*************************/
|
||||
void max10_program();
|
||||
struct max10_mem_t;
|
||||
static const std::map<uint32_t, Altera::max10_mem_t> max10_memory_map;
|
||||
|
||||
/* Write a full POF file, or updates UFM with an arbitrary binary file */
|
||||
void max10_program(uint32_t offset);
|
||||
/* Write something in UFMx sections after erase */
|
||||
bool max10_program_ufm(const max10_mem_t *mem, uint32_t offset);
|
||||
/* Write len Word from cfg_data at a specific address */
|
||||
void writeXFM(const uint8_t *cfg_data, uint32_t base_addr, uint32_t offset, uint32_t len);
|
||||
/* Compare cfg_data with data stored at base_addr */
|
||||
uint32_t verifyxFM(const uint8_t *cfg_data, uint32_t base_addr, uint32_t offset,
|
||||
uint32_t len);
|
||||
void max10_dsm_program_success(const uint32_t pgm_success_addr);
|
||||
|
|
@ -105,7 +113,8 @@ class Altera: public Device, SPIInterface {
|
|||
void max10_addr_shift(uint32_t addr);
|
||||
void max10_flow_enable();
|
||||
void max10_flow_disable();
|
||||
void max10_flow_erase();
|
||||
/* Performs a full internal flash erase or sectors per sectors erase */
|
||||
void max10_flow_erase(const max10_mem_t *mem, const uint8_t erase_sectors=0x1f);
|
||||
void max10_dsm_program(const uint8_t *dsm_data, const uint32_t dsm_len);
|
||||
bool max10_dsm_verify();
|
||||
bool max10_dump();
|
||||
|
|
|
|||
Loading…
Reference in New Issue