Source
x
/*
* FPGA Manager Driver for Lattice iCE40.
*
* Copyright (c) 2016 Joel Holdsworth
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This driver adds support to the FPGA manager for configuring the SRAM of
* Lattice iCE40 FPGAs through slave SPI.
*/
/* Hz */
/* Hz */
/* us (>200ns) */
/* us */
struct ice40_fpga_priv {
struct spi_device *dev;
struct gpio_desc *reset;
struct gpio_desc *cdone;
};
static enum fpga_mgr_states ice40_fpga_ops_state(struct fpga_manager *mgr)
{
struct ice40_fpga_priv *priv = mgr->priv;
return gpiod_get_value(priv->cdone) ? FPGA_MGR_STATE_OPERATING :
FPGA_MGR_STATE_UNKNOWN;
}
static int ice40_fpga_ops_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count)
{
struct ice40_fpga_priv *priv = mgr->priv;
struct spi_device *dev = priv->dev;
struct spi_message message;
struct spi_transfer assert_cs_then_reset_delay = {
.cs_change = 1,
.delay_usecs = ICE40_SPI_RESET_DELAY
};
struct spi_transfer housekeeping_delay_then_release_cs = {
.delay_usecs = ICE40_SPI_HOUSEKEEPING_DELAY
};
int ret;
if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
dev_err(&dev->dev,
"Partial reconfiguration is not supported\n");
return -ENOTSUPP;
}
/* Lock the bus, assert CRESET_B and SS_B and delay >200ns */
spi_bus_lock(dev->master);
gpiod_set_value(priv->reset, 1);
spi_message_init(&message);
spi_message_add_tail(&assert_cs_then_reset_delay, &message);
ret = spi_sync_locked(dev, &message);
/* Come out of reset */
gpiod_set_value(priv->reset, 0);
/* Abort if the chip-select failed */
if (ret)
goto fail;
/* Check CDONE is de-asserted i.e. the FPGA is reset */
if (gpiod_get_value(priv->cdone)) {
dev_err(&dev->dev, "Device reset failed, CDONE is asserted\n");
ret = -EIO;
goto fail;
}
/* Wait for the housekeeping to complete, and release SS_B */
spi_message_init(&message);
spi_message_add_tail(&housekeeping_delay_then_release_cs, &message);
ret = spi_sync_locked(dev, &message);