Commit | Line | Data |
---|---|---|
463dd43b IB |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Lattice FPGA programming over slave SPI sysCONFIG interface. | |
4 | */ | |
5 | ||
2febc5dd | 6 | #include <linux/of.h> |
463dd43b IB |
7 | #include <linux/spi/spi.h> |
8 | ||
9 | #include "lattice-sysconfig.h" | |
10 | ||
11 | static const u32 ecp5_spi_max_speed_hz = 60000000; | |
12 | ||
13 | static 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(priv->dev); | |
18 | ||
19 | return spi_write_then_read(spi, tx_buf, tx_len, rx_buf, rx_len); | |
20 | } | |
21 | ||
22 | static 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(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(lsc_bitstream_burst, 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(&msg, &xfer, 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(spi->controller); | |
49 | ||
50 | ret = spi_sync_locked(spi, &msg); | |
51 | if (ret) | |
52 | spi_bus_unlock(spi->controller); | |
53 | ||
54 | kfree(buf); | |
55 | ||
56 | return ret; | |
57 | } | |
58 | ||
59 | static 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(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(&msg, &xfer, 1); | |
71 | ||
72 | return spi_sync_locked(spi, &msg); | |
73 | } | |
74 | ||
75 | static int sysconfig_spi_bitstream_burst_complete(struct sysconfig_priv *priv) | |
76 | { | |
77 | struct spi_device *spi = to_spi_device(priv->dev); | |
78 | ||
79 | /* Bitstream burst write is done, release SPI bus */ | |
80 | spi_bus_unlock(spi->controller); | |
81 | ||
82 | /* Toggle CS to finish bitstream write */ | |
83 | return spi_write(spi, NULL, 0); | |
84 | } | |
85 | ||
86 | static 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, 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(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 | ||
124 | static 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 | }; | |
130 | MODULE_DEVICE_TABLE(spi, sysconfig_spi_ids); | |
131 | ||
132 | #if IS_ENABLED(CONFIG_OF) | |
133 | static const struct of_device_id sysconfig_of_ids[] = { | |
134 | { | |
135 | .compatible = "lattice,sysconfig-ecp5", | |
136 | .data = &ecp5_spi_max_speed_hz, | |
137 | }, {}, | |
138 | }; | |
139 | MODULE_DEVICE_TABLE(of, sysconfig_of_ids); | |
140 | #endif /* IS_ENABLED(CONFIG_OF) */ | |
141 | ||
142 | static 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 | }; | |
150 | module_spi_driver(lattice_sysconfig_driver); | |
151 | ||
152 | MODULE_DESCRIPTION("Lattice sysCONFIG Slave SPI FPGA Manager"); | |
153 | MODULE_LICENSE("GPL"); |