]>
Commit | Line | Data |
---|---|---|
468f0508 PD |
1 | // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause |
2 | /* | |
3 | * Copyright (C) 2020, STMicroelectronics - All Rights Reserved | |
4 | */ | |
5 | ||
d678a59d | 6 | #include <common.h> |
468f0508 | 7 | #include <console.h> |
a00867b4 | 8 | #include <dm.h> |
468f0508 PD |
9 | #include <dfu.h> |
10 | #include <malloc.h> | |
11 | #include <serial.h> | |
12 | #include <watchdog.h> | |
69446dee | 13 | #include <asm/arch/sys_proto.h> |
468f0508 PD |
14 | #include <dm/lists.h> |
15 | #include <dm/device-internal.h> | |
c05ed00a | 16 | #include <linux/delay.h> |
1e94b46f | 17 | #include <linux/printk.h> |
401d1c4f | 18 | #include <asm/global_data.h> |
468f0508 PD |
19 | #include "stm32prog.h" |
20 | ||
21 | /* - configuration part -----------------------------*/ | |
22 | #define USART_BL_VERSION 0x40 /* USART bootloader version V4.0*/ | |
23 | #define UBOOT_BL_VERSION 0x03 /* bootloader version V0.3*/ | |
69446dee | 24 | |
468f0508 PD |
25 | #define USART_RAM_BUFFER_SIZE 256 /* Size of USART_RAM_Buf buffer*/ |
26 | ||
27 | /* - Commands -----------------------------*/ | |
28 | #define GET_CMD_COMMAND 0x00 /* Get CMD command*/ | |
29 | #define GET_VER_COMMAND 0x01 /* Get Version command*/ | |
30 | #define GET_ID_COMMAND 0x02 /* Get ID command*/ | |
31 | #define GET_PHASE_COMMAND 0x03 /* Get Phase command*/ | |
32 | #define RM_COMMAND 0x11 /* Read Memory command*/ | |
33 | #define READ_PART_COMMAND 0x12 /* Read Partition command*/ | |
34 | #define START_COMMAND 0x21 /* START command (Go)*/ | |
35 | #define DOWNLOAD_COMMAND 0x31 /* Download command*/ | |
36 | /* existing command for other STM32 but not used */ | |
37 | /* ERASE 0x43 */ | |
38 | /* EXTENDED_ERASE 0x44 */ | |
39 | /* WRITE_UNPROTECTED 0x73 */ | |
40 | /* READOUT_PROTECT 0x82 */ | |
41 | /* READOUT_UNPROTECT 0x92 */ | |
42 | ||
43 | /* - miscellaneous defines ----------------------------------------*/ | |
44 | #define INIT_BYTE 0x7F /*Init Byte ID*/ | |
45 | #define ACK_BYTE 0x79 /*Acknowlede Byte ID*/ | |
46 | #define NACK_BYTE 0x1F /*No Acknowlede Byte ID*/ | |
47 | #define ABORT_BYTE 0x5F /*ABORT*/ | |
48 | ||
49 | struct udevice *down_serial_dev; | |
50 | ||
51 | const u8 cmd_id[] = { | |
52 | GET_CMD_COMMAND, | |
53 | GET_VER_COMMAND, | |
54 | GET_ID_COMMAND, | |
55 | GET_PHASE_COMMAND, | |
56 | RM_COMMAND, | |
57 | READ_PART_COMMAND, | |
58 | START_COMMAND, | |
59 | DOWNLOAD_COMMAND | |
60 | }; | |
61 | ||
62 | #define NB_CMD sizeof(cmd_id) | |
63 | ||
d4358a64 PD |
64 | /* with 115200 bauds, 20 ms allow to receive the 256 bytes buffer */ |
65 | #define TIMEOUT_SERIAL_BUFFER 30 | |
66 | ||
468f0508 PD |
67 | /* DFU support for serial *********************************************/ |
68 | static struct dfu_entity *stm32prog_get_entity(struct stm32prog_data *data) | |
69 | { | |
70 | int alt_id; | |
71 | ||
72 | if (!data->cur_part) | |
73 | if (data->phase == PHASE_FLASHLAYOUT) | |
74 | alt_id = 0; | |
75 | else | |
76 | return NULL; | |
77 | else | |
78 | alt_id = data->cur_part->alt_id; | |
79 | ||
80 | return dfu_get_entity(alt_id); | |
81 | } | |
82 | ||
83 | static int stm32prog_write(struct stm32prog_data *data, u8 *buffer, | |
84 | u32 buffer_size) | |
85 | { | |
86 | struct dfu_entity *dfu_entity; | |
87 | u8 ret = 0; | |
88 | ||
89 | dfu_entity = stm32prog_get_entity(data); | |
90 | if (!dfu_entity) | |
91 | return -ENODEV; | |
92 | ||
93 | ret = dfu_write(dfu_entity, | |
94 | buffer, | |
95 | buffer_size, | |
96 | data->dfu_seq); | |
97 | ||
98 | if (ret) { | |
99 | stm32prog_err("DFU write failed [%d] cnt: %d", | |
100 | ret, data->dfu_seq); | |
101 | } | |
102 | data->dfu_seq++; | |
103 | /* handle rollover as in driver/dfu/dfu.c */ | |
104 | data->dfu_seq &= 0xffff; | |
105 | if (buffer_size == 0) | |
106 | data->dfu_seq = 0; /* flush done */ | |
107 | ||
108 | return ret; | |
109 | } | |
110 | ||
111 | static int stm32prog_read(struct stm32prog_data *data, u8 phase, u32 offset, | |
112 | u8 *buffer, u32 buffer_size) | |
113 | { | |
114 | struct dfu_entity *dfu_entity; | |
115 | struct stm32prog_part_t *part; | |
116 | u32 size; | |
117 | int ret, i; | |
118 | ||
119 | if (data->dfu_seq) { | |
120 | stm32prog_err("DFU write pending for phase %d, seq %d", | |
121 | data->phase, data->dfu_seq); | |
122 | return -EINVAL; | |
123 | } | |
124 | if (phase == PHASE_FLASHLAYOUT || phase > PHASE_LAST_USER) { | |
125 | stm32prog_err("read failed : phase %d is invalid", phase); | |
126 | return -EINVAL; | |
127 | } | |
128 | if (data->read_phase <= PHASE_LAST_USER && | |
129 | phase != data->read_phase) { | |
130 | /* clear previous read session */ | |
131 | dfu_entity = dfu_get_entity(data->read_phase - 1); | |
132 | if (dfu_entity) | |
133 | dfu_transaction_cleanup(dfu_entity); | |
134 | } | |
135 | ||
136 | dfu_entity = NULL; | |
137 | /* found partition for the expected phase */ | |
138 | for (i = 0; i < data->part_nb; i++) { | |
139 | part = &data->part_array[i]; | |
140 | if (part->id == phase) | |
141 | dfu_entity = dfu_get_entity(part->alt_id); | |
142 | } | |
143 | if (!dfu_entity) { | |
144 | stm32prog_err("read failed : phase %d is unknown", phase); | |
145 | return -ENODEV; | |
146 | } | |
147 | ||
148 | /* clear pending read before to force offset */ | |
149 | if (dfu_entity->inited && | |
150 | (data->read_phase != phase || data->offset != offset)) | |
151 | dfu_transaction_cleanup(dfu_entity); | |
152 | ||
153 | /* initiate before to force offset */ | |
154 | if (!dfu_entity->inited) { | |
155 | ret = dfu_transaction_initiate(dfu_entity, true); | |
156 | if (ret < 0) { | |
157 | stm32prog_err("DFU read init failed [%d] phase = %d offset = 0x%08x", | |
158 | ret, phase, offset); | |
159 | return ret; | |
160 | } | |
161 | } | |
162 | /* force new offset */ | |
163 | if (dfu_entity->offset != offset) | |
164 | dfu_entity->offset = offset; | |
165 | data->offset = offset; | |
166 | data->read_phase = phase; | |
711b5bc0 PD |
167 | log_debug("\nSTM32 download read %s offset=0x%x\n", |
168 | dfu_entity->name, offset); | |
468f0508 PD |
169 | ret = dfu_read(dfu_entity, buffer, buffer_size, |
170 | dfu_entity->i_blk_seq_num); | |
171 | if (ret < 0) { | |
172 | stm32prog_err("DFU read failed [%d] phase = %d offset = 0x%08x", | |
173 | ret, phase, offset); | |
174 | return ret; | |
175 | } | |
176 | ||
177 | size = ret; | |
178 | ||
179 | if (size < buffer_size) { | |
180 | data->offset = 0; | |
181 | data->read_phase = PHASE_END; | |
182 | memset(buffer + size, 0, buffer_size - size); | |
183 | } else { | |
184 | data->offset += size; | |
185 | } | |
186 | ||
187 | return ret; | |
188 | } | |
189 | ||
190 | /* UART access ***************************************************/ | |
191 | int stm32prog_serial_init(struct stm32prog_data *data, int link_dev) | |
192 | { | |
193 | struct udevice *dev = NULL; | |
468f0508 PD |
194 | struct dm_serial_ops *ops; |
195 | /* no parity, 8 bits, 1 stop */ | |
196 | u32 serial_config = SERIAL_DEFAULT_CONFIG; | |
197 | ||
198 | down_serial_dev = NULL; | |
199 | ||
f49eb16c PD |
200 | if (uclass_get_device_by_seq(UCLASS_SERIAL, link_dev, &dev)) { |
201 | log_err("serial %d device not found\n", link_dev); | |
468f0508 PD |
202 | return -ENODEV; |
203 | } | |
204 | ||
f49eb16c PD |
205 | down_serial_dev = dev; |
206 | ||
468f0508 PD |
207 | /* force silent console on uart only when used */ |
208 | if (gd->cur_serial_dev == down_serial_dev) | |
209 | gd->flags |= GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT; | |
210 | else | |
211 | gd->flags &= ~(GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT); | |
212 | ||
213 | ops = serial_get_ops(down_serial_dev); | |
214 | ||
215 | if (!ops) { | |
f49eb16c | 216 | log_err("serial %d = %s missing ops\n", link_dev, dev->name); |
468f0508 PD |
217 | return -ENODEV; |
218 | } | |
219 | if (!ops->setconfig) { | |
f49eb16c | 220 | log_err("serial %d = %s missing setconfig\n", link_dev, dev->name); |
468f0508 PD |
221 | return -ENODEV; |
222 | } | |
223 | ||
224 | clrsetbits_le32(&serial_config, SERIAL_PAR_MASK, SERIAL_PAR_EVEN); | |
225 | ||
226 | data->buffer = memalign(CONFIG_SYS_CACHELINE_SIZE, | |
227 | USART_RAM_BUFFER_SIZE); | |
228 | ||
229 | return ops->setconfig(down_serial_dev, serial_config); | |
230 | } | |
231 | ||
232 | static void stm32prog_serial_flush(void) | |
233 | { | |
234 | struct dm_serial_ops *ops = serial_get_ops(down_serial_dev); | |
235 | int err; | |
236 | ||
237 | do { | |
238 | err = ops->getc(down_serial_dev); | |
239 | } while (err != -EAGAIN); | |
240 | } | |
241 | ||
242 | static int stm32prog_serial_getc_err(void) | |
243 | { | |
244 | struct dm_serial_ops *ops = serial_get_ops(down_serial_dev); | |
245 | int err; | |
246 | ||
247 | do { | |
248 | err = ops->getc(down_serial_dev); | |
249 | if (err == -EAGAIN) { | |
250 | ctrlc(); | |
29caf930 | 251 | schedule(); |
468f0508 PD |
252 | } |
253 | } while ((err == -EAGAIN) && (!had_ctrlc())); | |
254 | ||
255 | return err; | |
256 | } | |
257 | ||
258 | static u8 stm32prog_serial_getc(void) | |
259 | { | |
260 | int err; | |
261 | ||
262 | err = stm32prog_serial_getc_err(); | |
263 | ||
264 | return err >= 0 ? err : 0; | |
265 | } | |
266 | ||
267 | static bool stm32prog_serial_get_buffer(u8 *buffer, u32 *count) | |
268 | { | |
269 | struct dm_serial_ops *ops = serial_get_ops(down_serial_dev); | |
270 | int err; | |
d4358a64 | 271 | ulong start = get_timer(0); |
468f0508 PD |
272 | |
273 | do { | |
274 | err = ops->getc(down_serial_dev); | |
275 | if (err >= 0) { | |
276 | *buffer++ = err; | |
277 | *count -= 1; | |
278 | } else if (err == -EAGAIN) { | |
279 | ctrlc(); | |
29caf930 | 280 | schedule(); |
d4358a64 PD |
281 | if (get_timer(start) > TIMEOUT_SERIAL_BUFFER) { |
282 | err = -ETIMEDOUT; | |
283 | break; | |
284 | } | |
468f0508 PD |
285 | } else { |
286 | break; | |
287 | } | |
288 | } while (*count && !had_ctrlc()); | |
289 | ||
290 | return !!(err < 0); | |
291 | } | |
292 | ||
293 | static void stm32prog_serial_putc(u8 w_byte) | |
294 | { | |
295 | struct dm_serial_ops *ops = serial_get_ops(down_serial_dev); | |
296 | int err; | |
297 | ||
298 | do { | |
299 | err = ops->putc(down_serial_dev, w_byte); | |
300 | } while (err == -EAGAIN); | |
301 | } | |
302 | ||
303 | /* Helper function ************************************************/ | |
3df19b8b | 304 | static u8 stm32prog_start(struct stm32prog_data *data, uintptr_t address) |
468f0508 PD |
305 | { |
306 | u8 ret = 0; | |
307 | struct dfu_entity *dfu_entity; | |
308 | ||
309 | if (address < 0x100) { | |
310 | if (address == PHASE_OTP) | |
311 | return stm32prog_otp_start(data); | |
312 | ||
313 | if (address == PHASE_PMIC) | |
314 | return stm32prog_pmic_start(data); | |
315 | ||
316 | if (address == PHASE_RESET || address == PHASE_END) { | |
317 | data->cur_part = NULL; | |
318 | data->dfu_seq = 0; | |
319 | data->phase = address; | |
320 | return 0; | |
321 | } | |
322 | if (address != data->phase) { | |
323 | stm32prog_err("invalid received phase id %d, current phase is %d", | |
324 | (u8)address, (u8)data->phase); | |
325 | return -EINVAL; | |
326 | } | |
327 | } | |
328 | /* check the last loaded partition */ | |
329 | if (address == DEFAULT_ADDRESS || address == data->phase) { | |
330 | switch (data->phase) { | |
331 | case PHASE_END: | |
332 | case PHASE_RESET: | |
333 | case PHASE_DO_RESET: | |
334 | data->cur_part = NULL; | |
335 | data->phase = PHASE_DO_RESET; | |
336 | return 0; | |
337 | } | |
338 | dfu_entity = stm32prog_get_entity(data); | |
339 | if (!dfu_entity) | |
340 | return -ENODEV; | |
341 | ||
751f918b PD |
342 | ret = dfu_flush(dfu_entity, NULL, 0, data->dfu_seq); |
343 | if (ret) { | |
344 | stm32prog_err("DFU flush failed [%d]", ret); | |
345 | return ret; | |
468f0508 | 346 | } |
751f918b PD |
347 | data->dfu_seq = 0; |
348 | ||
468f0508 | 349 | printf("\n received length = 0x%x\n", data->cursor); |
468f0508 PD |
350 | |
351 | /* update DFU with received flashlayout */ | |
352 | if (data->phase == PHASE_FLASHLAYOUT) | |
353 | stm32prog_dfu_init(data); | |
354 | } else { | |
355 | void (*entry)(void) = (void *)address; | |
356 | ||
3df19b8b | 357 | printf("## Starting application at 0x%p ...\n", (void *)address); |
468f0508 PD |
358 | (*entry)(); |
359 | printf("## Application terminated\n"); | |
360 | ret = -ENOEXEC; | |
361 | } | |
362 | ||
363 | return ret; | |
364 | } | |
365 | ||
366 | /** | |
367 | * get_address() - Get address if it is valid | |
368 | * | |
369 | * @tmp_xor: Current xor value to update | |
185f812c | 370 | * Return: The address area |
468f0508 | 371 | */ |
3df19b8b | 372 | static uintptr_t get_address(u8 *tmp_xor) |
468f0508 | 373 | { |
3df19b8b | 374 | uintptr_t address = 0x0; |
468f0508 PD |
375 | u8 data; |
376 | ||
377 | data = stm32prog_serial_getc(); | |
378 | *tmp_xor ^= data; | |
379 | address |= ((u32)data) << 24; | |
380 | ||
381 | data = stm32prog_serial_getc(); | |
382 | address |= ((u32)data) << 16; | |
383 | *tmp_xor ^= data; | |
384 | ||
385 | data = stm32prog_serial_getc(); | |
386 | address |= ((u32)data) << 8; | |
387 | *tmp_xor ^= data; | |
388 | ||
389 | data = stm32prog_serial_getc(); | |
390 | address |= ((u32)data); | |
391 | *tmp_xor ^= data; | |
392 | ||
393 | return address; | |
394 | } | |
395 | ||
396 | static void stm32prog_serial_result(u8 result) | |
397 | { | |
398 | /* always flush fifo before to send result */ | |
399 | stm32prog_serial_flush(); | |
400 | stm32prog_serial_putc(result); | |
401 | } | |
402 | ||
403 | /* Command -----------------------------------------------*/ | |
404 | /** | |
405 | * get_cmd_command() - Respond to Get command | |
406 | * | |
407 | * @data: Current command context | |
408 | */ | |
409 | static void get_cmd_command(struct stm32prog_data *data) | |
410 | { | |
411 | u32 counter = 0x0; | |
412 | ||
413 | stm32prog_serial_putc(NB_CMD); | |
414 | stm32prog_serial_putc(USART_BL_VERSION); | |
415 | ||
416 | for (counter = 0; counter < NB_CMD; counter++) | |
417 | stm32prog_serial_putc(cmd_id[counter]); | |
418 | ||
419 | stm32prog_serial_result(ACK_BYTE); | |
420 | } | |
421 | ||
422 | /** | |
423 | * get_version_command() - Respond to Get Version command | |
424 | * | |
425 | * @data: Current command context | |
426 | */ | |
427 | static void get_version_command(struct stm32prog_data *data) | |
428 | { | |
429 | stm32prog_serial_putc(UBOOT_BL_VERSION); | |
430 | stm32prog_serial_result(ACK_BYTE); | |
431 | } | |
432 | ||
433 | /** | |
434 | * get_id_command() - Respond to Get ID command | |
435 | * | |
436 | * @data: Current command context | |
437 | */ | |
438 | static void get_id_command(struct stm32prog_data *data) | |
439 | { | |
69446dee PD |
440 | u32 cpu = get_cpu_dev(); |
441 | ||
468f0508 PD |
442 | /* Send Device IDCode */ |
443 | stm32prog_serial_putc(0x1); | |
69446dee PD |
444 | stm32prog_serial_putc((cpu >> 8) & 0xFF); |
445 | stm32prog_serial_putc(cpu & 0xFF); | |
468f0508 PD |
446 | stm32prog_serial_result(ACK_BYTE); |
447 | } | |
448 | ||
449 | /** | |
450 | * get_phase_command() - Respond to Get phase | |
451 | * | |
452 | * @data: Current command context | |
453 | */ | |
454 | static void get_phase_command(struct stm32prog_data *data) | |
455 | { | |
456 | char *err_msg = NULL; | |
457 | u8 i, length = 0; | |
458 | u32 destination = DEFAULT_ADDRESS; /* destination address */ | |
459 | int phase = data->phase; | |
460 | ||
461 | if (phase == PHASE_RESET || phase == PHASE_DO_RESET) { | |
462 | err_msg = stm32prog_get_error(data); | |
463 | length = strlen(err_msg); | |
464 | } | |
465 | if (phase == PHASE_FLASHLAYOUT) | |
ada8fe0c | 466 | destination = CONFIG_SYS_LOAD_ADDR; |
468f0508 PD |
467 | |
468 | stm32prog_serial_putc(length + 5); /* Total length */ | |
469 | stm32prog_serial_putc(phase & 0xFF); /* partition ID */ | |
470 | stm32prog_serial_putc(destination); /* byte 1 of address */ | |
471 | stm32prog_serial_putc(destination >> 8); /* byte 2 of address */ | |
472 | stm32prog_serial_putc(destination >> 16); /* byte 3 of address */ | |
473 | stm32prog_serial_putc(destination >> 24); /* byte 4 of address */ | |
474 | ||
475 | stm32prog_serial_putc(length); /* Information length */ | |
476 | for (i = 0; i < length; i++) | |
477 | stm32prog_serial_putc(err_msg[i]); | |
478 | stm32prog_serial_result(ACK_BYTE); | |
479 | ||
480 | if (phase == PHASE_RESET) | |
481 | stm32prog_do_reset(data); | |
482 | } | |
483 | ||
484 | /** | |
485 | * read_memory_command() - Read data from memory | |
486 | * | |
487 | * @data: Current command context | |
488 | */ | |
489 | static void read_memory_command(struct stm32prog_data *data) | |
490 | { | |
3df19b8b | 491 | uintptr_t address = 0x0; |
468f0508 PD |
492 | u8 rcv_data = 0x0, tmp_xor = 0x0; |
493 | u32 counter = 0x0; | |
494 | ||
495 | /* Read memory address */ | |
496 | address = get_address(&tmp_xor); | |
497 | ||
498 | /* If address memory is not received correctly */ | |
499 | rcv_data = stm32prog_serial_getc(); | |
500 | if (rcv_data != tmp_xor) { | |
501 | stm32prog_serial_result(NACK_BYTE); | |
502 | return; | |
503 | } | |
504 | ||
505 | stm32prog_serial_result(ACK_BYTE); | |
506 | ||
507 | /* Read the number of bytes to be received: | |
508 | * Max NbrOfData = Data + 1 = 256 | |
509 | */ | |
510 | rcv_data = stm32prog_serial_getc(); | |
511 | tmp_xor = ~rcv_data; | |
512 | if (stm32prog_serial_getc() != tmp_xor) { | |
513 | stm32prog_serial_result(NACK_BYTE); | |
514 | return; | |
515 | } | |
516 | ||
517 | /* If checksum is correct send ACK */ | |
518 | stm32prog_serial_result(ACK_BYTE); | |
519 | ||
520 | /* Send data to the host: | |
521 | * Number of data to read = data + 1 | |
522 | */ | |
523 | for (counter = (rcv_data + 1); counter != 0; counter--) | |
524 | stm32prog_serial_putc(*(u8 *)(address++)); | |
525 | } | |
526 | ||
527 | /** | |
528 | * start_command() - Respond to start command | |
529 | * | |
530 | * Jump to user application in RAM or partition check | |
531 | * | |
532 | * @data: Current command context | |
533 | */ | |
534 | static void start_command(struct stm32prog_data *data) | |
535 | { | |
3df19b8b | 536 | uintptr_t address = 0; |
468f0508 PD |
537 | u8 tmp_xor = 0x0; |
538 | u8 ret, rcv_data; | |
539 | ||
540 | /* Read memory address */ | |
541 | address = get_address(&tmp_xor); | |
542 | ||
543 | /* If address memory is not received correctly */ | |
544 | rcv_data = stm32prog_serial_getc(); | |
545 | if (rcv_data != tmp_xor) { | |
546 | stm32prog_serial_result(NACK_BYTE); | |
547 | return; | |
548 | } | |
549 | /* validate partition */ | |
3df19b8b | 550 | ret = stm32prog_start(data, address); |
468f0508 PD |
551 | |
552 | if (ret) | |
553 | stm32prog_serial_result(ABORT_BYTE); | |
554 | else | |
555 | stm32prog_serial_result(ACK_BYTE); | |
556 | } | |
557 | ||
558 | /** | |
559 | * download_command() - Respond to download command | |
560 | * | |
561 | * Write data to not volatile memory, Flash | |
562 | * | |
563 | * @data: Current command context | |
564 | */ | |
565 | static void download_command(struct stm32prog_data *data) | |
566 | { | |
567 | u32 address = 0x0; | |
568 | u8 my_xor = 0x0; | |
569 | u8 rcv_xor; | |
570 | u32 counter = 0x0, codesize = 0x0; | |
571 | u8 *ramaddress = 0; | |
572 | u8 rcv_data = 0x0; | |
468f0508 PD |
573 | u32 cursor = data->cursor; |
574 | long size = 0; | |
575 | u8 operation; | |
576 | u32 packet_number; | |
577 | u32 result = ACK_BYTE; | |
578 | u8 ret; | |
468f0508 PD |
579 | bool error; |
580 | int rcv; | |
581 | ||
582 | address = get_address(&my_xor); | |
583 | ||
584 | /* If address memory is not received correctly */ | |
585 | rcv_xor = stm32prog_serial_getc(); | |
586 | if (rcv_xor != my_xor) { | |
587 | result = NACK_BYTE; | |
588 | goto end; | |
589 | } | |
590 | ||
591 | /* If address valid send ACK */ | |
592 | stm32prog_serial_result(ACK_BYTE); | |
593 | ||
594 | /* get packet number and operation type */ | |
595 | operation = (u8)((u32)address >> 24); | |
596 | packet_number = ((u32)(((u32)address << 8))) >> 8; | |
597 | ||
598 | switch (operation) { | |
599 | /* supported operation */ | |
600 | case PHASE_FLASHLAYOUT: | |
601 | case PHASE_OTP: | |
602 | case PHASE_PMIC: | |
603 | break; | |
604 | default: | |
605 | result = NACK_BYTE; | |
606 | goto end; | |
607 | } | |
608 | /* check the packet number */ | |
609 | if (packet_number == 0) { | |
610 | /* erase: re-initialize the image_header struct */ | |
611 | data->packet_number = 0; | |
468f0508 PD |
612 | cursor = 0; |
613 | data->cursor = 0; | |
468f0508 PD |
614 | /*idx = cursor;*/ |
615 | } else { | |
616 | data->packet_number++; | |
617 | } | |
618 | ||
619 | /* Check with the number of current packet if the device receive | |
620 | * the true packet | |
621 | */ | |
622 | if (packet_number != data->packet_number) { | |
623 | data->packet_number--; | |
624 | result = NACK_BYTE; | |
625 | goto end; | |
626 | } | |
627 | ||
628 | /*-- Read number of bytes to be written and data -----------*/ | |
629 | ||
630 | /* Read the number of bytes to be written: | |
631 | * Max NbrOfData = data + 1 <= 256 | |
632 | */ | |
633 | rcv_data = stm32prog_serial_getc(); | |
634 | ||
635 | /* NbrOfData to write = data + 1 */ | |
636 | codesize = rcv_data + 0x01; | |
637 | ||
638 | if (codesize > USART_RAM_BUFFER_SIZE) { | |
639 | result = NACK_BYTE; | |
640 | goto end; | |
641 | } | |
642 | ||
643 | /* Checksum Initialization */ | |
644 | my_xor = rcv_data; | |
645 | ||
646 | /* UART receive data and send to Buffer */ | |
647 | counter = codesize; | |
648 | error = stm32prog_serial_get_buffer(data->buffer, &counter); | |
649 | ||
650 | /* read checksum */ | |
651 | if (!error) { | |
652 | rcv = stm32prog_serial_getc_err(); | |
653 | error = !!(rcv < 0); | |
654 | rcv_xor = rcv; | |
655 | } | |
656 | ||
657 | if (error) { | |
658 | printf("transmission error on packet %d, byte %d\n", | |
659 | packet_number, codesize - counter); | |
660 | /* waiting end of packet before flush & NACK */ | |
d4358a64 | 661 | mdelay(TIMEOUT_SERIAL_BUFFER); |
468f0508 PD |
662 | data->packet_number--; |
663 | result = NACK_BYTE; | |
664 | goto end; | |
665 | } | |
666 | ||
667 | /* Compute Checksum */ | |
668 | ramaddress = data->buffer; | |
669 | for (counter = codesize; counter != 0; counter--) | |
670 | my_xor ^= *(ramaddress++); | |
671 | ||
672 | /* If Checksum is incorrect */ | |
673 | if (rcv_xor != my_xor) { | |
674 | printf("checksum error on packet %d\n", | |
675 | packet_number); | |
676 | /* wait to be sure that all data are received | |
677 | * in the FIFO before flush | |
678 | */ | |
d4358a64 | 679 | mdelay(TIMEOUT_SERIAL_BUFFER); |
468f0508 PD |
680 | data->packet_number--; |
681 | result = NACK_BYTE; | |
682 | goto end; | |
683 | } | |
684 | ||
5f14e2fe PD |
685 | switch (operation) { |
686 | case PHASE_OTP: | |
687 | size = codesize; | |
688 | ret = stm32prog_otp_write(data, cursor, data->buffer, &size); | |
689 | break; | |
468f0508 | 690 | |
5f14e2fe PD |
691 | case PHASE_PMIC: |
692 | size = codesize; | |
693 | ret = stm32prog_pmic_write(data, cursor, data->buffer, &size); | |
694 | break; | |
468f0508 | 695 | |
5f14e2fe PD |
696 | default: |
697 | ret = stm32prog_write(data, data->buffer, codesize); | |
698 | break; | |
468f0508 PD |
699 | } |
700 | ||
468f0508 PD |
701 | if (ret) |
702 | result = ABORT_BYTE; | |
5f14e2fe PD |
703 | else |
704 | /* Update current position in buffer */ | |
705 | data->cursor += codesize; | |
468f0508 PD |
706 | |
707 | end: | |
708 | stm32prog_serial_result(result); | |
709 | } | |
710 | ||
711 | /** | |
712 | * read_partition() - Respond to read command | |
713 | * | |
714 | * Read data from not volatile memory, Flash | |
715 | * | |
716 | * @data: Current command context | |
717 | */ | |
718 | static void read_partition_command(struct stm32prog_data *data) | |
719 | { | |
720 | u32 i, part_id, codesize, offset = 0, rcv_data; | |
721 | long size; | |
722 | u8 tmp_xor; | |
723 | int res; | |
724 | u8 buffer[256]; | |
725 | ||
726 | part_id = stm32prog_serial_getc(); | |
727 | tmp_xor = part_id; | |
728 | ||
729 | offset = get_address(&tmp_xor); | |
730 | ||
731 | rcv_data = stm32prog_serial_getc(); | |
732 | if (rcv_data != tmp_xor) { | |
711b5bc0 PD |
733 | log_debug("1st checksum received = %x, computed %x\n", |
734 | rcv_data, tmp_xor); | |
468f0508 PD |
735 | goto error; |
736 | } | |
737 | stm32prog_serial_putc(ACK_BYTE); | |
738 | ||
739 | /* NbrOfData to read = data + 1 */ | |
740 | rcv_data = stm32prog_serial_getc(); | |
741 | codesize = rcv_data + 0x01; | |
742 | tmp_xor = rcv_data; | |
743 | ||
744 | rcv_data = stm32prog_serial_getc(); | |
745 | if ((rcv_data ^ tmp_xor) != 0xFF) { | |
711b5bc0 PD |
746 | log_debug("2nd checksum received = %x, computed %x\n", |
747 | rcv_data, tmp_xor); | |
468f0508 PD |
748 | goto error; |
749 | } | |
750 | ||
711b5bc0 | 751 | log_debug("%s : %x\n", __func__, part_id); |
468f0508 PD |
752 | rcv_data = 0; |
753 | switch (part_id) { | |
754 | case PHASE_OTP: | |
755 | size = codesize; | |
756 | if (!stm32prog_otp_read(data, offset, buffer, &size)) | |
757 | rcv_data = size; | |
758 | break; | |
759 | case PHASE_PMIC: | |
760 | size = codesize; | |
761 | if (!stm32prog_pmic_read(data, offset, buffer, &size)) | |
762 | rcv_data = size; | |
763 | break; | |
764 | default: | |
765 | res = stm32prog_read(data, part_id, offset, | |
766 | buffer, codesize); | |
767 | if (res > 0) | |
768 | rcv_data = res; | |
769 | break; | |
770 | } | |
771 | if (rcv_data > 0) { | |
772 | stm32prog_serial_putc(ACK_BYTE); | |
773 | /*----------- Send data to the host -----------*/ | |
774 | for (i = 0; i < rcv_data; i++) | |
775 | stm32prog_serial_putc(buffer[i]); | |
776 | /*----------- Send filler to the host -----------*/ | |
777 | for (; i < codesize; i++) | |
778 | stm32prog_serial_putc(0x0); | |
779 | return; | |
780 | } | |
781 | stm32prog_serial_result(ABORT_BYTE); | |
782 | return; | |
783 | ||
784 | error: | |
785 | stm32prog_serial_result(NACK_BYTE); | |
786 | } | |
787 | ||
788 | /* MAIN function = SERIAL LOOP ***********************************************/ | |
789 | ||
790 | /** | |
791 | * stm32prog_serial_loop() - USART bootloader Loop routine | |
792 | * | |
793 | * @data: Current command context | |
185f812c | 794 | * Return: true if reset is needed after loop |
468f0508 PD |
795 | */ |
796 | bool stm32prog_serial_loop(struct stm32prog_data *data) | |
797 | { | |
798 | u32 counter = 0x0; | |
799 | u8 command = 0x0; | |
800 | u8 found; | |
801 | int phase = data->phase; | |
802 | ||
803 | /* element of cmd_func need to aligned with cmd_id[]*/ | |
804 | void (*cmd_func[NB_CMD])(struct stm32prog_data *) = { | |
805 | /* GET_CMD_COMMAND */ get_cmd_command, | |
806 | /* GET_VER_COMMAND */ get_version_command, | |
807 | /* GET_ID_COMMAND */ get_id_command, | |
808 | /* GET_PHASE_COMMAND */ get_phase_command, | |
809 | /* RM_COMMAND */ read_memory_command, | |
810 | /* READ_PART_COMMAND */ read_partition_command, | |
811 | /* START_COMMAND */ start_command, | |
812 | /* DOWNLOAD_COMMAND */ download_command | |
813 | }; | |
814 | ||
815 | /* flush and NACK pending command received during u-boot init | |
816 | * request command reemit | |
817 | */ | |
818 | stm32prog_serial_result(NACK_BYTE); | |
819 | ||
820 | clear_ctrlc(); /* forget any previous Control C */ | |
821 | while (!had_ctrlc()) { | |
822 | phase = data->phase; | |
823 | ||
824 | if (phase == PHASE_DO_RESET) | |
825 | return true; | |
826 | ||
827 | /* Get the user command: read first byte */ | |
828 | command = stm32prog_serial_getc(); | |
829 | ||
830 | if (command == INIT_BYTE) { | |
831 | puts("\nConnected\n"); | |
832 | stm32prog_serial_result(ACK_BYTE); | |
833 | continue; | |
834 | } | |
835 | ||
836 | found = 0; | |
837 | for (counter = 0; counter < NB_CMD; counter++) | |
838 | if (cmd_id[counter] == command) { | |
839 | found = 1; | |
840 | break; | |
841 | } | |
842 | if (found) | |
843 | if ((command ^ stm32prog_serial_getc()) != 0xFF) | |
844 | found = 0; | |
845 | if (!found) { | |
846 | /* wait to be sure that all data are received | |
847 | * in the FIFO before flush (CMD and XOR) | |
848 | */ | |
849 | mdelay(3); | |
850 | stm32prog_serial_result(NACK_BYTE); | |
851 | } else { | |
852 | stm32prog_serial_result(ACK_BYTE); | |
853 | cmd_func[counter](data); | |
854 | } | |
29caf930 | 855 | schedule(); |
468f0508 PD |
856 | } |
857 | ||
858 | /* clean device */ | |
859 | if (gd->cur_serial_dev == down_serial_dev) { | |
860 | /* restore console on uart */ | |
861 | gd->flags &= ~(GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT); | |
862 | } | |
863 | down_serial_dev = NULL; | |
864 | ||
865 | return false; /* no reset after ctrlc */ | |
866 | } |