1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Lattice FPGA programming over slave SPI sysCONFIG interface.
4 */
5
6#include <linux/of.h>
7#include <linux/spi/spi.h>
8
9#include "lattice-sysconfig.h"
10
11static const u32 ecp5_spi_max_speed_hz = 60000000;
12
13static int sysconfig_spi_cmd_transfer(struct sysconfig_priv *priv,
14 const void *tx_buf, size_t tx_len,
15 void *rx_buf, size_t rx_len)
16{
17 struct spi_device *spi = to_spi_device(dev: priv->dev);
18
19 return spi_write_then_read(spi, txbuf: tx_buf, n_tx: tx_len, rxbuf: rx_buf, n_rx: rx_len);
20}
21
22static int sysconfig_spi_bitstream_burst_init(struct sysconfig_priv *priv)
23{
24 const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST;
25 struct spi_device *spi = to_spi_device(dev: priv->dev);
26 struct spi_transfer xfer = {};
27 struct spi_message msg;
28 size_t buf_len;
29 void *buf;
30 int ret;
31
32 buf_len = sizeof(lsc_bitstream_burst);
33
34 buf = kmemdup(p: lsc_bitstream_burst, size: buf_len, GFP_KERNEL);
35 if (!buf)
36 return -ENOMEM;
37
38 xfer.len = buf_len;
39 xfer.tx_buf = buf;
40 xfer.cs_change = 1;
41
42 spi_message_init_with_transfers(m: &msg, xfers: &xfer, num_xfers: 1);
43
44 /*
45 * Lock SPI bus for exclusive usage until FPGA programming is done.
46 * SPI bus will be released in sysconfig_spi_bitstream_burst_complete().
47 */
48 spi_bus_lock(ctlr: spi->controller);
49
50 ret = spi_sync_locked(spi, message: &msg);
51 if (ret)
52 spi_bus_unlock(ctlr: spi->controller);
53
54 kfree(objp: buf);
55
56 return ret;
57}
58
59static int sysconfig_spi_bitstream_burst_write(struct sysconfig_priv *priv,
60 const char *buf, size_t len)
61{
62 struct spi_device *spi = to_spi_device(dev: priv->dev);
63 struct spi_transfer xfer = {
64 .tx_buf = buf,
65 .len = len,
66 .cs_change = 1,
67 };
68 struct spi_message msg;
69
70 spi_message_init_with_transfers(m: &msg, xfers: &xfer, num_xfers: 1);
71
72 return spi_sync_locked(spi, message: &msg);
73}
74
75static int sysconfig_spi_bitstream_burst_complete(struct sysconfig_priv *priv)
76{
77 struct spi_device *spi = to_spi_device(dev: priv->dev);
78
79 /* Bitstream burst write is done, release SPI bus */
80 spi_bus_unlock(ctlr: spi->controller);
81
82 /* Toggle CS to finish bitstream write */
83 return spi_write(spi, NULL, len: 0);
84}
85
86static int sysconfig_spi_probe(struct spi_device *spi)
87{
88 const struct spi_device_id *dev_id;
89 struct device *dev = &spi->dev;
90 struct sysconfig_priv *priv;
91 const u32 *spi_max_speed;
92
93 priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL);
94 if (!priv)
95 return -ENOMEM;
96
97 spi_max_speed = device_get_match_data(dev);
98 if (!spi_max_speed) {
99 dev_id = spi_get_device_id(sdev: spi);
100 if (!dev_id)
101 return -ENODEV;
102
103 spi_max_speed = (const u32 *)dev_id->driver_data;
104 }
105
106 if (!spi_max_speed)
107 return -EINVAL;
108
109 if (spi->max_speed_hz > *spi_max_speed) {
110 dev_err(dev, "SPI speed %u is too high, maximum speed is %u\n",
111 spi->max_speed_hz, *spi_max_speed);
112 return -EINVAL;
113 }
114
115 priv->dev = dev;
116 priv->command_transfer = sysconfig_spi_cmd_transfer;
117 priv->bitstream_burst_write_init = sysconfig_spi_bitstream_burst_init;
118 priv->bitstream_burst_write = sysconfig_spi_bitstream_burst_write;
119 priv->bitstream_burst_write_complete = sysconfig_spi_bitstream_burst_complete;
120
121 return sysconfig_probe(priv);
122}
123
124static const struct spi_device_id sysconfig_spi_ids[] = {
125 {
126 .name = "sysconfig-ecp5",
127 .driver_data = (kernel_ulong_t)&ecp5_spi_max_speed_hz,
128 }, {},
129};
130MODULE_DEVICE_TABLE(spi, sysconfig_spi_ids);
131
132#if IS_ENABLED(CONFIG_OF)
133static const struct of_device_id sysconfig_of_ids[] = {
134 {
135 .compatible = "lattice,sysconfig-ecp5",
136 .data = &ecp5_spi_max_speed_hz,
137 }, {},
138};
139MODULE_DEVICE_TABLE(of, sysconfig_of_ids);
140#endif /* IS_ENABLED(CONFIG_OF) */
141
142static struct spi_driver lattice_sysconfig_driver = {
143 .probe = sysconfig_spi_probe,
144 .id_table = sysconfig_spi_ids,
145 .driver = {
146 .name = "lattice_sysconfig_spi_fpga_mgr",
147 .of_match_table = of_match_ptr(sysconfig_of_ids),
148 },
149};
150module_spi_driver(lattice_sysconfig_driver);
151
152MODULE_DESCRIPTION("Lattice sysCONFIG Slave SPI FPGA Manager");
153MODULE_LICENSE("GPL");
154

source code of linux/drivers/fpga/lattice-sysconfig-spi.c