All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [ RFC ] fastboot protocol support in u-boot
@ 2011-08-10 18:07 Sebastian Andrzej Siewior
  2011-08-10 18:07 ` [U-Boot] [RFC] fastboot gadget support Sebastian Andrzej Siewior
  2011-08-16 14:47 ` [U-Boot] [ RFC ] fastboot protocol support in u-boot Stefan Schmidt
  0 siblings, 2 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2011-08-10 18:07 UTC (permalink / raw)
  To: u-boot

Hi,

The patch which should come as a reply to this email contains a fastboot
gadget for u-boot. I don't claim that the code has been tested or
anything. I just want to post what I have now and get some feedback on it.

The code uses the "newer" gadget API which is used by the rndis gadget for
instance. The only udc implementing it (as far as I know) is the at91 udc
sitting in cdc-at91 branch [0]. The other udcs in tree (musb for intance)
is using the old interface which is something linux kernel 2.4 time frame.
Since nobody plans to develop a udc for both frameworks I went for the newer
framework.
The gadget uses the same callbacks as the the at91 driver. It additionally
requires usb_gadget_init_udc() and usb_gadget_exit_udc() to be exported by
the driver. This is the ->probe() and ->exit() function from the kernel.
The at91 driver does this in its board-setup code which is something I
don't like.

The fastboot protocol is described in [1]. Let me give a short summary
based on the code I post (which is more or less clean up of [3]). It
implements the protocol with a few extensions:
- ep0 communication is only used for initial enumeration
- one EP-IN BULK and one EP-OUT BULK is required for the communication
  between host and device.
- the device waits until a command is sent by the host. This command is
  acknowledged (either as OKAY or FAIL).
- one command is "download:%08x". Here the Host specifies that it wants to
  send binary data. The gadget does _not_ know the purpose of the data, it
  has to suck it up. Once the transfer is complete the host sends another
  command like "flash:%s" which specifies where to write the earlier
  received data.
- the "boot" command is used to boot the image. The code right now uses the
  do_bootm() function. However the expected format is different from the
  uImage format:
  - it contains phys addr + size of kernel and ram disk.
  - it contains phys addr + size of "second". I don't know its purpose.
    Its user [2] is setting this to zero, the gadget code does not use it.
  - There is tags field. I assume that this are atags but it is also
    unused.
  - it contains a command line and a "name" of the image
  - after the "Android" header, the image follows.
- the "flash" command checks in case of the MMC media for the "sparse"
  header. It is implemented on per-board. Two types are currently
  implemented:
  - CHUNK_TYPE_DONT_CARE: don't not write this part to media
  - CHUNK_TYPE_RAW: write this part 1:1 to media
  A third type is defined only: CHUNK_TYPE_FILL. It looks like RLE i.e.
  avoid sending blocks of 0x00 over the wire but write it to the media.
- There is support for "oem" commands. The "format" sub command is
  passed to the board and creates a partition table on MMC.
  The second sub command is "recovery" which resets the board and starts
  linux from a recovery partition.
- commands "mmcerase" and "mmcwrite". Those seem to serve same purpose as
  "erase" and "flash" if the media is pointing to mmc except that the
  "sparse" case is not considered.
- partitions (name, offset) are loaded from board coded. This looks like
  EFI in [3].

This should list everything fastboot specific unless I forgot something.

One think that I don't like is the fact after "download:" we have have
suck up the complete data stream. An advantage would be if we could write
the data directly to flash/mmc. So we could have two buffers or so and
will USB and MMC/NAND one one buffer is complete.
Another thing is the custom sparse format. I would prefer to pipe the data
via lzo instead. This not only shrinks the amount of 0x00 blocks but also
compresses the data image which in case of MMC is mostly uncompressed.
The boot image format that is used by Andorid is different from uImage but
I don't see any advantages. AFAIK the uImage format is capable of
including kernel + ramdisk into one image.

I've been looking at DFU as an alternative. I think its main problem is
the fact that it is ep0 based which limits the USB packet size to 64bytes
on HighSpeed which makes it slower than necessary.

Given the amount of features we require and the complexity what about
implementing the whole gadget as a user space application with a
minimal root file system? We could have graphical output during the update
process instead some printf on serial line. Only an idea. Linux boots
actually quite fast so it shouldn't be an argument. This would also make
it easy to use ubiformat for nand upates in order not to lose the erase
counters. The userland approach would use same linux udc driver so we
wouldn't have two code basis for same driver which might grow apart.

So, any comments on that? Suggestions? Anything?
I would prefer a solution which is accepted by both projects Das U-Boot
and Android in terms of the protocol and approach (u-boot implementation
vs userland).

[0] git://git.denx.de/u-boot-usb.git
[1] http://android.git.kernel.org/?p=platform/bootloader/legacy.git;a=blob_plain;f=fastboot_protocol.txt;hb=d08c9e9444e2fb688ca4d3c4d807ba69c680fb3c
[2] http://android.git.kernel.org/?p=platform/system/core.git;a=tree;f=fastboot;h=1b8baa394459efbbef44e59c5a5494c2e3f37177;hb=810cf41b6d5b772846bbb16700f8c69f03710e60
[3] git://git.omapzoom.org/repo/u-boot.git

Sebastian

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [U-Boot] [RFC] fastboot gadget support
  2011-08-10 18:07 [U-Boot] [ RFC ] fastboot protocol support in u-boot Sebastian Andrzej Siewior
@ 2011-08-10 18:07 ` Sebastian Andrzej Siewior
  2011-08-13 10:22   ` Remy Bohmer
  2011-08-24 19:34   ` Remy Bohmer
  2011-08-16 14:47 ` [U-Boot] [ RFC ] fastboot protocol support in u-boot Stefan Schmidt
  1 sibling, 2 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2011-08-10 18:07 UTC (permalink / raw)
  To: u-boot

This is the faastboot gadget code based on
git://git.omapzoom.org/repo/u-boot.git as of commit 601ff71c8 including
a few changes. Some of them are:
- generic mmc framework
- "new" gadget framework
- different / easier command parsing
- booti command is missing

It was tested before it has been re-written. It is possible that it is
broken. It is posted for reference only not for merging.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 common/Makefile                 |    2 +
 common/cmd_fastboot.c           | 1334 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc3/fastboot_oem.c |    7 +
 drivers/usb/dwc3/misc.c         |   19 +
 drivers/usb/dwc3/sparse.c       |    8 +
 drivers/usb/gadget/Makefile     |    5 +
 drivers/usb/gadget/g_fastboot.c |  608 ++++++++++++++++++
 drivers/usb/gadget/misc.h       |   14 +
 include/linux/usb/ch9.h         |    1 +
 include/linux/usb/gadget.h      |    4 +
 include/usb/fastboot.h          |  340 ++++++++++
 include/usb/sparse.h            |   33 +
 include/usb/sparse_format.h     |   47 ++
 13 files changed, 2422 insertions(+), 0 deletions(-)
 create mode 100644 common/cmd_fastboot.c
 create mode 100644 drivers/usb/dwc3/fastboot_oem.c
 create mode 100644 drivers/usb/dwc3/misc.c
 create mode 100644 drivers/usb/dwc3/sparse.c
 create mode 100644 drivers/usb/gadget/g_fastboot.c
 create mode 100644 drivers/usb/gadget/misc.h
 create mode 100644 include/usb/fastboot.h
 create mode 100644 include/usb/sparse.h
 create mode 100644 include/usb/sparse_format.h

diff --git a/common/Makefile b/common/Makefile
index d662468..da40d64 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -157,6 +157,8 @@ COBJS-y += cmd_usb.o
 COBJS-y += usb.o
 COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o
 endif
+COBJS-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
+
 COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o
 COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o
 
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
new file mode 100644
index 0000000..263dd52
--- /dev/null
+++ b/common/cmd_fastboot.c
@@ -0,0 +1,1334 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Part of the rx_handler were copied from the Android project.
+ * Specifically rx command parsing in the  usb_rx_data_complete
+ * function of the file bootable/bootloader/legacy/usbloader/usbloader.c
+ *
+ * The logical naming of flash comes from the Android project
+ * Thse structures and functions that look like fastboot_flash_*
+ * They come from bootable/bootloader/legacy/libboot/flash.c
+ *
+ * This is their Copyright:
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <common.h>
+#include <command.h>
+#include <nand.h>
+#include <usb/fastboot.h>
+#include <usb/sparse.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <environment.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Use do_reset for fastboot's 'reboot' command */
+#ifndef CONFIG_GENERIC_MMC
+#error Generic MMC support is required
+#endif
+
+/* Forward decl */
+static void reset_handler (void);
+
+static struct cmd_fastboot_interface interface =
+{
+	.reset_handler         = reset_handler,
+	.product_name          = NULL,
+	.serial_no             = NULL,
+	.storage_medium        = 0,
+	.nand_block_size       = 0,
+	.transfer_buffer       = (unsigned char *)0xffffffff,
+	.transfer_buffer_size  = 0,
+};
+
+static unsigned int download_size;
+static unsigned int download_bytes;
+static unsigned int download_bytes_unpadded;
+static unsigned int download_error;
+static unsigned int current_mmc_controller_no = -1;
+
+extern cmd_tbl_t __u_boot_cmd_mmc;
+int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+static void set_mmc_controller(unsigned int num)
+{
+	char str_num[20];
+	char *argv[] = {
+		NULL,
+		"dev",
+		str_num,
+	};
+	int ret;
+
+	if (current_mmc_controller_no == num)
+		return;
+	sprintf(str_num, "%u\n", num);
+	ret = do_mmcops(&__u_boot_cmd_mmc, 0, 3, argv);
+	if (ret)
+		return;
+	current_mmc_controller_no = num;
+}
+
+static int do_mmc_read(u32 block, u32 count, void *addr)
+{
+	char str_block[20];
+	char str_count[20];
+	char str_addr[20];
+	char *argv[] = {
+		NULL,
+		"read",
+		str_block,
+		str_count,
+		str_addr,
+	};
+
+	sprintf(str_block, "%x", block);
+	sprintf(str_count, "%x", count);
+	sprintf(str_addr, "%p", addr);
+	return do_mmcops(&__u_boot_cmd_mmc, 0, 5, argv);
+}
+
+static int do_mmc_write(u32 block, u32 count, void *addr)
+{
+	char str_block[20];
+	char str_count[20];
+	char str_addr[20];
+	char *argv[] = {
+		NULL,
+		"write",
+		str_block,
+		str_count,
+		str_addr,
+	};
+
+	sprintf(str_block, "%x", block);
+	sprintf(str_count, "%x", count);
+	sprintf(str_addr, "%p", addr);
+	return do_mmcops(&__u_boot_cmd_mmc, 0, 5, argv);
+}
+
+static int do_mmc_erase(u32 block, u32 count)
+{
+	char str_block[20];
+	char str_count[20];
+	char *argv[] = {
+		NULL,
+		"erase",
+		str_block,
+		str_count,
+	};
+
+	sprintf(str_block, "%x", block);
+	sprintf(str_count, "%x", count);
+	return do_mmcops(&__u_boot_cmd_mmc, 0, 4, argv);
+}
+
+static void save_env(struct fastboot_ptentry *ptn,
+		     char *var, char *val)
+{
+	setenv(var, val);
+	saveenv();
+}
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size);
+
+static int fastboot_tx_write_str(const char *buffer)
+{
+	return fastboot_tx_write(buffer, strlen(buffer));
+}
+
+static void save_block_values(struct fastboot_ptentry *ptn,
+			      unsigned int offset,
+			      unsigned int size)
+{
+	char var[64], val[32];
+
+	printf ("saving it..\n");
+	if (size == 0) {
+		/* The error case, where the variables are being unset */
+
+		sprintf (var, "%s_nand_offset", ptn->name);
+		val[0] = '\0';
+		setenv(var, val);
+
+		sprintf (var, "%s_nand_size", ptn->name);
+		val[0] = '\0';
+		setenv(var, val);
+	} else {
+		/* Normal case */
+
+		sprintf (var, "%s_nand_offset", ptn->name);
+		sprintf (val, "0x%x", offset);
+		printf ("setenv %s %s\n", var, val);
+		setenv(var, val);
+
+		sprintf (var, "%s_nand_size", ptn->name);
+		sprintf (val, "0x%x", size);
+		printf ("setenv %s %s\n", var, val);
+		setenv(var, val);
+	}
+	saveenv();
+}
+
+static void reset_handler ()
+{
+	/* If there was a download going on, bail */
+	download_size = 0;
+	download_bytes = 0;
+	download_bytes_unpadded = 0;
+	download_error = 0;
+}
+
+/* When save = 0, just parse.  The input is unchanged
+   When save = 1, parse and do the save.  The input is changed */
+static int parse_env(void *ptn, char *err_string, int save, int debug)
+{
+	int ret = 1;
+	unsigned int sets = 0;
+	char *var = NULL;
+	char *var_end = NULL;
+	char *val = NULL;
+	char *val_end = NULL;
+	unsigned int i;
+
+	char *buff = (char *)interface.transfer_buffer;
+	unsigned int size = download_bytes_unpadded;
+
+	/* The input does not have to be null terminated.
+	   This will cause a problem in the corner case
+	   where the last line does not have a new line.
+	   Put a null after the end of the input.
+
+	   WARNING : Input buffer is assumed to be bigger
+	   than the size of the input */
+	if (save)
+		buff[size] = 0;
+
+	for (i = 0; i < size; i++) {
+		if (NULL == var) {
+			if (!((buff[i] == ' ') ||
+			      (buff[i] == '\t') ||
+			      (buff[i] == '\r') ||
+			      (buff[i] == '\n')))
+				var = &buff[i];
+		} else if (((NULL == var_end) || (NULL == val)) &&
+			   ((buff[i] == '\r') || (buff[i] == '\n'))) {
+
+			/* This is the case when a variable
+			   is unset. */
+
+			if (save) {
+				/* Set the var end to null so the
+				   normal string routines will work
+
+				   WARNING : This changes the input */
+				buff[i] = '\0';
+
+				save_env(ptn, var, val);
+
+				if (debug)
+					printf("Unsetting %s\n", var);
+			}
+
+			/* Clear the variable so state is parse is back
+			   to initial. */
+			var = NULL;
+			var_end = NULL;
+			sets++;
+		} else if (NULL == var_end) {
+			if ((buff[i] == ' ') ||
+			    (buff[i] == '\t'))
+				var_end = &buff[i];
+		} else if (NULL == val) {
+			if (!((buff[i] == ' ') ||
+			      (buff[i] == '\t')))
+				val = &buff[i];
+		} else if (NULL == val_end) {
+			if ((buff[i] == '\r') ||
+			    (buff[i] == '\n')) {
+				/* look for escaped cr or ln */
+				if ('\\' == buff[i - 1]) {
+					/* check for dos */
+					if ((buff[i] == '\r') &&
+					    (buff[i+1] == '\n'))
+						buff[i + 1] = ' ';
+					buff[i - 1] = buff[i] = ' ';
+				} else {
+					val_end = &buff[i];
+				}
+			}
+		} else {
+			sprintf(err_string, "Internal Error");
+
+			if (debug)
+				printf("Internal error at %s %d\n",
+				       __FILE__, __LINE__);
+			return 1;
+		}
+		/* Check if a var / val pair is ready */
+		if (NULL != val_end) {
+			if (save) {
+				/* Set the end's with nulls so
+				   normal string routines will
+				   work.
+
+				   WARNING : This changes the input */
+				*var_end = '\0';
+				*val_end = '\0';
+
+				save_env(ptn, var, val);
+
+				if (debug)
+					printf("Setting %s %s\n", var, val);
+			}
+
+			/* Clear the variable so state is parse is back
+			   to initial. */
+			var = NULL;
+			var_end = NULL;
+			val = NULL;
+			val_end = NULL;
+
+			sets++;
+		}
+	}
+
+	/* Corner case
+	   Check for the case that no newline@end of the input */
+	if ((NULL != var) &&
+	    (NULL == val_end)) {
+		if (save) {
+			/* case of val / val pair */
+			if (var_end)
+				*var_end = '\0';
+			/* else case handled by setting 0 past
+			   the end of buffer.
+			   Similar for val_end being null */
+			save_env(ptn, var, val);
+
+			if (debug) {
+				if (var_end)
+					printf("Trailing Setting %s %s\n", var, val);
+				else
+					printf("Trailing Unsetting %s\n", var);
+			}
+		}
+		sets++;
+	}
+	/* Did we set anything ? */
+	if (0 == sets)
+		sprintf(err_string, "No variables set");
+	else
+		ret = 0;
+
+	return ret;
+}
+
+static int saveenv_to_ptn(struct fastboot_ptentry *ptn, char *err_string)
+{
+	int ret = 1;
+	int save = 0;
+	int debug = 0;
+
+	/* err_string is only 32 bytes
+	   Initialize with a generic error message. */
+	sprintf(err_string, "%s", "Unknown Error");
+
+	/* Parse the input twice.
+	   Only save to the enviroment if the entire input if correct */
+	save = 0;
+	if (0 == parse_env(ptn, err_string, save, debug)) {
+		save = 1;
+		ret = parse_env(ptn, err_string, save, debug);
+	}
+	return ret;
+}
+
+static int write_to_ptn(struct fastboot_ptentry *ptn)
+{
+	int ret = 1;
+	char start[32], length[32];
+	char wstart[32], wlength[32], addr[32];
+	char ecc_type[32], write_type[32];
+	int repeat, repeat_max;
+
+	char *lock[5]   = { "nand", "lock",   NULL, NULL, NULL, };
+	char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL,	};
+	char *write[6]  = { "nand", "write",  NULL, NULL, NULL, NULL, };
+	char *ecc[4]    = { "nand", "ecc",    NULL, NULL, };
+	char *erase[5]  = { "nand", "erase",  NULL, NULL, NULL, };
+
+	lock[2] = unlock[2] = erase[2] = start;
+	lock[3] = unlock[3] = erase[3] = length;
+
+	write[1] = write_type;
+	write[2] = addr;
+	write[3] = wstart;
+	write[4] = wlength;
+
+	printf("flashing '%s'\n", ptn->name);
+
+	/* Which flavor of write to use */
+	if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_I)
+		sprintf(write_type, "write.i");
+#ifdef CFG_NAND_YAFFS_WRITE
+	else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS)
+		sprintf(write_type, "write.yaffs");
+#endif
+	else
+		sprintf(write_type, "write");
+
+
+	/* Some flashing requires the nand's ecc to be set */
+	ecc[2] = ecc_type;
+	if ((ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) &&
+	    (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)) {
+		/* Both can not be true */
+		printf("Warning can not do hw and sw ecc for partition '%s'\n",
+		       ptn->name);
+		printf("Ignoring these flags\n");
+	} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) {
+		sprintf(ecc_type, "hw");
+	} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
+		sprintf(ecc_type, "sw");
+	}
+
+	/* Some flashing requires writing the same data in multiple,
+	   consecutive flash partitions */
+	repeat_max = 1;
+	if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK) {
+		if (ptn->flags &
+		    FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) {
+			printf("Warning can not do both 'contiguous block' and 'repeat' writes for for partition '%s'\n", ptn->name);
+			printf("Ignoring repeat flag\n");
+		} else {
+			repeat_max = ptn->flags &
+				FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK;
+		}
+	}
+
+	/* Unlock the whole partition instead of trying to
+	   manage special cases */
+	sprintf(length, "0x%x", ptn->length * repeat_max);
+
+	for (repeat = 0; repeat < repeat_max; repeat++) {
+		sprintf(start, "0x%x", ptn->start + (repeat * ptn->length));
+
+		if ((ptn->flags &
+		     FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) &&
+		    (ptn->flags &
+		     FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK)) {
+			/* Both can not be true */
+			printf("Warning can not do 'next good block' and 'contiguous block' for partition '%s'\n", ptn->name);
+			printf("Ignoring these flags\n");
+		} else if (ptn->flags &
+			   FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) {
+			/* Keep writing until you get a good block
+			   transfer_buffer should already be aligned */
+			if (interface.nand_block_size) {
+				unsigned int blocks = download_bytes /
+					interface.nand_block_size;
+				unsigned int i = 0;
+				unsigned int offset = 0;
+
+				sprintf(wlength, "0x%x",
+					interface.nand_block_size);
+				while (i < blocks) {
+					/* Check for overflow */
+					if (offset >= ptn->length)
+						break;
+
+					/* download's address only advance
+					   if last write was successful */
+					sprintf(addr, "0x%p",
+						interface.transfer_buffer +
+						(i * interface.nand_block_size));
+
+					/* nand's address always advances */
+					sprintf(wstart, "0x%x",
+						ptn->start + (repeat * ptn->length) + offset);
+					if (ret)
+						break;
+					else
+						i++;
+
+					/* Go to next nand block */
+					offset += interface.nand_block_size;
+				}
+			} else {
+				printf("Warning nand block size can not be 0 when using 'next good block' for partition '%s'\n", ptn->name);
+				printf("Ignoring write request\n");
+			}
+		} else if (ptn->flags &
+			 FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) {
+		} else {
+			/* Normal case */
+			sprintf(addr,    "0x%p", interface.transfer_buffer);
+			sprintf(wstart,  "0x%x", ptn->start +
+				(repeat * ptn->length));
+			sprintf(wlength, "0x%x", download_bytes);
+#ifdef CFG_NAND_YAFFS_WRITE
+			if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS)
+				sprintf(wlength, "0x%x",
+					download_bytes_unpadded);
+#endif
+
+
+			if (0 == repeat) {
+				if (ret) /* failed */
+					save_block_values(ptn, 0, 0);
+				else     /* success */
+					save_block_values(ptn, ptn->start,
+							  download_bytes);
+			}
+		}
+
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static unsigned int rx_bytes_expected(void)
+{
+	int rx_remain = download_size - download_bytes;
+	if (rx_remain < 0)
+		return 0;
+	if (rx_remain > EP_OUT_BUFFER_SIZE)
+		return EP_OUT_BUFFER_SIZE;
+	return rx_remain;
+}
+
+static char boot_addr_start[32];
+static char *booti_args[4] = { "booti", NULL, "boot", NULL };
+
+static inline int do_booti (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	return do_bootm(cmdtp, flag, argc, argv);
+}
+
+static void do_booti_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	req->complete = NULL;
+	fastboot_shutdown();
+	printf("Booting kernel..\n");
+
+	/* boot the boot.img */
+	do_booti(NULL, 0, 3, booti_args);
+	/*
+	 * the alternative would be to re-init fastboot and start from the
+	 * beginning
+	 */
+	do_reset(NULL, 0, 0, NULL);
+}
+
+void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
+{
+	char response[65];
+	unsigned int transfer_size = download_size - download_bytes;
+	const unsigned char *buffer = req->buf;
+	unsigned int buffer_size = req->actual;
+
+	if (!buffer_size) {
+		/* Ignore empty buffers */
+		printf ("Warning empty download buffer\n");
+		printf ("Ignoring\n");
+		return;
+	}
+	/* Handle possible overflow */
+
+	if (buffer_size < transfer_size)
+		transfer_size = buffer_size;
+
+	/* Save the data to the transfer buffer */
+	memcpy(interface.transfer_buffer + download_bytes,
+			buffer, transfer_size);
+
+	download_bytes += transfer_size;
+
+	/* Check if transfer is done */
+	if (download_bytes >= download_size) {
+		/* Reset global transfer variable,
+		   Keep download_bytes because it will be
+		   used in the next possible flashing command */
+		download_size = 0;
+		req->complete = rx_handler_command;
+		req->length = EP_OUT_BUFFER_SIZE;
+
+		if (download_error) {
+			/* There was an earlier error */
+			sprintf(response, "ERROR");
+		} else {
+			/* Everything has transferred,
+			   send the OK response */
+			sprintf(response, "OKAY");
+		}
+		fastboot_tx_write_str(response);
+
+		printf ("\ndownloading of %d bytes finished\n",
+				download_bytes);
+
+		/* Padding is required only if storage medium is NAND */
+		if (interface.storage_medium == NAND) {
+			/* Pad to block length
+			   In most cases, padding the download to be
+			   block aligned is correct. The exception is
+			   when the following flash writes to the oob
+			   area.  This happens when the image is a
+			   YAFFS image.  Since we do not know what
+			   the download is until it is flashed,
+			   go ahead and pad it, but save the true
+			   size in case if should have
+			   been unpadded */
+			download_bytes_unpadded = download_bytes;
+			if (interface.nand_block_size)
+			{
+				if (download_bytes %
+						interface.nand_block_size)
+				{
+					unsigned int pad = interface.nand_block_size - (download_bytes % interface.nand_block_size);
+					unsigned int i;
+
+					for (i = 0; i < pad; i++)
+					{
+						if (download_bytes >= interface.transfer_buffer_size)
+							break;
+
+						interface.transfer_buffer[download_bytes] = 0;
+						download_bytes++;
+					}
+				}
+			}
+		}
+	} else
+		req->length = rx_bytes_expected();
+
+	/* Provide some feedback */
+	if (download_bytes &&
+			0 == (download_bytes %
+				(16 * interface.nand_block_size)))
+	{
+		/* Some feeback that the
+		   download is happening */
+		if (download_error)
+			printf("X");
+		else
+			printf(".");
+		if (0 == (download_bytes %
+					(80 * 16 *
+					 interface.nand_block_size)))
+			printf("\n");
+
+	}
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
+
+static void compl_reboot_bootloader(struct usb_ep *ep, struct usb_request *req)
+{
+	/* Clear all reset reasons */
+	//__raw_writel(0xfff, PRM_RSTST);
+
+	//strcpy(PUBLIC_SAR_RAM_1_FREE, "reboot-bootloader");
+
+	/* now warm reset the silicon */
+	//__raw_writel(PRM_RSTCTRL_RESET_WARM_BIT, PRM_RSTCTRL);
+	printf("bootloader reset\n");
+	reset_cpu(0);
+}
+
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+	do_reset(NULL, 0, 0, NULL);
+}
+
+static void compl_do_recovery(struct usb_ep *ep, struct usb_request *req)
+{
+	printf("%s()\n", __func__);
+	/* Clear all reset reasons */
+	//__raw_writel(0xfff, PRM_RSTST);
+	//strcpy(PUBLIC_SAR_RAM_1_FREE, "recovery");
+	/* now warm reset the silicon */
+	//__raw_writel(PRM_RSTCTRL_RESET_WARM_BIT,
+	//	PRM_RSTCTRL);
+	/* Never returns */
+	while (1)
+		;
+}
+
+static void cb_reboot_bootloader(struct usb_ep *ep, struct usb_request *req)
+{
+	req_in->complete = compl_reboot_bootloader;
+	fastboot_tx_write_str("OKAY");
+}
+
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
+{
+	req_in->complete = compl_do_reset;
+	fastboot_tx_write_str("OKAY");
+}
+
+static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
+{
+	/* getvar
+	   Get common fastboot variables
+	   Board has a chance to handle other variables */
+	char *cmd = req->buf;
+	char response[65];
+
+	strcpy(response,"OKAY");
+	strsep(&cmd, ":");
+	if (!cmd) {
+		fastboot_tx_write_str("FAILmissing var");
+		return;
+	}
+
+	if(!strcmp(cmd, "version")) {
+		strncat(response, FASTBOOT_VERSION, sizeof(response));
+
+	} else if(!strcmp(cmd, "product")) {
+		if (interface.product_name)
+			strncat(response, interface.product_name, sizeof(response));
+		else
+			strcpy(response, "FAILproduct not set");
+
+	} else if(!strcmp(cmd, "serialno")) {
+		if (interface.serial_no)
+			strncat(response, interface.serial_no, sizeof(response));
+		else
+			strcpy(response, "FAILserialno not set");
+
+	} else if(!strcmp(cmd, "downloadsize")) {
+		char str_num[12];
+
+		sprintf(str_num, "%08x", interface.transfer_buffer_size);
+		strncat(response, str_num, sizeof(response));
+
+	} else if(!strcmp(cmd, "cpurev")) {
+		if (interface.proc_rev)
+			strncat(response, interface.proc_rev, sizeof(response));
+		else
+			strcpy(response, "FAILcpurev not set");
+	} else if(!strcmp(cmd, "secure")) {
+		if (interface.proc_type)
+			strncat(response, interface.proc_type, sizeof(response));
+		else
+			strcpy(response, "FAILsecure not set");
+	} else {
+		fastboot_getvar(cmd, response);
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void cb_oem(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[65];
+
+	strcpy(response,"OKAY");
+	strsep(&cmd, " ");
+
+	/* fastboot oem format */
+	if(memcmp(cmd, "format", 6) == 0){
+		int ret;
+
+		ret = fastboot_oem(cmd);
+		if (ret < 0) {
+			strcpy(response,"FAIL");
+		} else {
+			strcpy(response,"OKAY");
+		}
+
+	} else if(memcmp(cmd, "recovery", 8) == 0){
+		/* fastboot oem recovery */
+
+		sprintf(response,"OKAY");
+		req_in->complete = compl_do_recovery;
+
+	} else if(memcmp(cmd, "unlock", 6) == 0) {
+		/* fastboot oem unlock */
+
+		sprintf(response,"FAILnot implemented");
+		printf("\nfastboot: oem unlock not implemented yet!!\n");
+	} else {
+		printf("\nfastboot: do not understand oem %s\n", cmd);
+		strcpy(response,"FAILunknown command");
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void cb_erase(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[65];
+
+	/* erase
+	 * Erase a register flash partition
+	 * Board has to set up flash partitions
+	 */
+	strsep(&cmd, ":");
+
+	if (interface.storage_medium == NAND) {
+		/* storage medium is NAND */
+
+		struct fastboot_ptentry *ptn;
+
+		ptn = fastboot_flash_find_ptn(cmd);
+		if (ptn == 0)
+		{
+			sprintf(response, "FAILpartition does not exist");
+		}
+		else
+		{
+			char start[32], length[32];
+			int status = 0, repeat, repeat_max;
+
+			printf("erasing '%s'\n", ptn->name);
+
+			char *lock[5]   = { "nand", "lock",   NULL, NULL, NULL, };
+			char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL,	};
+			char *erase[5]  = { "nand", "erase",  NULL, NULL, NULL, };
+
+			lock[2] = unlock[2] = erase[2] = start;
+			lock[3] = unlock[3] = erase[3] = length;
+
+			repeat_max = 1;
+			if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK)
+				repeat_max = ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK;
+
+			sprintf (length, "0x%x", ptn->length);
+			for (repeat = 0; repeat < repeat_max; repeat++)
+			{
+				sprintf (start, "0x%x", ptn->start + (repeat * ptn->length));
+
+				if (status)
+					break;
+			}
+
+			if (status)
+			{
+				sprintf(response, "FAILfailed to erase partition");
+			}
+			else
+			{
+				printf("partition '%s' erased\n", ptn->name);
+				sprintf(response, "OKAY");
+			}
+		}
+	} else if (interface.storage_medium == EMMC) {
+		/* storage medium is EMMC */
+
+		struct fastboot_ptentry *ptn;
+
+		/* Save the MMC controller number */
+#if  defined(CONFIG_4430PANDA)
+		/* panda board does not have eMMC on mmc1 */
+		set_mmc_controller(0);
+#else
+		/* blaze has emmc on mmc1 */
+		set_mmc_controller(1);
+#endif
+
+		/* Find the partition and erase it */
+		ptn = fastboot_flash_find_ptn(cmd);
+
+		if (ptn == 0) {
+			sprintf(response,
+					"FAIL: partition doesn't exist");
+		} else {
+			printf("Erasing '%s'\n", ptn->name);
+			if (do_mmc_erase(ptn->start, ptn->length)) {
+				printf("Erasing '%s' FAILED!\n", ptn->name);
+				sprintf(response, "FAIL: Erase partition");
+			} else {
+				printf("Erasing '%s' DONE!\n", ptn->name);
+				sprintf(response, "OKAY");
+			}
+		}
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void cb_mmcerase(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fastboot_ptentry *ptn;
+	char *cmd = req->buf;
+	char response[65];
+	int mmc_no;
+
+	/* EMMC Erase
+	 * Erase a register flash partition on MMC
+	 * Board has to set up flash partitions
+	 */
+	strsep(&cmd, ":");
+
+	/* Save the MMC controller number */
+	mmc_no = simple_strtoul(cmd, NULL, 10);
+	set_mmc_controller(mmc_no);
+	/* Find the partition and erase it */
+	strsep(&cmd, " ");
+	ptn = fastboot_flash_find_ptn(cmd);
+
+	if (ptn == 0) {
+		sprintf(response,
+				"FAIL: partition doesn't exist");
+	} else {
+		/* Call MMC erase function here */
+		/* This is not complete */
+
+		printf("Erasing '%s'\n", ptn->name);
+		if (do_mmc_erase(ptn->start, ptn->length)) {
+			sprintf(response, "FAIL: Erase partition");
+		} else {
+			sprintf(response, "OKAY");
+		}
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void cb_download(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[65];
+	/*
+	 * download something ..
+	 * What happens to it depends on the next command after data
+	 */
+
+	strsep(&cmd, ":");
+	/* save the size */
+	download_size = simple_strtoul(cmd, NULL, 16);
+	/* Reset the bytes count, now it is safe */
+	download_bytes = 0;
+	/* Reset error */
+	download_error = 0;
+
+	printf("Starting download of %d bytes\n",
+			download_size);
+
+	if (0 == download_size) {
+		/* bad user input */
+		sprintf(response, "FAILdata invalid size");
+	} else if (download_size >
+			interface.transfer_buffer_size)
+	{
+		/* set download_size to 0
+		 * because this is an error */
+		download_size = 0;
+		sprintf(response, "FAILdata too large");
+	} else {
+		/* The default case, the transfer fits
+		   completely in the interface buffer */
+		sprintf(response, "DATA%08x", download_size);
+		req->complete = rx_handler_dl_image;
+		req->length = rx_bytes_expected();
+	}
+	fastboot_tx_write_str(response);
+}
+
+static void cb_boot(struct usb_ep *ep, struct usb_request *req)
+{
+	/* boot
+	   boot what was downloaded
+	 **
+	 ** +-----------------+
+	 ** | boot header     | 1 page
+	 ** +-----------------+
+	 ** | kernel          | n pages
+	 ** +-----------------+
+	 ** | ramdisk         | m pages
+	 ** +-----------------+
+	 ** | second stage    | o pages
+	 ** +-----------------+
+	 **
+	 Pagesize has default value of
+	 CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE
+	 */
+
+	if ((download_bytes) &&
+			(CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE < download_bytes))
+	{
+
+		/* Skip the mkbootimage header */
+		//boot_img_hdr*hdr =
+		//	(boot_img_hdr *)
+		//	&interface.transfer_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE];
+
+		booti_args[1] = boot_addr_start;
+		sprintf(boot_addr_start, "0x%p", interface.transfer_buffer);
+
+		req_in->complete = do_booti_on_complete;
+		/* Execution should jump to kernel so send the response
+		   now and wait a bit.  */
+		fastboot_tx_write_str("OKAY");
+		return;
+	}
+	fastboot_tx_write_str("FAILinvalid boot image");
+}
+
+static void cb_mmcwrite(struct usb_ep *ep, struct usb_request *req)
+{
+	struct fastboot_ptentry *ptn;
+	char *cmd = req->buf;
+	u32 mmc_no;
+
+	/* mmcwrite
+	   write what was downloaded on MMC*/
+	/* Write to MMC whatever was downloaded */
+
+	if (!download_bytes) {
+		fastboot_tx_write_str("FAILno image downloaded");
+		return;
+	}
+
+	/* Save the MMC controller number */
+	strsep(&cmd, ":");
+	mmc_no = simple_strtoul(cmd, NULL, 10);
+	set_mmc_controller(mmc_no);
+
+	/* Next is the partition name */
+	strsep(&cmd, " ");
+	ptn = fastboot_flash_find_ptn(cmd);
+
+	if (ptn == 0) {
+		fastboot_tx_write_str("FAILpartition does not exist");
+		return;
+	}
+
+	printf("writing to partition '%s'\n", ptn->name);
+	if (do_mmc_write(ptn->start, download_bytes, interface.transfer_buffer))
+		fastboot_tx_write_str("FAIL: Write partition");
+	else
+		fastboot_tx_write_str("OKAY");
+}
+
+static void cb_flash(struct usb_ep *ep, struct usb_request *req)
+{
+	char *cmd = req->buf;
+	char response[64];
+
+	/* flash
+	   Flash what was downloaded */
+	strsep(&cmd, ":");
+
+	if (interface.storage_medium == NAND) {
+		/* storage medium is NAND */
+
+		if (download_bytes)
+		{
+			struct fastboot_ptentry *ptn;
+
+			ptn = fastboot_flash_find_ptn(cmd);
+			if (ptn == 0) {
+				sprintf(response, "FAILpartition does not exist");
+			} else if ((download_bytes > ptn->length) &&
+					!(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
+				sprintf(response, "FAILimage too large for partition");
+				/* TODO : Improve check for yaffs write */
+			} else {
+				/* Check if this is not really a flash write
+				   but rather a saveenv */
+				if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
+					/* Since the response can only be 64 bytes,
+					   there is no point in having a large error message. */
+					char err_string[32];
+					if (saveenv_to_ptn(ptn, &err_string[0])) {
+						printf("savenv '%s' failed : %s\n", ptn->name, err_string);
+						sprintf(response, "FAIL%s", err_string);
+					} else {
+						printf("partition '%s' saveenv-ed\n", ptn->name);
+						sprintf(response, "OKAY");
+					}
+				} else {
+					/* Normal case */
+					if (write_to_ptn(ptn)) {
+						printf("flashing '%s' failed\n", ptn->name);
+						sprintf(response, "FAILfailed to flash partition");
+					} else {
+						printf("partition '%s' flashed\n", ptn->name);
+						sprintf(response, "OKAY");
+					}
+				}
+			}
+		}
+		else
+		{
+			sprintf(response, "FAILno image downloaded");
+		}
+	} else if (interface.storage_medium == EMMC) {
+		/* storage medium is EMMC */
+
+		if (download_bytes) {
+
+			struct fastboot_ptentry *ptn;
+
+			/* Save the MMC controller number */
+#if  defined(CONFIG_4430PANDA)
+			/* panda board does not have eMMC on mmc1 */
+			set_mmc_controller(0);
+#else
+			/* blaze has emmc on mmc1 */
+			set_mmc_controller(1);
+#endif
+
+			/* Next is the partition name */
+			ptn = fastboot_flash_find_ptn(cmd);
+
+			if (ptn == 0) {
+				printf("Partition:'%s' does not exist\n", ptn->name);
+				sprintf(response, "FAILpartition does not exist");
+			} else if ((download_bytes > ptn->length) &&
+					!(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
+				printf("Image too large for the partition\n");
+				sprintf(response, "FAILimage too large for partition");
+
+			} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
+
+				if (himport_r(&env_htab, (char *)interface.transfer_buffer, ENV_SIZE, '\0', 0)) {
+					gd->flags |= GD_FLG_ENV_READY;
+					saveenv();
+					printf("saveenv to '%s' DONE!\n", ptn->name);
+					sprintf(response, "OKAY");
+				}
+			} else {
+				/* Normal case */
+
+				printf("writing to partition '%s'\n", ptn->name);
+
+				/* Check if we have sparse compressed image */
+				if ( ((sparse_header_t *)interface.transfer_buffer)->magic
+						== SPARSE_HEADER_MAGIC) {
+					printf("fastboot: %s is in sparse format\n", ptn->name);
+					if (!do_unsparse(interface.transfer_buffer,
+								ptn->start,
+								ptn->length,
+								current_mmc_controller_no)) {
+						printf("Writing sparsed: '%s' DONE!\n", ptn->name);
+					} else {
+						printf("Writing sparsed '%s' FAILED!\n", ptn->name);
+						sprintf(response, "FAIL: Sparsed Write");
+					}
+				} else {
+					/* Normal image: no sparse */
+					printf("Writing '%s'\n", ptn->name);
+					if (do_mmc_write(ptn->start, download_bytes, interface.transfer_buffer)) {
+						printf("Writing '%s' FAILED!\n", ptn->name);
+						sprintf(response, "FAIL: Write partition");
+					} else {
+						printf("Writing '%s' DONE!\n", ptn->name);
+					}
+				}
+			} /* Normal Case */
+
+		} else {
+			sprintf(response, "FAILno image downloaded");
+		}
+	} /* EMMC */
+	fastboot_tx_write_str(response);
+}
+
+struct cmd_dispatch_info {
+	char *cmd;
+	void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+
+static struct cmd_dispatch_info cmd_dispatch_info[] = {
+	{
+		.cmd = "reboot-bootloader",
+		.cb = cb_reboot_bootloader,
+	}, {
+		.cmd = "reboot",
+		.cb = cb_reboot,
+	}, {
+		.cmd = "getvar:",
+		.cb = cb_getvar,
+	}, {
+		.cmd = "oem ",
+		.cb = cb_oem,
+	}, {
+		.cmd = "erase:",
+		.cb = cb_erase,
+	}, {
+		.cmd = "mmcerase:",
+		.cb = cb_mmcerase,
+	}, {
+		.cmd = "download:",
+		.cb = cb_download,
+	}, {
+		.cmd = "boot",
+		.cb = cb_boot,
+	}, {
+		.cmd = "mmcwrite:",
+		.cb = cb_mmcwrite,
+	}, {
+		.cmd = "flash:",
+		.cb = cb_flash,
+	},
+};
+
+void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
+{
+	/* Use 65 instead of 64
+	   null gets dropped
+	   strcpy's need the extra byte */
+	char response[65];
+	/* A command */
+	const char *cmdbuf = req->buf;
+	void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
+	int i;
+
+	/* Generic failed response */
+	sprintf(response, "FAIL");
+
+	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
+		if (!memcmp(cmdbuf, cmd_dispatch_info[i].cmd, strlen(cmd_dispatch_info[i].cmd))) {
+			func_cb = cmd_dispatch_info[i].cb;
+			break;
+		}
+	}
+
+	if (!func_cb) {
+		fastboot_tx_write_str("FAIL: unknown command");
+	} else {
+		func_cb(ep, req);
+	}
+	req->actual = 0;
+	usb_ep_queue(ep, req, 0);
+}
+
+int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	int ret = 1;
+
+	/* Initialize the board specific support */
+	if (!fastboot_init(&interface))
+	{
+		printf ("Fastboot entered...\n");
+
+		/* If we got this far, we are a success */
+		ret = 0;
+
+		/* On disconnect or error, polling returns non zero */
+		while (1)
+		{
+			if (fastboot_poll())
+				break;
+		}
+	}
+
+	/* Reset the board specific support */
+	fastboot_shutdown();
+
+	return ret;
+}
+
+U_BOOT_CMD(
+	fastboot,	1,	1,	do_fastboot,
+	"fastboot- use USB Fastboot protocol\n",
+	""
+);
+
+/* To support the Android-style naming of flash */
+#define MAX_PTN 16
+
+static fastboot_ptentry ptable[MAX_PTN];
+static unsigned int pcount = 0;
+
+void fastboot_flash_reset_ptn(void)
+{
+	pcount = 0;
+}
+
+void fastboot_flash_add_ptn(fastboot_ptentry *ptn)
+{
+    if(pcount < MAX_PTN){
+        memcpy(ptable + pcount, ptn, sizeof(*ptn));
+        pcount++;
+    }
+}
+
+void fastboot_flash_dump_ptn(void)
+{
+    unsigned int n;
+    for(n = 0; n < pcount; n++) {
+        fastboot_ptentry *ptn = ptable + n;
+        printf("ptn %d name='%s' start=%d len=%d\n",
+                n, ptn->name, ptn->start, ptn->length);
+    }
+}
+
+
+fastboot_ptentry *fastboot_flash_find_ptn(const char *name)
+{
+    unsigned int n;
+
+    for(n = 0; n < pcount; n++) {
+	    /* Make sure a substring is not accepted */
+	    if (strlen(name) == strlen(ptable[n].name))
+	    {
+		    if(0 == strcmp(ptable[n].name, name))
+			    return ptable + n;
+	    }
+    }
+    return 0;
+}
+
+fastboot_ptentry *fastboot_flash_get_ptn(unsigned int n)
+{
+    if(n < pcount) {
+        return ptable + n;
+    } else {
+        return 0;
+    }
+}
+
+unsigned int fastboot_flash_get_ptn_count(void)
+{
+    return pcount;
+}
diff --git a/drivers/usb/dwc3/fastboot_oem.c b/drivers/usb/dwc3/fastboot_oem.c
new file mode 100644
index 0000000..4974b7d
--- /dev/null
+++ b/drivers/usb/dwc3/fastboot_oem.c
@@ -0,0 +1,7 @@
+#include <common.h>
+#include <usb/fastboot.h>
+
+int fastboot_oem(const char *cmd)
+{
+	return -1;
+}
diff --git a/drivers/usb/dwc3/misc.c b/drivers/usb/dwc3/misc.c
new file mode 100644
index 0000000..346e42d
--- /dev/null
+++ b/drivers/usb/dwc3/misc.c
@@ -0,0 +1,19 @@
+#include <common.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "misc.h"
+
+int snprintf(char *buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i = vsprintf(buf, fmt, args);
+	va_end(args);
+	if (i > size)
+		printf("*** Wrote too much bytes into the buffer ***\n");
+	return i;
+}
diff --git a/drivers/usb/dwc3/sparse.c b/drivers/usb/dwc3/sparse.c
new file mode 100644
index 0000000..387f8ce
--- /dev/null
+++ b/drivers/usb/dwc3/sparse.c
@@ -0,0 +1,8 @@
+#include <common.h>
+#include <usb/fastboot.h>
+
+u8 do_unsparse(unsigned char *source, u32 sector, u32 section_size, int slot_no)
+{
+	printf("%s() unsupported\n", __func__);
+	return 1;
+}
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 7d5b504..80e5e5b 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -42,6 +42,11 @@ COBJS-$(CONFIG_SPEARUDC) += spr_udc.o
 endif
 endif
 
+ifdef CONFIG_CMD_FASTBOOT
+COBJS-$(CONFIG_CMD_FASTBOOT) += g_fastboot.o
+COBJS-y += epautoconf.o
+endif
+
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
diff --git a/drivers/usb/gadget/g_fastboot.c b/drivers/usb/gadget/g_fastboot.c
new file mode 100644
index 0000000..ea60cc2
--- /dev/null
+++ b/drivers/usb/gadget/g_fastboot.c
@@ -0,0 +1,608 @@
+#include <common.h>
+#include <errno.h>
+#include <usb/fastboot.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "misc.h"
+
+#ifdef USB_EP_DESC_USE_AUDIO
+#error Can not deal with the two extra bytes right now
+#endif
+
+#define CONFIGURATION_NORMAL      1
+#define BULK_ENDPOINT 1
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0  (0x0200)
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1  (0x0040)
+/* upgrade to HS? */
+#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE      (0x0040)
+
+#define DEVICE_STRING_PRODUCT_INDEX		1
+#define DEVICE_STRING_SERIAL_NUMBER_INDEX	2
+#define DEVICE_STRING_CONFIG_INDEX		3
+#define DEVICE_STRING_INTERFACE_INDEX		4
+#define DEVICE_STRING_MANUFACTURER_INDEX	5
+#define DEVICE_STRING_PROC_REVISION		6
+#define DEVICE_STRING_PROC_TYPE			7
+#define DEVICE_STRING_MAX_INDEX			DEVICE_STRING_PROC_TYPE
+#define DEVICE_STRING_LANGUAGE_ID		0x0409 /* English (United States) */
+
+unsigned int dwc3_cable_connected = 1;
+
+static u8 ep0_buffer[4096] __aligned(16);
+static u8 ep_out_buffer[EP_OUT_BUFFER_SIZE] __aligned(16);
+static u8 ep_in_buffer[4096] __aligned(16);
+static char *device_strings[DEVICE_STRING_MAX_INDEX + 1];
+static struct cmd_fastboot_interface *fastboot_interface;
+static int current_config;
+
+/* e1 */
+static struct usb_endpoint_descriptor fs_ep_in = {
+	.bLength            = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType    = USB_DT_ENDPOINT,
+	.bEndpointAddress   = USB_DIR_IN, /* IN */
+	.bmAttributes       = USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize     = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
+	.bInterval          = 0x00,
+};
+
+/* e2 */
+static struct usb_endpoint_descriptor fs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT, /* OUT */
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
+	.bInterval		= 0x00,
+};
+
+static struct usb_endpoint_descriptor hs_ep_out = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT, /* OUT */
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
+	.bInterval		= 0x00,
+};
+
+int fastboot_preboot(void)
+{
+	printf("\n%s() is always off\n", __func__);
+	return 0;
+}
+
+static struct usb_gadget *g;
+static struct usb_request *ep0_req;
+
+struct usb_ep *ep_in;
+struct usb_request *req_in;
+
+struct usb_ep *ep_out;
+struct usb_request *req_out;
+
+static void fastboot_ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+
+	if (!status)
+		return;
+	printf("%s() ep %s status %d\n", __func__, ep->name, status);
+}
+
+static int fastboot_bind(struct usb_gadget *gadget)
+{
+
+	g = gadget;
+	ep0_req = usb_ep_alloc_request(g->ep0, GFP_KERNEL);
+	if (!ep0_req)
+		goto err;
+	ep0_req->buf = ep0_buffer;
+	ep0_req->complete = fastboot_ep0_complete;
+
+	ep_in = usb_ep_autoconfig(gadget, &fs_ep_in);
+	if (!ep_in)
+		goto err;
+	ep_in->driver_data = ep_in;
+
+	ep_out = usb_ep_autoconfig(gadget, &fs_ep_out);
+	if (!ep_out)
+		goto err;
+	ep_out->driver_data = ep_out;
+
+	hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+	return 0;
+err:
+	return -1;
+}
+
+static void fastboot_unbind(struct usb_gadget *gadget)
+{
+	printf("%s\n", __func__);
+	usb_ep_free_request(g->ep0, ep0_req);
+	ep_in->driver_data = NULL;
+	ep_out->driver_data = NULL;
+}
+
+/* This is the TI USB vendor id */
+#define DEVICE_VENDOR_ID  0x0451
+/* This is just made up.. */
+#define DEVICE_PRODUCT_ID 0xd022
+/* This is just made up.. */
+#define DEVICE_BCD        0x0100
+
+struct usb_device_descriptor fb_descriptor = {
+	.bDescriptorType    = USB_DT_DEVICE,
+#ifdef CONFIG_USB_1_1_DEVICE
+	.bcdUSB             = 0x110,
+#else
+	.bcdUSB             = 0x200,
+#endif
+	.bDeviceClass       = 0x00,
+	.bDeviceSubClass    = 0x00,
+	.bDeviceProtocol    = 0x00,
+	.bMaxPacketSize0    = 0x40,
+	.idVendor           = DEVICE_VENDOR_ID,
+	.idProduct          = DEVICE_PRODUCT_ID,
+	.bcdDevice          = DEVICE_BCD,
+	.iManufacturer      = DEVICE_STRING_MANUFACTURER_INDEX,
+	.iProduct           = DEVICE_STRING_PRODUCT_INDEX,
+	.iSerialNumber      = DEVICE_STRING_SERIAL_NUMBER_INDEX,
+	.bNumConfigurations = 1,
+};
+
+struct fast_boot_config {
+	struct usb_config_descriptor c;
+	struct usb_interface_descriptor i;
+	struct usb_endpoint_descriptor e1;
+	struct usb_endpoint_descriptor e2;
+} __attribute__((packed));
+
+static struct fast_boot_config g_config;
+static int fastboot_setup_get_descr(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	struct usb_qualifier_descriptor d;
+	u16 w_value	= le16_to_cpu(ctrl->wValue);
+	u16 w_length	= le16_to_cpu(ctrl->wLength);
+	u16 val;
+	int ret;
+	unsigned char bytes_remaining;
+	unsigned char bytes_total;
+	unsigned char bLength;
+	unsigned char string_index;
+	u8 this_inc;
+
+	val = w_value >> 8;
+
+	switch (val) {
+		case USB_DT_DEVICE:
+
+			fb_descriptor.bLength = sizeof(fb_descriptor);
+			memcpy(ep0_buffer, &fb_descriptor, fb_descriptor.bLength);
+			ep0_req->length = min(w_length, sizeof(fb_descriptor));
+			ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+			break;
+
+		case USB_DT_CONFIG:
+
+			bytes_remaining = w_length;
+			bytes_total = 0;
+
+			g_config.c.bLength             = sizeof(struct usb_config_descriptor);
+			g_config.c.bDescriptorType     = USB_DT_CONFIG;
+			/* Set this to the total we want */
+			g_config.c.wTotalLength	= cpu_to_le16(sizeof(g_config));
+			g_config.c.bNumInterfaces	= 1;
+			g_config.c.bConfigurationValue	= CONFIGURATION_NORMAL;
+			g_config.c.iConfiguration	= DEVICE_STRING_CONFIG_INDEX;
+			g_config.c.bmAttributes		= 0xc0;
+			g_config.c.bMaxPower		= 0x32;
+
+			this_inc = min(bytes_remaining, sizeof(struct usb_config_descriptor));
+			bytes_remaining -= this_inc;
+			bytes_total += this_inc;
+
+			g_config.i.bLength		= sizeof(struct usb_interface_descriptor);
+			g_config.i.bDescriptorType	= USB_DT_INTERFACE;
+			g_config.i.bInterfaceNumber	= 0x00;
+			g_config.i.bAlternateSetting	= 0x00;
+			g_config.i.bNumEndpoints	= 0x02;
+			g_config.i.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS;
+			g_config.i.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS;
+			g_config.i.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL;
+			g_config.i.iInterface		= DEVICE_STRING_INTERFACE_INDEX;
+
+			this_inc = min(bytes_remaining, sizeof(struct usb_interface_descriptor));
+			bytes_remaining -= this_inc;
+			bytes_total += this_inc;
+
+			g_config.e1 = fs_ep_in;
+
+			this_inc = min(bytes_remaining, USB_DT_ENDPOINT_SIZE);
+			bytes_remaining -= this_inc;
+			bytes_total += this_inc;
+
+			if (gadget->speed == USB_SPEED_HIGH)
+				g_config.e2 = hs_ep_out;
+			else
+				g_config.e2 = fs_ep_out;
+
+			this_inc = min(bytes_remaining, USB_DT_ENDPOINT_SIZE);
+			bytes_remaining -= this_inc;
+			bytes_total += this_inc;
+
+			memcpy(ep0_buffer, &g_config, bytes_total);
+
+			ep0_req->length = bytes_total;
+			ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+			break;
+
+		case USB_DT_STRING:
+
+			string_index = w_value & 0xff;
+
+                         if (string_index > DEVICE_STRING_MAX_INDEX) {
+
+				 printf("%s(%d)\n", __func__, __LINE__);
+
+			 } else if (string_index == 0) {
+
+                                 /* Language ID */
+				 bLength = min(4, w_length);
+
+                                 ep0_buffer[0] = 4;        /* length */
+                                 ep0_buffer[1] = USB_DT_STRING;  /* descriptor = string */
+                                 ep0_buffer[2] = DEVICE_STRING_LANGUAGE_ID & 0xff;
+                                 ep0_buffer[3] = DEVICE_STRING_LANGUAGE_ID >> 8;
+
+				 ep0_req->length = bLength;
+				 ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+			 } else {
+				 unsigned char s;
+				 unsigned char sl = strlen(&device_strings[string_index][0]);
+
+                                 /* Size of string in chars */
+                                 /* Size of descriptor
+                                    1    : header
+                                    2    : type
+                                    2*sl : string */
+                                 unsigned char sLength = 2 + (2 * sl);
+                                 unsigned char bLength;
+                                 bLength = min(sLength, w_length);
+
+                                 ep0_buffer[0] = sLength;        /* length */
+                                 ep0_buffer[1] = USB_DT_STRING;  /* descriptor = string */
+
+                                 /* Copy device string to fifo, expand to simple unicode */
+                                 for (s = 0; s < sl; s++)
+                                 {
+                                         ep0_buffer[2+ 2*s + 0] = device_strings[string_index][s];
+                                         ep0_buffer[2+ 2*s + 1] = 0;
+                                 }
+
+				 ep0_req->length = bLength;
+				 ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+			 }
+			 break;
+
+		case USB_DT_DEVICE_QUALIFIER:
+#ifdef CONFIG_USB_1_1_DEVICE
+			 /* This is an invalid request for usb 1.1, nak it */
+			 NAK_REQ();
+#else
+			 d.bLength = min(w_length, sizeof(d));
+			 d.bDescriptorType	= USB_DT_DEVICE_QUALIFIER;
+			 d.bcdUSB		= 0x200;
+			 d.bDeviceClass		= 0xff;
+			 d.bDeviceSubClass	= 0xff;
+			 d.bDeviceProtocol	= 0xff;
+			 d.bMaxPacketSize0	= 0x40;
+			 d.bNumConfigurations	= 1;
+			 d.bRESERVED		= 0;
+
+			 memcpy(ep0_buffer, &d, d.bLength);
+			 ep0_req->length = d.bLength;
+			 ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+#endif
+			 break;
+		default:
+			ret = -EINVAL;
+	}
+	return ret;
+}
+
+#define USB_STATUS_SELFPOWERED	0x01
+#define USB_REQ_TYPE_MASK		0x60
+#define USB_REQ_TYPE_STANDARD		0x00
+#define USB_REQ_DIRECTION_MASK		0x80
+#define USB_REQ_RECIPIENT_MASK		0x1f
+
+static int fastbot_setup_get_status(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	u16 w_length	= le16_to_cpu(ctrl->wLength);
+
+	if (w_length == 0) {
+		ep0_req->length = 0;
+		return usb_ep_queue(gadget->ep0, ep0_req, 0);
+	}
+	ep0_buffer[0] = USB_STATUS_SELFPOWERED;
+	ep0_buffer[1] = 0;
+	ep0_req->length = 2;
+	return usb_ep_queue(gadget->ep0, ep0_req, 0);
+}
+
+static int fastboot_setup_get_configuration(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	u16 w_length	= le16_to_cpu(ctrl->wLength);
+
+	if (w_length == 0)
+		return -1;
+
+	ep0_buffer[0] = current_config;
+	ep0_req->length = 1;
+	return usb_ep_queue(gadget->ep0, ep0_req, 0);
+}
+
+static void fastboot_complete_in(struct usb_ep *ep, struct usb_request *req)
+{
+	int status = req->status;
+
+	if (status)
+		printf("status: %d ep_in trans: %d\n",
+				status,
+				req->actual);
+	req->actual = 0;
+	if (fastboot_interface && fastboot_interface->tx_complete)
+		fastboot_interface->tx_complete();
+}
+
+void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+
+static int fastboot_disable_ep(struct usb_gadget *gadget)
+{
+	if (req_out) {
+		usb_ep_free_request(ep_out, req_out);
+		req_out = NULL;
+	}
+	if (req_in) {
+		usb_ep_free_request(ep_in, req_in);
+		req_in = NULL;
+	}
+	usb_ep_disable(ep_out);
+	usb_ep_disable(ep_in);
+
+	return 0;
+}
+
+static int fastboot_enable_ep(struct usb_gadget *gadget)
+{
+	int ret;
+
+	/* make sure we don't enable the ep twice */
+	if (gadget->speed == USB_SPEED_HIGH)
+		ret = usb_ep_enable(ep_out, &hs_ep_out);
+	else
+		ret = usb_ep_enable(ep_out, &fs_ep_out);
+	if (ret) {
+		printf("%s(%d): %d\n", __func__, __LINE__, ret);
+		goto err;
+	}
+
+	req_out = usb_ep_alloc_request(ep_out, 0);
+	if (!req_out) {
+		printf("%s(%d): %d\n", __func__, __LINE__, ret);
+		goto err;
+	}
+
+	ret = usb_ep_enable(ep_in, &fs_ep_in);
+	if (ret) {
+		printf("%s(%d): %d\n", __func__, __LINE__, ret);
+		goto err;
+	}
+	req_in = usb_ep_alloc_request(ep_in, 0);
+	if (!req_in) {
+		printf("%s(%d): %d\n", __func__, __LINE__, ret);
+		goto err;
+	}
+
+	req_out->complete = rx_handler_command;
+	req_out->buf = ep_out_buffer;
+	req_out->length = sizeof(ep_out_buffer);
+
+	req_in->complete = fastboot_complete_in;
+	req_in->buf = ep_in_buffer;
+	req_in->length = sizeof(ep_in_buffer);
+
+	ret = usb_ep_queue(ep_out, req_out, 0);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	fastboot_disable_ep(gadget);
+	return -1;
+}
+
+static int fastboot_set_interface(struct usb_gadget *gadget, u32 enable)
+{
+	if (enable && req_out)
+		return 0;
+	if (!enable && !req_out)
+		return 0;
+
+	if (enable)
+		return fastboot_enable_ep(gadget);
+	else
+		return fastboot_disable_ep(gadget);
+}
+
+static int fastboot_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *req)
+{
+	if ((req->bRequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) {
+		if ((req->bRequestType & USB_REQ_DIRECTION_MASK) == 0) {
+			/* host-to-device */
+			if ((req->bRequestType & USB_REQ_RECIPIENT_MASK) == USB_RECIP_DEVICE) {
+				switch(req->bRequest) {
+					case USB_REQ_SET_CONFIGURATION:
+						ep0_req->length = 0;
+						if (req->wValue == CONFIGURATION_NORMAL) {
+							current_config = CONFIGURATION_NORMAL;
+							fastboot_set_interface(gadget, 1);
+							return usb_ep_queue(gadget->ep0, ep0_req, 0);
+						}
+						if (req->wValue == 0) {
+							current_config = 0;
+							fastboot_set_interface(gadget, 0);
+							return usb_ep_queue(gadget->ep0, ep0_req, 0);
+						}
+						return -1;
+						break;
+					default:
+						return -1;
+				};
+			}
+			if (USB_RECIP_INTERFACE == (req->bRequestType & USB_REQ_RECIPIENT_MASK)) {
+				switch(req->bRequest) {
+
+					case USB_REQ_SET_INTERFACE:
+						ep0_req->length = 0;
+						if (!fastboot_set_interface(gadget, 1))
+							return usb_ep_queue(gadget->ep0, ep0_req, 0);
+
+						return -1;
+						break;
+					default:
+						return -1;
+				}
+			}
+
+			if ((req->bRequestType & USB_REQ_RECIPIENT_MASK) == USB_RECIP_ENDPOINT) {
+				switch (req->bRequest) {
+					case USB_REQ_CLEAR_FEATURE:
+						return usb_ep_queue(gadget->ep0, ep0_req, 0);
+						break;
+					default:
+						return -1;
+				}
+			}
+		}
+		/* device-to-host */
+		if ((req->bRequestType & USB_REQ_RECIPIENT_MASK) == USB_RECIP_DEVICE) {
+			switch(req->bRequest) {
+			case USB_REQ_GET_DESCRIPTOR:
+				return fastboot_setup_get_descr(gadget, req);
+				break;
+			case USB_REQ_GET_STATUS:
+				/* should be handled by dwc3 anyway */
+				return fastbot_setup_get_status(gadget, req);
+
+			case USB_REQ_GET_CONFIGURATION:
+				return fastboot_setup_get_configuration(gadget, req);
+				break;
+			default:
+				return -1;
+			}
+		} else {
+			return -1;
+		}
+	} else
+		return -1;
+}
+
+static void fastboot_disconnect(struct usb_gadget *gadget)
+{
+	fastboot_disable_ep(gadget);
+}
+
+struct usb_gadget_driver fast_gadget = {
+	.bind		= fastboot_bind,
+	.unbind		= fastboot_unbind,
+	.setup		= fastboot_setup,
+	.disconnect	= fastboot_disconnect,
+};
+
+static int dwc3_is_up;
+#define CFG_FASTBOOT_TRANSFER_BUFFER_SIZE (1024)
+static unsigned char CFG_FASTBOOT_TRANSFER_BUFFER[CFG_FASTBOOT_TRANSFER_BUFFER_SIZE];
+
+int fastboot_init(struct cmd_fastboot_interface *interface)
+{
+	int ret;
+
+	device_strings[DEVICE_STRING_MANUFACTURER_INDEX]	= "Manucacturer";
+	device_strings[DEVICE_STRING_PRODUCT_INDEX]		= "Product";
+	device_strings[DEVICE_STRING_SERIAL_NUMBER_INDEX]	= "00123";
+	device_strings[DEVICE_STRING_CONFIG_INDEX]		= "Android Fastboot";
+	device_strings[DEVICE_STRING_INTERFACE_INDEX]		= "Android Fastboot";
+	device_strings[DEVICE_STRING_PROC_REVISION]		= "ES1.0";
+	device_strings[DEVICE_STRING_PROC_TYPE]			= "Type";
+
+	fastboot_interface = interface;
+	fastboot_interface->product_name	= device_strings[DEVICE_STRING_PRODUCT_INDEX];
+	fastboot_interface->serial_no		= device_strings[DEVICE_STRING_SERIAL_NUMBER_INDEX];
+	fastboot_interface->proc_rev		= device_strings[DEVICE_STRING_PROC_REVISION];
+	fastboot_interface->proc_type		= device_strings[DEVICE_STRING_PROC_TYPE];
+
+	fastboot_interface->storage_medium		= NAND;
+	fastboot_interface->nand_block_size		= 2048;
+	fastboot_interface->transfer_buffer		= (unsigned char *) CFG_FASTBOOT_TRANSFER_BUFFER;
+	fastboot_interface->transfer_buffer_size	= CFG_FASTBOOT_TRANSFER_BUFFER_SIZE;
+
+	ret = usb_gadget_init_udc();
+	if (ret) {
+		printf("%s() Probe failed.\n", __func__);
+		return 1;
+	}
+	dwc3_is_up = 1;
+
+	ret = usb_gadget_probe_driver(&fast_gadget, fastboot_bind);
+	if (ret) {
+		printf("Add gadget failed\n");
+		goto err;
+	}
+
+	usb_gadget_handle_interrupts();
+	return 0;
+
+err:
+	fastboot_shutdown();
+	return 1;
+}
+
+int fastboot_poll(void)
+{
+	usb_gadget_handle_interrupts();
+
+	if (dwc3_cable_connected)
+		return 0;
+	else
+		return 1;
+}
+
+void fastboot_shutdown(void)
+{
+	if (!dwc3_is_up)
+		return;
+	dwc3_is_up = 0;
+	fastboot_interface = NULL;
+	usb_gadget_exit_udc();
+}
+
+void (*complete)(struct usb_ep *ep, struct usb_request *req);
+
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
+{
+	int ret;
+
+	memcpy(req_in->buf, buffer, buffer_size);
+	req_in->length = buffer_size;
+	ret = usb_ep_queue(ep_in, req_in, 0);
+	if (ret)
+		printf("%s() error %d on queue\n", __func__, ret);
+	return 0;
+}
+
+int fastboot_getvar(const char *rx_buffer, char *tx_buffer)
+{
+	printf("%s() missing\n", __func__);
+	return 0;
+}
diff --git a/drivers/usb/gadget/misc.h b/drivers/usb/gadget/misc.h
new file mode 100644
index 0000000..acd23c8
--- /dev/null
+++ b/drivers/usb/gadget/misc.h
@@ -0,0 +1,14 @@
+#ifndef dwc3_misc_h
+#define dwc3_misc_h
+
+#include <linux/compiler.h>
+#include <malloc.h>
+#include <asm/io.h>
+
+#define GFP_KERNEL	0
+
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
+
+#endif
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 49b7483..70cea71 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -559,6 +559,7 @@ enum usb_device_speed {
 	USB_SPEED_LOW, USB_SPEED_FULL,		/* usb 1.1 */
 	USB_SPEED_HIGH,				/* usb 2.0 */
 	USB_SPEED_VARIABLE,			/* wireless (usb 2.5) */
+	USB_SPEED_SUPER,			/* usb 3.0 */
 };
 
 enum usb_device_state {
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 275cb5f..4de6ca8 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -19,6 +19,7 @@
 #define __LINUX_USB_GADGET_H
 
 #include <linux/list.h>
+#include <errno.h>
 
 struct usb_ep;
 
@@ -854,4 +855,7 @@ extern void usb_ep_autoconfig_reset(struct usb_gadget *);
 
 extern int usb_gadget_handle_interrupts(void);
 
+extern int usb_gadget_init_udc(void);
+extern void usb_gadget_exit_udc(void);
+
 #endif	/* __LINUX_USB_GADGET_H */
diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
new file mode 100644
index 0000000..1d67d94
--- /dev/null
+++ b/include/usb/fastboot.h
@@ -0,0 +1,340 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * The logical naming of flash comes from the Android project
+ * Thse structures and functions that look like fastboot_flash_*
+ * They come from bootloader/legacy/include/boot/flash.h
+ *
+ * The boot_img_hdr structure and associated magic numbers also
+ * come from the Android project.  They are from
+ * system/core/mkbootimg/bootimg.h
+ *
+ * Here are their copyrights
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef FASTBOOT_H
+#define FASTBOOT_H
+
+#include <common.h>
+#include <command.h>
+
+/* From fastboot client.. */
+#define FASTBOOT_INTERFACE_CLASS     0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS 0x42
+#define FASTBOOT_INTERFACE_PROTOCOL  0x03
+
+#define FASTBOOT_VERSION "0.5"
+
+/* The fastboot client uses a value of 2048 for the 
+   page size of it boot.img file format. 
+   Reset this in your board config file as needed. */
+#ifndef CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE
+#define CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE 2048
+#endif
+
+typedef enum { NAND, EMMC } storage_medium_type;
+
+struct cmd_fastboot_interface
+{
+	/* This function is called when a buffer has been 
+	   recieved from the client app.
+	   The buffer is a supplied by the board layer and must be unmodified. 
+	   The buffer_size is how much data is passed in. 
+	   Returns 0 on success
+	   Returns 1 on failure	
+
+	   Set by cmd_fastboot	*/
+	int (*rx_handler)(const unsigned char *buffer,
+			  unsigned int buffer_size);
+
+	/*
+	 * Returns the number of bytes which are expected in the next RX.
+	 * Returns 0 if unknown or the exact amount. This is required during
+	 * the transfer of an image where size may be a multiple of
+	 * MacPacketSize and the host is not sending a ZeroSizePacket to
+	 * terminate the tranfer. Thank you google.
+	 */
+	unsigned int (*rx_bytes_expected)(void);
+	/*
+	 * notify fastboot that a given tx-transfer completed. Used by the
+	 * "boot" command which should be executed after the transfer of
+	 * the "OKAY" message has been delived to the USB host.
+	 */
+	void (*tx_complete)(void);
+	/* This function is called when an exception has
+	   occurred in the device code and the state
+	   off fastboot needs to be reset
+
+	   Set by cmd_fastboot */
+	void (*reset_handler)(void);
+
+	/* A getvar string for the product name
+	   It can have a maximum of 60 characters
+
+	   Set by board	*/
+	char *product_name;
+
+	/* A getvar string for the serial number
+	   It can have a maximum of 60 characters
+
+	   Set by board */
+	char *serial_no;
+
+	/* A getvar string for the processor revision
+	   It can have a maximum of 60 characters
+
+	   Set by board */
+	char *proc_rev;
+
+	/* A getvar string for the processor type
+	   this can be GP, EMU or HS
+	   It can have a maximum of 60 characters
+
+	   Set by board */
+	char *proc_type;
+
+	/* To determine the storage type NAND or EMMC */
+	storage_medium_type storage_medium;
+
+	/* Nand block size
+	   Supports the write option WRITE_NEXT_GOOD_BLOCK
+
+	   Set by board */
+	unsigned int nand_block_size;
+
+	/* Transfer buffer, for handling flash updates
+	   Should be multiple of the nand_block_size
+	   Care should be take so it does not overrun bootloader memory
+	   Controlled by the configure variable CFG_FASTBOOT_TRANSFER_BUFFER
+
+	   Set by board */
+	unsigned char *transfer_buffer;
+
+	/* How big is the transfer buffer
+	   Controlled by the configure variable
+	   CFG_FASTBOOT_TRANSFER_BUFFER_SIZE
+
+	   Set by board	*/
+	unsigned int transfer_buffer_size;
+
+};
+
+/* Android-style flash naming */
+typedef struct fastboot_ptentry fastboot_ptentry;
+
+/* flash partitions are defined in terms of blocks
+** (flash erase units)
+*/
+struct fastboot_ptentry
+{
+	/* The logical name for this partition, null terminated */
+	char name[16];
+	/* The start wrt the nand part, must be multiple of nand block size */
+	unsigned int start;
+	/* The length of the partition, must be multiple of nand block size */
+	unsigned int length;
+	/* Controls the details of how operations are done on the partition
+	   See the FASTBOOT_PTENTRY_FLAGS_*'s defined below */
+	unsigned int flags;
+};
+
+/* Lower byte shows if the read/write/erase operation in
+   repeated.  The base address is incremented.
+   Either 0 or 1 is ok for a default */
+
+#define FASTBOOT_PTENTRY_FLAGS_REPEAT(n)              (n & 0x0f)
+#define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK            0x0000000F
+
+/* Writes happen a block at a time.
+   If the write fails, go to next block
+   NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK  0x00000010
+
+/* Find a contiguous block big enough for a the whole file
+   NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK 0x00000020
+
+/* Sets the ECC to hardware before writing
+   HW and SW ECC should not both be set. */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC           0x00000040
+
+/* Sets the ECC to software before writing
+   HW and SW ECC should not both be set. */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC           0x00000080
+
+/* Write the file with write.i */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_I                0x00000100
+
+/* Write the file with write.yaffs */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS            0x00000200
+
+/* Write the file as a series of variable/value pairs
+   using the setenv and saveenv commands */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_ENV              0x00000400
+
+/* Android bootimage file format */
+#define FASTBOOT_BOOT_MAGIC "ANDROID!"
+#define FASTBOOT_BOOT_MAGIC_SIZE 8
+#define FASTBOOT_BOOT_NAME_SIZE 16
+#define FASTBOOT_BOOT_ARGS_SIZE 512
+
+struct fastboot_boot_img_hdr {
+	unsigned char magic[FASTBOOT_BOOT_MAGIC_SIZE];
+
+	unsigned kernel_size;  /* size in bytes */
+	unsigned kernel_addr;  /* physical load addr */
+
+	unsigned ramdisk_size; /* size in bytes */
+	unsigned ramdisk_addr; /* physical load addr */
+
+	unsigned second_size;  /* size in bytes */
+	unsigned second_addr;  /* physical load addr */
+
+	unsigned tags_addr;    /* physical addr for kernel tags */
+	unsigned page_size;    /* flash page size we assume */
+	unsigned unused[2];    /* future expansion: should be 0 */
+
+	unsigned char name[FASTBOOT_BOOT_NAME_SIZE]; /* asciiz product name */
+
+	unsigned char cmdline[FASTBOOT_BOOT_ARGS_SIZE];
+
+	unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+#if (CONFIG_CMD_FASTBOOT)
+/* A board specific test if u-boot should go into the fastboot command
+   ahead of the bootcmd
+   Returns 0 to continue with normal u-boot flow
+   Returns 1 to execute fastboot */
+extern int fastboot_preboot(void);
+
+/* Initizes the board specific fastboot 
+   Returns 0 on success
+   Returns 1 on failure */
+extern int fastboot_init(struct cmd_fastboot_interface *interface);
+
+/* Cleans up the board specific fastboot */
+extern void fastboot_shutdown(void);
+
+/* Handles board specific usb protocol exchanges
+   Returns 0 on success
+   Returns 1 on disconnects, break out of loop
+   Returns -1 on failure, unhandled usb requests and other error conditions */
+extern int fastboot_poll(void);
+
+/* Is this high speed (2.0) or full speed (1.1) ? 
+   Returns 0 on full speed
+   Returns 1 on high speed */
+extern int fastboot_is_highspeed(void);
+
+/* Return the size of the fifo */
+extern int fastboot_fifo_size(void);
+
+/* A board specific variable handler. 
+   The size of the buffers is governed by the fastboot spec. 
+   rx_buffer is at most 57 bytes 
+   tx_buffer is at most 60 bytes
+   Returns 0 on success
+   Returns 1 on failure */
+extern int fastboot_getvar(const char *rx_buffer, char *tx_buffer);
+/* board-specific fastboot commands */
+extern int fastboot_oem(const char *command);
+
+/* The Android-style flash handling */
+
+/* tools to populate and query the partition table */
+extern void fastboot_flash_add_ptn(fastboot_ptentry *ptn);
+extern fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
+extern fastboot_ptentry *fastboot_flash_get_ptn(unsigned n);
+extern unsigned int fastboot_flash_get_ptn_count(void);
+extern void fastboot_flash_dump_ptn(void);
+
+extern int fastboot_flash_init(void);
+extern int fastboot_flash_erase(fastboot_ptentry *ptn);
+extern int fastboot_flash_read_ext(fastboot_ptentry *ptn, 
+				   unsigned extra_per_page, unsigned offset, 
+				   void *data, unsigned bytes);
+#define fastboot_flash_read(ptn, offset, data, bytes) \
+  flash_read_ext(ptn, 0, offset, data, bytes)
+extern int fastboot_flash_write(fastboot_ptentry *ptn, unsigned extra_per_page,
+				const void *data, unsigned bytes);
+
+
+#else
+
+static inline int fastboot_preboot(void) { return 0; }
+static inline int fastboot_init(struct cmd_fastboot_interface *interface) { return 1; }
+static inline void fastboot_shutdown(void) { }
+static inline int fastboot_poll(void) { return 1; }
+static inline int fastboot_is_highspeed(void) { return 0; }
+static inline int fastboot_fifo_size(void) { return 0; }
+static inline int fastboot_tx_write(const char *buffer, unsigned int buffer_size) { return 1; }
+static inline int fastboot_getvar(const char *rx_buffer, char *tx_buffer) { return 1; }
+static inline int fastboot_oem(const char *command);
+static inline void fastboot_flash_add_ptn(fastboot_ptentry *ptn) { }
+static inline fastboot_ptentry *fastboot_flash_find_ptn(const char *name) { return NULL; }
+static inline fastboot_ptentry *fastboot_flash_get_ptn(unsigned n) { return NULL; }
+static inline unsigned int fastboot_flash_get_ptn_count(void) { return 0; }
+static inline void fastboot_flash_dump_ptn(void) { }
+static inline int fastboot_flash_init(void) { }
+static inline int fastboot_flash_erase(fastboot_ptentry *ptn) { return 1; }
+static inline int fastboot_flash_read_ext(fastboot_ptentry *ptn,
+				   unsigned extra_per_page, unsigned offset,
+				   void *data, unsigned bytes) { return 0; }
+static inline int fastboot_flash_write(fastboot_ptentry *ptn, unsigned extra_per_page,
+				const void *data, unsigned bytes) { return 0; }
+
+#endif /* CONFIG_FASTBOOT */
+
+extern struct usb_ep *ep_in;
+extern struct usb_request *req_in;
+extern struct usb_ep *ep_out;
+extern struct usb_request *req_out;
+
+#define EP_OUT_BUFFER_SIZE      4096
+
+#endif /* FASTBOOT_H */
diff --git a/include/usb/sparse.h b/include/usb/sparse.h
new file mode 100644
index 0000000..6249e68
--- /dev/null
+++ b/include/usb/sparse.h
@@ -0,0 +1,33 @@
+/*
+ * (C) Copyright 2011
+ * Texas Instruments, <www.ti.com>
+ * Author: Vikram Pandita <vikram.pandita@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __SPARSE_H
+#define __SPARSE_H
+
+/* This file is taken as such from Android repo */
+#include <usb/sparse_format.h>
+
+u8
+do_unsparse(unsigned char *source,
+                u32 sector,
+                u32 section_size,
+                int slot_no);
+#endif /* __SPARSE_H */
diff --git a/include/usb/sparse_format.h b/include/usb/sparse_format.h
new file mode 100644
index 0000000..ba13214
--- /dev/null
+++ b/include/usb/sparse_format.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+typedef struct sparse_header {
+  __le32	magic;		/* 0xed26ff3a */
+  __le16	major_version;	/* (0x1) - reject images with higher major versions */
+  __le16	minor_version;	/* (0x0) - allow images with higer minor versions */
+  __le16	file_hdr_sz;	/* 28 bytes for first revision of the file format */
+  __le16	chunk_hdr_sz;	/* 12 bytes for first revision of the file format */
+  __le32	blk_sz;		/* block size in bytes, must be a multiple of 4 (4096) */
+  __le32	total_blks;	/* total blocks in the non-sparse output image */
+  __le32	total_chunks;	/* total chunks in the sparse input image */
+  __le32	image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
+				/* as 0. Standard 802.3 polynomial, use a Public Domain */
+				/* table implementation */
+} sparse_header_t;
+
+#define SPARSE_HEADER_MAGIC	0xed26ff3a
+
+#define CHUNK_TYPE_RAW		0xCAC1
+#define CHUNK_TYPE_FILL		0xCAC2
+#define CHUNK_TYPE_DONT_CARE	0xCAC3
+
+typedef struct chunk_header {
+  __le16	chunk_type;	/* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
+  __le16	reserved1;
+  __le32	chunk_sz;	/* in blocks in output image */
+  __le32	total_sz;	/* in bytes of chunk input file including chunk header and data */
+} chunk_header_t;
+
+/* Following a Raw or Fill chunk is data.  For a Raw chunk, it's the data in chunk_sz * blk_sz.
+ *  For a Fill chunk, it's 4 bytes of the fill data.
+ */
+
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [U-Boot] [RFC] fastboot gadget support
  2011-08-10 18:07 ` [U-Boot] [RFC] fastboot gadget support Sebastian Andrzej Siewior
@ 2011-08-13 10:22   ` Remy Bohmer
  2011-08-24 14:09     ` Sebastian Andrzej Siewior
  2011-08-24 19:34   ` Remy Bohmer
  1 sibling, 1 reply; 11+ messages in thread
From: Remy Bohmer @ 2011-08-13 10:22 UTC (permalink / raw)
  To: u-boot

Hi Sebastian,

2011/8/10 Sebastian Andrzej Siewior <bigeasy@linutronix.de>:
> This is the faastboot gadget code based on
> git://git.omapzoom.org/repo/u-boot.git as of commit 601ff71c8 including
> a few changes. Some of them are:
> - generic mmc framework
> - "new" gadget framework
> - different / easier command parsing
> - booti command is missing
>
> It was tested before it has been re-written. It is possible that it is
> broken. It is posted for reference only not for merging.
>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

I am going to look at it in detail  in a couple of days.
I will come back to this soon.

Kind regards,

Remy

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [U-Boot] [ RFC ] fastboot protocol support in u-boot
  2011-08-10 18:07 [U-Boot] [ RFC ] fastboot protocol support in u-boot Sebastian Andrzej Siewior
  2011-08-10 18:07 ` [U-Boot] [RFC] fastboot gadget support Sebastian Andrzej Siewior
@ 2011-08-16 14:47 ` Stefan Schmidt
  2011-08-16 15:32   ` John Rigby
  1 sibling, 1 reply; 11+ messages in thread
From: Stefan Schmidt @ 2011-08-16 14:47 UTC (permalink / raw)
  To: u-boot

Hello.

On Wed, 2011-08-10 at 20:07, Sebastian Andrzej Siewior wrote:
> 
> The code uses the "newer" gadget API which is used by the rndis gadget for
> instance. The only udc implementing it (as far as I know) is the at91 udc
> sitting in cdc-at91 branch [0]. The other udcs in tree (musb for intance)
> is using the old interface which is something linux kernel 2.4 time frame.
> Since nobody plans to develop a udc for both frameworks I went for the newer
> framework.

It would be good to know what the preferred way for new code is here.
I have some DFU work pending I need to finish and get it ready for
review and hopefully upstreaming.

Right now I'm using the "old" interface while working with musb on the
beagleboard. Having the "new" API only available on one hardware makes
it really hard to develop against it.

> I've been looking at DFU as an alternative. I think its main problem is
> the fact that it is ep0 based which limits the USB packet size to 64bytes
> on HighSpeed which makes it slower than necessary.

While speed may be a problem it still works ok for images with a size
over 60 MB. We used that a lot with DFU on the Freerunner devices from
Openmoko. Most devices using DFU are having way smaller images though.

I would like to wait for a ready to merge implementation before doing
measurements here on my side though.

But back to the DFU vs. fastboot topic. I'm maintaining the dfu-util
host utility which allows DFU flashing under Linux and other systems.
The devices supporting DFU I see are normally interested in flashing
or doing a backup only. Fastboot (or something like novacom for WebOS)
goes further here by providing other mechanisms to communicate with
the bootloader. This is beyond what DFU was designed and should be
used for in my opinion.

Given these different use cases I never seen fastboot and DFU as
competitors. Personally I see DFU as a good and standardized way of
_flashing_ devices while fastboot/novacom are way to communicate with
the bootloader (allow flashing as on task).

> So, any comments on that? Suggestions? Anything?

Not much over what I have written above. Looking into novacom for some
more ideas may be worth it.

regards
Stefan Schmidt

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [U-Boot] [ RFC ] fastboot protocol support in u-boot
  2011-08-16 14:47 ` [U-Boot] [ RFC ] fastboot protocol support in u-boot Stefan Schmidt
@ 2011-08-16 15:32   ` John Rigby
  2011-08-16 18:12     ` Stefan Schmidt
  0 siblings, 1 reply; 11+ messages in thread
From: John Rigby @ 2011-08-16 15:32 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 16, 2011 at 8:47 AM, Stefan Schmidt
<stefan@datenfreihafen.org> wrote:

>
> Given these different use cases I never seen fastboot and DFU as
> competitors. Personally I see DFU as a good and standardized way of
> _flashing_ devices while fastboot/novacom are way to communicate with
> the bootloader (allow flashing as on task).
>

Just my two cents.  From my discussions with Android developers, they
use fastboot as a quick turnaround way of getting an image on a board
during iterative development.

The other thing I think is important is the ability to choose DFU or
fastboot at run time vs compile time.  So we should be able to have
both features turned on in a given u-boot binary.  This means of
course that fastboot, or DFU would not assume it owned the gadget USB
HW.

--John

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [U-Boot] [ RFC ] fastboot protocol support in u-boot
  2011-08-16 15:32   ` John Rigby
@ 2011-08-16 18:12     ` Stefan Schmidt
  2011-08-16 19:44       ` John Rigby
  0 siblings, 1 reply; 11+ messages in thread
From: Stefan Schmidt @ 2011-08-16 18:12 UTC (permalink / raw)
  To: u-boot

Hello.

On Tue, 2011-08-16 at 09:32, John Rigby wrote:
> On Tue, Aug 16, 2011 at 8:47 AM, Stefan Schmidt
> <stefan@datenfreihafen.org> wrote:
> >
> > Given these different use cases I never seen fastboot and DFU as
> > competitors. Personally I see DFU as a good and standardized way of
> > _flashing_ devices while fastboot/novacom are way to communicate with
> > the bootloader (allow flashing as on task).
> >
> Just my two cents.  From my discussions with Android developers, they
> use fastboot as a quick turnaround way of getting an image on a board
> during iterative development.

Sure, we did the same with DFU at Openmoko and other companies have
done the same as well with DFU. What I was meaning to point out is
that flashing (be it to NAND, NOR or just to RAM) is only one action
out of many you can do with fastboot. While with DFU it was designed
to only do upgrade or backup operations. Nothing else.

> The other thing I think is important is the ability to choose DFU or
> fastboot at run time vs compile time.  So we should be able to have
> both features turned on in a given u-boot binary.  This means of
> course that fastboot, or DFU would not assume it owned the gadget USB
> HW.

Hmm, interesting point. To be honest I never have thought about people
having both enabled at runtime. Having fastboot with flashing seem to
imply that DFU is not used on that device to me. What is the use-case
you are describing here?

Or are you talking about changing fastboot to use DFU as a flashing
backend or such?

Anyway, DFU does distinguish between run-time and DFU mode. During
run-time it only offers a single DFU class interface descriptor and a
single functional descriptor. This get added to every USB
configuration the devices exposes (and wants to support DFU in it).

This is used to to trigger a switch to the DFU mode where the complete
DFU protocol interaction happens. Normally this is used to enter the
flash mode from the run-time mode via the host utility. Often there is
also a button combination that can be pressed to directly boot up the
device in DFU mode for flashing.

How we could hook that together with fastboot I don't know yet. One
easy solution would be to bring up u-boot in DFU run-time mode and
disable all fastboot stuff once we switch to DFU mode as well as the
other way around.

I'm still curious though if there are practical needs for both
fastboot and DFU enabled.

regards
Stefan Schmidt

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [U-Boot] [ RFC ] fastboot protocol support in u-boot
  2011-08-16 18:12     ` Stefan Schmidt
@ 2011-08-16 19:44       ` John Rigby
  2011-08-16 20:44         ` Stefan Schmidt
  0 siblings, 1 reply; 11+ messages in thread
From: John Rigby @ 2011-08-16 19:44 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 16, 2011 at 12:12 PM, Stefan Schmidt
<stefan@datenfreihafen.org> wrote:

>
> I'm still curious though if there are practical needs for both
> fastboot and DFU enabled.
>

My only point was that I would rather DFU, Fastboot, USBSerial and any
other potential users of MUSB or other gadget usb hw not be written in
a way that it is the only consumer of the hw.  I should be able to
choose at config time which I will potentially use and at run time
which I actually use.  That way the same u-boot.bin could be used with
DFU one day and Fastboot another without rebuilding and reinstalling.

--John

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [U-Boot] [ RFC ] fastboot protocol support in u-boot
  2011-08-16 19:44       ` John Rigby
@ 2011-08-16 20:44         ` Stefan Schmidt
  0 siblings, 0 replies; 11+ messages in thread
From: Stefan Schmidt @ 2011-08-16 20:44 UTC (permalink / raw)
  To: u-boot

Hello.

On Tue, 2011-08-16 at 13:44, John Rigby wrote:
> On Tue, Aug 16, 2011 at 12:12 PM, Stefan Schmidt
> <stefan@datenfreihafen.org> wrote:
> >
> > I'm still curious though if there are practical needs for both
> > fastboot and DFU enabled.
> >
> My only point was that I would rather DFU, Fastboot, USBSerial and any
> other potential users of MUSB or other gadget usb hw not be written in
> a way that it is the only consumer of the hw.  I should be able to
> choose at config time which I will potentially use and at run time
> which I actually use.  That way the same u-boot.bin could be used with
> DFU one day and Fastboot another without rebuilding and reinstalling.

For something like USB serial or USB ethernet I fully agree with
having it written in a way we use it together with fastboot and or
DFU.

If I remember correctly (On vacation, to lazy to check the code) we
had the setup with USB serial running. The device started u-boot up
with USB serial and DFU in run-time mode offering the additional
interface. You could then connect via serial to u-boot and once you
triggered the switch to DFU mode with dfu-util on the host we switched
to full DFU mode and USB serial was gone.

In addition to that we can offer a configuration to enter the DFU
directly when a button is pressed during startup or such.

So in summary I agree with your idea having the possibility to enable
more then one. Just having DFU and fastboot enabled together made me
wondering. :)

regards
Stefan Schmidt

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [U-Boot] [RFC] fastboot gadget support
  2011-08-13 10:22   ` Remy Bohmer
@ 2011-08-24 14:09     ` Sebastian Andrzej Siewior
  0 siblings, 0 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2011-08-24 14:09 UTC (permalink / raw)
  To: u-boot

On 08/13/2011 12:22 PM, Remy Bohmer wrote:
> Hi Sebastian,
Hi Remy,

> 2011/8/10 Sebastian Andrzej Siewior<bigeasy@linutronix.de>:
>> This is the faastboot gadget code based on
>> git://git.omapzoom.org/repo/u-boot.git as of commit 601ff71c8 including
>> a few changes. Some of them are:
>> - generic mmc framework
>> - "new" gadget framework
>> - different / easier command parsing
>> - booti command is missing
>>
>> It was tested before it has been re-written. It is possible that it is
>> broken. It is posted for reference only not for merging.
>>
>> Signed-off-by: Sebastian Andrzej Siewior<bigeasy@linutronix.de>
>
> I am going to look at it in detail  in a couple of days.
> I will come back to this soon.

any news so far? :)


> Kind regards,
>
> Remy

Sebastian

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [U-Boot] [RFC] fastboot gadget support
  2011-08-10 18:07 ` [U-Boot] [RFC] fastboot gadget support Sebastian Andrzej Siewior
  2011-08-13 10:22   ` Remy Bohmer
@ 2011-08-24 19:34   ` Remy Bohmer
  2011-08-26 10:09     ` Sebastian Andrzej Siewior
  1 sibling, 1 reply; 11+ messages in thread
From: Remy Bohmer @ 2011-08-24 19:34 UTC (permalink / raw)
  To: u-boot

Hi,

2011/8/10 Sebastian Andrzej Siewior <bigeasy@linutronix.de>:
>
> It was tested before it has been re-written. It is possible that it is
> broken. It is posted for reference only not for merging.

Looking at this code, I can already say that the way it is written is
not suitable for mainline acceptance at all. If you at least would run
the Linux checkpatch over it, it would result in an almost endless
list of style warnings and errors ;-)
But, since it RFC only, let's look into the design parts and not be
too picky about the style (yet)

I may be missing something, but it appears to me that this particular
patch for the fastboot framework makes several assumptions about:
* if MMC is available (max 2 controllers, namely 0 or 1). Let' s say
my hardware doe not support it, and I do not want to enable it due to
codesize reasons...
* if NAND is available and it is either YAFFS or raw, what if I have UBI?
* Or let's drop the MMC and NAND, and assume we only have a harddrive
or USB storage on our board ;-)
* Hardcoded NAND block sizes which are evil.
* storage_medium is hardcoded set to NAND, never to EMMC, so what is
the EMMC code doing here?

Furthermore:
* Board code is mixed up with generic code.
* drivers/usb/dwc3/fastboot_oem.c, drivers/usb/dwc3/misc.c,
drivers/usb/dwc3/sparse.c contain code that has _nothing_ to do with
USB.
* generic files (for example like include/linux/usb/ch9.h) are adapted
with changes not even used by the code.
* Mix up of different licenses: U-boot is still GPLv2, while this
patch contains Apache based licenses (Not sure if it conflicts with
GPL, but it seems strange)
* it makes a lot of assumptions how the hardware looks like.
* It is not properly separated across different subsystems. There need
to be a proper separation between drivers, library code, U-boot core
code and board files. Everything that is board specific should go in
board files. NAND-availability or partitioning is board specific, MMC
as well, the only assumption you can make about hardware that should
always be available is RAM, you can only not assume how much there is,
and which address area is free. NAND and MMC usage should be
completely configurable per board.
* There need to be proper Documentation in the doc directory.
* It would be great to have at least a demo tool in /tools or a
commonly used OSS package that provides the tools, such that the
mechanism can be tested as well.

> This is the faastboot gadget code based on
> git://git.omapzoom.org/repo/u-boot.git as of commit 601ff71c8 including
> a few changes. Some of them are:
> - generic mmc framework

I have not found a ' generic'  mmc framework, only a 'fastboot'
dedicated mmc framework.

So, I have no objections to the protocol or the mechanism itself, as
long as it is properly implemented.

Kind regards,

Remy

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [U-Boot] [RFC] fastboot gadget support
  2011-08-24 19:34   ` Remy Bohmer
@ 2011-08-26 10:09     ` Sebastian Andrzej Siewior
  0 siblings, 0 replies; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2011-08-26 10:09 UTC (permalink / raw)
  To: u-boot

On 08/24/2011 09:34 PM, Remy Bohmer wrote:
> Hi,
Hi,

thanks for your time.

> 2011/8/10 Sebastian Andrzej Siewior<bigeasy@linutronix.de>:
>>
>> It was tested before it has been re-written. It is possible that it is
>> broken. It is posted for reference only not for merging.
>
> Looking at this code, I can already say that the way it is written is
> not suitable for mainline acceptance at all. If you at least would run
> the Linux checkpatch over it, it would result in an almost endless
> list of style warnings and errors ;-)

Sure. I just wanted to avoid spending more time on it there are some
high level mistakes.

> I may be missing something, but it appears to me that this particular
> patch for the fastboot framework makes several assumptions about:
> * if MMC is available (max 2 controllers, namely 0 or 1). Let' s say
> my hardware doe not support it, and I do not want to enable it due to
> codesize reasons...
Why only two (0 / 1)?
"mmcwrite:X Y" where X is the number of the controller and Y the
partition name do support multiple controllers. The erase command does
not it is "erase:Y" where Y is the partition name.
If you want a ifdef around mmc code so you can disable it, this can be
arranged :)

> * if NAND is available and it is either YAFFS or raw, what if I have UBI?
NAND formats are not part of the fastboot protocol. For UBI you could 
use the raw format. If you want to rescue the erase counters than a 
per-partition flag has to be added (like it is the case for write.i and 
write.yaffs).

> * Or let's drop the MMC and NAND, and assume we only have a harddrive
> or USB storage on our board ;-)
My understanding is that the MMC / NAND partition table is comming from
EFI. So if you your requirement is usb disk media than you have to set
interface.storage_medium to USB_STORAGE (or whatever we define it) and
use the proper write command then.

> * Hardcoded NAND block sizes which are evil.
This should be moved to a per-board configuration.

> * storage_medium is hardcoded set to NAND, never to EMMC, so what is
> the EMMC code doing here?

most of fastboot_init() should be handled per-board. This includes the
name of the product, storage media & type and storage area for the
download command.

> Furthermore:
> * Board code is mixed up with generic code.
Yes, this has to be split up.

> * drivers/usb/dwc3/fastboot_oem.c,
is a hook for custom / vendor extensions to the fastboot protocol. It
will be most likely moved to board specific code.

> drivers/usb/dwc3/misc.c,
Contains currently a hacky snprintf() which is not used by the fastboot 
code and should be part of the patch. sorry.

> drivers/usb/dwc3/sparse.c
this contained custom unsparse code. It seemed to be used as some kind
of RLE compression which did not make much sense and I left it out.

> contain code that has _nothing_ to do with
> USB.
Yes, it will be moved to proper places.

> * generic files (for example like include/linux/usb/ch9.h) are adapted
> with changes not even used by the code.
I have also a USB3 gadget in the pipe. I removed it prior the post but
forgot about some changes.

> * Mix up of different licenses: U-boot is still GPLv2, while this
> patch contains Apache based licenses (Not sure if it conflicts with
> GPL, but it seems strange)

Fastboot are based on BSD license. The sparse header file is the only
part under the Apache v2 license. Since it is not compatible with v2 I
leave the sparse code completely out.

> * it makes a lot of assumptions how the hardware looks like.
This has to be defined somewhere and will be moved to board specific
implementation.

> * It is not properly separated across different subsystems. There need
> to be a proper separation between drivers, library code, U-boot core
> code and board files. Everything that is board specific should go in
> board files.
Okay, will split

> NAND-availability or partitioning is board specific, MMC
> as well, the only assumption you can make about hardware that should
> always be available is RAM, you can only not assume how much there is,
> and which address area is free.
The protocol requires that the complete data is loaded into ram before
anything is doen with it. So what options do I have to achieve this? The
old code hardcoded size to 512/256 - 16 MiB on panda/blaze board. The
buffer started physram + 16MiB. Should I continue this approach?

> NAND and MMC usage should be
> completely configurable per board.
This will be done.

> * There need to be proper Documentation in the doc directory.
I try to add something.

> * It would be great to have at least a demo tool in /tools or a
> commonly used OSS package that provides the tools, such that the
> mechanism can be tested as well.

Okay. There is a so called fastboot tool in the wide android
repository. I could copy it as-it or add a link to the git repository.
Any preferences? That folder can be compiled on windows, linux and mac
osx. The linux part requires libusb and is easy to use. The Windows
edition requires a bunch of Android's SDK to get access to the USB
device.

>> This is the faastboot gadget code based on
>> git://git.omapzoom.org/repo/u-boot.git as of commit 601ff71c8 including
>> a few changes. Some of them are:
>> - generic mmc framework
>
> I have not found a ' generic'  mmc framework, only a 'fastboot'
> dedicated mmc framework.

How so? What I meant is that it depends on CONFIG_GENERIC_MMC and uses
do_mmcops commands for its needs. Is this appropriate or is another 
interface preferred?


> So, I have no objections to the protocol or the mechanism itself, as
> long as it is properly implemented.

I see. So I guess I have to stick with it.

Thanks for the review.

> Kind regards,
>
> Remy

Sebastian

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2011-08-26 10:09 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-10 18:07 [U-Boot] [ RFC ] fastboot protocol support in u-boot Sebastian Andrzej Siewior
2011-08-10 18:07 ` [U-Boot] [RFC] fastboot gadget support Sebastian Andrzej Siewior
2011-08-13 10:22   ` Remy Bohmer
2011-08-24 14:09     ` Sebastian Andrzej Siewior
2011-08-24 19:34   ` Remy Bohmer
2011-08-26 10:09     ` Sebastian Andrzej Siewior
2011-08-16 14:47 ` [U-Boot] [ RFC ] fastboot protocol support in u-boot Stefan Schmidt
2011-08-16 15:32   ` John Rigby
2011-08-16 18:12     ` Stefan Schmidt
2011-08-16 19:44       ` John Rigby
2011-08-16 20:44         ` Stefan Schmidt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.