]>
Commit | Line | Data |
---|---|---|
5f8d4a90 IB |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Microchip Polarfire FPGA programming over slave SPI interface. | |
4 | */ | |
5 | ||
6 | #include <asm/unaligned.h> | |
7 | #include <linux/delay.h> | |
8 | #include <linux/fpga/fpga-mgr.h> | |
88e70569 | 9 | #include <linux/iopoll.h> |
5f8d4a90 | 10 | #include <linux/module.h> |
84020839 | 11 | #include <linux/of.h> |
5f8d4a90 IB |
12 | #include <linux/spi/spi.h> |
13 | ||
14 | #define MPF_SPI_ISC_ENABLE 0x0B | |
15 | #define MPF_SPI_ISC_DISABLE 0x0C | |
16 | #define MPF_SPI_READ_STATUS 0x00 | |
17 | #define MPF_SPI_READ_DATA 0x01 | |
18 | #define MPF_SPI_FRAME_INIT 0xAE | |
19 | #define MPF_SPI_FRAME 0xEE | |
20 | #define MPF_SPI_PRG_MODE 0x01 | |
21 | #define MPF_SPI_RELEASE 0x23 | |
22 | ||
23 | #define MPF_SPI_FRAME_SIZE 16 | |
24 | ||
25 | #define MPF_HEADER_SIZE_OFFSET 24 | |
26 | #define MPF_DATA_SIZE_OFFSET 55 | |
27 | ||
28 | #define MPF_LOOKUP_TABLE_RECORD_SIZE 9 | |
29 | #define MPF_LOOKUP_TABLE_BLOCK_ID_OFFSET 0 | |
30 | #define MPF_LOOKUP_TABLE_BLOCK_START_OFFSET 1 | |
31 | ||
32 | #define MPF_COMPONENTS_SIZE_ID 5 | |
33 | #define MPF_BITSTREAM_ID 8 | |
34 | ||
35 | #define MPF_BITS_PER_COMPONENT_SIZE 22 | |
36 | ||
88e70569 | 37 | #define MPF_STATUS_POLL_TIMEOUT (2 * USEC_PER_SEC) |
5f8d4a90 IB |
38 | #define MPF_STATUS_BUSY BIT(0) |
39 | #define MPF_STATUS_READY BIT(1) | |
40 | #define MPF_STATUS_SPI_VIOLATION BIT(2) | |
41 | #define MPF_STATUS_SPI_ERROR BIT(3) | |
42 | ||
43 | struct mpf_priv { | |
44 | struct spi_device *spi; | |
45 | bool program_mode; | |
1da53d23 IB |
46 | u8 tx __aligned(ARCH_KMALLOC_MINALIGN); |
47 | u8 rx; | |
5f8d4a90 IB |
48 | }; |
49 | ||
1da53d23 | 50 | static int mpf_read_status(struct mpf_priv *priv) |
5f8d4a90 | 51 | { |
5f8d4a90 IB |
52 | /* |
53 | * HW status is returned on MISO in the first byte after CS went | |
54 | * active. However, first reading can be inadequate, so we submit | |
55 | * two identical SPI transfers and use result of the later one. | |
56 | */ | |
1da53d23 IB |
57 | struct spi_transfer xfers[2] = { |
58 | { | |
59 | .tx_buf = &priv->tx, | |
60 | .rx_buf = &priv->rx, | |
61 | .len = 1, | |
62 | .cs_change = 1, | |
63 | }, { | |
64 | .tx_buf = &priv->tx, | |
65 | .rx_buf = &priv->rx, | |
66 | .len = 1, | |
67 | }, | |
68 | }; | |
69 | u8 status; | |
70 | int ret; | |
71 | ||
72 | priv->tx = MPF_SPI_READ_STATUS; | |
73 | ||
74 | ret = spi_sync_transfer(priv->spi, xfers, 2); | |
75 | if (ret) | |
76 | return ret; | |
5f8d4a90 | 77 | |
1da53d23 | 78 | status = priv->rx; |
5f8d4a90 IB |
79 | |
80 | if ((status & MPF_STATUS_SPI_VIOLATION) || | |
81 | (status & MPF_STATUS_SPI_ERROR)) | |
1da53d23 | 82 | return -EIO; |
5f8d4a90 | 83 | |
1da53d23 | 84 | return status; |
5f8d4a90 IB |
85 | } |
86 | ||
87 | static enum fpga_mgr_states mpf_ops_state(struct fpga_manager *mgr) | |
88 | { | |
89 | struct mpf_priv *priv = mgr->priv; | |
5f8d4a90 IB |
90 | bool program_mode; |
91 | int status; | |
92 | ||
5f8d4a90 | 93 | program_mode = priv->program_mode; |
1da53d23 | 94 | status = mpf_read_status(priv); |
5f8d4a90 IB |
95 | |
96 | if (!program_mode && !status) | |
97 | return FPGA_MGR_STATE_OPERATING; | |
98 | ||
99 | return FPGA_MGR_STATE_UNKNOWN; | |
100 | } | |
101 | ||
102 | static int mpf_ops_parse_header(struct fpga_manager *mgr, | |
103 | struct fpga_image_info *info, | |
104 | const char *buf, size_t count) | |
105 | { | |
106 | size_t component_size_byte_num, component_size_byte_off, | |
107 | components_size_start, bitstream_start, | |
108 | block_id_offset, block_start_offset; | |
109 | u8 header_size, blocks_num, block_id; | |
110 | u32 block_start, component_size; | |
111 | u16 components_num, i; | |
112 | ||
113 | if (!buf) { | |
114 | dev_err(&mgr->dev, "Image buffer is not provided\n"); | |
115 | return -EINVAL; | |
116 | } | |
117 | ||
118 | header_size = *(buf + MPF_HEADER_SIZE_OFFSET); | |
119 | if (header_size > count) { | |
120 | info->header_size = header_size; | |
121 | return -EAGAIN; | |
122 | } | |
123 | ||
124 | /* | |
125 | * Go through look-up table to find out where actual bitstream starts | |
126 | * and where sizes of components of the bitstream lies. | |
127 | */ | |
128 | blocks_num = *(buf + header_size - 1); | |
129 | block_id_offset = header_size + MPF_LOOKUP_TABLE_BLOCK_ID_OFFSET; | |
130 | block_start_offset = header_size + MPF_LOOKUP_TABLE_BLOCK_START_OFFSET; | |
131 | ||
132 | header_size += blocks_num * MPF_LOOKUP_TABLE_RECORD_SIZE; | |
133 | if (header_size > count) { | |
134 | info->header_size = header_size; | |
135 | return -EAGAIN; | |
136 | } | |
137 | ||
138 | components_size_start = 0; | |
139 | bitstream_start = 0; | |
140 | ||
141 | while (blocks_num--) { | |
142 | block_id = *(buf + block_id_offset); | |
143 | block_start = get_unaligned_le32(buf + block_start_offset); | |
144 | ||
145 | switch (block_id) { | |
146 | case MPF_BITSTREAM_ID: | |
147 | bitstream_start = block_start; | |
148 | info->header_size = block_start; | |
149 | if (block_start > count) | |
150 | return -EAGAIN; | |
151 | ||
152 | break; | |
153 | case MPF_COMPONENTS_SIZE_ID: | |
154 | components_size_start = block_start; | |
155 | break; | |
156 | default: | |
157 | break; | |
158 | } | |
159 | ||
160 | if (bitstream_start && components_size_start) | |
161 | break; | |
162 | ||
163 | block_id_offset += MPF_LOOKUP_TABLE_RECORD_SIZE; | |
164 | block_start_offset += MPF_LOOKUP_TABLE_RECORD_SIZE; | |
165 | } | |
166 | ||
167 | if (!bitstream_start || !components_size_start) { | |
168 | dev_err(&mgr->dev, "Failed to parse header look-up table\n"); | |
169 | return -EFAULT; | |
170 | } | |
171 | ||
172 | /* | |
173 | * Parse bitstream size. | |
174 | * Sizes of components of the bitstream are 22-bits long placed next | |
175 | * to each other. Image header should be extended by now up to where | |
176 | * actual bitstream starts, so no need for overflow check anymore. | |
177 | */ | |
178 | components_num = get_unaligned_le16(buf + MPF_DATA_SIZE_OFFSET); | |
179 | ||
180 | for (i = 0; i < components_num; i++) { | |
181 | component_size_byte_num = | |
182 | (i * MPF_BITS_PER_COMPONENT_SIZE) / BITS_PER_BYTE; | |
183 | component_size_byte_off = | |
184 | (i * MPF_BITS_PER_COMPONENT_SIZE) % BITS_PER_BYTE; | |
185 | ||
186 | component_size = get_unaligned_le32(buf + | |
187 | components_size_start + | |
188 | component_size_byte_num); | |
189 | component_size >>= component_size_byte_off; | |
190 | component_size &= GENMASK(MPF_BITS_PER_COMPONENT_SIZE - 1, 0); | |
191 | ||
192 | info->data_size += component_size * MPF_SPI_FRAME_SIZE; | |
193 | } | |
194 | ||
195 | return 0; | |
196 | } | |
197 | ||
1da53d23 | 198 | static int mpf_poll_status(struct mpf_priv *priv, u8 mask) |
5f8d4a90 | 199 | { |
88e70569 | 200 | int ret, status; |
5f8d4a90 | 201 | |
88e70569 IB |
202 | /* |
203 | * Busy poll HW status. Polling stops if any of the following | |
204 | * conditions are met: | |
205 | * - timeout is reached | |
206 | * - mpf_read_status() returns an error | |
207 | * - busy bit is cleared AND mask bits are set | |
208 | */ | |
209 | ret = read_poll_timeout(mpf_read_status, status, | |
210 | (status < 0) || | |
211 | ((status & (MPF_STATUS_BUSY | mask)) == mask), | |
212 | 0, MPF_STATUS_POLL_TIMEOUT, false, priv); | |
213 | if (ret < 0) | |
214 | return ret; | |
5f8d4a90 | 215 | |
88e70569 | 216 | return status; |
5f8d4a90 IB |
217 | } |
218 | ||
1da53d23 | 219 | static int mpf_spi_write(struct mpf_priv *priv, const void *buf, size_t buf_size) |
5f8d4a90 | 220 | { |
1da53d23 | 221 | int status = mpf_poll_status(priv, 0); |
5f8d4a90 IB |
222 | |
223 | if (status < 0) | |
224 | return status; | |
225 | ||
1da53d23 | 226 | return spi_write_then_read(priv->spi, buf, buf_size, NULL, 0); |
5f8d4a90 IB |
227 | } |
228 | ||
1da53d23 | 229 | static int mpf_spi_write_then_read(struct mpf_priv *priv, |
5f8d4a90 IB |
230 | const void *txbuf, size_t txbuf_size, |
231 | void *rxbuf, size_t rxbuf_size) | |
232 | { | |
233 | const u8 read_command[] = { MPF_SPI_READ_DATA }; | |
234 | int ret; | |
235 | ||
1da53d23 | 236 | ret = mpf_spi_write(priv, txbuf, txbuf_size); |
5f8d4a90 IB |
237 | if (ret) |
238 | return ret; | |
239 | ||
1da53d23 | 240 | ret = mpf_poll_status(priv, MPF_STATUS_READY); |
5f8d4a90 IB |
241 | if (ret < 0) |
242 | return ret; | |
243 | ||
1da53d23 | 244 | return spi_write_then_read(priv->spi, read_command, sizeof(read_command), |
5f8d4a90 IB |
245 | rxbuf, rxbuf_size); |
246 | } | |
247 | ||
248 | static int mpf_ops_write_init(struct fpga_manager *mgr, | |
249 | struct fpga_image_info *info, const char *buf, | |
250 | size_t count) | |
251 | { | |
252 | const u8 program_mode[] = { MPF_SPI_FRAME_INIT, MPF_SPI_PRG_MODE }; | |
253 | const u8 isc_en_command[] = { MPF_SPI_ISC_ENABLE }; | |
254 | struct mpf_priv *priv = mgr->priv; | |
255 | struct device *dev = &mgr->dev; | |
5f8d4a90 IB |
256 | u32 isc_ret = 0; |
257 | int ret; | |
258 | ||
259 | if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { | |
260 | dev_err(dev, "Partial reconfiguration is not supported\n"); | |
261 | return -EOPNOTSUPP; | |
262 | } | |
263 | ||
1da53d23 | 264 | ret = mpf_spi_write_then_read(priv, isc_en_command, sizeof(isc_en_command), |
5f8d4a90 IB |
265 | &isc_ret, sizeof(isc_ret)); |
266 | if (ret || isc_ret) { | |
267 | dev_err(dev, "Failed to enable ISC: spi_ret %d, isc_ret %u\n", | |
268 | ret, isc_ret); | |
269 | return -EFAULT; | |
270 | } | |
271 | ||
1da53d23 | 272 | ret = mpf_spi_write(priv, program_mode, sizeof(program_mode)); |
5f8d4a90 IB |
273 | if (ret) { |
274 | dev_err(dev, "Failed to enter program mode: %d\n", ret); | |
275 | return ret; | |
276 | } | |
277 | ||
278 | priv->program_mode = true; | |
279 | ||
280 | return 0; | |
281 | } | |
282 | ||
9d94ec98 IB |
283 | static int mpf_spi_frame_write(struct mpf_priv *priv, const char *buf) |
284 | { | |
285 | struct spi_transfer xfers[2] = { | |
286 | { | |
287 | .tx_buf = &priv->tx, | |
288 | .len = 1, | |
289 | }, { | |
290 | .tx_buf = buf, | |
291 | .len = MPF_SPI_FRAME_SIZE, | |
292 | }, | |
293 | }; | |
294 | int ret; | |
295 | ||
296 | ret = mpf_poll_status(priv, 0); | |
297 | if (ret < 0) | |
298 | return ret; | |
299 | ||
300 | priv->tx = MPF_SPI_FRAME; | |
301 | ||
302 | return spi_sync_transfer(priv->spi, xfers, ARRAY_SIZE(xfers)); | |
303 | } | |
304 | ||
5f8d4a90 IB |
305 | static int mpf_ops_write(struct fpga_manager *mgr, const char *buf, size_t count) |
306 | { | |
5f8d4a90 IB |
307 | struct mpf_priv *priv = mgr->priv; |
308 | struct device *dev = &mgr->dev; | |
5f8d4a90 IB |
309 | int ret, i; |
310 | ||
311 | if (count % MPF_SPI_FRAME_SIZE) { | |
312 | dev_err(dev, "Bitstream size is not a multiple of %d\n", | |
313 | MPF_SPI_FRAME_SIZE); | |
314 | return -EINVAL; | |
315 | } | |
316 | ||
5f8d4a90 | 317 | for (i = 0; i < count / MPF_SPI_FRAME_SIZE; i++) { |
9d94ec98 | 318 | ret = mpf_spi_frame_write(priv, buf + i * MPF_SPI_FRAME_SIZE); |
5f8d4a90 IB |
319 | if (ret) { |
320 | dev_err(dev, "Failed to write bitstream frame %d/%zu\n", | |
321 | i, count / MPF_SPI_FRAME_SIZE); | |
322 | return ret; | |
323 | } | |
324 | } | |
325 | ||
326 | return 0; | |
327 | } | |
328 | ||
329 | static int mpf_ops_write_complete(struct fpga_manager *mgr, | |
330 | struct fpga_image_info *info) | |
331 | { | |
332 | const u8 isc_dis_command[] = { MPF_SPI_ISC_DISABLE }; | |
333 | const u8 release_command[] = { MPF_SPI_RELEASE }; | |
334 | struct mpf_priv *priv = mgr->priv; | |
335 | struct device *dev = &mgr->dev; | |
5f8d4a90 IB |
336 | int ret; |
337 | ||
1da53d23 | 338 | ret = mpf_spi_write(priv, isc_dis_command, sizeof(isc_dis_command)); |
5f8d4a90 IB |
339 | if (ret) { |
340 | dev_err(dev, "Failed to disable ISC: %d\n", ret); | |
341 | return ret; | |
342 | } | |
343 | ||
344 | usleep_range(1000, 2000); | |
345 | ||
1da53d23 | 346 | ret = mpf_spi_write(priv, release_command, sizeof(release_command)); |
5f8d4a90 IB |
347 | if (ret) { |
348 | dev_err(dev, "Failed to exit program mode: %d\n", ret); | |
349 | return ret; | |
350 | } | |
351 | ||
352 | priv->program_mode = false; | |
353 | ||
354 | return 0; | |
355 | } | |
356 | ||
357 | static const struct fpga_manager_ops mpf_ops = { | |
358 | .state = mpf_ops_state, | |
359 | .initial_header_size = 71, | |
360 | .skip_header = true, | |
361 | .parse_header = mpf_ops_parse_header, | |
362 | .write_init = mpf_ops_write_init, | |
363 | .write = mpf_ops_write, | |
364 | .write_complete = mpf_ops_write_complete, | |
365 | }; | |
366 | ||
367 | static int mpf_probe(struct spi_device *spi) | |
368 | { | |
369 | struct device *dev = &spi->dev; | |
370 | struct fpga_manager *mgr; | |
371 | struct mpf_priv *priv; | |
372 | ||
373 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
374 | if (!priv) | |
375 | return -ENOMEM; | |
376 | ||
377 | priv->spi = spi; | |
378 | ||
379 | mgr = devm_fpga_mgr_register(dev, "Microchip Polarfire SPI FPGA Manager", | |
380 | &mpf_ops, priv); | |
381 | ||
382 | return PTR_ERR_OR_ZERO(mgr); | |
383 | } | |
384 | ||
385 | static const struct spi_device_id mpf_spi_ids[] = { | |
386 | { .name = "mpf-spi-fpga-mgr", }, | |
387 | {}, | |
388 | }; | |
389 | MODULE_DEVICE_TABLE(spi, mpf_spi_ids); | |
390 | ||
391 | #if IS_ENABLED(CONFIG_OF) | |
392 | static const struct of_device_id mpf_of_ids[] = { | |
393 | { .compatible = "microchip,mpf-spi-fpga-mgr" }, | |
394 | {}, | |
395 | }; | |
396 | MODULE_DEVICE_TABLE(of, mpf_of_ids); | |
397 | #endif /* IS_ENABLED(CONFIG_OF) */ | |
398 | ||
399 | static struct spi_driver mpf_driver = { | |
400 | .probe = mpf_probe, | |
401 | .id_table = mpf_spi_ids, | |
402 | .driver = { | |
403 | .name = "microchip_mpf_spi_fpga_mgr", | |
404 | .of_match_table = of_match_ptr(mpf_of_ids), | |
405 | }, | |
406 | }; | |
407 | ||
408 | module_spi_driver(mpf_driver); | |
409 | ||
410 | MODULE_DESCRIPTION("Microchip Polarfire SPI FPGA Manager"); | |
2a0805f5 | 411 | MODULE_AUTHOR("Ivan Bornyakov <[email protected]>"); |
5f8d4a90 | 412 | MODULE_LICENSE("GPL"); |