]> git.ipfire.org Git - thirdparty/u-boot.git/blame - drivers/fastboot/fb_command.c
Revert "Merge patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet""
[thirdparty/u-boot.git] / drivers / fastboot / fb_command.c
CommitLineData
f73a7df9
AK
1// SPDX-License-Identifier: BSD-2-Clause
2/*
3 * Copyright (C) 2016 The Android Open Source Project
4 */
5
d678a59d 6#include <common.h>
288b29e4 7#include <command.h>
85fcd69d 8#include <console.h>
c7694dd4 9#include <env.h>
f73a7df9
AK
10#include <fastboot.h>
11#include <fastboot-internal.h>
12#include <fb_mmc.h>
13#include <fb_nand.h>
14#include <part.h>
15#include <stdlib.h>
1e94b46f 16#include <linux/printk.h>
f73a7df9
AK
17
18/**
19 * image_size - final fastboot image size
20 */
21static u32 image_size;
22
23/**
24 * fastboot_bytes_received - number of bytes received in the current download
25 */
26static u32 fastboot_bytes_received;
27
28/**
29 * fastboot_bytes_expected - number of bytes expected in the current download
30 */
31static u32 fastboot_bytes_expected;
32
33static void okay(char *, char *);
34static void getvar(char *, char *);
35static void download(char *, char *);
f73a7df9
AK
36static void flash(char *, char *);
37static void erase(char *, char *);
f73a7df9 38static void reboot_bootloader(char *, char *);
2b2a771b
RK
39static void reboot_fastbootd(char *, char *);
40static void reboot_recovery(char *, char *);
3845b906 41static void oem_format(char *, char *);
b2f6b97b 42static void oem_partconf(char *, char *);
0c0394b5 43static void oem_bootbus(char *, char *);
16f79dd4 44static void oem_console(char *, char *);
b2acf59b 45static void oem_board(char *, char *);
bc820d5b
HS
46static void run_ucmd(char *, char *);
47static void run_acmd(char *, char *);
bc820d5b 48
f73a7df9
AK
49static const struct {
50 const char *command;
51 void (*dispatch)(char *cmd_parameter, char *response);
52} commands[FASTBOOT_COMMAND_COUNT] = {
53 [FASTBOOT_COMMAND_GETVAR] = {
54 .command = "getvar",
55 .dispatch = getvar
56 },
57 [FASTBOOT_COMMAND_DOWNLOAD] = {
58 .command = "download",
59 .dispatch = download
60 },
f73a7df9
AK
61 [FASTBOOT_COMMAND_FLASH] = {
62 .command = "flash",
d0379900 63 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_FLASH, (flash), (NULL))
f73a7df9
AK
64 },
65 [FASTBOOT_COMMAND_ERASE] = {
66 .command = "erase",
d0379900 67 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_FLASH, (erase), (NULL))
f73a7df9 68 },
f73a7df9
AK
69 [FASTBOOT_COMMAND_BOOT] = {
70 .command = "boot",
71 .dispatch = okay
72 },
73 [FASTBOOT_COMMAND_CONTINUE] = {
74 .command = "continue",
75 .dispatch = okay
76 },
77 [FASTBOOT_COMMAND_REBOOT] = {
78 .command = "reboot",
79 .dispatch = okay
80 },
81 [FASTBOOT_COMMAND_REBOOT_BOOTLOADER] = {
82 .command = "reboot-bootloader",
83 .dispatch = reboot_bootloader
84 },
2b2a771b
RK
85 [FASTBOOT_COMMAND_REBOOT_FASTBOOTD] = {
86 .command = "reboot-fastboot",
87 .dispatch = reboot_fastbootd
88 },
89 [FASTBOOT_COMMAND_REBOOT_RECOVERY] = {
90 .command = "reboot-recovery",
91 .dispatch = reboot_recovery
92 },
f73a7df9
AK
93 [FASTBOOT_COMMAND_SET_ACTIVE] = {
94 .command = "set_active",
95 .dispatch = okay
96 },
3845b906
AK
97 [FASTBOOT_COMMAND_OEM_FORMAT] = {
98 .command = "oem format",
d0379900 99 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT, (oem_format), (NULL))
3845b906 100 },
b2f6b97b
PD
101 [FASTBOOT_COMMAND_OEM_PARTCONF] = {
102 .command = "oem partconf",
d0379900 103 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF, (oem_partconf), (NULL))
b2f6b97b 104 },
0c0394b5
PD
105 [FASTBOOT_COMMAND_OEM_BOOTBUS] = {
106 .command = "oem bootbus",
d0379900 107 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS, (oem_bootbus), (NULL))
0c0394b5 108 },
f3d914cf
SA
109 [FASTBOOT_COMMAND_OEM_RUN] = {
110 .command = "oem run",
111 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_OEM_RUN, (run_ucmd), (NULL))
112 },
16f79dd4
IA
113 [FASTBOOT_COMMAND_OEM_CONSOLE] = {
114 .command = "oem console",
115 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONSOLE, (oem_console), (NULL))
116 },
b2acf59b
AR
117 [FASTBOOT_COMMAND_OEM_BOARD] = {
118 .command = "oem board",
119 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_OEM_BOARD, (oem_board), (NULL))
120 },
bc820d5b
HS
121 [FASTBOOT_COMMAND_UCMD] = {
122 .command = "UCmd",
d0379900 123 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_ucmd), (NULL))
bc820d5b
HS
124 },
125 [FASTBOOT_COMMAND_ACMD] = {
126 .command = "ACmd",
d0379900 127 .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_acmd), (NULL))
bc820d5b 128 },
f73a7df9
AK
129};
130
131/**
132 * fastboot_handle_command - Handle fastboot command
133 *
134 * @cmd_string: Pointer to command string
135 * @response: Pointer to fastboot response buffer
136 *
137 * Return: Executed command, or -1 if not recognized
138 */
139int fastboot_handle_command(char *cmd_string, char *response)
140{
141 int i;
142 char *cmd_parameter;
143
144 cmd_parameter = cmd_string;
145 strsep(&cmd_parameter, ":");
146
147 for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
148 if (!strcmp(commands[i].command, cmd_string)) {
149 if (commands[i].dispatch) {
150 commands[i].dispatch(cmd_parameter,
151 response);
152 return i;
153 } else {
d0379900
PD
154 pr_err("command %s not supported.\n", cmd_string);
155 fastboot_fail("Unsupported command", response);
156 return -1;
f73a7df9
AK
157 }
158 }
159 }
160
161 pr_err("command %s not recognized.\n", cmd_string);
162 fastboot_fail("unrecognized command", response);
163 return -1;
164}
165
85fcd69d
IA
166void fastboot_multiresponse(int cmd, char *response)
167{
168 switch (cmd) {
475aa9aa
IA
169 case FASTBOOT_COMMAND_GETVAR:
170 fastboot_getvar_all(response);
171 break;
16f79dd4
IA
172 case FASTBOOT_COMMAND_OEM_CONSOLE:
173 if (CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONSOLE)) {
174 char buf[FASTBOOT_RESPONSE_LEN] = { 0 };
175
176 if (console_record_isempty()) {
177 console_record_reset();
178 fastboot_okay(NULL, response);
179 } else {
180 int ret = console_record_readline(buf, sizeof(buf) - 5);
181
182 if (ret < 0)
183 fastboot_fail("Error reading console", response);
184 else
185 fastboot_response("INFO", response, "%s", buf);
186 }
187 break;
188 }
85fcd69d
IA
189 default:
190 fastboot_fail("Unknown multiresponse command", response);
191 break;
192 }
193}
194
f73a7df9
AK
195/**
196 * okay() - Send bare OKAY response
197 *
198 * @cmd_parameter: Pointer to command parameter
199 * @response: Pointer to fastboot response buffer
200 *
201 * Send a bare OKAY fastboot response. This is used where the command is
202 * valid, but all the work is done after the response has been sent (e.g.
203 * boot, reboot etc.)
204 */
205static void okay(char *cmd_parameter, char *response)
206{
207 fastboot_okay(NULL, response);
208}
209
210/**
211 * getvar() - Read a config/version variable
212 *
213 * @cmd_parameter: Pointer to command parameter
214 * @response: Pointer to fastboot response buffer
215 */
216static void getvar(char *cmd_parameter, char *response)
217{
218 fastboot_getvar(cmd_parameter, response);
219}
220
221/**
222 * fastboot_download() - Start a download transfer from the client
223 *
224 * @cmd_parameter: Pointer to command parameter
225 * @response: Pointer to fastboot response buffer
226 */
227static void download(char *cmd_parameter, char *response)
228{
229 char *tmp;
230
231 if (!cmd_parameter) {
232 fastboot_fail("Expected command parameter", response);
233 return;
234 }
235 fastboot_bytes_received = 0;
7e5f460e 236 fastboot_bytes_expected = hextoul(cmd_parameter, &tmp);
f73a7df9
AK
237 if (fastboot_bytes_expected == 0) {
238 fastboot_fail("Expected nonzero image size", response);
239 return;
240 }
241 /*
242 * Nothing to download yet. Response is of the form:
243 * [DATA|FAIL]$cmd_parameter
244 *
245 * where cmd_parameter is an 8 digit hexadecimal number
246 */
247 if (fastboot_bytes_expected > fastboot_buf_size) {
248 fastboot_fail(cmd_parameter, response);
249 } else {
250 printf("Starting download of %d bytes\n",
251 fastboot_bytes_expected);
252 fastboot_response("DATA", response, "%s", cmd_parameter);
253 }
254}
255
256/**
257 * fastboot_data_remaining() - return bytes remaining in current transfer
258 *
259 * Return: Number of bytes left in the current download
260 */
261u32 fastboot_data_remaining(void)
262{
263 return fastboot_bytes_expected - fastboot_bytes_received;
264}
265
266/**
267 * fastboot_data_download() - Copy image data to fastboot_buf_addr.
268 *
269 * @fastboot_data: Pointer to received fastboot data
270 * @fastboot_data_len: Length of received fastboot data
271 * @response: Pointer to fastboot response buffer
272 *
273 * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
274 * response. fastboot_bytes_received is updated to indicate the number
275 * of bytes that have been transferred.
276 *
277 * On completion sets image_size and ${filesize} to the total size of the
278 * downloaded image.
279 */
280void fastboot_data_download(const void *fastboot_data,
281 unsigned int fastboot_data_len,
282 char *response)
283{
284#define BYTES_PER_DOT 0x20000
285 u32 pre_dot_num, now_dot_num;
286
287 if (fastboot_data_len == 0 ||
288 (fastboot_bytes_received + fastboot_data_len) >
289 fastboot_bytes_expected) {
290 fastboot_fail("Received invalid data length",
291 response);
292 return;
293 }
294 /* Download data to fastboot_buf_addr */
cdd20e3f 295 memcpy(fastboot_buf_addr + fastboot_bytes_received,
f73a7df9
AK
296 fastboot_data, fastboot_data_len);
297
298 pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
299 fastboot_bytes_received += fastboot_data_len;
300 now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
301
302 if (pre_dot_num != now_dot_num) {
303 putc('.');
304 if (!(now_dot_num % 74))
305 putc('\n');
306 }
307 *response = '\0';
308}
309
310/**
311 * fastboot_data_complete() - Mark current transfer complete
312 *
313 * @response: Pointer to fastboot response buffer
314 *
315 * Set image_size and ${filesize} to the total size of the downloaded image.
316 */
317void fastboot_data_complete(char *response)
318{
319 /* Download complete. Respond with "OKAY" */
320 fastboot_okay(NULL, response);
321 printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
322 image_size = fastboot_bytes_received;
323 env_set_hex("filesize", image_size);
324 fastboot_bytes_expected = 0;
325 fastboot_bytes_received = 0;
326}
327
f73a7df9
AK
328/**
329 * flash() - write the downloaded image to the indicated partition.
330 *
331 * @cmd_parameter: Pointer to partition name
332 * @response: Pointer to fastboot response buffer
333 *
334 * Writes the previously downloaded image to the partition indicated by
335 * cmd_parameter. Writes to response.
336 */
d0379900 337static void __maybe_unused flash(char *cmd_parameter, char *response)
f73a7df9 338{
7cb10e51 339 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
cdd20e3f
TR
340 fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr,
341 image_size, response);
d0379900 342
c6228edf 343 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND))
cdd20e3f
TR
344 fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr,
345 image_size, response);
f73a7df9
AK
346}
347
348/**
349 * erase() - erase the indicated partition.
350 *
351 * @cmd_parameter: Pointer to partition name
352 * @response: Pointer to fastboot response buffer
353 *
354 * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
355 * to response.
356 */
d0379900 357static void __maybe_unused erase(char *cmd_parameter, char *response)
f73a7df9 358{
7cb10e51 359 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
d0379900
PD
360 fastboot_mmc_erase(cmd_parameter, response);
361
c6228edf 362 if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND))
d0379900 363 fastboot_nand_erase(cmd_parameter, response);
f73a7df9 364}
f73a7df9 365
bc820d5b
HS
366/**
367 * run_ucmd() - Execute the UCmd command
368 *
369 * @cmd_parameter: Pointer to command parameter
370 * @response: Pointer to fastboot response buffer
371 */
d0379900 372static void __maybe_unused run_ucmd(char *cmd_parameter, char *response)
bc820d5b
HS
373{
374 if (!cmd_parameter) {
375 pr_err("missing slot suffix\n");
376 fastboot_fail("missing command", response);
377 return;
378 }
379
380 if (run_command(cmd_parameter, 0))
381 fastboot_fail("", response);
382 else
383 fastboot_okay(NULL, response);
384}
385
386static char g_a_cmd_buff[64];
387
388void fastboot_acmd_complete(void)
389{
390 run_command(g_a_cmd_buff, 0);
391}
392
393/**
394 * run_acmd() - Execute the ACmd command
395 *
396 * @cmd_parameter: Pointer to command parameter
397 * @response: Pointer to fastboot response buffer
398 */
d0379900 399static void __maybe_unused run_acmd(char *cmd_parameter, char *response)
bc820d5b
HS
400{
401 if (!cmd_parameter) {
402 pr_err("missing slot suffix\n");
403 fastboot_fail("missing command", response);
404 return;
405 }
406
407 if (strlen(cmd_parameter) > sizeof(g_a_cmd_buff)) {
408 pr_err("too long command\n");
409 fastboot_fail("too long command", response);
410 return;
411 }
412
413 strcpy(g_a_cmd_buff, cmd_parameter);
414 fastboot_okay(NULL, response);
415}
bc820d5b 416
f73a7df9
AK
417/**
418 * reboot_bootloader() - Sets reboot bootloader flag.
419 *
420 * @cmd_parameter: Pointer to command parameter
421 * @response: Pointer to fastboot response buffer
422 */
423static void reboot_bootloader(char *cmd_parameter, char *response)
424{
851737ab 425 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_BOOTLOADER))
f73a7df9
AK
426 fastboot_fail("Cannot set reboot flag", response);
427 else
428 fastboot_okay(NULL, response);
429}
3845b906 430
2b2a771b
RK
431/**
432 * reboot_fastbootd() - Sets reboot fastboot flag.
433 *
434 * @cmd_parameter: Pointer to command parameter
435 * @response: Pointer to fastboot response buffer
436 */
437static void reboot_fastbootd(char *cmd_parameter, char *response)
438{
439 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_FASTBOOTD))
440 fastboot_fail("Cannot set fastboot flag", response);
441 else
442 fastboot_okay(NULL, response);
443}
444
445/**
446 * reboot_recovery() - Sets reboot recovery flag.
447 *
448 * @cmd_parameter: Pointer to command parameter
449 * @response: Pointer to fastboot response buffer
450 */
451static void reboot_recovery(char *cmd_parameter, char *response)
452{
453 if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_RECOVERY))
454 fastboot_fail("Cannot set recovery flag", response);
455 else
456 fastboot_okay(NULL, response);
457}
458
3845b906
AK
459/**
460 * oem_format() - Execute the OEM format command
461 *
462 * @cmd_parameter: Pointer to command parameter
463 * @response: Pointer to fastboot response buffer
464 */
d0379900 465static void __maybe_unused oem_format(char *cmd_parameter, char *response)
3845b906
AK
466{
467 char cmdbuf[32];
d0379900
PD
468 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
469 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
3845b906
AK
470
471 if (!env_get("partitions")) {
472 fastboot_fail("partitions not set", response);
473 } else {
d0379900 474 sprintf(cmdbuf, "gpt write mmc %x $partitions", mmc_dev);
3845b906
AK
475 if (run_command(cmdbuf, 0))
476 fastboot_fail("", response);
477 else
478 fastboot_okay(NULL, response);
479 }
480}
b2f6b97b 481
b2f6b97b
PD
482/**
483 * oem_partconf() - Execute the OEM partconf command
484 *
485 * @cmd_parameter: Pointer to command parameter
486 * @response: Pointer to fastboot response buffer
487 */
d0379900 488static void __maybe_unused oem_partconf(char *cmd_parameter, char *response)
b2f6b97b
PD
489{
490 char cmdbuf[32];
d0379900
PD
491 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
492 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
b2f6b97b
PD
493
494 if (!cmd_parameter) {
495 fastboot_fail("Expected command parameter", response);
496 return;
497 }
498
499 /* execute 'mmc partconfg' command with cmd_parameter arguments*/
d0379900 500 snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0", mmc_dev, cmd_parameter);
b2f6b97b
PD
501 printf("Execute: %s\n", cmdbuf);
502 if (run_command(cmdbuf, 0))
503 fastboot_fail("Cannot set oem partconf", response);
504 else
505 fastboot_okay(NULL, response);
506}
0c0394b5 507
0c0394b5
PD
508/**
509 * oem_bootbus() - Execute the OEM bootbus command
510 *
511 * @cmd_parameter: Pointer to command parameter
512 * @response: Pointer to fastboot response buffer
513 */
d0379900 514static void __maybe_unused oem_bootbus(char *cmd_parameter, char *response)
0c0394b5
PD
515{
516 char cmdbuf[32];
d0379900
PD
517 const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
518 CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
0c0394b5
PD
519
520 if (!cmd_parameter) {
521 fastboot_fail("Expected command parameter", response);
522 return;
523 }
524
525 /* execute 'mmc bootbus' command with cmd_parameter arguments*/
d0379900 526 snprintf(cmdbuf, sizeof(cmdbuf), "mmc bootbus %x %s", mmc_dev, cmd_parameter);
0c0394b5
PD
527 printf("Execute: %s\n", cmdbuf);
528 if (run_command(cmdbuf, 0))
529 fastboot_fail("Cannot set oem bootbus", response);
530 else
531 fastboot_okay(NULL, response);
532}
16f79dd4
IA
533
534/**
535 * oem_console() - Execute the OEM console command
536 *
537 * @cmd_parameter: Pointer to command parameter
538 * @response: Pointer to fastboot response buffer
539 */
540static void __maybe_unused oem_console(char *cmd_parameter, char *response)
541{
542 if (cmd_parameter)
543 console_in_puts(cmd_parameter);
544
545 if (console_record_isempty())
546 fastboot_fail("Empty console", response);
547 else
548 fastboot_response(FASTBOOT_MULTIRESPONSE_START, response, NULL);
549}
b2acf59b
AR
550
551/**
552 * fastboot_oem_board() - Execute the OEM board command. This is default
553 * weak implementation, which may be overwritten in board/ files.
554 *
555 * @cmd_parameter: Pointer to command parameter
556 * @data: Pointer to fastboot input buffer
557 * @size: Size of the fastboot input buffer
558 * @response: Pointer to fastboot response buffer
559 */
560void __weak fastboot_oem_board(char *cmd_parameter, void *data, u32 size, char *response)
561{
562 fastboot_fail("oem board function not defined", response);
563}
564
565/**
566 * oem_board() - Execute the OEM board command
567 *
568 * @cmd_parameter: Pointer to command parameter
569 * @response: Pointer to fastboot response buffer
570 */
571static void __maybe_unused oem_board(char *cmd_parameter, char *response)
572{
573 fastboot_oem_board(cmd_parameter, (void *)fastboot_buf_addr, image_size, response);
574}