Merge branch 'master' of git://git.denx.de/u-boot-usb
[platform/kernel/u-boot.git] / drivers / fastboot / fb_command.c
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2016 The Android Open Source Project
4  */
5
6 #include <common.h>
7 #include <command.h>
8 #include <env.h>
9 #include <fastboot.h>
10 #include <fastboot-internal.h>
11 #include <fb_mmc.h>
12 #include <fb_nand.h>
13 #include <flash.h>
14 #include <part.h>
15 #include <stdlib.h>
16
17 /**
18  * image_size - final fastboot image size
19  */
20 static u32 image_size;
21
22 /**
23  * fastboot_bytes_received - number of bytes received in the current download
24  */
25 static u32 fastboot_bytes_received;
26
27 /**
28  * fastboot_bytes_expected - number of bytes expected in the current download
29  */
30 static u32 fastboot_bytes_expected;
31
32 static void okay(char *, char *);
33 static void getvar(char *, char *);
34 static void download(char *, char *);
35 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
36 static void flash(char *, char *);
37 static void erase(char *, char *);
38 #endif
39 static void reboot_bootloader(char *, char *);
40 static void reboot_fastbootd(char *, char *);
41 static void reboot_recovery(char *, char *);
42 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
43 static void oem_format(char *, char *);
44 #endif
45 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
46 static void oem_partconf(char *, char *);
47 #endif
48 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
49 static void oem_bootbus(char *, char *);
50 #endif
51
52 static const struct {
53         const char *command;
54         void (*dispatch)(char *cmd_parameter, char *response);
55 } commands[FASTBOOT_COMMAND_COUNT] = {
56         [FASTBOOT_COMMAND_GETVAR] = {
57                 .command = "getvar",
58                 .dispatch = getvar
59         },
60         [FASTBOOT_COMMAND_DOWNLOAD] = {
61                 .command = "download",
62                 .dispatch = download
63         },
64 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
65         [FASTBOOT_COMMAND_FLASH] =  {
66                 .command = "flash",
67                 .dispatch = flash
68         },
69         [FASTBOOT_COMMAND_ERASE] =  {
70                 .command = "erase",
71                 .dispatch = erase
72         },
73 #endif
74         [FASTBOOT_COMMAND_BOOT] =  {
75                 .command = "boot",
76                 .dispatch = okay
77         },
78         [FASTBOOT_COMMAND_CONTINUE] =  {
79                 .command = "continue",
80                 .dispatch = okay
81         },
82         [FASTBOOT_COMMAND_REBOOT] =  {
83                 .command = "reboot",
84                 .dispatch = okay
85         },
86         [FASTBOOT_COMMAND_REBOOT_BOOTLOADER] =  {
87                 .command = "reboot-bootloader",
88                 .dispatch = reboot_bootloader
89         },
90         [FASTBOOT_COMMAND_REBOOT_FASTBOOTD] =  {
91                 .command = "reboot-fastboot",
92                 .dispatch = reboot_fastbootd
93         },
94         [FASTBOOT_COMMAND_REBOOT_RECOVERY] =  {
95                 .command = "reboot-recovery",
96                 .dispatch = reboot_recovery
97         },
98         [FASTBOOT_COMMAND_SET_ACTIVE] =  {
99                 .command = "set_active",
100                 .dispatch = okay
101         },
102 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
103         [FASTBOOT_COMMAND_OEM_FORMAT] = {
104                 .command = "oem format",
105                 .dispatch = oem_format,
106         },
107 #endif
108 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
109         [FASTBOOT_COMMAND_OEM_PARTCONF] = {
110                 .command = "oem partconf",
111                 .dispatch = oem_partconf,
112         },
113 #endif
114 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
115         [FASTBOOT_COMMAND_OEM_BOOTBUS] = {
116                 .command = "oem bootbus",
117                 .dispatch = oem_bootbus,
118         },
119 #endif
120 };
121
122 /**
123  * fastboot_handle_command - Handle fastboot command
124  *
125  * @cmd_string: Pointer to command string
126  * @response: Pointer to fastboot response buffer
127  *
128  * Return: Executed command, or -1 if not recognized
129  */
130 int fastboot_handle_command(char *cmd_string, char *response)
131 {
132         int i;
133         char *cmd_parameter;
134
135         cmd_parameter = cmd_string;
136         strsep(&cmd_parameter, ":");
137
138         for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
139                 if (!strcmp(commands[i].command, cmd_string)) {
140                         if (commands[i].dispatch) {
141                                 commands[i].dispatch(cmd_parameter,
142                                                         response);
143                                 return i;
144                         } else {
145                                 break;
146                         }
147                 }
148         }
149
150         pr_err("command %s not recognized.\n", cmd_string);
151         fastboot_fail("unrecognized command", response);
152         return -1;
153 }
154
155 /**
156  * okay() - Send bare OKAY response
157  *
158  * @cmd_parameter: Pointer to command parameter
159  * @response: Pointer to fastboot response buffer
160  *
161  * Send a bare OKAY fastboot response. This is used where the command is
162  * valid, but all the work is done after the response has been sent (e.g.
163  * boot, reboot etc.)
164  */
165 static void okay(char *cmd_parameter, char *response)
166 {
167         fastboot_okay(NULL, response);
168 }
169
170 /**
171  * getvar() - Read a config/version variable
172  *
173  * @cmd_parameter: Pointer to command parameter
174  * @response: Pointer to fastboot response buffer
175  */
176 static void getvar(char *cmd_parameter, char *response)
177 {
178         fastboot_getvar(cmd_parameter, response);
179 }
180
181 /**
182  * fastboot_download() - Start a download transfer from the client
183  *
184  * @cmd_parameter: Pointer to command parameter
185  * @response: Pointer to fastboot response buffer
186  */
187 static void download(char *cmd_parameter, char *response)
188 {
189         char *tmp;
190
191         if (!cmd_parameter) {
192                 fastboot_fail("Expected command parameter", response);
193                 return;
194         }
195         fastboot_bytes_received = 0;
196         fastboot_bytes_expected = simple_strtoul(cmd_parameter, &tmp, 16);
197         if (fastboot_bytes_expected == 0) {
198                 fastboot_fail("Expected nonzero image size", response);
199                 return;
200         }
201         /*
202          * Nothing to download yet. Response is of the form:
203          * [DATA|FAIL]$cmd_parameter
204          *
205          * where cmd_parameter is an 8 digit hexadecimal number
206          */
207         if (fastboot_bytes_expected > fastboot_buf_size) {
208                 fastboot_fail(cmd_parameter, response);
209         } else {
210                 printf("Starting download of %d bytes\n",
211                        fastboot_bytes_expected);
212                 fastboot_response("DATA", response, "%s", cmd_parameter);
213         }
214 }
215
216 /**
217  * fastboot_data_remaining() - return bytes remaining in current transfer
218  *
219  * Return: Number of bytes left in the current download
220  */
221 u32 fastboot_data_remaining(void)
222 {
223         return fastboot_bytes_expected - fastboot_bytes_received;
224 }
225
226 /**
227  * fastboot_data_download() - Copy image data to fastboot_buf_addr.
228  *
229  * @fastboot_data: Pointer to received fastboot data
230  * @fastboot_data_len: Length of received fastboot data
231  * @response: Pointer to fastboot response buffer
232  *
233  * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
234  * response. fastboot_bytes_received is updated to indicate the number
235  * of bytes that have been transferred.
236  *
237  * On completion sets image_size and ${filesize} to the total size of the
238  * downloaded image.
239  */
240 void fastboot_data_download(const void *fastboot_data,
241                             unsigned int fastboot_data_len,
242                             char *response)
243 {
244 #define BYTES_PER_DOT   0x20000
245         u32 pre_dot_num, now_dot_num;
246
247         if (fastboot_data_len == 0 ||
248             (fastboot_bytes_received + fastboot_data_len) >
249             fastboot_bytes_expected) {
250                 fastboot_fail("Received invalid data length",
251                               response);
252                 return;
253         }
254         /* Download data to fastboot_buf_addr */
255         memcpy(fastboot_buf_addr + fastboot_bytes_received,
256                fastboot_data, fastboot_data_len);
257
258         pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
259         fastboot_bytes_received += fastboot_data_len;
260         now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
261
262         if (pre_dot_num != now_dot_num) {
263                 putc('.');
264                 if (!(now_dot_num % 74))
265                         putc('\n');
266         }
267         *response = '\0';
268 }
269
270 /**
271  * fastboot_data_complete() - Mark current transfer complete
272  *
273  * @response: Pointer to fastboot response buffer
274  *
275  * Set image_size and ${filesize} to the total size of the downloaded image.
276  */
277 void fastboot_data_complete(char *response)
278 {
279         /* Download complete. Respond with "OKAY" */
280         fastboot_okay(NULL, response);
281         printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
282         image_size = fastboot_bytes_received;
283         env_set_hex("filesize", image_size);
284         fastboot_bytes_expected = 0;
285         fastboot_bytes_received = 0;
286 }
287
288 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
289 /**
290  * flash() - write the downloaded image to the indicated partition.
291  *
292  * @cmd_parameter: Pointer to partition name
293  * @response: Pointer to fastboot response buffer
294  *
295  * Writes the previously downloaded image to the partition indicated by
296  * cmd_parameter. Writes to response.
297  */
298 static void flash(char *cmd_parameter, char *response)
299 {
300 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
301         fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
302                                  response);
303 #endif
304 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
305         fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
306                                   response);
307 #endif
308 }
309
310 /**
311  * erase() - erase the indicated partition.
312  *
313  * @cmd_parameter: Pointer to partition name
314  * @response: Pointer to fastboot response buffer
315  *
316  * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
317  * to response.
318  */
319 static void erase(char *cmd_parameter, char *response)
320 {
321 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
322         fastboot_mmc_erase(cmd_parameter, response);
323 #endif
324 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
325         fastboot_nand_erase(cmd_parameter, response);
326 #endif
327 }
328 #endif
329
330 /**
331  * reboot_bootloader() - Sets reboot bootloader flag.
332  *
333  * @cmd_parameter: Pointer to command parameter
334  * @response: Pointer to fastboot response buffer
335  */
336 static void reboot_bootloader(char *cmd_parameter, char *response)
337 {
338         if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_BOOTLOADER))
339                 fastboot_fail("Cannot set reboot flag", response);
340         else
341                 fastboot_okay(NULL, response);
342 }
343
344 /**
345  * reboot_fastbootd() - Sets reboot fastboot flag.
346  *
347  * @cmd_parameter: Pointer to command parameter
348  * @response: Pointer to fastboot response buffer
349  */
350 static void reboot_fastbootd(char *cmd_parameter, char *response)
351 {
352         if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_FASTBOOTD))
353                 fastboot_fail("Cannot set fastboot flag", response);
354         else
355                 fastboot_okay(NULL, response);
356 }
357
358 /**
359  * reboot_recovery() - Sets reboot recovery flag.
360  *
361  * @cmd_parameter: Pointer to command parameter
362  * @response: Pointer to fastboot response buffer
363  */
364 static void reboot_recovery(char *cmd_parameter, char *response)
365 {
366         if (fastboot_set_reboot_flag(FASTBOOT_REBOOT_REASON_RECOVERY))
367                 fastboot_fail("Cannot set recovery flag", response);
368         else
369                 fastboot_okay(NULL, response);
370 }
371
372 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
373 /**
374  * oem_format() - Execute the OEM format command
375  *
376  * @cmd_parameter: Pointer to command parameter
377  * @response: Pointer to fastboot response buffer
378  */
379 static void oem_format(char *cmd_parameter, char *response)
380 {
381         char cmdbuf[32];
382
383         if (!env_get("partitions")) {
384                 fastboot_fail("partitions not set", response);
385         } else {
386                 sprintf(cmdbuf, "gpt write mmc %x $partitions",
387                         CONFIG_FASTBOOT_FLASH_MMC_DEV);
388                 if (run_command(cmdbuf, 0))
389                         fastboot_fail("", response);
390                 else
391                         fastboot_okay(NULL, response);
392         }
393 }
394 #endif
395
396 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_PARTCONF)
397 /**
398  * oem_partconf() - Execute the OEM partconf command
399  *
400  * @cmd_parameter: Pointer to command parameter
401  * @response: Pointer to fastboot response buffer
402  */
403 static void oem_partconf(char *cmd_parameter, char *response)
404 {
405         char cmdbuf[32];
406
407         if (!cmd_parameter) {
408                 fastboot_fail("Expected command parameter", response);
409                 return;
410         }
411
412         /* execute 'mmc partconfg' command with cmd_parameter arguments*/
413         snprintf(cmdbuf, sizeof(cmdbuf), "mmc partconf %x %s 0",
414                  CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
415         printf("Execute: %s\n", cmdbuf);
416         if (run_command(cmdbuf, 0))
417                 fastboot_fail("Cannot set oem partconf", response);
418         else
419                 fastboot_okay(NULL, response);
420 }
421 #endif
422
423 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
424 /**
425  * oem_bootbus() - Execute the OEM bootbus command
426  *
427  * @cmd_parameter: Pointer to command parameter
428  * @response: Pointer to fastboot response buffer
429  */
430 static void oem_bootbus(char *cmd_parameter, char *response)
431 {
432         char cmdbuf[32];
433
434         if (!cmd_parameter) {
435                 fastboot_fail("Expected command parameter", response);
436                 return;
437         }
438
439         /* execute 'mmc bootbus' command with cmd_parameter arguments*/
440         snprintf(cmdbuf, sizeof(cmdbuf), "mmc bootbus %x %s",
441                  CONFIG_FASTBOOT_FLASH_MMC_DEV, cmd_parameter);
442         printf("Execute: %s\n", cmdbuf);
443         if (run_command(cmdbuf, 0))
444                 fastboot_fail("Cannot set oem bootbus", response);
445         else
446                 fastboot_okay(NULL, response);
447 }
448 #endif