1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * datasheet: https://www.nxp.com/docs/en/data-sheet/K20P144M120SF3.pdf |
4 | * |
5 | * Copyright (C) 2018-2021 Collabora |
6 | * Copyright (C) 2018-2021 GE Healthcare |
7 | */ |
8 | |
9 | #include <linux/delay.h> |
10 | #include <linux/firmware.h> |
11 | #include <linux/gpio/consumer.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> |
14 | #include <linux/of.h> |
15 | #include <linux/spi/spi.h> |
16 | |
17 | #define ACHC_MAX_FREQ_HZ 300000 |
18 | #define ACHC_FAST_READ_FREQ_HZ 1000000 |
19 | |
20 | struct achc_data { |
21 | struct spi_device *main; |
22 | struct spi_device *ezport; |
23 | struct gpio_desc *reset; |
24 | |
25 | struct mutex device_lock; /* avoid concurrent device access */ |
26 | }; |
27 | |
28 | #define EZPORT_RESET_DELAY_MS 100 |
29 | #define EZPORT_STARTUP_DELAY_MS 200 |
30 | #define EZPORT_WRITE_WAIT_MS 10 |
31 | #define EZPORT_TRANSFER_SIZE 2048 |
32 | |
33 | #define EZPORT_CMD_SP 0x02 /* flash section program */ |
34 | #define EZPORT_CMD_RDSR 0x05 /* read status register */ |
35 | #define EZPORT_CMD_WREN 0x06 /* write enable */ |
36 | #define EZPORT_CMD_FAST_READ 0x0b /* flash read data at high speed */ |
37 | #define EZPORT_CMD_RESET 0xb9 /* reset chip */ |
38 | #define EZPORT_CMD_BE 0xc7 /* bulk erase */ |
39 | #define EZPORT_CMD_SE 0xd8 /* sector erase */ |
40 | |
41 | #define EZPORT_SECTOR_SIZE 4096 |
42 | #define EZPORT_SECTOR_MASK (EZPORT_SECTOR_SIZE - 1) |
43 | |
44 | #define EZPORT_STATUS_WIP BIT(0) /* write in progress */ |
45 | #define EZPORT_STATUS_WEN BIT(1) /* write enable */ |
46 | #define EZPORT_STATUS_BEDIS BIT(2) /* bulk erase disable */ |
47 | #define EZPORT_STATUS_FLEXRAM BIT(3) /* FlexRAM mode */ |
48 | #define EZPORT_STATUS_WEF BIT(6) /* write error flag */ |
49 | #define EZPORT_STATUS_FS BIT(7) /* flash security */ |
50 | |
51 | static void ezport_reset(struct gpio_desc *reset) |
52 | { |
53 | gpiod_set_value(desc: reset, value: 1); |
54 | msleep(EZPORT_RESET_DELAY_MS); |
55 | gpiod_set_value(desc: reset, value: 0); |
56 | msleep(EZPORT_STARTUP_DELAY_MS); |
57 | } |
58 | |
59 | static int ezport_start_programming(struct spi_device *spi, struct gpio_desc *reset) |
60 | { |
61 | struct spi_message msg; |
62 | struct spi_transfer assert_cs = { |
63 | .cs_change = 1, |
64 | }; |
65 | struct spi_transfer release_cs = { }; |
66 | int ret; |
67 | |
68 | spi_bus_lock(ctlr: spi->controller); |
69 | |
70 | /* assert chip select */ |
71 | spi_message_init(m: &msg); |
72 | spi_message_add_tail(t: &assert_cs, m: &msg); |
73 | ret = spi_sync_locked(spi, message: &msg); |
74 | if (ret) |
75 | goto fail; |
76 | |
77 | msleep(EZPORT_STARTUP_DELAY_MS); |
78 | |
79 | /* reset with asserted chip select to switch into programming mode */ |
80 | ezport_reset(reset); |
81 | |
82 | /* release chip select */ |
83 | spi_message_init(m: &msg); |
84 | spi_message_add_tail(t: &release_cs, m: &msg); |
85 | ret = spi_sync_locked(spi, message: &msg); |
86 | |
87 | fail: |
88 | spi_bus_unlock(ctlr: spi->controller); |
89 | return ret; |
90 | } |
91 | |
92 | static void ezport_stop_programming(struct spi_device *spi, struct gpio_desc *reset) |
93 | { |
94 | /* reset without asserted chip select to return into normal mode */ |
95 | spi_bus_lock(ctlr: spi->controller); |
96 | ezport_reset(reset); |
97 | spi_bus_unlock(ctlr: spi->controller); |
98 | } |
99 | |
100 | static int ezport_get_status_register(struct spi_device *spi) |
101 | { |
102 | int ret; |
103 | |
104 | ret = spi_w8r8(spi, EZPORT_CMD_RDSR); |
105 | if (ret < 0) |
106 | return ret; |
107 | if (ret == 0xff) { |
108 | dev_err(&spi->dev, "Invalid EzPort status, EzPort is not functional!\n" ); |
109 | return -EINVAL; |
110 | } |
111 | |
112 | return ret; |
113 | } |
114 | |
115 | static int ezport_soft_reset(struct spi_device *spi) |
116 | { |
117 | u8 cmd = EZPORT_CMD_RESET; |
118 | int ret; |
119 | |
120 | ret = spi_write(spi, buf: &cmd, len: 1); |
121 | if (ret < 0) |
122 | return ret; |
123 | |
124 | msleep(EZPORT_STARTUP_DELAY_MS); |
125 | |
126 | return 0; |
127 | } |
128 | |
129 | static int ezport_send_simple(struct spi_device *spi, u8 cmd) |
130 | { |
131 | int ret; |
132 | |
133 | ret = spi_write(spi, buf: &cmd, len: 1); |
134 | if (ret < 0) |
135 | return ret; |
136 | |
137 | return ezport_get_status_register(spi); |
138 | } |
139 | |
140 | static int ezport_wait_write(struct spi_device *spi, u32 retries) |
141 | { |
142 | int ret; |
143 | u32 i; |
144 | |
145 | for (i = 0; i < retries; i++) { |
146 | ret = ezport_get_status_register(spi); |
147 | if (ret >= 0 && !(ret & EZPORT_STATUS_WIP)) |
148 | break; |
149 | msleep(EZPORT_WRITE_WAIT_MS); |
150 | } |
151 | |
152 | return ret; |
153 | } |
154 | |
155 | static int ezport_write_enable(struct spi_device *spi) |
156 | { |
157 | int ret = 0, retries = 3; |
158 | |
159 | for (retries = 0; retries < 3; retries++) { |
160 | ret = ezport_send_simple(spi, EZPORT_CMD_WREN); |
161 | if (ret > 0 && ret & EZPORT_STATUS_WEN) |
162 | break; |
163 | } |
164 | |
165 | if (!(ret & EZPORT_STATUS_WEN)) { |
166 | dev_err(&spi->dev, "EzPort write enable timed out\n" ); |
167 | return -ETIMEDOUT; |
168 | } |
169 | return 0; |
170 | } |
171 | |
172 | static int ezport_bulk_erase(struct spi_device *spi) |
173 | { |
174 | int ret; |
175 | static const u8 cmd = EZPORT_CMD_BE; |
176 | |
177 | dev_dbg(&spi->dev, "EzPort bulk erase...\n" ); |
178 | |
179 | ret = ezport_write_enable(spi); |
180 | if (ret < 0) |
181 | return ret; |
182 | |
183 | ret = spi_write(spi, buf: &cmd, len: 1); |
184 | if (ret < 0) |
185 | return ret; |
186 | |
187 | ret = ezport_wait_write(spi, retries: 1000); |
188 | if (ret < 0) |
189 | return ret; |
190 | |
191 | return 0; |
192 | } |
193 | |
194 | static int ezport_section_erase(struct spi_device *spi, u32 address) |
195 | { |
196 | u8 query[] = {EZPORT_CMD_SE, (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff}; |
197 | int ret; |
198 | |
199 | dev_dbg(&spi->dev, "Ezport section erase @ 0x%06x...\n" , address); |
200 | |
201 | if (address & EZPORT_SECTOR_MASK) |
202 | return -EINVAL; |
203 | |
204 | ret = ezport_write_enable(spi); |
205 | if (ret < 0) |
206 | return ret; |
207 | |
208 | ret = spi_write(spi, buf: query, len: sizeof(query)); |
209 | if (ret < 0) |
210 | return ret; |
211 | |
212 | return ezport_wait_write(spi, retries: 200); |
213 | } |
214 | |
215 | static int ezport_flash_transfer(struct spi_device *spi, u32 address, |
216 | const u8 *payload, size_t payload_size) |
217 | { |
218 | struct spi_transfer xfers[2] = {}; |
219 | u8 *command; |
220 | int ret; |
221 | |
222 | dev_dbg(&spi->dev, "EzPort write %zu bytes @ 0x%06x...\n" , payload_size, address); |
223 | |
224 | ret = ezport_write_enable(spi); |
225 | if (ret < 0) |
226 | return ret; |
227 | |
228 | command = kmalloc(size: 4, GFP_KERNEL | GFP_DMA); |
229 | if (!command) |
230 | return -ENOMEM; |
231 | |
232 | command[0] = EZPORT_CMD_SP; |
233 | command[1] = address >> 16; |
234 | command[2] = address >> 8; |
235 | command[3] = address >> 0; |
236 | |
237 | xfers[0].tx_buf = command; |
238 | xfers[0].len = 4; |
239 | |
240 | xfers[1].tx_buf = payload; |
241 | xfers[1].len = payload_size; |
242 | |
243 | ret = spi_sync_transfer(spi, xfers, num_xfers: 2); |
244 | kfree(objp: command); |
245 | if (ret < 0) |
246 | return ret; |
247 | |
248 | return ezport_wait_write(spi, retries: 40); |
249 | } |
250 | |
251 | static int ezport_flash_compare(struct spi_device *spi, u32 address, |
252 | const u8 *payload, size_t payload_size) |
253 | { |
254 | struct spi_transfer xfers[2] = {}; |
255 | u8 *buffer; |
256 | int ret; |
257 | |
258 | buffer = kmalloc(size: payload_size + 5, GFP_KERNEL | GFP_DMA); |
259 | if (!buffer) |
260 | return -ENOMEM; |
261 | |
262 | buffer[0] = EZPORT_CMD_FAST_READ; |
263 | buffer[1] = address >> 16; |
264 | buffer[2] = address >> 8; |
265 | buffer[3] = address >> 0; |
266 | |
267 | xfers[0].tx_buf = buffer; |
268 | xfers[0].len = 4; |
269 | xfers[0].speed_hz = ACHC_FAST_READ_FREQ_HZ; |
270 | |
271 | xfers[1].rx_buf = buffer + 4; |
272 | xfers[1].len = payload_size + 1; |
273 | xfers[1].speed_hz = ACHC_FAST_READ_FREQ_HZ; |
274 | |
275 | ret = spi_sync_transfer(spi, xfers, num_xfers: 2); |
276 | if (ret) |
277 | goto err; |
278 | |
279 | /* FAST_READ receives one dummy byte before the real data */ |
280 | ret = memcmp(p: payload, q: buffer + 4 + 1, size: payload_size); |
281 | if (ret) { |
282 | ret = -EBADMSG; |
283 | dev_dbg(&spi->dev, "Verification failure @ %06x" , address); |
284 | print_hex_dump_bytes("fw: " , DUMP_PREFIX_OFFSET, payload, payload_size); |
285 | print_hex_dump_bytes("dev: " , DUMP_PREFIX_OFFSET, buffer + 4, payload_size); |
286 | } |
287 | |
288 | err: |
289 | kfree(objp: buffer); |
290 | return ret; |
291 | } |
292 | |
293 | static int ezport_firmware_compare_data(struct spi_device *spi, |
294 | const u8 *data, size_t size) |
295 | { |
296 | int ret; |
297 | size_t address = 0; |
298 | size_t transfer_size; |
299 | |
300 | dev_dbg(&spi->dev, "EzPort compare data with %zu bytes...\n" , size); |
301 | |
302 | ret = ezport_get_status_register(spi); |
303 | if (ret < 0) |
304 | return ret; |
305 | |
306 | if (ret & EZPORT_STATUS_FS) { |
307 | dev_info(&spi->dev, "Device is in secure mode (status=0x%02x)!\n" , ret); |
308 | dev_info(&spi->dev, "FW verification is not possible\n" ); |
309 | return -EACCES; |
310 | } |
311 | |
312 | while (size - address > 0) { |
313 | transfer_size = min((size_t) EZPORT_TRANSFER_SIZE, size - address); |
314 | |
315 | ret = ezport_flash_compare(spi, address, payload: data+address, payload_size: transfer_size); |
316 | if (ret) |
317 | return ret; |
318 | |
319 | address += transfer_size; |
320 | } |
321 | |
322 | return 0; |
323 | } |
324 | |
325 | static int ezport_firmware_flash_data(struct spi_device *spi, |
326 | const u8 *data, size_t size) |
327 | { |
328 | int ret; |
329 | size_t address = 0; |
330 | size_t transfer_size; |
331 | |
332 | dev_dbg(&spi->dev, "EzPort flash data with %zu bytes...\n" , size); |
333 | |
334 | ret = ezport_get_status_register(spi); |
335 | if (ret < 0) |
336 | return ret; |
337 | |
338 | if (ret & EZPORT_STATUS_FS) { |
339 | ret = ezport_bulk_erase(spi); |
340 | if (ret < 0) |
341 | return ret; |
342 | if (ret & EZPORT_STATUS_FS) |
343 | return -EINVAL; |
344 | } |
345 | |
346 | while (size - address > 0) { |
347 | if (!(address & EZPORT_SECTOR_MASK)) { |
348 | ret = ezport_section_erase(spi, address); |
349 | if (ret < 0) |
350 | return ret; |
351 | if (ret & EZPORT_STATUS_WIP || ret & EZPORT_STATUS_WEF) |
352 | return -EIO; |
353 | } |
354 | |
355 | transfer_size = min((size_t) EZPORT_TRANSFER_SIZE, size - address); |
356 | |
357 | ret = ezport_flash_transfer(spi, address, |
358 | payload: data+address, payload_size: transfer_size); |
359 | if (ret < 0) |
360 | return ret; |
361 | else if (ret & EZPORT_STATUS_WIP) |
362 | return -ETIMEDOUT; |
363 | else if (ret & EZPORT_STATUS_WEF) |
364 | return -EIO; |
365 | |
366 | address += transfer_size; |
367 | } |
368 | |
369 | dev_dbg(&spi->dev, "EzPort verify flashed data...\n" ); |
370 | ret = ezport_firmware_compare_data(spi, data, size); |
371 | |
372 | /* allow missing FW verfication in secure mode */ |
373 | if (ret == -EACCES) |
374 | ret = 0; |
375 | |
376 | if (ret < 0) |
377 | dev_err(&spi->dev, "Failed to verify flashed data: %d\n" , ret); |
378 | |
379 | ret = ezport_soft_reset(spi); |
380 | if (ret < 0) |
381 | dev_warn(&spi->dev, "EzPort reset failed!\n" ); |
382 | |
383 | return ret; |
384 | } |
385 | |
386 | static int ezport_firmware_load(struct spi_device *spi, const char *fwname) |
387 | { |
388 | const struct firmware *fw; |
389 | int ret; |
390 | |
391 | ret = request_firmware(fw: &fw, name: fwname, device: &spi->dev); |
392 | if (ret) { |
393 | dev_err(&spi->dev, "Could not get firmware: %d\n" , ret); |
394 | return ret; |
395 | } |
396 | |
397 | ret = ezport_firmware_flash_data(spi, data: fw->data, size: fw->size); |
398 | |
399 | release_firmware(fw); |
400 | |
401 | return ret; |
402 | } |
403 | |
404 | /** |
405 | * ezport_flash - flash device firmware |
406 | * @spi: SPI device for NXP EzPort interface |
407 | * @reset: the gpio connected to the device reset pin |
408 | * @fwname: filename of the firmware that should be flashed |
409 | * |
410 | * Context: can sleep |
411 | * |
412 | * Return: 0 on success; negative errno on failure |
413 | */ |
414 | static int ezport_flash(struct spi_device *spi, struct gpio_desc *reset, const char *fwname) |
415 | { |
416 | int ret; |
417 | |
418 | ret = ezport_start_programming(spi, reset); |
419 | if (ret) |
420 | return ret; |
421 | |
422 | ret = ezport_firmware_load(spi, fwname); |
423 | |
424 | ezport_stop_programming(spi, reset); |
425 | |
426 | if (ret) |
427 | dev_err(&spi->dev, "Failed to flash firmware: %d\n" , ret); |
428 | else |
429 | dev_dbg(&spi->dev, "Finished FW flashing!\n" ); |
430 | |
431 | return ret; |
432 | } |
433 | |
434 | static ssize_t update_firmware_store(struct device *dev, struct device_attribute *attr, |
435 | const char *buf, size_t count) |
436 | { |
437 | struct achc_data *achc = dev_get_drvdata(dev); |
438 | unsigned long value; |
439 | int ret; |
440 | |
441 | ret = kstrtoul(s: buf, base: 0, res: &value); |
442 | if (ret < 0 || value != 1) |
443 | return -EINVAL; |
444 | |
445 | mutex_lock(&achc->device_lock); |
446 | ret = ezport_flash(spi: achc->ezport, reset: achc->reset, fwname: "achc.bin" ); |
447 | mutex_unlock(lock: &achc->device_lock); |
448 | |
449 | if (ret < 0) |
450 | return ret; |
451 | |
452 | return count; |
453 | } |
454 | static DEVICE_ATTR_WO(update_firmware); |
455 | |
456 | static ssize_t reset_show(struct device *dev, struct device_attribute *attr, char *buf) |
457 | { |
458 | struct achc_data *achc = dev_get_drvdata(dev); |
459 | int ret; |
460 | |
461 | mutex_lock(&achc->device_lock); |
462 | ret = gpiod_get_value(desc: achc->reset); |
463 | mutex_unlock(lock: &achc->device_lock); |
464 | |
465 | if (ret < 0) |
466 | return ret; |
467 | |
468 | return sysfs_emit(buf, fmt: "%d\n" , ret); |
469 | } |
470 | |
471 | static ssize_t reset_store(struct device *dev, struct device_attribute *attr, |
472 | const char *buf, size_t count) |
473 | { |
474 | struct achc_data *achc = dev_get_drvdata(dev); |
475 | unsigned long value; |
476 | int ret; |
477 | |
478 | ret = kstrtoul(s: buf, base: 0, res: &value); |
479 | if (ret < 0 || value > 1) |
480 | return -EINVAL; |
481 | |
482 | mutex_lock(&achc->device_lock); |
483 | gpiod_set_value(desc: achc->reset, value); |
484 | mutex_unlock(lock: &achc->device_lock); |
485 | |
486 | return count; |
487 | } |
488 | static DEVICE_ATTR_RW(reset); |
489 | |
490 | static struct attribute *gehc_achc_attrs[] = { |
491 | &dev_attr_update_firmware.attr, |
492 | &dev_attr_reset.attr, |
493 | NULL, |
494 | }; |
495 | ATTRIBUTE_GROUPS(gehc_achc); |
496 | |
497 | static void unregister_ezport(void *data) |
498 | { |
499 | struct spi_device *ezport = data; |
500 | |
501 | spi_unregister_device(spi: ezport); |
502 | } |
503 | |
504 | static int gehc_achc_probe(struct spi_device *spi) |
505 | { |
506 | struct achc_data *achc; |
507 | int ezport_reg, ret; |
508 | |
509 | spi->max_speed_hz = ACHC_MAX_FREQ_HZ; |
510 | spi->bits_per_word = 8; |
511 | spi->mode = SPI_MODE_0; |
512 | |
513 | achc = devm_kzalloc(dev: &spi->dev, size: sizeof(*achc), GFP_KERNEL); |
514 | if (!achc) |
515 | return -ENOMEM; |
516 | spi_set_drvdata(spi, data: achc); |
517 | achc->main = spi; |
518 | |
519 | mutex_init(&achc->device_lock); |
520 | |
521 | ret = of_property_read_u32_index(np: spi->dev.of_node, propname: "reg" , index: 1, out_value: &ezport_reg); |
522 | if (ret) |
523 | return dev_err_probe(dev: &spi->dev, err: ret, fmt: "missing second reg entry!\n" ); |
524 | |
525 | achc->ezport = spi_new_ancillary_device(spi, chip_select: ezport_reg); |
526 | if (IS_ERR(ptr: achc->ezport)) |
527 | return PTR_ERR(ptr: achc->ezport); |
528 | |
529 | ret = devm_add_action_or_reset(&spi->dev, unregister_ezport, achc->ezport); |
530 | if (ret) |
531 | return ret; |
532 | |
533 | achc->reset = devm_gpiod_get(dev: &spi->dev, con_id: "reset" , flags: GPIOD_OUT_LOW); |
534 | if (IS_ERR(ptr: achc->reset)) |
535 | return dev_err_probe(dev: &spi->dev, err: PTR_ERR(ptr: achc->reset), fmt: "Could not get reset gpio\n" ); |
536 | |
537 | return 0; |
538 | } |
539 | |
540 | static const struct spi_device_id gehc_achc_id[] = { |
541 | { "ge,achc" , 0 }, |
542 | { "achc" , 0 }, |
543 | { } |
544 | }; |
545 | MODULE_DEVICE_TABLE(spi, gehc_achc_id); |
546 | |
547 | static const struct of_device_id gehc_achc_of_match[] = { |
548 | { .compatible = "ge,achc" }, |
549 | { /* sentinel */ } |
550 | }; |
551 | MODULE_DEVICE_TABLE(of, gehc_achc_of_match); |
552 | |
553 | static struct spi_driver gehc_achc_spi_driver = { |
554 | .driver = { |
555 | .name = "gehc-achc" , |
556 | .of_match_table = gehc_achc_of_match, |
557 | .dev_groups = gehc_achc_groups, |
558 | }, |
559 | .probe = gehc_achc_probe, |
560 | .id_table = gehc_achc_id, |
561 | }; |
562 | module_spi_driver(gehc_achc_spi_driver); |
563 | |
564 | MODULE_DESCRIPTION("GEHC ACHC driver" ); |
565 | MODULE_AUTHOR("Sebastian Reichel <sebastian.reichel@collabora.com>" ); |
566 | MODULE_LICENSE("GPL" ); |
567 | |