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