xref: /rk3399_rockchip-uboot/drivers/usb/gadget/f_fastboot.c (revision 46a8a26905fc68e6683b93c97adae0dd9a4e37ba)
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>
163aab70afSSebastian Siewior #include <errno.h>
173c8f98f5SMaxime Ripard #include <fastboot.h>
183aab70afSSebastian Siewior #include <malloc.h>
193aab70afSSebastian Siewior #include <linux/usb/ch9.h>
203aab70afSSebastian Siewior #include <linux/usb/gadget.h>
213aab70afSSebastian Siewior #include <linux/usb/composite.h>
223aab70afSSebastian Siewior #include <linux/compiler.h>
232e40c2c1SJason Zhu #include <u-boot/sha256.h>
243aab70afSSebastian Siewior #include <version.h>
253aab70afSSebastian Siewior #include <g_dnl.h>
262e40c2c1SJason Zhu #include <fs.h>
27367cce4dSXu Hongfei #include <android_avb/avb_ops_user.h>
2837a7bc39SJason Zhu #include <android_avb/rk_avb_ops_user.h>
292e40c2c1SJason Zhu #include <dm/uclass.h>
302e40c2c1SJason Zhu #include <power/fuel_gauge.h>
31d1b5ed07SSteve Rae #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
32d1b5ed07SSteve Rae #include <fb_mmc.h>
33d1b5ed07SSteve Rae #endif
34bf8940d3SMaxime Ripard #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
35bf8940d3SMaxime Ripard #include <fb_nand.h>
36bf8940d3SMaxime Ripard #endif
374d0fc665SAndy Ye #ifdef CONFIG_OPTEE_CLIENT
384d0fc665SAndy Ye #include <optee_include/OpteeClientInterface.h>
394d0fc665SAndy Ye #endif
40f61a997eSqiujian #include <boot_rkimg.h>
41f61a997eSqiujian #include <optee_include/tee_client_api.h>
423aab70afSSebastian Siewior 
433aab70afSSebastian Siewior #define FASTBOOT_VERSION		"0.4"
443aab70afSSebastian Siewior 
453aab70afSSebastian Siewior #define FASTBOOT_INTERFACE_CLASS	0xff
463aab70afSSebastian Siewior #define FASTBOOT_INTERFACE_SUB_CLASS	0x42
473aab70afSSebastian Siewior #define FASTBOOT_INTERFACE_PROTOCOL	0x03
483aab70afSSebastian Siewior 
493aab70afSSebastian Siewior #define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0  (0x0200)
503aab70afSSebastian Siewior #define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1  (0x0040)
513aab70afSSebastian Siewior #define TX_ENDPOINT_MAXIMUM_PACKET_SIZE      (0x0040)
523aab70afSSebastian Siewior 
533aab70afSSebastian Siewior #define EP_BUFFER_SIZE			4096
54de78ceaeSJason Zhu #define SLEEP_COUNT 20000
55ac484c5aSRoger Quadros /*
56ac484c5aSRoger Quadros  * EP_BUFFER_SIZE must always be an integral multiple of maxpacket size
57ac484c5aSRoger Quadros  * (64 or 512 or 1024), else we break on certain controllers like DWC3
58ac484c5aSRoger Quadros  * that expect bulk OUT requests to be divisible by maxpacket size.
59ac484c5aSRoger Quadros  */
603aab70afSSebastian Siewior 
613aab70afSSebastian Siewior struct f_fastboot {
623aab70afSSebastian Siewior 	struct usb_function usb_function;
633aab70afSSebastian Siewior 
64593cbd93SSteve Rae 	/* IN/OUT EP's and corresponding requests */
653aab70afSSebastian Siewior 	struct usb_ep *in_ep, *out_ep;
663aab70afSSebastian Siewior 	struct usb_request *in_req, *out_req;
673aab70afSSebastian Siewior };
683aab70afSSebastian Siewior 
693aab70afSSebastian Siewior static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
703aab70afSSebastian Siewior {
713aab70afSSebastian Siewior 	return container_of(f, struct f_fastboot, usb_function);
723aab70afSSebastian Siewior }
733aab70afSSebastian Siewior 
743aab70afSSebastian Siewior static struct f_fastboot *fastboot_func;
753aab70afSSebastian Siewior static unsigned int download_size;
763aab70afSSebastian Siewior static unsigned int download_bytes;
77367cce4dSXu Hongfei static unsigned int upload_size;
78367cce4dSXu Hongfei static unsigned int upload_bytes;
79367cce4dSXu Hongfei static bool start_upload;
80de78ceaeSJason Zhu static unsigned intthread_wakeup_needed;
813aab70afSSebastian Siewior 
823aab70afSSebastian Siewior static struct usb_endpoint_descriptor fs_ep_in = {
833aab70afSSebastian Siewior 	.bLength            = USB_DT_ENDPOINT_SIZE,
843aab70afSSebastian Siewior 	.bDescriptorType    = USB_DT_ENDPOINT,
853aab70afSSebastian Siewior 	.bEndpointAddress   = USB_DIR_IN,
863aab70afSSebastian Siewior 	.bmAttributes       = USB_ENDPOINT_XFER_BULK,
87718156adSRoger Quadros 	.wMaxPacketSize     = cpu_to_le16(64),
883aab70afSSebastian Siewior };
893aab70afSSebastian Siewior 
903aab70afSSebastian Siewior static struct usb_endpoint_descriptor fs_ep_out = {
913aab70afSSebastian Siewior 	.bLength		= USB_DT_ENDPOINT_SIZE,
923aab70afSSebastian Siewior 	.bDescriptorType	= USB_DT_ENDPOINT,
933aab70afSSebastian Siewior 	.bEndpointAddress	= USB_DIR_OUT,
943aab70afSSebastian Siewior 	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
95718156adSRoger Quadros 	.wMaxPacketSize		= cpu_to_le16(64),
96718156adSRoger Quadros };
97718156adSRoger Quadros 
98718156adSRoger Quadros static struct usb_endpoint_descriptor hs_ep_in = {
99718156adSRoger Quadros 	.bLength		= USB_DT_ENDPOINT_SIZE,
100718156adSRoger Quadros 	.bDescriptorType	= USB_DT_ENDPOINT,
101718156adSRoger Quadros 	.bEndpointAddress	= USB_DIR_IN,
102718156adSRoger Quadros 	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
103718156adSRoger Quadros 	.wMaxPacketSize		= cpu_to_le16(512),
1043aab70afSSebastian Siewior };
1053aab70afSSebastian Siewior 
1063aab70afSSebastian Siewior static struct usb_endpoint_descriptor hs_ep_out = {
1073aab70afSSebastian Siewior 	.bLength		= USB_DT_ENDPOINT_SIZE,
1083aab70afSSebastian Siewior 	.bDescriptorType	= USB_DT_ENDPOINT,
1093aab70afSSebastian Siewior 	.bEndpointAddress	= USB_DIR_OUT,
1103aab70afSSebastian Siewior 	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
111718156adSRoger Quadros 	.wMaxPacketSize		= cpu_to_le16(512),
1123aab70afSSebastian Siewior };
1133aab70afSSebastian Siewior 
1143aab70afSSebastian Siewior static struct usb_interface_descriptor interface_desc = {
1153aab70afSSebastian Siewior 	.bLength		= USB_DT_INTERFACE_SIZE,
1163aab70afSSebastian Siewior 	.bDescriptorType	= USB_DT_INTERFACE,
1173aab70afSSebastian Siewior 	.bInterfaceNumber	= 0x00,
1183aab70afSSebastian Siewior 	.bAlternateSetting	= 0x00,
1193aab70afSSebastian Siewior 	.bNumEndpoints		= 0x02,
1203aab70afSSebastian Siewior 	.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS,
1213aab70afSSebastian Siewior 	.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS,
1223aab70afSSebastian Siewior 	.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL,
1233aab70afSSebastian Siewior };
1243aab70afSSebastian Siewior 
125718156adSRoger Quadros static struct usb_descriptor_header *fb_fs_function[] = {
1263aab70afSSebastian Siewior 	(struct usb_descriptor_header *)&interface_desc,
1273aab70afSSebastian Siewior 	(struct usb_descriptor_header *)&fs_ep_in,
128718156adSRoger Quadros 	(struct usb_descriptor_header *)&fs_ep_out,
129718156adSRoger Quadros };
130718156adSRoger Quadros 
131718156adSRoger Quadros static struct usb_descriptor_header *fb_hs_function[] = {
132718156adSRoger Quadros 	(struct usb_descriptor_header *)&interface_desc,
133718156adSRoger Quadros 	(struct usb_descriptor_header *)&hs_ep_in,
1343aab70afSSebastian Siewior 	(struct usb_descriptor_header *)&hs_ep_out,
1353aab70afSSebastian Siewior 	NULL,
1363aab70afSSebastian Siewior };
1373aab70afSSebastian Siewior 
1388b704a0eSRoger Quadros static struct usb_endpoint_descriptor *
1398b704a0eSRoger Quadros fb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
1408b704a0eSRoger Quadros 	    struct usb_endpoint_descriptor *hs)
1418b704a0eSRoger Quadros {
1428b704a0eSRoger Quadros 	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
1438b704a0eSRoger Quadros 		return hs;
1448b704a0eSRoger Quadros 	return fs;
1458b704a0eSRoger Quadros }
1468b704a0eSRoger Quadros 
1473aab70afSSebastian Siewior /*
1483aab70afSSebastian Siewior  * static strings, in UTF-8
1493aab70afSSebastian Siewior  */
1503aab70afSSebastian Siewior static const char fastboot_name[] = "Android Fastboot";
1513aab70afSSebastian Siewior 
1523aab70afSSebastian Siewior static struct usb_string fastboot_string_defs[] = {
1533aab70afSSebastian Siewior 	[0].s = fastboot_name,
1543aab70afSSebastian Siewior 	{  }			/* end of list */
1553aab70afSSebastian Siewior };
1563aab70afSSebastian Siewior 
1573aab70afSSebastian Siewior static struct usb_gadget_strings stringtab_fastboot = {
1583aab70afSSebastian Siewior 	.language	= 0x0409,	/* en-us */
1593aab70afSSebastian Siewior 	.strings	= fastboot_string_defs,
1603aab70afSSebastian Siewior };
1613aab70afSSebastian Siewior 
1623aab70afSSebastian Siewior static struct usb_gadget_strings *fastboot_strings[] = {
1633aab70afSSebastian Siewior 	&stringtab_fastboot,
1643aab70afSSebastian Siewior 	NULL,
1653aab70afSSebastian Siewior };
1663aab70afSSebastian Siewior 
1673aab70afSSebastian Siewior static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
168e2ec3e46SAlexey Firago static int strcmp_l1(const char *s1, const char *s2);
169de78ceaeSJason Zhu static void wakeup_thread(void)
170de78ceaeSJason Zhu {
171de78ceaeSJason Zhu 	intthread_wakeup_needed = false;
172de78ceaeSJason Zhu }
173de78ceaeSJason Zhu 
174de78ceaeSJason Zhu static void busy_indicator(void)
175de78ceaeSJason Zhu {
176de78ceaeSJason Zhu 	static int state;
177de78ceaeSJason Zhu 
178de78ceaeSJason Zhu 	switch (state) {
179de78ceaeSJason Zhu 	case 0:
180de78ceaeSJason Zhu 		puts("\r|"); break;
181de78ceaeSJason Zhu 	case 1:
182de78ceaeSJason Zhu 		puts("\r/"); break;
183de78ceaeSJason Zhu 	case 2:
184de78ceaeSJason Zhu 		puts("\r-"); break;
185de78ceaeSJason Zhu 	case 3:
186de78ceaeSJason Zhu 		puts("\r\\"); break;
187de78ceaeSJason Zhu 	case 4:
188de78ceaeSJason Zhu 		puts("\r|"); break;
189de78ceaeSJason Zhu 	case 5:
190de78ceaeSJason Zhu 		puts("\r/"); break;
191de78ceaeSJason Zhu 	case 6:
192de78ceaeSJason Zhu 		puts("\r-"); break;
193de78ceaeSJason Zhu 	case 7:
194de78ceaeSJason Zhu 		puts("\r\\"); break;
195de78ceaeSJason Zhu 	default:
196de78ceaeSJason Zhu 		state = 0;
197de78ceaeSJason Zhu 	}
198de78ceaeSJason Zhu 	if (state++ == 8)
199de78ceaeSJason Zhu 		state = 0;
200de78ceaeSJason Zhu }
201de78ceaeSJason Zhu 
202de78ceaeSJason Zhu static int sleep_thread(void)
203de78ceaeSJason Zhu {
204de78ceaeSJason Zhu 	int rc = 0;
205de78ceaeSJason Zhu 	int i = 0, k = 0;
206de78ceaeSJason Zhu 
207de78ceaeSJason Zhu 	/* Wait until a signal arrives or we are woken up */
208de78ceaeSJason Zhu 	for (;;) {
209de78ceaeSJason Zhu 		if (!intthread_wakeup_needed)
210de78ceaeSJason Zhu 			break;
211de78ceaeSJason Zhu 
212de78ceaeSJason Zhu 		if (++i == SLEEP_COUNT) {
213de78ceaeSJason Zhu 			busy_indicator();
214de78ceaeSJason Zhu 			i = 0;
215de78ceaeSJason Zhu 			k++;
216de78ceaeSJason Zhu 		}
217de78ceaeSJason Zhu 
218de78ceaeSJason Zhu 		if (k == 10) {
219de78ceaeSJason Zhu 			/* Handle CTRL+C */
220de78ceaeSJason Zhu 			if (ctrlc())
221de78ceaeSJason Zhu 				return -EPIPE;
222de78ceaeSJason Zhu 
223de78ceaeSJason Zhu 			/* Check cable connection */
224de78ceaeSJason Zhu 			if (!g_dnl_board_usb_cable_connected())
225de78ceaeSJason Zhu 				return -EIO;
226de78ceaeSJason Zhu 
227de78ceaeSJason Zhu 			k = 0;
228de78ceaeSJason Zhu 		}
229de78ceaeSJason Zhu 
230de78ceaeSJason Zhu 		usb_gadget_handle_interrupts(0);
231de78ceaeSJason Zhu 	}
232de78ceaeSJason Zhu 	intthread_wakeup_needed = true;
233de78ceaeSJason Zhu 	return rc;
234de78ceaeSJason Zhu }
2353aab70afSSebastian Siewior 
2363aab70afSSebastian Siewior static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
2373aab70afSSebastian Siewior {
2383aab70afSSebastian Siewior 	int status = req->status;
239de78ceaeSJason Zhu 
240de78ceaeSJason Zhu 	wakeup_thread();
2413aab70afSSebastian Siewior 	if (!status)
2423aab70afSSebastian Siewior 		return;
2433aab70afSSebastian Siewior 	printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
2443aab70afSSebastian Siewior }
2453aab70afSSebastian Siewior 
2463aab70afSSebastian Siewior static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
2473aab70afSSebastian Siewior {
2483aab70afSSebastian Siewior 	int id;
2493aab70afSSebastian Siewior 	struct usb_gadget *gadget = c->cdev->gadget;
2503aab70afSSebastian Siewior 	struct f_fastboot *f_fb = func_to_fastboot(f);
251537cd072SDileep Katta 	const char *s;
2523aab70afSSebastian Siewior 
2533aab70afSSebastian Siewior 	/* DYNAMIC interface numbers assignments */
2543aab70afSSebastian Siewior 	id = usb_interface_id(c, f);
2553aab70afSSebastian Siewior 	if (id < 0)
2563aab70afSSebastian Siewior 		return id;
2573aab70afSSebastian Siewior 	interface_desc.bInterfaceNumber = id;
2583aab70afSSebastian Siewior 
2593aab70afSSebastian Siewior 	id = usb_string_id(c->cdev);
2603aab70afSSebastian Siewior 	if (id < 0)
2613aab70afSSebastian Siewior 		return id;
2623aab70afSSebastian Siewior 	fastboot_string_defs[0].id = id;
2633aab70afSSebastian Siewior 	interface_desc.iInterface = id;
2643aab70afSSebastian Siewior 
2653aab70afSSebastian Siewior 	f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
2663aab70afSSebastian Siewior 	if (!f_fb->in_ep)
2673aab70afSSebastian Siewior 		return -ENODEV;
2683aab70afSSebastian Siewior 	f_fb->in_ep->driver_data = c->cdev;
2693aab70afSSebastian Siewior 
2703aab70afSSebastian Siewior 	f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
2713aab70afSSebastian Siewior 	if (!f_fb->out_ep)
2723aab70afSSebastian Siewior 		return -ENODEV;
2733aab70afSSebastian Siewior 	f_fb->out_ep->driver_data = c->cdev;
2743aab70afSSebastian Siewior 
275718156adSRoger Quadros 	f->descriptors = fb_fs_function;
276718156adSRoger Quadros 
277718156adSRoger Quadros 	if (gadget_is_dualspeed(gadget)) {
278718156adSRoger Quadros 		/* Assume endpoint addresses are the same for both speeds */
279718156adSRoger Quadros 		hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
2803aab70afSSebastian Siewior 		hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
281718156adSRoger Quadros 		/* copy HS descriptors */
282718156adSRoger Quadros 		f->hs_descriptors = fb_hs_function;
283718156adSRoger Quadros 	}
2843aab70afSSebastian Siewior 
28500caae6dSSimon Glass 	s = env_get("serial#");
286537cd072SDileep Katta 	if (s)
287537cd072SDileep Katta 		g_dnl_set_serialnumber((char *)s);
288537cd072SDileep Katta 
2893aab70afSSebastian Siewior 	return 0;
2903aab70afSSebastian Siewior }
2913aab70afSSebastian Siewior 
2923aab70afSSebastian Siewior static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
2933aab70afSSebastian Siewior {
2943aab70afSSebastian Siewior 	memset(fastboot_func, 0, sizeof(*fastboot_func));
2953aab70afSSebastian Siewior }
2963aab70afSSebastian Siewior 
2973aab70afSSebastian Siewior static void fastboot_disable(struct usb_function *f)
2983aab70afSSebastian Siewior {
2993aab70afSSebastian Siewior 	struct f_fastboot *f_fb = func_to_fastboot(f);
3003aab70afSSebastian Siewior 
3013aab70afSSebastian Siewior 	usb_ep_disable(f_fb->out_ep);
3023aab70afSSebastian Siewior 	usb_ep_disable(f_fb->in_ep);
3033aab70afSSebastian Siewior 
3043aab70afSSebastian Siewior 	if (f_fb->out_req) {
3053aab70afSSebastian Siewior 		free(f_fb->out_req->buf);
3063aab70afSSebastian Siewior 		usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
3073aab70afSSebastian Siewior 		f_fb->out_req = NULL;
3083aab70afSSebastian Siewior 	}
3093aab70afSSebastian Siewior 	if (f_fb->in_req) {
3103aab70afSSebastian Siewior 		free(f_fb->in_req->buf);
3113aab70afSSebastian Siewior 		usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
3123aab70afSSebastian Siewior 		f_fb->in_req = NULL;
3133aab70afSSebastian Siewior 	}
3143aab70afSSebastian Siewior }
3153aab70afSSebastian Siewior 
3163aab70afSSebastian Siewior static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
3173aab70afSSebastian Siewior {
3183aab70afSSebastian Siewior 	struct usb_request *req;
3193aab70afSSebastian Siewior 
3203aab70afSSebastian Siewior 	req = usb_ep_alloc_request(ep, 0);
3213aab70afSSebastian Siewior 	if (!req)
3223aab70afSSebastian Siewior 		return NULL;
3233aab70afSSebastian Siewior 
3243aab70afSSebastian Siewior 	req->length = EP_BUFFER_SIZE;
3253aab70afSSebastian Siewior 	req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
3263aab70afSSebastian Siewior 	if (!req->buf) {
3273aab70afSSebastian Siewior 		usb_ep_free_request(ep, req);
3283aab70afSSebastian Siewior 		return NULL;
3293aab70afSSebastian Siewior 	}
3303aab70afSSebastian Siewior 
3313aab70afSSebastian Siewior 	memset(req->buf, 0, req->length);
3323aab70afSSebastian Siewior 	return req;
3333aab70afSSebastian Siewior }
3343aab70afSSebastian Siewior 
3353aab70afSSebastian Siewior static int fastboot_set_alt(struct usb_function *f,
3363aab70afSSebastian Siewior 			    unsigned interface, unsigned alt)
3373aab70afSSebastian Siewior {
3383aab70afSSebastian Siewior 	int ret;
3393aab70afSSebastian Siewior 	struct usb_composite_dev *cdev = f->config->cdev;
3403aab70afSSebastian Siewior 	struct usb_gadget *gadget = cdev->gadget;
3413aab70afSSebastian Siewior 	struct f_fastboot *f_fb = func_to_fastboot(f);
3428b704a0eSRoger Quadros 	const struct usb_endpoint_descriptor *d;
3433aab70afSSebastian Siewior 
3443aab70afSSebastian Siewior 	debug("%s: func: %s intf: %d alt: %d\n",
3453aab70afSSebastian Siewior 	      __func__, f->name, interface, alt);
3463aab70afSSebastian Siewior 
3478b704a0eSRoger Quadros 	d = fb_ep_desc(gadget, &fs_ep_out, &hs_ep_out);
3488b704a0eSRoger Quadros 	ret = usb_ep_enable(f_fb->out_ep, d);
3493aab70afSSebastian Siewior 	if (ret) {
3503aab70afSSebastian Siewior 		puts("failed to enable out ep\n");
3513aab70afSSebastian Siewior 		return ret;
3523aab70afSSebastian Siewior 	}
3533aab70afSSebastian Siewior 
3543aab70afSSebastian Siewior 	f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
3553aab70afSSebastian Siewior 	if (!f_fb->out_req) {
3563aab70afSSebastian Siewior 		puts("failed to alloc out req\n");
3573aab70afSSebastian Siewior 		ret = -EINVAL;
3583aab70afSSebastian Siewior 		goto err;
3593aab70afSSebastian Siewior 	}
3603aab70afSSebastian Siewior 	f_fb->out_req->complete = rx_handler_command;
3613aab70afSSebastian Siewior 
3628b704a0eSRoger Quadros 	d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in);
3638b704a0eSRoger Quadros 	ret = usb_ep_enable(f_fb->in_ep, d);
3643aab70afSSebastian Siewior 	if (ret) {
3653aab70afSSebastian Siewior 		puts("failed to enable in ep\n");
3663aab70afSSebastian Siewior 		goto err;
3673aab70afSSebastian Siewior 	}
3683aab70afSSebastian Siewior 
3693aab70afSSebastian Siewior 	f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
3703aab70afSSebastian Siewior 	if (!f_fb->in_req) {
3713aab70afSSebastian Siewior 		puts("failed alloc req in\n");
3723aab70afSSebastian Siewior 		ret = -EINVAL;
3733aab70afSSebastian Siewior 		goto err;
3743aab70afSSebastian Siewior 	}
3753aab70afSSebastian Siewior 	f_fb->in_req->complete = fastboot_complete;
3763aab70afSSebastian Siewior 
3773aab70afSSebastian Siewior 	ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
3783aab70afSSebastian Siewior 	if (ret)
3793aab70afSSebastian Siewior 		goto err;
3803aab70afSSebastian Siewior 
3813aab70afSSebastian Siewior 	return 0;
3823aab70afSSebastian Siewior err:
3833aab70afSSebastian Siewior 	fastboot_disable(f);
3843aab70afSSebastian Siewior 	return ret;
3853aab70afSSebastian Siewior }
3863aab70afSSebastian Siewior 
3873aab70afSSebastian Siewior static int fastboot_add(struct usb_configuration *c)
3883aab70afSSebastian Siewior {
3893aab70afSSebastian Siewior 	struct f_fastboot *f_fb = fastboot_func;
3903aab70afSSebastian Siewior 	int status;
3913aab70afSSebastian Siewior 
3923aab70afSSebastian Siewior 	debug("%s: cdev: 0x%p\n", __func__, c->cdev);
3933aab70afSSebastian Siewior 
3943aab70afSSebastian Siewior 	if (!f_fb) {
3953aab70afSSebastian Siewior 		f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
3963aab70afSSebastian Siewior 		if (!f_fb)
3973aab70afSSebastian Siewior 			return -ENOMEM;
3983aab70afSSebastian Siewior 
3993aab70afSSebastian Siewior 		fastboot_func = f_fb;
4003aab70afSSebastian Siewior 		memset(f_fb, 0, sizeof(*f_fb));
4013aab70afSSebastian Siewior 	}
4023aab70afSSebastian Siewior 
4033aab70afSSebastian Siewior 	f_fb->usb_function.name = "f_fastboot";
4043aab70afSSebastian Siewior 	f_fb->usb_function.bind = fastboot_bind;
4053aab70afSSebastian Siewior 	f_fb->usb_function.unbind = fastboot_unbind;
4063aab70afSSebastian Siewior 	f_fb->usb_function.set_alt = fastboot_set_alt;
4073aab70afSSebastian Siewior 	f_fb->usb_function.disable = fastboot_disable;
4083aab70afSSebastian Siewior 	f_fb->usb_function.strings = fastboot_strings;
4093aab70afSSebastian Siewior 
4103aab70afSSebastian Siewior 	status = usb_add_function(c, &f_fb->usb_function);
4113aab70afSSebastian Siewior 	if (status) {
4123aab70afSSebastian Siewior 		free(f_fb);
4133aab70afSSebastian Siewior 		fastboot_func = f_fb;
4143aab70afSSebastian Siewior 	}
4153aab70afSSebastian Siewior 
4163aab70afSSebastian Siewior 	return status;
4173aab70afSSebastian Siewior }
4183aab70afSSebastian Siewior DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
4193aab70afSSebastian Siewior 
420593cbd93SSteve Rae static int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
4213aab70afSSebastian Siewior {
4223aab70afSSebastian Siewior 	struct usb_request *in_req = fastboot_func->in_req;
4233aab70afSSebastian Siewior 	int ret;
4243aab70afSSebastian Siewior 
4253aab70afSSebastian Siewior 	memcpy(in_req->buf, buffer, buffer_size);
4263aab70afSSebastian Siewior 	in_req->length = buffer_size;
427bc9071c9SPaul Kocialkowski 
428bc9071c9SPaul Kocialkowski 	usb_ep_dequeue(fastboot_func->in_ep, in_req);
429bc9071c9SPaul Kocialkowski 
4303aab70afSSebastian Siewior 	ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
4313aab70afSSebastian Siewior 	if (ret)
4323aab70afSSebastian Siewior 		printf("Error %d on queue\n", ret);
4333aab70afSSebastian Siewior 	return 0;
4343aab70afSSebastian Siewior }
4353aab70afSSebastian Siewior 
4363aab70afSSebastian Siewior static int fastboot_tx_write_str(const char *buffer)
4373aab70afSSebastian Siewior {
438de78ceaeSJason Zhu 	int ret;
439de78ceaeSJason Zhu 
440de78ceaeSJason Zhu 	ret = sleep_thread();
441de78ceaeSJason Zhu 	if (ret < 0)
442de78ceaeSJason Zhu 		printf("warning: 0x%x, usb transmission is abnormal!\n", ret);
443de78ceaeSJason Zhu 
4443aab70afSSebastian Siewior 	return fastboot_tx_write(buffer, strlen(buffer));
4453aab70afSSebastian Siewior }
4463aab70afSSebastian Siewior 
4473aab70afSSebastian Siewior static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
4483aab70afSSebastian Siewior {
4493aab70afSSebastian Siewior 	do_reset(NULL, 0, 0, NULL);
4503aab70afSSebastian Siewior }
4513aab70afSSebastian Siewior 
452e2ec3e46SAlexey Firago int __weak fb_set_reboot_flag(void)
453e2ec3e46SAlexey Firago {
454e2ec3e46SAlexey Firago 	return -ENOSYS;
455e2ec3e46SAlexey Firago }
456e2ec3e46SAlexey Firago 
4573aab70afSSebastian Siewior static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
4583aab70afSSebastian Siewior {
459e2ec3e46SAlexey Firago 	char *cmd = req->buf;
460e2ec3e46SAlexey Firago 	if (!strcmp_l1("reboot-bootloader", cmd)) {
461e2ec3e46SAlexey Firago 		if (fb_set_reboot_flag()) {
462e2ec3e46SAlexey Firago 			fastboot_tx_write_str("FAILCannot set reboot flag");
463e2ec3e46SAlexey Firago 			return;
464e2ec3e46SAlexey Firago 		}
465e2ec3e46SAlexey Firago 	}
4663aab70afSSebastian Siewior 	fastboot_func->in_req->complete = compl_do_reset;
4673aab70afSSebastian Siewior 	fastboot_tx_write_str("OKAY");
4683aab70afSSebastian Siewior }
4693aab70afSSebastian Siewior 
4703aab70afSSebastian Siewior static int strcmp_l1(const char *s1, const char *s2)
4713aab70afSSebastian Siewior {
4723aab70afSSebastian Siewior 	if (!s1 || !s2)
4733aab70afSSebastian Siewior 		return -1;
4743aab70afSSebastian Siewior 	return strncmp(s1, s2, strlen(s1));
4753aab70afSSebastian Siewior }
4763aab70afSSebastian Siewior 
4773aab70afSSebastian Siewior static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
4783aab70afSSebastian Siewior {
4793aab70afSSebastian Siewior 	char *cmd = req->buf;
4803c8f98f5SMaxime Ripard 	char response[FASTBOOT_RESPONSE_LEN];
4813aab70afSSebastian Siewior 	const char *s;
48229425be4SJeroen Hofstee 	size_t chars_left;
4833aab70afSSebastian Siewior 
4843aab70afSSebastian Siewior 	strcpy(response, "OKAY");
48529425be4SJeroen Hofstee 	chars_left = sizeof(response) - strlen(response) - 1;
48629425be4SJeroen Hofstee 
4873aab70afSSebastian Siewior 	strsep(&cmd, ":");
4883aab70afSSebastian Siewior 	if (!cmd) {
48990aa625cSMasahiro Yamada 		pr_err("missing variable");
4903aab70afSSebastian Siewior 		fastboot_tx_write_str("FAILmissing var");
4913aab70afSSebastian Siewior 		return;
4923aab70afSSebastian Siewior 	}
4933aab70afSSebastian Siewior 
4943aab70afSSebastian Siewior 	if (!strcmp_l1("version", cmd)) {
49529425be4SJeroen Hofstee 		strncat(response, FASTBOOT_VERSION, chars_left);
4963aab70afSSebastian Siewior 	} else if (!strcmp_l1("bootloader-version", cmd)) {
49729425be4SJeroen Hofstee 		strncat(response, U_BOOT_VERSION, chars_left);
498374a9995SCody Xie 	} else if (!strcmp_l1("product", cmd)) {
499374a9995SCody Xie 		strncat(response, CONFIG_SYS_BOARD, chars_left);
500374a9995SCody Xie 	} else if (!strcmp_l1("variant", cmd)) {
501374a9995SCody Xie 		strncat(response, "userdebug", chars_left);
502374a9995SCody Xie 	} else if (!strcmp_l1("secure", cmd)) {
503374a9995SCody Xie 		strncat(response, "no", chars_left);
504374a9995SCody Xie 	} else if (!strcmp_l1("unlocked", cmd)) {
505374a9995SCody Xie 		strncat(response, "yes", chars_left);
506374a9995SCody Xie 	} else if (!strcmp_l1("off-mode-charge", cmd)) {
507374a9995SCody Xie 		strncat(response, "0", chars_left);
508374a9995SCody Xie 	} else if (!strcmp_l1("battery-voltage", cmd)) {
509374a9995SCody Xie 		strncat(response, "7.4", chars_left);
510374a9995SCody Xie 	} else if (!strcmp_l1("battery-soc-ok", cmd)) {
511374a9995SCody Xie 		strncat(response, "yes", chars_left);
512c674a666SEric Nelson 	} else if (!strcmp_l1("downloadsize", cmd) ||
513c674a666SEric Nelson 		!strcmp_l1("max-download-size", cmd)) {
5143aab70afSSebastian Siewior 		char str_num[12];
5153aab70afSSebastian Siewior 
516a588d99aSPaul Kocialkowski 		sprintf(str_num, "0x%08x", CONFIG_FASTBOOT_BUF_SIZE);
51729425be4SJeroen Hofstee 		strncat(response, str_num, chars_left);
5183aab70afSSebastian Siewior 	} else if (!strcmp_l1("serialno", cmd)) {
51900caae6dSSimon Glass 		s = env_get("serial#");
5203aab70afSSebastian Siewior 		if (s)
52129425be4SJeroen Hofstee 			strncat(response, s, chars_left);
5223aab70afSSebastian Siewior 		else
5233aab70afSSebastian Siewior 			strcpy(response, "FAILValue not set");
524367cce4dSXu Hongfei 	} else if (strncmp("at-attest-dh", cmd, 12) == 0) {
5254d0fc665SAndy Ye #ifdef CONFIG_OPTEE_CLIENT
5264d0fc665SAndy Ye 		char dhbuf[8];
5274d0fc665SAndy Ye 		uint32_t dh_len = 8;
5284d0fc665SAndy Ye 		uint32_t res = trusty_attest_dh((uint8_t *)dhbuf, &dh_len);
5294d0fc665SAndy Ye 		if (res)
5304d0fc665SAndy Ye 			strcpy(response, "FAILdh not set");
5314d0fc665SAndy Ye 		else
5324d0fc665SAndy Ye 			strncat(response, dhbuf, chars_left);
5334d0fc665SAndy Ye #else
5344d0fc665SAndy Ye 		fastboot_tx_write_str("FAILnot implemented");
5354d0fc665SAndy Ye 		return;
5364d0fc665SAndy Ye #endif
537367cce4dSXu Hongfei 	} else if (strncmp("at-attest-uuid", cmd, 14) == 0) {
5384d0fc665SAndy Ye #ifdef CONFIG_OPTEE_CLIENT
539367cce4dSXu Hongfei 		char uuid[32] = {0};
5404d0fc665SAndy Ye 		uint32_t uuid_len = 32;
5414d0fc665SAndy Ye 		uint32_t res = trusty_attest_uuid((uint8_t *)uuid, &uuid_len);
5424d0fc665SAndy Ye 		if (res)
5434d0fc665SAndy Ye 			strcpy(response, "FAILuuid not set");
5444d0fc665SAndy Ye 		else
545367cce4dSXu Hongfei 			strncat(response, uuid, chars_left);
5464d0fc665SAndy Ye #else
5474d0fc665SAndy Ye 		fastboot_tx_write_str("FAILnot implemented");
5484d0fc665SAndy Ye 		return;
5494d0fc665SAndy Ye #endif
550367cce4dSXu Hongfei 	} else if (strncmp("at-vboot-state", cmd, 14) == 0) {
551367cce4dSXu Hongfei 		char uuid[32] = {0};
552367cce4dSXu Hongfei 
553367cce4dSXu Hongfei 		strncat(response, uuid, chars_left);
554367cce4dSXu Hongfei 	} else if (!strcmp_l1("slot-count", cmd)) {
55537a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
556367cce4dSXu Hongfei 		char slot_count[2];
557367cce4dSXu Hongfei 		char temp;
558367cce4dSXu Hongfei 
559367cce4dSXu Hongfei 		slot_count[1] = '\0';
56037a7bc39SJason Zhu 		rk_avb_read_slot_count(&temp);
561367cce4dSXu Hongfei 		slot_count[0] = temp + 0x30;
562367cce4dSXu Hongfei 		strncat(response, slot_count, chars_left);
563367cce4dSXu Hongfei #else
564367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
565367cce4dSXu Hongfei 		return;
566367cce4dSXu Hongfei #endif
567367cce4dSXu Hongfei 	} else if (!strcmp_l1("current-slot", cmd)) {
56837a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
569367cce4dSXu Hongfei 		char slot_surrent[8] = {0};
570367cce4dSXu Hongfei 
57137a7bc39SJason Zhu 		if (!rk_avb_get_current_slot(slot_surrent))
572374a9995SCody Xie 			strncat(response, slot_surrent+1, chars_left);
573367cce4dSXu Hongfei 		else
574367cce4dSXu Hongfei 			strcpy(response, "FAILgeterror");
575367cce4dSXu Hongfei #else
576367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
577367cce4dSXu Hongfei 		return;
578367cce4dSXu Hongfei #endif
579367cce4dSXu Hongfei 	} else if (!strcmp_l1("slot-suffixes", cmd)) {
58037a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
581367cce4dSXu Hongfei 		char slot_suffixes_temp[4];
582367cce4dSXu Hongfei 		char slot_suffixes[9];
583367cce4dSXu Hongfei 		int slot_cnt = 0;
584367cce4dSXu Hongfei 
585367cce4dSXu Hongfei 		memset(slot_suffixes_temp, 0, 4);
586367cce4dSXu Hongfei 		memset(slot_suffixes, 0, 9);
58737a7bc39SJason Zhu 		rk_avb_read_slot_suffixes(slot_suffixes_temp);
588367cce4dSXu Hongfei 		while (slot_suffixes_temp[slot_cnt] != '\0') {
589367cce4dSXu Hongfei 			slot_suffixes[slot_cnt * 2]
590367cce4dSXu Hongfei 				= slot_suffixes_temp[slot_cnt];
591367cce4dSXu Hongfei 			slot_suffixes[slot_cnt * 2 + 1] = ',';
592367cce4dSXu Hongfei 			slot_cnt++;
593367cce4dSXu Hongfei 		}
594367cce4dSXu Hongfei 		strncat(response, slot_suffixes, chars_left);
595367cce4dSXu Hongfei #else
596367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
597367cce4dSXu Hongfei 		return;
598367cce4dSXu Hongfei #endif
599367cce4dSXu Hongfei 	} else if (!strncmp("has-slot", cmd, 8)) {
60037a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
601367cce4dSXu Hongfei 		char *part_name = cmd;
602367cce4dSXu Hongfei 
603367cce4dSXu Hongfei 		cmd = strsep(&part_name, ":");
604367cce4dSXu Hongfei 		if (!strcmp(part_name, "boot") ||
605367cce4dSXu Hongfei 		    !strcmp(part_name, "system") ||
606374a9995SCody Xie 		    !strcmp(part_name, "vendor") ||
607374a9995SCody Xie 		    !strcmp(part_name, "vbmeta") ||
608374a9995SCody Xie 		    !strcmp(part_name, "oem")) {
609367cce4dSXu Hongfei 			strncat(response, "yes", chars_left);
610367cce4dSXu Hongfei 		} else {
611367cce4dSXu Hongfei 			strcpy(response, "FAILno");
612367cce4dSXu Hongfei 		}
613367cce4dSXu Hongfei #else
614367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
615367cce4dSXu Hongfei 		return;
616367cce4dSXu Hongfei #endif
617374a9995SCody Xie 	} else if (!strncmp("slot-unbootable", cmd, 15)) {
61837a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
619374a9995SCody Xie 		char *slot_name = cmd;
620374a9995SCody Xie 
621374a9995SCody Xie 		cmd = strsep(&slot_name, ":");
622374a9995SCody Xie 		if (!strcmp(slot_name, "a") ||
623374a9995SCody Xie 		    !strcmp(slot_name, "b")) {
624374a9995SCody Xie 			strncat(response, "no", chars_left);
625374a9995SCody Xie 		} else {
626374a9995SCody Xie 			strcpy(response, "FAILno");
627374a9995SCody Xie 		}
628374a9995SCody Xie #else
629374a9995SCody Xie 		fastboot_tx_write_str("FAILnot implemented");
630374a9995SCody Xie 		return;
631374a9995SCody Xie #endif
632374a9995SCody Xie 	} else if (!strncmp("slot-successful", cmd, 15)) {
63337a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
634374a9995SCody Xie 		char *slot_name = cmd;
635374a9995SCody Xie 
636374a9995SCody Xie 		cmd = strsep(&slot_name, ":");
637374a9995SCody Xie 		if (!strcmp(slot_name, "a") ||
638374a9995SCody Xie 		    !strcmp(slot_name, "b")) {
639374a9995SCody Xie 			strncat(response, "no", chars_left);
640374a9995SCody Xie 		} else {
641374a9995SCody Xie 			strcpy(response, "FAILno");
642374a9995SCody Xie 		}
643374a9995SCody Xie #else
644374a9995SCody Xie 		fastboot_tx_write_str("FAILnot implemented");
645374a9995SCody Xie 		return;
646374a9995SCody Xie #endif
647374a9995SCody Xie 	} else if (!strncmp("slot-retry-count", cmd, 16)) {
64837a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
649374a9995SCody Xie 		char *slot_name = cmd;
650374a9995SCody Xie 		char count[10] = {0};
651374a9995SCody Xie 		static int cnt[2] = {0};
652374a9995SCody Xie 
653374a9995SCody Xie 		cmd = strsep(&slot_name, ":");
654374a9995SCody Xie 		if (!strcmp(slot_name, "a")) {
655374a9995SCody Xie 			sprintf(count, "%c", 0x30+cnt[0]);
656374a9995SCody Xie 			strncat(response, count, chars_left);
657374a9995SCody Xie 			if (cnt[0] > 0)
658374a9995SCody Xie 				cnt[0]--;
659374a9995SCody Xie 		} else if (!strcmp(slot_name, "b")) {
660374a9995SCody Xie 			sprintf(count, "%c", 0x30+cnt[1]);
661374a9995SCody Xie 			strncat(response, count, chars_left);
662374a9995SCody Xie 			if (cnt[1] > 0)
663374a9995SCody Xie 				cnt[1]--;
664374a9995SCody Xie 		} else {
665374a9995SCody Xie 			strcpy(response, "FAILno");
666374a9995SCody Xie 		}
667374a9995SCody Xie #else
668374a9995SCody Xie 		fastboot_tx_write_str("FAILnot implemented");
669374a9995SCody Xie 		return;
670374a9995SCody Xie #endif
671367cce4dSXu Hongfei 	} else if (!strncmp("partition-type", cmd, 14) ||
672367cce4dSXu Hongfei 		   !strncmp("partition-size", cmd, 14)) {
673367cce4dSXu Hongfei 		disk_partition_t part_info;
674367cce4dSXu Hongfei 		struct blk_desc *dev_desc;
675367cce4dSXu Hongfei 		char *part_name = cmd;
676367cce4dSXu Hongfei 		char part_size_str[20];
677367cce4dSXu Hongfei 
678367cce4dSXu Hongfei 		cmd = strsep(&part_name, ":");
679367cce4dSXu Hongfei 		dev_desc = blk_get_dev("mmc", 0);
680367cce4dSXu Hongfei 		if (!dev_desc) {
681367cce4dSXu Hongfei 			strcpy(response, "FAILblock device not found");
682367cce4dSXu Hongfei 		} else if (part_get_info_by_name(dev_desc, part_name, &part_info) < 0) {
683367cce4dSXu Hongfei 			strcpy(response, "FAILpartition not found");
684367cce4dSXu Hongfei 		} else if (!strncmp("partition-type", cmd, 14)) {
685367cce4dSXu Hongfei 			strncat(response, (char *)part_info.type, chars_left);
686367cce4dSXu Hongfei 		} else if (!strncmp("partition-size", cmd, 14)) {
687367cce4dSXu Hongfei 			sprintf(part_size_str, "0x%016x", (int)part_info.size);
688367cce4dSXu Hongfei 			strncat(response, part_size_str, chars_left);
689367cce4dSXu Hongfei 		}
690f61a997eSqiujian 	} else if (!strncmp("oem-unlock", cmd, 10)) {
69165413a00SJian Qiu #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
692f61a997eSqiujian #ifdef CONFIG_RK_AVB_LIBAVB_USER
693f61a997eSqiujian 		fastboot_tx_write_str("FAILnot implemented");
694f61a997eSqiujian 		return;
695f61a997eSqiujian #else
696f61a997eSqiujian 
697f61a997eSqiujian 		char msg[50] = {0};
698f61a997eSqiujian 		uint8_t unlock = 0;
699f61a997eSqiujian 		TEEC_Result result;
700f61a997eSqiujian 
701f61a997eSqiujian 		result = trusty_read_oem_unlock(&unlock);
702f61a997eSqiujian 		if (result) {
703f61a997eSqiujian 			printf("read oem unlock status with error : 0x%x\n", result);
704f61a997eSqiujian 			fastboot_tx_write_str("FAILRead oem unlock status failed");
705f61a997eSqiujian 			return;
706f61a997eSqiujian 		}
707f61a997eSqiujian 		sprintf(msg, "Device is %s, Status Code: %d\n",
708f61a997eSqiujian 			unlock == 0 ? "LOCKED" : "UNLOCKED", unlock);
709f61a997eSqiujian 
710f61a997eSqiujian 		printf(msg);
711f61a997eSqiujian 		strncat(response, msg, chars_left);
712f61a997eSqiujian #endif
713f61a997eSqiujian #else
714f61a997eSqiujian 		fastboot_tx_write_str("FAILnot implemented");
715f61a997eSqiujian 		return;
716f61a997eSqiujian #endif
7173aab70afSSebastian Siewior 	} else {
718b1f2a17cSnicolas.le.bayon@st.com 		char *envstr;
71974322201SRob Herring 
720b1f2a17cSnicolas.le.bayon@st.com 		envstr = malloc(strlen("fastboot.") + strlen(cmd) + 1);
721b1f2a17cSnicolas.le.bayon@st.com 		if (!envstr) {
722b1f2a17cSnicolas.le.bayon@st.com 			fastboot_tx_write_str("FAILmalloc error");
723b1f2a17cSnicolas.le.bayon@st.com 			return;
724b1f2a17cSnicolas.le.bayon@st.com 		}
725b1f2a17cSnicolas.le.bayon@st.com 
726b1f2a17cSnicolas.le.bayon@st.com 		sprintf(envstr, "fastboot.%s", cmd);
72700caae6dSSimon Glass 		s = env_get(envstr);
72874322201SRob Herring 		if (s) {
72974322201SRob Herring 			strncat(response, s, chars_left);
73074322201SRob Herring 		} else {
731a18c2706SSteve Rae 			printf("WARNING: unknown variable: %s\n", cmd);
7323aab70afSSebastian Siewior 			strcpy(response, "FAILVariable not implemented");
7333aab70afSSebastian Siewior 		}
734b1f2a17cSnicolas.le.bayon@st.com 
735b1f2a17cSnicolas.le.bayon@st.com 		free(envstr);
73674322201SRob Herring 	}
7373aab70afSSebastian Siewior 	fastboot_tx_write_str(response);
7383aab70afSSebastian Siewior }
7393aab70afSSebastian Siewior 
740ac484c5aSRoger Quadros static unsigned int rx_bytes_expected(struct usb_ep *ep)
7413aab70afSSebastian Siewior {
7423aab70afSSebastian Siewior 	int rx_remain = download_size - download_bytes;
743ac484c5aSRoger Quadros 	unsigned int rem;
744ac484c5aSRoger Quadros 	unsigned int maxpacket = ep->maxpacket;
745ac484c5aSRoger Quadros 
746ac484c5aSRoger Quadros 	if (rx_remain <= 0)
7473aab70afSSebastian Siewior 		return 0;
748ac484c5aSRoger Quadros 	else if (rx_remain > EP_BUFFER_SIZE)
7493aab70afSSebastian Siewior 		return EP_BUFFER_SIZE;
750ac484c5aSRoger Quadros 
751ac484c5aSRoger Quadros 	/*
752ac484c5aSRoger Quadros 	 * Some controllers e.g. DWC3 don't like OUT transfers to be
753ac484c5aSRoger Quadros 	 * not ending in maxpacket boundary. So just make them happy by
754ac484c5aSRoger Quadros 	 * always requesting for integral multiple of maxpackets.
755ac484c5aSRoger Quadros 	 * This shouldn't bother controllers that don't care about it.
756ac484c5aSRoger Quadros 	 */
7579e4b510dSDileep Katta 	rem = rx_remain % maxpacket;
758ac484c5aSRoger Quadros 	if (rem > 0)
7599e4b510dSDileep Katta 		rx_remain = rx_remain + (maxpacket - rem);
760ac484c5aSRoger Quadros 
7613aab70afSSebastian Siewior 	return rx_remain;
7623aab70afSSebastian Siewior }
7633aab70afSSebastian Siewior 
7643aab70afSSebastian Siewior #define BYTES_PER_DOT	0x20000
7653aab70afSSebastian Siewior static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
7663aab70afSSebastian Siewior {
7673c8f98f5SMaxime Ripard 	char response[FASTBOOT_RESPONSE_LEN];
7683aab70afSSebastian Siewior 	unsigned int transfer_size = download_size - download_bytes;
7693aab70afSSebastian Siewior 	const unsigned char *buffer = req->buf;
7703aab70afSSebastian Siewior 	unsigned int buffer_size = req->actual;
77123d1d10cSBo Shen 	unsigned int pre_dot_num, now_dot_num;
7723aab70afSSebastian Siewior 
7733aab70afSSebastian Siewior 	if (req->status != 0) {
7743aab70afSSebastian Siewior 		printf("Bad status: %d\n", req->status);
7753aab70afSSebastian Siewior 		return;
7763aab70afSSebastian Siewior 	}
7773aab70afSSebastian Siewior 
7783aab70afSSebastian Siewior 	if (buffer_size < transfer_size)
7793aab70afSSebastian Siewior 		transfer_size = buffer_size;
7803aab70afSSebastian Siewior 
781a588d99aSPaul Kocialkowski 	memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes,
7823aab70afSSebastian Siewior 	       buffer, transfer_size);
7833aab70afSSebastian Siewior 
78423d1d10cSBo Shen 	pre_dot_num = download_bytes / BYTES_PER_DOT;
7853aab70afSSebastian Siewior 	download_bytes += transfer_size;
78623d1d10cSBo Shen 	now_dot_num = download_bytes / BYTES_PER_DOT;
78723d1d10cSBo Shen 
78823d1d10cSBo Shen 	if (pre_dot_num != now_dot_num) {
78923d1d10cSBo Shen 		putc('.');
79023d1d10cSBo Shen 		if (!(now_dot_num % 74))
79123d1d10cSBo Shen 			putc('\n');
79223d1d10cSBo Shen 	}
7933aab70afSSebastian Siewior 
7943aab70afSSebastian Siewior 	/* Check if transfer is done */
7953aab70afSSebastian Siewior 	if (download_bytes >= download_size) {
7963aab70afSSebastian Siewior 		/*
7973aab70afSSebastian Siewior 		 * Reset global transfer variable, keep download_bytes because
7983aab70afSSebastian Siewior 		 * it will be used in the next possible flashing command
7993aab70afSSebastian Siewior 		 */
8003aab70afSSebastian Siewior 		download_size = 0;
8013aab70afSSebastian Siewior 		req->complete = rx_handler_command;
8023aab70afSSebastian Siewior 		req->length = EP_BUFFER_SIZE;
8033aab70afSSebastian Siewior 
804192bc694SBen Whitten 		strcpy(response, "OKAY");
8053aab70afSSebastian Siewior 		fastboot_tx_write_str(response);
8063aab70afSSebastian Siewior 
8073aab70afSSebastian Siewior 		printf("\ndownloading of %d bytes finished\n", download_bytes);
8083aab70afSSebastian Siewior 	} else {
809ac484c5aSRoger Quadros 		req->length = rx_bytes_expected(ep);
8103aab70afSSebastian Siewior 	}
8113aab70afSSebastian Siewior 
8123aab70afSSebastian Siewior 	req->actual = 0;
8133aab70afSSebastian Siewior 	usb_ep_queue(ep, req, 0);
8143aab70afSSebastian Siewior }
8153aab70afSSebastian Siewior 
8163aab70afSSebastian Siewior static void cb_download(struct usb_ep *ep, struct usb_request *req)
8173aab70afSSebastian Siewior {
8183aab70afSSebastian Siewior 	char *cmd = req->buf;
8193c8f98f5SMaxime Ripard 	char response[FASTBOOT_RESPONSE_LEN];
8203aab70afSSebastian Siewior 
8213aab70afSSebastian Siewior 	strsep(&cmd, ":");
8223aab70afSSebastian Siewior 	download_size = simple_strtoul(cmd, NULL, 16);
8233aab70afSSebastian Siewior 	download_bytes = 0;
8243aab70afSSebastian Siewior 
8253aab70afSSebastian Siewior 	printf("Starting download of %d bytes\n", download_size);
8263aab70afSSebastian Siewior 
8273aab70afSSebastian Siewior 	if (0 == download_size) {
828192bc694SBen Whitten 		strcpy(response, "FAILdata invalid size");
829a588d99aSPaul Kocialkowski 	} else if (download_size > CONFIG_FASTBOOT_BUF_SIZE) {
8303aab70afSSebastian Siewior 		download_size = 0;
831192bc694SBen Whitten 		strcpy(response, "FAILdata too large");
8323aab70afSSebastian Siewior 	} else {
8333aab70afSSebastian Siewior 		sprintf(response, "DATA%08x", download_size);
8343aab70afSSebastian Siewior 		req->complete = rx_handler_dl_image;
835ac484c5aSRoger Quadros 		req->length = rx_bytes_expected(ep);
8363aab70afSSebastian Siewior 	}
837367cce4dSXu Hongfei 
838367cce4dSXu Hongfei 	fastboot_tx_write_str(response);
839367cce4dSXu Hongfei }
840367cce4dSXu Hongfei 
841367cce4dSXu Hongfei static void tx_handler_ul(struct usb_ep *ep, struct usb_request *req)
842367cce4dSXu Hongfei {
843367cce4dSXu Hongfei 	unsigned int xfer_size = 0;
844367cce4dSXu Hongfei 	unsigned int pre_dot_num, now_dot_num;
845367cce4dSXu Hongfei 	unsigned int remain_size = 0;
846367cce4dSXu Hongfei 	unsigned int transferred_size = req->actual;
847367cce4dSXu Hongfei 
848367cce4dSXu Hongfei 	if (req->status != 0) {
849367cce4dSXu Hongfei 		printf("Bad status: %d\n", req->status);
850367cce4dSXu Hongfei 		return;
851367cce4dSXu Hongfei 	}
852367cce4dSXu Hongfei 
853367cce4dSXu Hongfei 	if (start_upload) {
854367cce4dSXu Hongfei 		pre_dot_num = upload_bytes / BYTES_PER_DOT;
855367cce4dSXu Hongfei 		upload_bytes += transferred_size;
856367cce4dSXu Hongfei 		now_dot_num = upload_bytes / BYTES_PER_DOT;
857367cce4dSXu Hongfei 
858367cce4dSXu Hongfei 		if (pre_dot_num != now_dot_num) {
859367cce4dSXu Hongfei 			putc('.');
860367cce4dSXu Hongfei 			if (!(now_dot_num % 74))
861367cce4dSXu Hongfei 				putc('\n');
862367cce4dSXu Hongfei 		}
863367cce4dSXu Hongfei 	}
864367cce4dSXu Hongfei 
865367cce4dSXu Hongfei 	remain_size = upload_size - upload_bytes;
866367cce4dSXu Hongfei 	xfer_size = (remain_size > EP_BUFFER_SIZE) ?
867367cce4dSXu Hongfei 		    EP_BUFFER_SIZE : remain_size;
868367cce4dSXu Hongfei 
869367cce4dSXu Hongfei 	debug("%s: remain_size=%d, transferred_size=%d",
870367cce4dSXu Hongfei 	      __func__, remain_size, transferred_size);
871367cce4dSXu Hongfei 	debug("xfer_size=%d, upload_bytes=%d, upload_size=%d!\n",
872367cce4dSXu Hongfei 	      xfer_size, upload_bytes, upload_size);
873367cce4dSXu Hongfei 
874367cce4dSXu Hongfei 	if (remain_size <= 0) {
875367cce4dSXu Hongfei 		fastboot_func->in_req->complete = fastboot_complete;
876aa74b607SJason Zhu 		wakeup_thread();
877367cce4dSXu Hongfei 		fastboot_tx_write_str("OKAY");
878367cce4dSXu Hongfei 		printf("\nuploading of %d bytes finished\n", upload_bytes);
879367cce4dSXu Hongfei 		upload_bytes = 0;
880367cce4dSXu Hongfei 		upload_size = 0;
881367cce4dSXu Hongfei 		start_upload = false;
882367cce4dSXu Hongfei 		return;
883367cce4dSXu Hongfei 	}
884367cce4dSXu Hongfei 
885367cce4dSXu Hongfei 	/* Remove the transfer callback which response the upload */
886367cce4dSXu Hongfei 	/* request from host */
887367cce4dSXu Hongfei 	if (!upload_bytes)
888367cce4dSXu Hongfei 		start_upload = true;
889367cce4dSXu Hongfei 
890174b4544SKever Yang 	fastboot_tx_write((char *)((phys_addr_t)CONFIG_FASTBOOT_BUF_ADDR + \
891174b4544SKever Yang 			  upload_bytes),
892367cce4dSXu Hongfei 			  xfer_size);
893367cce4dSXu Hongfei }
894367cce4dSXu Hongfei 
895367cce4dSXu Hongfei static void cb_upload(struct usb_ep *ep, struct usb_request *req)
896367cce4dSXu Hongfei {
897367cce4dSXu Hongfei 	char response[FASTBOOT_RESPONSE_LEN];
898367cce4dSXu Hongfei 
899367cce4dSXu Hongfei 	printf("Starting upload of %d bytes\n", upload_size);
900367cce4dSXu Hongfei 
901367cce4dSXu Hongfei 	if (0 == upload_size) {
902367cce4dSXu Hongfei 		strcpy(response, "FAILdata invalid size");
903367cce4dSXu Hongfei 	} else {
904367cce4dSXu Hongfei 		start_upload = false;
905367cce4dSXu Hongfei 		sprintf(response, "DATA%08x", upload_size);
906367cce4dSXu Hongfei 		fastboot_func->in_req->complete = tx_handler_ul;
907367cce4dSXu Hongfei 	}
908367cce4dSXu Hongfei 
9093aab70afSSebastian Siewior 	fastboot_tx_write_str(response);
9103aab70afSSebastian Siewior }
9113aab70afSSebastian Siewior 
9123aab70afSSebastian Siewior static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
9133aab70afSSebastian Siewior {
9143aab70afSSebastian Siewior 	char boot_addr_start[12];
9153aab70afSSebastian Siewior 	char *bootm_args[] = { "bootm", boot_addr_start, NULL };
9163aab70afSSebastian Siewior 
9173aab70afSSebastian Siewior 	puts("Booting kernel..\n");
9183aab70afSSebastian Siewior 
91990ae53ceSTom Rini 	sprintf(boot_addr_start, "0x%lx", (long)CONFIG_FASTBOOT_BUF_ADDR);
9203aab70afSSebastian Siewior 	do_bootm(NULL, 0, 2, bootm_args);
9213aab70afSSebastian Siewior 
9223aab70afSSebastian Siewior 	/* This only happens if image is somehow faulty so we start over */
9233aab70afSSebastian Siewior 	do_reset(NULL, 0, 0, NULL);
9243aab70afSSebastian Siewior }
9253aab70afSSebastian Siewior 
9263aab70afSSebastian Siewior static void cb_boot(struct usb_ep *ep, struct usb_request *req)
9273aab70afSSebastian Siewior {
9283aab70afSSebastian Siewior 	fastboot_func->in_req->complete = do_bootm_on_complete;
9293aab70afSSebastian Siewior 	fastboot_tx_write_str("OKAY");
9303aab70afSSebastian Siewior }
9313aab70afSSebastian Siewior 
932267abc62SRob Herring static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req)
933267abc62SRob Herring {
934267abc62SRob Herring 	g_dnl_trigger_detach();
935267abc62SRob Herring }
936267abc62SRob Herring 
937267abc62SRob Herring static void cb_continue(struct usb_ep *ep, struct usb_request *req)
938267abc62SRob Herring {
939267abc62SRob Herring 	fastboot_func->in_req->complete = do_exit_on_complete;
940267abc62SRob Herring 	fastboot_tx_write_str("OKAY");
941267abc62SRob Herring }
942267abc62SRob Herring 
943367cce4dSXu Hongfei static void cb_set_active(struct usb_ep *ep, struct usb_request *req)
944367cce4dSXu Hongfei {
945367cce4dSXu Hongfei 	char *cmd = req->buf;
946367cce4dSXu Hongfei 
947367cce4dSXu Hongfei 	debug("%s: %s\n", __func__, cmd);
948367cce4dSXu Hongfei 
949367cce4dSXu Hongfei 	strsep(&cmd, ":");
950367cce4dSXu Hongfei 	if (!cmd) {
95190aa625cSMasahiro Yamada 		pr_err("missing slot name");
9522e40c2c1SJason Zhu 		fastboot_tx_write_str("FAILmissing slot name");
953367cce4dSXu Hongfei 		return;
954367cce4dSXu Hongfei 	}
95537a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
956367cce4dSXu Hongfei 	unsigned int slot_number;
957367cce4dSXu Hongfei 	if (strncmp("a", cmd, 1) == 0) {
958367cce4dSXu Hongfei 		slot_number = 0;
95937a7bc39SJason Zhu 		rk_avb_set_slot_active(&slot_number);
960367cce4dSXu Hongfei 	} else if (strncmp("b", cmd, 1) == 0) {
961367cce4dSXu Hongfei 		slot_number = 1;
96237a7bc39SJason Zhu 		rk_avb_set_slot_active(&slot_number);
963367cce4dSXu Hongfei 	} else {
9642e40c2c1SJason Zhu 		fastboot_tx_write_str("FAILunkown slot name");
965367cce4dSXu Hongfei 		return;
966367cce4dSXu Hongfei 	}
967367cce4dSXu Hongfei 
968367cce4dSXu Hongfei 	fastboot_tx_write_str("OKAY");
969367cce4dSXu Hongfei 	return;
970367cce4dSXu Hongfei #else
971367cce4dSXu Hongfei 	fastboot_tx_write_str("FAILnot implemented");
972367cce4dSXu Hongfei 	return;
973367cce4dSXu Hongfei #endif
974367cce4dSXu Hongfei }
975367cce4dSXu Hongfei 
976d1b5ed07SSteve Rae #ifdef CONFIG_FASTBOOT_FLASH
977d1b5ed07SSteve Rae static void cb_flash(struct usb_ep *ep, struct usb_request *req)
978d1b5ed07SSteve Rae {
979d1b5ed07SSteve Rae 	char *cmd = req->buf;
980374a9995SCody Xie 	char response[FASTBOOT_RESPONSE_LEN] = {0};
98137a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
9827bc1707dSJason Zhu 	uint8_t flash_lock_state;
983d1b5ed07SSteve Rae 
98437a7bc39SJason Zhu 	if (rk_avb_read_flash_lock_state(&flash_lock_state)) {
9852e40c2c1SJason Zhu 		/* write the device flashing unlock when first read */
9862e40c2c1SJason Zhu 		if (rk_avb_write_flash_lock_state(1)) {
9872e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILflash lock state write failure");
9887bc1707dSJason Zhu 			return;
989ef52a073SJason Zhu 		}
9902e40c2c1SJason Zhu 		if (rk_avb_read_flash_lock_state(&flash_lock_state)) {
9912e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILflash lock state read failure");
9922e40c2c1SJason Zhu 			return;
9932e40c2c1SJason Zhu 		}
9942e40c2c1SJason Zhu 	}
995ef52a073SJason Zhu 
9967bc1707dSJason Zhu 	if (flash_lock_state == 0) {
9977bc1707dSJason Zhu 		fastboot_tx_write_str("FAILThe device is locked, can not flash!");
9987bc1707dSJason Zhu 		printf("The device is locked, can not flash!\n");
9997bc1707dSJason Zhu 		return;
10007bc1707dSJason Zhu 	}
10017bc1707dSJason Zhu #endif
1002d1b5ed07SSteve Rae 	strsep(&cmd, ":");
1003d1b5ed07SSteve Rae 	if (!cmd) {
100490aa625cSMasahiro Yamada 		pr_err("missing partition name");
1005d1b5ed07SSteve Rae 		fastboot_tx_write_str("FAILmissing partition name");
1006d1b5ed07SSteve Rae 		return;
1007d1b5ed07SSteve Rae 	}
1008d1b5ed07SSteve Rae 
10098b464fa9SJocelyn Bohr 	fastboot_fail("no flash device defined", response);
1010d1b5ed07SSteve Rae #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
101164ece848SSteve Rae 	fb_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR,
10128b464fa9SJocelyn Bohr 				download_bytes, response);
1013d1b5ed07SSteve Rae #endif
1014bf8940d3SMaxime Ripard #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
10158b464fa9SJocelyn Bohr 	fb_nand_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR,
10168b464fa9SJocelyn Bohr 				download_bytes, response);
1017bf8940d3SMaxime Ripard #endif
1018d1b5ed07SSteve Rae 	fastboot_tx_write_str(response);
1019d1b5ed07SSteve Rae }
1020d1b5ed07SSteve Rae 
1021367cce4dSXu Hongfei static void cb_flashing(struct usb_ep *ep, struct usb_request *req)
1022367cce4dSXu Hongfei {
1023367cce4dSXu Hongfei 	char *cmd = req->buf;
1024367cce4dSXu Hongfei 
1025367cce4dSXu Hongfei 	if (strncmp("lock", cmd + 9, 4) == 0) {
102637a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
10277bc1707dSJason Zhu 		uint8_t flash_lock_state;
10287bc1707dSJason Zhu 		flash_lock_state = 0;
102937a7bc39SJason Zhu 		if (rk_avb_write_flash_lock_state(flash_lock_state))
10302e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILflash lock state"
10312e40c2c1SJason Zhu 					      " write failure");
10327bc1707dSJason Zhu 		else
10337bc1707dSJason Zhu 			fastboot_tx_write_str("OKAY");
10347bc1707dSJason Zhu #else
1035367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
10367bc1707dSJason Zhu #endif
1037367cce4dSXu Hongfei 	} else if (strncmp("unlock", cmd + 9, 6) == 0) {
103837a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
10397bc1707dSJason Zhu 		uint8_t flash_lock_state;
10407bc1707dSJason Zhu 		flash_lock_state = 1;
104137a7bc39SJason Zhu 		if (rk_avb_write_flash_lock_state(flash_lock_state))
10422e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILflash lock state"
10432e40c2c1SJason Zhu 					      " write failure");
10447bc1707dSJason Zhu 		else
10457bc1707dSJason Zhu 			fastboot_tx_write_str("OKAY");
10467bc1707dSJason Zhu #else
1047367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
10487bc1707dSJason Zhu #endif
1049367cce4dSXu Hongfei 	} else if (strncmp("lock_critical", cmd + 9, 12) == 0) {
1050367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
1051367cce4dSXu Hongfei 	} else if (strncmp("unlock_critical", cmd + 9, 14) == 0) {
1052367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
1053367cce4dSXu Hongfei 	} else if (strncmp("get_unlock_ability", cmd + 9, 17) == 0) {
1054367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
1055367cce4dSXu Hongfei 	} else if (strncmp("get_unlock_bootloader_nonce", cmd + 4, 27) == 0) {
1056367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
1057367cce4dSXu Hongfei 	} else if (strncmp("unlock_bootloader", cmd + 9, 17) == 0) {
1058367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
1059367cce4dSXu Hongfei 	} else if (strncmp("lock_bootloader", cmd + 9, 15) == 0) {
1060367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
1061367cce4dSXu Hongfei 	} else {
1062367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILunknown flashing command");
1063367cce4dSXu Hongfei 	}
1064367cce4dSXu Hongfei }
10656f3eb474SKever Yang #endif
1066367cce4dSXu Hongfei 
10672e40c2c1SJason Zhu static void cb_oem_perm_attr(void)
10682e40c2c1SJason Zhu {
10692e40c2c1SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
10702e40c2c1SJason Zhu 	sha256_context ctx;
10712e40c2c1SJason Zhu 	uint8_t digest[SHA256_SUM_LEN] = {0};
10722e40c2c1SJason Zhu 	uint8_t digest_temp[SHA256_SUM_LEN] = {0};
10732e40c2c1SJason Zhu 	uint8_t perm_attr_temp[PERM_ATTR_TOTAL_SIZE] = {0};
10742e40c2c1SJason Zhu 	uint8_t flag = 0;
10752e40c2c1SJason Zhu 
10762e40c2c1SJason Zhu 	if (PERM_ATTR_TOTAL_SIZE != download_bytes) {
10772e40c2c1SJason Zhu 		printf("Permanent attribute size is not equal!\n");
10782e40c2c1SJason Zhu 		fastboot_tx_write_str("FAILincorrect perm attribute size");
10792e40c2c1SJason Zhu 		return;
10802e40c2c1SJason Zhu 	}
10812e40c2c1SJason Zhu 
10822e40c2c1SJason Zhu 	if (rk_avb_read_perm_attr_flag(&flag)) {
10832e40c2c1SJason Zhu 		printf("rk_avb_read_perm_attr_flag error!\n");
10842e40c2c1SJason Zhu 		fastboot_tx_write_str("FAILperm attr read failed");
10852e40c2c1SJason Zhu 		return;
10862e40c2c1SJason Zhu 	}
10872e40c2c1SJason Zhu 
10882e40c2c1SJason Zhu 	if (flag == PERM_ATTR_SUCCESS_FLAG) {
10892e40c2c1SJason Zhu 		if (rk_avb_read_attribute_hash(digest_temp,
10902e40c2c1SJason Zhu 					       SHA256_SUM_LEN)) {
10912e40c2c1SJason Zhu 			printf("The efuse IO can not be used!\n");
10922e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILefuse IO can not be used");
10932e40c2c1SJason Zhu 			return;
10942e40c2c1SJason Zhu 		}
10952e40c2c1SJason Zhu 
10962e40c2c1SJason Zhu 		if (memcmp(digest, digest_temp, SHA256_SUM_LEN) != 0) {
10972e40c2c1SJason Zhu 			if (rk_avb_read_permanent_attributes(perm_attr_temp,
10982e40c2c1SJason Zhu 							     PERM_ATTR_TOTAL_SIZE)) {
10992e40c2c1SJason Zhu 				printf("rk_avb_write_permanent_attributes error!\n");
11002e40c2c1SJason Zhu 				fastboot_tx_write_str("FAILread perm attr error");
11012e40c2c1SJason Zhu 				return;
11022e40c2c1SJason Zhu 			}
11032e40c2c1SJason Zhu 
11042e40c2c1SJason Zhu 			sha256_starts(&ctx);
11052e40c2c1SJason Zhu 			sha256_update(&ctx,
11062e40c2c1SJason Zhu 				      (const uint8_t *)perm_attr_temp,
11072e40c2c1SJason Zhu 				      PERM_ATTR_TOTAL_SIZE);
11082e40c2c1SJason Zhu 			sha256_finish(&ctx, digest);
11092e40c2c1SJason Zhu 			if (memcmp(digest, digest_temp, SHA256_SUM_LEN) == 0) {
11102e40c2c1SJason Zhu 				printf("The hash has been written!\n");
11112e40c2c1SJason Zhu 				fastboot_tx_write_str("OKAY");
11122e40c2c1SJason Zhu 				return;
11132e40c2c1SJason Zhu 			}
11142e40c2c1SJason Zhu 		}
11152e40c2c1SJason Zhu 
11162e40c2c1SJason Zhu 		if (rk_avb_write_perm_attr_flag(0)) {
11172e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILperm attr flag write failure");
11182e40c2c1SJason Zhu 			return;
11192e40c2c1SJason Zhu 		}
11202e40c2c1SJason Zhu 	}
11212e40c2c1SJason Zhu 
11222e40c2c1SJason Zhu 	if (rk_avb_write_permanent_attributes((uint8_t *)
11232e40c2c1SJason Zhu 					      CONFIG_FASTBOOT_BUF_ADDR,
11242e40c2c1SJason Zhu 					      download_bytes)) {
11252e40c2c1SJason Zhu 		if (rk_avb_write_perm_attr_flag(0)) {
11262e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILperm attr flag write failure");
11272e40c2c1SJason Zhu 			return;
11282e40c2c1SJason Zhu 		}
11292e40c2c1SJason Zhu 		fastboot_tx_write_str("FAILperm attr write failed");
11302e40c2c1SJason Zhu 		return;
11312e40c2c1SJason Zhu 	}
11322e40c2c1SJason Zhu 
11332e40c2c1SJason Zhu 	memset(digest, 0, SHA256_SUM_LEN);
11342e40c2c1SJason Zhu 	sha256_starts(&ctx);
11352e40c2c1SJason Zhu 	sha256_update(&ctx, (const uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
11362e40c2c1SJason Zhu 		      PERM_ATTR_TOTAL_SIZE);
11372e40c2c1SJason Zhu 	sha256_finish(&ctx, digest);
11382e40c2c1SJason Zhu 
11392e40c2c1SJason Zhu 	if (rk_avb_write_attribute_hash((uint8_t *)digest,
11402e40c2c1SJason Zhu 					SHA256_SUM_LEN)) {
11412e40c2c1SJason Zhu 		if (rk_avb_read_attribute_hash(digest_temp,
11422e40c2c1SJason Zhu 						SHA256_SUM_LEN)) {
11432e40c2c1SJason Zhu 			printf("The efuse IO can not be used!\n");
11442e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILefuse IO can not be used");
11452e40c2c1SJason Zhu 			return;
11462e40c2c1SJason Zhu 		}
11472e40c2c1SJason Zhu 		if (memcmp(digest, digest_temp, SHA256_SUM_LEN) != 0) {
11482e40c2c1SJason Zhu 			if (rk_avb_write_perm_attr_flag(0)) {
11492e40c2c1SJason Zhu 				fastboot_tx_write_str("FAILperm attr flag write failure");
11502e40c2c1SJason Zhu 				return;
11512e40c2c1SJason Zhu 			}
11522e40c2c1SJason Zhu 			printf("The hash has been written, but is different!\n");
11532e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILhash comparison failure");
11542e40c2c1SJason Zhu 			return;
11552e40c2c1SJason Zhu 		}
11562e40c2c1SJason Zhu 	}
11572e40c2c1SJason Zhu 
11582e40c2c1SJason Zhu 	if (rk_avb_write_perm_attr_flag(PERM_ATTR_SUCCESS_FLAG)) {
11592e40c2c1SJason Zhu 		fastboot_tx_write_str("FAILperm attr flag write failure");
11602e40c2c1SJason Zhu 		return;
11612e40c2c1SJason Zhu 	}
11622e40c2c1SJason Zhu 
11632e40c2c1SJason Zhu 	fastboot_tx_write_str("OKAY");
11642e40c2c1SJason Zhu #else
11652e40c2c1SJason Zhu 	fastboot_tx_write_str("FAILnot implemented");
11662e40c2c1SJason Zhu #endif
11672e40c2c1SJason Zhu }
11682e40c2c1SJason Zhu 
1169de195620SMichael Scott static void cb_oem(struct usb_ep *ep, struct usb_request *req)
1170de195620SMichael Scott {
1171de195620SMichael Scott 	char *cmd = req->buf;
1172367cce4dSXu Hongfei 
11734adef270SMaxime Ripard #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
1174372d7decSRob Herring 	if (strncmp("format", cmd + 4, 6) == 0) {
1175372d7decSRob Herring 		char cmdbuf[32];
1176372d7decSRob Herring 		sprintf(cmdbuf, "gpt write mmc %x $partitions",
1177372d7decSRob Herring 			CONFIG_FASTBOOT_FLASH_MMC_DEV);
1178372d7decSRob Herring 		if (run_command(cmdbuf, 0))
11792e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILmmc write failure");
1180372d7decSRob Herring 		else
1181372d7decSRob Herring 			fastboot_tx_write_str("OKAY");
1182372d7decSRob Herring 	} else
1183372d7decSRob Herring #endif
1184de195620SMichael Scott 	if (strncmp("unlock", cmd + 4, 8) == 0) {
118565413a00SJian Qiu #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
1186f61a997eSqiujian #ifdef CONFIG_RK_AVB_LIBAVB_USER
1187de195620SMichael Scott 		fastboot_tx_write_str("FAILnot implemented");
1188f61a997eSqiujian 		return;
1189f61a997eSqiujian #else
1190f61a997eSqiujian 		uint8_t unlock = 0;
1191f61a997eSqiujian 		TEEC_Result result;
1192f61a997eSqiujian 		debug("oem unlock\n");
1193f61a997eSqiujian 		result = trusty_read_oem_unlock(&unlock);
1194f61a997eSqiujian 		if (result) {
1195f61a997eSqiujian 			printf("read oem unlock status with error : 0x%x\n", result);
1196f61a997eSqiujian 			fastboot_tx_write_str("FAILRead oem unlock status failed");
1197f61a997eSqiujian 			return;
1198f61a997eSqiujian 		}
1199f61a997eSqiujian 		if (unlock) {
1200f61a997eSqiujian 			printf("oem unlock ignored, device already unlocked\n");
1201f61a997eSqiujian 			fastboot_tx_write_str("FAILalready unlocked");
1202f61a997eSqiujian 			return;
1203f61a997eSqiujian 		}
1204f61a997eSqiujian 		printf("oem unlock requested:\n");
1205f61a997eSqiujian 		printf("\tUnlocking forces a factory reset and could\n");
1206f61a997eSqiujian 		printf("\topen your device up to a world of hurt.  If you\n");
1207f61a997eSqiujian 		printf("\tare sure you know what you're doing, then accept\n");
1208f61a997eSqiujian 		printf("\tvia 'fastboot oem unlock_accept'.\n");
1209f61a997eSqiujian 		env_set("unlock", "unlock");
1210f61a997eSqiujian 		fastboot_tx_write_str("OKAY");
1211f61a997eSqiujian #endif
1212f61a997eSqiujian #else
1213f61a997eSqiujian 		fastboot_tx_write_str("FAILnot implemented");
1214f61a997eSqiujian 		return;
1215f61a997eSqiujian #endif
1216f61a997eSqiujian 	} else if (strncmp("unlock_accept", cmd + 4, 13) == 0) {
121765413a00SJian Qiu #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
1218f61a997eSqiujian #ifdef CONFIG_RK_AVB_LIBAVB_USER
1219f61a997eSqiujian 		fastboot_tx_write_str("FAILnot implemented");
1220f61a997eSqiujian 		return;
1221f61a997eSqiujian #else
1222f61a997eSqiujian 		char *unlock = env_get("unlock");
1223f61a997eSqiujian 		TEEC_Result result;
1224f61a997eSqiujian 		debug("oem unlock_accept\n");
1225f61a997eSqiujian 		if (unlock == NULL || strncmp("unlock", unlock, 6) != 0) {
1226f61a997eSqiujian 			printf("oem unlock_accept ignored, not pending\n");
1227f61a997eSqiujian 			fastboot_tx_write_str("FAILoem unlock not requested");
1228f61a997eSqiujian 			return;
1229f61a997eSqiujian 		}
1230f61a997eSqiujian 		env_set("unlock", "");
1231f61a997eSqiujian 		printf("Erasing userdata partition\n");
1232f61a997eSqiujian 		struct blk_desc *dev_desc;
1233f61a997eSqiujian 		disk_partition_t part_info;
1234f61a997eSqiujian 		dev_desc = rockchip_get_bootdev();
12356651d4c0SJason Zhu 		if (!dev_desc) {
12366651d4c0SJason Zhu 			printf("%s: dev_desc is NULL!\n", __func__);
12376651d4c0SJason Zhu 			return;
12386651d4c0SJason Zhu 		}
1239f61a997eSqiujian 		int ret = part_get_info_by_name(dev_desc, "userdata",
1240f61a997eSqiujian 				&part_info);
1241f61a997eSqiujian 		if (ret < 0) {
1242f61a997eSqiujian 			printf("not found userdata partition");
1243f61a997eSqiujian 			printf("Erase failed with error %d\n", ret);
1244f61a997eSqiujian 			fastboot_tx_write_str("FAILErasing userdata failed");
1245f61a997eSqiujian 			return;
1246f61a997eSqiujian 		}
1247f61a997eSqiujian 		ret = blk_derase(dev_desc, part_info.start, part_info.size);
1248f61a997eSqiujian 		if (ret != part_info.size) {
1249f61a997eSqiujian 			printf("Erase failed with error %d\n", ret);
1250f61a997eSqiujian 			fastboot_tx_write_str("FAILErasing userdata failed");
1251f61a997eSqiujian 			return;
1252f61a997eSqiujian 		}
1253f61a997eSqiujian 		printf("Erasing succeeded\n");
1254f61a997eSqiujian 
1255f61a997eSqiujian 		result = trusty_write_oem_unlock(1);
1256f61a997eSqiujian 		if (result) {
1257f61a997eSqiujian 			printf("write oem unlock status with error : 0x%x\n", result);
1258f61a997eSqiujian 			fastboot_tx_write_str("FAILWrite oem unlock status failed");
1259f61a997eSqiujian 			return;
1260f61a997eSqiujian 		}
1261f61a997eSqiujian 		fastboot_tx_write_str("OKAY");
1262f61a997eSqiujian 
1263f61a997eSqiujian 		/*
1264f61a997eSqiujian 		 * now reboot into recovery to do a format of the
1265f61a997eSqiujian 		 * userdata partition so it's ready to use on next boot
1266f61a997eSqiujian 		 */
1267f61a997eSqiujian 		board_run_recovery_wipe_data();
1268f61a997eSqiujian #endif
1269f61a997eSqiujian #else
1270f61a997eSqiujian 		fastboot_tx_write_str("FAILnot implemented");
1271f61a997eSqiujian 		return;
1272f61a997eSqiujian #endif
1273f61a997eSqiujian 	} else if (strncmp("lock", cmd + 4, 8) == 0) {
127465413a00SJian Qiu #ifdef CONFIG_FASTBOOT_OEM_UNLOCK
1275f61a997eSqiujian #ifdef CONFIG_RK_AVB_LIBAVB_USER
1276f61a997eSqiujian 		fastboot_tx_write_str("FAILnot implemented");
1277f61a997eSqiujian 		return;
1278f61a997eSqiujian #else
1279f61a997eSqiujian 		TEEC_Result result;
1280f61a997eSqiujian 		uint8_t unlock = 0;
1281f61a997eSqiujian 		trusty_read_oem_unlock(&unlock);
1282f61a997eSqiujian 		if (!unlock) {
1283f61a997eSqiujian 			printf("oem lock ignored, already locked\n");
1284f61a997eSqiujian 			fastboot_tx_write_str("FAILalready locked");
1285f61a997eSqiujian 			return;
1286f61a997eSqiujian 		}
1287f61a997eSqiujian 
1288f61a997eSqiujian 		result = trusty_write_oem_unlock(0);
1289f61a997eSqiujian 		if (result) {
1290f61a997eSqiujian 			printf("write oem unlock status with error : 0x%x\n", result);
1291f61a997eSqiujian 			fastboot_tx_write_str("FAILWrite oem unlock status failed");
1292f61a997eSqiujian 			return;
1293f61a997eSqiujian 		}
1294f61a997eSqiujian 		fastboot_tx_write_str("OKAY");
1295f61a997eSqiujian #endif
1296f61a997eSqiujian #else
1297f61a997eSqiujian 		fastboot_tx_write_str("FAILnot implemented");
1298f61a997eSqiujian 		return;
1299f61a997eSqiujian #endif
1300367cce4dSXu Hongfei 	} else if (strncmp("at-get-ca-request", cmd + 4, 17) == 0) {
13014d0fc665SAndy Ye #ifdef CONFIG_OPTEE_CLIENT
13022e40c2c1SJason Zhu 		uint8_t out[ATTEST_CA_OUT_SIZE];
13034d0fc665SAndy Ye 		uint32_t operation_size = download_bytes;
13042e40c2c1SJason Zhu 		uint32_t out_len = ATTEST_CA_OUT_SIZE;
13054d0fc665SAndy Ye 		uint32_t res = 0;
13062e40c2c1SJason Zhu 
13072e40c2c1SJason Zhu 		res = trusty_attest_get_ca((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
13082e40c2c1SJason Zhu 					   &operation_size, out, &out_len);
13094d0fc665SAndy Ye 		if (res) {
13104d0fc665SAndy Ye 			fastboot_tx_write_str("FAILtrusty_attest_get_ca failed");
13114d0fc665SAndy Ye 			return;
13124d0fc665SAndy Ye 		}
13134d0fc665SAndy Ye 		upload_size = out_len;
13144d0fc665SAndy Ye 		memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR, out, out_len);
1315367cce4dSXu Hongfei 		fastboot_tx_write_str("OKAY");
13164d0fc665SAndy Ye #else
13174d0fc665SAndy Ye 		fastboot_tx_write_str("FAILnot implemented");
13184d0fc665SAndy Ye 		return;
13194d0fc665SAndy Ye #endif
1320367cce4dSXu Hongfei 	} else if (strncmp("at-set-ca-response", cmd + 4, 18) == 0) {
13214d0fc665SAndy Ye #ifdef CONFIG_OPTEE_CLIENT
13224d0fc665SAndy Ye 		uint32_t ca_response_size = download_bytes;
13234d0fc665SAndy Ye 		uint32_t res = 0;
13242e40c2c1SJason Zhu 
13252e40c2c1SJason Zhu 		res = trusty_attest_set_ca((uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
13262e40c2c1SJason Zhu 					   &ca_response_size);
13272e40c2c1SJason Zhu 		if (res)
13284d0fc665SAndy Ye 			fastboot_tx_write_str("FAILtrusty_attest_set_ca failed");
13292e40c2c1SJason Zhu 		else
1330367cce4dSXu Hongfei 			fastboot_tx_write_str("OKAY");
13314d0fc665SAndy Ye #else
13324d0fc665SAndy Ye 		fastboot_tx_write_str("FAILnot implemented");
13334d0fc665SAndy Ye 		return;
13344d0fc665SAndy Ye #endif
133562b11485SJason Zhu 	} else if (strncmp("at-get-vboot-unlock-challenge", cmd + 4, 29) == 0) {
133662b11485SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
133762b11485SJason Zhu 		uint32_t challenge_len = 0;
133862b11485SJason Zhu 		int ret = 0;
133962b11485SJason Zhu 
134062b11485SJason Zhu 		ret = rk_generate_unlock_challenge((void *)CONFIG_FASTBOOT_BUF_ADDR, &challenge_len);
134162b11485SJason Zhu 		if (ret == 0) {
134262b11485SJason Zhu 			upload_size = challenge_len;
134362b11485SJason Zhu 			fastboot_tx_write_str("OKAY");
134462b11485SJason Zhu 		} else {
134562b11485SJason Zhu 			fastboot_tx_write_str("FAILgenerate unlock challenge fail!");
134662b11485SJason Zhu 		}
134762b11485SJason Zhu #else
134862b11485SJason Zhu 		fastboot_tx_write_str("FAILnot implemented");
134962b11485SJason Zhu 		return;
135062b11485SJason Zhu #endif
1351367cce4dSXu Hongfei 	} else if (strncmp("at-lock-vboot", cmd + 4, 13) == 0) {
135237a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
1353d8bd6e97SJason Zhu 		uint8_t lock_state;
1354d8bd6e97SJason Zhu 		lock_state = 0;
135537a7bc39SJason Zhu 		if (rk_avb_write_lock_state(lock_state))
13562e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILwrite lock state failed");
1357d8bd6e97SJason Zhu 		else
1358d8bd6e97SJason Zhu 			fastboot_tx_write_str("OKAY");
1359d8bd6e97SJason Zhu #else
1360367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
1361d8bd6e97SJason Zhu #endif
1362367cce4dSXu Hongfei 	} else if (strncmp("at-unlock-vboot", cmd + 4, 15) == 0) {
136337a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
1364d8bd6e97SJason Zhu 		uint8_t lock_state;
1365*46a8a269SJason Zhu 		bool out_is_trusted = true;
1366542316a9SJason Zhu 
136737a7bc39SJason Zhu 		if (rk_avb_read_lock_state(&lock_state))
13682e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILlock sate read failure");
1369d8bd6e97SJason Zhu 		if (lock_state >> 1 == 1) {
1370d8bd6e97SJason Zhu 			fastboot_tx_write_str("FAILThe vboot is disable!");
1371d8bd6e97SJason Zhu 		} else {
1372d8bd6e97SJason Zhu 			lock_state = 1;
1373*46a8a269SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_ENABLE_ATH_UNLOCK
1374542316a9SJason Zhu 			if (rk_auth_unlock((void *)CONFIG_FASTBOOT_BUF_ADDR,
1375542316a9SJason Zhu 					   &out_is_trusted)) {
1376542316a9SJason Zhu 				printf("rk_auth_unlock ops error!\n");
1377542316a9SJason Zhu 				fastboot_tx_write_str("FAILrk_auth_unlock ops error!");
1378542316a9SJason Zhu 				return;
1379542316a9SJason Zhu 			}
1380*46a8a269SJason Zhu #endif
1381542316a9SJason Zhu 			if (out_is_trusted == true) {
138237a7bc39SJason Zhu 				if (rk_avb_write_lock_state(lock_state))
13832e40c2c1SJason Zhu 					fastboot_tx_write_str("FAILwrite lock state failed");
1384d8bd6e97SJason Zhu 				else
1385d8bd6e97SJason Zhu 					fastboot_tx_write_str("OKAY");
1386542316a9SJason Zhu 			} else {
1387542316a9SJason Zhu 				fastboot_tx_write_str("FAILauthenticated unlock fail");
1388542316a9SJason Zhu 			}
1389d8bd6e97SJason Zhu 		}
1390d8bd6e97SJason Zhu #else
1391367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
1392d8bd6e97SJason Zhu #endif
1393367cce4dSXu Hongfei 	} else if (strncmp("at-disable-unlock-vboot", cmd + 4, 23) == 0) {
139437a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
1395d8bd6e97SJason Zhu 		uint8_t lock_state;
1396d8bd6e97SJason Zhu 		lock_state = 2;
139737a7bc39SJason Zhu 		if (rk_avb_write_lock_state(lock_state))
13982e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILwrite lock state failed");
1399d8bd6e97SJason Zhu 		else
1400d8bd6e97SJason Zhu 			fastboot_tx_write_str("OKAY");
1401d8bd6e97SJason Zhu #else
1402367cce4dSXu Hongfei 		fastboot_tx_write_str("FAILnot implemented");
1403d8bd6e97SJason Zhu #endif
1404367cce4dSXu Hongfei 	} else if (strncmp("fuse at-perm-attr", cmd + 4, 16) == 0) {
14052e40c2c1SJason Zhu 		cb_oem_perm_attr();
14064e1bbe84SJason Zhu 	} else if (strncmp("fuse at-bootloader-vboot-key", cmd + 4, 27) == 0) {
140737a7bc39SJason Zhu #ifdef CONFIG_RK_AVB_LIBAVB_USER
14082e40c2c1SJason Zhu 		sha256_context ctx;
14092e40c2c1SJason Zhu 		uint8_t digest[SHA256_SUM_LEN];
14102e40c2c1SJason Zhu 
14114e1bbe84SJason Zhu 		if (download_bytes != VBOOT_KEY_HASH_SIZE) {
14122e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILinvalid vboot key length");
14134e1bbe84SJason Zhu 			printf("The vboot key size error!\n");
14142e40c2c1SJason Zhu 			return;
14154e1bbe84SJason Zhu 		}
14164e1bbe84SJason Zhu 
14172e40c2c1SJason Zhu 		sha256_starts(&ctx);
14182e40c2c1SJason Zhu 		sha256_update(&ctx, (const uint8_t *)CONFIG_FASTBOOT_BUF_ADDR,
14192e40c2c1SJason Zhu 			      VBOOT_KEY_SIZE);
14202e40c2c1SJason Zhu 		sha256_finish(&ctx, digest);
14212e40c2c1SJason Zhu 
14222e40c2c1SJason Zhu 		if (rk_avb_write_vbootkey_hash((uint8_t *)digest,
14232e40c2c1SJason Zhu 					       SHA256_SUM_LEN)) {
14242e40c2c1SJason Zhu 			fastboot_tx_write_str("FAILvbootkey hash write failure");
14254e1bbe84SJason Zhu 			return;
14264e1bbe84SJason Zhu 		}
14274e1bbe84SJason Zhu 		fastboot_tx_write_str("OKAY");
14284e1bbe84SJason Zhu #else
14294e1bbe84SJason Zhu 		fastboot_tx_write_str("FAILnot implemented");
14304e1bbe84SJason Zhu #endif
1431367cce4dSXu Hongfei 	} else {
1432de195620SMichael Scott 		fastboot_tx_write_str("FAILunknown oem command");
1433de195620SMichael Scott 	}
1434de195620SMichael Scott }
1435de195620SMichael Scott 
143689792381SDileep Katta #ifdef CONFIG_FASTBOOT_FLASH
143789792381SDileep Katta static void cb_erase(struct usb_ep *ep, struct usb_request *req)
143889792381SDileep Katta {
143989792381SDileep Katta 	char *cmd = req->buf;
14403c8f98f5SMaxime Ripard 	char response[FASTBOOT_RESPONSE_LEN];
144189792381SDileep Katta 
144289792381SDileep Katta 	strsep(&cmd, ":");
144389792381SDileep Katta 	if (!cmd) {
144490aa625cSMasahiro Yamada 		pr_err("missing partition name");
144589792381SDileep Katta 		fastboot_tx_write_str("FAILmissing partition name");
144689792381SDileep Katta 		return;
144789792381SDileep Katta 	}
144889792381SDileep Katta 
14498b464fa9SJocelyn Bohr 	fastboot_fail("no flash device defined", response);
145089792381SDileep Katta #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
14518b464fa9SJocelyn Bohr 	fb_mmc_erase(cmd, response);
145289792381SDileep Katta #endif
1453bf8940d3SMaxime Ripard #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
14548b464fa9SJocelyn Bohr 	fb_nand_erase(cmd, response);
1455bf8940d3SMaxime Ripard #endif
145689792381SDileep Katta 	fastboot_tx_write_str(response);
145789792381SDileep Katta }
145889792381SDileep Katta #endif
145989792381SDileep Katta 
14603aab70afSSebastian Siewior struct cmd_dispatch_info {
14613aab70afSSebastian Siewior 	char *cmd;
14623aab70afSSebastian Siewior 	void (*cb)(struct usb_ep *ep, struct usb_request *req);
14633aab70afSSebastian Siewior };
14643aab70afSSebastian Siewior 
14653aab70afSSebastian Siewior static const struct cmd_dispatch_info cmd_dispatch_info[] = {
14663aab70afSSebastian Siewior 	{
14673aab70afSSebastian Siewior 		.cmd = "reboot",
14683aab70afSSebastian Siewior 		.cb = cb_reboot,
14693aab70afSSebastian Siewior 	}, {
14703aab70afSSebastian Siewior 		.cmd = "getvar:",
14713aab70afSSebastian Siewior 		.cb = cb_getvar,
14723aab70afSSebastian Siewior 	}, {
14733aab70afSSebastian Siewior 		.cmd = "download:",
14743aab70afSSebastian Siewior 		.cb = cb_download,
14753aab70afSSebastian Siewior 	}, {
1476367cce4dSXu Hongfei 		.cmd = "upload",
1477367cce4dSXu Hongfei 		.cb = cb_upload,
1478367cce4dSXu Hongfei 	}, {
14793aab70afSSebastian Siewior 		.cmd = "boot",
14803aab70afSSebastian Siewior 		.cb = cb_boot,
1481267abc62SRob Herring 	}, {
1482267abc62SRob Herring 		.cmd = "continue",
1483267abc62SRob Herring 		.cb = cb_continue,
1484367cce4dSXu Hongfei 	}, {
1485367cce4dSXu Hongfei 		.cmd = "set_active",
1486367cce4dSXu Hongfei 		.cb = cb_set_active,
14873aab70afSSebastian Siewior 	},
1488d1b5ed07SSteve Rae #ifdef CONFIG_FASTBOOT_FLASH
1489d1b5ed07SSteve Rae 	{
1490367cce4dSXu Hongfei 		.cmd = "flashing",
1491367cce4dSXu Hongfei 		.cb = cb_flashing,
1492367cce4dSXu Hongfei 	},
1493367cce4dSXu Hongfei 	{
1494d1b5ed07SSteve Rae 		.cmd = "flash",
1495d1b5ed07SSteve Rae 		.cb = cb_flash,
149689792381SDileep Katta 	}, {
149789792381SDileep Katta 		.cmd = "erase",
149889792381SDileep Katta 		.cb = cb_erase,
1499d1b5ed07SSteve Rae 	},
1500d1b5ed07SSteve Rae #endif
1501de195620SMichael Scott 	{
1502de195620SMichael Scott 		.cmd = "oem",
1503de195620SMichael Scott 		.cb = cb_oem,
1504de195620SMichael Scott 	},
15053aab70afSSebastian Siewior };
15063aab70afSSebastian Siewior 
15073aab70afSSebastian Siewior static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
15083aab70afSSebastian Siewior {
15093aab70afSSebastian Siewior 	char *cmdbuf = req->buf;
15103aab70afSSebastian Siewior 	void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
15113aab70afSSebastian Siewior 	int i;
15123aab70afSSebastian Siewior 
151394b385faSPaul Kocialkowski 	if (req->status != 0 || req->length == 0)
151494b385faSPaul Kocialkowski 		return;
151594b385faSPaul Kocialkowski 
15163aab70afSSebastian Siewior 	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
15173aab70afSSebastian Siewior 		if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
15183aab70afSSebastian Siewior 			func_cb = cmd_dispatch_info[i].cb;
15193aab70afSSebastian Siewior 			break;
15203aab70afSSebastian Siewior 		}
15213aab70afSSebastian Siewior 	}
15223aab70afSSebastian Siewior 
1523593cbd93SSteve Rae 	if (!func_cb) {
152490aa625cSMasahiro Yamada 		pr_err("unknown command: %.*s", req->actual, cmdbuf);
15253aab70afSSebastian Siewior 		fastboot_tx_write_str("FAILunknown command");
1526593cbd93SSteve Rae 	} else {
1527e2140588SEric Nelson 		if (req->actual < req->length) {
1528e2140588SEric Nelson 			u8 *buf = (u8 *)req->buf;
1529e2140588SEric Nelson 			buf[req->actual] = 0;
15303aab70afSSebastian Siewior 			func_cb(ep, req);
1531e2140588SEric Nelson 		} else {
153290aa625cSMasahiro Yamada 			pr_err("buffer overflow");
1533e2140588SEric Nelson 			fastboot_tx_write_str("FAILbuffer overflow");
1534e2140588SEric Nelson 		}
1535593cbd93SSteve Rae 	}
15363aab70afSSebastian Siewior 
15373aab70afSSebastian Siewior 	*cmdbuf = '\0';
15383aab70afSSebastian Siewior 	req->actual = 0;
15393aab70afSSebastian Siewior 	usb_ep_queue(ep, req, 0);
15403aab70afSSebastian Siewior }
1541