net: fastboot: Merge AOSP UDP fastboot

Merge UDP fastboot support from AOSP:

  https://android.googlesource.com/platform/external/u-boot/+/android-o-mr1-iot-preview-8

Signed-off-by: Alex Kiernan <alex.kiernan@gmail.com>
Signed-off-by: Alex Deymo <deymo@google.com>
Signed-off-by: Jocelyn Bohr <bohr@google.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 30cf63f..17ca0bb 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -655,8 +655,8 @@
 	  This enables the command "fastboot" which enables the Android
 	  fastboot mode for the platform. Fastboot is a protocol for
 	  downloading images, flashing and device control used on
-	  Android devices. Fastboot requires support for acting as a USB
-	  device.
+	  Android devices. Fastboot requires either the network stack
+	  enabled or support for acting as a USB device.
 
 	  See doc/README.android-fastboot for more information.
 
diff --git a/cmd/fastboot.c b/cmd/fastboot.c
index a5ec5f4..557257a 100644
--- a/cmd/fastboot.c
+++ b/cmd/fastboot.c
@@ -10,10 +10,32 @@
 #include <command.h>
 #include <console.h>
 #include <g_dnl.h>
+#include <fastboot.h>
+#include <net.h>
 #include <usb.h>
 
-static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+static int do_fastboot_udp(int argc, char *const argv[],
+			   uintptr_t buf_addr, size_t buf_size)
 {
+#if CONFIG_IS_ENABLED(UDP_FUNCTION_FASTBOOT)
+	int err = net_loop(FASTBOOT);
+
+	if (err < 0) {
+		printf("fastboot udp error: %d\n", err);
+		return CMD_RET_FAILURE;
+	}
+
+	return CMD_RET_SUCCESS;
+#else
+	pr_err("Fastboot UDP not enabled\n");
+	return CMD_RET_FAILURE;
+#endif
+}
+
+static int do_fastboot_usb(int argc, char *const argv[],
+			   uintptr_t buf_addr, size_t buf_size)
+{
+#if CONFIG_IS_ENABLED(USB_FUNCTION_FASTBOOT)
 	int controller_index;
 	char *usb_controller;
 	int ret;
@@ -58,11 +80,70 @@
 	board_usb_cleanup(controller_index, USB_INIT_DEVICE);
 
 	return ret;
+#else
+	pr_err("Fastboot USB not enabled\n");
+	return CMD_RET_FAILURE;
+#endif
 }
 
+static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	uintptr_t buf_addr = (uintptr_t)NULL;
+	size_t buf_size = 0;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	while (argc > 1 && **(argv + 1) == '-') {
+		char *arg = *++argv;
+
+		--argc;
+		while (*++arg) {
+			switch (*arg) {
+			case 'l':
+				if (--argc <= 0)
+					return CMD_RET_USAGE;
+				buf_addr = simple_strtoul(*++argv, NULL, 16);
+				goto NXTARG;
+
+			case 's':
+				if (--argc <= 0)
+					return CMD_RET_USAGE;
+				buf_size = simple_strtoul(*++argv, NULL, 16);
+				goto NXTARG;
+
+			default:
+				return CMD_RET_USAGE;
+			}
+		}
+NXTARG:
+		;
+	}
+
+	fastboot_init((void *)buf_addr, buf_size);
+
+	if (!strcmp(argv[1], "udp"))
+		return do_fastboot_udp(argc, argv, buf_addr, buf_size);
+
+	if (!strcmp(argv[1], "usb")) {
+		argv++;
+		argc--;
+	}
+
+	return do_fastboot_usb(argc, argv, buf_addr, buf_size);
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char fastboot_help_text[] =
+	"[-l addr] [-s size] usb <controller> | udp\n"
+	"\taddr - address of buffer used during data transfers ("
+	__stringify(CONFIG_FASTBOOT_BUF_ADDR) ")\n"
+	"\tsize - size of buffer used during data transfers ("
+	__stringify(CONFIG_FASTBOOT_BUF_SIZE) ")"
+	;
+#endif
+
 U_BOOT_CMD(
-	fastboot, 2, 1, do_fastboot,
-	"use USB Fastboot protocol",
-	"<USB_controller>\n"
-	"    - run as a fastboot usb device"
+	fastboot, CONFIG_SYS_MAXARGS, 1, do_fastboot,
+	"run as a fastboot usb or udp device", fastboot_help_text
 );