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 <command.h>
10 #include <console.h>
11 #include <g_dnl.h>
12 #include <fastboot.h>
13 #include <net.h>
14 #include <usb.h>
15 #include <watchdog.h>
16 #include <linux/printk.h>
17 #include <linux/stringify.h>
18 
19 #if CONFIG_IS_ENABLED(NET)
do_fastboot_udp(int argc,char * const argv[],uintptr_t buf_addr,size_t buf_size)20 static int do_fastboot_udp(int argc, char *const argv[],
21 			   uintptr_t buf_addr, size_t buf_size)
22 {
23 	int err;
24 
25 	if (!IS_ENABLED(CONFIG_UDP_FUNCTION_FASTBOOT)) {
26 		pr_err("Fastboot UDP not enabled\n");
27 		return CMD_RET_FAILURE;
28 	}
29 
30 	err = net_loop(FASTBOOT_UDP);
31 
32 	if (err < 0) {
33 		printf("fastboot udp error: %d\n", err);
34 		return CMD_RET_FAILURE;
35 	}
36 
37 	return CMD_RET_SUCCESS;
38 }
39 
do_fastboot_tcp(int argc,char * const argv[],uintptr_t buf_addr,size_t buf_size)40 static int do_fastboot_tcp(int argc, char *const argv[],
41 			   uintptr_t buf_addr, size_t buf_size)
42 {
43 	int err;
44 
45 	if (!IS_ENABLED(CONFIG_TCP_FUNCTION_FASTBOOT)) {
46 		pr_err("Fastboot TCP not enabled\n");
47 		return CMD_RET_FAILURE;
48 	}
49 
50 	err = net_loop(FASTBOOT_TCP);
51 
52 	if (err < 0) {
53 		printf("fastboot tcp error: %d\n", err);
54 		return CMD_RET_FAILURE;
55 	}
56 
57 	return CMD_RET_SUCCESS;
58 }
59 #endif
60 
do_fastboot_usb(int argc,char * const argv[],uintptr_t buf_addr,size_t buf_size)61 static int do_fastboot_usb(int argc, char *const argv[],
62 			   uintptr_t buf_addr, size_t buf_size)
63 {
64 	int controller_index;
65 	char *usb_controller;
66 	struct udevice *udc;
67 	char *endp;
68 	int ret;
69 
70 	if (!IS_ENABLED(CONFIG_USB_FUNCTION_FASTBOOT)) {
71 		pr_err("Fastboot USB not enabled\n");
72 		return CMD_RET_FAILURE;
73 	}
74 
75 	if (argc < 2)
76 		return CMD_RET_USAGE;
77 
78 	usb_controller = argv[1];
79 	controller_index = simple_strtoul(usb_controller, &endp, 0);
80 	if (*endp != '\0') {
81 		pr_err("Error: Wrong USB controller index format\n");
82 		return CMD_RET_FAILURE;
83 	}
84 
85 	ret = udc_device_get_by_index(controller_index, &udc);
86 	if (ret) {
87 		pr_err("USB init failed: %d\n", ret);
88 		return CMD_RET_FAILURE;
89 	}
90 
91 	g_dnl_clear_detach();
92 	ret = g_dnl_register("usb_dnl_fastboot");
93 	if (ret)
94 		return ret;
95 
96 	if (!g_dnl_board_usb_cable_connected()) {
97 		puts("\rUSB cable not detected.\n" \
98 		     "Command exit.\n");
99 		ret = CMD_RET_FAILURE;
100 		goto exit;
101 	}
102 
103 	while (1) {
104 		if (g_dnl_detach())
105 			break;
106 		if (ctrlc())
107 			break;
108 		schedule();
109 		dm_usb_gadget_handle_interrupts(udc);
110 	}
111 
112 	ret = CMD_RET_SUCCESS;
113 
114 exit:
115 	udc_device_put(udc);
116 	g_dnl_unregister();
117 	g_dnl_clear_detach();
118 
119 	return ret;
120 }
121 
do_fastboot(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])122 static int do_fastboot(struct cmd_tbl *cmdtp, int flag, int argc,
123 		       char *const argv[])
124 {
125 	uintptr_t buf_addr = (uintptr_t)NULL;
126 	size_t buf_size = 0;
127 
128 	if (argc < 2)
129 		return CMD_RET_USAGE;
130 
131 	while (argc > 1 && **(argv + 1) == '-') {
132 		char *arg = *++argv;
133 
134 		--argc;
135 		while (*++arg) {
136 			switch (*arg) {
137 			case 'l':
138 				if (--argc <= 0)
139 					return CMD_RET_USAGE;
140 				buf_addr = hextoul(*++argv, NULL);
141 				goto NXTARG;
142 
143 			case 's':
144 				if (--argc <= 0)
145 					return CMD_RET_USAGE;
146 				buf_size = hextoul(*++argv, NULL);
147 				goto NXTARG;
148 
149 			default:
150 				return CMD_RET_USAGE;
151 			}
152 		}
153 NXTARG:
154 		;
155 	}
156 
157 	/* Handle case when USB controller param is just '-' */
158 	if (argc == 1) {
159 		pr_err("Error: Incorrect USB controller index\n");
160 		return CMD_RET_USAGE;
161 	}
162 
163 	fastboot_init((void *)buf_addr, buf_size);
164 
165 #if CONFIG_IS_ENABLED(NET)
166 	if (!strcmp(argv[1], "udp"))
167 		return do_fastboot_udp(argc, argv, buf_addr, buf_size);
168 	if (!strcmp(argv[1], "tcp"))
169 		return do_fastboot_tcp(argc, argv, buf_addr, buf_size);
170 #endif
171 	if (!strcmp(argv[1], "usb")) {
172 		argv++;
173 		argc--;
174 	}
175 
176 	return do_fastboot_usb(argc, argv, buf_addr, buf_size);
177 }
178 
179 U_BOOT_CMD(
180 	fastboot, CONFIG_SYS_MAXARGS, 1, do_fastboot,
181 	"run as a fastboot usb or udp device",
182 	"[-l addr] [-s size] usb <controller> | udp\n"
183 	"\taddr - address of buffer used during data transfers ("
184 	__stringify(CONFIG_FASTBOOT_BUF_ADDR) ")\n"
185 	"\tsize - size of buffer used during data transfers ("
186 	__stringify(CONFIG_FASTBOOT_BUF_SIZE) ")"
187 );
188