Merge tag 'u-boot-rockchip-20200501' of https://gitlab.denx.de/u-boot/custodians...
[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 <part.h>
14 #include <stdlib.h>
15
16 /**
17  * image_size - final fastboot image size
18  */
19 static u32 image_size;
20
21 /**
22  * fastboot_bytes_received - number of bytes received in the current download
23  */
24 static u32 fastboot_bytes_received;
25
26 /**
27  * fastboot_bytes_expected - number of bytes expected in the current download
28  */
29 static u32 fastboot_bytes_expected;
30
31 static void okay(char *, char *);
32 static void getvar(char *, char *);
33 static void download(char *, char *);
34 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
35 static void flash(char *, char *);
36 static void erase(char *, char *);
37 #endif
38 static void reboot_bootloader(char *, char *);
39 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
40 static void oem_format(char *, char *);
41 #endif
42
43 static const struct {
44         const char *command;
45         void (*dispatch)(char *cmd_parameter, char *response);
46 } commands[FASTBOOT_COMMAND_COUNT] = {
47         [FASTBOOT_COMMAND_GETVAR] = {
48                 .command = "getvar",
49                 .dispatch = getvar
50         },
51         [FASTBOOT_COMMAND_DOWNLOAD] = {
52                 .command = "download",
53                 .dispatch = download
54         },
55 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
56         [FASTBOOT_COMMAND_FLASH] =  {
57                 .command = "flash",
58                 .dispatch = flash
59         },
60         [FASTBOOT_COMMAND_ERASE] =  {
61                 .command = "erase",
62                 .dispatch = erase
63         },
64 #endif
65         [FASTBOOT_COMMAND_BOOT] =  {
66                 .command = "boot",
67                 .dispatch = okay
68         },
69         [FASTBOOT_COMMAND_CONTINUE] =  {
70                 .command = "continue",
71                 .dispatch = okay
72         },
73         [FASTBOOT_COMMAND_REBOOT] =  {
74                 .command = "reboot",
75                 .dispatch = okay
76         },
77         [FASTBOOT_COMMAND_REBOOT_BOOTLOADER] =  {
78                 .command = "reboot-bootloader",
79                 .dispatch = reboot_bootloader
80         },
81         [FASTBOOT_COMMAND_SET_ACTIVE] =  {
82                 .command = "set_active",
83                 .dispatch = okay
84         },
85 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
86         [FASTBOOT_COMMAND_OEM_FORMAT] = {
87                 .command = "oem format",
88                 .dispatch = oem_format,
89         },
90 #endif
91 };
92
93 /**
94  * fastboot_handle_command - Handle fastboot command
95  *
96  * @cmd_string: Pointer to command string
97  * @response: Pointer to fastboot response buffer
98  *
99  * Return: Executed command, or -1 if not recognized
100  */
101 int fastboot_handle_command(char *cmd_string, char *response)
102 {
103         int i;
104         char *cmd_parameter;
105
106         cmd_parameter = cmd_string;
107         strsep(&cmd_parameter, ":");
108
109         for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
110                 if (!strcmp(commands[i].command, cmd_string)) {
111                         if (commands[i].dispatch) {
112                                 commands[i].dispatch(cmd_parameter,
113                                                         response);
114                                 return i;
115                         } else {
116                                 break;
117                         }
118                 }
119         }
120
121         pr_err("command %s not recognized.\n", cmd_string);
122         fastboot_fail("unrecognized command", response);
123         return -1;
124 }
125
126 /**
127  * okay() - Send bare OKAY response
128  *
129  * @cmd_parameter: Pointer to command parameter
130  * @response: Pointer to fastboot response buffer
131  *
132  * Send a bare OKAY fastboot response. This is used where the command is
133  * valid, but all the work is done after the response has been sent (e.g.
134  * boot, reboot etc.)
135  */
136 static void okay(char *cmd_parameter, char *response)
137 {
138         fastboot_okay(NULL, response);
139 }
140
141 /**
142  * getvar() - Read a config/version variable
143  *
144  * @cmd_parameter: Pointer to command parameter
145  * @response: Pointer to fastboot response buffer
146  */
147 static void getvar(char *cmd_parameter, char *response)
148 {
149         fastboot_getvar(cmd_parameter, response);
150 }
151
152 /**
153  * fastboot_download() - Start a download transfer from the client
154  *
155  * @cmd_parameter: Pointer to command parameter
156  * @response: Pointer to fastboot response buffer
157  */
158 static void download(char *cmd_parameter, char *response)
159 {
160         char *tmp;
161
162         if (!cmd_parameter) {
163                 fastboot_fail("Expected command parameter", response);
164                 return;
165         }
166         fastboot_bytes_received = 0;
167         fastboot_bytes_expected = simple_strtoul(cmd_parameter, &tmp, 16);
168         if (fastboot_bytes_expected == 0) {
169                 fastboot_fail("Expected nonzero image size", response);
170                 return;
171         }
172         /*
173          * Nothing to download yet. Response is of the form:
174          * [DATA|FAIL]$cmd_parameter
175          *
176          * where cmd_parameter is an 8 digit hexadecimal number
177          */
178         if (fastboot_bytes_expected > fastboot_buf_size) {
179                 fastboot_fail(cmd_parameter, response);
180         } else {
181                 printf("Starting download of %d bytes\n",
182                        fastboot_bytes_expected);
183                 fastboot_response("DATA", response, "%s", cmd_parameter);
184         }
185 }
186
187 /**
188  * fastboot_data_remaining() - return bytes remaining in current transfer
189  *
190  * Return: Number of bytes left in the current download
191  */
192 u32 fastboot_data_remaining(void)
193 {
194         return fastboot_bytes_expected - fastboot_bytes_received;
195 }
196
197 /**
198  * fastboot_data_download() - Copy image data to fastboot_buf_addr.
199  *
200  * @fastboot_data: Pointer to received fastboot data
201  * @fastboot_data_len: Length of received fastboot data
202  * @response: Pointer to fastboot response buffer
203  *
204  * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
205  * response. fastboot_bytes_received is updated to indicate the number
206  * of bytes that have been transferred.
207  *
208  * On completion sets image_size and ${filesize} to the total size of the
209  * downloaded image.
210  */
211 void fastboot_data_download(const void *fastboot_data,
212                             unsigned int fastboot_data_len,
213                             char *response)
214 {
215 #define BYTES_PER_DOT   0x20000
216         u32 pre_dot_num, now_dot_num;
217
218         if (fastboot_data_len == 0 ||
219             (fastboot_bytes_received + fastboot_data_len) >
220             fastboot_bytes_expected) {
221                 fastboot_fail("Received invalid data length",
222                               response);
223                 return;
224         }
225         /* Download data to fastboot_buf_addr */
226         memcpy(fastboot_buf_addr + fastboot_bytes_received,
227                fastboot_data, fastboot_data_len);
228
229         pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
230         fastboot_bytes_received += fastboot_data_len;
231         now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
232
233         if (pre_dot_num != now_dot_num) {
234                 putc('.');
235                 if (!(now_dot_num % 74))
236                         putc('\n');
237         }
238         *response = '\0';
239 }
240
241 /**
242  * fastboot_data_complete() - Mark current transfer complete
243  *
244  * @response: Pointer to fastboot response buffer
245  *
246  * Set image_size and ${filesize} to the total size of the downloaded image.
247  */
248 void fastboot_data_complete(char *response)
249 {
250         /* Download complete. Respond with "OKAY" */
251         fastboot_okay(NULL, response);
252         printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
253         image_size = fastboot_bytes_received;
254         env_set_hex("filesize", image_size);
255         fastboot_bytes_expected = 0;
256         fastboot_bytes_received = 0;
257 }
258
259 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
260 /**
261  * flash() - write the downloaded image to the indicated partition.
262  *
263  * @cmd_parameter: Pointer to partition name
264  * @response: Pointer to fastboot response buffer
265  *
266  * Writes the previously downloaded image to the partition indicated by
267  * cmd_parameter. Writes to response.
268  */
269 static void flash(char *cmd_parameter, char *response)
270 {
271 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
272         fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
273                                  response);
274 #endif
275 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
276         fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
277                                   response);
278 #endif
279 }
280
281 /**
282  * erase() - erase the indicated partition.
283  *
284  * @cmd_parameter: Pointer to partition name
285  * @response: Pointer to fastboot response buffer
286  *
287  * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
288  * to response.
289  */
290 static void erase(char *cmd_parameter, char *response)
291 {
292 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
293         fastboot_mmc_erase(cmd_parameter, response);
294 #endif
295 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
296         fastboot_nand_erase(cmd_parameter, response);
297 #endif
298 }
299 #endif
300
301 /**
302  * reboot_bootloader() - Sets reboot bootloader flag.
303  *
304  * @cmd_parameter: Pointer to command parameter
305  * @response: Pointer to fastboot response buffer
306  */
307 static void reboot_bootloader(char *cmd_parameter, char *response)
308 {
309         if (fastboot_set_reboot_flag())
310                 fastboot_fail("Cannot set reboot flag", response);
311         else
312                 fastboot_okay(NULL, response);
313 }
314
315 #if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT)
316 /**
317  * oem_format() - Execute the OEM format command
318  *
319  * @cmd_parameter: Pointer to command parameter
320  * @response: Pointer to fastboot response buffer
321  */
322 static void oem_format(char *cmd_parameter, char *response)
323 {
324         char cmdbuf[32];
325
326         if (!env_get("partitions")) {
327                 fastboot_fail("partitions not set", response);
328         } else {
329                 sprintf(cmdbuf, "gpt write mmc %x $partitions",
330                         CONFIG_FASTBOOT_FLASH_MMC_DEV);
331                 if (run_command(cmdbuf, 0))
332                         fastboot_fail("", response);
333                 else
334                         fastboot_okay(NULL, response);
335         }
336 }
337 #endif