brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · 62c3026 Raw
212 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * FPGA Manager Driver for Lattice iCE40.4 *5 *  Copyright (c) 2016 Joel Holdsworth6 *7 * This driver adds support to the FPGA manager for configuring the SRAM of8 * Lattice iCE40 FPGAs through slave SPI.9 */10 11#include <linux/fpga/fpga-mgr.h>12#include <linux/gpio/consumer.h>13#include <linux/mod_devicetable.h>14#include <linux/module.h>15#include <linux/spi/spi.h>16#include <linux/stringify.h>17 18#define ICE40_SPI_MAX_SPEED 25000000 /* Hz */19#define ICE40_SPI_MIN_SPEED 1000000 /* Hz */20 21#define ICE40_SPI_RESET_DELAY 1 /* us (>200ns) */22#define ICE40_SPI_HOUSEKEEPING_DELAY 1200 /* us */23 24#define ICE40_SPI_NUM_ACTIVATION_BYTES DIV_ROUND_UP(49, 8)25 26struct ice40_fpga_priv {27	struct spi_device *dev;28	struct gpio_desc *reset;29	struct gpio_desc *cdone;30};31 32static enum fpga_mgr_states ice40_fpga_ops_state(struct fpga_manager *mgr)33{34	struct ice40_fpga_priv *priv = mgr->priv;35 36	return gpiod_get_value(priv->cdone) ? FPGA_MGR_STATE_OPERATING :37		FPGA_MGR_STATE_UNKNOWN;38}39 40static int ice40_fpga_ops_write_init(struct fpga_manager *mgr,41				     struct fpga_image_info *info,42				     const char *buf, size_t count)43{44	struct ice40_fpga_priv *priv = mgr->priv;45	struct spi_device *dev = priv->dev;46	struct spi_message message;47	struct spi_transfer assert_cs_then_reset_delay = {48		.cs_change   = 1,49		.delay = {50			.value = ICE40_SPI_RESET_DELAY,51			.unit = SPI_DELAY_UNIT_USECS52		}53	};54	struct spi_transfer housekeeping_delay_then_release_cs = {55		.delay = {56			.value = ICE40_SPI_HOUSEKEEPING_DELAY,57			.unit = SPI_DELAY_UNIT_USECS58		}59	};60	int ret;61 62	if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {63		dev_err(&dev->dev,64			"Partial reconfiguration is not supported\n");65		return -ENOTSUPP;66	}67 68	/* Lock the bus, assert CRESET_B and SS_B and delay >200ns */69	spi_bus_lock(dev->controller);70 71	gpiod_set_value(priv->reset, 1);72 73	spi_message_init(&message);74	spi_message_add_tail(&assert_cs_then_reset_delay, &message);75	ret = spi_sync_locked(dev, &message);76 77	/* Come out of reset */78	gpiod_set_value(priv->reset, 0);79 80	/* Abort if the chip-select failed */81	if (ret)82		goto fail;83 84	/* Check CDONE is de-asserted i.e. the FPGA is reset */85	if (gpiod_get_value(priv->cdone)) {86		dev_err(&dev->dev, "Device reset failed, CDONE is asserted\n");87		ret = -EIO;88		goto fail;89	}90 91	/* Wait for the housekeeping to complete, and release SS_B */92	spi_message_init(&message);93	spi_message_add_tail(&housekeeping_delay_then_release_cs, &message);94	ret = spi_sync_locked(dev, &message);95 96fail:97	spi_bus_unlock(dev->controller);98 99	return ret;100}101 102static int ice40_fpga_ops_write(struct fpga_manager *mgr,103				const char *buf, size_t count)104{105	struct ice40_fpga_priv *priv = mgr->priv;106 107	return spi_write(priv->dev, buf, count);108}109 110static int ice40_fpga_ops_write_complete(struct fpga_manager *mgr,111					 struct fpga_image_info *info)112{113	struct ice40_fpga_priv *priv = mgr->priv;114	struct spi_device *dev = priv->dev;115	const u8 padding[ICE40_SPI_NUM_ACTIVATION_BYTES] = {0};116 117	/* Check CDONE is asserted */118	if (!gpiod_get_value(priv->cdone)) {119		dev_err(&dev->dev,120			"CDONE was not asserted after firmware transfer\n");121		return -EIO;122	}123 124	/* Send of zero-padding to activate the firmware */125	return spi_write(dev, padding, sizeof(padding));126}127 128static const struct fpga_manager_ops ice40_fpga_ops = {129	.state = ice40_fpga_ops_state,130	.write_init = ice40_fpga_ops_write_init,131	.write = ice40_fpga_ops_write,132	.write_complete = ice40_fpga_ops_write_complete,133};134 135static int ice40_fpga_probe(struct spi_device *spi)136{137	struct device *dev = &spi->dev;138	struct ice40_fpga_priv *priv;139	struct fpga_manager *mgr;140	int ret;141 142	priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);143	if (!priv)144		return -ENOMEM;145 146	priv->dev = spi;147 148	/* Check board setup data. */149	if (spi->max_speed_hz > ICE40_SPI_MAX_SPEED) {150		dev_err(dev, "SPI speed is too high, maximum speed is "151			__stringify(ICE40_SPI_MAX_SPEED) "\n");152		return -EINVAL;153	}154 155	if (spi->max_speed_hz < ICE40_SPI_MIN_SPEED) {156		dev_err(dev, "SPI speed is too low, minimum speed is "157			__stringify(ICE40_SPI_MIN_SPEED) "\n");158		return -EINVAL;159	}160 161	if (spi->mode & SPI_CPHA) {162		dev_err(dev, "Bad SPI mode, CPHA not supported\n");163		return -EINVAL;164	}165 166	/* Set up the GPIOs */167	priv->cdone = devm_gpiod_get(dev, "cdone", GPIOD_IN);168	if (IS_ERR(priv->cdone)) {169		ret = PTR_ERR(priv->cdone);170		dev_err(dev, "Failed to get CDONE GPIO: %d\n", ret);171		return ret;172	}173 174	priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);175	if (IS_ERR(priv->reset)) {176		ret = PTR_ERR(priv->reset);177		dev_err(dev, "Failed to get CRESET_B GPIO: %d\n", ret);178		return ret;179	}180 181	mgr = devm_fpga_mgr_register(dev, "Lattice iCE40 FPGA Manager",182				     &ice40_fpga_ops, priv);183	return PTR_ERR_OR_ZERO(mgr);184}185 186static const struct of_device_id ice40_fpga_of_match[] = {187	{ .compatible = "lattice,ice40-fpga-mgr", },188	{},189};190MODULE_DEVICE_TABLE(of, ice40_fpga_of_match);191 192static const struct spi_device_id ice40_fpga_spi_ids[] = {193	{ .name = "ice40-fpga-mgr", },194	{},195};196MODULE_DEVICE_TABLE(spi, ice40_fpga_spi_ids);197 198static struct spi_driver ice40_fpga_driver = {199	.probe = ice40_fpga_probe,200	.driver = {201		.name = "ice40spi",202		.of_match_table = ice40_fpga_of_match,203	},204	.id_table = ice40_fpga_spi_ids,205};206 207module_spi_driver(ice40_fpga_driver);208 209MODULE_AUTHOR("Joel Holdsworth <joel@airwebreathe.org.uk>");210MODULE_DESCRIPTION("Lattice iCE40 FPGA Manager");211MODULE_LICENSE("GPL v2");212