Browse Source

fastboot for vybrid

u-boot code base for vybrid fastboot function

Signed-off-by: Han Xu <b45815@freescale.com>
Han Xu 12 years ago
parent
commit
cb16338463

+ 1 - 0
Makefile

@@ -302,6 +302,7 @@ LIBS-y += drivers/power/libpower.o \
 	drivers/power/pmic/libpmic.o \
 	drivers/power/battery/libbattery.o
 LIBS-y += drivers/spi/libspi.o
+LIBS-y += drivers/fastboot/libfastboot.o
 LIBS-y += drivers/dfu/libdfu.o
 ifeq ($(CPU),mpc83xx)
 LIBS-y += drivers/qe/libqe.o

+ 35 - 0
arch/arm/cpu/armv7/vf610/generic.c

@@ -322,3 +322,38 @@ int get_clocks(void)
 #endif
 	return 0;
 }
+
+void set_usboh3_clk(void)
+{
+        udc_pins_setting();
+}
+
+void set_usb_phy1_clk(void)
+{
+        /* make sure pll3 is enable here */
+        REG_SET(ANATOP_BASE_ADDR, HW_ANADIG_USB1_CHRG_DETECT,
+                BM_ANADIG_USB1_CHRG_DETECT_EN_B | BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
+        REG_SET(ANATOP_BASE_ADDR, HW_ANADIG_USB1_PLL_480_CTRL,
+                BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS);
+}
+
+void enable_usboh3_clk(unsigned char enable)
+{
+        unsigned int reg;
+        reg = readl(MXC_CCM_CCGR6);
+        if (enable)
+                reg |= 1 << MXC_CCM_CCGR6_CG0_OFFSET;
+        else
+                reg &= ~(1 << MXC_CCM_CCGR6_CG0_OFFSET);
+        writel(reg, MXC_CCM_CCGR6);
+}
+
+void enable_usb_phy1_clk(unsigned char enable)
+{
+        if (enable) {
+                writel(BM_USBPHY_CTRL_CLKGATE, USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL_CLR);
+        } else {
+                writel(BM_USBPHY_CTRL_CLKGATE, USB_PHY0_BASE_ADDR + HW_USBPHY_CTRL_SET);
+        }
+}
+

+ 15 - 0
arch/arm/imx-common/iomux-v3.c

@@ -67,3 +67,18 @@ void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list,
 	for (i = 0; i < count; i++)
 		imx_iomux_v3_setup_pad(*p++);
 }
+
+void imx_iomux_set_gpr_register(int group, int start_bit, int num_bits, int value)
+{
+        int i = 0;
+        u32 reg;
+        reg = readl(base + group * 4);
+        while (num_bits) {
+                reg &= ~(1<<(start_bit + i));
+                i++;
+                num_bits--;
+        }
+        reg |= (value << start_bit);
+        writel(reg, base + group * 4);
+}
+

+ 1 - 0
arch/arm/include/asm/arch-vf610/imx-regs.h

@@ -65,6 +65,7 @@
 #define SAI2_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00031000)
 #define SAI3_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00032000)
 #define CRC_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00033000)
+#define OTG_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00034000)
 #define PDB_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00036000)
 #define PIT_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00037000)
 #define FTM0_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00038000)

+ 1 - 0
arch/arm/include/asm/imx-common/iomux-v3.h

@@ -179,5 +179,6 @@ typedef u64 iomux_v3_cfg_t;
 void imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad);
 void imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t const *pad_list,
 				     unsigned count);
+void imx_iomux_set_gpr_register(int group, int start_bit, int num_bits, int value);
 
 #endif	/* __MACH_IOMUX_V3_H__*/

+ 20 - 0
board/freescale/vf610twr/vf610twr.c

@@ -21,6 +21,7 @@
 #include <asm/io.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/iomux-vf610.h>
+#include <asm/imx-common/iomux-v3.h> 
 #include <asm/arch/crm_regs.h>
 #include <asm/arch/clock.h>
 #include <mmc.h>
@@ -405,3 +406,22 @@ int checkboard(void)
 
 	return 0;
 }
+
+#ifdef CONFIG_IMX_UDC
+
+void udc_pins_setting(void)
+{
+        imx_iomux_v3_setup_pad(MX6X_IOMUX(PAD_ENET_RX_ER__ANATOP_USBOTG_ID));
+        imx_iomux_v3_setup_pad(MX6X_IOMUX(PAD_EIM_D22__GPIO_3_22));
+        imx_iomux_v3_setup_pad(MX6X_IOMUX(PAD_ENET_TXD1__GPIO_1_29));
+
+        /* USB_OTG_PWR = 0 */
+        gpio_direction_output(USB_OTG_PWR, 0);
+        /* USB_H1_POWER = 1 */
+        gpio_direction_output(USB_H1_POWER, 1);
+
+        imx_iomux_set_gpr_register(1, 13, 1, 0);
+
+}
+#endif
+

+ 1 - 0
common/Makefile

@@ -205,6 +205,7 @@ COBJS-$(CONFIG_UPDATE_TFTP) += update.o
 COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o
 COBJS-$(CONFIG_CMD_DFU) += cmd_dfu.o
 COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o
+COBJS-$(CONFIG_FASTBOOT) += cmd_fastboot.o
 endif
 
 ifdef CONFIG_SPL_BUILD

+ 1883 - 0
common/cmd_fastboot.c

@@ -0,0 +1,1883 @@
+/*
+ * Copyright 2008 - 2009 (C) Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright (C) 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * 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 <common.h>
+#include <command.h>
+#include <nand.h>
+#include <fastboot.h>
+#include <environment.h>
+
+#ifdef CONFIG_FASTBOOT
+
+/* Use do_reset for fastboot's 'reboot' command */
+extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+/* Use do_nand for fastboot's flash commands */
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+extern int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+#elif defined(CONFIG_FASTBOOT_STORAGE_EMMC_SATA)
+extern int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+#if defined(CONFIG_CMD_SATA)
+extern int do_sata(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+#endif
+extern env_t *env_ptr;
+#endif
+//extern int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+/* Use do_setenv and do_saveenv to permenantly save data */
+//int do_saveenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+int do_setenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+/* Use do_bootm and do_go for fastboot's 'boot' command */
+int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+
+/* Forward decl */
+static int tx_handler(void);
+static int rx_handler(const unsigned char *buffer, unsigned int buffer_size);
+static void reset_handler(void);
+
+static struct cmd_fastboot_interface interface = {
+	.rx_handler            = rx_handler,
+	.reset_handler         = reset_handler,
+	.product_name          = NULL,
+	.serial_no             = NULL,
+	.nand_block_size       = 0,
+	.transfer_buffer       = (unsigned char *)0xffffffff,
+	.transfer_buffer_size  = 0,
+};
+
+extern struct fastboot_device_info fastboot_devinfo;
+
+static unsigned int download_size;
+static unsigned int download_bytes;
+static unsigned int download_bytes_unpadded;
+static unsigned int download_error;
+static unsigned int continue_booting;
+static unsigned int upload_size;
+static unsigned int upload_bytes;
+static unsigned int upload_error;
+
+/* To support the Android-style naming of flash */
+#define MAX_PTN		    16
+#define MMC_SATA_BLOCK_SIZE 512
+
+static fastboot_ptentry ptable[MAX_PTN];
+static unsigned int pcount;
+static int static_pcount = -1;
+
+#ifdef CONFIG_FASTBOOT_STORAGE_NAND
+static void set_env(char *var, char *val)
+{
+	char *setenv[4]  = { "setenv", NULL, NULL, NULL, };
+
+	setenv[1] = var;
+	setenv[2] = val;
+
+	do_setenv(NULL, 0, 3, setenv);
+}
+
+static void save_env(struct fastboot_ptentry *ptn,
+		     char *var, char *val)
+{
+	char start[32], length[32];
+	char ecc_type[32];
+
+	char *lock[5]    = { "nand", "lock",   NULL, NULL, NULL, };
+	char *unlock[5]  = { "nand", "unlock", NULL, NULL, NULL, };
+	char *ecc[4]     = { "nand", "ecc",    NULL, NULL, };
+	char *saveenv[2] = { "setenv", NULL, };
+
+	lock[2] = unlock[2] = start;
+	lock[3] = unlock[3] = length;
+
+	set_env(var, val);
+
+	/* 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");
+		do_nand(NULL, 0, 3, ecc);
+	} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
+		sprintf(ecc_type, "sw");
+		do_nand(NULL, 0, 3, ecc);
+	}
+	sprintf(start, "0x%x", ptn->start);
+	sprintf(length, "0x%x", ptn->length);
+
+	/* This could be a problem is there is an outstanding lock */
+	do_nand(NULL, 0, 4, unlock);
+	//do_saveenv(NULL, 0, 1, saveenv);
+	do_nand(NULL, 0, 4, lock);
+}
+
+static void save_block_values(struct fastboot_ptentry *ptn,
+			      unsigned int offset,
+			      unsigned int size)
+{
+	struct fastboot_ptentry *env_ptn;
+
+	char var[64], val[32];
+	char start[32], length[32];
+	char ecc_type[32];
+
+	char *lock[5]    = { "nand", "lock",   NULL, NULL, NULL, };
+	char *unlock[5]  = { "nand", "unlock", NULL, NULL, NULL, };
+	char *ecc[4]     = { "nand", "ecc",    NULL, NULL, };
+	char *setenv[4]  = { "setenv", NULL, NULL, NULL, };
+	char *saveenv[2] = { "setenv", NULL, };
+
+	setenv[1] = var;
+	setenv[2] = val;
+	lock[2] = unlock[2] = start;
+	lock[3] = unlock[3] = length;
+
+	printf("saving it..\n");
+
+	if (size == 0) {
+		/* The error case, where the variables are being unset */
+
+		sprintf(var, "%s_nand_offset", ptn->name);
+		sprintf(val, "");
+		do_setenv(NULL, 0, 3, setenv);
+
+		sprintf(var, "%s_nand_size", ptn->name);
+		sprintf(val, "");
+		do_setenv(NULL, 0, 3, setenv);
+	} else {
+		/* Normal case */
+
+		sprintf(var, "%s_nand_offset", ptn->name);
+		sprintf(val, "0x%x", offset);
+
+		printf("%s %s %s\n", setenv[0], setenv[1], setenv[2]);
+
+		do_setenv(NULL, 0, 3, setenv);
+
+		sprintf(var, "%s_nand_size", ptn->name);
+
+		sprintf(val, "0x%x", size);
+
+		printf("%s %s %s\n", setenv[0], setenv[1], setenv[2]);
+
+		do_setenv(NULL, 0, 3, setenv);
+	}
+
+
+	/* Warning :
+	   The environment is assumed to be in a partition named 'enviroment'.
+	   It is very possible that your board stores the enviroment
+	   someplace else. */
+	env_ptn = fastboot_flash_find_ptn("environment");
+
+	if (env_ptn) {
+		/* Some flashing requires the nand's ecc to be set */
+		ecc[2] = ecc_type;
+		if ((env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) &&
+		    (env_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 (env_ptn->flags &
+			    FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) {
+			sprintf(ecc_type, "hw");
+			do_nand(NULL, 0, 3, ecc);
+		} else if (env_ptn->flags &
+			    FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
+			sprintf(ecc_type, "sw");
+			do_nand(NULL, 0, 3, ecc);
+		}
+
+		sprintf(start, "0x%x", env_ptn->start);
+		sprintf(length, "0x%x", env_ptn->length);
+
+		/* This could be a problem is there is an outstanding lock */
+		do_nand(NULL, 0, 4, unlock);
+	}
+
+	//do_saveenv(NULL, 0, 1, saveenv);
+
+	if (env_ptn)
+		do_nand(NULL, 0, 4, lock);
+}
+#else
+/* will do later */
+#endif
+
+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;
+	continue_booting = 0;
+	upload_size = 0;
+	upload_bytes = 0;
+	upload_error = 0;
+}
+
+#ifdef CONFIG_FASTBOOT_STORAGE_NAND
+/* 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;
+	unsigned int comment_start = 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) {
+
+			/*
+			 * Check for comments, comment ok only on
+			 * mostly empty lines
+			 */
+			if (buff[i] == '#')
+				comment_start = 1;
+
+			if (comment_start) {
+				if  ((buff[i] == '\r') ||
+				     (buff[i] == '\n')) {
+					comment_start = 0;
+				}
+			} else {
+				if (!((buff[i] == ' ') ||
+				      (buff[i] == '\t') ||
+				      (buff[i] == '\r') ||
+				      (buff[i] == '\n'))) {
+					/*
+					 * Normal whitespace before the
+					 * variable
+					 */
+					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 at 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 void set_ptn_ecc(struct fastboot_ptentry *ptn)
+{
+	char ecc_type[32];
+	char *ecc[4] = {"nand", "ecc", NULL, NULL, };
+
+	/* 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");
+		do_nand(NULL, 0, 3, ecc);
+	} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
+		sprintf(ecc_type, "sw");
+		do_nand(NULL, 0, 3, ecc);
+	}
+}
+
+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 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 *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");
+
+	set_ptn_ecc(ptn);
+
+	/* 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));
+
+		do_nand(NULL, 0, 4, unlock);
+		do_nand(NULL, 0, 4, erase);
+
+		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);
+
+					ret = do_nand(NULL, 0, 5, write);
+					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) {
+			/* Keep writing until you get a good block
+			   transfer_buffer should already be aligned */
+			if (interface.nand_block_size) {
+				if (0 == nand_curr_device) {
+					nand_info_t *nand;
+					unsigned long off;
+					unsigned int ok_start;
+
+					nand = &nand_info[nand_curr_device];
+
+					printf("\nDevice %d bad blocks:\n",
+					       nand_curr_device);
+
+					/* Initialize the ok_start to the
+					   start of the partition
+					   Then try to find a block large
+					   enough for the download */
+					ok_start = ptn->start;
+
+					/* It is assumed that the start and
+					   length are multiples of block size */
+					for (off = ptn->start;
+					     off < ptn->start + ptn->length;
+					     off += nand->erasesize) {
+						if (nand_block_isbad(nand, off)) {
+							/* Reset the ok_start
+							   to the next block */
+							ok_start = off +
+								nand->erasesize;
+						}
+
+						/* Check if we have enough
+						   blocks */
+						if ((ok_start - off) >=
+						    download_bytes)
+							break;
+					}
+
+					/* Check if there is enough space */
+					if (ok_start + download_bytes <=
+					    ptn->start + ptn->length) {
+						sprintf(addr,    "0x%p",
+						interface.transfer_buffer);
+						sprintf(wstart,  "0x%x", ok_start);
+						sprintf(wlength, "0x%x", download_bytes);
+
+						ret = do_nand(NULL, 0, 5, write);
+
+						/* Save the results into an
+						   environment variable on the
+						   format
+						   ptn_name + 'offset'
+						   ptn_name + 'size'  */
+						if (ret) {
+							/* failed */
+							save_block_values(ptn, 0, 0);
+						} else {
+							/* success */
+							save_block_values(ptn, ok_start, download_bytes);
+						}
+					} else {
+						printf("Error could not find enough contiguous space in partition '%s' \n", ptn->name);
+						printf("Ignoring write request\n");
+					}
+				} else {
+					/* TBD : Generalize flash handling */
+					printf("Error only handling 1 NAND per board");
+					printf("Ignoring write request\n");
+				}
+			} else {
+				printf("Warning nand block size can not be 0 \
+					when using 'continuous block' for \
+					partition '%s'\n", ptn->name);
+				printf("Ignoring write request\n");
+			}
+		} 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
+
+			ret = do_nand(NULL, 0, 5, write);
+
+			if (0 == repeat) {
+				if (ret) /* failed */
+					save_block_values(ptn, 0, 0);
+				else     /* success */
+					save_block_values(ptn, ptn->start,
+							  download_bytes);
+			}
+		}
+
+		do_nand(NULL, 0, 4, lock);
+
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+#else
+/* will do environment writing/saving later */
+#endif
+
+static int tx_handler(void)
+{
+	if (upload_size) {
+
+		int bytes_written;
+		bytes_written = fastboot_tx(interface.transfer_buffer +
+					    upload_bytes, upload_size -
+					    upload_bytes);
+		if (bytes_written > 0) {
+
+			upload_bytes += bytes_written;
+			/* Check if this is the last */
+			if (upload_bytes == upload_size) {
+
+				/* Reset upload */
+				upload_size = 0;
+				upload_bytes = 0;
+				upload_error = 0;
+			}
+		}
+	}
+	return upload_error;
+}
+
+static int rx_handler (const unsigned char *buffer, unsigned int buffer_size)
+{
+	int ret = 1, temp_len = 0;
+
+	/* Use 65 instead of 64
+	   null gets dropped
+	   strcpy's need the extra byte */
+	char response[65];
+
+	if (download_size) {
+		/* Something to download */
+
+		if (buffer_size) {
+			/* Handle possible overflow */
+			unsigned int transfer_size =
+				download_size - download_bytes;
+
+			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;
+
+				if (download_error) {
+					/* There was an earlier error */
+					sprintf(response, "ERROR");
+				} else {
+					/* Everything has transferred,
+					   send the OK response */
+					sprintf(response, "OKAY");
+				}
+				fastboot_tx_status(response, strlen(response));
+
+				printf("\ndownloading of %d bytes finished\n",
+					download_bytes);
+
+#if defined(CONFIG_FASTBOOT_STORAGE_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++;
+						}
+					}
+				}
+#endif
+			}
+
+			/* 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");
+
+			}
+		} else {
+			/* Ignore empty buffers */
+			printf("Warning empty download buffer\n");
+			printf("Ignoring\n");
+		}
+		ret = 0;
+	} else {
+		/* A command */
+
+		/* Cast to make compiler happy with string functions */
+		const char *cmdbuf = (char *) buffer;
+		printf("cmdbuf: %s\n", cmdbuf);
+
+		/* Generic failed response */
+		sprintf(response, "FAIL");
+
+		/* reboot
+		   Reboot the board. */
+
+		if (memcmp(cmdbuf, "reboot", 6) == 0) {
+			sprintf(response, "OKAY");
+			fastboot_tx_status(response, strlen(response));
+			udelay(1000000); /* 1 sec */
+
+			do_reset(NULL, 0, 0, NULL);
+
+			/* This code is unreachable,
+			   leave it to make the compiler happy */
+			return 0;
+		}
+
+		/* getvar
+		   Get common fastboot variables
+		   Board has a chance to handle other variables */
+		if (memcmp(cmdbuf, "getvar:", 7) == 0) {
+			strcpy(response, "OKAY");
+
+			temp_len = strlen("getvar:");
+			if (!strcmp(cmdbuf + temp_len, "version")) {
+				strcpy(response + 4, FASTBOOT_VERSION);
+			} else if (!strcmp(cmdbuf + temp_len,
+					     "product")) {
+				if (interface.product_name)
+					strcpy(response + 4, interface.product_name);
+
+			} else if (!strcmp(cmdbuf + temp_len,
+					     "serialno")) {
+				if (interface.serial_no)
+					strcpy(response + 4, interface.serial_no);
+
+			} else if (!strcmp(cmdbuf + temp_len,
+					    "downloadsize")) {
+				if (interface.transfer_buffer_size)
+					sprintf(response + 4, "0x%x",
+						interface.transfer_buffer_size);
+			} else {
+				fastboot_getvar(cmdbuf + 7, response + 4);
+			}
+			ret = 0;
+
+		}
+
+		/* erase
+		   Erase a register flash partition
+		   Board has to set up flash partitions */
+		if (memcmp(cmdbuf, "erase:", 6) == 0) {
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+			struct fastboot_ptentry *ptn;
+
+			ptn = fastboot_flash_find_ptn(cmdbuf + 6);
+			if (ptn == 0) {
+				sprintf(response, "FAILpartition does not exist");
+			} else {
+				char start[32], length[32];
+				int status, 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));
+
+					do_nand(NULL, 0, 4, unlock);
+					status = do_nand(NULL, 0, 4, erase);
+					do_nand(NULL, 0, 4, lock);
+
+					if (status)
+						break;
+				}
+
+				if (status) {
+					sprintf(response,
+					       "FAILfailed to erase partition");
+				} else {
+					printf("partition '%s' erased\n", ptn->name);
+					sprintf(response, "OKAY");
+				}
+			}
+			ret = 0;
+#else
+			printf("Not support erase command for EMMC\n");
+			ret = -1;
+#endif
+		}
+
+		/* download
+		   download something ..
+		   What happens to it depends on the next command after data */
+
+		if (memcmp(cmdbuf, "download:", 9) == 0) {
+
+			/* save the size */
+			download_size = simple_strtoul(cmdbuf + 9, 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);
+			}
+			ret = 0;
+		}
+
+		/* boot
+		   boot what was downloaded
+
+		   WARNING WARNING WARNING
+
+		   This is not what you expect.
+		   The fastboot client does its own packaging of the
+		   kernel.  The layout is defined in the android header
+		   file bootimage.h.  This layeout is copiedlooks like this,
+
+		   **
+		   ** +-----------------+
+		   ** | boot header     | 1 page
+		   ** +-----------------+
+		   ** | kernel          | n pages
+		   ** +-----------------+
+		   ** | ramdisk         | m pages
+		   ** +-----------------+
+		   ** | second stage    | o pages
+		   ** +-----------------+
+		   **
+
+		   We only care about the kernel.
+		   So we have to jump past a page.
+
+		   What is a page size ?
+		   The fastboot client uses 2048
+
+		   The is the default value of
+
+		   CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE
+
+		*/
+
+		if (memcmp(cmdbuf, "boot", 4) == 0) {
+
+			if ((download_bytes) &&
+			    (CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE <
+				    download_bytes)) {
+				char start[32];
+				char *booti_args[4] = {"booti",  NULL, "boot", NULL};
+
+				/*
+				 * Use this later to determine if a command line was passed
+				 * for the kernel.
+				 */
+				/* struct fastboot_boot_img_hdr *fb_hdr = */
+				/* 	(struct fastboot_boot_img_hdr *) interface.transfer_buffer; */
+
+				/* Skip the mkbootimage header */
+				/* image_header_t *hdr = */
+				/* 	(image_header_t *) */
+				/* 	&interface.transfer_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE]; */
+
+				booti_args[1] = start;
+				sprintf(start, "0x%x", (unsigned int)interface.transfer_buffer);
+
+				/* Execution should jump to kernel so send the response
+				   now and wait a bit.  */
+				sprintf(response, "OKAY");
+				fastboot_tx_status(response, strlen(response));
+
+				printf("Booting kernel...\n");
+
+
+				/* Reserve for further use, this can
+				 * be more convient for developer. */
+				/* if (strlen ((char *) &fb_hdr->cmdline[0])) */
+				/* 	set_env("bootargs", (char *) &fb_hdr->cmdline[0]); */
+
+				/* boot the boot.img */
+				//do_booti(NULL, 0, 3, booti_args);
+
+
+			}
+			sprintf(response, "FAILinvalid boot image");
+			ret = 0;
+		}
+
+		/* flash
+		   Flash what was downloaded */
+
+		if (memcmp(cmdbuf, "flash:", 6) == 0) {
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+			if (download_bytes) {
+				struct fastboot_ptentry *ptn;
+
+				ptn = fastboot_flash_find_ptn(cmdbuf + 6);
+				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");
+			}
+#elif defined(CONFIG_FASTBOOT_STORAGE_EMMC_SATA)
+			if (download_bytes) {
+				struct fastboot_ptentry *ptn;
+
+				/* Next is the partition name */
+				ptn = fastboot_flash_find_ptn(cmdbuf + 6);
+				if (ptn == 0) {
+					printf("Partition:'%s' does not exist\n", ptn->name);
+					sprintf(response, "FAILpartition does not exist");
+				} else if ((download_bytes >
+					   ptn->length * MMC_SATA_BLOCK_SIZE) &&
+						!(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) {
+					/* Check if this is not really a flash write,
+					 * but instead a saveenv
+					 */
+					unsigned int i = 0;
+					/* Env file is expected with a NULL delimeter between
+					 * env variables So replace New line Feeds (0x0a) with
+					 * NULL (0x00)
+					 */
+					printf("Goto write env, flags=0x%x\n",
+						    ptn->flags);
+					for (i = 0; i < download_bytes; i++) {
+						if (interface.transfer_buffer[i] == 0x0a)
+							interface.transfer_buffer[i] = 0x00;
+					}
+					memset(env_ptr->data, 0, ENV_SIZE);
+					memcpy(env_ptr->data, interface.transfer_buffer, download_bytes);
+					//do_saveenv(NULL, 0, 1, NULL);
+					printf("saveenv to '%s' DONE!\n", ptn->name);
+					sprintf(response, "OKAY");
+				} else {
+					char source[32], dest[32];
+					char length[32], slot_no[32];
+					char part_no[32];
+					unsigned int temp;
+
+					/* Normal case */
+					if (fastboot_devinfo.type == DEV_MMC)
+						/* download to mmc */
+						goto mmc_ops;
+					else {
+						/* downaload to sata */
+#ifdef CONFIG_CMD_SATA
+					char *sata_write[5] = {"sata", "write",
+						NULL, NULL, NULL};
+
+					sata_write[2] = source;
+					sata_write[3] = dest;
+					sata_write[4] = length;
+
+					sprintf(source, "0x%x",
+						 (unsigned int)interface.transfer_buffer);
+					/* block offset */
+					sprintf(dest, "0x%x", ptn->start);
+					/* block count */
+					temp = (download_bytes +
+						MMC_SATA_BLOCK_SIZE - 1) /
+							MMC_SATA_BLOCK_SIZE;
+					sprintf(length, "0x%x", temp);
+					if (do_sata(NULL, 0, 5, sata_write)) {
+						printf("Writing '%s' FAILED!\n",
+							 ptn->name);
+						sprintf(response,
+						       "FAIL: Write partition");
+					} else {
+						printf("Writing '%s' DONE!\n",
+							ptn->name);
+						sprintf(response, "OKAY");
+						ret = 0;
+					}
+#else
+					sprintf(response, "FAIL: Not support");
+#endif
+					fastboot_tx_status(response,
+							    strlen(response));
+					return ret; /* End of sata download */
+				}
+
+mmc_ops:
+					printf("writing to partition '%s'\n", ptn->name);
+					char *mmc_write[5] = {"mmc", "write",
+						NULL, NULL, NULL};
+					char *mmc_dev[4] = {"mmc", "dev", NULL, NULL};
+
+					mmc_dev[2] = slot_no;
+					mmc_dev[3] = part_no;
+					mmc_write[2] = source;
+					mmc_write[3] = dest;
+					mmc_write[4] = length;
+
+					sprintf(slot_no, "%d",
+						    fastboot_devinfo.dev_id);
+					sprintf(source, "0x%x", (unsigned int)interface.transfer_buffer);
+					/* partition no */
+					sprintf(part_no, "%d",
+						    ptn->partition_id);
+					/* block offset */
+					sprintf(dest, "0x%x", ptn->start);
+					/* block count */
+					temp = (download_bytes +
+						    MMC_SATA_BLOCK_SIZE - 1) /
+						    MMC_SATA_BLOCK_SIZE;
+					sprintf(length, "0x%x", temp);
+
+					printf("Initializing '%s'\n", ptn->name);
+					if(1)
+					//if (do_mmcops(NULL, 0, 4, mmc_dev))
+						sprintf(response, "FAIL:Init of MMC card");
+					else
+						sprintf(response, "OKAY");
+
+					printf("Writing '%s'\n", ptn->name);
+					if(1) {
+					//if (do_mmcops(NULL, 0, 5, mmc_write)) {
+						printf("Writing '%s' FAILED!\n", ptn->name);
+						sprintf(response, "FAIL: Write partition");
+					} else {
+						printf("Writing '%s' DONE!\n", ptn->name);
+						sprintf(response, "OKAY");
+					}
+				}
+
+		} else {
+			sprintf(response, "FAILno image downloaded");
+		}
+#endif
+			ret = 0;
+		}
+
+		/* continue
+		   Stop doing fastboot */
+		if (memcmp(cmdbuf, "continue", 8) == 0) {
+			sprintf(response, "OKAY");
+			continue_booting = 1;
+			ret = 0;
+		}
+
+		/* upload
+		   Upload just the data in a partition */
+		if ((memcmp(cmdbuf, "upload:", 7) == 0) ||
+		    (memcmp(cmdbuf, "uploadraw:", 10) == 0)) {
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+			unsigned int adv, delim_index, len;
+			struct fastboot_ptentry *ptn;
+			unsigned int is_raw = 0;
+
+			/* Is this a raw read ? */
+			if (memcmp(cmdbuf, "uploadraw:", 10) == 0) {
+				is_raw = 1;
+				adv = 10;
+			} else {
+				adv = 7;
+			}
+
+			/* Scan to the next ':' to find when the size starts */
+			len = strlen(cmdbuf);
+			for (delim_index = adv;
+			     delim_index < len; delim_index++) {
+				if (cmdbuf[delim_index] == ':') {
+					/* WARNING, cmdbuf is being modified. */
+					*((char *) &cmdbuf[delim_index]) = 0;
+					break;
+				}
+			}
+
+			ptn = fastboot_flash_find_ptn(cmdbuf + adv);
+			if (ptn == 0) {
+				sprintf(response,
+					"FAILpartition does not exist");
+			} else {
+				/* This is how much the user is expecting */
+				unsigned int user_size;
+				/*
+				 * This is the maximum size needed for
+				 * this partition
+				 */
+				unsigned int size;
+				/* This is the length of the data */
+				unsigned int length;
+				/*
+				 * Used to check previous write of
+				 * the parition
+				 */
+				char env_ptn_length_var[128];
+				char *env_ptn_length_val;
+
+				user_size = 0;
+				if (delim_index < len)
+					user_size =
+					  simple_strtoul(cmdbuf + delim_index +
+							 1, NULL, 16);
+
+				/* Make sure output is padded to block size */
+				length = ptn->length;
+				sprintf(env_ptn_length_var,
+					"%s_nand_size", ptn->name);
+				env_ptn_length_val = getenv(env_ptn_length_var);
+				if (env_ptn_length_val) {
+					length =
+					  simple_strtoul(env_ptn_length_val,
+							 NULL, 16);
+					/* Catch possible problems */
+					if (!length)
+						length = ptn->length;
+				}
+
+				size = length / interface.nand_block_size;
+				size *= interface.nand_block_size;
+				if (length % interface.nand_block_size)
+					size += interface.nand_block_size;
+
+				if (is_raw)
+					size += (size /
+						 interface.nand_block_size) *
+						interface.nand_oob_size;
+
+				if (size > interface.transfer_buffer_size) {
+
+					sprintf(response, "FAILdata too large");
+
+				} else if (user_size == 0) {
+
+					/* Send the data response */
+					sprintf(response, "DATA%08x", size);
+
+				} else if (user_size != size) {
+					/* This is the wrong size */
+					sprintf(response, "FAIL");
+				} else {
+					/*
+					 * This is where the transfer
+					 * buffer is populated
+					 */
+					unsigned char *buf =
+					  interface.transfer_buffer;
+					char start[32], length[32], type[32],
+					  addr[32];
+					char *read[6] = { "nand", NULL, NULL,
+							  NULL, NULL, NULL, };
+
+					/*
+					 * Setting upload_size causes
+					 * transfer to happen in main loop
+					 */
+					upload_size = size;
+					upload_bytes = 0;
+					upload_error = 0;
+
+					/*
+					 * Poison the transfer buffer, 0xff
+					 * is erase value of nand
+					 */
+					memset(buf, 0xff, upload_size);
+
+					/* Which flavor of read to use */
+					if (is_raw)
+						sprintf(type, "read.raw");
+					else
+						sprintf(type, "read.i");
+
+					sprintf(addr, "0x%x",
+						interface.transfer_buffer);
+					sprintf(start, "0x%x", ptn->start);
+					sprintf(length, "0x%x", upload_size);
+
+					read[1] = type;
+					read[2] = addr;
+					read[3] = start;
+					read[4] = length;
+
+					set_ptn_ecc(ptn);
+
+					do_nand(NULL, 0, 5, read);
+
+					/* Send the data response */
+					sprintf(response, "DATA%08x", size);
+				}
+			}
+#endif
+			ret = 0;
+		}
+
+		fastboot_tx_status(response, strlen(response));
+
+	} /* End of command */
+
+	return ret;
+}
+
+static int check_against_static_partition(struct fastboot_ptentry *ptn)
+{
+	int ret = 0;
+	struct fastboot_ptentry *c;
+	int i;
+
+	for (i = 0; i < static_pcount; i++) {
+		c = fastboot_flash_get_ptn((unsigned int) i);
+
+		if (0 == ptn->length)
+			break;
+
+		if ((ptn->start >= c->start) &&
+		    (ptn->start < c->start + c->length))
+			break;
+
+		if ((ptn->start + ptn->length > c->start) &&
+		    (ptn->start + ptn->length <= c->start + c->length))
+			break;
+
+		if ((0 == strcmp(ptn->name, c->name)) &&
+		    (0 == strcmp(c->name, ptn->name)))
+			break;
+	}
+
+	if (i >= static_pcount)
+		ret = 1;
+	return ret;
+}
+
+static unsigned long long memparse(char *ptr, char **retptr)
+{
+	char *endptr;	/* local pointer to end of parsed string */
+
+	unsigned long ret = simple_strtoul(ptr, &endptr, 0);
+
+	switch (*endptr) {
+	case 'M':
+	case 'm':
+		ret <<= 10;
+	case 'K':
+	case 'k':
+		ret <<= 10;
+		endptr++;
+	default:
+		break;
+	}
+
+	if (retptr)
+		*retptr = endptr;
+
+	return ret;
+}
+
+static int add_partition_from_environment(char *s, char **retptr)
+{
+	unsigned long size;
+	unsigned long offset = 0;
+	char *name;
+	int name_len;
+	int delim;
+	unsigned int flags;
+	struct fastboot_ptentry part;
+
+	size = memparse(s, &s);
+	if (0 == size) {
+		printf("Error:FASTBOOT size of parition is 0\n");
+		return 1;
+	}
+
+	/* fetch partition name and flags */
+	flags = 0; /* this is going to be a regular partition */
+	delim = 0;
+	/* check for offset */
+	if (*s == '@') {
+		s++;
+		offset = memparse(s, &s);
+	} else {
+		printf("Error:FASTBOOT offset of parition is not given\n");
+		return 1;
+	}
+
+	/* now look for name */
+	if (*s == '(')
+		delim = ')';
+
+	if (delim) {
+		char *p;
+
+		name = ++s;
+		p = strchr((const char *)name, delim);
+		if (!p) {
+			printf("Error:FASTBOOT no closing %c found in partition name\n", delim);
+			return 1;
+		}
+		name_len = p - name;
+		s = p + 1;
+	} else {
+		printf("Error:FASTBOOT no partition name for \'%s\'\n", s);
+		return 1;
+	}
+
+	/* test for options */
+	while (1) {
+		if (strncmp(s, "i", 1) == 0) {
+			flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_I;
+			s += 1;
+		} else if (strncmp(s, "yaffs", 5) == 0) {
+			/* yaffs */
+			flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS;
+			s += 5;
+		} else if (strncmp(s, "swecc", 5) == 0) {
+			/* swecc */
+			flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC;
+			s += 5;
+		} else if (strncmp(s, "hwecc", 5) == 0) {
+			/* hwecc */
+			flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC;
+			s += 5;
+		} else {
+			break;
+		}
+		if (strncmp(s, "|", 1) == 0)
+			s += 1;
+	}
+
+	/* enter this partition (offset will be calculated later if it is zero at this point) */
+	part.length = size;
+	part.start = offset;
+	part.flags = flags;
+
+	if (name) {
+		if (name_len >= sizeof(part.name)) {
+			printf("Error:FASTBOOT partition name is too long\n");
+			return 1;
+		}
+		strncpy(&part.name[0], name, name_len);
+		/* name is not null terminated */
+		part.name[name_len] = '\0';
+	} else {
+		printf("Error:FASTBOOT no name\n");
+		return 1;
+	}
+
+
+	/* Check if this overlaps a static partition */
+	if (check_against_static_partition(&part)) {
+		printf("Adding: %s, offset 0x%8.8x, size 0x%8.8x, flags 0x%8.8x\n",
+		       part.name, part.start, part.length, part.flags);
+		fastboot_flash_add_ptn(&part);
+	}
+
+	/* return (updated) pointer command line string */
+	*retptr = s;
+
+	/* return partition table */
+	return 0;
+}
+
+
+
+int do_fastboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int ret = 1;
+	char fbparts[4096], *env;
+	int check_timeout = 0;
+	uint64_t timeout_endtime = 0;
+	uint64_t timeout_ticks = 1000;
+	long timeout_seconds = -1;
+	int continue_from_disconnect = 0;
+
+	/*
+	 * Place the runtime partitions at the end of the
+	 * static paritions.  First save the start off so
+	 * it can be saved from run to run.
+	 */
+	if (static_pcount >= 0) {
+		/* Reset */
+		pcount = static_pcount;
+	} else {
+		/* Save */
+		static_pcount = pcount;
+	}
+	env = getenv("fbparts");
+	if (env) {
+		unsigned int len;
+		len = strlen(env);
+		if (len && len < 4096) {
+			char *s, *e;
+
+			memcpy(&fbparts[0], env, len + 1);
+			printf("Fastboot: Adding partitions from environment\n");
+			s = &fbparts[0];
+			e = s + len;
+			while (s < e) {
+				if (add_partition_from_environment(s, &s)) {
+					printf("Error:Fastboot: Abort adding partitions\n");
+					/* reset back to static */
+					pcount = static_pcount;
+					break;
+				}
+				/* Skip a bunch of delimiters */
+				while (s < e) {
+					if ((' ' == *s) ||
+					    ('\t' == *s) ||
+					    ('\n' == *s) ||
+					    ('\r' == *s) ||
+					    (',' == *s)) {
+						s++;
+					} else {
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	/* Time out */
+	if (2 == argc) {
+		long try_seconds;
+		char *try_seconds_end;
+
+		if (argv[1][0] == 'q') {
+			if ((argv[1][1] >= '0') && (argv[1][1] <= '2'))
+				fastboot_quick(argv[1][1] - '0');
+			else
+				fastboot_quick(0);
+		}
+
+
+		/* Check for timeout */
+		try_seconds = simple_strtol(argv[1],
+					    &try_seconds_end, 10);
+		if ((try_seconds_end != argv[1]) &&
+		    (try_seconds >= 0)) {
+			check_timeout = 1;
+			timeout_seconds = try_seconds;
+			printf("Fastboot inactivity timeout %ld seconds\n", timeout_seconds);
+		}
+	}
+
+	do {
+		continue_from_disconnect = 0;
+
+		/* Initialize the board specific support */
+		if (0 == fastboot_init(&interface)) {
+
+			int poll_status;
+
+			/* If we got this far, we are a success */
+			ret = 0;
+			printf("fastboot initialized\n");
+
+			timeout_endtime = get_timer(0);
+			timeout_endtime += timeout_ticks;
+
+			while (1) {
+				uint64_t current_time = 0;
+				poll_status = fastboot_poll();
+
+				if (1 == check_timeout)
+					current_time = get_timer(0);
+
+				if (FASTBOOT_ERROR == poll_status) {
+					/* Error */
+					break;
+				} else if (FASTBOOT_DISCONNECT == poll_status) {
+					/* beak, cleanup and re-init */
+					printf("Fastboot disconnect detected\n");
+					continue_from_disconnect = 1;
+					break;
+				} else if ((1 == check_timeout) &&
+					   (FASTBOOT_INACTIVE == poll_status)) {
+
+					/* No activity */
+					if (current_time >= timeout_endtime) {
+						printf("Fastboot inactivity detected\n");
+						break;
+					}
+				} else {
+					/* Something happened */
+					if (1 == check_timeout) {
+						/* Update the timeout endtime */
+						timeout_endtime = current_time;
+						timeout_endtime += timeout_ticks;
+					}
+				}
+
+				/* Check if the user wanted to terminate with ^C */
+				if ((FASTBOOT_INACTIVE == poll_status) &&
+				    (ctrlc())) {
+					printf("Fastboot ended by user\n");
+					break;
+				}
+
+				/*
+				 * Check if the fastboot client wanted to
+				 * continue booting
+				 */
+				if (continue_booting) {
+					printf("Fastboot ended by client\n");
+					break;
+				}
+
+				/* Check if there is something to upload */
+				tx_handler();
+			}
+		}
+
+		/* Reset the board specific support */
+		fastboot_shutdown();
+
+		/* restart the loop if a disconnect was detected */
+	} while (continue_from_disconnect);
+
+	return ret;
+}
+
+U_BOOT_CMD(
+	fastboot,	2,	1,	do_fastboot,
+	"fastboot- use USB Fastboot protocol\n",
+	"[inactive timeout]\n"
+	"    - Run as a fastboot usb device.\n"
+	"    - The optional inactive timeout is the decimal seconds before\n"
+	"    - the normal console resumes\n"
+);
+
+
+/*
+ * Android style flash utilties */
+void fastboot_flash_add_ptn(fastboot_ptentry *ptn)
+{
+	if (pcount < MAX_PTN) {
+		memcpy(ptable + pcount, ptn, sizeof(fastboot_ptentry));
+		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;
+		}
+	}
+
+	printf("can't find partition: %s, dump the partition table\n", name);
+	fastboot_flash_dump_ptn();
+	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;
+}
+
+int fastboot_write_storage(u8 *partition_name, u32 write_len)
+{
+	struct fastboot_ptentry *ptn;
+	u32 storage_len = 0;
+
+	if (0 == write_len) {
+		DBG_ERR("WriteMMC with 0 lenght\n");
+		return -1;
+	}
+
+	ptn = fastboot_flash_find_ptn((const char *)partition_name);
+	if (!ptn) {
+		DBG_ERR("Partition:'%s' does not exist\n", partition_name);
+		return -1;
+	}
+
+	if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
+		DBG_ERR("ENV Write, None image partition, failed\n");
+		return -1;
+	}
+
+	DBG_DEBUG("PTN name=%s, start=0x%x, len=0x%x, flags=0x%x, id=0x%x\n",
+	ptn->name, ptn->start, ptn->length, ptn->flags, ptn->partition_id);
+
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+	storage_len = ptn->length;
+#elif defined(CONFIG_FASTBOOT_STORAGE_EMMC_SATA)
+	storage_len = ptn->length * MMC_SATA_BLOCK_SIZE;
+#endif
+
+	if (write_len > storage_len) {
+		DBG_ERR("Write len big than part volume. 0x%x:0x%x\n",
+						write_len, storage_len);
+		return -1;
+	}
+
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+	DBG_ALWS("Writing nand %s...", ptn->name);
+	download_bytes_unpadded = download_bytes = write_len;
+	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++;
+			}
+		}
+	}
+
+	if (write_to_ptn(ptn)) {
+		DBG_ERR("Write to nand %s failed\n", ptn->name);
+		return -1;
+	} else {
+		DBG_ALWS("Write to nand %s done\n", ptn->name);
+		return write_len;
+	}
+#elif defined(CONFIG_FASTBOOT_STORAGE_EMMC_SATA)
+{
+    char source[32], dest[32], length[32];
+    char part_no[32], slot_no[32];
+    unsigned int temp;
+
+    char *mmc_write[5] = {"mmc", "write", source, dest, length};
+    char *mmc_dev[4] = {"mmc", "dev", slot_no, part_no};
+
+    memset(source,  0, sizeof(source));
+    memset(dest,    0, sizeof(dest));
+    memset(length,  0, sizeof(length));
+    memset(part_no, 0, sizeof(part_no));
+    memset(slot_no, 0, sizeof(slot_no));
+
+    sprintf(slot_no, "%d", fastboot_devinfo.dev_id);
+    sprintf(part_no, "%d", ptn->partition_id);
+
+    DBG_ALWS("Init MMC%s(%s)...\n", slot_no,  ptn->name);
+    if(0) {
+    //if (do_mmcops(NULL, 0, 4, mmc_dev)) {
+	DBG_ERR("MMC%s(%s) init fail\n", slot_no, ptn->name);
+	return -1;
+    } else {
+	DBG_ALWS("MMC%s(%s) init done\n", slot_no, ptn->name);
+    }
+
+    sprintf(source, "0x%x", CONFIG_FASTBOOT_TRANSFER_BUF);
+    sprintf(dest, "0x%x", ptn->start);
+    temp = (write_len + MMC_SATA_BLOCK_SIZE - 1) / MMC_SATA_BLOCK_SIZE;
+    sprintf(length, "0x%x", temp);
+
+    DBG_ALWS("Writing MMC%s(%s), %u blocks...", slot_no, ptn->name, temp);
+
+    if(0) {
+    //if (do_mmcops(NULL, 0, 5, mmc_write)) {
+	DBG_ERR("MMC%s(%s) write fail\n", slot_no, ptn->name);
+	return -1;
+    } else {
+	DBG_ALWS("MMC%s(%s) write done\n", slot_no, ptn->name);
+	return write_len;
+    }
+}
+#endif
+}
+
+#endif	/* CONFIG_FASTBOOT */

+ 47 - 0
drivers/fastboot/Makefile

@@ -0,0 +1,47 @@
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	:= $(obj)libfastboot.o
+
+# ohci
+COBJS-$(CONFIG_FASTBOOT) += fastboot.o
+
+COBJS	:= $(COBJS-y)
+SRCS	:= $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+
+all:	$(LIB)
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################

+ 950 - 0
drivers/fastboot/fastboot.c

@@ -0,0 +1,950 @@
+/*
+ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc.
+ *
+ * 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 <common.h>
+#include <config.h>
+#include <malloc.h>
+#include <fastboot.h>
+#include <usb/imx_udc.h>
+#include <asm/io.h>
+#include <usbdevice.h>
+#include <mmc.h>
+#include <sata.h>
+
+/*
+ * Defines
+ */
+#define NUM_ENDPOINTS  2
+
+#define CONFIG_USBD_OUT_PKTSIZE	    0x200
+#define CONFIG_USBD_IN_PKTSIZE	    0x200
+#define MAX_BUFFER_SIZE		    0x200
+
+/*
+ * imx family android layout
+ * mbr -  0 ~ 0x3FF byte
+ * bootloader - 0x400 ~ 0xFFFFF byte
+ * kernel - 0x100000 ~ 5FFFFF byte
+ * uramedisk - 0x600000 ~ 0x6FFFFF  supposing 1M temporarily
+ * SYSTEM partition - /dev/mmcblk0p2  or /dev/sda2
+ * RECOVERY parittion - dev/mmcblk0p4 or /dev/sda4
+ */
+#define ANDROID_MBR_OFFSET	    0
+#define ANDROID_MBR_SIZE	    0x200
+#define ANDROID_BOOTLOADER_OFFSET   0x400
+#define ANDROID_BOOTLOADER_SIZE	    0xFFC00
+#define ANDROID_KERNEL_OFFSET	    0x100000
+#define ANDROID_KERNEL_SIZE	    0x500000
+#define ANDROID_URAMDISK_OFFSET	    0x600000
+#define ANDROID_URAMDISK_SIZE	    0x100000
+
+#define STR_LANG_INDEX		    0x00
+#define STR_MANUFACTURER_INDEX	    0x01
+#define STR_PRODUCT_INDEX	    0x02
+#define STR_SERIAL_INDEX	    0x03
+#define STR_CONFIG_INDEX	    0x04
+#define STR_DATA_INTERFACE_INDEX    0x05
+#define STR_CTRL_INTERFACE_INDEX    0x06
+#define STR_COUNT		    0x07
+
+/*pentry index internally*/
+enum {
+    PTN_MBR_INDEX = 0,
+    PTN_BOOTLOADER_INDEX,
+    PTN_KERNEL_INDEX,
+    PTN_URAMDISK_INDEX,
+    PTN_SYSTEM_INDEX,
+    PTN_RECOVERY_INDEX
+};
+
+struct fastboot_device_info fastboot_devinfo;
+
+/* defined and used by gadget/ep0.c */
+extern struct usb_string_descriptor **usb_strings;
+
+static struct usb_device_instance device_instance[1];
+static struct usb_bus_instance bus_instance[1];
+static struct usb_configuration_instance config_instance[1];
+static struct usb_interface_instance interface_instance[1];
+static struct usb_alternate_instance alternate_instance[1];
+/* one extra for control endpoint */
+static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1];
+
+static struct cmd_fastboot_interface *fastboot_interface;
+static int fastboot_configured_flag;
+static int usb_disconnected;
+
+/* Indicies, References */
+static u8 rx_endpoint;
+static u8 tx_endpoint;
+static struct usb_string_descriptor *fastboot_string_table[STR_COUNT];
+
+/* USB Descriptor Strings */
+static u8 wstrLang[4] = {4, USB_DT_STRING, 0x9, 0x4};
+static u8 wstrManufacturer[2 * (sizeof(CONFIG_FASTBOOT_MANUFACTURER_STR))];
+static u8 wstrProduct[2 * (sizeof(CONFIG_FASTBOOT_PRODUCT_NAME_STR))];
+static u8 wstrSerial[2*(sizeof(CONFIG_FASTBOOT_SERIAL_NUM))];
+static u8 wstrConfiguration[2 * (sizeof(CONFIG_FASTBOOT_CONFIGURATION_STR))];
+static u8 wstrDataInterface[2 * (sizeof(CONFIG_FASTBOOT_INTERFACE_STR))];
+
+/* Standard USB Data Structures */
+static struct usb_interface_descriptor interface_descriptors[1];
+static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS];
+static struct usb_configuration_descriptor *configuration_descriptor;
+static struct usb_device_descriptor device_descriptor = {
+	.bLength = sizeof(struct usb_device_descriptor),
+	.bDescriptorType =	USB_DT_DEVICE,
+	.bcdUSB =		cpu_to_le16(USB_BCD_VERSION),
+	.bDeviceClass =		0xff,
+	.bDeviceSubClass =	0xff,
+	.bDeviceProtocol =	0xff,
+	.bMaxPacketSize0 =	0x40,
+	.idVendor =		cpu_to_le16(CONFIG_FASTBOOT_VENDOR_ID),
+	.idProduct =		cpu_to_le16(CONFIG_FASTBOOT_PRODUCT_ID),
+	.bcdDevice =		cpu_to_le16(CONFIG_FASTBOOT_BCD_DEVICE),
+	.iManufacturer =	STR_MANUFACTURER_INDEX,
+	.iProduct =		STR_PRODUCT_INDEX,
+	.iSerialNumber =	STR_SERIAL_INDEX,
+	.bNumConfigurations =	1
+};
+
+/*
+ * Static Generic Serial specific data
+ */
+
+struct fastboot_config_desc {
+	struct usb_configuration_descriptor configuration_desc;
+	struct usb_interface_descriptor	interface_desc[1];
+	struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS];
+
+} __attribute__((packed));
+
+static struct fastboot_config_desc
+fastboot_configuration_descriptors[1] = {
+	{
+		.configuration_desc = {
+			.bLength = sizeof(struct usb_configuration_descriptor),
+			.bDescriptorType = USB_DT_CONFIG,
+			.wTotalLength =
+			    cpu_to_le16(sizeof(struct fastboot_config_desc)),
+			.bNumInterfaces = 1,
+			.bConfigurationValue = 1,
+			.iConfiguration = STR_CONFIG_INDEX,
+			.bmAttributes =
+				BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
+			.bMaxPower = 0x32
+		},
+		.interface_desc = {
+			{
+				.bLength  =
+					sizeof(struct usb_interface_descriptor),
+				.bDescriptorType = USB_DT_INTERFACE,
+				.bInterfaceNumber = 0,
+				.bAlternateSetting = 0,
+				.bNumEndpoints = NUM_ENDPOINTS,
+				.bInterfaceClass =
+					FASTBOOT_INTERFACE_CLASS,
+				.bInterfaceSubClass =
+					FASTBOOT_INTERFACE_SUB_CLASS,
+				.bInterfaceProtocol =
+					FASTBOOT_INTERFACE_PROTOCOL,
+				.iInterface = STR_DATA_INTERFACE_INDEX
+			},
+		},
+		.data_endpoints  = {
+			{
+				.bLength =
+					sizeof(struct usb_endpoint_descriptor),
+				.bDescriptorType =  USB_DT_ENDPOINT,
+				.bEndpointAddress = UDC_OUT_ENDPOINT |
+							 USB_DIR_OUT,
+				.bmAttributes =	USB_ENDPOINT_XFER_BULK,
+				.wMaxPacketSize =
+					cpu_to_le16(CONFIG_USBD_OUT_PKTSIZE),
+				.bInterval = 0x00,
+			},
+			{
+				.bLength =
+					sizeof(struct usb_endpoint_descriptor),
+				.bDescriptorType =  USB_DT_ENDPOINT,
+				.bEndpointAddress = UDC_IN_ENDPOINT |
+							USB_DIR_IN,
+				.bmAttributes =	USB_ENDPOINT_XFER_BULK,
+				.wMaxPacketSize =
+					cpu_to_le16(CONFIG_USBD_IN_PKTSIZE),
+				.bInterval = 0x00,
+			},
+		},
+	},
+};
+
+/* Static Function Prototypes */
+static void fastboot_init_strings(void);
+static void fastboot_init_instances(void);
+static void fastboot_init_endpoints(void);
+static void fastboot_event_handler(struct usb_device_instance *device,
+				usb_device_event_t event, int data);
+static int fastboot_cdc_setup(struct usb_device_request *request,
+				struct urb *urb);
+static int fastboot_usb_configured(void);
+#ifdef CONFIG_FASTBOOT_STORAGE_EMMC_SATA
+static int fastboot_init_mmc_sata_ptable(void);
+#endif
+
+/* utility function for converting char* to wide string used by USB */
+static void str2wide(char *str, u16 * wide)
+{
+	int i;
+	for (i = 0; i < strlen(str) && str[i]; i++) {
+		#if defined(__LITTLE_ENDIAN)
+			wide[i] = (u16) str[i];
+		#elif defined(__BIG_ENDIAN)
+			wide[i] = ((u16)(str[i])<<8);
+		#else
+			#error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined"
+		#endif
+	}
+}
+
+/*
+   Get mmc control number from passed string, eg, "mmc1" mean device 1. Only
+   support "mmc0" to "mmc9" currently. It will be treated as device 0 for
+   other string.
+*/
+static int get_mmc_no(char *env_str)
+{
+	int digit = 0;
+	unsigned char a;
+
+	if (env_str && (strlen(env_str) >= 4) &&
+	    !strncmp(env_str, "mmc", 3)) {
+		a = env_str[3];
+		if (a >= '0' && a <= '9')
+			digit = a - '0';
+	}
+
+	return digit;
+}
+
+/*
+ * Initialize fastboot
+ */
+int fastboot_init(struct cmd_fastboot_interface *interface)
+{
+	printf("fastboot is in init......");
+	fastboot_interface = interface;
+	fastboot_interface->product_name = CONFIG_FASTBOOT_PRODUCT_NAME_STR;
+	fastboot_interface->serial_no = CONFIG_FASTBOOT_SERIAL_NUM;
+	fastboot_interface->nand_block_size = 4096;
+	fastboot_interface->transfer_buffer =
+				(unsigned char *)CONFIG_FASTBOOT_TRANSFER_BUF;
+	fastboot_interface->transfer_buffer_size =
+				CONFIG_FASTBOOT_TRANSFER_BUF_SIZE;
+	fastboot_init_strings();
+	/* Basic USB initialization */
+	udc_init();
+
+	fastboot_init_instances();
+#ifdef CONFIG_FASTBOOT_STORAGE_EMMC_SATA
+	fastboot_init_mmc_sata_ptable();
+#endif
+	udc_startup_events(device_instance);
+	udc_connect();		/* Enable pullup for host detection */
+
+	return 0;
+}
+
+#ifdef CONFIG_FASTBOOT_STORAGE_EMMC_SATA
+/**
+   @mmc_dos_partition_index: the partition index in mbr.
+   @mmc_partition_index: the boot partition or user partition index,
+   not related to the partition table.
+ */
+static int setup_ptable_mmc_partition(int ptable_index,
+				      int mmc_dos_partition_index,
+				      int mmc_partition_index,
+				      const char *name,
+				      block_dev_desc_t *dev_desc,
+				      fastboot_ptentry *ptable)
+{
+	disk_partition_t info;
+	strcpy(ptable[ptable_index].name, name);
+
+	if (get_partition_info(dev_desc,
+			       mmc_dos_partition_index, &info)) {
+		printf("Bad partition index:%d for partition:%s\n",
+		       mmc_dos_partition_index, name);
+		return -1;
+	} else {
+		ptable[ptable_index].start = info.start;
+		ptable[ptable_index].length = info.size;
+		ptable[ptable_index].partition_id = mmc_partition_index;
+	}
+	return 0;
+}
+
+static int fastboot_init_mmc_sata_ptable(void)
+{
+	int i;
+#ifdef CONFIG_CMD_SATA
+	int sata_device_no;
+#endif
+	int boot_partition = -1, user_partition = -1;
+	/* mmc boot partition: -1 means no partition, 0 user part., 1 boot part.
+	 * default is no partition, for emmc default user part, except emmc*/
+	struct mmc *mmc;
+	block_dev_desc_t *dev_desc;
+	char *fastboot_env;
+	fastboot_ptentry ptable[PTN_RECOVERY_INDEX + 1];
+
+	fastboot_env = getenv("fastboot_dev");
+	/* sata case in env */
+	if (fastboot_env && !strcmp(fastboot_env, "sata")) {
+		fastboot_devinfo.type = DEV_SATA;
+#ifdef CONFIG_CMD_SATA
+		puts("flash target is SATA\n");
+		if (sata_initialize())
+			return -1;
+		sata_device_no = CONFIG_FASTBOOT_SATA_NO;
+		if (sata_device_no >= CONFIG_SYS_SATA_MAX_DEVICE) {
+			printf("Unknown SATA(%d) device for fastboot\n",
+				sata_device_no);
+			return -1;
+		}
+		dev_desc = sata_get_dev(sata_device_no);
+#else
+		puts("SATA isn't buildin\n");
+		return -1;
+#endif
+	} else {
+		int mmc_no = 0;
+
+		mmc_no = get_mmc_no(fastboot_env);
+
+		fastboot_devinfo.type = DEV_MMC;
+		fastboot_devinfo.dev_id = mmc_no;
+
+		printf("flash target is MMC:%d\n", mmc_no);
+		mmc = find_mmc_device(mmc_no);
+		if (mmc && mmc_init(mmc))
+			printf("MMC card init failed!\n");
+
+		dev_desc = get_dev("mmc", mmc_no);
+		if (NULL == dev_desc) {
+			printf("** Block device MMC %d not supported\n",
+				mmc_no);
+			return -1;
+		}
+
+		/* multiple boot paritions for eMMC 4.3 later */
+		if (mmc->part_config != MMCPART_NOAVAILABLE) {
+			boot_partition = 1;
+			user_partition = 0;
+		}
+	}
+
+	memset((char *)ptable, 0,
+		    sizeof(fastboot_ptentry) * (PTN_RECOVERY_INDEX + 1));
+	/* MBR */
+	strcpy(ptable[PTN_MBR_INDEX].name, "mbr");
+	ptable[PTN_MBR_INDEX].start = ANDROID_MBR_OFFSET / dev_desc->blksz;
+	ptable[PTN_MBR_INDEX].length = ANDROID_MBR_SIZE / dev_desc->blksz;
+	ptable[PTN_MBR_INDEX].partition_id = user_partition;
+	/* Bootloader */
+	strcpy(ptable[PTN_BOOTLOADER_INDEX].name, "bootloader");
+	ptable[PTN_BOOTLOADER_INDEX].start =
+				ANDROID_BOOTLOADER_OFFSET / dev_desc->blksz;
+	ptable[PTN_BOOTLOADER_INDEX].length =
+				 ANDROID_BOOTLOADER_SIZE / dev_desc->blksz;
+	ptable[PTN_BOOTLOADER_INDEX].partition_id = boot_partition;
+
+	setup_ptable_mmc_partition(PTN_KERNEL_INDEX,
+				   CONFIG_ANDROID_BOOT_PARTITION_MMC,
+				   user_partition, "boot", dev_desc, ptable);
+	setup_ptable_mmc_partition(PTN_RECOVERY_INDEX,
+				   CONFIG_ANDROID_RECOVERY_PARTITION_MMC,
+				   user_partition,
+				   "recovery", dev_desc, ptable);
+	setup_ptable_mmc_partition(PTN_SYSTEM_INDEX,
+				   CONFIG_ANDROID_SYSTEM_PARTITION_MMC,
+				   user_partition,
+				   "system", dev_desc, ptable);
+
+	for (i = 0; i <= PTN_RECOVERY_INDEX; i++)
+		fastboot_flash_add_ptn(&ptable[i]);
+
+	return 0;
+}
+#endif
+
+static void fastboot_init_strings(void)
+{
+	struct usb_string_descriptor *string;
+
+	fastboot_string_table[STR_LANG_INDEX] =
+		(struct usb_string_descriptor *)wstrLang;
+
+	string = (struct usb_string_descriptor *)wstrManufacturer;
+	string->bLength = sizeof(wstrManufacturer);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide(CONFIG_FASTBOOT_MANUFACTURER_STR, string->wData);
+	fastboot_string_table[STR_MANUFACTURER_INDEX] = string;
+
+	string = (struct usb_string_descriptor *)wstrProduct;
+	string->bLength = sizeof(wstrProduct);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide(CONFIG_FASTBOOT_PRODUCT_NAME_STR, string->wData);
+	fastboot_string_table[STR_PRODUCT_INDEX] = string;
+
+	string = (struct usb_string_descriptor *)wstrSerial;
+	string->bLength = sizeof(wstrSerial);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide(CONFIG_FASTBOOT_SERIAL_NUM, string->wData);
+	fastboot_string_table[STR_SERIAL_INDEX] = string;
+
+	string = (struct usb_string_descriptor *)wstrConfiguration;
+	string->bLength = sizeof(wstrConfiguration);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide(CONFIG_FASTBOOT_CONFIGURATION_STR, string->wData);
+	fastboot_string_table[STR_CONFIG_INDEX] = string;
+
+	string = (struct usb_string_descriptor *) wstrDataInterface;
+	string->bLength = sizeof(wstrDataInterface);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide(CONFIG_FASTBOOT_INTERFACE_STR, string->wData);
+	fastboot_string_table[STR_DATA_INTERFACE_INDEX] = string;
+
+	/* Now, initialize the string table for ep0 handling */
+	usb_strings = fastboot_string_table;
+}
+
+static void fastboot_init_instances(void)
+{
+	int i;
+
+	/* Assign endpoint descriptors */
+	ep_descriptor_ptrs[0] =
+		&fastboot_configuration_descriptors[0].data_endpoints[0];
+	ep_descriptor_ptrs[1] =
+		&fastboot_configuration_descriptors[0].data_endpoints[1];
+
+	/* Configuration Descriptor */
+	configuration_descriptor =
+		(struct usb_configuration_descriptor *)
+		&fastboot_configuration_descriptors;
+
+	/* initialize device instance */
+	memset(device_instance, 0, sizeof(struct usb_device_instance));
+	device_instance->device_state = STATE_INIT;
+	device_instance->device_descriptor = &device_descriptor;
+	device_instance->event = fastboot_event_handler;
+	device_instance->cdc_recv_setup = fastboot_cdc_setup;
+	device_instance->bus = bus_instance;
+	device_instance->configurations = 1;
+	device_instance->configuration_instance_array = config_instance;
+
+	/* initialize bus instance */
+	memset(bus_instance, 0, sizeof(struct usb_bus_instance));
+	bus_instance->device = device_instance;
+	bus_instance->endpoint_array = endpoint_instance;
+	bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
+	bus_instance->maxpacketsize = 0xFF;
+	bus_instance->serial_number_str = CONFIG_FASTBOOT_SERIAL_NUM;
+
+	/* configuration instance */
+	memset(config_instance, 0,
+		sizeof(struct usb_configuration_instance));
+	config_instance->interfaces = 1;
+	config_instance->configuration_descriptor = configuration_descriptor;
+	config_instance->interface_instance_array = interface_instance;
+
+	/* interface instance */
+	memset(interface_instance, 0,
+		sizeof(struct usb_interface_instance));
+	interface_instance->alternates = 1;
+	interface_instance->alternates_instance_array = alternate_instance;
+
+	/* alternates instance */
+	memset(alternate_instance, 0,
+		sizeof(struct usb_alternate_instance));
+	alternate_instance->interface_descriptor = interface_descriptors;
+	alternate_instance->endpoints = NUM_ENDPOINTS;
+	alternate_instance->endpoints_descriptor_array = ep_descriptor_ptrs;
+
+	/* endpoint instances */
+	memset(&endpoint_instance[0], 0,
+		sizeof(struct usb_endpoint_instance));
+	endpoint_instance[0].endpoint_address = 0;
+	endpoint_instance[0].rcv_packetSize = EP0_MAX_PACKET_SIZE;
+	endpoint_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL;
+	endpoint_instance[0].tx_packetSize = EP0_MAX_PACKET_SIZE;
+	endpoint_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL;
+	udc_setup_ep(device_instance, 0, &endpoint_instance[0]);
+
+	for (i = 1; i <= NUM_ENDPOINTS; i++) {
+		memset(&endpoint_instance[i], 0,
+			sizeof(struct usb_endpoint_instance));
+
+		endpoint_instance[i].endpoint_address =
+			ep_descriptor_ptrs[i - 1]->bEndpointAddress;
+
+		endpoint_instance[i].rcv_attributes =
+			ep_descriptor_ptrs[i - 1]->bmAttributes;
+
+		endpoint_instance[i].rcv_packetSize =
+			le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
+
+		endpoint_instance[i].tx_attributes =
+			ep_descriptor_ptrs[i - 1]->bmAttributes;
+
+		endpoint_instance[i].tx_packetSize =
+			le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
+
+		endpoint_instance[i].tx_attributes =
+			ep_descriptor_ptrs[i - 1]->bmAttributes;
+
+		urb_link_init(&endpoint_instance[i].rcv);
+		urb_link_init(&endpoint_instance[i].rdy);
+		urb_link_init(&endpoint_instance[i].tx);
+		urb_link_init(&endpoint_instance[i].done);
+
+		if (endpoint_instance[i].endpoint_address & USB_DIR_IN) {
+			tx_endpoint = i;
+			endpoint_instance[i].tx_urb =
+				usbd_alloc_urb(device_instance,
+						&endpoint_instance[i]);
+		} else {
+			rx_endpoint = i;
+			endpoint_instance[i].rcv_urb =
+				usbd_alloc_urb(device_instance,
+						&endpoint_instance[i]);
+		}
+	}
+}
+
+static void fastboot_init_endpoints(void)
+{
+	int i;
+
+	bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
+	for (i = 1; i <= NUM_ENDPOINTS; i++)
+		udc_setup_ep(device_instance, i, &endpoint_instance[i]);
+}
+
+static int fill_buffer(u8 *buf)
+{
+	struct usb_endpoint_instance *endpoint =
+					&endpoint_instance[rx_endpoint];
+
+	if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) {
+		unsigned int nb = 0;
+		char *src = (char *)endpoint->rcv_urb->buffer;
+		unsigned int rx_avail = MAX_BUFFER_SIZE;
+
+		if (rx_avail >= endpoint->rcv_urb->actual_length) {
+			nb = endpoint->rcv_urb->actual_length;
+			memcpy(buf, src, nb);
+			endpoint->rcv_urb->actual_length = 0;
+		}
+		return nb;
+	}
+	return 0;
+}
+
+static struct urb *next_urb(struct usb_device_instance *device,
+				struct usb_endpoint_instance *endpoint)
+{
+	struct urb *current_urb = NULL;
+	int space;
+
+	/* If there's a queue, then we should add to the last urb */
+	if (!endpoint->tx_queue)
+		current_urb = endpoint->tx_urb;
+	else
+		/* Last urb from tx chain */
+		current_urb =
+		    p2surround(struct urb, link, endpoint->tx.prev);
+
+	/* Make sure this one has enough room */
+	space = current_urb->buffer_length - current_urb->actual_length;
+	if (space > 0)
+		return current_urb;
+	else {    /* No space here */
+		/* First look at done list */
+		current_urb = first_urb_detached(&endpoint->done);
+		if (!current_urb)
+			current_urb = usbd_alloc_urb(device, endpoint);
+
+		urb_append(&endpoint->tx, current_urb);
+		endpoint->tx_queue++;
+	}
+	return current_urb;
+}
+
+/*!
+ * Function to receive data from host through channel
+ *
+ * @buf  buffer to fill in
+ * @count  read data size
+ *
+ * @return 0
+ */
+int fastboot_usb_recv(u8 *buf, int count)
+{
+	int len = 0;
+
+	while (!fastboot_usb_configured())
+		udc_irq();
+
+	/* update rxqueue to wait new data */
+	mxc_udc_rxqueue_update(2, count);
+
+	while (!len) {
+		if (is_usb_disconnected()) {
+			/*it will not unconfigure when disconnect
+			from host, so here needs manual unconfigure
+			anyway, it's just a workaround*/
+			fastboot_configured_flag = 0;
+			usb_disconnected = 1;
+			return 0;
+		}
+		udc_irq();
+		if (fastboot_usb_configured())
+			len = fill_buffer(buf);
+	}
+	return len;
+}
+
+int fastboot_getvar(const char *rx_buffer, char *tx_buffer)
+{
+	/* Place board specific variables here */
+	return 0;
+}
+
+int fastboot_poll()
+{
+	u8 buffer[MAX_BUFFER_SIZE];
+	int length = 0;
+
+	memset(buffer, 0, MAX_BUFFER_SIZE);
+
+	length = fastboot_usb_recv(buffer, MAX_BUFFER_SIZE);
+
+	/* If usb disconnected, blocked here to wait */
+	if (usb_disconnected) {
+		udc_disconnect();
+		udc_connect();
+		/*the udc_connect will be blocked until connect to host
+		  so, the usb_disconnect should be 0 after udc_connect,
+		  and should be set manually. Anyway, it's just a workaround*/
+		usb_disconnected = 0;
+	}
+
+	if (!length)
+		return FASTBOOT_INACTIVE;
+
+	/* Pass this up to the interface's handler */
+	if (fastboot_interface && fastboot_interface->rx_handler) {
+		if (!fastboot_interface->rx_handler(buffer, length))
+			return FASTBOOT_OK;
+	}
+	return FASTBOOT_OK;
+}
+
+int fastboot_tx(unsigned char *buffer, unsigned int buffer_size)
+{
+	/* Not realized yet */
+	return 0;
+}
+
+static int write_buffer(const char *buffer, unsigned int buffer_size)
+{
+	struct usb_endpoint_instance *endpoint =
+		(struct usb_endpoint_instance *)&endpoint_instance[tx_endpoint];
+	struct urb *current_urb = NULL;
+
+	if (!fastboot_usb_configured())
+		return 0;
+
+	current_urb = next_urb(device_instance, endpoint);
+	if (buffer_size) {
+		char *dest;
+		int space_avail, popnum, count, total = 0;
+
+		/* Break buffer into urb sized pieces,
+		 * and link each to the endpoint
+		 */
+		count = buffer_size;
+		while (count > 0) {
+			if (!current_urb) {
+				printf("current_urb is NULL, buffer_size %d\n",
+				    buffer_size);
+				return total;
+			}
+
+			dest = (char *)current_urb->buffer +
+			current_urb->actual_length;
+
+			space_avail = current_urb->buffer_length -
+					current_urb->actual_length;
+			popnum = MIN(space_avail, count);
+			if (popnum == 0)
+				break;
+
+			memcpy(dest, buffer + total, popnum);
+			printf("send: %s\n", (char *)buffer);
+
+			current_urb->actual_length += popnum;
+			total += popnum;
+
+			if (udc_endpoint_write(endpoint))
+				/* Write pre-empted by RX */
+				return 0;
+			count -= popnum;
+		} /* end while */
+		return total;
+	}
+	return 0;
+}
+
+int fastboot_tx_status(const char *buffer, unsigned int buffer_size)
+{
+	int len = 0;
+
+	while (buffer_size > 0) {
+		len = write_buffer(buffer + len, buffer_size);
+		buffer_size -= len;
+
+		udc_irq();
+	}
+	udc_irq();
+
+	return 0;
+}
+
+void fastboot_shutdown(void)
+{
+	usb_shutdown();
+
+	/* Reset some globals */
+	fastboot_interface = NULL;
+}
+
+static int fastboot_usb_configured(void)
+{
+	return fastboot_configured_flag;
+}
+
+static void fastboot_event_handler(struct usb_device_instance *device,
+				  usb_device_event_t event, int data)
+{
+	switch (event) {
+	case DEVICE_RESET:
+	case DEVICE_BUS_INACTIVE:
+		fastboot_configured_flag = 0;
+		break;
+	case DEVICE_CONFIGURED:
+		fastboot_configured_flag = 1;
+		fastboot_init_endpoints();
+		break;
+	case DEVICE_ADDRESS_ASSIGNED:
+	default:
+		break;
+	}
+}
+
+static int fastboot_cdc_setup(struct usb_device_request *request, struct urb *urb)
+{
+	return 0;
+}
+
+/* export to lib_arm/board.c */
+void check_fastboot_mode(void)
+{
+	if (fastboot_check_and_clean_flag())
+		do_fastboot(NULL, 0, 0, 0);
+}
+
+u8 fastboot_debug_level;
+void fastboot_dump_memory(u32 *ptr, u32 len)
+{
+    u32 i;
+    for (i = 0; i < len; i++) {
+	DBG_DEBUG("0x%p: %08x %08x %08x %08x\n", ptr,
+			*ptr, *(ptr+1), *(ptr+2), *(ptr+3));
+	ptr += 4;
+    }
+}
+
+#define FASTBOOT_STS_CMD 0
+#define FASTBOOT_STS_CMD_WAIT 1
+#define FASTBOOT_STS_DATA 2
+#define FASTBOOT_STS_DATA_WAIT 3
+
+static u8 fastboot_status;
+static u8 g_fastboot_recvbuf[MAX_PAKET_LEN];
+static u8 g_fastboot_sendbuf[MAX_PAKET_LEN];
+
+static u32 g_fastboot_datalen;
+static u8 g_fastboot_outep_index, g_fastboot_inep_index;
+static u8 g_usb_connected;
+
+void fastboot_get_ep_num(u8 *in, u8 *out)
+{
+    if (out)
+	*out = rx_endpoint + EP0_OUT_INDEX + 1;
+    if (in)
+	*in = tx_endpoint + EP0_IN_INDEX + 1;
+}
+
+static void fastboot_data_handler(u32 len, u8 *recvbuf)
+{
+    if (len != g_fastboot_datalen)
+	DBG_ERR("Fastboot data recv error, want:%d, recv:%d\n",
+					g_fastboot_datalen, len);
+    sprintf((char *)g_fastboot_sendbuf, "OKAY");
+    udc_send_data(g_fastboot_inep_index, g_fastboot_sendbuf, 4, NULL);
+    fastboot_status = FASTBOOT_STS_CMD;
+}
+
+static void fastboot_cmd_handler(u32 len, u8 *recvbuf)
+{
+    u32 *databuf = (u32 *)CONFIG_FASTBOOT_TRANSFER_BUF;
+
+    if (len > sizeof(g_fastboot_recvbuf)) {
+	DBG_ERR("%s, recv len=%d error\n", __func__, len);
+	return;
+    }
+    recvbuf[len] = 0;
+    DBG_ALWS("\nFastboot Cmd, len=%u, %s\n", len, recvbuf);
+
+    if (memcmp(recvbuf, "download:", 9) == 0) {
+	g_fastboot_datalen = simple_strtoul((const char *)recvbuf + 9,
+								NULL, 16);
+	if (g_fastboot_datalen > CONFIG_FASTBOOT_TRANSFER_BUF_SIZE) {
+		DBG_ERR("Download too much data\n");
+		sprintf((char *)g_fastboot_sendbuf, "FAIL");
+		udc_send_data(g_fastboot_inep_index, g_fastboot_sendbuf,
+								4, NULL);
+		fastboot_status = FASTBOOT_STS_CMD;
+	} else {
+		sprintf((char *)g_fastboot_sendbuf, "DATA%08x",
+							g_fastboot_datalen);
+		udc_send_data(g_fastboot_inep_index, g_fastboot_sendbuf,
+								12, NULL);
+		DBG_ALWS("Fastboot is receiveing data...\n");
+		udc_recv_data(g_fastboot_outep_index, (u8 *)databuf,
+				g_fastboot_datalen, fastboot_data_handler);
+		fastboot_status = FASTBOOT_STS_DATA_WAIT;
+	}
+    } else if (memcmp(recvbuf, "flash:", 6) == 0) {
+		if (g_fastboot_datalen ==
+			fastboot_write_storage(recvbuf+6, g_fastboot_datalen)) {
+			DBG_ALWS("Fastboot write OK, send OKAY...\n");
+			sprintf((char *)g_fastboot_sendbuf, "OKAY");
+			udc_send_data(g_fastboot_inep_index, g_fastboot_sendbuf,
+								4, NULL);
+		} else {
+			DBG_ERR("Fastboot write error, write 0x%x\n",
+							g_fastboot_datalen);
+			sprintf((char *)g_fastboot_sendbuf, "FAIL");
+			udc_send_data(g_fastboot_inep_index, g_fastboot_sendbuf,
+								4, NULL);
+		}
+		g_fastboot_datalen = 0;
+		fastboot_status = FASTBOOT_STS_CMD;
+    } else if (memcmp(recvbuf, "reboot", 6) == 0) {
+			sprintf((char *)g_fastboot_sendbuf, "OKAY");
+			udc_send_data(g_fastboot_inep_index, g_fastboot_sendbuf,
+								4, NULL);
+			udelay(100000); /* 1 sec */
+
+			do_reset(NULL, 0, 0, NULL);
+
+    } else {
+		DBG_ERR("Not support command:%s\n", recvbuf);
+		sprintf((char *)g_fastboot_sendbuf, "FAIL");
+		udc_send_data(g_fastboot_inep_index, g_fastboot_sendbuf,
+								4, NULL);
+		g_fastboot_datalen = 0;
+		fastboot_status = FASTBOOT_STS_CMD;
+    }
+}
+
+static struct cmd_fastboot_interface interface = {
+    .rx_handler            = NULL,
+    .reset_handler         = NULL,
+    .product_name          = NULL,
+    .serial_no             = NULL,
+    .nand_block_size       = 0,
+    .transfer_buffer       = (unsigned char *)0xffffffff,
+    .transfer_buffer_size  = 0,
+};
+
+/*
+ * fastboot main process, only support 'download', 'flash' 'reboot' command now
+ *
+ * @debug  control debug level, support three level now,
+ *	   0(normal), 1(debug), 2(info), default is 0
+ */
+void fastboot_quick(u8 debug)
+{
+    u32 plug_cnt = 0;
+    if (debug > 2)
+	debug = 0;
+    fastboot_debug_level = debug;
+
+    fastboot_init(&interface);
+    fastboot_get_ep_num(&g_fastboot_inep_index, &g_fastboot_outep_index);
+    DBG_INFO("g_fastboot_inep_index=%d, g_fastboot_outep_index=%d\n",
+		g_fastboot_inep_index, g_fastboot_outep_index);
+    while (++plug_cnt) {
+	fastboot_status = FASTBOOT_STS_CMD;
+	udc_hal_data_init();
+	udc_run();
+	if (plug_cnt > 1)
+		DBG_ALWS("wait usb cable into the connector!\n");
+	udc_wait_connect();
+	g_usb_connected = 1;
+	if (plug_cnt > 1)
+		DBG_ALWS("USB Mini b cable Connected!\n");
+	while (g_usb_connected) {
+		int usb_irq = udc_irq_handler();
+		if (usb_irq > 0) {
+			if (fastboot_status == FASTBOOT_STS_CMD) {
+				memset(g_fastboot_recvbuf, 0 , MAX_PAKET_LEN);
+				udc_recv_data(g_fastboot_outep_index,
+					g_fastboot_recvbuf, MAX_PAKET_LEN,
+					fastboot_cmd_handler);
+				fastboot_status = FASTBOOT_STS_CMD_WAIT;
+			}
+		}
+		if (usb_irq < 0)
+			g_usb_connected = 0;
+	}
+    }
+}

+ 1 - 0
drivers/usb/gadget/Makefile

@@ -49,6 +49,7 @@ else
 ifdef CONFIG_USB_DEVICE
 COBJS-y += core.o
 COBJS-y += ep0.o
+COBJS-$(CONFIG_IMX_UDC) += imx_udc.o  
 COBJS-$(CONFIG_DW_UDC) += designware_udc.o
 COBJS-$(CONFIG_OMAP1510) += omap1510_udc.o
 COBJS-$(CONFIG_OMAP1610) += omap1510_udc.o

+ 1565 - 0
drivers/usb/gadget/imx_udc.c

@@ -0,0 +1,1565 @@
+/*
+ * Copyright (C) 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * 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 <common.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <malloc.h>
+#include <command.h>
+#include <asm/errno.h>
+#include <usbdevice.h>
+#include <usb/imx_udc.h>
+
+#include "ep0.h"
+
+#ifdef DEBUG
+#define DBG(x...) printf(x)
+#else
+#define DBG(x...) do {} while (0)
+#endif
+
+#define mdelay(n) udelay((n)*1000)
+
+#define EP_TQ_ITEM_SIZE 16
+
+#define inc_index(x) (x = ((x+1) % EP_TQ_ITEM_SIZE))
+
+#define ep_is_in(e, tx) ((e == 0) ? (mxc_udc.ep0_dir == USB_DIR_IN) : tx)
+
+#define USB_RECIP_MASK	    0x03
+#define USB_TYPE_MASK	    (0x03 << 5)
+#define USB_MEM_ALIGN_BYTE  4096
+
+typedef struct {
+	int epnum;
+	int dir;
+	int max_pkt_size;
+	struct usb_endpoint_instance *epi;
+	struct ep_queue_item *ep_dtd[EP_TQ_ITEM_SIZE];
+	int index; /* to index the free tx tqi */
+	int done;  /* to index the complete rx tqi */
+	struct ep_queue_item *tail; /* last item in the dtd chain */
+	struct ep_queue_head *ep_qh;
+} mxc_ep_t;
+
+typedef struct {
+	int    max_ep;
+	int    ep0_dir;
+	int    setaddr;
+	struct ep_queue_head *ep_qh;
+	mxc_ep_t *mxc_ep;
+	u32    qh_dma;
+} mxc_udc_ctrl;
+
+typedef struct usb_device_request setup_packet;
+
+static int usb_highspeed;
+static int usb_inited;
+static mxc_udc_ctrl mxc_udc;
+static struct usb_device_instance *udc_device;
+static struct urb *ep0_urb;
+/*
+ * malloc an nocached memory
+ * dmaaddr: phys address
+ * size   : memory size
+ * align  : alignment for this memroy
+ * return : vir address(NULL when malloc failt)
+*/
+static void *malloc_dma_buffer(u32 *dmaaddr, int size, int align)
+{
+	int msize = (size + align  - 1);
+	u32 vir, vir_align;
+
+	vir = (u32)malloc(msize);
+#ifdef CONFIG_ARCH_MMU
+	vir = ioremap_nocache(iomem_to_phys(vir), msize);
+#endif
+	memset((void *)vir, 0, msize);
+	vir_align = (vir + align - 1) & (~(align - 1));
+#ifdef CONFIG_ARCH_MMU
+	*dmaaddr = (u32)iomem_to_phys(vir_align);
+#else
+	*dmaaddr = vir_align;
+#endif
+	DBG("vir addr %x, dma addr %x\n", vir_align, *dmaaddr);
+	return (void *)vir_align;
+}
+
+int is_usb_disconnected()
+{
+	int ret = 0;
+
+	ret = readl(USB_OTGSC) & OTGSC_B_SESSION_VALID ? 0 : 1;
+	return ret;
+}
+
+static int mxc_init_usb_qh(void)
+{
+	int size;
+	memset(&mxc_udc, 0, sizeof(mxc_udc));
+	mxc_udc.max_ep = (readl(USB_DCCPARAMS) & DCCPARAMS_DEN_MASK) * 2;
+	DBG("udc max ep = %d\n", mxc_udc.max_ep);
+	size = mxc_udc.max_ep * sizeof(struct ep_queue_head);
+	mxc_udc.ep_qh = malloc_dma_buffer(&mxc_udc.qh_dma,
+					     size, USB_MEM_ALIGN_BYTE);
+	if (!mxc_udc.ep_qh) {
+		printf("malloc ep qh dma buffer failure\n");
+		return -1;
+	}
+	memset(mxc_udc.ep_qh, 0, size);
+	writel(mxc_udc.qh_dma & 0xfffff800, USB_ENDPOINTLISTADDR);
+	return 0;
+}
+
+static int mxc_init_ep_struct(void)
+{
+	int i;
+
+	DBG("init mxc ep\n");
+	mxc_udc.mxc_ep = malloc(mxc_udc.max_ep * sizeof(mxc_ep_t));
+	if (!mxc_udc.mxc_ep) {
+		printf("malloc ep struct failure\n");
+		return -1;
+	}
+	memset((void *)mxc_udc.mxc_ep, 0, sizeof(mxc_ep_t) * mxc_udc.max_ep);
+	for (i = 0; i < mxc_udc.max_ep / 2; i++) {
+		mxc_ep_t *ep;
+		ep  = mxc_udc.mxc_ep + i * 2;
+		ep->epnum = i;
+		ep->index = ep->done = 0;
+		ep->dir = USB_RECV;  /* data from host to device */
+		ep->ep_qh = &mxc_udc.ep_qh[i * 2];
+
+		ep  = mxc_udc.mxc_ep + (i * 2 + 1);
+		ep->epnum = i;
+		ep->index = ep->done = 0;
+		ep->dir = USB_SEND;  /* data to host from device */
+		ep->ep_qh = &mxc_udc.ep_qh[(i * 2 + 1)];
+	}
+	return 0;
+}
+
+static int mxc_init_ep_dtd(u8 index)
+{
+	mxc_ep_t *ep;
+	struct ep_queue_item *tqi;
+	u32 dma;
+	int i;
+
+	if (index >= mxc_udc.max_ep)
+		DBG("%s ep %d is not valid\n", __func__, index);
+
+	ep = mxc_udc.mxc_ep + index;
+	tqi = malloc_dma_buffer(&dma, EP_TQ_ITEM_SIZE *
+			    EP_TQ_ITEM_SIZE * sizeof(struct ep_queue_item),
+			    USB_MEM_ALIGN_BYTE);
+	if (tqi == NULL) {
+		printf("%s malloc tq item failure\n", __func__);
+		return -1;
+	}
+	for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+		ep->ep_dtd[i] = tqi + i;
+		ep->ep_dtd[i]->item_dma =
+			dma + i * sizeof(struct ep_queue_item);
+	}
+	return -1;
+}
+static void mxc_ep_qh_setup(u8 ep_num, u8 dir, u8 ep_type,
+				 u32 max_pkt_len, u32 zlt, u8 mult)
+{
+	struct ep_queue_head *p_qh = mxc_udc.ep_qh + (2 * ep_num + dir);
+	u32 tmp = 0;
+
+	tmp = max_pkt_len << 16;
+	switch (ep_type) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		tmp |= (1 << 15);
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		tmp |= (mult << 30);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+	case USB_ENDPOINT_XFER_INT:
+		break;
+	default:
+		DBG("error ep type is %d\n", ep_type);
+		return;
+	}
+	if (zlt)
+		tmp |= (1<<29);
+
+	p_qh->config = tmp;
+}
+
+static void mxc_ep_setup(u8 ep_num, u8 dir, u8 ep_type)
+{
+	u32 epctrl = 0;
+	epctrl = readl(USB_ENDPTCTRL(ep_num));
+	if (dir) {
+		if (ep_num)
+			epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+		epctrl |= EPCTRL_TX_ENABLE;
+		epctrl |= ((u32)(ep_type) << EPCTRL_TX_EP_TYPE_SHIFT);
+	} else {
+		if (ep_num)
+			epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+		epctrl |= EPCTRL_RX_ENABLE;
+		epctrl |= ((u32)(ep_type) << EPCTRL_RX_EP_TYPE_SHIFT);
+	}
+	writel(epctrl, USB_ENDPTCTRL(ep_num));
+}
+
+static void mxc_tqi_init_page(struct ep_queue_item *tqi)
+{
+	tqi->page0 = tqi->page_dma;
+	tqi->page1 = tqi->page0 + 0x1000;
+	tqi->page2 = tqi->page1 + 0x1000;
+	tqi->page3 = tqi->page2 + 0x1000;
+	tqi->page4 = tqi->page3 + 0x1000;
+}
+static int mxc_malloc_ep0_ptr(mxc_ep_t *ep)
+{
+	int i;
+	struct ep_queue_item *tqi;
+	int max_pkt_size = USB_MAX_CTRL_PAYLOAD;
+
+	ep->max_pkt_size = max_pkt_size;
+	for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+		tqi = ep->ep_dtd[i];
+		tqi->page_vir = (u32)malloc_dma_buffer(&tqi->page_dma,
+						    max_pkt_size,
+						    USB_MEM_ALIGN_BYTE);
+		if ((void *)tqi->page_vir == NULL) {
+			printf("malloc ep's dtd bufer failure, i=%d\n", i);
+			return -1;
+		}
+		mxc_tqi_init_page(tqi);
+	}
+	return 0;
+}
+
+static void ep0_setup(void)
+{
+	mxc_ep_qh_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL,
+			    USB_MAX_CTRL_PAYLOAD, 0, 0);
+	mxc_ep_qh_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL,
+			    USB_MAX_CTRL_PAYLOAD, 0, 0);
+	mxc_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
+	mxc_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
+	mxc_init_ep_dtd(0 * 2 + USB_RECV);
+	mxc_init_ep_dtd(0 * 2 + USB_SEND);
+	mxc_malloc_ep0_ptr(mxc_udc.mxc_ep + (USB_RECV));
+	mxc_malloc_ep0_ptr(mxc_udc.mxc_ep + (USB_SEND));
+}
+
+
+static int mxc_tqi_is_busy(struct ep_queue_item *tqi)
+{
+	/* bit 7 is set by software when send, clear by controller
+	   when finish */
+	return tqi->info & (1 << 7);
+}
+
+static int mxc_ep_xfer_is_working(mxc_ep_t *ep, u32 in)
+{
+	/* in: means device -> host */
+	u32 bitmask = 1 << (ep->epnum + in * 16);
+	u32 temp, prime, tstat;
+
+	prime = (bitmask & readl(USB_ENDPTPRIME));
+	if (prime)
+		return 1;
+	do {
+		temp = readl(USB_USBCMD);
+		writel(temp|USB_CMD_ATDTW, USB_USBCMD);
+		tstat = readl(USB_ENDPTSTAT) & bitmask;
+	} while (!(readl(USB_USBCMD) & USB_CMD_ATDTW));
+	writel(temp & (~USB_CMD_ATDTW), USB_USBCMD);
+
+	if (tstat)
+		return 1;
+	return 0;
+}
+
+static void mxc_update_qh(mxc_ep_t *ep, struct ep_queue_item *tqi, u32 in)
+{
+	/* in: means device -> host */
+	struct ep_queue_head *qh = ep->ep_qh;
+	u32 bitmask = 1 << (ep->epnum + in * 16);
+	DBG("%s, line %d, epnum=%d, in=%d\n", __func__,
+		__LINE__, ep->epnum, in);
+	qh->next_queue_item = tqi->item_dma;
+	qh->info = 0;
+	writel(bitmask, USB_ENDPTPRIME);
+}
+
+static void _dump_buf(u32 buf, u32 len)
+{
+#ifdef DEBUG
+	char *data = (char *)buf;
+	int i;
+	for (i = 0; i < len; i++)
+		printf("%x ", data[i]);
+	printf("\n");
+#endif
+}
+
+
+static void mxc_udc_queue_update(u8 epnum, u8 *data, u32 len, u32 tx)
+{
+	mxc_ep_t *ep;
+	struct ep_queue_item *tqi, *head, *last;
+	int send = 0;
+	int in;
+
+	head = last = NULL;
+	in = ep_is_in(epnum, tx);
+	ep = mxc_udc.mxc_ep + (epnum * 2 + in);
+	DBG("epnum = %d,  in = %d\n", epnum, in);
+	do {
+		tqi = ep->ep_dtd[ep->index];
+		DBG("%s, index = %d, tqi = %p\n", __func__, ep->index, tqi);
+		while (mxc_tqi_is_busy(tqi))
+			;
+		mxc_tqi_init_page(tqi);
+		DBG("%s, line = %d, len = %d\n", __func__, __LINE__, len);
+		inc_index(ep->index);
+		send = MIN(len, 0x1000);
+		if (data) {
+			memcpy((void *)tqi->page_vir, (void *)data, send);
+			_dump_buf(tqi->page_vir, send);
+		}
+		if (!head)
+			last = head = tqi;
+		else {
+			last->next_item_ptr = tqi->item_dma;
+			last->next_item_vir = tqi;
+			last = tqi;
+		}
+		if (!tx)
+			tqi->reserved[0] = send;
+		/* we set IOS for every dtd */
+		tqi->info = ((send << 16) | (1 << 15) | (1 << 7));
+		data += send;
+		len -= send;
+	} while (len);
+
+	last->next_item_ptr = 0x1; /* end */
+	if (ep->tail) {
+		ep->tail->next_item_ptr = head->item_dma;
+		ep->tail->next_item_vir = head;
+		if (mxc_ep_xfer_is_working(ep, in)) {
+			DBG("ep is working\n");
+			goto out;
+		}
+	}
+	mxc_update_qh(ep, head, in);
+out:
+	ep->tail = last;
+}
+
+static void mxc_udc_txqueue_update(u8 ep, u8 *data, u32 len)
+{
+	mxc_udc_queue_update(ep, data, len, 1);
+}
+
+void mxc_udc_rxqueue_update(u8 ep, u32 len)
+{
+	mxc_udc_queue_update(ep, NULL, len, 0);
+}
+
+static void mxc_ep0_stall(void)
+{
+	u32 temp;
+	temp = readl(USB_ENDPTCTRL(0));
+	temp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;
+	writel(temp, USB_ENDPTCTRL(0));
+}
+
+static void mxc_usb_run(void)
+{
+	unsigned int temp = 0;
+
+	/* Enable DR irq reg */
+	temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
+		| USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
+		| USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
+
+	writel(temp, USB_USBINTR);
+
+	/* Set controller to Run */
+	temp = readl(USB_USBCMD);
+	temp |= USB_CMD_RUN_STOP;
+	writel(temp, USB_USBCMD);
+}
+
+static void mxc_usb_stop(void)
+{
+	unsigned int temp = 0;
+
+	writel(temp, USB_USBINTR);
+
+	/* Set controller to Stop */
+	temp = readl(USB_USBCMD);
+	temp &= ~USB_CMD_RUN_STOP;
+	writel(temp, USB_USBCMD);
+}
+
+static void usb_phy_init(void)
+{
+	u32 temp;
+	/* select 24M clk */
+	temp = readl(USB_PHY1_CTRL);
+	temp &= ~3;
+	temp |= 1;
+	writel(temp, USB_PHY1_CTRL);
+	/* Config PHY interface */
+	temp = readl(USB_PORTSC1);
+	temp &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
+	temp |= PORTSCX_PTW_16BIT;
+	writel(temp, USB_PORTSC1);
+	DBG("Config PHY  END\n");
+}
+
+static void usb_set_mode_device(void)
+{
+	u32 temp;
+
+	/* Set controller to stop */
+	temp = readl(USB_USBCMD);
+	temp &= ~USB_CMD_RUN_STOP;
+	writel(temp, USB_USBCMD);
+
+	while (readl(USB_USBCMD) & USB_CMD_RUN_STOP)
+		;
+	/* Do core reset */
+	temp = readl(USB_USBCMD);
+	temp |= USB_CMD_CTRL_RESET;
+	writel(temp, USB_USBCMD);
+	while (readl(USB_USBCMD) & USB_CMD_CTRL_RESET)
+		;
+	DBG("DOORE RESET END\n");
+
+#if defined(CONFIG_MX6Q) || defined(CONFIG_MX6DL) || defined(CONFIG_MX6SL)
+	reset_usb_phy1();
+#endif
+	DBG("init core to device mode\n");
+	temp = readl(USB_USBMODE);
+	temp &= ~USB_MODE_CTRL_MODE_MASK;	/* clear mode bits */
+	temp |= USB_MODE_CTRL_MODE_DEVICE;
+	/* Disable Setup Lockout */
+	temp |= USB_MODE_SETUP_LOCK_OFF;
+	writel(temp, USB_USBMODE);
+	DBG("init core to device mode end\n");
+}
+
+static void usb_init_eps(void)
+{
+	u32 temp;
+	DBG("Flush begin\n");
+	temp = readl(USB_ENDPTNAKEN);
+	temp |= 0x10001;	/* clear mode bits */
+	writel(temp, USB_ENDPTNAKEN);
+	writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
+	writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
+	writel(0xffffffff, USB_ENDPTFLUSH);
+	DBG("FLUSH END\n");
+}
+
+static void usb_udc_init(void)
+{
+	DBG("\n************************\n");
+	DBG("         usb init start\n");
+	DBG("\n************************\n");
+
+	usb_phy_init();
+	usb_set_mode_device();
+	mxc_init_usb_qh();
+	usb_init_eps();
+	mxc_init_ep_struct();
+	ep0_setup();
+	usb_inited = 1;
+}
+
+void usb_shutdown(void)
+{
+	u32 temp;
+	/* disable pullup */
+	temp = readl(USB_USBCMD);
+	temp &= ~USB_CMD_RUN_STOP;
+	writel(temp, USB_USBCMD);
+	mdelay(2);
+}
+
+static void ch9getstatus(u8 request_type, u16 value, u16 index, u16 length)
+{
+	u16 tmp;
+
+	if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+		tmp = 1 << 0; /* self powerd */
+		tmp |= 0 << 1; /* not remote wakeup able */
+	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
+		tmp = 0;
+	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
+		tmp = 0;
+	}
+	mxc_udc.ep0_dir = USB_DIR_IN;
+	mxc_udc_queue_update(0, (u8 *)&tmp, 2, 0xffffffff);
+}
+static void mxc_udc_read_setup_pkt(setup_packet *s)
+{
+	u32 temp;
+	temp = readl(USB_ENDPTSETUPSTAT);
+	writel(temp, USB_ENDPTSETUPSTAT);
+	DBG("setup stat %x\n", temp);
+	do {
+		temp = readl(USB_USBCMD);
+		temp |= USB_CMD_SUTW;
+		writel(temp, USB_USBCMD);
+		memcpy((void *)s,
+			(void *)mxc_udc.mxc_ep[0].ep_qh->setup_data, 8);
+	} while (!(readl(USB_USBCMD) & USB_CMD_SUTW));
+
+	DBG("handle_setup s.type=%x req=%x len=%x\n",
+		s->bmRequestType, s->bRequest, s->wLength);
+	temp = readl(USB_USBCMD);
+	temp &= ~USB_CMD_SUTW;
+	writel(temp, USB_ENDPTSETUPSTAT);
+}
+
+static void mxc_udc_recv_setup(void)
+{
+	setup_packet *s = &ep0_urb->device_request;
+
+	mxc_udc_read_setup_pkt(s);
+	if (s->wLength)	{
+		mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ?
+					USB_DIR_OUT : USB_DIR_IN;
+		mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+	}
+	if (ep0_recv_setup(ep0_urb)) {
+		mxc_ep0_stall();
+		return;
+	}
+	switch (s->bRequest) {
+	case USB_REQ_GET_STATUS:
+		if ((s->bmRequestType & (USB_DIR_IN | USB_TYPE_MASK)) !=
+					 (USB_DIR_IN | USB_TYPE_STANDARD))
+			break;
+		ch9getstatus(s->bmRequestType, s->wValue,
+				s->wIndex, s->wLength);
+		return;
+	case USB_REQ_SET_ADDRESS:
+		if (s->bmRequestType != (USB_DIR_OUT |
+			    USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+			break;
+		mxc_udc.setaddr = 1;
+		mxc_udc.ep0_dir = USB_DIR_IN;
+		mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+		usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+		return;
+	case USB_REQ_SET_CONFIGURATION:
+		usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+	{
+		int rc = -1;
+		if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+				 (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD))
+			rc = 0;
+		else if ((s->bmRequestType &
+			    (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+			     (USB_RECIP_DEVICE | USB_TYPE_STANDARD))
+			rc = 0;
+		else
+			break;
+		if (rc == 0) {
+			mxc_udc.ep0_dir = USB_DIR_IN;
+			mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+		}
+		return;
+	}
+	default:
+		break;
+	}
+	if (s->wLength) {
+		mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ?
+					USB_DIR_IN : USB_DIR_OUT;
+		mxc_udc_queue_update(0, ep0_urb->buffer,
+				ep0_urb->actual_length, 0xffffffff);
+		ep0_urb->actual_length = 0;
+	} else {
+		mxc_udc.ep0_dir = USB_DIR_IN;
+		mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+	}
+}
+static int mxc_udc_tqi_empty(struct ep_queue_item *tqi)
+{
+	int ret;
+
+	ret = tqi->info & (1 << 7);
+	return ret;
+}
+
+static struct usb_endpoint_instance *mxc_get_epi(u8 epnum)
+{
+	int i;
+	for (i = 0; i < udc_device->bus->max_endpoints; i++) {
+		if ((udc_device->bus->endpoint_array[i].endpoint_address &
+			 USB_ENDPOINT_NUMBER_MASK) == epnum)
+			return &udc_device->bus->endpoint_array[i];
+	}
+	return NULL;
+}
+static u32 _mxc_ep_recv_data(u8 epnum, struct ep_queue_item *tqi)
+{
+	struct usb_endpoint_instance *epi = mxc_get_epi(epnum);
+	struct urb *urb;
+	u32 len = 0;
+
+	if (!epi)
+		return 0;
+
+	urb = epi->rcv_urb;
+	if (urb) {
+		u8 *data = urb->buffer + urb->actual_length;
+		int remain_len = (tqi->info >> 16) & (0xefff);
+		len = tqi->reserved[0] - remain_len;
+		DBG("recv len %d-%d-%d\n", len, tqi->reserved[0], remain_len);
+		memcpy(data, (void *)tqi->page_vir, len);
+	}
+	return len;
+}
+
+static void mxc_udc_ep_recv(u8 epnum)
+{
+	mxc_ep_t *ep = mxc_udc.mxc_ep + (epnum * 2 + USB_RECV);
+	struct ep_queue_item *tqi;
+	while (1) {
+		u32 nbytes;
+		tqi = ep->ep_dtd[ep->done];
+		if (mxc_udc_tqi_empty(tqi))
+			break;
+		nbytes = _mxc_ep_recv_data(epnum, tqi);
+		usbd_rcv_complete(ep->epi, nbytes, 0);
+		inc_index(ep->done);
+		if (ep->done == ep->index)
+			break;
+	}
+}
+static void mxc_udc_handle_xfer_complete(void)
+{
+	int i;
+	u32 bitpos = readl(USB_ENDPTCOMPLETE);
+
+	writel(bitpos, USB_ENDPTCOMPLETE);
+
+	for (i = 0; i < mxc_udc.max_ep; i++) {
+		int epnum = i >> 1;
+		int dir = i % 2;
+		u32 bitmask = 1 << (epnum + 16 * dir);
+		if (!(bitmask & bitpos))
+			continue;
+		DBG("ep %d, dir %d, complete\n", epnum, dir);
+		if (!epnum) {
+			if (mxc_udc.setaddr) {
+				writel(udc_device->address << 25,
+					USB_DEVICEADDR);
+				mxc_udc.setaddr = 0;
+			}
+			continue;
+		}
+		DBG("############### dir = %d ***************\n", dir);
+		if (dir == USB_SEND)
+			continue;
+		mxc_udc_ep_recv(epnum);
+	}
+}
+static void usb_dev_hand_usbint(void)
+{
+	if (readl(USB_ENDPTSETUPSTAT)) {
+		DBG("recv one setup packet\n");
+		mxc_udc_recv_setup();
+	}
+	if (readl(USB_ENDPTCOMPLETE)) {
+		DBG("Dtd complete irq\n");
+		mxc_udc_handle_xfer_complete();
+	}
+}
+
+static void usb_dev_hand_reset(void)
+{
+	u32 temp;
+	temp = readl(USB_DEVICEADDR);
+	temp &= ~0xfe000000;
+	writel(temp, USB_DEVICEADDR);
+	writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
+	writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
+	while (readl(USB_ENDPTPRIME))
+		;
+	writel(0xffffffff, USB_ENDPTFLUSH);
+	DBG("reset-PORTSC=%x\n", readl(USB_PORTSC1));
+	usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+}
+
+void usb_dev_hand_pci(void)
+{
+	u32 speed;
+	while (readl(USB_PORTSC1) & PORTSCX_PORT_RESET)
+		;
+	speed = readl(USB_PORTSC1) & PORTSCX_PORT_SPEED_MASK;
+	switch (speed) {
+	case PORTSCX_PORT_SPEED_HIGH:
+		usb_highspeed = 2;
+		break;
+	case PORTSCX_PORT_SPEED_FULL:
+		usb_highspeed = 1;
+		break;
+	case PORTSCX_PORT_SPEED_LOW:
+		usb_highspeed = 0;
+		break;
+	default:
+		break;
+	}
+	DBG("portspeed=%d, speed = %x\n", usb_highspeed, speed);
+}
+
+void usb_dev_hand_suspend(void)
+{
+}
+static int ll;
+void mxc_irq_poll(void)
+{
+	unsigned irq_src = readl(USB_USBSTS) & readl(USB_USBINTR);
+	writel(irq_src, USB_USBSTS);
+
+	if (irq_src == 0)
+		return;
+
+	if (irq_src & USB_STS_INT) {
+		ll++;
+		DBG("USB_INT\n");
+		usb_dev_hand_usbint();
+	}
+	if (irq_src & USB_STS_RESET) {
+		printf("USB_RESET\n");
+		usb_dev_hand_reset();
+	}
+	if (irq_src & USB_STS_PORT_CHANGE)
+		usb_dev_hand_pci();
+	if (irq_src & USB_STS_SUSPEND)
+		printf("USB_SUSPEND\n");
+	if (irq_src & USB_STS_ERR)
+		printf("USB_ERR\n");
+}
+
+void mxc_udc_wait_cable_insert(void)
+{
+	u32 temp;
+	int cable_connect = 1;
+
+	do {
+		udelay(50);
+
+		temp = readl(USB_OTGSC);
+		if (temp & (OTGSC_B_SESSION_VALID)) {
+			printf("USB Mini b cable Connected!\n");
+			break;
+		} else if (cable_connect == 1) {
+			printf("wait usb cable into the connector!\n");
+			cable_connect = 0;
+		}
+	} while (1);
+}
+
+void udc_disable_over_current(void)
+{
+	u32 temp;
+	temp = readl(USB_OTG_CTRL);
+	temp |= UCTRL_OVER_CUR_POL;
+	writel(temp, USB_OTG_CTRL);
+}
+
+/*
+ * mxc_udc_init function
+ */
+int mxc_udc_init(void)
+{
+	set_usboh3_clk();
+	set_usb_phy1_clk();
+	enable_usboh3_clk(1);
+#if defined(CONFIG_MX6Q) || defined(CONFIG_MX6DL) || defined(CONFIG_MX6SL)
+	udc_disable_over_current();
+#endif
+	enable_usb_phy1_clk(1);
+	usb_udc_init();
+
+	return 0;
+}
+
+void mxc_udc_poll(void)
+{
+	mxc_irq_poll();
+}
+
+/*
+ * Functions for gadget APIs
+ */
+int udc_init(void)
+{
+	mxc_udc_init();
+	return 0;
+}
+
+void udc_setup_ep(struct usb_device_instance *device, u32 index,
+		    struct usb_endpoint_instance *epi)
+{
+	u8 dir, epnum, zlt, mult;
+	u8 ep_type;
+	u32 max_pkt_size;
+	int ep_addr;
+	mxc_ep_t *ep;
+
+	if (epi) {
+		zlt = 1;
+		mult = 0;
+		ep_addr = epi->endpoint_address;
+		epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+		DBG("setup ep %d\n", epnum);
+		if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+			dir = USB_SEND;
+			ep_type = epi->tx_attributes;
+			max_pkt_size = epi->tx_packetSize;
+		} else {
+			dir = USB_RECV;
+			ep_type = epi->rcv_attributes;
+			max_pkt_size = epi->rcv_packetSize;
+		}
+		if (ep_type == USB_ENDPOINT_XFER_ISOC) {
+			mult = (u32)(1 + ((max_pkt_size >> 11) & 0x03));
+			max_pkt_size = max_pkt_size & 0x7ff;
+			DBG("mult = %d\n", mult);
+		}
+		ep = mxc_udc.mxc_ep + (epnum * 2 + dir);
+		ep->epi = epi;
+		if (epnum) {
+			struct ep_queue_item *tqi;
+			int i;
+
+			mxc_ep_qh_setup(epnum, dir, ep_type,
+					    max_pkt_size, zlt, mult);
+			mxc_ep_setup(epnum, dir, ep_type);
+			mxc_init_ep_dtd(epnum * 2 + dir);
+
+			/* malloc endpoint's dtd's data buffer*/
+			ep->max_pkt_size = max_pkt_size;
+			for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+				tqi = ep->ep_dtd[i];
+				tqi->page_vir = (u32)malloc_dma_buffer(
+					    &tqi->page_dma, max_pkt_size,
+					    USB_MEM_ALIGN_BYTE);
+				if ((void *)tqi->page_vir == NULL) {
+					printf("malloc dtd bufer failure\n");
+					return;
+				}
+				mxc_tqi_init_page(tqi);
+			}
+		}
+	}
+}
+
+
+int udc_endpoint_write(struct usb_endpoint_instance *epi)
+{
+	struct urb *urb = epi->tx_urb;
+	int ep_num = epi->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
+	u8 *data = (u8 *)urb->buffer + epi->sent;
+	int n = urb->actual_length - epi->sent;
+	mxc_udc_txqueue_update(ep_num, data, n);
+	epi->last = n;
+	epi->sent += n;
+	return 0;
+}
+
+void udc_enable(struct usb_device_instance *device)
+{
+	udc_device = device;
+	ep0_urb = usbd_alloc_urb(udc_device, udc_device->bus->endpoint_array);
+}
+
+void udc_startup_events(struct usb_device_instance *device)
+{
+	usbd_device_event_irq(device, DEVICE_INIT, 0);
+	usbd_device_event_irq(device, DEVICE_CREATE, 0);
+	udc_enable(device);
+}
+
+void udc_irq(void)
+{
+	mxc_irq_poll();
+}
+
+void udc_connect(void)
+{
+	mxc_usb_run();
+	mxc_udc_wait_cable_insert();
+}
+
+void udc_disconnect(void)
+{
+	/* imx6 will hang if access usb register without init oh3
+	 * clock, so not access it if not init. */
+	if (usb_inited)
+		mxc_usb_stop();
+}
+
+void udc_set_nak(int epid)
+{
+}
+
+void udc_unset_nak(int epid)
+{
+}
+
+#ifdef CONFIG_FASTBOOT
+
+#include <fastboot.h>
+
+struct EP_QUEUE_HEAD_T {
+    unsigned int config;
+    unsigned int current; /* read-only */
+
+    unsigned int next_queue_item;
+    unsigned int info;
+    unsigned int page0;
+    unsigned int page1;
+    unsigned int page2;
+    unsigned int page3;
+    unsigned int page4;
+    unsigned int reserved_0;
+
+    unsigned char setup_data[8];
+    unsigned int self_buf;
+    unsigned int deal_cnt;
+    unsigned int total_len;
+    unsigned char *deal_buf;
+};
+
+struct EP_DTD_ITEM_T {
+    unsigned int next_item_ptr;
+    unsigned int info;
+    unsigned int page0;
+    unsigned int page1;
+    unsigned int page2;
+    unsigned int page3;
+    unsigned int page4;
+    unsigned int reserved[9];
+};
+
+struct USB_CTRL_T {
+    struct EP_QUEUE_HEAD_T *qh_ptr;
+    struct EP_DTD_ITEM_T *dtd_ptr;
+    EP_HANDLER_P *handler_ptr;
+    u32 configed;
+    u32 max_ep;
+};
+
+struct USB_CTRL_T g_usb_ctrl;
+
+u8 *udc_get_descriptor(u8 type, u8 *plen)
+{
+    if (USB_DESCRIPTOR_TYPE_DEVICE == type) {
+	*plen = ep0_urb->device->device_descriptor->bLength;
+	return (u8 *)(ep0_urb->device->device_descriptor);
+    } else if (USB_DESCRIPTOR_TYPE_CONFIGURATION == type) {
+	*plen = ep0_urb->device->configuration_instance_array->
+			configuration_descriptor->wTotalLength;
+	return (u8 *)(ep0_urb->device->configuration_instance_array->
+			configuration_descriptor);
+    } else {
+	*plen = 0;
+	DBG_ERR("%s, wrong type:%x\n", __func__, type);
+	return NULL;
+    }
+}
+
+void udc_qh_setup(u32 index, u8 ep_type, u32 max_pkt_len, u32 zlt, u8 mult)
+{
+    u32 tmp = max_pkt_len << 16;
+    u32 offset;
+    struct EP_QUEUE_HEAD_T *qh_ptr;
+
+    if (index > EP15_IN_INDEX) {
+	DBG_ERR("%s:%d error, wrong index=%d\n", __func__, __LINE__, index);
+	return;
+    }
+
+    if (index >= EP0_IN_INDEX)
+	offset = (index-EP0_IN_INDEX) * 2 + 1;
+    else
+	offset = index * 2;
+
+    qh_ptr = g_usb_ctrl.qh_ptr + offset;
+
+    switch (ep_type) {
+    case USB_ENDPOINT_XFER_CONTROL:
+	tmp |= (1 << 15);
+	break;
+    case USB_ENDPOINT_XFER_ISOC:
+	tmp |= (mult << 30);
+	break;
+    case USB_ENDPOINT_XFER_BULK:
+    case USB_ENDPOINT_XFER_INT:
+	break;
+    default:
+	DBG_ERR("%s:%d, index=%d, error_type=%d\n",
+			__func__, __LINE__, index, ep_type);
+	return;
+    }
+    if (zlt)
+	tmp |= (1<<29);
+
+    qh_ptr->config = tmp;
+}
+
+void udc_dtd_setup(u32 index, u8 ep_type)
+{
+    u32 epctrl = 0;
+    u8 ep_num, dir;
+
+    if (index > EP15_IN_INDEX) {
+	DBG_ERR("%s:%d error, wrong index=%d", __func__, __LINE__, index);
+	return;
+    }
+
+    if (index >= EP0_IN_INDEX) {
+	ep_num = index - EP0_IN_INDEX;
+	dir = 1;
+    } else {
+	ep_num = index;
+	dir = 0;
+    }
+
+    epctrl = readl(USB_ENDPTCTRL(ep_num));
+    if (dir) {
+	if (ep_num != 0)
+		epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+	epctrl |= EPCTRL_TX_ENABLE;
+	epctrl |= ((u32)(ep_type) << EPCTRL_TX_EP_TYPE_SHIFT);
+    } else {
+	if (ep_num != 0)
+		epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+	epctrl |= EPCTRL_RX_ENABLE;
+	epctrl |= ((u32)(ep_type) << EPCTRL_RX_EP_TYPE_SHIFT);
+    }
+    writel(epctrl, USB_ENDPTCTRL(ep_num));
+}
+
+
+void udc_qh_dtd_init(u32 index)
+{
+    u32 i, tmp, max_len = 0;
+    u32 offset;
+
+    if (index > EP15_IN_INDEX) {
+	DBG_ERR("%s:%d error, wrong index=%d", __func__, __LINE__, index);
+	return;
+    }
+
+    if (index >= EP0_IN_INDEX)
+	offset = (index-EP0_IN_INDEX) * 2 + 1;
+    else
+	offset = index * 2;
+
+    struct EP_QUEUE_HEAD_T *qh_ptr = g_usb_ctrl.qh_ptr + offset;
+    struct EP_DTD_ITEM_T *dtd_ptr = g_usb_ctrl.dtd_ptr +
+					offset * EP_TQ_ITEM_SIZE;
+
+    if ((index == EP0_IN_INDEX) || (index == EP0_OUT_INDEX))
+	max_len = 64;
+    else
+	max_len = MAX_PAKET_LEN;
+
+    qh_ptr->self_buf = (u32)malloc_dma_buffer(&tmp, max_len,
+						USB_MEM_ALIGN_BYTE);
+    if (!qh_ptr->self_buf) {
+	DBG_ERR("malloc ep data buffer error\n");
+	return;
+    }
+    qh_ptr->next_queue_item = 0x1;
+
+    for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+	dtd_ptr[i].next_item_ptr = 1;
+	dtd_ptr[i].info  = 0x0;
+    }
+}
+
+int udc_recv_data(u32 index, u8 *buf, u32 recvlen, EP_HANDLER_P cb)
+{
+    u32 offset;
+    struct EP_DTD_ITEM_T *dtd_ptr;
+    struct EP_QUEUE_HEAD_T *qh_ptr;
+    u32 max_pkt_len, i;
+    u32 dtd_cnt = 0;
+    u32 len = recvlen;
+
+    if (index >= EP0_IN_INDEX) {
+	DBG_ERR("IN %d is trying to recv data\n", index);
+	return 0;
+    }
+
+    if (index != EP0_OUT_INDEX)
+	max_pkt_len = MAX_PAKET_LEN;
+    else
+	max_pkt_len = 64;
+
+    if ((len > max_pkt_len) && (!buf)) {
+	DBG_ERR("RecvData, wrong param\n");
+	return 0;
+    }
+
+    offset = index * 2;
+
+    dtd_ptr = g_usb_ctrl.dtd_ptr + offset*EP_TQ_ITEM_SIZE;
+    qh_ptr = g_usb_ctrl.qh_ptr + offset;
+    if (!buf)
+	buf = (u8 *)(qh_ptr->self_buf);
+
+    DBG_INFO("\n\n\n\nRecvData, index=%d, qh_ptr=0x%p, recvlen=0x%x, "
+				"recvbuf=0x%p\n", index, qh_ptr, len, buf);
+    for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+	if (dtd_ptr[i].info & 0x80) {
+		DBG_ERR("We got index=%d dtd%u error[0x%08x]\n",
+			index, i, dtd_ptr[i].info);
+	}
+    }
+
+    if (qh_ptr->total_len == 0) {
+	qh_ptr->total_len = recvlen;
+	qh_ptr->deal_buf = buf;
+	qh_ptr->deal_cnt = 0;
+	g_usb_ctrl.handler_ptr[index] = cb;
+    }
+
+    while (dtd_cnt < EP_TQ_ITEM_SIZE) {
+	u32 remain = 0x1000 - (((u32)buf)&0xfff);
+	dtd_ptr[dtd_cnt].page0 = (u32)buf;
+	dtd_ptr[dtd_cnt].page1 = (dtd_ptr[dtd_cnt].page0&0xfffff000) + 0x1000;
+	dtd_ptr[dtd_cnt].page2 = dtd_ptr[dtd_cnt].page1 + 0x1000;
+	dtd_ptr[dtd_cnt].page3 = dtd_ptr[dtd_cnt].page2 + 0x1000;
+	dtd_ptr[dtd_cnt].page4 = dtd_ptr[dtd_cnt].page3 + 0x1000;
+
+	if (len > (remain+16*1024)) { /*we need another dtd*/
+	    len -= (remain+16*1024);
+	    buf += (remain+16*1024);
+	    /*no interrupt here*/
+	    dtd_ptr[dtd_cnt].info = (((remain+16*1024)<<16) | (1<<7));
+	    if (dtd_cnt < (EP_TQ_ITEM_SIZE-1)) { /*we have another dtd*/
+		/*get dtd linked*/
+		dtd_ptr[dtd_cnt].next_item_ptr = (u32)(dtd_ptr+dtd_cnt+1);
+		DBG_INFO("we have another dtd, cnt=%u, remain=0x%x\n",
+							dtd_cnt, remain);
+		dtd_cnt++;
+		continue;
+	    } else { /*there is no more dtd, so we need to recv the dtd chain*/
+		dtd_ptr[dtd_cnt].next_item_ptr = 0x1;  /*dtd terminate*/
+		/*interrupt when transfer done*/
+		dtd_ptr[dtd_cnt].info |= (1<<15);
+		DBG_INFO("we have none dtd, cnt=%u, remain=%u, "
+				"len_left=0x%x\n", dtd_cnt, remain, len);
+		break;
+	    }
+	} else { /*we could recv all data in this dtd*/
+	    /*interrupt when transfer done*/
+	    dtd_ptr[dtd_cnt].info = ((len<<16) | (1<<15) | (1<<7));
+	    dtd_ptr[dtd_cnt].next_item_ptr = 0x1;  /*dtd terminate*/
+	    len = 0;
+	    DBG_INFO("we could done in this dtd, cnt=%u, remain=%u, "
+				"len_left=0x%x\n", dtd_cnt, remain, len);
+	    break;
+	}
+    }
+
+    for (i = dtd_cnt+1; i < EP_TQ_ITEM_SIZE; i++)
+	dtd_ptr[i].info = 0;
+
+    qh_ptr->next_queue_item = (u32)dtd_ptr;
+    qh_ptr->deal_cnt += (recvlen - len);
+    writel(1 << index, USB_ENDPTPRIME);
+    return qh_ptr->deal_cnt;
+}
+
+int udc_send_data(u32 index, u8 *buf, u32 sendlen, EP_HANDLER_P cb)
+{
+    u32 offset;
+    struct EP_DTD_ITEM_T *dtd_ptr;
+    struct EP_QUEUE_HEAD_T *qh_ptr;
+    u32 max_pkt_len, i;
+    u32 dtd_cnt = 0;
+    u32 len = sendlen;
+
+    if (index < EP0_IN_INDEX) {
+	DBG_ERR("OUT %d is trying to send data\n", index);
+	return 0;
+    }
+
+    if (index != EP0_IN_INDEX)
+	max_pkt_len = MAX_PAKET_LEN;
+    else
+	max_pkt_len = 64;
+
+    if ((len > max_pkt_len) && (!buf)) {
+	DBG_ERR("SendData, wrong param\n");
+	return 0;
+    }
+
+    offset = (index - EP0_IN_INDEX) * 2 + 1;
+
+    dtd_ptr = g_usb_ctrl.dtd_ptr + offset*EP_TQ_ITEM_SIZE;
+    qh_ptr = g_usb_ctrl.qh_ptr + offset;
+    if (!buf)
+	buf = (u8 *)(qh_ptr->self_buf);
+
+    DBG_INFO("\n\n\n\nSendData, index=%d, qh_ptr=0x%p, sendlen=0x%x, "
+				"sendbuf=0x%p\n", index, qh_ptr, len, buf);
+    for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+	if (dtd_ptr[i].info & 0x80) {
+		DBG_ERR("We got index=%d dtd%u error[0x%08x]\n",
+					index, i, dtd_ptr[i].info);
+	}
+    }
+
+    if (qh_ptr->total_len == 0) {
+	qh_ptr->total_len = sendlen;
+	qh_ptr->deal_buf = buf;
+	qh_ptr->deal_cnt = 0;
+	g_usb_ctrl.handler_ptr[index] = cb;
+    }
+
+    while (dtd_cnt < EP_TQ_ITEM_SIZE) {
+	u32 remain = 0x1000 - (((u32)buf)&0xfff);
+	dtd_ptr[dtd_cnt].page0 = (u32)buf;
+	dtd_ptr[dtd_cnt].page1 = (dtd_ptr[dtd_cnt].page0&0xfffff000) + 0x1000;
+	dtd_ptr[dtd_cnt].page2 = dtd_ptr[dtd_cnt].page1 + 0x1000;
+	dtd_ptr[dtd_cnt].page3 = dtd_ptr[dtd_cnt].page2 + 0x1000;
+	dtd_ptr[dtd_cnt].page4 = dtd_ptr[dtd_cnt].page3 + 0x1000;
+
+	if (len > (remain+16*1024)) { /*we need another dtd*/
+	    len -= (remain+16*1024);
+	    buf += (remain+16*1024);
+	    /*no interrupt here*/
+	    dtd_ptr[dtd_cnt].info = (((remain+16*1024)<<16) | (1<<7));
+	    if (dtd_cnt < (EP_TQ_ITEM_SIZE-1)) { /*we have another dtd*/
+		/*get dtd linked*/
+		dtd_ptr[dtd_cnt].next_item_ptr = (u32)(dtd_ptr+dtd_cnt+1);
+		DBG_INFO("we have another dtd, cnt=%u, remain=0x%x\n",
+				dtd_cnt, remain);
+		dtd_cnt++;
+		continue;
+	    } else { /*there is no more dtd, so we need to recv the dtd chain*/
+		dtd_ptr[dtd_cnt].next_item_ptr = 0x1;  /*dtd terminate*/
+		/*interrupt when transfer done*/
+		dtd_ptr[dtd_cnt].info |= (1<<15);
+		DBG_INFO("we have none dtd, cnt=%u, remain=%u, "
+				"len_left=0x%x\n", dtd_cnt, remain, len);
+		break;
+	    }
+	} else { /* we could recv all data in this dtd */
+	    /*interrupt when transfer done*/
+	    dtd_ptr[dtd_cnt].info = ((len<<16) | (1<<15) | (1<<7));
+	    dtd_ptr[dtd_cnt].next_item_ptr = 0x1;  /*dtd terminate*/
+	    len = 0;
+	    DBG_INFO("we could done in this dtd, cnt=%u, remain=%u, "
+				"len_left=0x%x\n", dtd_cnt, remain, len);
+	    break;
+	}
+    }
+
+    for (i = dtd_cnt+1; i < EP_TQ_ITEM_SIZE; i++)
+	dtd_ptr[i].info = 0;
+
+    qh_ptr->next_queue_item = (u32)dtd_ptr;
+    qh_ptr->deal_cnt += (sendlen - len);
+    writel(1 << index, USB_ENDPTPRIME);
+    return qh_ptr->deal_cnt;
+}
+
+static void udc_get_setup(void *s)
+{
+    u32 temp;
+    temp = readl(USB_ENDPTSETUPSTAT);
+    writel(temp, USB_ENDPTSETUPSTAT);
+    DBG_INFO("setup stat %x\n", temp);
+    do {
+	temp = readl(USB_USBCMD);
+	temp |= USB_CMD_SUTW;
+	writel(temp, USB_USBCMD);
+	memcpy((void *)s, (void *)g_usb_ctrl.qh_ptr[0].setup_data, 8);
+    } while (!(readl(USB_USBCMD) & USB_CMD_SUTW));
+
+    temp = readl(USB_USBCMD);
+    temp &= ~USB_CMD_SUTW;
+    writel(temp, USB_ENDPTSETUPSTAT);
+}
+
+static void ep_out_handler(u32 index)
+{
+    u32 offset = index*2;
+    struct EP_DTD_ITEM_T *dtd_ptr = g_usb_ctrl.dtd_ptr +
+						offset * EP_TQ_ITEM_SIZE;
+    struct EP_QUEUE_HEAD_T *qh_ptr = g_usb_ctrl.qh_ptr + offset;
+
+    u32 i, len = 0;
+
+    for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+	len += (dtd_ptr[i].info >> 16 & 0x7fff);
+	dtd_ptr[i].info = 0;
+    }
+
+    DBG_INFO("%s, index=%d, qh_ptr=0x%p\n", __func__, index, qh_ptr);
+    DBG_DEBUG("%s, index=%d, dealbuf=0x%p, len_cnt=0x%x, total_len=0x%x\n",
+	__func__, index, qh_ptr->deal_buf, qh_ptr->deal_cnt, qh_ptr->total_len);
+
+    if (qh_ptr->total_len < qh_ptr->deal_cnt)
+	DBG_ERR("index %d recv error, total=0x%x, cnt=0x%x\n",
+		index, qh_ptr->total_len, qh_ptr->deal_cnt);
+    if (qh_ptr->total_len != qh_ptr->deal_cnt) {
+	u32 nowcnt, precnt = qh_ptr->deal_cnt;
+	nowcnt = udc_recv_data(index, (u8 *)(qh_ptr->deal_buf+qh_ptr->deal_cnt),
+			qh_ptr->total_len - qh_ptr->deal_cnt,
+			g_usb_ctrl.handler_ptr[index]);
+	if (nowcnt > qh_ptr->total_len)
+		DBG_ERR("index %d recv error, total=0x%x, cnt=0x%x\n",
+			index, qh_ptr->total_len, qh_ptr->deal_cnt);
+	else if (nowcnt == qh_ptr->total_len)
+		DBG_ALWS("\rreceive 100%\n");
+	else
+		DBG_ALWS("\rreceive %d%", precnt/(qh_ptr->total_len/100));
+    } else {
+	qh_ptr->total_len = 0;
+	if (g_usb_ctrl.handler_ptr[index]) {
+		g_usb_ctrl.handler_ptr[index](qh_ptr->deal_cnt-len,
+						(u8 *)(qh_ptr->deal_buf));
+	}
+    }
+}
+
+static void ep_in_handler(u32 index)
+{
+    u32 offset = (index-EP0_IN_INDEX) * 2 + 1;
+    struct EP_DTD_ITEM_T *dtd_ptr = g_usb_ctrl.dtd_ptr +
+					offset * EP_TQ_ITEM_SIZE;
+    struct EP_QUEUE_HEAD_T *qh_ptr = g_usb_ctrl.qh_ptr + offset;
+
+    u32 i, len = 0;
+    for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+	len += (dtd_ptr[i].info >> 16 & 0x7fff);
+	dtd_ptr[i].info = 0;
+    }
+
+    DBG_INFO("%s, index=%d, qh_ptr=0x%p\n", __func__, index, qh_ptr);
+    DBG_DEBUG("%s, index=%d, dealbuf=0x%p, len_cnt=0x%x, total_len=0x%x\n",
+	__func__, index, qh_ptr->deal_buf, qh_ptr->deal_cnt, qh_ptr->total_len);
+
+    if (qh_ptr->total_len < qh_ptr->deal_cnt)
+	DBG_ERR("index %d send error, total=0x%x, cnt=0x%x\n",
+		index, qh_ptr->total_len, qh_ptr->deal_cnt);
+    if (qh_ptr->total_len != qh_ptr->deal_cnt) {
+	u32 nowcnt, precnt = qh_ptr->deal_cnt;
+	nowcnt = udc_send_data(index, (u8 *)(qh_ptr->deal_buf+qh_ptr->deal_cnt),
+			qh_ptr->total_len - qh_ptr->deal_cnt,
+			g_usb_ctrl.handler_ptr[index]);
+	if (nowcnt > (qh_ptr->total_len))
+		DBG_ERR("index %d recv error, total=0x%x, cnt=0x%x\n",
+			index, qh_ptr->total_len, qh_ptr->deal_cnt);
+	else if (nowcnt == qh_ptr->total_len)
+		DBG_ALWS("\rreceive 100%\n");
+	else
+		DBG_ALWS("\rreceive %d%", precnt/(qh_ptr->total_len/100));
+    } else {
+	qh_ptr->total_len = 0;
+	if (g_usb_ctrl.handler_ptr[index]) {
+		g_usb_ctrl.handler_ptr[index](qh_ptr->deal_cnt-len,
+						(u8 *)(qh_ptr->deal_buf));
+	}
+    }
+}
+
+int udc_irq_handler(void)
+{
+    u32 irq_src = readl(USB_USBSTS) & readl(USB_USBINTR);
+    writel(irq_src, USB_USBSTS);
+
+    if (!(readl(USB_OTGSC) & OTGSC_B_SESSION_VALID)) {
+	DBG_ALWS("USB disconnect\n");
+	return -1;
+    }
+
+    if (irq_src == 0)
+	return g_usb_ctrl.configed;
+
+    DBG_DEBUG("\nGet USB irq: 0x%x\n", irq_src);
+
+    if (irq_src & USB_STS_INT) {
+	u32 complete, i;
+
+	complete = readl(USB_ENDPTCOMPLETE);
+	writel(complete, USB_ENDPTCOMPLETE);
+	if (complete) {
+		DBG_INFO("Dtd complete irq, 0x%x\n", complete);
+		for (i = 0;  i < g_usb_ctrl.max_ep; i++) {
+			if (complete & (1<<i))
+				ep_out_handler(i);
+
+			if (complete & (1<<(i+EP0_IN_INDEX)))
+				ep_in_handler(i+EP0_IN_INDEX);
+		}
+	}
+
+	if (readl(USB_ENDPTSETUPSTAT)) {
+		u32 setup[2];
+		DBG_INFO("recv setup packet\n");
+		udc_get_setup(setup);
+		if (ep0_parse_setup(setup) < 0)
+			mxc_ep0_stall();
+	}
+    }
+
+    if (irq_src & USB_STS_RESET) {
+	u32 temp;
+	temp = readl(USB_DEVICEADDR);
+	temp &= ~0xfe000000;
+	writel(temp, USB_DEVICEADDR);
+	writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
+	writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
+	while (readl(USB_ENDPTPRIME))
+			;
+	writel(0xffffffff, USB_ENDPTFLUSH);
+	DBG_DEBUG("USB_RESET, PORTSC = 0x%x\n", readl(USB_PORTSC1));
+    }
+
+    if (irq_src & USB_STS_PORT_CHANGE) {
+	u32 speed;
+	while (readl(USB_PORTSC1) & PORTSCX_PORT_RESET)
+		;
+	speed = readl(USB_PORTSC1) & PORTSCX_PORT_SPEED_MASK;
+	DBG_DEBUG("USB port changed, speed = 0x%x\n", speed);
+    }
+
+    if (irq_src & USB_STS_SUSPEND)
+	DBG_DEBUG("USB_SUSPEND\n");
+
+    if (irq_src & USB_STS_ERR)
+	DBG_ERR("USB_ERR\n");
+
+    return g_usb_ctrl.configed;
+}
+
+void udc_set_addr(u8 addr)
+{
+    writel((addr << 25) | (1<<24), USB_DEVICEADDR);
+}
+
+void udc_set_configure(u8 config)
+{
+    g_usb_ctrl.configed = config;
+}
+
+void udc_run(void)
+{
+    unsigned int reg;
+    /* Set controller to Run */
+    reg = readl(USB_USBCMD);
+    reg |= USB_CMD_RUN_STOP;
+    writel(reg, USB_USBCMD);
+}
+
+
+void udc_wait_connect(void)
+{
+	unsigned int reg;
+	do {
+		udelay(50);
+		reg = readl(USB_OTGSC);
+		if (reg & (OTGSC_B_SESSION_VALID))
+			break;
+	} while (1);
+}
+
+
+void udc_hal_data_init(void)
+{
+    u32 size, tmp;
+
+    g_usb_ctrl.max_ep = (readl(USB_DCCPARAMS) & DCCPARAMS_DEN_MASK);
+    udc_set_configure(0);
+    size = g_usb_ctrl.max_ep * 2 * sizeof(struct EP_QUEUE_HEAD_T);
+    if (g_usb_ctrl.qh_ptr == NULL)
+	g_usb_ctrl.qh_ptr = malloc_dma_buffer(&tmp, size, USB_MEM_ALIGN_BYTE);
+    if (g_usb_ctrl.qh_ptr == NULL) {
+	DBG_ERR("malloc ep qh error\n");
+	return;
+    }
+    memset(g_usb_ctrl.qh_ptr, 0, size);
+    writel(((u32)(g_usb_ctrl.qh_ptr)) & 0xfffff800, USB_ENDPOINTLISTADDR);
+
+    size = g_usb_ctrl.max_ep * 2
+		* sizeof(struct EP_DTD_ITEM_T) * EP_TQ_ITEM_SIZE;
+    if (g_usb_ctrl.dtd_ptr == NULL)
+	g_usb_ctrl.dtd_ptr = malloc_dma_buffer(&tmp, size, USB_MEM_ALIGN_BYTE);
+    if (g_usb_ctrl.dtd_ptr == NULL) {
+	DBG_ERR("malloc ep dtd error\n");
+	return;
+    }
+    memset(g_usb_ctrl.dtd_ptr, 0, size);
+
+    size = (EP15_IN_INDEX + 1) * sizeof(EP_HANDLER_P);
+    if (g_usb_ctrl.handler_ptr == NULL)
+	g_usb_ctrl.handler_ptr = malloc_dma_buffer(&tmp, size, 4);
+
+    if (g_usb_ctrl.handler_ptr == NULL) {
+	DBG_ERR("malloc ep dtd error\n");
+	return;
+    }
+    memset(g_usb_ctrl.handler_ptr, 0, size);
+
+    DBG_INFO("USB max ep = %d, qh_addr = 0x%p, dtd_addr = 0x%p\n",
+	g_usb_ctrl.max_ep, g_usb_ctrl.qh_ptr, g_usb_ctrl.dtd_ptr);
+
+    udc_qh_dtd_init(EP0_OUT_INDEX);
+    udc_qh_dtd_init(EP0_IN_INDEX);
+
+    udc_qh_setup(EP0_OUT_INDEX, USB_ENDPOINT_XFER_CONTROL,
+					USB_MAX_CTRL_PAYLOAD, 0, 0);
+    udc_qh_setup(EP0_IN_INDEX, USB_ENDPOINT_XFER_CONTROL,
+					USB_MAX_CTRL_PAYLOAD, 0, 0);
+
+    udc_dtd_setup(EP0_OUT_INDEX, USB_ENDPOINT_XFER_CONTROL);
+    udc_dtd_setup(EP0_IN_INDEX, USB_ENDPOINT_XFER_CONTROL);
+}
+
+#endif  /* CONFIG_FASTBOOT */

+ 33 - 7
include/configs/vf610twr.h

@@ -27,6 +27,31 @@
 
 #define CONFIG_VF610
 
+#define CONFIG_USB_DEVICE
+#define CONFIG_IMX_UDC                 1
+#define CONFIG_FASTBOOT                1
+#define CONFIG_FASTBOOT_STORAGE_EMMC_SATA
+#define CONFIG_FASTBOOT_VENDOR_ID      0x18d1
+#define CONFIG_FASTBOOT_PRODUCT_ID     0x0d02
+#define CONFIG_FASTBOOT_BCD_DEVICE     0x311
+#define CONFIG_FASTBOOT_MANUFACTURER_STR  "Freescale"
+#define CONFIG_FASTBOOT_PRODUCT_NAME_STR "i.mx6q Sabre Smart Device"
+#define CONFIG_FASTBOOT_INTERFACE_STR    "Android fastboot"
+#define CONFIG_FASTBOOT_CONFIGURATION_STR  "Android fastboot"
+#define CONFIG_FASTBOOT_SERIAL_NUM      "12345"
+#define CONFIG_FASTBOOT_SATA_NO          0
+
+/*  For system.img growing up more than 256MB, more buffer needs
+ *  *   to receive the system.img*/
+#define CONFIG_FASTBOOT_TRANSFER_BUF    0x2c000000
+#define CONFIG_FASTBOOT_TRANSFER_BUF_SIZE 0x14000000 /* 320M byte */
+/* which mmc bus is your main storage ? */
+#define CONFIG_ANDROID_MAIN_MMC_BUS 3
+#define CONFIG_ANDROID_BOOT_PARTITION_MMC 1
+#define CONFIG_ANDROID_SYSTEM_PARTITION_MMC 5
+#define CONFIG_ANDROID_RECOVERY_PARTITION_MMC 2
+#define CONFIG_ANDROID_CACHE_PARTITION_MMC 6
+
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
 
@@ -43,7 +68,7 @@
 #endif
 
 /* Size of malloc() pool */
-#define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + 2 * 1024 * 1024)
+#define CONFIG_SYS_MALLOC_LEN		(16<<10)
 
 #define CONFIG_BOARD_EARLY_INIT_F
 
@@ -83,7 +108,7 @@
 
 #define CONFIG_BOOTDELAY		3
 
-#define CONFIG_LOADADDR			0x82000000
+#define CONFIG_LOADADDR			0x3f400000
 #define CONFIG_SYS_TEXT_BASE		0x3f008000
 
 #define CONFIG_EXTRA_ENV_SETTINGS \
@@ -186,8 +211,8 @@
 #define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
 
 #define CONFIG_CMD_MEMTEST
-#define CONFIG_SYS_MEMTEST_START	0x80010000
-#define CONFIG_SYS_MEMTEST_END		0x87C00000
+#define CONFIG_SYS_MEMTEST_START	0x3f400000
+#define CONFIG_SYS_MEMTEST_END		0x3f480000
 
 #define CONFIG_SYS_LOAD_ADDR		CONFIG_LOADADDR
 #define CONFIG_SYS_HZ			1000
@@ -200,8 +225,8 @@
 
 /* Physical memory map */
 #define CONFIG_NR_DRAM_BANKS		1
-#define PHYS_SDRAM			(0x80000000)
-#define PHYS_SDRAM_SIZE			(128 * 1024 * 1024)
+#define PHYS_SDRAM			(0x3f400000)
+#define PHYS_SDRAM_SIZE			(512 * 1024)
 
 #define CONFIG_SYS_SDRAM_BASE		PHYS_SDRAM
 #define CONFIG_SYS_INIT_RAM_ADDR	IRAM_BASE_ADDR
@@ -216,7 +241,8 @@
 #define CONFIG_SYS_NO_FLASH
 
 #define CONFIG_ENV_SIZE			(8 * 1024)
-#define CONFIG_ENV_IS_IN_MMC
+#undef CONFIG_ENV_IS_IN_MMC
+#define CONFIG_ENV_IS_NOWHERE
 
 #define CONFIG_ENV_OFFSET		(12 * 64 * 1024)
 #define CONFIG_SYS_MMC_ENV_DEV		0

+ 382 - 0
include/fastboot.h

@@ -0,0 +1,382 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright (C) 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * 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>
+
+/* This is the interface file between the common cmd_fastboot.c and
+   the board specific support.
+
+   To use this interface, define CONFIG_FASTBOOT in your board config file.
+   An example is include/configs/omap3430labrador.h
+   ...
+   #define CONFIG_FASTBOOT	        1    / * Using fastboot interface * /
+   ...
+
+   An example of the board specific spupport for omap3 is found at
+   cpu/omap3/fastboot.c
+
+*/
+
+/* 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
+
+enum {
+    DEV_SATA,
+    DEV_MMC,
+    DEV_NAND
+};
+
+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);
+
+	/* 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;
+
+	/* Nand block size
+	   Supports the write option WRITE_NEXT_GOOD_BLOCK
+
+	   Set by board */
+	unsigned int nand_block_size;
+
+	/* Nand oob size
+	   Set by board */
+	unsigned int nand_oob_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;
+	/* partition id: 0 - normal partition; 1 - boot partition */
+	unsigned int partition_id;
+};
+
+struct fastboot_device_info {
+	unsigned char type;
+	unsigned char dev_id;
+};
+
+/* 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
+
+/* Status values */
+#define FASTBOOT_OK			0
+#define FASTBOOT_ERROR			-1
+#define FASTBOOT_DISCONNECT		1
+#define FASTBOOT_INACTIVE		2
+
+/* 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 */
+};
+
+#ifdef CONFIG_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 */
+int fastboot_preboot(void);
+
+/* Initizes the board specific fastboot
+   Returns 0 on success
+   Returns 1 on failure */
+int fastboot_init(struct cmd_fastboot_interface *interface);
+
+/* Cleans up the board specific fastboot */
+void fastboot_shutdown(void);
+
+/*
+ * Handles board specific usb protocol exchanges
+ * Returns 0 on success
+ * Returns 1 on disconnects, break out of loop
+ * Returns 2 if no USB activity detected
+ * Returns -1 on failure, unhandled usb requests and other error conditions
+*/
+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 */
+int fastboot_is_highspeed(void);
+
+/* Return the size of the fifo */
+int fastboot_fifo_size(void);
+
+/* Send a status reply to the client app
+   buffer does not have to be null terminated.
+   buffer_size must be not be larger than what is returned by
+   fastboot_fifo_size
+   Returns 0 on success
+   Returns 1 on failure */
+int fastboot_tx_status(const char *buffer, unsigned int buffer_size);
+
+/*
+ * Send some data to the client app
+ * buffer does not have to be null terminated.
+ * buffer_size can be larger than what is returned by
+ * fastboot_fifo_size
+ * Returns number of bytes written
+ */
+int fastboot_tx(unsigned char *buffer, unsigned int buffer_size);
+
+/* 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 */
+int fastboot_getvar(const char *rx_buffer, char *tx_buffer);
+
+/* The Android-style flash handling */
+
+/* tools to populate and query the partition table */
+void fastboot_flash_add_ptn(fastboot_ptentry *ptn);
+fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
+fastboot_ptentry *fastboot_flash_get_ptn(unsigned n);
+unsigned int fastboot_flash_get_ptn_count(void);
+void fastboot_flash_dump_ptn(void);
+
+int fastboot_flash_init(void);
+int fastboot_flash_erase(fastboot_ptentry *ptn);
+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)
+int fastboot_flash_write(fastboot_ptentry *ptn, unsigned extra_per_page,
+				const void *data, unsigned bytes);
+
+/* Check the board special boot mode reboot to fastboot mode. */
+int fastboot_check_and_clean_flag(void);
+int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+void check_fastboot_mode(void);
+
+
+void fastboot_quick(u8 debug);
+int  fastboot_write_storage(u8 *partition_name, u32 write_len);
+void fastboot_dump_memory(u32 *ptr, u32 lEN);
+void fastboot_get_ep_num(u8 *in, u8 *out);
+extern u8 fastboot_debug_level;
+#define DBG_ALWS(x...)    printf(x)
+#define DBG_ERR(x...)     printf(x)
+#define DBG_DEBUG(x...)   if (fastboot_debug_level >= 1) printf(x)
+#define DBG_INFO(x...)    if (fastboot_debug_level >= 2) printf(x)
+
+
+#else
+
+/* Stubs for when CONFIG_FASTBOOT is not defined */
+#define fastboot_preboot() 0
+#define fastboot_init(a) 1
+#define fastboot_shutdown()
+#define fastboot_poll() 1
+#define fastboot_is_highspeed() 0
+#define fastboot_fifo_size() 0
+#define fastboot_tx_status(a, b) 1
+#define fastboot_getvar(a, b) 1
+#define fastboot_tx(a, b) 1
+
+#define fastboot_flash_add_ptn(a)
+#define fastboot_flash_find_ptn(a) NULL
+#define fastboot_flash_get_ptn(a) NULL
+#define fastboot_flash_get_ptn_count() 0
+#define fastboot_flash_dump_ptn()
+#define fastboot_flash_init()
+#define fastboot_flash_erase(a) 1
+#define fastboot_flash_read_ext(a, b, c, d, e) 0
+#define fastboot_flash_read(a, b, c, d, e) 0
+#define fastboot_flash_write(a, b, c, d) 0
+#define do_fastboot(a, b, c, d) 0
+
+
+#define fastboot_quick(a) 0
+#define fastboot_get_ep_num(a, b)  0
+#define fastboot_dump_memory(a, b) 0
+#define DBG_ALWS(x...)
+#define DBG_ERR(x...)
+#define DBG_DEBUG(x...)
+#define DBG_INFO(x...)
+
+
+#endif /* CONFIG_FASTBOOT */
+#endif /* FASTBOOT_H */

+ 549 - 0
include/usb/imx_udc.h

@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2010-2012 Freescale Semiconductor, Inc.
+ *
+ * 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 _IMX_UDC_H_
+#define _IMX_UDC_H_
+
+#include <usbdevice.h>
+
+#define USB_OTGREGS_BASE	(OTG_BASE_ADDR + 0x000)
+#define USB_H1REGS_BASE		(OTG_BASE_ADDR + 0x200)
+#define USB_H2REGS_BASE		(OTG_BASE_ADDR + 0x400)
+#if (defined CONFIG_MX51 || defined CONFIG_MX50 || defined CONFIG_MX6Q \
+     || defined CONFIG_MX53 || defined CONFIG_MX6DL || defined CONFIG_MX6SL)
+#define USB_H3REGS_BASE		(OTG_BASE_ADDR + 0x600)
+#define USB_OTHERREGS_BASE	(OTG_BASE_ADDR + 0x800)
+#else
+#define USB_OTHERREGS_BASE	(OTG_BASE_ADDR + 0x600)
+#endif
+
+#define USBOTG_REG32(offset)	(USB_OTGREGS_BASE + (offset))
+#define USBOTG_REG16(offset)	(USB_OTGREGS_BASE + (offset))
+#define USBOTHER_REG(offset)	(USB_OTHERREGS_BASE + (offset))
+
+#define USB_ID               (OTG_BASE_ADDR + 0x0000)
+#define USB_HWGENERAL        (OTG_BASE_ADDR + 0x0004)
+#define USB_HWHOST           (OTG_BASE_ADDR + 0x0008)
+#define USB_HWDEVICE         (OTG_BASE_ADDR + 0x000C)
+#define USB_HWTXBUF          (OTG_BASE_ADDR + 0x0010)
+#define USB_HWRXBUF          (OTG_BASE_ADDR + 0x0014)
+#define USB_SBUSCFG          (OTG_BASE_ADDR + 0x0090)
+
+#define USB_CAPLENGTH        (OTG_BASE_ADDR + 0x0100) /* 8 bit */
+#define USB_HCIVERSION       (OTG_BASE_ADDR + 0x0102) /* 16 bit */
+#define USB_HCSPARAMS        (OTG_BASE_ADDR + 0x0104)
+#define USB_HCCPARAMS        (OTG_BASE_ADDR + 0x0108)
+#define USB_DCIVERSION       (OTG_BASE_ADDR + 0x0120) /* 16 bit */
+#define USB_DCCPARAMS        (OTG_BASE_ADDR + 0x0124)
+#define USB_USBCMD           (OTG_BASE_ADDR + 0x0140)
+#define USB_USBSTS           (OTG_BASE_ADDR + 0x0144)
+#define USB_USBINTR          (OTG_BASE_ADDR + 0x0148)
+#define USB_FRINDEX          (OTG_BASE_ADDR + 0x014C)
+#define USB_DEVICEADDR       (OTG_BASE_ADDR + 0x0154)
+#define USB_ENDPOINTLISTADDR (OTG_BASE_ADDR + 0x0158)
+#define USB_BURSTSIZE        (OTG_BASE_ADDR + 0x0160)
+#define USB_TXFILLTUNING     (OTG_BASE_ADDR + 0x0164)
+#define USB_ULPI_VIEWPORT    (OTG_BASE_ADDR + 0x0170)
+#define USB_ENDPTNAK         (OTG_BASE_ADDR + 0x0178)
+#define USB_ENDPTNAKEN       (OTG_BASE_ADDR + 0x017C)
+#define USB_PORTSC1          (OTG_BASE_ADDR + 0x0184)
+#define USB_OTGSC            (OTG_BASE_ADDR + 0x01A4)
+#define USB_USBMODE          (OTG_BASE_ADDR + 0x01A8)
+#define USB_ENDPTSETUPSTAT   (OTG_BASE_ADDR + 0x01AC)
+#define USB_ENDPTPRIME       (OTG_BASE_ADDR + 0x01B0)
+#define USB_ENDPTFLUSH       (OTG_BASE_ADDR + 0x01B4)
+#define USB_ENDPTSTAT        (OTG_BASE_ADDR + 0x01B8)
+#define USB_ENDPTCOMPLETE    (OTG_BASE_ADDR + 0x01BC)
+#define USB_ENDPTCTRL(n)     (OTG_BASE_ADDR + 0x01C0 + (4 * (n)))
+
+/*
+ * other regs (not part of ARC core)
+ */
+#define USBCTRL			USBOTHER_REG(0x00)	/* USB Control register */
+#define USB_OTG_MIRROR		USBOTHER_REG(0x04)	/* USB OTG mirror register */
+#define USB_PHY_CTR_FUNC	USBOTHER_REG(0x08)      /* OTG UTMI PHY Function Control register */
+#define USB_PHY_CTR_FUNC2	USBOTHER_REG(0x0c)      /* OTG UTMI PHY Function Control register */
+#define USB_CTRL_1		USBOTHER_REG(0x10)	/* USB Cotrol Register 1*/
+#define USBCTRL_HOST2		USBOTHER_REG(0x14)	/* USB Cotrol Register 1*/
+#define USBCTRL_HOST3		USBOTHER_REG(0x18)	/* USB Cotrol Register 1*/
+#define USBH1_PHY_CTRL0		USBOTHER_REG(0x1c)	/* USB Cotrol Register 1*/
+#define USBH1_PHY_CTRL1		USBOTHER_REG(0x20)	/* USB Cotrol Register 1*/
+#define USB_CLKONOFF_CTRL       USBOTHER_REG(0x24)      /* USB Clock on/off Control Register */
+/* mx6x other regs */
+#define USB_OTG_CTRL			USBOTHER_REG(0x00)	/* USB OTG Control register */
+#define USB_H1_CTRL			USBOTHER_REG(0x04)	/* USB H1 Control register */
+#define USB_H2_CTRL			USBOTHER_REG(0x08)	/* USB H2 Control register */
+#define USB_H3_CTRL			USBOTHER_REG(0x0c)	/* USB H3 Control register */
+#define USB_UH2_HSIC_CTRL		USBOTHER_REG(0x10)	/* USB Host2 HSIC Control Register */
+#define USB_UH3_HSIC_CTRL		USBOTHER_REG(0x14)	/* USB Host3 HSIC Control Register */
+#define USB_OTG_PHY_CTRL_0		USBOTHER_REG(0x18)	/* OTG UTMI PHY Control 0 Register */
+#define USB_H1_PHY_CTRL_0		USBOTHER_REG(0x1c)	/* OTG UTMI PHY Control 1 Register */
+#define USB_UH2_HSIC_DLL_CFG1		USBOTHER_REG(0x20)      /* USB Host2 HSIC DLL Configuration Register 1 */
+#define USB_UH2_HSIC_DLL_CFG2		USBOTHER_REG(0x24)      /* USB Host2 HSIC DLL Configuration Register 2 */
+#define USB_UH2_HSIC_DLL_CFG3		USBOTHER_REG(0x28)      /* USB Host2 HSIC DLL Configuration Register 3 */
+#define USB_UH3_HSIC_DLL_CFG1		USBOTHER_REG(0x30)      /* USB Host3 HSIC DLL Configuration Register 1 */
+#define USB_UH3_HSIC_DLL_CFG2		USBOTHER_REG(0x34)      /* USB Host3 HSIC DLL Configuration Register 2 */
+#define USB_UH3_HSIC_DLL_CFG3		USBOTHER_REG(0x38)      /* USB Host3 HSIC DLL Configuration Register 3 */
+
+
+#define USB_PHY1_CTRL        (OTG_BASE_ADDR + 0x80C)
+#define USBCMD_RESET   2
+#define USBCMD_ATTACH  1
+
+#define USBMODE_DEVICE 2
+#define USBMODE_HOST   3
+
+struct ep_queue_head {
+	volatile unsigned int config;
+	volatile unsigned int current; /* read-only */
+
+	volatile unsigned int next_queue_item;
+	volatile unsigned int info;
+	volatile unsigned int page0;
+	volatile unsigned int page1;
+	volatile unsigned int page2;
+	volatile unsigned int page3;
+	volatile unsigned int page4;
+	volatile unsigned int reserved_0;
+
+	volatile unsigned char setup_data[8];
+	volatile unsigned int reserved[4];
+};
+
+#define CONFIG_MAX_PKT(n)     ((n) << 16)
+#define CONFIG_ZLT            (1 << 29)    /* stop on zero-len xfer */
+#define CONFIG_IOS            (1 << 15)    /* IRQ on setup */
+
+struct ep_queue_item {
+	volatile unsigned int next_item_ptr;
+	volatile unsigned int info;
+	volatile unsigned int page0;
+	volatile unsigned int page1;
+	volatile unsigned int page2;
+	volatile unsigned int page3;
+	volatile unsigned int page4;
+	unsigned int item_dma;
+	unsigned int page_vir;
+	unsigned int page_dma;
+	struct ep_queue_item *next_item_vir;
+	volatile unsigned int reserved[5];
+};
+
+#define TERMINATE 1
+
+#define INFO_BYTES(n)         ((n) << 16)
+#define INFO_IOC              (1 << 15)
+#define INFO_ACTIVE           (1 << 7)
+#define INFO_HALTED           (1 << 6)
+#define INFO_BUFFER_ERROR     (1 << 5)
+#define INFO_TX_ERROR         (1 << 3)
+
+/* Device Controller Capability Parameter register */
+#define DCCPARAMS_DC				0x00000080
+#define DCCPARAMS_DEN_MASK			0x0000001f
+
+/* Frame Index Register Bit Masks */
+#define	USB_FRINDEX_MASKS			(0x3fff)
+/* USB CMD  Register Bit Masks */
+#define  USB_CMD_RUN_STOP                     (0x00000001)
+#define  USB_CMD_CTRL_RESET                   (0x00000002)
+#define  USB_CMD_PERIODIC_SCHEDULE_EN         (0x00000010)
+#define  USB_CMD_ASYNC_SCHEDULE_EN            (0x00000020)
+#define  USB_CMD_INT_AA_DOORBELL              (0x00000040)
+#define  USB_CMD_ASP                          (0x00000300)
+#define  USB_CMD_ASYNC_SCH_PARK_EN            (0x00000800)
+#define  USB_CMD_SUTW                         (0x00002000)
+#define  USB_CMD_ATDTW                        (0x00004000)
+#define  USB_CMD_ITC                          (0x00FF0000)
+
+/* bit 15,3,2 are frame list size */
+#define  USB_CMD_FRAME_SIZE_1024              (0x00000000)
+#define  USB_CMD_FRAME_SIZE_512               (0x00000004)
+#define  USB_CMD_FRAME_SIZE_256               (0x00000008)
+#define  USB_CMD_FRAME_SIZE_128               (0x0000000C)
+#define  USB_CMD_FRAME_SIZE_64                (0x00008000)
+#define  USB_CMD_FRAME_SIZE_32                (0x00008004)
+#define  USB_CMD_FRAME_SIZE_16                (0x00008008)
+#define  USB_CMD_FRAME_SIZE_8                 (0x0000800C)
+
+/* bit 9-8 are async schedule park mode count */
+#define  USB_CMD_ASP_00                       (0x00000000)
+#define  USB_CMD_ASP_01                       (0x00000100)
+#define  USB_CMD_ASP_10                       (0x00000200)
+#define  USB_CMD_ASP_11                       (0x00000300)
+#define  USB_CMD_ASP_BIT_POS                  (8)
+
+/* bit 23-16 are interrupt threshold control */
+#define  USB_CMD_ITC_NO_THRESHOLD             (0x00000000)
+#define  USB_CMD_ITC_1_MICRO_FRM              (0x00010000)
+#define  USB_CMD_ITC_2_MICRO_FRM              (0x00020000)
+#define  USB_CMD_ITC_4_MICRO_FRM              (0x00040000)
+#define  USB_CMD_ITC_8_MICRO_FRM              (0x00080000)
+#define  USB_CMD_ITC_16_MICRO_FRM             (0x00100000)
+#define  USB_CMD_ITC_32_MICRO_FRM             (0x00200000)
+#define  USB_CMD_ITC_64_MICRO_FRM             (0x00400000)
+#define  USB_CMD_ITC_BIT_POS                  (16)
+
+/* USB STS Register Bit Masks */
+#define  USB_STS_INT                          (0x00000001)
+#define  USB_STS_ERR                          (0x00000002)
+#define  USB_STS_PORT_CHANGE                  (0x00000004)
+#define  USB_STS_FRM_LST_ROLL                 (0x00000008)
+#define  USB_STS_SYS_ERR                      (0x00000010)
+#define  USB_STS_IAA                          (0x00000020)
+#define  USB_STS_RESET                        (0x00000040)
+#define  USB_STS_SOF                          (0x00000080)
+#define  USB_STS_SUSPEND                      (0x00000100)
+#define  USB_STS_HC_HALTED                    (0x00001000)
+#define  USB_STS_RCL                          (0x00002000)
+#define  USB_STS_PERIODIC_SCHEDULE            (0x00004000)
+#define  USB_STS_ASYNC_SCHEDULE               (0x00008000)
+
+/* USB INTR Register Bit Masks */
+#define  USB_INTR_INT_EN                      (0x00000001)
+#define  USB_INTR_ERR_INT_EN                  (0x00000002)
+#define  USB_INTR_PTC_DETECT_EN               (0x00000004)
+#define  USB_INTR_FRM_LST_ROLL_EN             (0x00000008)
+#define  USB_INTR_SYS_ERR_EN                  (0x00000010)
+#define  USB_INTR_ASYN_ADV_EN                 (0x00000020)
+#define  USB_INTR_RESET_EN                    (0x00000040)
+#define  USB_INTR_SOF_EN                      (0x00000080)
+#define  USB_INTR_DEVICE_SUSPEND              (0x00000100)
+
+/* Device Address bit masks */
+#define  USB_DEVICE_ADDRESS_MASK              (0xFE000000)
+#define  USB_DEVICE_ADDRESS_BIT_POS           (25)
+
+/* endpoint list address bit masks */
+#define USB_EP_LIST_ADDRESS_MASK              (0xfffff800)
+
+/* PORTSCX  Register Bit Masks */
+#define  PORTSCX_CURRENT_CONNECT_STATUS       (0x00000001)
+#define  PORTSCX_CONNECT_STATUS_CHANGE        (0x00000002)
+#define  PORTSCX_PORT_ENABLE                  (0x00000004)
+#define  PORTSCX_PORT_EN_DIS_CHANGE           (0x00000008)
+#define  PORTSCX_OVER_CURRENT_ACT             (0x00000010)
+#define  PORTSCX_OVER_CURRENT_CHG             (0x00000020)
+#define  PORTSCX_PORT_FORCE_RESUME            (0x00000040)
+#define  PORTSCX_PORT_SUSPEND                 (0x00000080)
+#define  PORTSCX_PORT_RESET                   (0x00000100)
+#define  PORTSCX_LINE_STATUS_BITS             (0x00000C00)
+#define  PORTSCX_PORT_POWER                   (0x00001000)
+#define  PORTSCX_PORT_INDICTOR_CTRL           (0x0000C000)
+#define  PORTSCX_PORT_TEST_CTRL               (0x000F0000)
+#define  PORTSCX_WAKE_ON_CONNECT_EN           (0x00100000)
+#define  PORTSCX_WAKE_ON_CONNECT_DIS          (0x00200000)
+#define  PORTSCX_WAKE_ON_OVER_CURRENT         (0x00400000)
+#define  PORTSCX_PHY_LOW_POWER_SPD            (0x00800000)
+#define  PORTSCX_PORT_FORCE_FULL_SPEED        (0x01000000)
+#define  PORTSCX_PORT_SPEED_MASK              (0x0C000000)
+#define  PORTSCX_PORT_WIDTH                   (0x10000000)
+#define  PORTSCX_PHY_TYPE_SEL                 (0xC0000000)
+
+/* bit 11-10 are line status */
+#define  PORTSCX_LINE_STATUS_SE0              (0x00000000)
+#define  PORTSCX_LINE_STATUS_JSTATE           (0x00000400)
+#define  PORTSCX_LINE_STATUS_KSTATE           (0x00000800)
+#define  PORTSCX_LINE_STATUS_UNDEF            (0x00000C00)
+#define  PORTSCX_LINE_STATUS_BIT_POS          (10)
+
+/* bit 15-14 are port indicator control */
+#define  PORTSCX_PIC_OFF                      (0x00000000)
+#define  PORTSCX_PIC_AMBER                    (0x00004000)
+#define  PORTSCX_PIC_GREEN                    (0x00008000)
+#define  PORTSCX_PIC_UNDEF                    (0x0000C000)
+#define  PORTSCX_PIC_BIT_POS                  (14)
+
+/* bit 19-16 are port test control */
+#define  PORTSCX_PTC_DISABLE                  (0x00000000)
+#define  PORTSCX_PTC_JSTATE                   (0x00010000)
+#define  PORTSCX_PTC_KSTATE                   (0x00020000)
+#define  PORTSCX_PTC_SEQNAK                   (0x00030000)
+#define  PORTSCX_PTC_PACKET                   (0x00040000)
+#define  PORTSCX_PTC_FORCE_EN                 (0x00050000)
+#define  PORTSCX_PTC_BIT_POS                  (16)
+
+/* bit 27-26 are port speed */
+#define  PORTSCX_PORT_SPEED_FULL              (0x00000000)
+#define  PORTSCX_PORT_SPEED_LOW               (0x04000000)
+#define  PORTSCX_PORT_SPEED_HIGH              (0x08000000)
+#define  PORTSCX_PORT_SPEED_UNDEF             (0x0C000000)
+#define  PORTSCX_SPEED_BIT_POS                (26)
+
+/* OTGSC Register Bit Masks */
+#define  OTGSC_B_SESSION_VALID_IRQ_EN           (1 << 27)
+#define  OTGSC_B_SESSION_VALID_IRQ_STS          (1 << 19)
+#define  OTGSC_B_SESSION_VALID                  (1 << 11)
+
+/* bit 28 is parallel transceiver width for UTMI interface */
+#define  PORTSCX_PTW                          (0x10000000)
+#define  PORTSCX_PTW_8BIT                     (0x00000000)
+#define  PORTSCX_PTW_16BIT                    (0x10000000)
+
+/* bit 31-30 are port transceiver select */
+#define  PORTSCX_PTS_UTMI                     (0x00000000)
+#define  PORTSCX_PTS_ULPI                     (0x80000000)
+#define  PORTSCX_PTS_FSLS                     (0xC0000000)
+#define  PORTSCX_PTS_BIT_POS                  (30)
+
+/* USB MODE Register Bit Masks */
+#define  USB_MODE_CTRL_MODE_IDLE              (0x00000000)
+#define  USB_MODE_CTRL_MODE_DEVICE            (0x00000002)
+#define  USB_MODE_CTRL_MODE_HOST              (0x00000003)
+#define  USB_MODE_CTRL_MODE_MASK              0x00000003
+#define  USB_MODE_CTRL_MODE_RSV               (0x00000001)
+#define  USB_MODE_ES                          0x00000004 /* (big) Endian Sel */
+#define  USB_MODE_SETUP_LOCK_OFF              (0x00000008)
+#define  USB_MODE_STREAM_DISABLE              (0x00000010)
+/* Endpoint Flush Register */
+#define EPFLUSH_TX_OFFSET		      (0x00010000)
+#define EPFLUSH_RX_OFFSET		      (0x00000000)
+
+/* Endpoint Setup Status bit masks */
+#define  EP_SETUP_STATUS_MASK                 (0x0000003F)
+#define  EP_SETUP_STATUS_EP0		      (0x00000001)
+
+/* ENDPOINTCTRLx  Register Bit Masks */
+#define  EPCTRL_TX_ENABLE                     (0x00800000)
+#define  EPCTRL_TX_DATA_TOGGLE_RST            (0x00400000)	/* Not EP0 */
+#define  EPCTRL_TX_DATA_TOGGLE_INH            (0x00200000)	/* Not EP0 */
+#define  EPCTRL_TX_TYPE                       (0x000C0000)
+#define  EPCTRL_TX_DATA_SOURCE                (0x00020000)	/* Not EP0 */
+#define  EPCTRL_TX_EP_STALL                   (0x00010000)
+#define  EPCTRL_RX_ENABLE                     (0x00000080)
+#define  EPCTRL_RX_DATA_TOGGLE_RST            (0x00000040)	/* Not EP0 */
+#define  EPCTRL_RX_DATA_TOGGLE_INH            (0x00000020)	/* Not EP0 */
+#define  EPCTRL_RX_TYPE                       (0x0000000C)
+#define  EPCTRL_RX_DATA_SINK                  (0x00000002)	/* Not EP0 */
+#define  EPCTRL_RX_EP_STALL                   (0x00000001)
+
+/* bit 19-18 and 3-2 are endpoint type */
+#define  EPCTRL_EP_TYPE_CONTROL               (0)
+#define  EPCTRL_EP_TYPE_ISO                   (1)
+#define  EPCTRL_EP_TYPE_BULK                  (2)
+#define  EPCTRL_EP_TYPE_INTERRUPT             (3)
+#define  EPCTRL_TX_EP_TYPE_SHIFT              (18)
+#define  EPCTRL_RX_EP_TYPE_SHIFT              (2)
+
+/* SNOOPn Register Bit Masks */
+#define  SNOOP_ADDRESS_MASK                   (0xFFFFF000)
+#define  SNOOP_SIZE_ZERO                      (0x00)	/* snooping disable */
+#define  SNOOP_SIZE_4KB                       (0x0B)	/* 4KB snoop size */
+#define  SNOOP_SIZE_8KB                       (0x0C)
+#define  SNOOP_SIZE_16KB                      (0x0D)
+#define  SNOOP_SIZE_32KB                      (0x0E)
+#define  SNOOP_SIZE_64KB                      (0x0F)
+#define  SNOOP_SIZE_128KB                     (0x10)
+#define  SNOOP_SIZE_256KB                     (0x11)
+#define  SNOOP_SIZE_512KB                     (0x12)
+#define  SNOOP_SIZE_1MB                       (0x13)
+#define  SNOOP_SIZE_2MB                       (0x14)
+#define  SNOOP_SIZE_4MB                       (0x15)
+#define  SNOOP_SIZE_8MB                       (0x16)
+#define  SNOOP_SIZE_16MB                      (0x17)
+#define  SNOOP_SIZE_32MB                      (0x18)
+#define  SNOOP_SIZE_64MB                      (0x19)
+#define  SNOOP_SIZE_128MB                     (0x1A)
+#define  SNOOP_SIZE_256MB                     (0x1B)
+#define  SNOOP_SIZE_512MB                     (0x1C)
+#define  SNOOP_SIZE_1GB                       (0x1D)
+#define  SNOOP_SIZE_2GB                       (0x1E)	/* 2GB snoop size */
+
+/* pri_ctrl Register Bit Masks */
+#define  PRI_CTRL_PRI_LVL1                    (0x0000000C)
+#define  PRI_CTRL_PRI_LVL0                    (0x00000003)
+
+/* si_ctrl Register Bit Masks */
+#define  SI_CTRL_ERR_DISABLE                  (0x00000010)
+#define  SI_CTRL_IDRC_DISABLE                 (0x00000008)
+#define  SI_CTRL_RD_SAFE_EN                   (0x00000004)
+#define  SI_CTRL_RD_PREFETCH_DISABLE          (0x00000002)
+#define  SI_CTRL_RD_PREFEFETCH_VAL            (0x00000001)
+
+/* control Register Bit Masks */
+#define  USB_CTRL_IOENB                       (0x00000004)
+#define  USB_CTRL_ULPI_INT0EN                 (0x00000001)
+#define  USB_CTRL_OTG_WUIR                   (0x80000000)
+#define  USB_CTRL_OTG_WUIE                   (0x08000000)
+#define  USB_CTRL_OTG_VWUE			(0x00001000)
+#define  USB_CTRL_OTG_IWUE			(0x00100000)
+
+
+
+#define INTR_UE		      (1 << 0)
+#define INTR_UEE	      (1 << 1)
+#define INTR_PCE	      (1 << 2)
+#define INTR_SEE	      (1 << 4)
+#define INTR_URE	      (1 << 6)
+#define INTR_SRE	      (1 << 7)
+#define INTR_SLE	      (1 << 8)
+
+
+/* bits used in all the endpoint status registers */
+#define EPT_TX(n) (1 << ((n) + 16))
+#define EPT_RX(n) (1 << (n))
+
+
+#define CTRL_TXE              (1 << 23)
+#define CTRL_TXR              (1 << 22)
+#define CTRL_TXI              (1 << 21)
+#define CTRL_TXD              (1 << 17)
+#define CTRL_TXS              (1 << 16)
+#define CTRL_RXE              (1 << 7)
+#define CTRL_RXR              (1 << 6)
+#define CTRL_RXI              (1 << 5)
+#define CTRL_RXD              (1 << 1)
+#define CTRL_RXS              (1 << 0)
+
+#define CTRL_TXT_CTRL         (0 << 18)
+#define CTRL_TXT_ISOCH        (1 << 18)
+#define CTRL_TXT_BULK         (2 << 18)
+#define CTRL_TXT_INT          (3 << 18)
+
+#define CTRL_RXT_CTRL         (0 << 2)
+#define CTRL_RXT_ISOCH        (1 << 2)
+#define CTRL_RXT_BULK         (2 << 2)
+#define CTRL_RXT_INT          (3 << 2)
+
+#define USB_RECV 0
+#define USB_SEND 1
+#define USB_MAX_CTRL_PAYLOAD 64
+
+/* UDC device defines */
+#define EP0_MAX_PACKET_SIZE     USB_MAX_CTRL_PAYLOAD
+#define UDC_OUT_ENDPOINT        0x02
+#define UDC_OUT_PACKET_SIZE     USB_MAX_CTRL_PAYLOAD
+#define UDC_IN_ENDPOINT         0x03
+#define UDC_IN_PACKET_SIZE      USB_MAX_CTRL_PAYLOAD
+#define UDC_INT_ENDPOINT        0x01
+#define UDC_INT_PACKET_SIZE     USB_MAX_CTRL_PAYLOAD
+#define UDC_BULK_PACKET_SIZE    USB_MAX_CTRL_PAYLOAD
+
+/* mx6q's register bit begins*/
+
+/* OTG CTRL - H3 CTRL */
+#define UCTRL_OWIR		(1 << 31)	/* OTG wakeup intr request received */
+/* bit 18 - bit 30 is reserved at mx6q */
+#define UCTRL_WKUP_VBUS_EN	(1 << 17)	/* OTG wake-up on VBUS change enable */
+#define UCTRL_WKUP_ID_EN	(1 << 16)	/* OTG wake-up on ID change enable */
+#define UCTRL_WKUP_SW		(1 << 15)	/* OTG Software Wake-up */
+#define UCTRL_WKUP_SW_EN	(1 << 14)	/* OTG Software Wake-up enable */
+#define UCTRL_UTMI_ON_CLOCK	(1 << 13)	/* Force OTG UTMI PHY clock output on even if suspend mode */
+#define UCTRL_SUSPENDM		(1 << 12)	/* Force OTG UTMI PHY Suspend */
+#define UCTRL_RESET		(1 << 11)	/* Force OTG UTMI PHY Reset */
+#define UCTRL_OWIE		(1 << 10)	/* OTG wakeup intr request received */
+#define UCTRL_PM		(1 << 9)	/* OTG Power Mask */
+#define UCTRL_OVER_CUR_POL	(1 << 8)	/* OTG Polarity of Overcurrent */
+#define UCTRL_OVER_CUR_DIS	(1 << 7)	/* Disable OTG Overcurrent Detection */
+/* bit 0 - bit 6 is reserved at mx6q */
+
+/* Host2/3 HSIC Ctrl */
+#define CLK_VLD		(1 << 31)	/* Indicating whether HSIC clock is valid */
+#define HSIC_EN		(1 << 12)	/* HSIC enable */
+#define HSIC_CLK_ON		(1 << 11)	/* Force HSIC module 480M clock on,
+						 * even when in Host is in suspend mode
+						 */
+/* OTG/HOST1 Phy Ctrl */
+#define PHY_UTMI_CLK_VLD	(1 << 31)	/* Indicating whether OTG UTMI PHY Clock Valida */
+
+int  udc_init(void);
+
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+
+void udc_connect(void);
+void udc_disconnect(void);
+
+void udc_startup_events(struct usb_device_instance *device);
+void udc_setup_ep(struct usb_device_instance *device,
+	unsigned int ep, struct usb_endpoint_instance *endpoint);
+int udc_endpoint_write(struct usb_endpoint_instance *epi);
+void udc_irq(void);
+void usb_shutdown(void);
+void mxc_udc_rxqueue_update(u8 ep, u32 len);
+int is_usb_disconnected(void);
+void reset_usb_phy1(void);
+void set_usboh3_clk(void);
+void set_usb_phy1_clk(void);
+void enable_usb_phy1_clk(unsigned char enable);
+void enable_usboh3_clk(unsigned char enable);
+void udc_pins_setting(void);
+
+#ifdef CONFIG_FASTBOOT
+
+#define EP0_OUT_INDEX    0
+#define EP0_IN_INDEX    16
+#define EP1_OUT_INDEX    1
+#define EP1_IN_INDEX    17
+#define EP2_OUT_INDEX    2
+#define EP2_IN_INDEX    18
+#define EP3_OUT_INDEX    3
+#define EP3_IN_INDEX    19
+#define EP4_OUT_INDEX    4
+#define EP4_IN_INDEX    20
+#define EP5_OUT_INDEX    5
+#define EP5_IN_INDEX    21
+#define EP6_OUT_INDEX    6
+#define EP6_IN_INDEX    22
+#define EP7_OUT_INDEX    7
+#define EP7_IN_INDEX    23
+#define EP8_OUT_INDEX    8
+#define EP8_IN_INDEX    24
+#define EP9_OUT_INDEX    9
+#define EP9_IN_INDEX    25
+#define EP10_OUT_INDEX  10
+#define EP10_IN_INDEX   26
+#define EP11_OUT_INDEX  11
+#define EP11_IN_INDEX   27
+#define EP12_OUT_INDEX  12
+#define EP12_IN_INDEX   28
+#define EP13_OUT_INDEX  13
+#define EP13_IN_INDEX   29
+#define EP14_OUT_INDEX  14
+#define EP14_IN_INDEX   30
+#define EP15_OUT_INDEX  15
+#define EP15_IN_INDEX   31
+
+#define MAX_PAKET_LEN 512
+typedef void (*EP_HANDLER_P)(u32 index, u8 *buf);
+
+int  udc_irq_handler(void);
+void udc_hal_data_init(void);
+void udc_wait_connect(void);
+void udc_run(void);
+int  udc_recv_data(u32 index, u8 *recvbuf, u32 recvlen, EP_HANDLER_P cb);
+int  udc_send_data(u32 index, u8 *buf, u32 sendlen, EP_HANDLER_P cb);
+void udc_qh_dtd_init(u32 index);
+void udc_dtd_setup(u32 index, u8 ep_type);
+void udc_qh_setup(u32 index, u8 ep_type, u32 max_pkt_len, u32 zlt, u8 mult);
+u8  *udc_get_descriptor(u8 type, u8 *plen);
+void udc_set_addr(u8 addr);
+void udc_set_configure(u8 config);
+
+#endif  /* CONFIG_FASTBOOT */
+
+#endif