1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2008 - 2009 Windriver, <www.windriver.com>
4  * Author: Tom Rix <Tom.Rix@windriver.com>
5  *
6  * (C) Copyright 2014 Linaro, Ltd.
7  * Rob Herring <robh@kernel.org>
8  */
9 #include <common.h>
10 #include <command.h>
11 #include <console.h>
12 #include <g_dnl.h>
13 #include <fastboot.h>
14 #include <net.h>
15 #include <usb.h>
16 #include <watchdog.h>
17 #include <linux/stringify.h>
18 
do_fastboot_udp(int argc,char * const argv[],uintptr_t buf_addr,size_t buf_size)19 static int do_fastboot_udp(int argc, char *const argv[],
20 			   uintptr_t buf_addr, size_t buf_size)
21 {
22 #if CONFIG_IS_ENABLED(UDP_FUNCTION_FASTBOOT)
23 	int err = net_loop(FASTBOOT);
24 
25 	if (err < 0) {
26 		printf("fastboot udp error: %d\n", err);
27 		return CMD_RET_FAILURE;
28 	}
29 
30 	return CMD_RET_SUCCESS;
31 #else
32 	pr_err("Fastboot UDP not enabled\n");
33 	return CMD_RET_FAILURE;
34 #endif
35 }
36 
do_fastboot_usb(int argc,char * const argv[],uintptr_t buf_addr,size_t buf_size)37 static int do_fastboot_usb(int argc, char *const argv[],
38 			   uintptr_t buf_addr, size_t buf_size)
39 {
40 #if CONFIG_IS_ENABLED(USB_FUNCTION_FASTBOOT)
41 	int controller_index;
42 	char *usb_controller;
43 	char *endp;
44 	int ret;
45 
46 	if (argc < 2)
47 		return CMD_RET_USAGE;
48 
49 	usb_controller = argv[1];
50 	controller_index = simple_strtoul(usb_controller, &endp, 0);
51 	if (*endp != '\0') {
52 		pr_err("Error: Wrong USB controller index format\n");
53 		return CMD_RET_FAILURE;
54 	}
55 
56 	ret = usb_gadget_initialize(controller_index);
57 	if (ret) {
58 		pr_err("USB init failed: %d\n", ret);
59 		return CMD_RET_FAILURE;
60 	}
61 
62 	g_dnl_clear_detach();
63 	ret = g_dnl_register("usb_dnl_fastboot");
64 	if (ret)
65 		return ret;
66 
67 	if (!g_dnl_board_usb_cable_connected()) {
68 		puts("\rUSB cable not detected.\n" \
69 		     "Command exit.\n");
70 		ret = CMD_RET_FAILURE;
71 		goto exit;
72 	}
73 
74 	while (1) {
75 		if (g_dnl_detach())
76 			break;
77 		if (ctrlc())
78 			break;
79 		WATCHDOG_RESET();
80 		usb_gadget_handle_interrupts(controller_index);
81 	}
82 
83 	ret = CMD_RET_SUCCESS;
84 
85 exit:
86 	g_dnl_unregister();
87 	g_dnl_clear_detach();
88 	usb_gadget_release(controller_index);
89 
90 	return ret;
91 #else
92 	pr_err("Fastboot USB not enabled\n");
93 	return CMD_RET_FAILURE;
94 #endif
95 }
96 
do_fastboot(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])97 static int do_fastboot(struct cmd_tbl *cmdtp, int flag, int argc,
98 		       char *const argv[])
99 {
100 	uintptr_t buf_addr = (uintptr_t)NULL;
101 	size_t buf_size = 0;
102 
103 	if (argc < 2)
104 		return CMD_RET_USAGE;
105 
106 	while (argc > 1 && **(argv + 1) == '-') {
107 		char *arg = *++argv;
108 
109 		--argc;
110 		while (*++arg) {
111 			switch (*arg) {
112 			case 'l':
113 				if (--argc <= 0)
114 					return CMD_RET_USAGE;
115 				buf_addr = simple_strtoul(*++argv, NULL, 16);
116 				goto NXTARG;
117 
118 			case 's':
119 				if (--argc <= 0)
120 					return CMD_RET_USAGE;
121 				buf_size = simple_strtoul(*++argv, NULL, 16);
122 				goto NXTARG;
123 
124 			default:
125 				return CMD_RET_USAGE;
126 			}
127 		}
128 NXTARG:
129 		;
130 	}
131 
132 	/* Handle case when USB controller param is just '-' */
133 	if (argc == 1) {
134 		pr_err("Error: Incorrect USB controller index\n");
135 		return CMD_RET_USAGE;
136 	}
137 
138 	fastboot_init((void *)buf_addr, buf_size);
139 
140 	if (!strcmp(argv[1], "udp"))
141 		return do_fastboot_udp(argc, argv, buf_addr, buf_size);
142 
143 	if (!strcmp(argv[1], "usb")) {
144 		argv++;
145 		argc--;
146 	}
147 
148 	return do_fastboot_usb(argc, argv, buf_addr, buf_size);
149 }
150 
151 #ifdef CONFIG_SYS_LONGHELP
152 static char fastboot_help_text[] =
153 	"[-l addr] [-s size] usb <controller> | udp\n"
154 	"\taddr - address of buffer used during data transfers ("
155 	__stringify(CONFIG_FASTBOOT_BUF_ADDR) ")\n"
156 	"\tsize - size of buffer used during data transfers ("
157 	__stringify(CONFIG_FASTBOOT_BUF_SIZE) ")"
158 	;
159 #endif
160 
161 U_BOOT_CMD(
162 	fastboot, CONFIG_SYS_MAXARGS, 1, do_fastboot,
163 	"run as a fastboot usb or udp device", fastboot_help_text
164 );
165