Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
f0b7215e1This file is pinned to the selected release. Download the original to open it in your design tool.
// 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);
usleep(12000);
printInfo("Reset and Wait for CDONE:");
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(const 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, _quiet);
const 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];
memset(dummy, 0xff, sizeof(dummy));
_spi->spi_put(dummy, NULL, 12);
/* wait CDONE */
usleep(12000);
printInfo("Wait for CDONE");
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 (timeout == 0) ? false : true;
}
void Ice40::program(unsigned int offset, bool unprotect_flash)
{
if (_file_extension.empty())
return;
RawParser bit(_filename, false);
printInfo("Parse file ", false);
if (bit.parse() == EXIT_SUCCESS) {
printSuccess("DONE");
} else {
printError("FAIL");
return;
}
const 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,
_verbose_level);
flash.erase_and_prog(offset, data, length);
if (_verify)
flash.verify(offset, data, length);
/* release SPI access / reload */
post_flash_access();
}
bool Ice40::dumpFlash(uint32_t base_addr, uint32_t len)
{
/* prepare SPI access */
prepare_flash_access();
printInfo("Read Flash ", false);
try {
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), false, _verbose_level);
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 / reload */
return post_flash_access();
}
bool Ice40::protect_flash(uint32_t len)
{
/* SPI access */
prepare_flash_access();
/* acess */
try {
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), false, _verbose_level);
/* 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_level);
/* 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::bulk_erase_flash()
{
/* SPI access */
prepare_flash_access();
/* acess */
try {
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), false, _verbose_level);
/* bulk erase flash */
if (flash.bulk_erase() == -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;
}