openFPGALoader/src/ice40.cpp

253 lines
5.1 KiB
C++

// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (C) 2020 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
*/
#include "ice40.hpp"
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include "display.hpp"
#include "ftdispi.hpp"
#include "device.hpp"
#include "progressBar.hpp"
#include "rawParser.hpp"
#include "spiFlash.hpp"
Ice40::Ice40(FtdiSpi* spi, const std::string &filename,
const std::string &file_type,
Device::prog_type_t prg_type,
uint16_t rst_pin, uint16_t done_pin,
bool verify, int8_t verbose):
Device(NULL, filename, file_type, verify, verbose), _rst_pin(rst_pin),
_done_pin(done_pin)
{
_spi = spi;
_spi->gpio_set_input(_done_pin);
_spi->gpio_set_output(_rst_pin);
if (prg_type == Device::WR_FLASH)
_mode = Device::SPI_MODE;
else
_mode = Device::MEM_MODE;
}
Ice40::~Ice40()
{}
void Ice40::reset()
{
uint32_t timeout = 1000;
_spi->gpio_clear(_rst_pin);
usleep(1000);
_spi->gpio_set(_rst_pin);
printInfo("Reset ", false);
usleep(12000);
do {
timeout--;
usleep(12000);
} while (((_spi->gpio_get(true) & _done_pin) == 0) && timeout > 0);
if (timeout == 0)
printError("FAIL");
else
printSuccess("DONE");
}
/* cf. TN1248 (iCE40 Programming and Configuration)
* Appendix A. SPI Slave Configuration Procedure
*/
bool Ice40::program_cram(uint8_t *data, uint32_t length)
{
uint32_t timeout = 1000;
/* configure SPI */
_spi->setMode(3); // IDLE high, write on falling
_spi->setCSmode(FtdiSpi::SPI_CS_MANUAL);
/* reset device */
_spi->clearCs();
_spi->gpio_clear(_rst_pin);
usleep(100); // 200 ns ...
_spi->gpio_set(_rst_pin);
usleep(2000); // 800 -> 1200 us + guard
/* load configuration data MSB first
*/
ProgressBar progress("Loading to CRAM", length, 50, _verbose);
uint8_t *ptr = data;
int size = 0;
for (uint32_t addr = 0; addr < length; addr += size, ptr+=size) {
size = (addr + 256 > length)?(length-addr) : 256;
if (_spi->spi_put(ptr, NULL, size) == -1)
return -1;
progress.display(addr);
}
progress.done();
/* send 48 to 100 dummy bits */
uint8_t dummy[12];
_spi->spi_put(dummy, NULL, 12);
/* wait CDONE */
usleep(12000);
printInfo("Wait for CDONE ", false);
do {
timeout--;
usleep(12000);
} while (((_spi->gpio_get(true) & _done_pin) == 0) && timeout > 0);
if (timeout == 0)
printError("FAIL");
else
printSuccess("DONE");
_spi->setCs();
return true;
}
void Ice40::program(unsigned int offset, bool unprotect_flash)
{
uint32_t timeout = 1000;
if (_file_extension.empty())
return;
RawParser bit(_filename, false);
printInfo("Parse file ", false);
if (bit.parse() == EXIT_SUCCESS) {
printSuccess("DONE");
} else {
printError("FAIL");
return;
}
uint8_t *data = bit.getData();
int length = bit.getLength() / 8;
if (_mode == Device::MEM_MODE) {
program_cram(data, length);
return;
}
_spi->gpio_clear(_rst_pin);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), unprotect_flash,
_quiet);
printf("%02x\n", flash.read_status_reg());
flash.read_id();
flash.erase_and_prog(offset, data, length);
if (_verify)
flash.verify(offset, data, length);
_spi->gpio_set(_rst_pin);
usleep(12000);
printInfo("Wait for CDONE ", false);
do {
timeout--;
usleep(12000);
} while (((_spi->gpio_get(true) & _done_pin) == 0) && timeout > 0);
if (timeout == 0)
printError("FAIL");
else
printSuccess("DONE");
}
bool Ice40::dumpFlash(uint32_t base_addr, uint32_t len)
{
uint32_t timeout = 1000;
_spi->gpio_clear(_rst_pin);
/* prepare SPI access */
printInfo("Read Flash ", false);
try {
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), false, _verbose);
flash.reset();
flash.power_up();
flash.dump(_filename, base_addr, len);
} catch (std::exception &e) {
printError("Fail");
printError(std::string(e.what()));
return false;
}
/* release SPI access */
_spi->gpio_set(_rst_pin);
usleep(12000);
printInfo("Wait for CDONE ", false);
do {
timeout--;
usleep(12000);
} while (((_spi->gpio_get(true) & _done_pin) == 0) && timeout > 0);
if (timeout == 0)
printError("FAIL");
else
printSuccess("DONE");
return false;
}
bool Ice40::protect_flash(uint32_t len)
{
/* SPI access */
prepare_flash_access();
/* acess */
try {
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), false, _verbose);
/* configure flash protection */
if (flash.enable_protection(len) == -1)
return false;
} catch (std::exception &e) {
printError("Fail");
printError(std::string(e.what()));
return false;
}
/* reload */
return post_flash_access();
}
bool Ice40::unprotect_flash()
{
/* SPI access */
prepare_flash_access();
/* acess */
try {
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), false, _verbose);
/* configure flash protection */
if (flash.disable_protection() == -1)
return false;
} catch (std::exception &e) {
printError("Fail");
printError(std::string(e.what()));
return false;
}
/* reload */
return post_flash_access();
}
bool Ice40::prepare_flash_access()
{
/* SPI access: shutdown ICE40 */
_spi->gpio_clear(_rst_pin);
usleep(1000);
return true;
}
bool Ice40::post_flash_access()
{
reset();
return ((_spi->gpio_get(true) & _done_pin) == 0) ? false : true;
}