18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * FPGA Manager Driver for Lattice iCE40. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Joel Holdsworth 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This driver adds support to the FPGA manager for configuring the SRAM of 88c2ecf20Sopenharmony_ci * Lattice iCE40 FPGAs through slave SPI. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/fpga/fpga-mgr.h> 128c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 158c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 168c2ecf20Sopenharmony_ci#include <linux/stringify.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define ICE40_SPI_MAX_SPEED 25000000 /* Hz */ 198c2ecf20Sopenharmony_ci#define ICE40_SPI_MIN_SPEED 1000000 /* Hz */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define ICE40_SPI_RESET_DELAY 1 /* us (>200ns) */ 228c2ecf20Sopenharmony_ci#define ICE40_SPI_HOUSEKEEPING_DELAY 1200 /* us */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define ICE40_SPI_NUM_ACTIVATION_BYTES DIV_ROUND_UP(49, 8) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct ice40_fpga_priv { 278c2ecf20Sopenharmony_ci struct spi_device *dev; 288c2ecf20Sopenharmony_ci struct gpio_desc *reset; 298c2ecf20Sopenharmony_ci struct gpio_desc *cdone; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic enum fpga_mgr_states ice40_fpga_ops_state(struct fpga_manager *mgr) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct ice40_fpga_priv *priv = mgr->priv; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return gpiod_get_value(priv->cdone) ? FPGA_MGR_STATE_OPERATING : 378c2ecf20Sopenharmony_ci FPGA_MGR_STATE_UNKNOWN; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int ice40_fpga_ops_write_init(struct fpga_manager *mgr, 418c2ecf20Sopenharmony_ci struct fpga_image_info *info, 428c2ecf20Sopenharmony_ci const char *buf, size_t count) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct ice40_fpga_priv *priv = mgr->priv; 458c2ecf20Sopenharmony_ci struct spi_device *dev = priv->dev; 468c2ecf20Sopenharmony_ci struct spi_message message; 478c2ecf20Sopenharmony_ci struct spi_transfer assert_cs_then_reset_delay = { 488c2ecf20Sopenharmony_ci .cs_change = 1, 498c2ecf20Sopenharmony_ci .delay = { 508c2ecf20Sopenharmony_ci .value = ICE40_SPI_RESET_DELAY, 518c2ecf20Sopenharmony_ci .unit = SPI_DELAY_UNIT_USECS 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci }; 548c2ecf20Sopenharmony_ci struct spi_transfer housekeeping_delay_then_release_cs = { 558c2ecf20Sopenharmony_ci .delay = { 568c2ecf20Sopenharmony_ci .value = ICE40_SPI_HOUSEKEEPING_DELAY, 578c2ecf20Sopenharmony_ci .unit = SPI_DELAY_UNIT_USECS 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci }; 608c2ecf20Sopenharmony_ci int ret; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { 638c2ecf20Sopenharmony_ci dev_err(&dev->dev, 648c2ecf20Sopenharmony_ci "Partial reconfiguration is not supported\n"); 658c2ecf20Sopenharmony_ci return -ENOTSUPP; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Lock the bus, assert CRESET_B and SS_B and delay >200ns */ 698c2ecf20Sopenharmony_ci spi_bus_lock(dev->master); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci gpiod_set_value(priv->reset, 1); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci spi_message_init(&message); 748c2ecf20Sopenharmony_ci spi_message_add_tail(&assert_cs_then_reset_delay, &message); 758c2ecf20Sopenharmony_ci ret = spi_sync_locked(dev, &message); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Come out of reset */ 788c2ecf20Sopenharmony_ci gpiod_set_value(priv->reset, 0); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* Abort if the chip-select failed */ 818c2ecf20Sopenharmony_ci if (ret) 828c2ecf20Sopenharmony_ci goto fail; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* Check CDONE is de-asserted i.e. the FPGA is reset */ 858c2ecf20Sopenharmony_ci if (gpiod_get_value(priv->cdone)) { 868c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Device reset failed, CDONE is asserted\n"); 878c2ecf20Sopenharmony_ci ret = -EIO; 888c2ecf20Sopenharmony_ci goto fail; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* Wait for the housekeeping to complete, and release SS_B */ 928c2ecf20Sopenharmony_ci spi_message_init(&message); 938c2ecf20Sopenharmony_ci spi_message_add_tail(&housekeeping_delay_then_release_cs, &message); 948c2ecf20Sopenharmony_ci ret = spi_sync_locked(dev, &message); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cifail: 978c2ecf20Sopenharmony_ci spi_bus_unlock(dev->master); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return ret; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int ice40_fpga_ops_write(struct fpga_manager *mgr, 1038c2ecf20Sopenharmony_ci const char *buf, size_t count) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct ice40_fpga_priv *priv = mgr->priv; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return spi_write(priv->dev, buf, count); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int ice40_fpga_ops_write_complete(struct fpga_manager *mgr, 1118c2ecf20Sopenharmony_ci struct fpga_image_info *info) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct ice40_fpga_priv *priv = mgr->priv; 1148c2ecf20Sopenharmony_ci struct spi_device *dev = priv->dev; 1158c2ecf20Sopenharmony_ci const u8 padding[ICE40_SPI_NUM_ACTIVATION_BYTES] = {0}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* Check CDONE is asserted */ 1188c2ecf20Sopenharmony_ci if (!gpiod_get_value(priv->cdone)) { 1198c2ecf20Sopenharmony_ci dev_err(&dev->dev, 1208c2ecf20Sopenharmony_ci "CDONE was not asserted after firmware transfer\n"); 1218c2ecf20Sopenharmony_ci return -EIO; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* Send of zero-padding to activate the firmware */ 1258c2ecf20Sopenharmony_ci return spi_write(dev, padding, sizeof(padding)); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic const struct fpga_manager_ops ice40_fpga_ops = { 1298c2ecf20Sopenharmony_ci .state = ice40_fpga_ops_state, 1308c2ecf20Sopenharmony_ci .write_init = ice40_fpga_ops_write_init, 1318c2ecf20Sopenharmony_ci .write = ice40_fpga_ops_write, 1328c2ecf20Sopenharmony_ci .write_complete = ice40_fpga_ops_write_complete, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int ice40_fpga_probe(struct spi_device *spi) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct device *dev = &spi->dev; 1388c2ecf20Sopenharmony_ci struct ice40_fpga_priv *priv; 1398c2ecf20Sopenharmony_ci struct fpga_manager *mgr; 1408c2ecf20Sopenharmony_ci int ret; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); 1438c2ecf20Sopenharmony_ci if (!priv) 1448c2ecf20Sopenharmony_ci return -ENOMEM; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci priv->dev = spi; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Check board setup data. */ 1498c2ecf20Sopenharmony_ci if (spi->max_speed_hz > ICE40_SPI_MAX_SPEED) { 1508c2ecf20Sopenharmony_ci dev_err(dev, "SPI speed is too high, maximum speed is " 1518c2ecf20Sopenharmony_ci __stringify(ICE40_SPI_MAX_SPEED) "\n"); 1528c2ecf20Sopenharmony_ci return -EINVAL; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (spi->max_speed_hz < ICE40_SPI_MIN_SPEED) { 1568c2ecf20Sopenharmony_ci dev_err(dev, "SPI speed is too low, minimum speed is " 1578c2ecf20Sopenharmony_ci __stringify(ICE40_SPI_MIN_SPEED) "\n"); 1588c2ecf20Sopenharmony_ci return -EINVAL; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPHA) { 1628c2ecf20Sopenharmony_ci dev_err(dev, "Bad SPI mode, CPHA not supported\n"); 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Set up the GPIOs */ 1678c2ecf20Sopenharmony_ci priv->cdone = devm_gpiod_get(dev, "cdone", GPIOD_IN); 1688c2ecf20Sopenharmony_ci if (IS_ERR(priv->cdone)) { 1698c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->cdone); 1708c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get CDONE GPIO: %d\n", ret); 1718c2ecf20Sopenharmony_ci return ret; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 1758c2ecf20Sopenharmony_ci if (IS_ERR(priv->reset)) { 1768c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->reset); 1778c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get CRESET_B GPIO: %d\n", ret); 1788c2ecf20Sopenharmony_ci return ret; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci mgr = devm_fpga_mgr_create(dev, "Lattice iCE40 FPGA Manager", 1828c2ecf20Sopenharmony_ci &ice40_fpga_ops, priv); 1838c2ecf20Sopenharmony_ci if (!mgr) 1848c2ecf20Sopenharmony_ci return -ENOMEM; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci spi_set_drvdata(spi, mgr); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return fpga_mgr_register(mgr); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int ice40_fpga_remove(struct spi_device *spi) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct fpga_manager *mgr = spi_get_drvdata(spi); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci fpga_mgr_unregister(mgr); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic const struct of_device_id ice40_fpga_of_match[] = { 2018c2ecf20Sopenharmony_ci { .compatible = "lattice,ice40-fpga-mgr", }, 2028c2ecf20Sopenharmony_ci {}, 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ice40_fpga_of_match); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic struct spi_driver ice40_fpga_driver = { 2078c2ecf20Sopenharmony_ci .probe = ice40_fpga_probe, 2088c2ecf20Sopenharmony_ci .remove = ice40_fpga_remove, 2098c2ecf20Sopenharmony_ci .driver = { 2108c2ecf20Sopenharmony_ci .name = "ice40spi", 2118c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(ice40_fpga_of_match), 2128c2ecf20Sopenharmony_ci }, 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cimodule_spi_driver(ice40_fpga_driver); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Joel Holdsworth <joel@airwebreathe.org.uk>"); 2188c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Lattice iCE40 FPGA Manager"); 2198c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 220