13aab70afSSebastian Siewior /*
23aab70afSSebastian Siewior * (C) Copyright 2008 - 2009
33aab70afSSebastian Siewior * Windriver, <www.windriver.com>
43aab70afSSebastian Siewior * Tom Rix <Tom.Rix@windriver.com>
53aab70afSSebastian Siewior *
63aab70afSSebastian Siewior * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
73aab70afSSebastian Siewior *
83aab70afSSebastian Siewior * Copyright 2014 Linaro, Ltd.
93aab70afSSebastian Siewior * Rob Herring <robh@kernel.org>
103aab70afSSebastian Siewior *
113aab70afSSebastian Siewior * SPDX-License-Identifier: GPL-2.0+
123aab70afSSebastian Siewior */
13593cbd93SSteve Rae #include <config.h>
143aab70afSSebastian Siewior #include <common.h>
152e40c2c1SJason Zhu #include <console.h>
162442fbadSJason Zhu #include <android_bootloader.h>
173aab70afSSebastian Siewior #include <errno.h>
183c8f98f5SMaxime Ripard #include <fastboot.h>
193aab70afSSebastian Siewior #include <malloc.h>
203aab70afSSebastian Siewior #include <linux/usb/ch9.h>
213aab70afSSebastian Siewior #include <linux/usb/gadget.h>
223aab70afSSebastian Siewior #include <linux/usb/composite.h>
233aab70afSSebastian Siewior #include <linux/compiler.h>
242e40c2c1SJason Zhu #include <u-boot/sha256.h>
253aab70afSSebastian Siewior #include <version.h>
263aab70afSSebastian Siewior #include <g_dnl.h>
272e40c2c1SJason Zhu #include <fs.h>
28367cce4dSXu Hongfei #include <android_avb/avb_ops_user.h>
2937a7bc39SJason Zhu #include <android_avb/rk_avb_ops_user.h>
302e40c2c1SJason Zhu #include <dm/uclass.h>
312e40c2c1SJason Zhu #include <power/fuel_gauge.h>
32d1b5ed07SSteve Rae #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
33d1b5ed07SSteve Rae #include <fb_mmc.h>
34d1b5ed07SSteve Rae #endif
35bf8940d3SMaxime Ripard #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
36bf8940d3SMaxime Ripard #include <fb_nand.h>
37bf8940d3SMaxime Ripard #endif
384d0fc665SAndy Ye #ifdef CONFIG_OPTEE_CLIENT
394d0fc665SAndy Ye #include <optee_include/OpteeClientInterface.h>
404d0fc665SAndy Ye #endif
41f61a997eSqiujian #include <boot_rkimg.h>
42f61a997eSqiujian #include <optee_include/tee_client_api.h>
43c2ba77d9SJian Qiu #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
44c2ba77d9SJian Qiu #include <keymaster.h>
45c2ba77d9SJian Qiu #endif
46*40a6a2cbSDayao Ji #ifdef CONFIG_ANDROID_AB
47*40a6a2cbSDayao Ji #include <android_ab.h>
48*40a6a2cbSDayao Ji #endif
493aab70afSSebastian Siewior
503aab70afSSebastian Siewior #define FASTBOOT_VERSION "0.4"
513aab70afSSebastian Siewior
523aab70afSSebastian Siewior #define FASTBOOT_INTERFACE_CLASS 0xff
533aab70afSSebastian Siewior #define FASTBOOT_INTERFACE_SUB_CLASS 0x42
543aab70afSSebastian Siewior #define FASTBOOT_INTERFACE_PROTOCOL 0x03
553aab70afSSebastian Siewior
563aab70afSSebastian Siewior #define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200)
573aab70afSSebastian Siewior #define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040)
583aab70afSSebastian Siewior #define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
593aab70afSSebastian Siewior
603aab70afSSebastian Siewior #define EP_BUFFER_SIZE 4096
61de78ceaeSJason Zhu #define SLEEP_COUNT 20000
6290d27e7fSJason Zhu #define MAX_PART_NUM_STR_SIZE 4
6390d27e7fSJason Zhu #define PARTITION_TYPE_STRINGS "partition-type"
6490d27e7fSJason Zhu
65ac484c5aSRoger Quadros /*
66ac484c5aSRoger Quadros * EP_BUFFER_SIZE must always be an integral multiple of maxpacket size
67ac484c5aSRoger Quadros * (64 or 512 or 1024), else we break on certain controllers like DWC3
68ac484c5aSRoger Quadros * that expect bulk OUT requests to be divisible by maxpacket size.
69ac484c5aSRoger Quadros */
703aab70afSSebastian Siewior
713aab70afSSebastian Siewior struct f_fastboot {
723aab70afSSebastian Siewior struct usb_function usb_function;
733aab70afSSebastian Siewior
74593cbd93SSteve Rae /* IN/OUT EP's and corresponding requests */
753aab70afSSebastian Siewior struct usb_ep *in_ep, *out_ep;
763aab70afSSebastian Siewior struct usb_request *in_req, *out_req;
773aab70afSSebastian Siewior };
783aab70afSSebastian Siewior
func_to_fastboot(struct usb_function * f)793aab70afSSebastian Siewior static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
803aab70afSSebastian Siewior {
813aab70afSSebastian Siewior return container_of(f, struct f_fastboot, usb_function);
823aab70afSSebastian Siewior }
833aab70afSSebastian Siewior
843aab70afSSebastian Siewior static struct f_fastboot *fastboot_func;
853aab70afSSebastian Siewior static unsigned int download_size;
863aab70afSSebastian Siewior static unsigned int download_bytes;
87367cce4dSXu Hongfei static unsigned int upload_size;
88367cce4dSXu Hongfei static unsigned int upload_bytes;
89367cce4dSXu Hongfei static bool start_upload;
90de78ceaeSJason Zhu static unsigned intthread_wakeup_needed;
913aab70afSSebastian Siewior
923aab70afSSebastian Siewior static struct usb_endpoint_descriptor fs_ep_in = {
933aab70afSSebastian Siewior .bLength = USB_DT_ENDPOINT_SIZE,
943aab70afSSebastian Siewior .bDescriptorType = USB_DT_ENDPOINT,
953aab70afSSebastian Siewior .bEndpointAddress = USB_DIR_IN,
963aab70afSSebastian Siewior .bmAttributes = USB_ENDPOINT_XFER_BULK,
97718156adSRoger Quadros .wMaxPacketSize = cpu_to_le16(64),
983aab70afSSebastian Siewior };
993aab70afSSebastian Siewior
1003aab70afSSebastian Siewior static struct usb_endpoint_descriptor fs_ep_out = {
1013aab70afSSebastian Siewior .bLength = USB_DT_ENDPOINT_SIZE,
1023aab70afSSebastian Siewior .bDescriptorType = USB_DT_ENDPOINT,
1033aab70afSSebastian Siewior .bEndpointAddress = USB_DIR_OUT,
1043aab70afSSebastian Siewior .bmAttributes = USB_ENDPOINT_XFER_BULK,
105718156adSRoger Quadros .wMaxPacketSize = cpu_to_le16(64),
106718156adSRoger Quadros };
107718156adSRoger Quadros
108718156adSRoger Quadros static struct usb_endpoint_descriptor hs_ep_in = {
109718156adSRoger Quadros .bLength = USB_DT_ENDPOINT_SIZE,
110718156adSRoger Quadros .bDescriptorType = USB_DT_ENDPOINT,
111718156adSRoger Quadros .bEndpointAddress = USB_DIR_IN,
112718156adSRoger Quadros .bmAttributes = USB_ENDPOINT_XFER_BULK,
113718156adSRoger Quadros .wMaxPacketSize = cpu_to_le16(512),
1143aab70afSSebastian Siewior };
1153aab70afSSebastian Siewior
1163aab70afSSebastian Siewior static struct usb_endpoint_descriptor hs_ep_out = {
1173aab70afSSebastian Siewior .bLength = USB_DT_ENDPOINT_SIZE,
1183aab70afSSebastian Siewior .bDescriptorType = USB_DT_ENDPOINT,
1193aab70afSSebastian Siewior .bEndpointAddress = USB_DIR_OUT,
1203aab70afSSebastian Siewior .bmAttributes = USB_ENDPOINT_XFER_BULK,
121718156adSRoger Quadros .wMaxPacketSize = cpu_to_le16(512),
1223aab70afSSebastian Siewior };
1233aab70afSSebastian Siewior
12426dd3474SWilliam Wu static struct usb_endpoint_descriptor ss_ep_in = {
12526dd3474SWilliam Wu .bLength = USB_DT_ENDPOINT_SIZE,
12626dd3474SWilliam Wu .bDescriptorType = USB_DT_ENDPOINT,
12726dd3474SWilliam Wu .bEndpointAddress = USB_DIR_IN,
12826dd3474SWilliam Wu .bmAttributes = USB_ENDPOINT_XFER_BULK,
12926dd3474SWilliam Wu .wMaxPacketSize = cpu_to_le16(1024),
13026dd3474SWilliam Wu };
13126dd3474SWilliam Wu
13226dd3474SWilliam Wu static struct usb_ss_ep_comp_descriptor ss_ep_in_comp_desc = {
13326dd3474SWilliam Wu .bLength = sizeof(ss_ep_in_comp_desc),
13426dd3474SWilliam Wu .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
13526dd3474SWilliam Wu /* .bMaxBurst = DYNAMIC, */
13626dd3474SWilliam Wu };
13726dd3474SWilliam Wu
13826dd3474SWilliam Wu static struct usb_endpoint_descriptor ss_ep_out = {
13926dd3474SWilliam Wu .bLength = USB_DT_ENDPOINT_SIZE,
14026dd3474SWilliam Wu .bDescriptorType = USB_DT_ENDPOINT,
14126dd3474SWilliam Wu .bEndpointAddress = USB_DIR_OUT,
14226dd3474SWilliam Wu .bmAttributes = USB_ENDPOINT_XFER_BULK,
14326dd3474SWilliam Wu .wMaxPacketSize = cpu_to_le16(1024),
14426dd3474SWilliam Wu };
14526dd3474SWilliam Wu
14626dd3474SWilliam Wu static struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = {
14726dd3474SWilliam Wu .bLength = sizeof(ss_ep_out_comp_desc),
14826dd3474SWilliam Wu .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
14926dd3474SWilliam Wu /* .bMaxBurst = DYNAMIC, */
15026dd3474SWilliam Wu };
15126dd3474SWilliam Wu
1523aab70afSSebastian Siewior static struct usb_interface_descriptor interface_desc = {
1533aab70afSSebastian Siewior .bLength = USB_DT_INTERFACE_SIZE,
1543aab70afSSebastian Siewior .bDescriptorType = USB_DT_INTERFACE,
1553aab70afSSebastian Siewior .bInterfaceNumber = 0x00,
1563aab70afSSebastian Siewior .bAlternateSetting = 0x00,
1573aab70afSSebastian Siewior .bNumEndpoints = 0x02,
1583aab70afSSebastian Siewior .bInterfaceClass = FASTBOOT_INTERFACE_CLASS,
1593aab70afSSebastian Siewior .bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS,
1603aab70afSSebastian Siewior .bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL,
1613aab70afSSebastian Siewior };
1623aab70afSSebastian Siewior
163718156adSRoger Quadros static struct usb_descriptor_header *fb_fs_function[] = {
1643aab70afSSebastian Siewior (struct usb_descriptor_header *)&interface_desc,
1653aab70afSSebastian Siewior (struct usb_descriptor_header *)&fs_ep_in,
166718156adSRoger Quadros (struct usb_descriptor_header *)&fs_ep_out,
167718156adSRoger Quadros };
168718156adSRoger Quadros
169718156adSRoger Quadros static struct usb_descriptor_header *fb_hs_function[] = {
170718156adSRoger Quadros (struct usb_descriptor_header *)&interface_desc,
171718156adSRoger Quadros (struct usb_descriptor_header *)&hs_ep_in,
1723aab70afSSebastian Siewior (struct usb_descriptor_header *)&hs_ep_out,
1733aab70afSSebastian Siewior NULL,
1743aab70afSSebastian Siewior };
1753aab70afSSebastian Siewior
17626dd3474SWilliam Wu static struct usb_descriptor_header *fb_ss_function[] = {
17726dd3474SWilliam Wu (struct usb_descriptor_header *)&interface_desc,
17826dd3474SWilliam Wu (struct usb_descriptor_header *)&ss_ep_in,
17926dd3474SWilliam Wu (struct usb_descriptor_header *)&ss_ep_in_comp_desc,
18026dd3474SWilliam Wu (struct usb_descriptor_header *)&ss_ep_out,
18126dd3474SWilliam Wu (struct usb_descriptor_header *)&ss_ep_out_comp_desc,
18226dd3474SWilliam Wu NULL,
18326dd3474SWilliam Wu };
18426dd3474SWilliam Wu
1858b704a0eSRoger Quadros static struct usb_endpoint_descriptor *
fb_ep_desc(struct usb_gadget * g,struct usb_endpoint_descriptor * fs,struct usb_endpoint_descriptor * hs,struct usb_endpoint_descriptor * ss,struct usb_ss_ep_comp_descriptor * comp_desc,struct usb_ep * ep)1868b704a0eSRoger Quadros fb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
18726dd3474SWilliam Wu struct usb_endpoint_descriptor *hs,
18826dd3474SWilliam Wu struct usb_endpoint_descriptor *ss,
18926dd3474SWilliam Wu struct usb_ss_ep_comp_descriptor *comp_desc,
19026dd3474SWilliam Wu struct usb_ep *ep)
1918b704a0eSRoger Quadros {
19226dd3474SWilliam Wu struct usb_endpoint_descriptor *speed_desc = NULL;
19326dd3474SWilliam Wu
19426dd3474SWilliam Wu /* select desired speed */
19526dd3474SWilliam Wu switch (g->speed) {
19626dd3474SWilliam Wu case USB_SPEED_SUPER:
19726dd3474SWilliam Wu if (gadget_is_superspeed(g)) {
19826dd3474SWilliam Wu speed_desc = ss;
19926dd3474SWilliam Wu ep->comp_desc = comp_desc;
20026dd3474SWilliam Wu break;
20126dd3474SWilliam Wu }
20226dd3474SWilliam Wu /* else: Fall trough */
20326dd3474SWilliam Wu case USB_SPEED_HIGH:
20426dd3474SWilliam Wu if (gadget_is_dualspeed(g)) {
20526dd3474SWilliam Wu speed_desc = hs;
20626dd3474SWilliam Wu break;
20726dd3474SWilliam Wu }
20826dd3474SWilliam Wu /* else: fall through */
20926dd3474SWilliam Wu default:
21026dd3474SWilliam Wu speed_desc = fs;
21126dd3474SWilliam Wu }
21226dd3474SWilliam Wu
21326dd3474SWilliam Wu return speed_desc;
2148b704a0eSRoger Quadros }
2158b704a0eSRoger Quadros
2163aab70afSSebastian Siewior /*
2173aab70afSSebastian Siewior * static strings, in UTF-8
2183aab70afSSebastian Siewior */
2193aab70afSSebastian Siewior static const char fastboot_name[] = "Android Fastboot";
2203aab70afSSebastian Siewior
2213aab70afSSebastian Siewior static struct usb_string fastboot_string_defs[] = {
2223aab70afSSebastian Siewior [0].s = fastboot_name,
2233aab70afSSebastian Siewior { } /* end of list */
2243aab70afSSebastian Siewior };
2253aab70afSSebastian Siewior
2263aab70afSSebastian Siewior static struct usb_gadget_strings stringtab_fastboot = {
2273aab70afSSebastian Siewior .language = 0x0409, /* en-us */
2283aab70afSSebastian Siewior .strings = fastboot_string_defs,
2293aab70afSSebastian Siewior };
2303aab70afSSebastian Siewior
2313aab70afSSebastian Siewior static struct usb_gadget_strings *fastboot_strings[] = {
2323aab70afSSebastian Siewior &stringtab_fastboot,
2333aab70afSSebastian Siewior NULL,
2343aab70afSSebastian Siewior };
2353aab70afSSebastian Siewior
2363aab70afSSebastian Siewior static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
237e2ec3e46SAlexey Firago static int strcmp_l1(const char *s1, const char *s2);
wakeup_thread(void)238de78ceaeSJason Zhu static void wakeup_thread(void)
239de78ceaeSJason Zhu {
240de78ceaeSJason Zhu intthread_wakeup_needed = false;
241de78ceaeSJason Zhu }
242de78ceaeSJason Zhu
busy_indicator(void)243de78ceaeSJason Zhu static void busy_indicator(void)
244de78ceaeSJason Zhu {
245de78ceaeSJason Zhu static int state;
246de78ceaeSJason Zhu
247de78ceaeSJason Zhu switch (state) {
248de78ceaeSJason Zhu case 0:
249de78ceaeSJason Zhu puts("\r|"); break;
250de78ceaeSJason Zhu case 1:
251de78ceaeSJason Zhu puts("\r/"); break;
252de78ceaeSJason Zhu case 2:
253de78ceaeSJason Zhu puts("\r-"); break;
254de78ceaeSJason Zhu case 3:
255de78ceaeSJason Zhu puts("\r\\"); break;
256de78ceaeSJason Zhu case 4:
257de78ceaeSJason Zhu puts("\r|"); break;
258de78ceaeSJason Zhu case 5:
259de78ceaeSJason Zhu puts("\r/"); break;
260de78ceaeSJason Zhu case 6:
261de78ceaeSJason Zhu puts("\r-"); break;
262de78ceaeSJason Zhu case 7:
263de78ceaeSJason Zhu puts("\r\\"); break;
264de78ceaeSJason Zhu default:
265de78ceaeSJason Zhu state = 0;
266de78ceaeSJason Zhu }
267de78ceaeSJason Zhu if (state++ == 8)
268de78ceaeSJason Zhu state = 0;
269de78ceaeSJason Zhu }
270de78ceaeSJason Zhu
fb_get_fstype(const char * ifname,const int part_num,const char ** fs_type)27190d27e7fSJason Zhu static int fb_get_fstype(const char *ifname, const int part_num,
27290d27e7fSJason Zhu const char **fs_type)
27390d27e7fSJason Zhu {
27490d27e7fSJason Zhu char part_num_str[MAX_PART_NUM_STR_SIZE] = {0};
27590d27e7fSJason Zhu
27690d27e7fSJason Zhu snprintf(part_num_str, ARRAY_SIZE(part_num_str), ":%x", part_num);
27790d27e7fSJason Zhu
27890d27e7fSJason Zhu if (fs_set_blk_dev(ifname, part_num_str, FS_TYPE_ANY))
27990d27e7fSJason Zhu return -1;
28090d27e7fSJason Zhu
28190d27e7fSJason Zhu if (fs_get_fstype(fs_type))
28290d27e7fSJason Zhu return -1;
28390d27e7fSJason Zhu
28490d27e7fSJason Zhu return 0;
28590d27e7fSJason Zhu }
28690d27e7fSJason Zhu
sleep_thread(void)287de78ceaeSJason Zhu static int sleep_thread(void)
288de78ceaeSJason Zhu {
289de78ceaeSJason Zhu int rc = 0;
290de78ceaeSJason Zhu int i = 0, k = 0;
291de78ceaeSJason Zhu
292de78ceaeSJason Zhu /* Wait until a signal arrives or we are woken up */
293de78ceaeSJason Zhu for (;;) {
294de78ceaeSJason Zhu if (!intthread_wakeup_needed)
295de78ceaeSJason Zhu break;
296de78ceaeSJason Zhu
297de78ceaeSJason Zhu if (++i == SLEEP_COUNT) {
298de78ceaeSJason Zhu busy_indicator();
299de78ceaeSJason Zhu i = 0;
300de78ceaeSJason Zhu k++;
301de78ceaeSJason Zhu }
302de78ceaeSJason Zhu
303de78ceaeSJason Zhu if (k == 10) {
304de78ceaeSJason Zhu /* Handle CTRL+C */
305de78ceaeSJason Zhu if (ctrlc())
306de78ceaeSJason Zhu return -EPIPE;
307de78ceaeSJason Zhu
308de78ceaeSJason Zhu /* Check cable connection */
309de78ceaeSJason Zhu if (!g_dnl_board_usb_cable_connected())
310de78ceaeSJason Zhu return -EIO;
311de78ceaeSJason Zhu
312de78ceaeSJason Zhu k = 0;
313de78ceaeSJason Zhu }
314de78ceaeSJason Zhu
315de78ceaeSJason Zhu usb_gadget_handle_interrupts(0);
316de78ceaeSJason Zhu }
317de78ceaeSJason Zhu intthread_wakeup_needed = true;
318de78ceaeSJason Zhu return rc;
319de78ceaeSJason Zhu }
3203aab70afSSebastian Siewior
fastboot_complete(struct usb_ep * ep,struct usb_request * req)3213aab70afSSebastian Siewior static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
3223aab70afSSebastian Siewior {
3233aab70afSSebastian Siewior int status = req->status;
324de78ceaeSJason Zhu
325de78ceaeSJason Zhu wakeup_thread();
3263aab70afSSebastian Siewior if (!status)
3273aab70afSSebastian Siewior return;
3283aab70afSSebastian Siewior printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
3293aab70afSSebastian Siewior }
3303aab70afSSebastian Siewior
fastboot_bind(struct usb_configuration * c,struct usb_function * f)3313aab70afSSebastian Siewior static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
3323aab70afSSebastian Siewior {
3333aab70afSSebastian Siewior int id;
3343aab70afSSebastian Siewior struct usb_gadget *gadget = c->cdev->gadget;
3353aab70afSSebastian Siewior struct f_fastboot *f_fb = func_to_fastboot(f);
336537cd072SDileep Katta const char *s;
3373aab70afSSebastian Siewior
3383aab70afSSebastian Siewior /* DYNAMIC interface numbers assignments */
3393aab70afSSebastian Siewior id = usb_interface_id(c, f);
3403aab70afSSebastian Siewior if (id < 0)
3413aab70afSSebastian Siewior return id;
3423aab70afSSebastian Siewior interface_desc.bInterfaceNumber = id;
3433aab70afSSebastian Siewior
3443aab70afSSebastian Siewior id = usb_string_id(c->cdev);
3453aab70afSSebastian Siewior if (id < 0)
3463aab70afSSebastian Siewior return id;
3473aab70afSSebastian Siewior fastboot_string_defs[0].id = id;
3483aab70afSSebastian Siewior interface_desc.iInterface = id;
3493aab70afSSebastian Siewior
3503aab70afSSebastian Siewior f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
3513aab70afSSebastian Siewior if (!f_fb->in_ep)
3523aab70afSSebastian Siewior return -ENODEV;
3533aab70afSSebastian Siewior f_fb->in_ep->driver_data = c->cdev;
3543aab70afSSebastian Siewior
3553aab70afSSebastian Siewior f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
3563aab70afSSebastian Siewior if (!f_fb->out_ep)
3573aab70afSSebastian Siewior return -ENODEV;
3583aab70afSSebastian Siewior f_fb->out_ep->driver_data = c->cdev;
3593aab70afSSebastian Siewior
360718156adSRoger Quadros f->descriptors = fb_fs_function;
361718156adSRoger Quadros
362718156adSRoger Quadros if (gadget_is_dualspeed(gadget)) {
363718156adSRoger Quadros /* Assume endpoint addresses are the same for both speeds */
364718156adSRoger Quadros hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
3653aab70afSSebastian Siewior hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
366718156adSRoger Quadros /* copy HS descriptors */
367718156adSRoger Quadros f->hs_descriptors = fb_hs_function;
368718156adSRoger Quadros }
3693aab70afSSebastian Siewior
37026dd3474SWilliam Wu if (gadget_is_superspeed(gadget)) {
37126dd3474SWilliam Wu /* Assume endpoint addresses are the same as full speed */
37226dd3474SWilliam Wu ss_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
37326dd3474SWilliam Wu ss_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
37426dd3474SWilliam Wu /* copy SS descriptors */
37526dd3474SWilliam Wu f->ss_descriptors = fb_ss_function;
37626dd3474SWilliam Wu }
37726dd3474SWilliam Wu
37800caae6dSSimon Glass s = env_get("serial#");
379537cd072SDileep Katta if (s)
380537cd072SDileep Katta g_dnl_set_serialnumber((char *)s);
381537cd072SDileep Katta
3823aab70afSSebastian Siewior return 0;
3833aab70afSSebastian Siewior }
3843aab70afSSebastian Siewior
fastboot_unbind(struct usb_configuration * c,struct usb_function * f)3853aab70afSSebastian Siewior static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
3863aab70afSSebastian Siewior {
3873aab70afSSebastian Siewior memset(fastboot_func, 0, sizeof(*fastboot_func));
3883aab70afSSebastian Siewior }
3893aab70afSSebastian Siewior
fastboot_disable(struct usb_function * f)3903aab70afSSebastian Siewior static void fastboot_disable(struct usb_function *f)
3913aab70afSSebastian Siewior {
3923aab70afSSebastian Siewior struct f_fastboot *f_fb = func_to_fastboot(f);
3933aab70afSSebastian Siewior
3943aab70afSSebastian Siewior usb_ep_disable(f_fb->out_ep);
3953aab70afSSebastian Siewior usb_ep_disable(f_fb->in_ep);
3963aab70afSSebastian Siewior
3973aab70afSSebastian Siewior if (f_fb->out_req) {
3983aab70afSSebastian Siewior free(f_fb->out_req->buf);
3993aab70afSSebastian Siewior usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
4003aab70afSSebastian Siewior f_fb->out_req = NULL;
4013aab70afSSebastian Siewior }
4023aab70afSSebastian Siewior if (f_fb->in_req) {
4033aab70afSSebastian Siewior free(f_fb->in_req->buf);
4043aab70afSSebastian Siewior usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
4053aab70afSSebastian Siewior f_fb->in_req = NULL;
4063aab70afSSebastian Siewior }
4073aab70afSSebastian Siewior }
4083aab70afSSebastian Siewior
fastboot_start_ep(struct usb_ep * ep)4093aab70afSSebastian Siewior static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
4103aab70afSSebastian Siewior {
4113aab70afSSebastian Siewior struct usb_request *req;
4123aab70afSSebastian Siewior
4133aab70afSSebastian Siewior req = usb_ep_alloc_request(ep, 0);
4143aab70afSSebastian Siewior if (!req)
4153aab70afSSebastian Siewior return NULL;
4163aab70afSSebastian Siewior
4173aab70afSSebastian Siewior req->length = EP_BUFFER_SIZE;
4183aab70afSSebastian Siewior req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
4193aab70afSSebastian Siewior if (!req->buf) {
4203aab70afSSebastian Siewior usb_ep_free_request(ep, req);
4213aab70afSSebastian Siewior return NULL;
4223aab70afSSebastian Siewior }
4233aab70afSSebastian Siewior
4243aab70afSSebastian Siewior memset(req->buf, 0, req->length);
4253aab70afSSebastian Siewior return req;
4263aab70afSSebastian Siewior }
4273aab70afSSebastian Siewior
fastboot_set_alt(struct usb_function * f,unsigned interface,unsigned alt)4283aab70afSSebastian Siewior static int fastboot_set_alt(struct usb_function *f,
4293aab70afSSebastian Siewior unsigned interface, unsigned alt)
4303aab70afSSebastian Siewior {
4313aab70afSSebastian Siewior int ret;
4323aab70afSSebastian Siewior struct usb_composite_dev *cdev = f->config->cdev;
4333aab70afSSebastian Siewior struct usb_gadget *gadget = cdev->gadget;
4343aab70afSSebastian Siewior struct f_fastboot *f_fb = func_to_fastboot(f);
4358b704a0eSRoger Quadros const struct usb_endpoint_descriptor *d;
4363aab70afSSebastian Siewior
4373aab70afSSebastian Siewior debug("%s: func: %s intf: %d alt: %d\n",
4383aab70afSSebastian Siewior __func__, f->name, interface, alt);
4393aab70afSSebastian Siewior
44026dd3474SWilliam Wu d = fb_ep_desc(gadget, &fs_ep_out, &hs_ep_out, &ss_ep_out,
44126dd3474SWilliam Wu &ss_ep_out_comp_desc, f_fb->out_ep);
4428b704a0eSRoger Quadros ret = usb_ep_enable(f_fb->out_ep, d);
4433aab70afSSebastian Siewior if (ret) {
4443aab70afSSebastian Siewior puts("failed to enable out ep\n");
4453aab70afSSebastian Siewior return ret;
4463aab70afSSebastian Siewior }
4473aab70afSSebastian Siewior
4483aab70afSSebastian Siewior f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
4493aab70afSSebastian Siewior if (!f_fb->out_req) {
4503aab70afSSebastian Siewior puts("failed to alloc out req\n");
4513aab70afSSebastian Siewior ret = -EINVAL;
4523aab70afSSebastian Siewior goto err;
4533aab70afSSebastian Siewior }
4543aab70afSSebastian Siewior f_fb->out_req->complete = rx_handler_command;
4553aab70afSSebastian Siewior
45626dd3474SWilliam Wu d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in, &ss_ep_in,
45726dd3474SWilliam Wu &ss_ep_in_comp_desc, f_fb->in_ep);
4588b704a0eSRoger Quadros ret = usb_ep_enable(f_fb->in_ep, d);
4593aab70afSSebastian Siewior if (ret) {
4603aab70afSSebastian Siewior puts("failed to enable in ep\n");
4613aab70afSSebastian Siewior goto err;
4623aab70afSSebastian Siewior }
4633aab70afSSebastian Siewior
4643aab70afSSebastian Siewior f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
4653aab70afSSebastian Siewior if (!f_fb->in_req) {
4663aab70afSSebastian Siewior puts("failed alloc req in\n");
4673aab70afSSebastian Siewior ret = -EINVAL;
4683aab70afSSebastian Siewior goto err;
4693aab70afSSebastian Siewior }
4703aab70afSSebastian Siewior f_fb->in_req->complete = fastboot_complete;
4713aab70afSSebastian Siewior
4723aab70afSSebastian Siewior ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
4733aab70afSSebastian Siewior if (ret)
4743aab70afSSebastian Siewior goto err;
4753aab70afSSebastian Siewior
4763aab70afSSebastian Siewior return 0;
4773aab70afSSebastian Siewior err:
4783aab70afSSebastian Siewior fastboot_disable(f);
4793aab70afSSebastian Siewior return ret;
4803aab70afSSebastian Siewior }
4813aab70afSSebastian Siewior
fastboot_add(struct usb_configuration * c)4823aab70afSSebastian Siewior static int fastboot_add(struct usb_configuration *c)
4833aab70afSSebastian Siewior {
4843aab70afSSebastian Siewior struct f_fastboot *f_fb = fastboot_func;
4853aab70afSSebastian Siewior int status;
4863aab70afSSebastian Siewior
4873aab70afSSebastian Siewior debug("%s: cdev: 0x%p\n", __func__, c->cdev);
4883aab70afSSebastian Siewior
4893aab70afSSebastian Siewior if (!f_fb) {
4903aab70afSSebastian Siewior f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
4913aab70afSSebastian Siewior if (!f_fb)
4923aab70afSSebastian Siewior return -ENOMEM;
4933aab70afSSebastian Siewior
4943aab70afSSebastian Siewior fastboot_func = f_fb;
4953aab70afSSebastian Siewior memset(f_fb, 0, sizeof(*f_fb));
4963aab70afSSebastian Siewior }
4973aab70afSSebastian Siewior
4983aab70afSSebastian Siewior f_fb->usb_function.name = "f_fastboot";
4993aab70afSSebastian Siewior f_fb->usb_function.bind = fastboot_bind;
5003aab70afSSebastian Siewior f_fb->usb_function.unbind = fastboot_unbind;
5013aab70afSSebastian Siewior f_fb->usb_function.set_alt = fastboot_set_alt;
5023aab70afSSebastian Siewior f_fb->usb_function.disable = fastboot_disable;
5033aab70afSSebastian Siewior f_fb->usb_function.strings = fastboot_strings;
5043aab70afSSebastian Siewior
5053aab70afSSebastian Siewior status = usb_add_function(c, &f_fb->usb_function);
5063aab70afSSebastian Siewior if (status) {
5073aab70afSSebastian Siewior free(f_fb);
5083aab70afSSebastian Siewior fastboot_func = f_fb;
5093aab70afSSebastian Siewior }
5103aab70afSSebastian Siewior
5113aab70afSSebastian Siewior return status;
5123aab70afSSebastian Siewior }
5133aab70afSSebastian Siewior DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
5143aab70afSSebastian Siewior
fastboot_tx_write(const char * buffer,unsigned int buffer_size)515593cbd93SSteve Rae static int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
5163aab70afSSebastian Siewior {
5173aab70afSSebastian Siewior struct usb_request *in_req = fastboot_func->in_req;
5183aab70afSSebastian Siewior int ret;
5193aab70afSSebastian Siewior
5203aab70afSSebastian Siewior memcpy(in_req->buf, buffer, buffer_size);
5213aab70afSSebastian Siewior in_req->length = buffer_size;
522bc9071c9SPaul Kocialkowski
523bc9071c9SPaul Kocialkowski usb_ep_dequeue(fastboot_func->in_ep, in_req);
524bc9071c9SPaul Kocialkowski
5253aab70afSSebastian Siewior ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
5263aab70afSSebastian Siewior if (ret)
5273aab70afSSebastian Siewior printf("Error %d on queue\n", ret);
5283aab70afSSebastian Siewior return 0;
5293aab70afSSebastian Siewior }
5303aab70afSSebastian Siewior
fastboot_tx_write_str(const char * buffer)5313aab70afSSebastian Siewior static int fastboot_tx_write_str(const char *buffer)
5323aab70afSSebastian Siewior {
533de78ceaeSJason Zhu int ret;
534de78ceaeSJason Zhu
535de78ceaeSJason Zhu ret = sleep_thread();
536de78ceaeSJason Zhu if (ret < 0)
537de78ceaeSJason Zhu printf("warning: 0x%x, usb transmission is abnormal!\n", ret);
538de78ceaeSJason Zhu
5393aab70afSSebastian Siewior return fastboot_tx_write(buffer, strlen(buffer));
5403aab70afSSebastian Siewior }
5413aab70afSSebastian Siewior
compl_do_reset(struct usb_ep * ep,struct usb_request * req)5423aab70afSSebastian Siewior static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
5433aab70afSSebastian Siewior {
5443aab70afSSebastian Siewior do_reset(NULL, 0, 0, NULL);
5453aab70afSSebastian Siewior }
5463aab70afSSebastian Siewior
fb_set_reboot_flag(void)547e2ec3e46SAlexey Firago int __weak fb_set_reboot_flag(void)
548e2ec3e46SAlexey Firago {
549e2ec3e46SAlexey Firago return -ENOSYS;
550e2ec3e46SAlexey Firago }
551e2ec3e46SAlexey Firago
cb_reboot(struct usb_ep * ep,struct usb_request * req)5523aab70afSSebastian Siewior static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
5533aab70afSSebastian Siewior {
554e2ec3e46SAlexey Firago char *cmd = req->buf;
5552442fbadSJason Zhu
556e2ec3e46SAlexey Firago if (!strcmp_l1("reboot-bootloader", cmd)) {
557e2ec3e46SAlexey Firago if (fb_set_reboot_flag()) {
558e2ec3e46SAlexey Firago fastboot_tx_write_str("FAILCannot set reboot flag");
559e2ec3e46SAlexey Firago return;
560e2ec3e46SAlexey Firago }
561e2ec3e46SAlexey Firago }
5622442fbadSJason Zhu #ifdef CONFIG_ANDROID_BOOTLOADER
5632442fbadSJason Zhu if (!strcmp_l1("reboot-fastboot", cmd)) {
5642442fbadSJason Zhu if (android_bcb_write("boot-fastboot")) {
5652442fbadSJason Zhu fastboot_tx_write_str("FAILCannot set boot-fastboot");
5662442fbadSJason Zhu return;
5672442fbadSJason Zhu }
5682442fbadSJason Zhu }
5692442fbadSJason Zhu
5702442fbadSJason Zhu if (!strcmp_l1("reboot-recovery", cmd)) {
5712442fbadSJason Zhu if (android_bcb_write("boot-recovery")) {
5722442fbadSJason Zhu fastboot_tx_write_str("FAILCannot set boot-recovery");
5732442fbadSJason Zhu return;
5742442fbadSJason Zhu }
5752442fbadSJason Zhu }
5762442fbadSJason Zhu #endif
5773aab70afSSebastian Siewior fastboot_func->in_req->complete = compl_do_reset;
5783aab70afSSebastian Siewior fastboot_tx_write_str("OKAY");
5793aab70afSSebastian Siewior }
5803aab70afSSebastian Siewior
strcmp_l1(const char * s1,const char * s2)5813aab70afSSebastian Siewior static int strcmp_l1(const char *s1, const char *s2)
5823aab70afSSebastian Siewior {
5833aab70afSSebastian Siewior if (!s1 || !s2)
5843aab70afSSebastian Siewior return -1;
5853aab70afSSebastian Siewior return strncmp(s1, s2, strlen(s1));
5863aab70afSSebastian Siewior }
5873aab70afSSebastian Siewior
58890d27e7fSJason Zhu struct name_string {
58990d27e7fSJason Zhu const char *str;
59090d27e7fSJason Zhu int expects_args;
59190d27e7fSJason Zhu char delim;
59290d27e7fSJason Zhu };
59390d27e7fSJason Zhu
59490d27e7fSJason Zhu #define NAME_NO_ARGS(s) {.str = s, .expects_args = 0}
59590d27e7fSJason Zhu #define NAME_ARGS(s, d) {.str = s, .expects_args = 1, .delim = d}
59690d27e7fSJason Zhu
name_check_match(const char * str,size_t len,const struct name_string * name)59790d27e7fSJason Zhu static size_t name_check_match(const char *str, size_t len,
59890d27e7fSJason Zhu const struct name_string *name)
5993aab70afSSebastian Siewior {
60090d27e7fSJason Zhu size_t str_len = strlen(name->str);
6013aab70afSSebastian Siewior
60290d27e7fSJason Zhu /* If name len is greater than input, return 0. */
60390d27e7fSJason Zhu if (str_len > len)
60490d27e7fSJason Zhu return 0;
60529425be4SJeroen Hofstee
60690d27e7fSJason Zhu /* If name str does not match input string, return 0. */
60790d27e7fSJason Zhu if (memcmp(name->str, str, str_len))
60890d27e7fSJason Zhu return 0;
60990d27e7fSJason Zhu
61090d27e7fSJason Zhu if (name->expects_args) {
61190d27e7fSJason Zhu /* string should have space for delim */
61290d27e7fSJason Zhu if (len == str_len)
61390d27e7fSJason Zhu return 0;
61490d27e7fSJason Zhu
61590d27e7fSJason Zhu /* Check delim match */
61690d27e7fSJason Zhu if (name->delim != str[str_len])
61790d27e7fSJason Zhu return 0;
61890d27e7fSJason Zhu } else {
61990d27e7fSJason Zhu /* Name str len should match input len */
62090d27e7fSJason Zhu if (str_len != len)
62190d27e7fSJason Zhu return 0;
6223aab70afSSebastian Siewior }
6233aab70afSSebastian Siewior
62490d27e7fSJason Zhu return str_len + name->expects_args;
62590d27e7fSJason Zhu }
6263aab70afSSebastian Siewior
fb_add_string(char * dst,size_t chars_left,const char * str,const char * args)62790d27e7fSJason Zhu static void fb_add_string(char *dst, size_t chars_left,
62890d27e7fSJason Zhu const char *str, const char *args)
62990d27e7fSJason Zhu {
63090d27e7fSJason Zhu if (!str)
63190d27e7fSJason Zhu return;
63290d27e7fSJason Zhu
63390d27e7fSJason Zhu int ret = snprintf(dst, chars_left, str, args);
63490d27e7fSJason Zhu
63590d27e7fSJason Zhu if (ret < 0)
63690d27e7fSJason Zhu pr_err("snprintf is error!");
63790d27e7fSJason Zhu }
63890d27e7fSJason Zhu
fb_add_number(char * dst,size_t chars_left,const char * format,size_t num)63990d27e7fSJason Zhu static void fb_add_number(char *dst, size_t chars_left,
64090d27e7fSJason Zhu const char *format, size_t num)
64190d27e7fSJason Zhu {
64290d27e7fSJason Zhu if (!format)
64390d27e7fSJason Zhu return;
64490d27e7fSJason Zhu
64590d27e7fSJason Zhu int ret = snprintf(dst, chars_left, format, num);
64690d27e7fSJason Zhu
64790d27e7fSJason Zhu if (ret > chars_left)
64890d27e7fSJason Zhu pr_err("snprintf is error!");
64990d27e7fSJason Zhu }
65090d27e7fSJason Zhu
fb_read_var(char * cmd,char * response,fb_getvar_t var,size_t chars_left)65190d27e7fSJason Zhu static int fb_read_var(char *cmd, char *response,
65290d27e7fSJason Zhu fb_getvar_t var, size_t chars_left)
65390d27e7fSJason Zhu {
65490d27e7fSJason Zhu const char *s;
65590d27e7fSJason Zhu int ret = 0;
65690d27e7fSJason Zhu
65790d27e7fSJason Zhu switch (var) {
65890d27e7fSJason Zhu case FB_VERSION:
65990d27e7fSJason Zhu fb_add_string(response, chars_left, FASTBOOT_VERSION, NULL);
66090d27e7fSJason Zhu break;
66190d27e7fSJason Zhu case FB_BOOTLOADER_VERSION:
66290d27e7fSJason Zhu fb_add_string(response, chars_left, U_BOOT_VERSION, NULL);
66390d27e7fSJason Zhu break;
66490d27e7fSJason Zhu case FB_BASEBAND_VERSION:
66590d27e7fSJason Zhu fb_add_string(response, chars_left, "N/A", NULL);
66690d27e7fSJason Zhu break;
66790d27e7fSJason Zhu case FB_PRODUCT:
66890d27e7fSJason Zhu fb_add_string(response, chars_left, CONFIG_SYS_BOARD, NULL);
66990d27e7fSJason Zhu break;
67090d27e7fSJason Zhu case FB_SERIAL_NO:
67100caae6dSSimon Glass s = env_get("serial#");
6723aab70afSSebastian Siewior if (s)
67390d27e7fSJason Zhu fb_add_string(response, chars_left, s, NULL);
6743aab70afSSebastian Siewior else
67590d27e7fSJason Zhu ret = -1;
67690d27e7fSJason Zhu break;
67790d27e7fSJason Zhu case FB_SECURE:
67890d27e7fSJason Zhu fb_add_string(response, chars_left, "yes", NULL);
67990d27e7fSJason Zhu break;
68090d27e7fSJason Zhu case FB_VARIANT:
68190d27e7fSJason Zhu fb_add_string(response, chars_left, "userdebug", NULL);
68290d27e7fSJason Zhu break;
68390d27e7fSJason Zhu case FB_DWNLD_SIZE:
68490d27e7fSJason Zhu fb_add_number(response, chars_left, "0x%08x",
68590d27e7fSJason Zhu CONFIG_FASTBOOT_BUF_SIZE);
68690d27e7fSJason Zhu break;
68790d27e7fSJason Zhu case FB_PART_SIZE:
68890d27e7fSJason Zhu case FB_PART_TYPE: {
68990d27e7fSJason Zhu char *part_name = cmd;
690367cce4dSXu Hongfei
69190d27e7fSJason Zhu cmd = strsep(&part_name, ":");
69290d27e7fSJason Zhu if (!cmd || !part_name) {
69390d27e7fSJason Zhu fb_add_string(response, chars_left,
69490d27e7fSJason Zhu "argument Invalid!", NULL);
69590d27e7fSJason Zhu ret = -1;
69690d27e7fSJason Zhu break;
69790d27e7fSJason Zhu }
69890d27e7fSJason Zhu
69990d27e7fSJason Zhu #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
70090d27e7fSJason Zhu disk_partition_t part_info;
70190d27e7fSJason Zhu struct blk_desc *dev_desc;
70290d27e7fSJason Zhu int part_num = -1;
70390d27e7fSJason Zhu const char *fs_type = NULL;
70490d27e7fSJason Zhu
70590d27e7fSJason Zhu #ifdef CONFIG_RKIMG_BOOTLOADER
70690d27e7fSJason Zhu dev_desc = rockchip_get_bootdev();
70790d27e7fSJason Zhu #else
70890d27e7fSJason Zhu dev_desc = NULL;
70990d27e7fSJason Zhu #endif
71090d27e7fSJason Zhu if (!dev_desc) {
71190d27e7fSJason Zhu fb_add_string(response, chars_left,
71290d27e7fSJason Zhu "block device not found", NULL);
71390d27e7fSJason Zhu ret = -1;
71490d27e7fSJason Zhu break;
71590d27e7fSJason Zhu }
71690d27e7fSJason Zhu
71790d27e7fSJason Zhu part_num = part_get_info_by_name(dev_desc, part_name,
71890d27e7fSJason Zhu &part_info);
71990d27e7fSJason Zhu if (part_num < 0) {
72090d27e7fSJason Zhu fb_add_string(response, chars_left,
72190d27e7fSJason Zhu "partition not found", NULL);
72290d27e7fSJason Zhu ret = -1;
72390d27e7fSJason Zhu } else if (!strncmp(PARTITION_TYPE_STRINGS, cmd,
72490d27e7fSJason Zhu strlen(PARTITION_TYPE_STRINGS))) {
72590d27e7fSJason Zhu if (fb_get_fstype("mmc", part_num, &fs_type)) {
72690d27e7fSJason Zhu fb_add_string(response, chars_left,
72790d27e7fSJason Zhu (char *)part_info.type, NULL);
72890d27e7fSJason Zhu } else {
72990d27e7fSJason Zhu fb_add_string(response, chars_left,
73090d27e7fSJason Zhu fs_type, NULL);
73190d27e7fSJason Zhu }
73290d27e7fSJason Zhu } else if (!strncmp("partition-size", cmd, 14)) {
73390d27e7fSJason Zhu u64 part_size;
73490d27e7fSJason Zhu
73590d27e7fSJason Zhu part_size = (uint64_t)part_info.size;
73690d27e7fSJason Zhu snprintf(response, chars_left, "0x%llx",
73790d27e7fSJason Zhu part_size * dev_desc->blksz);
73890d27e7fSJason Zhu }
73990d27e7fSJason Zhu #else
74090d27e7fSJason Zhu fb_add_string(response, chars_left, "not implemented", NULL);
74190d27e7fSJason Zhu ret = -1;
74290d27e7fSJason Zhu #endif
74390d27e7fSJason Zhu break;
74490d27e7fSJason Zhu }
74590d27e7fSJason Zhu case FB_BLK_SIZE: {
74690d27e7fSJason Zhu #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
74790d27e7fSJason Zhu struct blk_desc *dev_desc;
74890d27e7fSJason Zhu
74990d27e7fSJason Zhu #ifdef CONFIG_RKIMG_BOOTLOADER
75090d27e7fSJason Zhu dev_desc = rockchip_get_bootdev();
75190d27e7fSJason Zhu #else
75290d27e7fSJason Zhu dev_desc = NULL;
75390d27e7fSJason Zhu #endif
75490d27e7fSJason Zhu if (!dev_desc) {
75590d27e7fSJason Zhu fb_add_string(response, chars_left,
75690d27e7fSJason Zhu "block device not found", NULL);
75790d27e7fSJason Zhu ret = -1;
75890d27e7fSJason Zhu } else {
75990d27e7fSJason Zhu fb_add_number(response, chars_left,
76090d27e7fSJason Zhu "0x%lx", dev_desc->blksz);
76190d27e7fSJason Zhu }
76290d27e7fSJason Zhu #else
76390d27e7fSJason Zhu fb_add_string(response, chars_left, "not implemented", NULL);
76490d27e7fSJason Zhu ret = -1;
76590d27e7fSJason Zhu #endif
76690d27e7fSJason Zhu break;
76790d27e7fSJason Zhu }
76890d27e7fSJason Zhu case FB_ERASE_SIZE: {
76990d27e7fSJason Zhu #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
77090d27e7fSJason Zhu lbaint_t erase_grp_size;
77190d27e7fSJason Zhu
77290d27e7fSJason Zhu erase_grp_size = fb_mmc_get_erase_grp_size();
77390d27e7fSJason Zhu if (erase_grp_size < 0) {
77490d27e7fSJason Zhu fb_add_string(response, chars_left,
77590d27e7fSJason Zhu "block device not found", NULL);
77690d27e7fSJason Zhu ret = -1;
77790d27e7fSJason Zhu } else {
77890d27e7fSJason Zhu fb_add_number(response, chars_left, "0x"LBAF"",
77990d27e7fSJason Zhu erase_grp_size);
78090d27e7fSJason Zhu }
78190d27e7fSJason Zhu #else
78290d27e7fSJason Zhu fb_add_string(response, chars_left, "not implemented", NULL);
78390d27e7fSJason Zhu ret = -1;
78490d27e7fSJason Zhu #endif
78590d27e7fSJason Zhu break;
78690d27e7fSJason Zhu }
78790d27e7fSJason Zhu case FB_UNLOCKED: {
78837a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
78990d27e7fSJason Zhu uint8_t flash_lock_state = 0;
79090d27e7fSJason Zhu
79190d27e7fSJason Zhu if (rk_avb_read_flash_lock_state(&flash_lock_state))
79290d27e7fSJason Zhu fb_add_string(response, chars_left, "yes", NULL);
79390d27e7fSJason Zhu else
79490d27e7fSJason Zhu fb_add_string(response, chars_left, "no", NULL);
79590d27e7fSJason Zhu #else
79690d27e7fSJason Zhu fb_add_string(response, chars_left, "not implemented", NULL);
79790d27e7fSJason Zhu ret = -1;
79890d27e7fSJason Zhu #endif
79990d27e7fSJason Zhu break;
80090d27e7fSJason Zhu }
80190d27e7fSJason Zhu case FB_OFF_MODE_CHARGE: {
80290d27e7fSJason Zhu fb_add_string(response, chars_left, "not implemented", NULL);
80390d27e7fSJason Zhu break;
80490d27e7fSJason Zhu }
80590d27e7fSJason Zhu case FB_BATT_VOLTAGE: {
80690d27e7fSJason Zhu fb_add_string(response, chars_left, "not implemented", NULL);
80790d27e7fSJason Zhu break;
80890d27e7fSJason Zhu }
80990d27e7fSJason Zhu case FB_BATT_SOC_OK: {
81090d27e7fSJason Zhu fb_add_string(response, chars_left, "no", NULL);
81190d27e7fSJason Zhu break;
81290d27e7fSJason Zhu }
8139b323397SJoseph Chen case FB_IS_USERSPACE: {
8149b323397SJoseph Chen fb_add_string(response, chars_left, "no", NULL);
8159b323397SJoseph Chen break;
8169b323397SJoseph Chen }
81790d27e7fSJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
81890d27e7fSJason Zhu case FB_HAS_COUNT: {
819367cce4dSXu Hongfei char slot_count[2];
820367cce4dSXu Hongfei char temp;
821367cce4dSXu Hongfei
822367cce4dSXu Hongfei slot_count[1] = '\0';
82390d27e7fSJason Zhu if (rk_avb_read_slot_count(&temp) < 0) {
82490d27e7fSJason Zhu fb_add_number(response, chars_left, "%d", 0);
82590d27e7fSJason Zhu ret = -1;
82690d27e7fSJason Zhu break;
82790d27e7fSJason Zhu }
828367cce4dSXu Hongfei slot_count[0] = temp + 0x30;
82990d27e7fSJason Zhu fb_add_string(response, chars_left, slot_count, NULL);
83090d27e7fSJason Zhu break;
83190d27e7fSJason Zhu }
83290d27e7fSJason Zhu case FB_HAS_SLOT: {
83390d27e7fSJason Zhu char *part_name = cmd;
83490d27e7fSJason Zhu int has_slot = -1;
83590d27e7fSJason Zhu
83690d27e7fSJason Zhu cmd = strsep(&part_name, ":");
83790d27e7fSJason Zhu if (!cmd || !part_name) {
83890d27e7fSJason Zhu fb_add_string(response, chars_left,
83990d27e7fSJason Zhu "argument Invalid!", NULL);
84090d27e7fSJason Zhu ret = -1;
84190d27e7fSJason Zhu break;
84290d27e7fSJason Zhu }
84390d27e7fSJason Zhu
84490d27e7fSJason Zhu has_slot = rk_avb_get_part_has_slot_info(part_name);
84590d27e7fSJason Zhu if (has_slot < 0)
84690d27e7fSJason Zhu fb_add_string(response, chars_left, "no", NULL);
84790d27e7fSJason Zhu else
84890d27e7fSJason Zhu fb_add_string(response, chars_left, "yes", NULL);
84990d27e7fSJason Zhu break;
85090d27e7fSJason Zhu }
85190d27e7fSJason Zhu case FB_CURR_SLOT: {
852367cce4dSXu Hongfei char slot_surrent[8] = {0};
853367cce4dSXu Hongfei
85490d27e7fSJason Zhu if (!rk_avb_get_current_slot(slot_surrent)) {
85590d27e7fSJason Zhu fb_add_string(response, chars_left,
85690d27e7fSJason Zhu slot_surrent + 1, NULL);
85790d27e7fSJason Zhu } else {
85890d27e7fSJason Zhu fb_add_string(response, chars_left, "get error", NULL);
85990d27e7fSJason Zhu ret = -1;
86090d27e7fSJason Zhu }
86190d27e7fSJason Zhu break;
86290d27e7fSJason Zhu }
86390d27e7fSJason Zhu case FB_SLOT_SUFFIXES: {
86490d27e7fSJason Zhu char slot_suffixes_temp[4] = {0};
86590d27e7fSJason Zhu char slot_suffixes[9] = {0};
866367cce4dSXu Hongfei int slot_cnt = 0;
867367cce4dSXu Hongfei
86837a7bc39SJason Zhu rk_avb_read_slot_suffixes(slot_suffixes_temp);
869367cce4dSXu Hongfei while (slot_suffixes_temp[slot_cnt] != '\0') {
870367cce4dSXu Hongfei slot_suffixes[slot_cnt * 2]
871367cce4dSXu Hongfei = slot_suffixes_temp[slot_cnt];
872367cce4dSXu Hongfei slot_suffixes[slot_cnt * 2 + 1] = ',';
873367cce4dSXu Hongfei slot_cnt++;
874367cce4dSXu Hongfei }
875367cce4dSXu Hongfei
87690d27e7fSJason Zhu slot_suffixes[(slot_cnt - 1) * 2 + 1] = '\0';
87790d27e7fSJason Zhu fb_add_string(response, chars_left, slot_suffixes, NULL);
87890d27e7fSJason Zhu break;
879367cce4dSXu Hongfei }
88090d27e7fSJason Zhu case FB_SLOT_SUCCESSFUL:{
881374a9995SCody Xie char *slot_name = cmd;
88290d27e7fSJason Zhu AvbABData ab_info;
883374a9995SCody Xie
884374a9995SCody Xie cmd = strsep(&slot_name, ":");
88590d27e7fSJason Zhu if (!cmd || !slot_name) {
88690d27e7fSJason Zhu fb_add_string(response, chars_left,
88790d27e7fSJason Zhu "argument Invalid!", NULL);
88890d27e7fSJason Zhu ret = -1;
88990d27e7fSJason Zhu break;
890374a9995SCody Xie }
891374a9995SCody Xie
89290d27e7fSJason Zhu if (rk_avb_get_ab_info(&ab_info) < 0) {
89390d27e7fSJason Zhu fb_add_string(response, chars_left,
89490d27e7fSJason Zhu "get ab info failed!", NULL);
89590d27e7fSJason Zhu ret = -1;
89690d27e7fSJason Zhu break;
897374a9995SCody Xie }
898374a9995SCody Xie
899374a9995SCody Xie if (!strcmp(slot_name, "a")) {
90090d27e7fSJason Zhu if (ab_info.slots[0].successful_boot)
90190d27e7fSJason Zhu fb_add_string(response, chars_left,
90290d27e7fSJason Zhu "yes", NULL);
90390d27e7fSJason Zhu else
90490d27e7fSJason Zhu fb_add_string(response, chars_left,
90590d27e7fSJason Zhu "no", NULL);
906374a9995SCody Xie } else if (!strcmp(slot_name, "b")) {
90790d27e7fSJason Zhu if (ab_info.slots[1].successful_boot)
90890d27e7fSJason Zhu fb_add_string(response, chars_left,
90990d27e7fSJason Zhu "yes", NULL);
91090d27e7fSJason Zhu else
91190d27e7fSJason Zhu fb_add_string(response, chars_left,
91290d27e7fSJason Zhu "no", NULL);
91390d27e7fSJason Zhu } else {
91490d27e7fSJason Zhu fb_add_string(response, chars_left, "no", NULL);
91590d27e7fSJason Zhu }
91690d27e7fSJason Zhu break;
91790d27e7fSJason Zhu }
91890d27e7fSJason Zhu case FB_SLOT_UNBOOTABLE: {
91990d27e7fSJason Zhu char *slot_name = cmd;
92090d27e7fSJason Zhu AvbABData ab_info;
92190d27e7fSJason Zhu
92290d27e7fSJason Zhu cmd = strsep(&slot_name, ":");
92390d27e7fSJason Zhu
92490d27e7fSJason Zhu if (!cmd || !slot_name) {
92590d27e7fSJason Zhu fb_add_string(response, chars_left,
92690d27e7fSJason Zhu "argument Invalid!", NULL);
92790d27e7fSJason Zhu ret = -1;
92890d27e7fSJason Zhu break;
92990d27e7fSJason Zhu }
93090d27e7fSJason Zhu
93190d27e7fSJason Zhu if (rk_avb_get_ab_info(&ab_info) < 0) {
93290d27e7fSJason Zhu fb_add_string(response, chars_left,
93390d27e7fSJason Zhu "get ab info failed!", NULL);
93490d27e7fSJason Zhu ret = -1;
93590d27e7fSJason Zhu break;
93690d27e7fSJason Zhu }
93790d27e7fSJason Zhu
93890d27e7fSJason Zhu if (!strcmp(slot_name, "a")) {
93990d27e7fSJason Zhu if (!ab_info.slots[0].successful_boot &&
94090d27e7fSJason Zhu !ab_info.slots[0].tries_remaining &&
94190d27e7fSJason Zhu !ab_info.slots[0].priority)
94290d27e7fSJason Zhu fb_add_string(response, chars_left,
94390d27e7fSJason Zhu "yes", NULL);
94490d27e7fSJason Zhu else
94590d27e7fSJason Zhu fb_add_string(response, chars_left, "no", NULL);
94690d27e7fSJason Zhu } else if (!strcmp(slot_name, "b")) {
94790d27e7fSJason Zhu if (!ab_info.slots[1].successful_boot &&
94890d27e7fSJason Zhu !ab_info.slots[1].tries_remaining &&
94990d27e7fSJason Zhu !ab_info.slots[1].priority)
95090d27e7fSJason Zhu fb_add_string(response, chars_left,
95190d27e7fSJason Zhu "yes", NULL);
95290d27e7fSJason Zhu else
95390d27e7fSJason Zhu fb_add_string(response, chars_left, "no", NULL);
95490d27e7fSJason Zhu } else {
95590d27e7fSJason Zhu fb_add_string(response, chars_left, "no", NULL);
95690d27e7fSJason Zhu }
95790d27e7fSJason Zhu break;
95890d27e7fSJason Zhu }
95990d27e7fSJason Zhu case FB_SLOT_RETRY_COUNT: {
96090d27e7fSJason Zhu char *slot_name = cmd;
96190d27e7fSJason Zhu AvbABData ab_info;
96290d27e7fSJason Zhu
96390d27e7fSJason Zhu cmd = strsep(&slot_name, ":");
96490d27e7fSJason Zhu if (!cmd || !slot_name) {
96590d27e7fSJason Zhu fb_add_string(response, chars_left,
96690d27e7fSJason Zhu "argument Invalid!", NULL);
96790d27e7fSJason Zhu ret = -1;
96890d27e7fSJason Zhu break;
96990d27e7fSJason Zhu }
97090d27e7fSJason Zhu
97190d27e7fSJason Zhu if (rk_avb_get_ab_info(&ab_info) < 0) {
97290d27e7fSJason Zhu fb_add_string(response, chars_left,
97390d27e7fSJason Zhu "get ab info failed!", NULL);
97490d27e7fSJason Zhu ret = -1;
97590d27e7fSJason Zhu break;
97690d27e7fSJason Zhu }
97790d27e7fSJason Zhu
97890d27e7fSJason Zhu if (!strcmp(slot_name, "a")) {
97990d27e7fSJason Zhu fb_add_number(response, chars_left,
98090d27e7fSJason Zhu "%d", ab_info.slots[0].tries_remaining);
98190d27e7fSJason Zhu } else if (!strcmp(slot_name, "b")) {
98290d27e7fSJason Zhu fb_add_number(response, chars_left, "%d",
98390d27e7fSJason Zhu ab_info.slots[1].tries_remaining);
98490d27e7fSJason Zhu
985374a9995SCody Xie } else {
986374a9995SCody Xie strcpy(response, "FAILno");
987374a9995SCody Xie }
98890d27e7fSJason Zhu break;
989367cce4dSXu Hongfei }
99090d27e7fSJason Zhu case FB_AT_VBST: {
99190d27e7fSJason Zhu char vbst[VBOOT_STATE_SIZE] = {0};
99290d27e7fSJason Zhu char *p_vbst;
993f61a997eSqiujian
99490d27e7fSJason Zhu strcpy(response, "INFO");
99590d27e7fSJason Zhu rk_avb_get_at_vboot_state(vbst);
99690d27e7fSJason Zhu p_vbst = vbst;
99790d27e7fSJason Zhu do {
99890d27e7fSJason Zhu cmd = strsep(&p_vbst, "\n");
99990d27e7fSJason Zhu if (strlen(cmd) > 0) {
100090d27e7fSJason Zhu memcpy(&response[4], cmd, chars_left);
100190d27e7fSJason Zhu fastboot_tx_write_str(response);
1002f61a997eSqiujian }
100390d27e7fSJason Zhu } while (strlen(cmd));
100490d27e7fSJason Zhu break;
100590d27e7fSJason Zhu }
1006*40a6a2cbSDayao Ji case FB_SNAPSHOT_STATUS: {
1007*40a6a2cbSDayao Ji #ifdef CONFIG_ANDROID_AB
1008*40a6a2cbSDayao Ji struct misc_virtual_ab_message state;
1009*40a6a2cbSDayao Ji
1010*40a6a2cbSDayao Ji memset(&state, 0x0, sizeof(state));
1011*40a6a2cbSDayao Ji if (read_misc_virtual_ab_message(&state) != 0) {
1012*40a6a2cbSDayao Ji printf("FB_SNAPSHOT_STATUS read_misc_virtual_ab_message failed!\n");
1013*40a6a2cbSDayao Ji fb_add_string(response, chars_left, "get error", NULL);
1014*40a6a2cbSDayao Ji ret = -1;
1015*40a6a2cbSDayao Ji }
1016*40a6a2cbSDayao Ji
1017*40a6a2cbSDayao Ji if (state.magic != MISC_VIRTUAL_AB_MAGIC_HEADER) {
1018*40a6a2cbSDayao Ji printf("FB_SNAPSHOT_STATUS not virtual A/B metadata!\n");
1019*40a6a2cbSDayao Ji fb_add_string(response, chars_left, "get error", NULL);
1020*40a6a2cbSDayao Ji ret = -1;
1021*40a6a2cbSDayao Ji }
1022*40a6a2cbSDayao Ji
1023*40a6a2cbSDayao Ji if (state.merge_status == ENUM_MERGE_STATUS_MERGING) {
1024*40a6a2cbSDayao Ji fb_add_string(response, chars_left, "merging", NULL);
1025*40a6a2cbSDayao Ji } else if (state.merge_status == ENUM_MERGE_STATUS_SNAPSHOTTED) {
1026*40a6a2cbSDayao Ji fb_add_string(response, chars_left, "snapshotted", NULL);
1027*40a6a2cbSDayao Ji } else {
1028*40a6a2cbSDayao Ji fb_add_string(response, chars_left, "none", NULL);
1029*40a6a2cbSDayao Ji }
1030*40a6a2cbSDayao Ji #else
1031*40a6a2cbSDayao Ji fb_add_string(response, chars_left, "get error", NULL);
1032*40a6a2cbSDayao Ji ret = -1;
1033*40a6a2cbSDayao Ji #endif
1034*40a6a2cbSDayao Ji break;
1035*40a6a2cbSDayao Ji }
1036*40a6a2cbSDayao Ji
103790d27e7fSJason Zhu #endif
103890d27e7fSJason Zhu #ifdef CONFIG_OPTEE_CLIENT
103990d27e7fSJason Zhu case FB_AT_DH: {
104090d27e7fSJason Zhu char dhbuf[ATTEST_DH_SIZE];
104190d27e7fSJason Zhu uint32_t dh_len = ATTEST_DH_SIZE;
104290d27e7fSJason Zhu uint32_t res = trusty_attest_dh((uint8_t *)dhbuf, &dh_len);
1043f61a997eSqiujian
104490d27e7fSJason Zhu if (res) {
104590d27e7fSJason Zhu fb_add_string(response, chars_left, "dh not set", NULL);
104690d27e7fSJason Zhu ret = -1;
10473aab70afSSebastian Siewior } else {
104890d27e7fSJason Zhu fb_add_string(response, chars_left, dhbuf, NULL);
104990d27e7fSJason Zhu }
105090d27e7fSJason Zhu break;
105190d27e7fSJason Zhu }
105290d27e7fSJason Zhu case FB_AT_UUID: {
105390d27e7fSJason Zhu char uuid[ATTEST_UUID_SIZE] = {0};
105490d27e7fSJason Zhu uint32_t uuid_len = ATTEST_UUID_SIZE;
105590d27e7fSJason Zhu uint32_t res = trusty_attest_uuid((uint8_t *)uuid, &uuid_len);
105690d27e7fSJason Zhu
105790d27e7fSJason Zhu uuid[ATTEST_UUID_SIZE - 1] = 0;
105890d27e7fSJason Zhu if (res) {
105990d27e7fSJason Zhu fb_add_string(response, chars_left, "dh not set", NULL);
106090d27e7fSJason Zhu ret = -1;
106190d27e7fSJason Zhu } else {
106290d27e7fSJason Zhu fb_add_string(response, chars_left, uuid, NULL);
106390d27e7fSJason Zhu }
106490d27e7fSJason Zhu break;
106590d27e7fSJason Zhu }
106690d27e7fSJason Zhu #endif
106790d27e7fSJason Zhu default: {
1068b1f2a17cSnicolas.le.bayon@st.com char *envstr;
106974322201SRob Herring
1070b1f2a17cSnicolas.le.bayon@st.com envstr = malloc(strlen("fastboot.") + strlen(cmd) + 1);
1071b1f2a17cSnicolas.le.bayon@st.com if (!envstr) {
107290d27e7fSJason Zhu fb_add_string(response, chars_left,
107390d27e7fSJason Zhu "malloc error", NULL);
107490d27e7fSJason Zhu ret = -1;
107590d27e7fSJason Zhu break;
1076b1f2a17cSnicolas.le.bayon@st.com }
1077b1f2a17cSnicolas.le.bayon@st.com
1078b1f2a17cSnicolas.le.bayon@st.com sprintf(envstr, "fastboot.%s", cmd);
107900caae6dSSimon Glass s = env_get(envstr);
108074322201SRob Herring if (s) {
108174322201SRob Herring strncat(response, s, chars_left);
108274322201SRob Herring } else {
1083a18c2706SSteve Rae printf("WARNING: unknown variable: %s\n", cmd);
108490d27e7fSJason Zhu fb_add_string(response, chars_left,
108590d27e7fSJason Zhu "not implemented", NULL);
10863aab70afSSebastian Siewior }
1087b1f2a17cSnicolas.le.bayon@st.com
1088b1f2a17cSnicolas.le.bayon@st.com free(envstr);
108990d27e7fSJason Zhu break;
109090d27e7fSJason Zhu }
109190d27e7fSJason Zhu }
109290d27e7fSJason Zhu
109390d27e7fSJason Zhu return ret;
109490d27e7fSJason Zhu }
109590d27e7fSJason Zhu
109690d27e7fSJason Zhu static const struct {
109790d27e7fSJason Zhu /*
109890d27e7fSJason Zhu *any changes to this array require an update to the corresponding
109990d27e7fSJason Zhu *enum in fastboot.h
110090d27e7fSJason Zhu */
110190d27e7fSJason Zhu struct name_string name;
110290d27e7fSJason Zhu fb_getvar_t var;
110390d27e7fSJason Zhu } getvar_table[] = {
110490d27e7fSJason Zhu { NAME_NO_ARGS("version"), FB_VERSION},
110590d27e7fSJason Zhu { NAME_NO_ARGS("version-bootloader"), FB_BOOTLOADER_VERSION},
110690d27e7fSJason Zhu { NAME_NO_ARGS("version-baseband"), FB_BASEBAND_VERSION},
110790d27e7fSJason Zhu { NAME_NO_ARGS("product"), FB_PRODUCT},
110890d27e7fSJason Zhu { NAME_NO_ARGS("serialno"), FB_SERIAL_NO},
110990d27e7fSJason Zhu { NAME_NO_ARGS("secure"), FB_SECURE},
111090d27e7fSJason Zhu { NAME_NO_ARGS("max-download-size"), FB_DWNLD_SIZE},
111190d27e7fSJason Zhu { NAME_NO_ARGS("logical-block-size"), FB_BLK_SIZE},
111290d27e7fSJason Zhu { NAME_NO_ARGS("erase-block-size"), FB_ERASE_SIZE},
111390d27e7fSJason Zhu { NAME_ARGS("partition-type", ':'), FB_PART_TYPE},
111490d27e7fSJason Zhu { NAME_ARGS("partition-size", ':'), FB_PART_SIZE},
111590d27e7fSJason Zhu { NAME_NO_ARGS("unlocked"), FB_UNLOCKED},
111690d27e7fSJason Zhu { NAME_NO_ARGS("off-mode-charge"), FB_OFF_MODE_CHARGE},
111790d27e7fSJason Zhu { NAME_NO_ARGS("battery-voltage"), FB_BATT_VOLTAGE},
111890d27e7fSJason Zhu { NAME_NO_ARGS("variant"), FB_VARIANT},
111990d27e7fSJason Zhu { NAME_NO_ARGS("battery-soc-ok"), FB_BATT_SOC_OK},
11209b323397SJoseph Chen { NAME_NO_ARGS("is-userspace"), FB_IS_USERSPACE},
112190d27e7fSJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
112290d27e7fSJason Zhu /* Slots related */
112390d27e7fSJason Zhu { NAME_NO_ARGS("slot-count"), FB_HAS_COUNT},
112490d27e7fSJason Zhu { NAME_ARGS("has-slot", ':'), FB_HAS_SLOT},
112590d27e7fSJason Zhu { NAME_NO_ARGS("current-slot"), FB_CURR_SLOT},
112690d27e7fSJason Zhu { NAME_NO_ARGS("slot-suffixes"), FB_SLOT_SUFFIXES},
112790d27e7fSJason Zhu { NAME_ARGS("slot-successful", ':'), FB_SLOT_SUCCESSFUL},
112890d27e7fSJason Zhu { NAME_ARGS("slot-unbootable", ':'), FB_SLOT_UNBOOTABLE},
112990d27e7fSJason Zhu { NAME_ARGS("slot-retry-count", ':'), FB_SLOT_RETRY_COUNT},
113090d27e7fSJason Zhu { NAME_NO_ARGS("at-vboot-state"), FB_AT_VBST},
1131*40a6a2cbSDayao Ji { NAME_NO_ARGS("snapshot-update-status"), FB_SNAPSHOT_STATUS},
113290d27e7fSJason Zhu #endif
113390d27e7fSJason Zhu /*
113490d27e7fSJason Zhu * OEM specific :
113590d27e7fSJason Zhu * Spec says names starting with lowercase letter are reserved.
113690d27e7fSJason Zhu */
113790d27e7fSJason Zhu #ifdef CONFIG_OPTEE_CLIENT
113890d27e7fSJason Zhu { NAME_NO_ARGS("at-attest-dh"), FB_AT_DH},
113990d27e7fSJason Zhu { NAME_NO_ARGS("at-attest-uuid"), FB_AT_UUID},
114090d27e7fSJason Zhu #endif
114190d27e7fSJason Zhu };
114290d27e7fSJason Zhu
fb_getvar_single(char * cmd,char * response,size_t chars_left)114390d27e7fSJason Zhu static int fb_getvar_single(char *cmd, char *response, size_t chars_left)
114490d27e7fSJason Zhu {
114590d27e7fSJason Zhu int i;
114690d27e7fSJason Zhu size_t match_len = 0;
114790d27e7fSJason Zhu size_t len = strlen(cmd);
114890d27e7fSJason Zhu
114990d27e7fSJason Zhu for (i = 0; i < ARRAY_SIZE(getvar_table); i++) {
115090d27e7fSJason Zhu match_len = name_check_match(cmd, len, &getvar_table[i].name);
115190d27e7fSJason Zhu if (match_len)
115290d27e7fSJason Zhu break;
115390d27e7fSJason Zhu }
115490d27e7fSJason Zhu
115590d27e7fSJason Zhu if (match_len == 0) {
115690d27e7fSJason Zhu fb_add_string(response, chars_left, "unknown variable", NULL);
115790d27e7fSJason Zhu return -1;
115890d27e7fSJason Zhu }
115990d27e7fSJason Zhu
116090d27e7fSJason Zhu if (fb_read_var(cmd, response, getvar_table[i].var, chars_left) < 0)
116190d27e7fSJason Zhu return -1;
116290d27e7fSJason Zhu
116390d27e7fSJason Zhu return 0;
116490d27e7fSJason Zhu }
116590d27e7fSJason Zhu
fb_getvar_all(void)116690d27e7fSJason Zhu static void fb_getvar_all(void)
116790d27e7fSJason Zhu {
116890d27e7fSJason Zhu char response[FASTBOOT_RESPONSE_LEN] = {0};
116990d27e7fSJason Zhu char resp_tmp[FASTBOOT_RESPONSE_LEN] = {0};
117090d27e7fSJason Zhu char *actual_resp;
117190d27e7fSJason Zhu size_t chars_left;
117290d27e7fSJason Zhu int i, p;
117390d27e7fSJason Zhu disk_partition_t part_info;
117490d27e7fSJason Zhu struct blk_desc *dev_desc;
117590d27e7fSJason Zhu
117690d27e7fSJason Zhu strcpy(response, "INFO");
117790d27e7fSJason Zhu chars_left = sizeof(response) - strlen(response) - 1;
117890d27e7fSJason Zhu actual_resp = response + strlen(response);
117990d27e7fSJason Zhu
118090d27e7fSJason Zhu for (i = 0; i < ARRAY_SIZE(getvar_table); i++) {
118190d27e7fSJason Zhu fb_getvar_t var = getvar_table[i].var;
118290d27e7fSJason Zhu
118390d27e7fSJason Zhu switch (var) {
118490d27e7fSJason Zhu case FB_PART_TYPE:
118590d27e7fSJason Zhu case FB_PART_SIZE: {
118690d27e7fSJason Zhu const char *fs_type = NULL;
118790d27e7fSJason Zhu #ifdef CONFIG_RKIMG_BOOTLOADER
118890d27e7fSJason Zhu dev_desc = rockchip_get_bootdev();
118990d27e7fSJason Zhu #else
119090d27e7fSJason Zhu dev_desc = NULL;
119190d27e7fSJason Zhu #endif
119290d27e7fSJason Zhu if (!dev_desc) {
119390d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
119490d27e7fSJason Zhu "%s:block device not found",
119590d27e7fSJason Zhu getvar_table[i].name.str);
119690d27e7fSJason Zhu fastboot_tx_write_str(response);
119790d27e7fSJason Zhu break;
119890d27e7fSJason Zhu }
119990d27e7fSJason Zhu
120090d27e7fSJason Zhu for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
120190d27e7fSJason Zhu if (part_get_info(dev_desc, p,
120290d27e7fSJason Zhu &part_info) < 0) {
120390d27e7fSJason Zhu break;
120490d27e7fSJason Zhu }
120590d27e7fSJason Zhu
120690d27e7fSJason Zhu if (var == FB_PART_TYPE) {
120790d27e7fSJason Zhu fs_type = NULL;
120890d27e7fSJason Zhu if (fb_get_fstype("mmc", p,
120990d27e7fSJason Zhu &fs_type)) {
121090d27e7fSJason Zhu fb_add_string(
121190d27e7fSJason Zhu resp_tmp,
121290d27e7fSJason Zhu FASTBOOT_RESPONSE_LEN,
121390d27e7fSJason Zhu (char *)part_info.type,
121490d27e7fSJason Zhu NULL);
121590d27e7fSJason Zhu } else {
121690d27e7fSJason Zhu fb_add_string(
121790d27e7fSJason Zhu resp_tmp,
121890d27e7fSJason Zhu FASTBOOT_RESPONSE_LEN,
121990d27e7fSJason Zhu fs_type,
122090d27e7fSJason Zhu NULL);
122190d27e7fSJason Zhu }
122290d27e7fSJason Zhu
122390d27e7fSJason Zhu snprintf(actual_resp,
122490d27e7fSJason Zhu chars_left,
122590d27e7fSJason Zhu "%s:%s:%s",
122690d27e7fSJason Zhu getvar_table[i].name.str,
122790d27e7fSJason Zhu part_info.name,
122890d27e7fSJason Zhu resp_tmp);
122990d27e7fSJason Zhu } else {
123090d27e7fSJason Zhu uint64_t part_size;
123190d27e7fSJason Zhu
123290d27e7fSJason Zhu part_size = (uint64_t)part_info.size;
123390d27e7fSJason Zhu snprintf(actual_resp,
123490d27e7fSJason Zhu chars_left,
123590d27e7fSJason Zhu "%s:%s:0x%llx",
123690d27e7fSJason Zhu getvar_table[i].name.str,
123790d27e7fSJason Zhu part_info.name,
123890d27e7fSJason Zhu part_size * dev_desc->blksz);
123974322201SRob Herring }
12403aab70afSSebastian Siewior fastboot_tx_write_str(response);
12413aab70afSSebastian Siewior }
124290d27e7fSJason Zhu break;
124390d27e7fSJason Zhu }
124490d27e7fSJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
124590d27e7fSJason Zhu case FB_HAS_SLOT: {
124690d27e7fSJason Zhu uchar *ptr_name_tmp;
124790d27e7fSJason Zhu char c = '_';
124890d27e7fSJason Zhu int has_slot = -1;
124990d27e7fSJason Zhu
125090d27e7fSJason Zhu #ifdef CONFIG_RKIMG_BOOTLOADER
125190d27e7fSJason Zhu dev_desc = rockchip_get_bootdev();
125290d27e7fSJason Zhu #else
125390d27e7fSJason Zhu dev_desc = NULL;
125490d27e7fSJason Zhu #endif
125590d27e7fSJason Zhu if (!dev_desc) {
125690d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
125790d27e7fSJason Zhu "%s:block device not found",
125890d27e7fSJason Zhu getvar_table[i].name.str);
125990d27e7fSJason Zhu fastboot_tx_write_str(response);
126090d27e7fSJason Zhu break;
126190d27e7fSJason Zhu }
126290d27e7fSJason Zhu
126390d27e7fSJason Zhu for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
126490d27e7fSJason Zhu if (part_get_info(dev_desc, p,
126590d27e7fSJason Zhu &part_info) < 0) {
126690d27e7fSJason Zhu break;
126790d27e7fSJason Zhu } else {
126890d27e7fSJason Zhu ptr_name_tmp = (uchar *)strrchr(
126990d27e7fSJason Zhu (char *)part_info.name, c);
127090d27e7fSJason Zhu if (ptr_name_tmp &&
127190d27e7fSJason Zhu part_info.name[ptr_name_tmp -
127290d27e7fSJason Zhu part_info.name + 2] == '\0')
127390d27e7fSJason Zhu fb_add_string(
127490d27e7fSJason Zhu resp_tmp,
127590d27e7fSJason Zhu ptr_name_tmp -
127690d27e7fSJason Zhu part_info.name + 1,
127790d27e7fSJason Zhu (char *)part_info.name,
127890d27e7fSJason Zhu NULL);
127990d27e7fSJason Zhu else
128090d27e7fSJason Zhu strcpy(resp_tmp,
128190d27e7fSJason Zhu (char *)part_info.name);
128290d27e7fSJason Zhu
128390d27e7fSJason Zhu has_slot = rk_avb_get_part_has_slot_info(
128490d27e7fSJason Zhu resp_tmp);
128590d27e7fSJason Zhu if (has_slot < 0) {
128690d27e7fSJason Zhu snprintf(actual_resp,
128790d27e7fSJason Zhu chars_left,
128890d27e7fSJason Zhu "%s:%s:no",
128990d27e7fSJason Zhu getvar_table[i].name.str,
129090d27e7fSJason Zhu resp_tmp);
129190d27e7fSJason Zhu } else {
129290d27e7fSJason Zhu snprintf(actual_resp,
129390d27e7fSJason Zhu chars_left,
129490d27e7fSJason Zhu "%s:%s:yes",
129590d27e7fSJason Zhu getvar_table[i].name.str,
129690d27e7fSJason Zhu resp_tmp);
129790d27e7fSJason Zhu p++;
129890d27e7fSJason Zhu }
129990d27e7fSJason Zhu
130090d27e7fSJason Zhu fastboot_tx_write_str(response);
130190d27e7fSJason Zhu }
130290d27e7fSJason Zhu }
130390d27e7fSJason Zhu break;
130490d27e7fSJason Zhu }
130590d27e7fSJason Zhu
130690d27e7fSJason Zhu case FB_SLOT_SUCCESSFUL: {
130790d27e7fSJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
130890d27e7fSJason Zhu AvbABData ab_info;
130990d27e7fSJason Zhu
131090d27e7fSJason Zhu if (rk_avb_get_ab_info(&ab_info) < 0) {
131190d27e7fSJason Zhu fb_add_string(actual_resp,
131290d27e7fSJason Zhu chars_left,
131390d27e7fSJason Zhu "%s:get ab info failed!",
131490d27e7fSJason Zhu getvar_table[i].name.str);
131590d27e7fSJason Zhu fastboot_tx_write_str(response);
131690d27e7fSJason Zhu break;
131790d27e7fSJason Zhu }
131890d27e7fSJason Zhu
131990d27e7fSJason Zhu if (ab_info.slots[0].successful_boot)
132090d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
132190d27e7fSJason Zhu "%s:a:yes",
132290d27e7fSJason Zhu getvar_table[i].name.str);
132390d27e7fSJason Zhu else
132490d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
132590d27e7fSJason Zhu "%s:a:no",
132690d27e7fSJason Zhu getvar_table[i].name.str);
132790d27e7fSJason Zhu fastboot_tx_write_str(response);
132890d27e7fSJason Zhu
132990d27e7fSJason Zhu if (ab_info.slots[1].successful_boot)
133090d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
133190d27e7fSJason Zhu "%s:b:yes",
133290d27e7fSJason Zhu getvar_table[i].name.str);
133390d27e7fSJason Zhu else
133490d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
133590d27e7fSJason Zhu "%s:b:no",
133690d27e7fSJason Zhu getvar_table[i].name.str);
133790d27e7fSJason Zhu fastboot_tx_write_str(response);
133890d27e7fSJason Zhu #else
133990d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
134090d27e7fSJason Zhu "%s:not find ab info!",
134190d27e7fSJason Zhu getvar_table[i].name.str);
134290d27e7fSJason Zhu fastboot_tx_write_str(response);
134390d27e7fSJason Zhu #endif
134490d27e7fSJason Zhu break;
134590d27e7fSJason Zhu }
134690d27e7fSJason Zhu
134790d27e7fSJason Zhu case FB_SLOT_UNBOOTABLE: {
134890d27e7fSJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
134990d27e7fSJason Zhu AvbABData ab_info;
135090d27e7fSJason Zhu
135190d27e7fSJason Zhu if (rk_avb_get_ab_info(&ab_info) < 0) {
135290d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
135390d27e7fSJason Zhu "%s:not find ab info!",
135490d27e7fSJason Zhu getvar_table[i].name.str);
135590d27e7fSJason Zhu fastboot_tx_write_str(response);
135690d27e7fSJason Zhu break;
135790d27e7fSJason Zhu }
135890d27e7fSJason Zhu
135990d27e7fSJason Zhu if (!ab_info.slots[0].successful_boot &&
136090d27e7fSJason Zhu !ab_info.slots[0].tries_remaining &&
136190d27e7fSJason Zhu !ab_info.slots[0].priority)
136290d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
136390d27e7fSJason Zhu "%s:a:yes",
136490d27e7fSJason Zhu getvar_table[i].name.str);
136590d27e7fSJason Zhu else
136690d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
136790d27e7fSJason Zhu "%s:a:no",
136890d27e7fSJason Zhu getvar_table[i].name.str);
136990d27e7fSJason Zhu fastboot_tx_write_str(response);
137090d27e7fSJason Zhu
137190d27e7fSJason Zhu if (!ab_info.slots[1].successful_boot &&
137290d27e7fSJason Zhu !ab_info.slots[1].tries_remaining &&
137390d27e7fSJason Zhu !ab_info.slots[1].priority)
137490d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
137590d27e7fSJason Zhu "%s:b:yes",
137690d27e7fSJason Zhu getvar_table[i].name.str);
137790d27e7fSJason Zhu else
137890d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
137990d27e7fSJason Zhu "%s:b:no",
138090d27e7fSJason Zhu getvar_table[i].name.str);
138190d27e7fSJason Zhu
138290d27e7fSJason Zhu fastboot_tx_write_str(response);
138390d27e7fSJason Zhu #else
138490d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
138590d27e7fSJason Zhu "%s:not find ab info!",
138690d27e7fSJason Zhu getvar_table[i].name.str);
138790d27e7fSJason Zhu fastboot_tx_write_str(response);
138890d27e7fSJason Zhu #endif
138990d27e7fSJason Zhu break;
139090d27e7fSJason Zhu }
139190d27e7fSJason Zhu
139290d27e7fSJason Zhu case FB_SLOT_RETRY_COUNT: {
139390d27e7fSJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
139490d27e7fSJason Zhu AvbABData ab_info;
139590d27e7fSJason Zhu
139690d27e7fSJason Zhu if (rk_avb_get_ab_info(&ab_info) < 0) {
139790d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
139890d27e7fSJason Zhu "%s:not find ab info!",
139990d27e7fSJason Zhu getvar_table[i].name.str);
140090d27e7fSJason Zhu fastboot_tx_write_str(response);
140190d27e7fSJason Zhu break;
140290d27e7fSJason Zhu }
140390d27e7fSJason Zhu
140490d27e7fSJason Zhu snprintf(actual_resp, chars_left, "%s:a:%d",
140590d27e7fSJason Zhu getvar_table[i].name.str,
140690d27e7fSJason Zhu ab_info.slots[1].tries_remaining);
140790d27e7fSJason Zhu fastboot_tx_write_str(response);
140890d27e7fSJason Zhu snprintf(actual_resp, chars_left, "%s:b:%d",
140990d27e7fSJason Zhu getvar_table[i].name.str,
141090d27e7fSJason Zhu ab_info.slots[1].tries_remaining);
141190d27e7fSJason Zhu fastboot_tx_write_str(response);
141290d27e7fSJason Zhu #else
141390d27e7fSJason Zhu fb_add_string(actual_resp, chars_left,
141490d27e7fSJason Zhu "%s:not find ab info!",
141590d27e7fSJason Zhu getvar_table[i].name.str);
141690d27e7fSJason Zhu fastboot_tx_write_str(response);
141790d27e7fSJason Zhu #endif
141890d27e7fSJason Zhu break;
141990d27e7fSJason Zhu }
142090d27e7fSJason Zhu #endif
142190d27e7fSJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
142290d27e7fSJason Zhu case FB_AT_VBST:
142390d27e7fSJason Zhu break;
142490d27e7fSJason Zhu #endif
142590d27e7fSJason Zhu default:
142690d27e7fSJason Zhu fb_getvar_single((char *)getvar_table[i].name.str,
142790d27e7fSJason Zhu resp_tmp, FASTBOOT_RESPONSE_LEN);
142890d27e7fSJason Zhu snprintf(actual_resp, chars_left, "%s:%s",
142990d27e7fSJason Zhu getvar_table[i].name.str, resp_tmp);
143090d27e7fSJason Zhu fastboot_tx_write_str(response);
143190d27e7fSJason Zhu }
143290d27e7fSJason Zhu }
143390d27e7fSJason Zhu }
143490d27e7fSJason Zhu
1435*40a6a2cbSDayao Ji #ifdef CONFIG_ANDROID_AB
get_current_slot(void)1436*40a6a2cbSDayao Ji static int get_current_slot(void)
1437*40a6a2cbSDayao Ji {
1438*40a6a2cbSDayao Ji #ifdef CONFIG_RK_AVB_LIBAVB_USER
1439*40a6a2cbSDayao Ji char cmd[8] = {0};
1440*40a6a2cbSDayao Ji unsigned int slot_number = -1;
1441*40a6a2cbSDayao Ji
1442*40a6a2cbSDayao Ji memset(cmd, 0x0, sizeof(cmd));
1443*40a6a2cbSDayao Ji rk_avb_get_current_slot(cmd);
1444*40a6a2cbSDayao Ji if (strncmp("_a", cmd, 2) == 0) {
1445*40a6a2cbSDayao Ji slot_number = 0;
1446*40a6a2cbSDayao Ji } else if (strncmp("_b", cmd, 2) == 0) {
1447*40a6a2cbSDayao Ji slot_number = 1;
1448*40a6a2cbSDayao Ji } else {
1449*40a6a2cbSDayao Ji pr_err("%s: FAILunkown slot name\n", __func__);
1450*40a6a2cbSDayao Ji return -1;
1451*40a6a2cbSDayao Ji }
1452*40a6a2cbSDayao Ji
1453*40a6a2cbSDayao Ji return slot_number;
1454*40a6a2cbSDayao Ji #else
1455*40a6a2cbSDayao Ji pr_err("%s: FAILnot implemented\n", __func__);
1456*40a6a2cbSDayao Ji return -1;
1457*40a6a2cbSDayao Ji #endif
1458*40a6a2cbSDayao Ji }
1459*40a6a2cbSDayao Ji
1460*40a6a2cbSDayao Ji #ifdef CONFIG_FASTBOOT_FLASH
should_prevent_userdata_wipe(void)1461*40a6a2cbSDayao Ji static int should_prevent_userdata_wipe(void)
1462*40a6a2cbSDayao Ji {
1463*40a6a2cbSDayao Ji struct misc_virtual_ab_message state;
1464*40a6a2cbSDayao Ji
1465*40a6a2cbSDayao Ji memset(&state, 0x0, sizeof(state));
1466*40a6a2cbSDayao Ji if (read_misc_virtual_ab_message(&state) != 0) {
1467*40a6a2cbSDayao Ji pr_err("%s: read_misc_virtual_ab_message failed!\n", __func__);
1468*40a6a2cbSDayao Ji return 0;
1469*40a6a2cbSDayao Ji }
1470*40a6a2cbSDayao Ji
1471*40a6a2cbSDayao Ji if (state.magic != MISC_VIRTUAL_AB_MAGIC_HEADER) {
1472*40a6a2cbSDayao Ji pr_err("%s: NOT virtual A/B metadata!\n", __func__);
1473*40a6a2cbSDayao Ji return 0;
1474*40a6a2cbSDayao Ji }
1475*40a6a2cbSDayao Ji
1476*40a6a2cbSDayao Ji if (state.merge_status == (uint8_t)ENUM_MERGE_STATUS_MERGING ||
1477*40a6a2cbSDayao Ji (state.merge_status == (uint8_t)ENUM_MERGE_STATUS_SNAPSHOTTED &&
1478*40a6a2cbSDayao Ji state.source_slot != get_current_slot())) {
1479*40a6a2cbSDayao Ji return 1;
1480*40a6a2cbSDayao Ji }
1481*40a6a2cbSDayao Ji
1482*40a6a2cbSDayao Ji return 0;
1483*40a6a2cbSDayao Ji }
1484*40a6a2cbSDayao Ji #endif
1485*40a6a2cbSDayao Ji
get_virtual_ab_merge_status(void)1486*40a6a2cbSDayao Ji static int get_virtual_ab_merge_status(void)
1487*40a6a2cbSDayao Ji {
1488*40a6a2cbSDayao Ji struct misc_virtual_ab_message state;
1489*40a6a2cbSDayao Ji
1490*40a6a2cbSDayao Ji memset(&state, 0x0, sizeof(state));
1491*40a6a2cbSDayao Ji if (read_misc_virtual_ab_message(&state) != 0) {
1492*40a6a2cbSDayao Ji pr_err("%s: read_misc_virtual_ab_message failed!\n", __func__);
1493*40a6a2cbSDayao Ji return -1;
1494*40a6a2cbSDayao Ji }
1495*40a6a2cbSDayao Ji
1496*40a6a2cbSDayao Ji if (state.magic != MISC_VIRTUAL_AB_MAGIC_HEADER) {
1497*40a6a2cbSDayao Ji pr_err("%s: NOT virtual A/B metadata!\n", __func__);
1498*40a6a2cbSDayao Ji return -1;
1499*40a6a2cbSDayao Ji }
1500*40a6a2cbSDayao Ji
1501*40a6a2cbSDayao Ji return state.merge_status;
1502*40a6a2cbSDayao Ji }
1503*40a6a2cbSDayao Ji #endif
1504*40a6a2cbSDayao Ji
cb_getvar(struct usb_ep * ep,struct usb_request * req)150590d27e7fSJason Zhu static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
150690d27e7fSJason Zhu {
150790d27e7fSJason Zhu char *cmd = req->buf;
150890d27e7fSJason Zhu char response[FASTBOOT_RESPONSE_LEN] = {0};
150990d27e7fSJason Zhu const char *str_read_all = "all";
151090d27e7fSJason Zhu size_t len = 0;
151190d27e7fSJason Zhu size_t chars_left;
151290d27e7fSJason Zhu
151390d27e7fSJason Zhu strsep(&cmd, ":");
151490d27e7fSJason Zhu if (!cmd) {
151590d27e7fSJason Zhu pr_err("missing variable");
151690d27e7fSJason Zhu fastboot_tx_write_str("FAILmissing var");
151790d27e7fSJason Zhu return;
151890d27e7fSJason Zhu }
151990d27e7fSJason Zhu
152090d27e7fSJason Zhu len = strlen(cmd);
152190d27e7fSJason Zhu if (len == strlen(str_read_all) &&
152290d27e7fSJason Zhu (strncmp(cmd, str_read_all, len) == 0)) {
152390d27e7fSJason Zhu fb_getvar_all();
152490d27e7fSJason Zhu fastboot_tx_write_str("OKAYDone!");
152590d27e7fSJason Zhu } else {
152690d27e7fSJason Zhu strcpy(response, "OKAY");
152790d27e7fSJason Zhu chars_left = sizeof(response) - strlen(response) - 1;
152890d27e7fSJason Zhu
152990d27e7fSJason Zhu if (fb_getvar_single(cmd, &response[strlen(response)],
153090d27e7fSJason Zhu chars_left) < 0) {
153190d27e7fSJason Zhu strcpy(cmd, "FAILunknown variable");
153290d27e7fSJason Zhu strncat(cmd, &response[strlen(response)], chars_left);
153390d27e7fSJason Zhu fastboot_tx_write_str(cmd);
153490d27e7fSJason Zhu return;
153590d27e7fSJason Zhu }
153690d27e7fSJason Zhu fastboot_tx_write_str(response);
153790d27e7fSJason Zhu }
153890d27e7fSJason Zhu
153990d27e7fSJason Zhu return;
154090d27e7fSJason Zhu }
15413aab70afSSebastian Siewior
rx_bytes_expected(struct usb_ep * ep)1542ac484c5aSRoger Quadros static unsigned int rx_bytes_expected(struct usb_ep *ep)
15433aab70afSSebastian Siewior {
15443aab70afSSebastian Siewior int rx_remain = download_size - download_bytes;
1545ac484c5aSRoger Quadros unsigned int rem;
1546ac484c5aSRoger Quadros unsigned int maxpacket = ep->maxpacket;
1547ac484c5aSRoger Quadros
1548ac484c5aSRoger Quadros if (rx_remain <= 0)
15493aab70afSSebastian Siewior return 0;
1550ac484c5aSRoger Quadros else if (rx_remain > EP_BUFFER_SIZE)
15513aab70afSSebastian Siewior return EP_BUFFER_SIZE;
1552ac484c5aSRoger Quadros
1553ac484c5aSRoger Quadros /*
1554ac484c5aSRoger Quadros * Some controllers e.g. DWC3 don't like OUT transfers to be
1555ac484c5aSRoger Quadros * not ending in maxpacket boundary. So just make them happy by
1556ac484c5aSRoger Quadros * always requesting for integral multiple of maxpackets.
1557ac484c5aSRoger Quadros * This shouldn't bother controllers that don't care about it.
1558ac484c5aSRoger Quadros */
15599e4b510dSDileep Katta rem = rx_remain % maxpacket;
1560ac484c5aSRoger Quadros if (rem > 0)
15619e4b510dSDileep Katta rx_remain = rx_remain + (maxpacket - rem);
1562ac484c5aSRoger Quadros
15633aab70afSSebastian Siewior return rx_remain;
15643aab70afSSebastian Siewior }
15653aab70afSSebastian Siewior
15663aab70afSSebastian Siewior #define BYTES_PER_DOT 0x20000
rx_handler_dl_image(struct usb_ep * ep,struct usb_request * req)15673aab70afSSebastian Siewior static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
15683aab70afSSebastian Siewior {
15693c8f98f5SMaxime Ripard char response[FASTBOOT_RESPONSE_LEN];
15703aab70afSSebastian Siewior unsigned int transfer_size = download_size - download_bytes;
15713aab70afSSebastian Siewior const unsigned char *buffer = req->buf;
15723aab70afSSebastian Siewior unsigned int buffer_size = req->actual;
157323d1d10cSBo Shen unsigned int pre_dot_num, now_dot_num;
15743aab70afSSebastian Siewior
15753aab70afSSebastian Siewior if (req->status != 0) {
15763aab70afSSebastian Siewior printf("Bad status: %d\n", req->status);
15773aab70afSSebastian Siewior return;
15783aab70afSSebastian Siewior }
15793aab70afSSebastian Siewior
15803aab70afSSebastian Siewior if (buffer_size < transfer_size)
15813aab70afSSebastian Siewior transfer_size = buffer_size;
15823aab70afSSebastian Siewior
1583a588d99aSPaul Kocialkowski memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes,
15843aab70afSSebastian Siewior buffer, transfer_size);
15853aab70afSSebastian Siewior
158623d1d10cSBo Shen pre_dot_num = download_bytes / BYTES_PER_DOT;
15873aab70afSSebastian Siewior download_bytes += transfer_size;
158823d1d10cSBo Shen now_dot_num = download_bytes / BYTES_PER_DOT;
158923d1d10cSBo Shen
159023d1d10cSBo Shen if (pre_dot_num != now_dot_num) {
159123d1d10cSBo Shen putc('.');
159223d1d10cSBo Shen if (!(now_dot_num % 74))
159323d1d10cSBo Shen putc('\n');
159423d1d10cSBo Shen }
15953aab70afSSebastian Siewior
15963aab70afSSebastian Siewior /* Check if transfer is done */
15973aab70afSSebastian Siewior if (download_bytes >= download_size) {
15983aab70afSSebastian Siewior /*
15993aab70afSSebastian Siewior * Reset global transfer variable, keep download_bytes because
16003aab70afSSebastian Siewior * it will be used in the next possible flashing command
16013aab70afSSebastian Siewior */
16023aab70afSSebastian Siewior download_size = 0;
16033aab70afSSebastian Siewior req->complete = rx_handler_command;
16043aab70afSSebastian Siewior req->length = EP_BUFFER_SIZE;
16053aab70afSSebastian Siewior
1606192bc694SBen Whitten strcpy(response, "OKAY");
16073aab70afSSebastian Siewior fastboot_tx_write_str(response);
16083aab70afSSebastian Siewior
16093aab70afSSebastian Siewior printf("\ndownloading of %d bytes finished\n", download_bytes);
16103aab70afSSebastian Siewior } else {
1611ac484c5aSRoger Quadros req->length = rx_bytes_expected(ep);
16123aab70afSSebastian Siewior }
16133aab70afSSebastian Siewior
16143aab70afSSebastian Siewior req->actual = 0;
16153aab70afSSebastian Siewior usb_ep_queue(ep, req, 0);
16163aab70afSSebastian Siewior }
16173aab70afSSebastian Siewior
cb_download(struct usb_ep * ep,struct usb_request * req)16183aab70afSSebastian Siewior static void cb_download(struct usb_ep *ep, struct usb_request *req)
16193aab70afSSebastian Siewior {
16203aab70afSSebastian Siewior char *cmd = req->buf;
16213c8f98f5SMaxime Ripard char response[FASTBOOT_RESPONSE_LEN];
16223aab70afSSebastian Siewior
16233aab70afSSebastian Siewior strsep(&cmd, ":");
16243aab70afSSebastian Siewior download_size = simple_strtoul(cmd, NULL, 16);
16253aab70afSSebastian Siewior download_bytes = 0;
16263aab70afSSebastian Siewior
16273aab70afSSebastian Siewior printf("Starting download of %d bytes\n", download_size);
16283aab70afSSebastian Siewior
16293aab70afSSebastian Siewior if (0 == download_size) {
1630192bc694SBen Whitten strcpy(response, "FAILdata invalid size");
1631a588d99aSPaul Kocialkowski } else if (download_size > CONFIG_FASTBOOT_BUF_SIZE) {
16323aab70afSSebastian Siewior download_size = 0;
1633192bc694SBen Whitten strcpy(response, "FAILdata too large");
16343aab70afSSebastian Siewior } else {
16353aab70afSSebastian Siewior sprintf(response, "DATA%08x", download_size);
16363aab70afSSebastian Siewior req->complete = rx_handler_dl_image;
1637ac484c5aSRoger Quadros req->length = rx_bytes_expected(ep);
16383aab70afSSebastian Siewior }
1639367cce4dSXu Hongfei
1640367cce4dSXu Hongfei fastboot_tx_write_str(response);
1641367cce4dSXu Hongfei }
1642367cce4dSXu Hongfei
tx_handler_ul(struct usb_ep * ep,struct usb_request * req)1643367cce4dSXu Hongfei static void tx_handler_ul(struct usb_ep *ep, struct usb_request *req)
1644367cce4dSXu Hongfei {
1645367cce4dSXu Hongfei unsigned int xfer_size = 0;
1646367cce4dSXu Hongfei unsigned int pre_dot_num, now_dot_num;
1647367cce4dSXu Hongfei unsigned int remain_size = 0;
1648367cce4dSXu Hongfei unsigned int transferred_size = req->actual;
1649367cce4dSXu Hongfei
1650367cce4dSXu Hongfei if (req->status != 0) {
1651367cce4dSXu Hongfei printf("Bad status: %d\n", req->status);
1652367cce4dSXu Hongfei return;
1653367cce4dSXu Hongfei }
1654367cce4dSXu Hongfei
1655367cce4dSXu Hongfei if (start_upload) {
1656367cce4dSXu Hongfei pre_dot_num = upload_bytes / BYTES_PER_DOT;
1657367cce4dSXu Hongfei upload_bytes += transferred_size;
1658367cce4dSXu Hongfei now_dot_num = upload_bytes / BYTES_PER_DOT;
1659367cce4dSXu Hongfei
1660367cce4dSXu Hongfei if (pre_dot_num != now_dot_num) {
1661367cce4dSXu Hongfei putc('.');
1662367cce4dSXu Hongfei if (!(now_dot_num % 74))
1663367cce4dSXu Hongfei putc('\n');
1664367cce4dSXu Hongfei }
1665367cce4dSXu Hongfei }
1666367cce4dSXu Hongfei
1667367cce4dSXu Hongfei remain_size = upload_size - upload_bytes;
1668367cce4dSXu Hongfei xfer_size = (remain_size > EP_BUFFER_SIZE) ?
1669367cce4dSXu Hongfei EP_BUFFER_SIZE : remain_size;
1670367cce4dSXu Hongfei
1671367cce4dSXu Hongfei debug("%s: remain_size=%d, transferred_size=%d",
1672367cce4dSXu Hongfei __func__, remain_size, transferred_size);
1673367cce4dSXu Hongfei debug("xfer_size=%d, upload_bytes=%d, upload_size=%d!\n",
1674367cce4dSXu Hongfei xfer_size, upload_bytes, upload_size);
1675367cce4dSXu Hongfei
1676367cce4dSXu Hongfei if (remain_size <= 0) {
1677367cce4dSXu Hongfei fastboot_func->in_req->complete = fastboot_complete;
1678aa74b607SJason Zhu wakeup_thread();
1679367cce4dSXu Hongfei fastboot_tx_write_str("OKAY");
1680367cce4dSXu Hongfei printf("\nuploading of %d bytes finished\n", upload_bytes);
1681367cce4dSXu Hongfei upload_bytes = 0;
1682367cce4dSXu Hongfei upload_size = 0;
1683367cce4dSXu Hongfei start_upload = false;
1684367cce4dSXu Hongfei return;
1685367cce4dSXu Hongfei }
1686367cce4dSXu Hongfei
1687367cce4dSXu Hongfei /* Remove the transfer callback which response the upload */
1688367cce4dSXu Hongfei /* request from host */
1689367cce4dSXu Hongfei if (!upload_bytes)
1690367cce4dSXu Hongfei start_upload = true;
1691367cce4dSXu Hongfei
1692174b4544SKever Yang fastboot_tx_write((char *)((phys_addr_t)CONFIG_FASTBOOT_BUF_ADDR + \
1693174b4544SKever Yang upload_bytes),
1694367cce4dSXu Hongfei xfer_size);
1695367cce4dSXu Hongfei }
1696367cce4dSXu Hongfei
cb_upload(struct usb_ep * ep,struct usb_request * req)1697367cce4dSXu Hongfei static void cb_upload(struct usb_ep *ep, struct usb_request *req)
1698367cce4dSXu Hongfei {
1699367cce4dSXu Hongfei char response[FASTBOOT_RESPONSE_LEN];
1700367cce4dSXu Hongfei
1701367cce4dSXu Hongfei printf("Starting upload of %d bytes\n", upload_size);
1702367cce4dSXu Hongfei
1703367cce4dSXu Hongfei if (0 == upload_size) {
1704367cce4dSXu Hongfei strcpy(response, "FAILdata invalid size");
1705367cce4dSXu Hongfei } else {
1706367cce4dSXu Hongfei start_upload = false;
1707367cce4dSXu Hongfei sprintf(response, "DATA%08x", upload_size);
1708367cce4dSXu Hongfei fastboot_func->in_req->complete = tx_handler_ul;
1709367cce4dSXu Hongfei }
1710367cce4dSXu Hongfei
17113aab70afSSebastian Siewior fastboot_tx_write_str(response);
17123aab70afSSebastian Siewior }
17133aab70afSSebastian Siewior
do_bootm_on_complete(struct usb_ep * ep,struct usb_request * req)17143aab70afSSebastian Siewior static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
17153aab70afSSebastian Siewior {
17163aab70afSSebastian Siewior char boot_addr_start[12];
17173aab70afSSebastian Siewior char *bootm_args[] = { "bootm", boot_addr_start, NULL };
17183aab70afSSebastian Siewior
17193aab70afSSebastian Siewior puts("Booting kernel..\n");
17203aab70afSSebastian Siewior
172190ae53ceSTom Rini sprintf(boot_addr_start, "0x%lx", (long)CONFIG_FASTBOOT_BUF_ADDR);
17223aab70afSSebastian Siewior do_bootm(NULL, 0, 2, bootm_args);
17233aab70afSSebastian Siewior
17243aab70afSSebastian Siewior /* This only happens if image is somehow faulty so we start over */
17253aab70afSSebastian Siewior do_reset(NULL, 0, 0, NULL);
17263aab70afSSebastian Siewior }
17273aab70afSSebastian Siewior
cb_boot(struct usb_ep * ep,struct usb_request * req)17283aab70afSSebastian Siewior static void cb_boot(struct usb_ep *ep, struct usb_request *req)
17293aab70afSSebastian Siewior {
17303aab70afSSebastian Siewior fastboot_func->in_req->complete = do_bootm_on_complete;
17313aab70afSSebastian Siewior fastboot_tx_write_str("OKAY");
17323aab70afSSebastian Siewior }
17333aab70afSSebastian Siewior
do_exit_on_complete(struct usb_ep * ep,struct usb_request * req)1734267abc62SRob Herring static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req)
1735267abc62SRob Herring {
1736267abc62SRob Herring g_dnl_trigger_detach();
1737267abc62SRob Herring }
1738267abc62SRob Herring
cb_continue(struct usb_ep * ep,struct usb_request * req)1739267abc62SRob Herring static void cb_continue(struct usb_ep *ep, struct usb_request *req)
1740267abc62SRob Herring {
1741267abc62SRob Herring fastboot_func->in_req->complete = do_exit_on_complete;
1742267abc62SRob Herring fastboot_tx_write_str("OKAY");
1743267abc62SRob Herring }
1744267abc62SRob Herring
cb_set_active(struct usb_ep * ep,struct usb_request * req)1745367cce4dSXu Hongfei static void cb_set_active(struct usb_ep *ep, struct usb_request *req)
1746367cce4dSXu Hongfei {
1747367cce4dSXu Hongfei char *cmd = req->buf;
1748367cce4dSXu Hongfei
1749367cce4dSXu Hongfei debug("%s: %s\n", __func__, cmd);
1750367cce4dSXu Hongfei
1751367cce4dSXu Hongfei strsep(&cmd, ":");
1752367cce4dSXu Hongfei if (!cmd) {
175390aa625cSMasahiro Yamada pr_err("missing slot name");
17542e40c2c1SJason Zhu fastboot_tx_write_str("FAILmissing slot name");
1755367cce4dSXu Hongfei return;
1756367cce4dSXu Hongfei }
1757*40a6a2cbSDayao Ji #ifdef CONFIG_ANDROID_AB
1758*40a6a2cbSDayao Ji if (get_virtual_ab_merge_status() == ENUM_MERGE_STATUS_MERGING) {
1759*40a6a2cbSDayao Ji pr_err("virtual A/B is merging, abort the operation");
1760*40a6a2cbSDayao Ji fastboot_tx_write_str("FAILvirtual A/B is merging, abort");
1761*40a6a2cbSDayao Ji return;
1762*40a6a2cbSDayao Ji }
1763*40a6a2cbSDayao Ji #endif
176437a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
1765367cce4dSXu Hongfei unsigned int slot_number;
1766367cce4dSXu Hongfei if (strncmp("a", cmd, 1) == 0) {
1767367cce4dSXu Hongfei slot_number = 0;
176837a7bc39SJason Zhu rk_avb_set_slot_active(&slot_number);
1769367cce4dSXu Hongfei } else if (strncmp("b", cmd, 1) == 0) {
1770367cce4dSXu Hongfei slot_number = 1;
177137a7bc39SJason Zhu rk_avb_set_slot_active(&slot_number);
1772367cce4dSXu Hongfei } else {
17732e40c2c1SJason Zhu fastboot_tx_write_str("FAILunkown slot name");
1774367cce4dSXu Hongfei return;
1775367cce4dSXu Hongfei }
1776367cce4dSXu Hongfei
1777367cce4dSXu Hongfei fastboot_tx_write_str("OKAY");
1778367cce4dSXu Hongfei return;
1779367cce4dSXu Hongfei #else
1780367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
1781367cce4dSXu Hongfei return;
1782367cce4dSXu Hongfei #endif
1783367cce4dSXu Hongfei }
1784367cce4dSXu Hongfei
1785d1b5ed07SSteve Rae #ifdef CONFIG_FASTBOOT_FLASH
cb_flash(struct usb_ep * ep,struct usb_request * req)1786d1b5ed07SSteve Rae static void cb_flash(struct usb_ep *ep, struct usb_request *req)
1787d1b5ed07SSteve Rae {
1788d1b5ed07SSteve Rae char *cmd = req->buf;
1789374a9995SCody Xie char response[FASTBOOT_RESPONSE_LEN] = {0};
179037a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
17917bc1707dSJason Zhu uint8_t flash_lock_state;
1792d1b5ed07SSteve Rae
179337a7bc39SJason Zhu if (rk_avb_read_flash_lock_state(&flash_lock_state)) {
17942e40c2c1SJason Zhu /* write the device flashing unlock when first read */
17952e40c2c1SJason Zhu if (rk_avb_write_flash_lock_state(1)) {
17962e40c2c1SJason Zhu fastboot_tx_write_str("FAILflash lock state write failure");
17977bc1707dSJason Zhu return;
1798ef52a073SJason Zhu }
17992e40c2c1SJason Zhu if (rk_avb_read_flash_lock_state(&flash_lock_state)) {
18002e40c2c1SJason Zhu fastboot_tx_write_str("FAILflash lock state read failure");
18012e40c2c1SJason Zhu return;
18022e40c2c1SJason Zhu }
18032e40c2c1SJason Zhu }
1804ef52a073SJason Zhu
18057bc1707dSJason Zhu if (flash_lock_state == 0) {
18067bc1707dSJason Zhu fastboot_tx_write_str("FAILThe device is locked, can not flash!");
18077bc1707dSJason Zhu printf("The device is locked, can not flash!\n");
18087bc1707dSJason Zhu return;
18097bc1707dSJason Zhu }
18107bc1707dSJason Zhu #endif
1811d1b5ed07SSteve Rae strsep(&cmd, ":");
1812d1b5ed07SSteve Rae if (!cmd) {
181390aa625cSMasahiro Yamada pr_err("missing partition name");
1814d1b5ed07SSteve Rae fastboot_tx_write_str("FAILmissing partition name");
1815d1b5ed07SSteve Rae return;
1816d1b5ed07SSteve Rae }
1817*40a6a2cbSDayao Ji #ifdef CONFIG_ANDROID_AB
1818*40a6a2cbSDayao Ji if ((strcmp(cmd, PART_USERDATA) == 0) || (strcmp(cmd, PART_METADATA) == 0)) {
1819*40a6a2cbSDayao Ji if (should_prevent_userdata_wipe()) {
1820*40a6a2cbSDayao Ji pr_err("FAILThe virtual A/B merging, can not flash userdata or metadata!\n");
1821*40a6a2cbSDayao Ji fastboot_tx_write_str("FAILvirtual A/B merging,abort flash!");
1822*40a6a2cbSDayao Ji return;
1823*40a6a2cbSDayao Ji }
1824*40a6a2cbSDayao Ji }
1825*40a6a2cbSDayao Ji #endif
18268b464fa9SJocelyn Bohr fastboot_fail("no flash device defined", response);
1827d1b5ed07SSteve Rae #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
182864ece848SSteve Rae fb_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR,
18298b464fa9SJocelyn Bohr download_bytes, response);
1830d1b5ed07SSteve Rae #endif
1831bf8940d3SMaxime Ripard #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
18328b464fa9SJocelyn Bohr fb_nand_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR,
18338b464fa9SJocelyn Bohr download_bytes, response);
1834bf8940d3SMaxime Ripard #endif
1835d1b5ed07SSteve Rae fastboot_tx_write_str(response);
1836d1b5ed07SSteve Rae }
1837d1b5ed07SSteve Rae
cb_flashing(struct usb_ep * ep,struct usb_request * req)1838367cce4dSXu Hongfei static void cb_flashing(struct usb_ep *ep, struct usb_request *req)
1839367cce4dSXu Hongfei {
1840367cce4dSXu Hongfei char *cmd = req->buf;
1841367cce4dSXu Hongfei
1842367cce4dSXu Hongfei if (strncmp("lock", cmd + 9, 4) == 0) {
184337a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
18447bc1707dSJason Zhu uint8_t flash_lock_state;
18457bc1707dSJason Zhu flash_lock_state = 0;
184637a7bc39SJason Zhu if (rk_avb_write_flash_lock_state(flash_lock_state))
18472e40c2c1SJason Zhu fastboot_tx_write_str("FAILflash lock state"
18482e40c2c1SJason Zhu " write failure");
18497bc1707dSJason Zhu else
18507bc1707dSJason Zhu fastboot_tx_write_str("OKAY");
18517bc1707dSJason Zhu #else
1852367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
18537bc1707dSJason Zhu #endif
1854367cce4dSXu Hongfei } else if (strncmp("unlock", cmd + 9, 6) == 0) {
185537a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
18567bc1707dSJason Zhu uint8_t flash_lock_state;
18577bc1707dSJason Zhu flash_lock_state = 1;
185837a7bc39SJason Zhu if (rk_avb_write_flash_lock_state(flash_lock_state))
18592e40c2c1SJason Zhu fastboot_tx_write_str("FAILflash lock state"
18602e40c2c1SJason Zhu " write failure");
18617bc1707dSJason Zhu else
18627bc1707dSJason Zhu fastboot_tx_write_str("OKAY");
18637bc1707dSJason Zhu #else
1864367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
18657bc1707dSJason Zhu #endif
1866367cce4dSXu Hongfei } else if (strncmp("lock_critical", cmd + 9, 12) == 0) {
1867367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
1868367cce4dSXu Hongfei } else if (strncmp("unlock_critical", cmd + 9, 14) == 0) {
1869367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
1870367cce4dSXu Hongfei } else if (strncmp("get_unlock_ability", cmd + 9, 17) == 0) {
1871367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
1872367cce4dSXu Hongfei } else if (strncmp("get_unlock_bootloader_nonce", cmd + 4, 27) == 0) {
1873367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
1874367cce4dSXu Hongfei } else if (strncmp("unlock_bootloader", cmd + 9, 17) == 0) {
1875367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
1876367cce4dSXu Hongfei } else if (strncmp("lock_bootloader", cmd + 9, 15) == 0) {
1877367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
1878367cce4dSXu Hongfei } else {
1879367cce4dSXu Hongfei fastboot_tx_write_str("FAILunknown flashing command");
1880367cce4dSXu Hongfei }
1881367cce4dSXu Hongfei }
18826f3eb474SKever Yang #endif
1883367cce4dSXu Hongfei
cb_oem_perm_attr(void)18842e40c2c1SJason Zhu static void cb_oem_perm_attr(void)
18852e40c2c1SJason Zhu {
18862e40c2c1SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
188774b485fbSJason Zhu #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY
18882e40c2c1SJason Zhu sha256_context ctx;
18892e40c2c1SJason Zhu uint8_t digest[SHA256_SUM_LEN] = {0};
18902e40c2c1SJason Zhu uint8_t digest_temp[SHA256_SUM_LEN] = {0};
18912e40c2c1SJason Zhu uint8_t perm_attr_temp[PERM_ATTR_TOTAL_SIZE] = {0};
18922e40c2c1SJason Zhu uint8_t flag = 0;
189374b485fbSJason Zhu #endif
18942e40c2c1SJason Zhu if (PERM_ATTR_TOTAL_SIZE != download_bytes) {
18952e40c2c1SJason Zhu printf("Permanent attribute size is not equal!\n");
18962e40c2c1SJason Zhu fastboot_tx_write_str("FAILincorrect perm attribute size");
18972e40c2c1SJason Zhu return;
18982e40c2c1SJason Zhu }
189974b485fbSJason Zhu #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY
19002e40c2c1SJason Zhu if (rk_avb_read_perm_attr_flag(&flag)) {
19012e40c2c1SJason Zhu printf("rk_avb_read_perm_attr_flag error!\n");
19022e40c2c1SJason Zhu fastboot_tx_write_str("FAILperm attr read failed");
19032e40c2c1SJason Zhu return;
19042e40c2c1SJason Zhu }
19052e40c2c1SJason Zhu
19062e40c2c1SJason Zhu if (flag == PERM_ATTR_SUCCESS_FLAG) {
19072e40c2c1SJason Zhu if (rk_avb_read_attribute_hash(digest_temp,
19082e40c2c1SJason Zhu SHA256_SUM_LEN)) {
19092e40c2c1SJason Zhu printf("The efuse IO can not be used!\n");
19102e40c2c1SJason Zhu fastboot_tx_write_str("FAILefuse IO can not be used");
19112e40c2c1SJason Zhu return;
19122e40c2c1SJason Zhu }
19132e40c2c1SJason Zhu
19142e40c2c1SJason Zhu if (memcmp(digest, digest_temp, SHA256_SUM_LEN) != 0) {
19152e40c2c1SJason Zhu if (rk_avb_read_permanent_attributes(perm_attr_temp,
19162e40c2c1SJason Zhu PERM_ATTR_TOTAL_SIZE)) {
19172e40c2c1SJason Zhu printf("rk_avb_write_permanent_attributes error!\n");
19182e40c2c1SJason Zhu fastboot_tx_write_str("FAILread perm attr error");
19192e40c2c1SJason Zhu return;
19202e40c2c1SJason Zhu }
19212e40c2c1SJason Zhu
19222e40c2c1SJason Zhu sha256_starts(&ctx);
19232e40c2c1SJason Zhu sha256_update(&ctx,
19242e40c2c1SJason Zhu (const uint8_t *)perm_attr_temp,
19252e40c2c1SJason Zhu PERM_ATTR_TOTAL_SIZE);
19262e40c2c1SJason Zhu sha256_finish(&ctx, digest);
19272e40c2c1SJason Zhu if (memcmp(digest, digest_temp, SHA256_SUM_LEN) == 0) {
19282e40c2c1SJason Zhu printf("The hash has been written!\n");
19292e40c2c1SJason Zhu fastboot_tx_write_str("OKAY");
19302e40c2c1SJason Zhu return;
19312e40c2c1SJason Zhu }
19322e40c2c1SJason Zhu }
19332e40c2c1SJason Zhu
19342e40c2c1SJason Zhu if (rk_avb_write_perm_attr_flag(0)) {
19352e40c2c1SJason Zhu fastboot_tx_write_str("FAILperm attr flag write failure");
19362e40c2c1SJason Zhu return;
19372e40c2c1SJason Zhu }
19382e40c2c1SJason Zhu }
193974b485fbSJason Zhu #endif
19402e40c2c1SJason Zhu if (rk_avb_write_permanent_attributes((uint8_t *)
19412e40c2c1SJason Zhu CONFIG_FASTBOOT_BUF_ADDR,
19422e40c2c1SJason Zhu download_bytes)) {
19432e40c2c1SJason Zhu if (rk_avb_write_perm_attr_flag(0)) {
19442e40c2c1SJason Zhu fastboot_tx_write_str("FAILperm attr flag write failure");
19452e40c2c1SJason Zhu return;
19462e40c2c1SJason Zhu }
19472e40c2c1SJason Zhu fastboot_tx_write_str("FAILperm attr write failed");
19482e40c2c1SJason Zhu return;
19492e40c2c1SJason Zhu }
195074b485fbSJason Zhu #ifndef CONFIG_ROCKCHIP_PRELOADER_PUB_KEY
19512e40c2c1SJason Zhu memset(digest, 0, SHA256_SUM_LEN);
19522e40c2c1SJason Zhu sha256_starts(&ctx);
19532e40c2c1SJason Zhu sha256_update(&ctx, (const uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
19542e40c2c1SJason Zhu PERM_ATTR_TOTAL_SIZE);
19552e40c2c1SJason Zhu sha256_finish(&ctx, digest);
19562e40c2c1SJason Zhu
19572e40c2c1SJason Zhu if (rk_avb_write_attribute_hash((uint8_t *)digest,
19582e40c2c1SJason Zhu SHA256_SUM_LEN)) {
19592e40c2c1SJason Zhu if (rk_avb_read_attribute_hash(digest_temp,
19602e40c2c1SJason Zhu SHA256_SUM_LEN)) {
19612e40c2c1SJason Zhu printf("The efuse IO can not be used!\n");
19622e40c2c1SJason Zhu fastboot_tx_write_str("FAILefuse IO can not be used");
19632e40c2c1SJason Zhu return;
19642e40c2c1SJason Zhu }
19652e40c2c1SJason Zhu if (memcmp(digest, digest_temp, SHA256_SUM_LEN) != 0) {
19662e40c2c1SJason Zhu if (rk_avb_write_perm_attr_flag(0)) {
19672e40c2c1SJason Zhu fastboot_tx_write_str("FAILperm attr flag write failure");
19682e40c2c1SJason Zhu return;
19692e40c2c1SJason Zhu }
19702e40c2c1SJason Zhu printf("The hash has been written, but is different!\n");
19712e40c2c1SJason Zhu fastboot_tx_write_str("FAILhash comparison failure");
19722e40c2c1SJason Zhu return;
19732e40c2c1SJason Zhu }
19742e40c2c1SJason Zhu }
197574b485fbSJason Zhu #endif
19762e40c2c1SJason Zhu if (rk_avb_write_perm_attr_flag(PERM_ATTR_SUCCESS_FLAG)) {
19772e40c2c1SJason Zhu fastboot_tx_write_str("FAILperm attr flag write failure");
19782e40c2c1SJason Zhu return;
19792e40c2c1SJason Zhu }
19802e40c2c1SJason Zhu
19812e40c2c1SJason Zhu fastboot_tx_write_str("OKAY");
19822e40c2c1SJason Zhu #else
19832e40c2c1SJason Zhu fastboot_tx_write_str("FAILnot implemented");
19842e40c2c1SJason Zhu #endif
19852e40c2c1SJason Zhu }
19862e40c2c1SJason Zhu
cb_oem_perm_attr_rsa_cer(void)19873cf641a8SJason Zhu static void cb_oem_perm_attr_rsa_cer(void)
19883cf641a8SJason Zhu {
19893cf641a8SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
19903cf641a8SJason Zhu if (download_bytes != 256) {
19913cf641a8SJason Zhu printf("Permanent attribute rsahash size is not equal!\n");
19923cf641a8SJason Zhu fastboot_tx_write_str("FAILperm attribute rsahash size error");
19933cf641a8SJason Zhu return;
19943cf641a8SJason Zhu }
19953cf641a8SJason Zhu
19963cf641a8SJason Zhu if (rk_avb_set_perm_attr_cer((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
19973cf641a8SJason Zhu download_bytes)) {
19983cf641a8SJason Zhu fastboot_tx_write_str("FAILSet perm attr cer fail!");
19993cf641a8SJason Zhu return;
20003cf641a8SJason Zhu }
20013cf641a8SJason Zhu
20023cf641a8SJason Zhu fastboot_tx_write_str("OKAY");
20033cf641a8SJason Zhu #else
20043cf641a8SJason Zhu fastboot_tx_write_str("FAILnot implemented");
20053cf641a8SJason Zhu #endif
20063cf641a8SJason Zhu }
20073cf641a8SJason Zhu
cb_oem(struct usb_ep * ep,struct usb_request * req)2008de195620SMichael Scott static void cb_oem(struct usb_ep *ep, struct usb_request *req)
2009de195620SMichael Scott {
2010de195620SMichael Scott char *cmd = req->buf;
2011367cce4dSXu Hongfei
20124adef270SMaxime Ripard #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
2013372d7decSRob Herring if (strncmp("format", cmd + 4, 6) == 0) {
2014372d7decSRob Herring char cmdbuf[32];
2015372d7decSRob Herring sprintf(cmdbuf, "gpt write mmc %x $partitions",
2016372d7decSRob Herring CONFIG_FASTBOOT_FLASH_MMC_DEV);
2017*40a6a2cbSDayao Ji #ifdef CONFIG_ANDROID_AB
2018*40a6a2cbSDayao Ji if (should_prevent_userdata_wipe()) {
2019*40a6a2cbSDayao Ji printf("FAILThe virtual A/B merging, can not format!\n");
2020*40a6a2cbSDayao Ji fastboot_tx_write_str("FAILvirtual A/B merging,abort format!");
2021*40a6a2cbSDayao Ji } else {
2022372d7decSRob Herring if (run_command(cmdbuf, 0))
20232e40c2c1SJason Zhu fastboot_tx_write_str("FAILmmc write failure");
2024372d7decSRob Herring else
2025372d7decSRob Herring fastboot_tx_write_str("OKAY");
2026*40a6a2cbSDayao Ji }
2027*40a6a2cbSDayao Ji #else
2028*40a6a2cbSDayao Ji if (run_command(cmdbuf, 0))
2029*40a6a2cbSDayao Ji fastboot_tx_write_str("FAILmmc write failure");
2030*40a6a2cbSDayao Ji else
2031*40a6a2cbSDayao Ji fastboot_tx_write_str("OKAY");
2032*40a6a2cbSDayao Ji #endif
2033372d7decSRob Herring } else
2034372d7decSRob Herring #endif
2035de195620SMichael Scott if (strncmp("unlock", cmd + 4, 8) == 0) {
203665413a00SJian Qiu #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
2037f61a997eSqiujian #ifdef CONFIG_RK_AVB_LIBAVB_USER
2038de195620SMichael Scott fastboot_tx_write_str("FAILnot implemented");
2039f61a997eSqiujian return;
2040f61a997eSqiujian #else
2041f61a997eSqiujian uint8_t unlock = 0;
2042f61a997eSqiujian TEEC_Result result;
2043f61a997eSqiujian debug("oem unlock\n");
2044f61a997eSqiujian result = trusty_read_oem_unlock(&unlock);
2045f61a997eSqiujian if (result) {
2046f61a997eSqiujian printf("read oem unlock status with error : 0x%x\n", result);
2047f61a997eSqiujian fastboot_tx_write_str("FAILRead oem unlock status failed");
2048f61a997eSqiujian return;
2049f61a997eSqiujian }
2050f61a997eSqiujian if (unlock) {
2051f61a997eSqiujian printf("oem unlock ignored, device already unlocked\n");
2052f61a997eSqiujian fastboot_tx_write_str("FAILalready unlocked");
2053f61a997eSqiujian return;
2054f61a997eSqiujian }
2055f61a997eSqiujian printf("oem unlock requested:\n");
2056f61a997eSqiujian printf("\tUnlocking forces a factory reset and could\n");
2057f61a997eSqiujian printf("\topen your device up to a world of hurt. If you\n");
2058f61a997eSqiujian printf("\tare sure you know what you're doing, then accept\n");
2059f61a997eSqiujian printf("\tvia 'fastboot oem unlock_accept'.\n");
2060f61a997eSqiujian env_set("unlock", "unlock");
2061f61a997eSqiujian fastboot_tx_write_str("OKAY");
2062f61a997eSqiujian #endif
2063f61a997eSqiujian #else
2064f61a997eSqiujian fastboot_tx_write_str("FAILnot implemented");
2065f61a997eSqiujian return;
2066f61a997eSqiujian #endif
2067f61a997eSqiujian } else if (strncmp("unlock_accept", cmd + 4, 13) == 0) {
206865413a00SJian Qiu #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
2069f61a997eSqiujian #ifdef CONFIG_RK_AVB_LIBAVB_USER
2070f61a997eSqiujian fastboot_tx_write_str("FAILnot implemented");
2071f61a997eSqiujian return;
2072f61a997eSqiujian #else
2073f61a997eSqiujian char *unlock = env_get("unlock");
2074f61a997eSqiujian TEEC_Result result;
2075f61a997eSqiujian debug("oem unlock_accept\n");
2076f61a997eSqiujian if (unlock == NULL || strncmp("unlock", unlock, 6) != 0) {
2077f61a997eSqiujian printf("oem unlock_accept ignored, not pending\n");
2078f61a997eSqiujian fastboot_tx_write_str("FAILoem unlock not requested");
2079f61a997eSqiujian return;
2080f61a997eSqiujian }
2081f61a997eSqiujian env_set("unlock", "");
2082f61a997eSqiujian printf("Erasing userdata partition\n");
2083f61a997eSqiujian struct blk_desc *dev_desc;
2084f61a997eSqiujian disk_partition_t part_info;
2085f61a997eSqiujian dev_desc = rockchip_get_bootdev();
20866651d4c0SJason Zhu if (!dev_desc) {
20876651d4c0SJason Zhu printf("%s: dev_desc is NULL!\n", __func__);
20886651d4c0SJason Zhu return;
20896651d4c0SJason Zhu }
2090f61a997eSqiujian int ret = part_get_info_by_name(dev_desc, "userdata",
2091f61a997eSqiujian &part_info);
2092f61a997eSqiujian if (ret < 0) {
2093f61a997eSqiujian printf("not found userdata partition");
2094f61a997eSqiujian printf("Erase failed with error %d\n", ret);
2095f61a997eSqiujian fastboot_tx_write_str("FAILErasing userdata failed");
2096f61a997eSqiujian return;
2097f61a997eSqiujian }
2098f61a997eSqiujian ret = blk_derase(dev_desc, part_info.start, part_info.size);
2099f61a997eSqiujian if (ret != part_info.size) {
2100f61a997eSqiujian printf("Erase failed with error %d\n", ret);
2101f61a997eSqiujian fastboot_tx_write_str("FAILErasing userdata failed");
2102f61a997eSqiujian return;
2103f61a997eSqiujian }
2104f61a997eSqiujian printf("Erasing succeeded\n");
2105f61a997eSqiujian
2106f61a997eSqiujian result = trusty_write_oem_unlock(1);
2107f61a997eSqiujian if (result) {
2108f61a997eSqiujian printf("write oem unlock status with error : 0x%x\n", result);
2109f61a997eSqiujian fastboot_tx_write_str("FAILWrite oem unlock status failed");
2110f61a997eSqiujian return;
2111f61a997eSqiujian }
2112f61a997eSqiujian fastboot_tx_write_str("OKAY");
2113f61a997eSqiujian
2114f61a997eSqiujian /*
2115f61a997eSqiujian * now reboot into recovery to do a format of the
2116f61a997eSqiujian * userdata partition so it's ready to use on next boot
2117f61a997eSqiujian */
2118f61a997eSqiujian board_run_recovery_wipe_data();
2119f61a997eSqiujian #endif
2120f61a997eSqiujian #else
2121f61a997eSqiujian fastboot_tx_write_str("FAILnot implemented");
2122f61a997eSqiujian return;
2123f61a997eSqiujian #endif
2124f61a997eSqiujian } else if (strncmp("lock", cmd + 4, 8) == 0) {
212565413a00SJian Qiu #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
2126f61a997eSqiujian #ifdef CONFIG_RK_AVB_LIBAVB_USER
2127f61a997eSqiujian fastboot_tx_write_str("FAILnot implemented");
2128f61a997eSqiujian return;
2129f61a997eSqiujian #else
2130f61a997eSqiujian TEEC_Result result;
2131f61a997eSqiujian uint8_t unlock = 0;
2132f61a997eSqiujian trusty_read_oem_unlock(&unlock);
2133f61a997eSqiujian if (!unlock) {
2134f61a997eSqiujian printf("oem lock ignored, already locked\n");
2135f61a997eSqiujian fastboot_tx_write_str("FAILalready locked");
2136f61a997eSqiujian return;
2137f61a997eSqiujian }
2138f61a997eSqiujian
2139f61a997eSqiujian result = trusty_write_oem_unlock(0);
2140f61a997eSqiujian if (result) {
2141f61a997eSqiujian printf("write oem unlock status with error : 0x%x\n", result);
2142f61a997eSqiujian fastboot_tx_write_str("FAILWrite oem unlock status failed");
2143f61a997eSqiujian return;
2144f61a997eSqiujian }
2145f61a997eSqiujian fastboot_tx_write_str("OKAY");
2146f61a997eSqiujian #endif
2147f61a997eSqiujian #else
2148f61a997eSqiujian fastboot_tx_write_str("FAILnot implemented");
2149f61a997eSqiujian return;
2150f61a997eSqiujian #endif
2151367cce4dSXu Hongfei } else if (strncmp("at-get-ca-request", cmd + 4, 17) == 0) {
21524d0fc665SAndy Ye #ifdef CONFIG_OPTEE_CLIENT
21532e40c2c1SJason Zhu uint8_t out[ATTEST_CA_OUT_SIZE];
21544d0fc665SAndy Ye uint32_t operation_size = download_bytes;
21552e40c2c1SJason Zhu uint32_t out_len = ATTEST_CA_OUT_SIZE;
21564d0fc665SAndy Ye uint32_t res = 0;
21572e40c2c1SJason Zhu
21582e40c2c1SJason Zhu res = trusty_attest_get_ca((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
21592e40c2c1SJason Zhu &operation_size, out, &out_len);
21604d0fc665SAndy Ye if (res) {
21614d0fc665SAndy Ye fastboot_tx_write_str("FAILtrusty_attest_get_ca failed");
21624d0fc665SAndy Ye return;
21634d0fc665SAndy Ye }
21644d0fc665SAndy Ye upload_size = out_len;
21654d0fc665SAndy Ye memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR, out, out_len);
2166367cce4dSXu Hongfei fastboot_tx_write_str("OKAY");
21674d0fc665SAndy Ye #else
21684d0fc665SAndy Ye fastboot_tx_write_str("FAILnot implemented");
21694d0fc665SAndy Ye return;
21704d0fc665SAndy Ye #endif
2171367cce4dSXu Hongfei } else if (strncmp("at-set-ca-response", cmd + 4, 18) == 0) {
21724d0fc665SAndy Ye #ifdef CONFIG_OPTEE_CLIENT
21734d0fc665SAndy Ye uint32_t ca_response_size = download_bytes;
21744d0fc665SAndy Ye uint32_t res = 0;
21752e40c2c1SJason Zhu
21762e40c2c1SJason Zhu res = trusty_attest_set_ca((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
21772e40c2c1SJason Zhu &ca_response_size);
21782e40c2c1SJason Zhu if (res)
21794d0fc665SAndy Ye fastboot_tx_write_str("FAILtrusty_attest_set_ca failed");
21802e40c2c1SJason Zhu else
2181367cce4dSXu Hongfei fastboot_tx_write_str("OKAY");
21824d0fc665SAndy Ye #else
21834d0fc665SAndy Ye fastboot_tx_write_str("FAILnot implemented");
21844d0fc665SAndy Ye return;
21854d0fc665SAndy Ye #endif
218662b11485SJason Zhu } else if (strncmp("at-get-vboot-unlock-challenge", cmd + 4, 29) == 0) {
218762b11485SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
218862b11485SJason Zhu uint32_t challenge_len = 0;
218962b11485SJason Zhu int ret = 0;
219062b11485SJason Zhu
219162b11485SJason Zhu ret = rk_generate_unlock_challenge((void *)CONFIG_FASTBOOT_BUF_ADDR, &challenge_len);
219262b11485SJason Zhu if (ret == 0) {
219362b11485SJason Zhu upload_size = challenge_len;
219462b11485SJason Zhu fastboot_tx_write_str("OKAY");
219562b11485SJason Zhu } else {
219662b11485SJason Zhu fastboot_tx_write_str("FAILgenerate unlock challenge fail!");
219762b11485SJason Zhu }
219862b11485SJason Zhu #else
219962b11485SJason Zhu fastboot_tx_write_str("FAILnot implemented");
220062b11485SJason Zhu return;
220162b11485SJason Zhu #endif
2202367cce4dSXu Hongfei } else if (strncmp("at-lock-vboot", cmd + 4, 13) == 0) {
220337a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
2204d8bd6e97SJason Zhu uint8_t lock_state;
2205d8bd6e97SJason Zhu lock_state = 0;
220637a7bc39SJason Zhu if (rk_avb_write_lock_state(lock_state))
22072e40c2c1SJason Zhu fastboot_tx_write_str("FAILwrite lock state failed");
2208d8bd6e97SJason Zhu else
2209d8bd6e97SJason Zhu fastboot_tx_write_str("OKAY");
2210d8bd6e97SJason Zhu #else
2211367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
2212d8bd6e97SJason Zhu #endif
2213367cce4dSXu Hongfei } else if (strncmp("at-unlock-vboot", cmd + 4, 15) == 0) {
221437a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
2215d8bd6e97SJason Zhu uint8_t lock_state;
2216d38ae1a6Szain wang char out_is_trusted = true;
2217542316a9SJason Zhu
221837a7bc39SJason Zhu if (rk_avb_read_lock_state(&lock_state))
22192e40c2c1SJason Zhu fastboot_tx_write_str("FAILlock sate read failure");
2220d8bd6e97SJason Zhu if (lock_state >> 1 == 1) {
2221d8bd6e97SJason Zhu fastboot_tx_write_str("FAILThe vboot is disable!");
2222d8bd6e97SJason Zhu } else {
2223d8bd6e97SJason Zhu lock_state = 1;
222446a8a269SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_ENABLE_ATH_UNLOCK
2225542316a9SJason Zhu if (rk_auth_unlock((void *)CONFIG_FASTBOOT_BUF_ADDR,
2226542316a9SJason Zhu &out_is_trusted)) {
2227542316a9SJason Zhu printf("rk_auth_unlock ops error!\n");
2228542316a9SJason Zhu fastboot_tx_write_str("FAILrk_auth_unlock ops error!");
2229542316a9SJason Zhu return;
2230542316a9SJason Zhu }
223146a8a269SJason Zhu #endif
2232542316a9SJason Zhu if (out_is_trusted == true) {
223337a7bc39SJason Zhu if (rk_avb_write_lock_state(lock_state))
22342e40c2c1SJason Zhu fastboot_tx_write_str("FAILwrite lock state failed");
2235d8bd6e97SJason Zhu else
2236d8bd6e97SJason Zhu fastboot_tx_write_str("OKAY");
2237542316a9SJason Zhu } else {
2238542316a9SJason Zhu fastboot_tx_write_str("FAILauthenticated unlock fail");
2239542316a9SJason Zhu }
2240d8bd6e97SJason Zhu }
2241d8bd6e97SJason Zhu #else
2242367cce4dSXu Hongfei fastboot_tx_write_str("FAILnot implemented");
2243d8bd6e97SJason Zhu #endif
2244367cce4dSXu Hongfei } else if (strncmp("fuse at-perm-attr", cmd + 4, 16) == 0) {
22452e40c2c1SJason Zhu cb_oem_perm_attr();
22463cf641a8SJason Zhu } else if (strncmp("fuse at-rsa-perm-attr", cmd + 4, 25) == 0) {
22473cf641a8SJason Zhu cb_oem_perm_attr_rsa_cer();
22484e1bbe84SJason Zhu } else if (strncmp("fuse at-bootloader-vboot-key", cmd + 4, 27) == 0) {
224937a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
22502e40c2c1SJason Zhu sha256_context ctx;
22512e40c2c1SJason Zhu uint8_t digest[SHA256_SUM_LEN];
22522e40c2c1SJason Zhu
22534e1bbe84SJason Zhu if (download_bytes != VBOOT_KEY_HASH_SIZE) {
22542e40c2c1SJason Zhu fastboot_tx_write_str("FAILinvalid vboot key length");
22554e1bbe84SJason Zhu printf("The vboot key size error!\n");
22562e40c2c1SJason Zhu return;
22574e1bbe84SJason Zhu }
22584e1bbe84SJason Zhu
22592e40c2c1SJason Zhu sha256_starts(&ctx);
22602e40c2c1SJason Zhu sha256_update(&ctx, (const uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
22612e40c2c1SJason Zhu VBOOT_KEY_SIZE);
22622e40c2c1SJason Zhu sha256_finish(&ctx, digest);
22632e40c2c1SJason Zhu
22642e40c2c1SJason Zhu if (rk_avb_write_vbootkey_hash((uint8_t *)digest,
22652e40c2c1SJason Zhu SHA256_SUM_LEN)) {
22662e40c2c1SJason Zhu fastboot_tx_write_str("FAILvbootkey hash write failure");
22674e1bbe84SJason Zhu return;
22684e1bbe84SJason Zhu }
22694e1bbe84SJason Zhu fastboot_tx_write_str("OKAY");
22704e1bbe84SJason Zhu #else
22714e1bbe84SJason Zhu fastboot_tx_write_str("FAILnot implemented");
22724e1bbe84SJason Zhu #endif
227341386eddSJason Zhu } else if (strncmp("init-ab-metadata", cmd + 4, 16) == 0) {
227441386eddSJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
227541386eddSJason Zhu if (rk_avb_init_ab_metadata()) {
227641386eddSJason Zhu fastboot_tx_write_str("FAILinit ab data fail!");
227741386eddSJason Zhu return;
227841386eddSJason Zhu }
227941386eddSJason Zhu fastboot_tx_write_str("OKAY");
228041386eddSJason Zhu #else
228141386eddSJason Zhu fastboot_tx_write_str("FAILnot implemented");
228241386eddSJason Zhu #endif
2283367cce4dSXu Hongfei } else {
2284de195620SMichael Scott fastboot_tx_write_str("FAILunknown oem command");
2285de195620SMichael Scott }
2286de195620SMichael Scott }
2287de195620SMichael Scott
228889792381SDileep Katta #ifdef CONFIG_FASTBOOT_FLASH
cb_erase(struct usb_ep * ep,struct usb_request * req)228989792381SDileep Katta static void cb_erase(struct usb_ep *ep, struct usb_request *req)
229089792381SDileep Katta {
229189792381SDileep Katta char *cmd = req->buf;
2292*40a6a2cbSDayao Ji char response[FASTBOOT_RESPONSE_LEN] = {0};
229389792381SDileep Katta
229489792381SDileep Katta strsep(&cmd, ":");
229589792381SDileep Katta if (!cmd) {
229690aa625cSMasahiro Yamada pr_err("missing partition name");
229789792381SDileep Katta fastboot_tx_write_str("FAILmissing partition name");
229889792381SDileep Katta return;
229989792381SDileep Katta }
2300*40a6a2cbSDayao Ji #ifdef CONFIG_ANDROID_AB
2301*40a6a2cbSDayao Ji if ((strcmp(cmd, PART_USERDATA) == 0) || (strcmp(cmd, PART_METADATA) == 0)) {
2302*40a6a2cbSDayao Ji if (should_prevent_userdata_wipe()) {
2303*40a6a2cbSDayao Ji pr_err("virtual A/B merging, can not erase userdata or metadata!\n");
2304*40a6a2cbSDayao Ji fastboot_tx_write_str("FAILvirtual A/B merging,abort erase!");
2305*40a6a2cbSDayao Ji return;
2306*40a6a2cbSDayao Ji }
2307*40a6a2cbSDayao Ji }
2308*40a6a2cbSDayao Ji #endif
23098b464fa9SJocelyn Bohr fastboot_fail("no flash device defined", response);
231089792381SDileep Katta #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
23118b464fa9SJocelyn Bohr fb_mmc_erase(cmd, response);
231289792381SDileep Katta #endif
2313bf8940d3SMaxime Ripard #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
23148b464fa9SJocelyn Bohr fb_nand_erase(cmd, response);
2315bf8940d3SMaxime Ripard #endif
231689792381SDileep Katta fastboot_tx_write_str(response);
231789792381SDileep Katta }
231889792381SDileep Katta #endif
231989792381SDileep Katta
23203aab70afSSebastian Siewior struct cmd_dispatch_info {
23213aab70afSSebastian Siewior char *cmd;
23223aab70afSSebastian Siewior void (*cb)(struct usb_ep *ep, struct usb_request *req);
23233aab70afSSebastian Siewior };
23243aab70afSSebastian Siewior
23253aab70afSSebastian Siewior static const struct cmd_dispatch_info cmd_dispatch_info[] = {
23263aab70afSSebastian Siewior {
23273aab70afSSebastian Siewior .cmd = "reboot",
23283aab70afSSebastian Siewior .cb = cb_reboot,
23293aab70afSSebastian Siewior }, {
23303aab70afSSebastian Siewior .cmd = "getvar:",
23313aab70afSSebastian Siewior .cb = cb_getvar,
23323aab70afSSebastian Siewior }, {
23333aab70afSSebastian Siewior .cmd = "download:",
23343aab70afSSebastian Siewior .cb = cb_download,
23353aab70afSSebastian Siewior }, {
2336367cce4dSXu Hongfei .cmd = "upload",
2337367cce4dSXu Hongfei .cb = cb_upload,
2338367cce4dSXu Hongfei }, {
23393aab70afSSebastian Siewior .cmd = "boot",
23403aab70afSSebastian Siewior .cb = cb_boot,
2341267abc62SRob Herring }, {
2342267abc62SRob Herring .cmd = "continue",
2343267abc62SRob Herring .cb = cb_continue,
2344367cce4dSXu Hongfei }, {
2345367cce4dSXu Hongfei .cmd = "set_active",
2346367cce4dSXu Hongfei .cb = cb_set_active,
23473aab70afSSebastian Siewior },
2348d1b5ed07SSteve Rae #ifdef CONFIG_FASTBOOT_FLASH
2349d1b5ed07SSteve Rae {
2350367cce4dSXu Hongfei .cmd = "flashing",
2351367cce4dSXu Hongfei .cb = cb_flashing,
2352367cce4dSXu Hongfei },
2353367cce4dSXu Hongfei {
2354d1b5ed07SSteve Rae .cmd = "flash",
2355d1b5ed07SSteve Rae .cb = cb_flash,
235689792381SDileep Katta }, {
235789792381SDileep Katta .cmd = "erase",
235889792381SDileep Katta .cb = cb_erase,
2359d1b5ed07SSteve Rae },
2360d1b5ed07SSteve Rae #endif
2361de195620SMichael Scott {
2362de195620SMichael Scott .cmd = "oem",
2363de195620SMichael Scott .cb = cb_oem,
2364de195620SMichael Scott },
23653aab70afSSebastian Siewior };
23663aab70afSSebastian Siewior
rx_handler_command(struct usb_ep * ep,struct usb_request * req)23673aab70afSSebastian Siewior static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
23683aab70afSSebastian Siewior {
23693aab70afSSebastian Siewior char *cmdbuf = req->buf;
23703aab70afSSebastian Siewior void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
23713aab70afSSebastian Siewior int i;
23723aab70afSSebastian Siewior
237394b385faSPaul Kocialkowski if (req->status != 0 || req->length == 0)
237494b385faSPaul Kocialkowski return;
237594b385faSPaul Kocialkowski
23763aab70afSSebastian Siewior for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
23773aab70afSSebastian Siewior if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
23783aab70afSSebastian Siewior func_cb = cmd_dispatch_info[i].cb;
23793aab70afSSebastian Siewior break;
23803aab70afSSebastian Siewior }
23813aab70afSSebastian Siewior }
23823aab70afSSebastian Siewior
2383593cbd93SSteve Rae if (!func_cb) {
238490aa625cSMasahiro Yamada pr_err("unknown command: %.*s", req->actual, cmdbuf);
23853aab70afSSebastian Siewior fastboot_tx_write_str("FAILunknown command");
2386593cbd93SSteve Rae } else {
2387e2140588SEric Nelson if (req->actual < req->length) {
2388e2140588SEric Nelson u8 *buf = (u8 *)req->buf;
2389e2140588SEric Nelson buf[req->actual] = 0;
23903aab70afSSebastian Siewior func_cb(ep, req);
2391e2140588SEric Nelson } else {
239290aa625cSMasahiro Yamada pr_err("buffer overflow");
2393e2140588SEric Nelson fastboot_tx_write_str("FAILbuffer overflow");
2394e2140588SEric Nelson }
2395593cbd93SSteve Rae }
23963aab70afSSebastian Siewior
23973aab70afSSebastian Siewior *cmdbuf = '\0';
23983aab70afSSebastian Siewior req->actual = 0;
23993aab70afSSebastian Siewior usb_ep_queue(ep, req, 0);
24003aab70afSSebastian Siewior }
2401