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/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
index 0c9ced5..625f016 100644
--- a/drivers/fastboot/Kconfig
+++ b/drivers/fastboot/Kconfig
@@ -14,6 +14,13 @@
 	help
 	  This enables the USB part of the fastboot gadget.
 
+config UDP_FUNCTION_FASTBOOT
+	depends on NET
+	select FASTBOOT
+	bool "Enable fastboot protocol over UDP"
+	help
+	  This enables the fastboot protocol over UDP.
+
 if FASTBOOT
 
 config FASTBOOT_BUF_ADDR
diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile
index e4bd389..8831096 100644
--- a/drivers/fastboot/Makefile
+++ b/drivers/fastboot/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier:      GPL-2.0+
 
 obj-y += fb_common.o
-
+obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fb_getvar.o
+obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fb_command.o
 obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_mmc.o
 obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o
diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c
new file mode 100644
index 0000000..af4f500
--- /dev/null
+++ b/drivers/fastboot/fb_command.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include <common.h>
+#include <fastboot.h>
+#include <fastboot-internal.h>
+#include <fb_mmc.h>
+#include <fb_nand.h>
+#include <part.h>
+#include <stdlib.h>
+
+/**
+ * image_size - final fastboot image size
+ */
+static u32 image_size;
+
+/**
+ * fastboot_bytes_received - number of bytes received in the current download
+ */
+static u32 fastboot_bytes_received;
+
+/**
+ * fastboot_bytes_expected - number of bytes expected in the current download
+ */
+static u32 fastboot_bytes_expected;
+
+static void okay(char *, char *);
+static void getvar(char *, char *);
+static void download(char *, char *);
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+static void flash(char *, char *);
+static void erase(char *, char *);
+#endif
+static void reboot_bootloader(char *, char *);
+
+static const struct {
+	const char *command;
+	void (*dispatch)(char *cmd_parameter, char *response);
+} commands[FASTBOOT_COMMAND_COUNT] = {
+	[FASTBOOT_COMMAND_GETVAR] = {
+		.command = "getvar",
+		.dispatch = getvar
+	},
+	[FASTBOOT_COMMAND_DOWNLOAD] = {
+		.command = "download",
+		.dispatch = download
+	},
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+	[FASTBOOT_COMMAND_FLASH] =  {
+		.command = "flash",
+		.dispatch = flash
+	},
+	[FASTBOOT_COMMAND_ERASE] =  {
+		.command = "erase",
+		.dispatch = erase
+	},
+#endif
+	[FASTBOOT_COMMAND_BOOT] =  {
+		.command = "boot",
+		.dispatch = okay
+	},
+	[FASTBOOT_COMMAND_CONTINUE] =  {
+		.command = "continue",
+		.dispatch = okay
+	},
+	[FASTBOOT_COMMAND_REBOOT] =  {
+		.command = "reboot",
+		.dispatch = okay
+	},
+	[FASTBOOT_COMMAND_REBOOT_BOOTLOADER] =  {
+		.command = "reboot-bootloader",
+		.dispatch = reboot_bootloader
+	},
+	[FASTBOOT_COMMAND_SET_ACTIVE] =  {
+		.command = "set_active",
+		.dispatch = okay
+	},
+};
+
+/**
+ * fastboot_handle_command - Handle fastboot command
+ *
+ * @cmd_string: Pointer to command string
+ * @response: Pointer to fastboot response buffer
+ *
+ * Return: Executed command, or -1 if not recognized
+ */
+int fastboot_handle_command(char *cmd_string, char *response)
+{
+	int i;
+	char *cmd_parameter;
+
+	cmd_parameter = cmd_string;
+	strsep(&cmd_parameter, ":");
+
+	for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) {
+		if (!strcmp(commands[i].command, cmd_string)) {
+			if (commands[i].dispatch) {
+				commands[i].dispatch(cmd_parameter,
+							response);
+				return i;
+			} else {
+				break;
+			}
+		}
+	}
+
+	pr_err("command %s not recognized.\n", cmd_string);
+	fastboot_fail("unrecognized command", response);
+	return -1;
+}
+
+/**
+ * okay() - Send bare OKAY response
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ *
+ * Send a bare OKAY fastboot response. This is used where the command is
+ * valid, but all the work is done after the response has been sent (e.g.
+ * boot, reboot etc.)
+ */
+static void okay(char *cmd_parameter, char *response)
+{
+	fastboot_okay(NULL, response);
+}
+
+/**
+ * getvar() - Read a config/version variable
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void getvar(char *cmd_parameter, char *response)
+{
+	fastboot_getvar(cmd_parameter, response);
+}
+
+/**
+ * fastboot_download() - Start a download transfer from the client
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void download(char *cmd_parameter, char *response)
+{
+	char *tmp;
+
+	if (!cmd_parameter) {
+		fastboot_fail("Expected command parameter", response);
+		return;
+	}
+	fastboot_bytes_received = 0;
+	fastboot_bytes_expected = simple_strtoul(cmd_parameter, &tmp, 16);
+	if (fastboot_bytes_expected == 0) {
+		fastboot_fail("Expected nonzero image size", response);
+		return;
+	}
+	/*
+	 * Nothing to download yet. Response is of the form:
+	 * [DATA|FAIL]$cmd_parameter
+	 *
+	 * where cmd_parameter is an 8 digit hexadecimal number
+	 */
+	if (fastboot_bytes_expected > fastboot_buf_size) {
+		fastboot_fail(cmd_parameter, response);
+	} else {
+		printf("Starting download of %d bytes\n",
+		       fastboot_bytes_expected);
+		fastboot_response("DATA", response, "%s", cmd_parameter);
+	}
+}
+
+/**
+ * fastboot_data_remaining() - return bytes remaining in current transfer
+ *
+ * Return: Number of bytes left in the current download
+ */
+u32 fastboot_data_remaining(void)
+{
+	return fastboot_bytes_expected - fastboot_bytes_received;
+}
+
+/**
+ * fastboot_data_download() - Copy image data to fastboot_buf_addr.
+ *
+ * @fastboot_data: Pointer to received fastboot data
+ * @fastboot_data_len: Length of received fastboot data
+ * @response: Pointer to fastboot response buffer
+ *
+ * Copies image data from fastboot_data to fastboot_buf_addr. Writes to
+ * response. fastboot_bytes_received is updated to indicate the number
+ * of bytes that have been transferred.
+ *
+ * On completion sets image_size and ${filesize} to the total size of the
+ * downloaded image.
+ */
+void fastboot_data_download(const void *fastboot_data,
+			    unsigned int fastboot_data_len,
+			    char *response)
+{
+#define BYTES_PER_DOT	0x20000
+	u32 pre_dot_num, now_dot_num;
+
+	if (fastboot_data_len == 0 ||
+	    (fastboot_bytes_received + fastboot_data_len) >
+	    fastboot_bytes_expected) {
+		fastboot_fail("Received invalid data length",
+			      response);
+		return;
+	}
+	/* Download data to fastboot_buf_addr */
+	memcpy(fastboot_buf_addr + fastboot_bytes_received,
+	       fastboot_data, fastboot_data_len);
+
+	pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
+	fastboot_bytes_received += fastboot_data_len;
+	now_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
+
+	if (pre_dot_num != now_dot_num) {
+		putc('.');
+		if (!(now_dot_num % 74))
+			putc('\n');
+	}
+	*response = '\0';
+}
+
+/**
+ * fastboot_data_complete() - Mark current transfer complete
+ *
+ * @response: Pointer to fastboot response buffer
+ *
+ * Set image_size and ${filesize} to the total size of the downloaded image.
+ */
+void fastboot_data_complete(char *response)
+{
+	/* Download complete. Respond with "OKAY" */
+	fastboot_okay(NULL, response);
+	printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received);
+	image_size = fastboot_bytes_received;
+	env_set_hex("filesize", image_size);
+	fastboot_bytes_expected = 0;
+	fastboot_bytes_received = 0;
+}
+
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+/**
+ * flash() - write the downloaded image to the indicated partition.
+ *
+ * @cmd_parameter: Pointer to partition name
+ * @response: Pointer to fastboot response buffer
+ *
+ * Writes the previously downloaded image to the partition indicated by
+ * cmd_parameter. Writes to response.
+ */
+static void flash(char *cmd_parameter, char *response)
+{
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+	fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
+				 response);
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
+	fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size,
+				  response);
+#endif
+}
+
+/**
+ * erase() - erase the indicated partition.
+ *
+ * @cmd_parameter: Pointer to partition name
+ * @response: Pointer to fastboot response buffer
+ *
+ * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes
+ * to response.
+ */
+static void erase(char *cmd_parameter, char *response)
+{
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+	fastboot_mmc_erase(cmd_parameter, response);
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
+	fastboot_nand_erase(cmd_parameter, response);
+#endif
+}
+#endif
+
+/**
+ * reboot_bootloader() - Sets reboot bootloader flag.
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ */
+static void reboot_bootloader(char *cmd_parameter, char *response)
+{
+	if (fastboot_set_reboot_flag())
+		fastboot_fail("Cannot set reboot flag", response);
+	else
+		fastboot_okay(NULL, response);
+}
diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c
index 79e080a..c6e06aa 100644
--- a/drivers/fastboot/fb_common.c
+++ b/drivers/fastboot/fb_common.c
@@ -12,8 +12,24 @@
 
 #include <common.h>
 #include <fastboot.h>
+#include <net/fastboot.h>
 
 /**
+ * fastboot_buf_addr - base address of the fastboot download buffer
+ */
+void *fastboot_buf_addr;
+
+/**
+ * fastboot_buf_size - size of the fastboot download buffer
+ */
+u32 fastboot_buf_size;
+
+/**
+ * fastboot_progress_callback - callback executed during long operations
+ */
+void (*fastboot_progress_callback)(const char *msg);
+
+/**
  * fastboot_response() - Writes a response of the form "$tag$reason".
  *
  * @tag: The first part of the response
@@ -74,3 +90,80 @@
 {
 	return -ENOSYS;
 }
+
+/**
+ * fastboot_get_progress_callback() - Return progress callback
+ *
+ * Return: Pointer to function called during long operations
+ */
+void (*fastboot_get_progress_callback(void))(const char *)
+{
+	return fastboot_progress_callback;
+}
+
+/**
+ * fastboot_boot() - Execute fastboot boot command
+ *
+ * If ${fastboot_bootcmd} is set, run that command to execute the boot
+ * process, if that returns, then exit the fastboot server and return
+ * control to the caller.
+ *
+ * Otherwise execute "bootm <fastboot_buf_addr>", if that fails, reset
+ * the board.
+ */
+void fastboot_boot(void)
+{
+	char *s;
+
+	s = env_get("fastboot_bootcmd");
+	if (s) {
+		run_command(s, CMD_FLAG_ENV);
+	} else {
+		static char boot_addr_start[12];
+		static char *const bootm_args[] = {
+			"bootm", boot_addr_start, NULL
+		};
+
+		snprintf(boot_addr_start, sizeof(boot_addr_start) - 1,
+			 "0x%p", fastboot_buf_addr);
+		printf("Booting kernel at %s...\n\n\n", boot_addr_start);
+
+		do_bootm(NULL, 0, 2, bootm_args);
+
+		/*
+		 * This only happens if image is somehow faulty so we start
+		 * over. We deliberately leave this policy to the invocation
+		 * of fastbootcmd if that's what's being run
+		 */
+		do_reset(NULL, 0, 0, NULL);
+	}
+}
+
+/**
+ * fastboot_set_progress_callback() - set progress callback
+ *
+ * @progress: Pointer to progress callback
+ *
+ * Set a callback which is invoked periodically during long running operations
+ * (flash and erase). This can be used (for example) by the UDP transport to
+ * send INFO responses to keep the client alive whilst those commands are
+ * executing.
+ */
+void fastboot_set_progress_callback(void (*progress)(const char *msg))
+{
+	fastboot_progress_callback = progress;
+}
+
+/*
+ * fastboot_init() - initialise new fastboot protocol session
+ *
+ * @buf_addr: Pointer to download buffer, or NULL for default
+ * @buf_size: Size of download buffer, or zero for default
+ */
+void fastboot_init(void *buf_addr, u32 buf_size)
+{
+	fastboot_buf_addr = buf_addr ? buf_addr :
+				       (void *)CONFIG_FASTBOOT_BUF_ADDR;
+	fastboot_buf_size = buf_size ? buf_size : CONFIG_FASTBOOT_BUF_SIZE;
+	fastboot_set_progress_callback(NULL);
+}
diff --git a/drivers/fastboot/fb_getvar.c b/drivers/fastboot/fb_getvar.c
new file mode 100644
index 0000000..4d264c9
--- /dev/null
+++ b/drivers/fastboot/fb_getvar.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ */
+
+#include <common.h>
+#include <fastboot.h>
+#include <fastboot-internal.h>
+#include <fb_mmc.h>
+#include <fb_nand.h>
+#include <fs.h>
+#include <version.h>
+
+static void getvar_version(char *var_parameter, char *response);
+static void getvar_bootloader_version(char *var_parameter, char *response);
+static void getvar_downloadsize(char *var_parameter, char *response);
+static void getvar_serialno(char *var_parameter, char *response);
+static void getvar_version_baseband(char *var_parameter, char *response);
+static void getvar_product(char *var_parameter, char *response);
+static void getvar_current_slot(char *var_parameter, char *response);
+static void getvar_slot_suffixes(char *var_parameter, char *response);
+static void getvar_has_slot(char *var_parameter, char *response);
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+static void getvar_partition_type(char *part_name, char *response);
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+static void getvar_partition_size(char *part_name, char *response);
+#endif
+
+static const struct {
+	const char *variable;
+	void (*dispatch)(char *var_parameter, char *response);
+} getvar_dispatch[] = {
+	{
+		.variable = "version",
+		.dispatch = getvar_version
+	}, {
+		.variable = "bootloader-version",
+		.dispatch = getvar_bootloader_version
+	}, {
+		.variable = "version-bootloader",
+		.dispatch = getvar_bootloader_version
+	}, {
+		.variable = "downloadsize",
+		.dispatch = getvar_downloadsize
+	}, {
+		.variable = "max-download-size",
+		.dispatch = getvar_downloadsize
+	}, {
+		.variable = "serialno",
+		.dispatch = getvar_serialno
+	}, {
+		.variable = "version-baseband",
+		.dispatch = getvar_version_baseband
+	}, {
+		.variable = "product",
+		.dispatch = getvar_product
+	}, {
+		.variable = "current-slot",
+		.dispatch = getvar_current_slot
+	}, {
+		.variable = "slot-suffixes",
+		.dispatch = getvar_slot_suffixes
+	}, {
+		.variable = "has_slot",
+		.dispatch = getvar_has_slot
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+	}, {
+		.variable = "partition-type",
+		.dispatch = getvar_partition_type
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+	}, {
+		.variable = "partition-size",
+		.dispatch = getvar_partition_size
+#endif
+	}
+};
+
+static void getvar_version(char *var_parameter, char *response)
+{
+	fastboot_okay(FASTBOOT_VERSION, response);
+}
+
+static void getvar_bootloader_version(char *var_parameter, char *response)
+{
+	fastboot_okay(U_BOOT_VERSION, response);
+}
+
+static void getvar_downloadsize(char *var_parameter, char *response)
+{
+	fastboot_response("OKAY", response, "0x%08x", fastboot_buf_size);
+}
+
+static void getvar_serialno(char *var_parameter, char *response)
+{
+	const char *tmp = env_get("serial#");
+
+	if (tmp)
+		fastboot_okay(tmp, response);
+	else
+		fastboot_fail("Value not set", response);
+}
+
+static void getvar_version_baseband(char *var_parameter, char *response)
+{
+	fastboot_okay("N/A", response);
+}
+
+static void getvar_product(char *var_parameter, char *response)
+{
+	const char *board = env_get("board");
+
+	if (board)
+		fastboot_okay(board, response);
+	else
+		fastboot_fail("Board not set", response);
+}
+
+static void getvar_current_slot(char *var_parameter, char *response)
+{
+	/* A/B not implemented, for now always return _a */
+	fastboot_okay("_a", response);
+}
+
+static void getvar_slot_suffixes(char *var_parameter, char *response)
+{
+	fastboot_okay("_a,_b", response);
+}
+
+static void getvar_has_slot(char *part_name, char *response)
+{
+	if (part_name && (!strcmp(part_name, "boot") ||
+			  !strcmp(part_name, "system")))
+		fastboot_okay("yes", response);
+	else
+		fastboot_okay("no", response);
+}
+
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+static void getvar_partition_type(char *part_name, char *response)
+{
+	int r;
+	struct blk_desc *dev_desc;
+	disk_partition_t part_info;
+
+	r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info,
+				       response);
+	if (r >= 0) {
+		r = fs_set_blk_dev_with_part(dev_desc, r);
+		if (r < 0)
+			fastboot_fail("failed to set partition", response);
+		else
+			fastboot_okay(fs_get_type_name(), response);
+	}
+}
+#endif
+
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
+static void getvar_partition_size(char *part_name, char *response)
+{
+	int r;
+	size_t size;
+
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
+	struct blk_desc *dev_desc;
+	disk_partition_t part_info;
+
+	r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info,
+				       response);
+	if (r >= 0)
+		size = part_info.size;
+#endif
+#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
+	struct part_info *part_info;
+
+	r = fastboot_nand_get_part_info(part_name, &part_info, response);
+	if (r >= 0)
+		size = part_info->size;
+#endif
+	if (r >= 0)
+		fastboot_response("OKAY", response, "0x%016zx", size);
+}
+#endif
+
+/**
+ * fastboot_getvar() - Writes variable indicated by cmd_parameter to response.
+ *
+ * @cmd_parameter: Pointer to command parameter
+ * @response: Pointer to fastboot response buffer
+ *
+ * Look up cmd_parameter first as an environment variable of the form
+ * fastboot.<cmd_parameter>, if that exists return use its value to set
+ * response.
+ *
+ * Otherwise lookup the name of variable and execute the appropriate
+ * function to return the requested value.
+ */
+void fastboot_getvar(char *cmd_parameter, char *response)
+{
+	if (!cmd_parameter) {
+		fastboot_fail("missing var", response);
+	} else {
+#define FASTBOOT_ENV_PREFIX	"fastboot."
+		int i;
+		char *var_parameter = cmd_parameter;
+		char envstr[FASTBOOT_RESPONSE_LEN];
+		const char *s;
+
+		snprintf(envstr, sizeof(envstr) - 1,
+			 FASTBOOT_ENV_PREFIX "%s", cmd_parameter);
+		s = env_get(envstr);
+		if (s) {
+			fastboot_response("OKAY", response, "%s", s);
+			return;
+		}
+
+		strsep(&var_parameter, ":");
+		for (i = 0; i < ARRAY_SIZE(getvar_dispatch); ++i) {
+			if (!strcmp(getvar_dispatch[i].variable,
+				    cmd_parameter)) {
+				getvar_dispatch[i].dispatch(var_parameter,
+							    response);
+				return;
+			}
+		}
+		pr_warn("WARNING: unknown variable: %s\n", cmd_parameter);
+		fastboot_fail("Variable not implemented", response);
+	}
+}
diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c
index 47fcf74..4c1c7fd 100644
--- a/drivers/fastboot/fb_mmc.c
+++ b/drivers/fastboot/fb_mmc.c
@@ -7,6 +7,7 @@
 #include <common.h>
 #include <blk.h>
 #include <fastboot.h>
+#include <fastboot-internal.h>
 #include <fb_mmc.h>
 #include <image-sparse.h>
 #include <part.h>
@@ -15,6 +16,8 @@
 #include <linux/compat.h>
 #include <android_image.h>
 
+#define FASTBOOT_MAX_BLK_WRITE 16384
+
 #define BOOT_PARTITION_NAME "boot"
 
 struct fb_mmc_sparse {
@@ -43,13 +46,48 @@
 	return ret;
 }
 
+/**
+ * fb_mmc_blk_write() - Write/erase MMC in chunks of FASTBOOT_MAX_BLK_WRITE
+ *
+ * @block_dev: Pointer to block device
+ * @start: First block to write/erase
+ * @blkcnt: Count of blocks
+ * @buffer: Pointer to data buffer for write or NULL for erase
+ */
+static lbaint_t fb_mmc_blk_write(struct blk_desc *block_dev, lbaint_t start,
+				 lbaint_t blkcnt, const void *buffer)
+{
+	lbaint_t blk = start;
+	lbaint_t blks_written;
+	lbaint_t cur_blkcnt;
+	lbaint_t blks = 0;
+	int i;
+
+	for (i = 0; i < blkcnt; i += FASTBOOT_MAX_BLK_WRITE) {
+		cur_blkcnt = min((int)blkcnt - i, FASTBOOT_MAX_BLK_WRITE);
+		if (buffer) {
+			if (fastboot_progress_callback)
+				fastboot_progress_callback("writing");
+			blks_written = blk_dwrite(block_dev, blk, cur_blkcnt,
+						  buffer + (i * block_dev->blksz));
+		} else {
+			if (fastboot_progress_callback)
+				fastboot_progress_callback("erasing");
+			blks_written = blk_derase(block_dev, blk, cur_blkcnt);
+		}
+		blk += blks_written;
+		blks += blks_written;
+	}
+	return blks;
+}
+
 static lbaint_t fb_mmc_sparse_write(struct sparse_storage *info,
 		lbaint_t blk, lbaint_t blkcnt, const void *buffer)
 {
 	struct fb_mmc_sparse *sparse = info->priv;
 	struct blk_desc *dev_desc = sparse->dev_desc;
 
-	return blk_dwrite(dev_desc, blk, blkcnt, buffer);
+	return fb_mmc_blk_write(dev_desc, blk, blkcnt, buffer);
 }
 
 static lbaint_t fb_mmc_sparse_reserve(struct sparse_storage *info,
@@ -60,7 +98,7 @@
 
 static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info,
 		const char *part_name, void *buffer,
-		unsigned int download_bytes, char *response)
+		u32 download_bytes, char *response)
 {
 	lbaint_t blkcnt;
 	lbaint_t blks;
@@ -77,7 +115,8 @@
 
 	puts("Flashing Raw Image\n");
 
-	blks = blk_dwrite(dev_desc, info->start, blkcnt, buffer);
+	blks = fb_mmc_blk_write(dev_desc, info->start, blkcnt, buffer);
+
 	if (blks != blkcnt) {
 		pr_err("failed writing to device %d\n", dev_desc->devnum);
 		fastboot_fail("failed writing to device", response);
@@ -148,7 +187,7 @@
  */
 static int fb_mmc_update_zimage(struct blk_desc *dev_desc,
 				void *download_buffer,
-				unsigned int download_bytes,
+				u32 download_bytes,
 				char *response)
 {
 	uintptr_t hdr_addr;			/* boot image header address */
@@ -252,6 +291,38 @@
 #endif
 
 /**
+ * fastboot_mmc_get_part_info() - Lookup eMMC partion by name
+ *
+ * @part_name: Named partition to lookup
+ * @dev_desc: Pointer to returned blk_desc pointer
+ * @part_info: Pointer to returned disk_partition_t
+ * @response: Pointer to fastboot response buffer
+ */
+int fastboot_mmc_get_part_info(char *part_name, struct blk_desc **dev_desc,
+			       disk_partition_t *part_info, char *response)
+{
+	int r;
+
+	*dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
+	if (!*dev_desc) {
+		fastboot_fail("block device not found", response);
+		return -ENOENT;
+	}
+	if (!part_name) {
+		fastboot_fail("partition not found", response);
+		return -ENOENT;
+	}
+
+	r = part_get_info_by_name_or_alias(*dev_desc, part_name, part_info);
+	if (r < 0) {
+		fastboot_fail("partition not found", response);
+		return r;
+	}
+
+	return r;
+}
+
+/**
  * fastboot_mmc_flash_write() - Write image to eMMC for fastboot
  *
  * @cmd: Named partition to write image to
@@ -260,7 +331,7 @@
  * @response: Pointer to fastboot response buffer
  */
 void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
-			      unsigned int download_bytes, char *response)
+			      u32 download_bytes, char *response)
 {
 	struct blk_desc *dev_desc;
 	disk_partition_t info;
@@ -403,7 +474,8 @@
 	printf("Erasing blocks " LBAFU " to " LBAFU " due to alignment\n",
 	       blks_start, blks_start + blks_size);
 
-	blks = blk_derase(dev_desc, blks_start, blks_size);
+	blks = fb_mmc_blk_write(dev_desc, blks_start, blks_size, NULL);
+
 	if (blks != blks_size) {
 		pr_err("failed erasing from device %d\n", dev_desc->devnum);
 		fastboot_fail("failed erasing from device", response);
diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c
index 535f541..526bc12 100644
--- a/drivers/fastboot/fb_nand.c
+++ b/drivers/fastboot/fb_nand.c
@@ -88,7 +88,7 @@
 }
 
 static int _fb_nand_write(struct mtd_info *mtd, struct part_info *part,
-			  void *buffer, unsigned int offset,
+			  void *buffer, u32 offset,
 			  size_t length, size_t *written)
 {
 	int flags = WITH_WR_VERIFY;
@@ -146,6 +146,21 @@
 }
 
 /**
+ * fastboot_nand_get_part_info() - Lookup NAND partion by name
+ *
+ * @part_name: Named device to lookup
+ * @part_info: Pointer to returned part_info pointer
+ * @response: Pointer to fastboot response buffer
+ */
+int fastboot_nand_get_part_info(char *part_name, struct part_info **part_info,
+				char *response)
+{
+	struct mtd_info *mtd = NULL;
+
+	return fb_nand_lookup(part_name, &mtd, part_info, response);
+}
+
+/**
  * fastboot_nand_flash_write() - Write image to NAND for fastboot
  *
  * @cmd: Named device to write image to
@@ -154,7 +169,7 @@
  * @response: Pointer to fastboot response buffer
  */
 void fastboot_nand_flash_write(const char *cmd, void *download_buffer,
-			       unsigned int download_bytes, char *response)
+			       u32 download_bytes, char *response)
 {
 	struct part_info *part;
 	struct mtd_info *mtd = NULL;