| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Lattice FPGA programming over slave SPI sysCONFIG interface.
- */
- #include <linux/of.h>
- #include <linux/spi/spi.h>
- #include "lattice-sysconfig.h"
- static const u32 ecp5_spi_max_speed_hz = 60000000;
- static int sysconfig_spi_cmd_transfer(struct sysconfig_priv *priv,
- const void *tx_buf, size_t tx_len,
- void *rx_buf, size_t rx_len)
- {
- struct spi_device *spi = to_spi_device(priv->dev);
- return spi_write_then_read(spi, tx_buf, tx_len, rx_buf, rx_len);
- }
- static int sysconfig_spi_bitstream_burst_init(struct sysconfig_priv *priv)
- {
- const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST;
- struct spi_device *spi = to_spi_device(priv->dev);
- struct spi_transfer xfer = {};
- struct spi_message msg;
- size_t buf_len;
- void *buf;
- int ret;
- buf_len = sizeof(lsc_bitstream_burst);
- buf = kmemdup(lsc_bitstream_burst, buf_len, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- xfer.len = buf_len;
- xfer.tx_buf = buf;
- xfer.cs_change = 1;
- spi_message_init_with_transfers(&msg, &xfer, 1);
- /*
- * Lock SPI bus for exclusive usage until FPGA programming is done.
- * SPI bus will be released in sysconfig_spi_bitstream_burst_complete().
- */
- spi_bus_lock(spi->controller);
- ret = spi_sync_locked(spi, &msg);
- if (ret)
- spi_bus_unlock(spi->controller);
- kfree(buf);
- return ret;
- }
- static int sysconfig_spi_bitstream_burst_write(struct sysconfig_priv *priv,
- const char *buf, size_t len)
- {
- struct spi_device *spi = to_spi_device(priv->dev);
- struct spi_transfer xfer = {
- .tx_buf = buf,
- .len = len,
- .cs_change = 1,
- };
- struct spi_message msg;
- spi_message_init_with_transfers(&msg, &xfer, 1);
- return spi_sync_locked(spi, &msg);
- }
- static int sysconfig_spi_bitstream_burst_complete(struct sysconfig_priv *priv)
- {
- struct spi_device *spi = to_spi_device(priv->dev);
- /* Bitstream burst write is done, release SPI bus */
- spi_bus_unlock(spi->controller);
- /* Toggle CS to finish bitstream write */
- return spi_write(spi, NULL, 0);
- }
- static int sysconfig_spi_probe(struct spi_device *spi)
- {
- const struct spi_device_id *dev_id;
- struct device *dev = &spi->dev;
- struct sysconfig_priv *priv;
- const u32 *spi_max_speed;
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- spi_max_speed = device_get_match_data(dev);
- if (!spi_max_speed) {
- dev_id = spi_get_device_id(spi);
- if (!dev_id)
- return -ENODEV;
- spi_max_speed = (const u32 *)dev_id->driver_data;
- }
- if (!spi_max_speed)
- return -EINVAL;
- if (spi->max_speed_hz > *spi_max_speed) {
- dev_err(dev, "SPI speed %u is too high, maximum speed is %u\n",
- spi->max_speed_hz, *spi_max_speed);
- return -EINVAL;
- }
- priv->dev = dev;
- priv->command_transfer = sysconfig_spi_cmd_transfer;
- priv->bitstream_burst_write_init = sysconfig_spi_bitstream_burst_init;
- priv->bitstream_burst_write = sysconfig_spi_bitstream_burst_write;
- priv->bitstream_burst_write_complete = sysconfig_spi_bitstream_burst_complete;
- return sysconfig_probe(priv);
- }
- static const struct spi_device_id sysconfig_spi_ids[] = {
- {
- .name = "sysconfig-ecp5",
- .driver_data = (kernel_ulong_t)&ecp5_spi_max_speed_hz,
- }, {},
- };
- MODULE_DEVICE_TABLE(spi, sysconfig_spi_ids);
- #if IS_ENABLED(CONFIG_OF)
- static const struct of_device_id sysconfig_of_ids[] = {
- {
- .compatible = "lattice,sysconfig-ecp5",
- .data = &ecp5_spi_max_speed_hz,
- }, {},
- };
- MODULE_DEVICE_TABLE(of, sysconfig_of_ids);
- #endif /* IS_ENABLED(CONFIG_OF) */
- static struct spi_driver lattice_sysconfig_driver = {
- .probe = sysconfig_spi_probe,
- .id_table = sysconfig_spi_ids,
- .driver = {
- .name = "lattice_sysconfig_spi_fpga_mgr",
- .of_match_table = of_match_ptr(sysconfig_of_ids),
- },
- };
- module_spi_driver(lattice_sysconfig_driver);
- MODULE_DESCRIPTION("Lattice sysCONFIG Slave SPI FPGA Manager");
- MODULE_LICENSE("GPL");
|