summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormattis fjallstrom <mattis@acm.org>2015-09-06 11:09:39 -0700
committermattis fjallstrom <mattis@acm.org>2015-09-06 11:09:39 -0700
commitee87ec4d2c955c929a4c27ce8a56f918444cf955 (patch)
treec18141755ad893eddd5b504e4cf096ad4e7062b9
parent2c25de1ed5c6f8f6bba3b5ec506f430d8a883a83 (diff)
downloadolio-uboot-2014.01-ee87ec4d2c955c929a4c27ce8a56f918444cf955.tar.xz
olio-uboot-2014.01-ee87ec4d2c955c929a4c27ce8a56f918444cf955.zip
First fastboot commit, MLO built here wont work so be careful.
Change-Id: Ic8d65a92da82896282eee71cf0d0515f64c939bc
-rw-r--r--arch/arm/cpu/armv7/omap3/board.c2
-rw-r--r--board/olio/h1/h1.c72
-rw-r--r--board/olio/h1/h1.c.bak105
-rw-r--r--board/olio/h1/pinmux.h33
-rw-r--r--common/Makefile2
-rw-r--r--common/cmd_fastboot.c117
-rw-r--r--common/cmd_fastboot_omap.c2544
-rw-r--r--common/cmd_nand.c2
-rw-r--r--common/cmd_nvedit.c4
-rw-r--r--drivers/mtd/nand/omap_gpmc.c2
-rw-r--r--drivers/usb/gadget/Makefile10
-rw-r--r--drivers/usb/gadget/f_fastboot.c609
-rw-r--r--drivers/usb/gadget/g_fastboot.h23
-rw-r--r--drivers/usb/gadget/u_fastboot.c416
-rw-r--r--drivers/usb/gadget/u_fastboot_mmc.c609
-rw-r--r--drivers/usb/gadget/u_fastboot_nand.c838
-rw-r--r--drivers/usb/musb-new/musb_core.c5
-rw-r--r--include/configs/omap3_h1.h100
-rw-r--r--include/olioh1_reboot.h32
-rw-r--r--include/sparse_format.h50
-rw-r--r--include/usb/fastboot.h213
21 files changed, 5770 insertions, 18 deletions
diff --git a/arch/arm/cpu/armv7/omap3/board.c b/arch/arm/cpu/armv7/omap3/board.c
index 2cd2df519..3cee4cb8d 100644
--- a/arch/arm/cpu/armv7/omap3/board.c
+++ b/arch/arm/cpu/armv7/omap3/board.c
@@ -321,7 +321,7 @@ void abort(void)
/******************************************************************************
* OMAP3 specific command to switch between NAND HW and SW ecc
*****************************************************************************/
-static int do_switch_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+int do_switch_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
if (argc < 2 || argc > 3)
goto usage;
diff --git a/board/olio/h1/h1.c b/board/olio/h1/h1.c
index e69797638..43bc998fd 100644
--- a/board/olio/h1/h1.c
+++ b/board/olio/h1/h1.c
@@ -26,9 +26,43 @@
#include <command.h>
#include <power/tps65910.h>
#include <i2c.h>
+#include <asm/arch/musb.h>
+#include <asm/arch/mmc_host_def.h>
+#include <asm/arch/am35x_def.h>
+#include <i2c.h>
+#include <linux/compiler.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/musb.h>
+#include <asm/omap_musb.h>
+
+#ifdef CONFIG_USB_EHCI
+#include <usb.h>
+#include <asm/ehci-omap.h>
+#endif
DECLARE_GLOBAL_DATA_PTR;
+#define USB_CS 17
+
+
+static struct omap_usbhs_board_data usbhs_bdata = {
+ .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
+ .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
+ .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
+};
+
+int ehci_hcd_init(int index, enum usb_init_type init,
+ struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+ return omap_ehci_hcd_init(index, &usbhs_bdata, hccr, hcor);
+}
+
+int ehci_hcd_stop(int index)
+{
+ return omap_ehci_hcd_stop();
+}
+
/*
* Routine: board_init
* Description: Early hardware init.
@@ -154,6 +188,38 @@ static int accel_regulator_init(void)
return i2c_write(TPS65910_CTRL_I2C_ADDR, TPS65910_VDIG1_REG, 1, &buf, 1);
}
+static struct musb_hdrc_config musb_config = {
+ .multipoint = 1,
+ .dyn_fifo = 1,
+ .num_eps = 16,
+ .ram_bits = 12,
+};
+
+static struct omap_musb_board_data musb_board_data = {
+ .interface_type = MUSB_INTERFACE_ULPI,
+};
+
+static struct musb_hdrc_platform_data musb_plat = {
+#if defined(CONFIG_MUSB_HOST)
+ .mode = MUSB_HOST,
+#elif defined(CONFIG_MUSB_GADGET)
+ .mode = MUSB_PERIPHERAL,
+#else
+#error "Please define either CONFIG_MUSB_HOST or CONFIG_MUSB_GADGET"
+#endif
+ .config = &musb_config,
+ .power = 100,
+ .platform_ops = &omap2430_ops,
+ .board_data = &musb_board_data,
+};
+
+
+static void olio_evm_musb_init(void)
+{
+ printf("musb mode %s \n", musb_plat.mode == MUSB_PERIPHERAL ? "MUSB_PERIPHERAL" : "MUSB_HOST");
+ musb_register(&musb_plat, &musb_board_data, (void *)MUSB_BASE);
+}
+
/*
* Routine: misc_init_r
* Description: Configure board specific parts
@@ -174,6 +240,12 @@ int misc_init_r(void)
dieid_num_r();
+ printf("debug usb_data0 %d mode %d \n", CONTROL_PADCONF_HSUSB0_DATA0 , (IEN | PD | M0));
+ gpio_request(USB_CS, "usb_cs");
+ gpio_direction_output(USB_CS, 1);
+
+ olio_evm_musb_init();
+
return 0;
}
diff --git a/board/olio/h1/h1.c.bak b/board/olio/h1/h1.c.bak
new file mode 100644
index 000000000..325e4ded1
--- /dev/null
+++ b/board/olio/h1/h1.c.bak
@@ -0,0 +1,105 @@
+/*
+ * (C) Copyright 2004-2011
+ * Texas Instruments, <www.ti.com>
+ *
+ * Author :
+ * Sunil Kumar <sunilsaini05@gmail.com>
+ * Shashi Ranjan <shashiranjanmca05@gmail.com>
+ *
+ * Derived from Beagle Board and 3430 SDP code by
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Syed Mohammed Khasim <khasim@ti.com>
+ *
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <linux/mtd/nand.h>
+#include <asm/io.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/mem.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/errno.h>
+#include "h1.h"
+#include <command.h>
+#include <power/tps65910.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Routine: board_init
+ * Description: Early hardware init.
+ */
+int board_init(void)
+{
+ gpmc_init(); /* in SRAM or SDRAM, finish GPMC */
+ /* board id for Linux */
+ gd->bd->bi_arch_number = MACH_TYPE_OMAP3_H1;
+ /* boot param addr */
+ gd->bd->bi_boot_params = (OMAP34XX_SDRC_CS0 + 0x100);
+
+ return 0;
+}
+
+#ifdef CONFIG_SPL_BUILD
+/*
+ * Routine: get_board_mem_timings
+ * Description: If we use SPL then there is no x-loader nor config header
+ * so we have to setup the DDR timings ourself on both banks.
+ */
+void get_board_mem_timings(struct board_sdrc_timings *timings)
+{
+ int pop_mfr, pop_id;
+
+ /*
+ * We need to identify what PoP memory is on the board so that
+ * we know what timings to use. If we can't identify it then
+ * we know it's an xM. To map the ID values please see nand_ids.c
+ */
+ identify_nand_chip(&pop_mfr, &pop_id);
+
+ timings->mr = 0x00000032;
+ timings->mcfg = MICRON_V_MCFG_200(512 << 20); /* OLIO, mfj: not sure what this should be */
+ timings->ctrla = 0x7AE1B4C6;
+ timings->ctrlb = 0x00021217;
+ timings->rfr_ctrl = 0x00062701;
+
+ /* 128MB DDR - safe settings from Beagle
+ timings->mr = MICRON_V_MR_165;
+ timings->mcfg = MICRON_V_MCFG_200(256 << 20);
+ timings->ctrla = MICRON_V_ACTIMA_200;
+ timings->ctrlb = MICRON_V_ACTIMB_200;
+ timings->rfr_ctrl = SDP_3430_SDRC_RFR_CTRL_200MHz;
+ */
+}
+#endif
+
+/*
+ * Routine: misc_init_r
+ * Description: Configure board specific parts
+ */
+int misc_init_r(void)
+{
+ struct gpio *gpio5_base = (struct gpio *)OMAP34XX_GPIO5_BASE;
+ struct gpio *gpio6_base = (struct gpio *)OMAP34XX_GPIO6_BASE;
+ struct control_prog_io *prog_io_base = (struct control_prog_io *)OMAP34XX_CTRL_BASE;
+
+ //MUX_BEAGLE_XM();
+
+ dieid_num_r();
+
+ return 0;
+}
+
+/*
+ * Routine: set_muxconf_regs
+ * Description: Setting up the configuration Mux registers specific to the
+ * hardware. Many pins need to be moved from protect to primary
+ * mode.
+ */
+void set_muxconf_regs(void)
+{
+ MUX_EVM();
+}
diff --git a/board/olio/h1/pinmux.h b/board/olio/h1/pinmux.h
index 23cfede2e..3861c3bad 100644
--- a/board/olio/h1/pinmux.h
+++ b/board/olio/h1/pinmux.h
@@ -146,15 +146,15 @@ MUX_VAL(CONTROL_PADCONF_GPMC_WAIT1, (IEN | PU | M7 | SB_PU)) /* safe_mode - edit
MUX_VAL(CONTROL_PADCONF_GPMC_WAIT2, (IEN | PU | M7 | SB_PU)) /* safe_mode - edit 2014-05-11 */ \
MUX_VAL(CONTROL_PADCONF_GPMC_WAIT3, (IEN | PU | M7 | SB_PU)) /* safe_mode - edit 2014-05-11 */ \
MUX_VAL(CONTROL_PADCONF_HDQ_SIO, (IEN | PD | M7 | SB_PD)) /* safe_mode - edit 2014-05-11 */ \
-MUX_VAL(CONTROL_PADCONF_HSUSB0_CLK, (IEN | PD | M7 )) /* safe_mode */\
-MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA0, (IEN | PD | M4 )) /* gpio_125 */\
-MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA1, (IEN | PD | M4 )) /* gpio_130 */\
-MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA2, (IEN | PD | M4 )) /* gpio_131 */\
-MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA3, (IEN | PD | M4 )) /* gpio_169 */\
-MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA4, (IEN | PD | M4 )) /* gpio_188 */\
-MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA5, (IEN | PD | M4 )) /* gpio_189 */\
-MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA6, (IEN | PD | M4 )) /* gpio_190 */\
-MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA7, (IEN | PD | M4 )) /* gpio_191 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_CLK, (IEN | PD | M7 )) /* safe_mode */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA0, (IEN | PD | M4 )) /* gpio_125 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA1, (IEN | PD | M4 )) /* gpio_130 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA2, (IEN | PD | M4 )) /* gpio_131 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA3, (IEN | PD | M4 )) /* gpio_169 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA4, (IEN | PD | M4 )) /* gpio_188 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA5, (IEN | PD | M4 )) /* gpio_189 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA6, (IEN | PD | M4 )) /* gpio_190 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA7, (IEN | PD | M4 )) /* gpio_191 */\
MUX_VAL(CONTROL_PADCONF_HSUSB0_DIR, (IEN | PD | M7 )) /* safe_mode */\
MUX_VAL(CONTROL_PADCONF_HSUSB0_NXT, (IEN | PD | M7 )) /* safe_mode */\
MUX_VAL(CONTROL_PADCONF_HSUSB0_STP, (IEN | PU | M7 )) /* safe_mode */\
@@ -312,5 +312,18 @@ MUX_VAL(CONTROL_PADCONF_UART2_TX, (IEN | PU | M4 )) /* gpio_146 */\
MUX_VAL(CONTROL_PADCONF_UART3_CTS_RCTX, (IEN | PU | M0 )) /* uart3_cts_rctx */\
MUX_VAL(CONTROL_PADCONF_UART3_RTS_SD, (IDIS | PU | M0 )) /* uart3_rts_sd */\
MUX_VAL(CONTROL_PADCONF_UART3_RX_IRRX, (IEN | PU | M0 )) /* uart3_rx_irrx */\
-MUX_VAL(CONTROL_PADCONF_UART3_TX_IRTX, (IDIS | PU | M0 )) /* uart3_tx_irtx */
+MUX_VAL(CONTROL_PADCONF_UART3_TX_IRTX, (IDIS | PU | M0 )) /* uart3_tx_irtx */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_CLK, (IEN | PI | M0 )) /* hsusb0_clk */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA0, (IEN | PI | M0)) /* hsusb0_data0 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA1, (IEN | PI | M0)) /* hsusb0_data1 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA2, (IEN | PI | M0)) /* hsusb0_data2 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA3, (IEN | PI | M0)) /* hsusb0_data3 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA4, (IEN | PI | M0)) /* hsusb0_data4 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA5, (IEN | PI | M0)) /* hsusb0_data5 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA6, (IEN | PI | M0)) /* hsusb0_data6 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DATA7, (IEN | PI | M0)) /* hsusb0_data7 */\
+MUX_VAL(CONTROL_PADCONF_HSUSB0_DIR, (IEN | PI | M0)) /*hsusb0_dir */ \
+MUX_VAL(CONTROL_PADCONF_HSUSB0_STP, (IDIS | PI | M0)) /*hsusb0_stp */ \
+MUX_VAL(CONTROL_PADCONF_HSUSB0_NXT, (IEN | PI | M0)) /*hsusb0_nxt */ \
+MUX_VAL(CONTROL_PADCONF_ETK_D3_ES2, (IDIS | PI | M4)) /* gpio_17 */
#endif
diff --git a/common/Makefile b/common/Makefile
index d12cba5bf..de4253401 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -163,6 +163,8 @@ obj-y += cmd_usb.o
obj-y += usb.o usb_hub.o
obj-$(CONFIG_USB_STORAGE) += usb_storage.o
endif
+obj-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
+
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
obj-$(CONFIG_CMD_THOR_DOWNLOAD) += cmd_thordown.o
obj-$(CONFIG_CMD_XIMG) += cmd_ximg.o
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
new file mode 100644
index 000000000..4ccf9af86
--- /dev/null
+++ b/common/cmd_fastboot.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy at linutronix.de>
+ *
+ * Modified by Vishveshwar Bhat <vishveshwar.bhat@ti.com>
+ * Pankaj Bharadiya <pankaj.bharadiya@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <usb/fastboot.h>
+#include <asm/sizes.h>
+
+static char serial_number[28] = "001234";
+
+static struct usb_string def_usb_fb_strings[] = {
+ /* This has to match the product name used in the AOSP build.
+ Should not be hard coded here... */
+ /* { FB_STR_PRODUCT_IDX, "AM335xevm" }, */
+ { FB_STR_PRODUCT_IDX, "beagleboneblack" },
+ { FB_STR_SERIAL_IDX, serial_number },
+ { FB_STR_PROC_REV_IDX, "ES2.x" },
+ { FB_STR_PROC_TYPE_IDX, "ARMv7" },
+ { FB_STR_MANUFACTURER_IDX, "Texas Instruments" },
+ { }
+};
+
+static struct usb_gadget_strings def_fb_strings = {
+ .language = 0x0409, /* en-us */
+ .strings = def_usb_fb_strings,
+};
+
+/*
+ * Hardcoded memory region to stash data which comes over USB before it is
+ * stored on media
+ */
+DECLARE_GLOBAL_DATA_PTR;
+#define CFG_FASTBOOT_TRANSFER_BUFFER (void *)(gd->bd->bi_dram[0].start + SZ_16M)
+
+static void set_serial_number(void)
+{
+ /* use ethaddr for fastboot serial no. */
+ char *ethaddr = "123456789012345678901234567890";/*getenv("ethaddr");*/
+
+ if (ethaddr != NULL) {
+ int len;
+
+ memset(&serial_number[0], 0, 28);
+ len = strlen(ethaddr);
+ if (len > 28)
+ len = 26;
+
+ strncpy(&serial_number[0], ethaddr, len);
+ }
+}
+
+int fastboot_board_init(struct fastboot_config *interface,
+ struct usb_gadget_strings **str)
+{
+ /* Initialize board serial no. */
+ set_serial_number();
+
+ interface->transfer_buffer = CFG_FASTBOOT_TRANSFER_BUFFER;
+ interface->transfer_buffer_size = CONFIG_FASTBOOT_MAX_TRANSFER_SIZE;
+ interface->nand_block_size = FASTBOOT_NAND_BLOCK_SIZE;
+ interface->nand_oob_size = FASTBOOT_NAND_OOB_SIZE;
+ interface->download_bytes = 0;
+ interface->download_size = 0;
+
+ *str = &def_fb_strings;
+ return 0;
+}
+
+static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ int ret = 1;
+
+ printf("Fastboot dbg...\n");
+ if (!fastboot_init()) {
+ //board_mmc_fbtptn_init();
+ printf("Fastboot entered...\n");
+
+ ret = 0;
+
+ while (1) {
+ if (fastboot_poll())
+ {
+ printf("Fastboot poll break...\n");
+ break;
+ }
+ }
+ }
+
+ fastboot_shutdown();
+ return ret;
+}
+
+U_BOOT_CMD(
+ fastboot, 1, 1, do_fastboot,
+ "fastboot- use USB Fastboot protocol\n",
+ ""
+);
diff --git a/common/cmd_fastboot_omap.c b/common/cmd_fastboot_omap.c
new file mode 100644
index 000000000..c0b5c283e
--- /dev/null
+++ b/common/cmd_fastboot_omap.c
@@ -0,0 +1,2544 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * Author : Mohammed Afzal M A <afzal@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Fastboot is implemented using gadget stack, many of the ideas are
+ * derived from fastboot implemented in OmapZoom by
+ * Tom Rix <Tom.Rix@windriver.com>, and portion of the code has been
+ * ported from OmapZoom.
+ *
+ * Part of OmapZoom was copied from Android project, Android source
+ * (legacy bootloader) was used indirectly here by using OmapZoom.
+ *
+ * This is Android's 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 <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <usb/fastboot.h>
+#include <omap_fastboot.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* If a BUILD_TAG was passed as an argument to make, use it
+ * for the fastboot version. Otherwise, see if a board file
+ * defined a CONFIG_FASTBOOT_VERSION_BOOTLOADER and if so, use
+ * that. Otherwise, use an automatically constructed one of the form:
+ * productnameYMDHB
+ * where:
+ * productname is FASTBOOT_PRODUCT_NAME
+ * Y is the year with 'A' being 2011 and incrementing from there
+ * M is the month
+ * D is the day of the month
+ * H is the hour
+ * B is the minute divided by two
+ * All of the fields are based upon the build time. M, D, H and B are all
+ * output in base 36 (i.e. each digit is in the set 0-9A-Z). A quick and
+ * dirty Python program to convert one of these versions back to the build
+ * time:
+
+#! /usr/bin/env python
+import sys
+foo = sys.argv[1][-5:]
+print "%04d/%02d/%02d %02d:%02d\n" % (int(foo[0], 36) + 2001,
+ int(foo[1], 36),
+ int(foo[2], 36),
+ int(foo[3], 36),
+ int(foo[4], 36) * 2)
+ */
+#ifdef BUILD_TAG
+#undef CONFIG_FASTBOOT_VERSION_BOOTLOADER
+#define CONFIG_FASTBOOT_VERSION_BOOTLOADER BUILD_TAG
+#else
+#ifndef CONFIG_FASTBOOT_VERSION_BOOTLOADER
+#include <timestamp_autogenerated.h>
+#define CONFIG_FASTBOOT_VERSION_BOOTLOADER \
+ (FASTBOOT_PRODUCT_NAME FASTBOOT_TIMESTAMP)
+#endif
+#endif
+
+#define FASTBOOT_RUN_RECOVERY_ENV_NAME "fastboot_run_recovery"
+#define FASTBOOT_UNLOCKED_ENV_NAME "fastboot_unlocked"
+#define FASTBOOT_UNLOCK_TIMEOUT_SECS 5
+
+#ifndef CONFIG_ENV_BLK_PARTITION
+#define CONFIG_ENV_BLK_PARTITION "environment"
+#endif
+#ifndef CONFIG_INFO_PARTITION
+#define CONFIG_INFO_PARTITION "device_info"
+#endif
+
+#define ERR
+#define WARN
+#undef INFO
+#undef DEBUG
+
+#ifndef CONFIG_FASTBOOT_LOG_SIZE
+#define CONFIG_FASTBOOT_LOG_SIZE 4000
+#endif
+static char log_buffer[CONFIG_FASTBOOT_LOG_SIZE];
+static uint32_t log_position;
+
+
+#ifdef DEBUG
+#define FBTDBG(fmt, args...)\
+ printf("DEBUG: [%s]: %d:\n"fmt, __func__, __LINE__, ##args)
+#else
+#define FBTDBG(fmt, args...) do {} while (0)
+#endif
+
+#ifdef INFO
+#define FBTINFO(fmt, args...)\
+ printf("INFO: [%s]: "fmt, __func__, ##args)
+#else
+#define FBTINFO(fmt, args...) do {} while (0)
+#endif
+
+#ifdef WARN
+#define FBTWARN(fmt, args...)\
+ printf("WARNING: [%s]: "fmt, __func__, ##args)
+#else
+#define FBTWARN(fmt, args...) do {} while (0)
+#endif
+
+#ifdef ERR
+#define FBTERR(fmt, args...)\
+ printf("ERROR: [%s]: "fmt, __func__, ##args)
+#else
+#define FBTERR(fmt, args...) do {} while (0)
+#endif
+
+#include <exports.h>
+#include <environment.h>
+
+/* USB specific */
+
+#include <usb_defs.h>
+
+#if defined(CONFIG_PPC)
+#include <usb/mpc8xx_udc.h>
+#elif defined(CONFIG_OMAP1510)
+#include <usb/omap1510_udc.h>
+#elif defined(CONFIG_MUSB_UDC)
+#include <usb/musb_udc.h>
+#elif defined(CONFIG_PXA27X)
+#include <usb/pxa27x_udc.h>
+#elif defined(CONFIG_SPEAR3XX) || defined(CONFIG_SPEAR600)
+#include <usb/spr_udc.h>
+#endif
+
+#if defined (CONFIG_OMAP)
+#include <asm/arch/sys_proto.h>
+#endif
+
+#define STR_LANG 0x00
+#define STR_MANUFACTURER 0x01
+#define STR_PRODUCT 0x02
+#define STR_SERIAL 0x03
+#define STR_CONFIGURATION 0x04
+#define STR_INTERFACE 0x05
+#define STR_COUNT 0x06
+
+#define CONFIG_USBD_CONFIGURATION_STR "Android Fastboot Configuration"
+#define CONFIG_USBD_INTERFACE_STR "Android Fastboot Interface"
+
+#define USBFBT_BCD_DEVICE 0x00
+#define USBFBT_MAXPOWER 0x32
+
+#define USB_FLUSH_DELAY_MICROSECS 1000
+
+#define NUM_CONFIGS 1
+#define NUM_INTERFACES 1
+#define NUM_ENDPOINTS 2
+
+#define RX_EP_INDEX 1
+#define TX_EP_INDEX 2
+
+struct _fbt_config_desc {
+ struct usb_configuration_descriptor configuration_desc;
+ struct usb_interface_descriptor interface_desc;
+ struct usb_endpoint_descriptor endpoint_desc[NUM_ENDPOINTS];
+};
+
+static void fbt_handle_response(void);
+static disk_partition_t *fastboot_flash_find_ptn(const char *name);
+static void fbt_run_recovery_wipe_data(void);
+static void fbt_run_recovery(int do_saveenv);
+
+/* defined and used by gadget/ep0.c */
+extern struct usb_string_descriptor **usb_strings;
+
+/* USB Descriptor Strings */
+static char serial_number[33]; /* what should be the length ?, 33 ? */
+static u8 wstr_lang[4] = {4, USB_DT_STRING, 0x9, 0x4};
+static u8 wstr_manufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)];
+static u8 wstr_product[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)];
+static u8 wstr_serial[2 + 2*(sizeof(serial_number) - 1)];
+static u8 wstr_configuration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)];
+static u8 wstr_interface[2 + 2*(sizeof(CONFIG_USBD_INTERFACE_STR)-1)];
+
+/* USB descriptors */
+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 = 0x00,
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+ .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE,
+ .idVendor = cpu_to_le16(CONFIG_USBD_VENDORID),
+ .idProduct = cpu_to_le16(CONFIG_USBD_PRODUCTID),
+ .bcdDevice = cpu_to_le16(USBFBT_BCD_DEVICE),
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT,
+ .iSerialNumber = STR_SERIAL,
+ .bNumConfigurations = NUM_CONFIGS
+};
+
+static struct _fbt_config_desc fbt_config_desc = {
+ .configuration_desc = {
+ .bLength = sizeof(struct usb_configuration_descriptor),
+ .bDescriptorType = USB_DT_CONFIG,
+ .wTotalLength = cpu_to_le16(sizeof(struct _fbt_config_desc)),
+ .bNumInterfaces = NUM_INTERFACES,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIGURATION,
+ .bmAttributes = BMATTRIBUTE_SELF_POWERED | BMATTRIBUTE_RESERVED,
+ .bMaxPower = USBFBT_MAXPOWER,
+ },
+ .interface_desc = {
+ .bLength = sizeof(struct usb_interface_descriptor),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0x2,
+ .bInterfaceClass = FASTBOOT_INTERFACE_CLASS,
+ .bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS,
+ .bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL,
+ .iInterface = STR_INTERFACE,
+ },
+ .endpoint_desc = {
+ {
+ .bLength = sizeof(struct usb_endpoint_descriptor),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ /* XXX: can't the address start from 0x1, currently
+ seeing problem with "epinfo" */
+ .bEndpointAddress = RX_EP_INDEX | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .bInterval = 0xFF,
+ },
+ {
+ .bLength = sizeof(struct usb_endpoint_descriptor),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ /* XXX: can't the address start from 0x1, currently
+ seeing problem with "epinfo" */
+ .bEndpointAddress = TX_EP_INDEX | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .bInterval = 0xFF,
+ },
+ },
+};
+
+static struct usb_interface_descriptor interface_descriptors[NUM_INTERFACES];
+static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS];
+
+static struct usb_string_descriptor *fbt_string_table[STR_COUNT];
+static struct usb_device_instance device_instance[1];
+static struct usb_bus_instance bus_instance[1];
+static struct usb_configuration_instance config_instance[NUM_CONFIGS];
+static struct usb_interface_instance interface_instance[NUM_INTERFACES];
+static struct usb_alternate_instance alternate_instance[NUM_INTERFACES];
+static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS + 1];
+
+/* FASBOOT specific */
+
+/* U-boot version */
+extern char version_string[];
+
+static const char info_partition_magic[] = {'I', 'n', 'f', 'o'};
+
+static struct cmd_fastboot_interface priv = {
+ .transfer_buffer = (u8 *)CONFIG_FASTBOOT_TRANSFER_BUFFER,
+ .transfer_buffer_size = CONFIG_FASTBOOT_TRANSFER_BUFFER_SIZE,
+};
+
+static void fbt_init_endpoints(void);
+static int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
+
+extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
+/* Use do_bootm_linux and do_go for fastboot's 'boot' command */
+extern int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
+extern int do_bootm_linux(int flag, int argc, char *argv[],
+ bootm_headers_t *images);
+extern int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,
+ char *const argv[]);
+
+/* To support the Android-style naming of flash */
+#define MAX_PTN (CONFIG_MAX_PARTITION_NUM - CONFIG_MIN_PARTITION_NUM + 1)
+static disk_partition_t ptable[MAX_PTN];
+static unsigned int pcount;
+
+/* USB specific */
+
+/* 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
+ }
+}
+
+/* fastboot_init has to be called before this fn to get correct serial string */
+static void fbt_init_strings(void)
+{
+ struct usb_string_descriptor *string;
+
+ fbt_string_table[STR_LANG] = (struct usb_string_descriptor *)wstr_lang;
+
+ string = (struct usb_string_descriptor *) wstr_manufacturer;
+ string->bLength = sizeof(wstr_manufacturer);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide(CONFIG_USBD_MANUFACTURER, string->wData);
+ fbt_string_table[STR_MANUFACTURER] = string;
+
+ string = (struct usb_string_descriptor *) wstr_product;
+ string->bLength = sizeof(wstr_product);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide(CONFIG_USBD_PRODUCT_NAME, string->wData);
+ fbt_string_table[STR_PRODUCT] = string;
+
+ string = (struct usb_string_descriptor *) wstr_serial;
+ string->bLength = sizeof(wstr_serial);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide(serial_number, string->wData);
+ fbt_string_table[STR_SERIAL] = string;
+
+ string = (struct usb_string_descriptor *) wstr_configuration;
+ string->bLength = sizeof(wstr_configuration);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide(CONFIG_USBD_CONFIGURATION_STR, string->wData);
+ fbt_string_table[STR_CONFIGURATION] = string;
+
+ string = (struct usb_string_descriptor *) wstr_interface;
+ string->bLength = sizeof(wstr_interface);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide(CONFIG_USBD_INTERFACE_STR, string->wData);
+ fbt_string_table[STR_INTERFACE] = string;
+
+ /* Now, initialize the string table for ep0 handling */
+ usb_strings = fbt_string_table;
+}
+
+static void fbt_event_handler (struct usb_device_instance *device,
+ usb_device_event_t event, int data)
+{
+ switch (event) {
+ case DEVICE_RESET:
+ case DEVICE_BUS_INACTIVE:
+ priv.configured = 0;
+ break;
+ case DEVICE_CONFIGURED:
+ priv.configured = 1;
+ break;
+
+ case DEVICE_ADDRESS_ASSIGNED:
+ fbt_init_endpoints();
+
+ default:
+ break;
+ }
+}
+
+/* fastboot_init has to be called before this fn to get correct serial string */
+static void fbt_init_instances(void)
+{
+ int i;
+
+ /* 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 = fbt_event_handler;
+ device_instance->cdc_recv_setup = NULL;
+ device_instance->bus = bus_instance;
+ device_instance->configurations = NUM_CONFIGS;
+ device_instance->configuration_instance_array = config_instance;
+
+ /* XXX: what is this bus instance for ?, can't it be removed by moving
+ endpoint_array and serial_number_str is moved to device instance */
+ /* initialize bus instance */
+ memset(bus_instance, 0, sizeof(struct usb_bus_instance));
+ bus_instance->device = device_instance;
+ bus_instance->endpoint_array = endpoint_instance;
+ /* XXX: what is the relevance of max_endpoints & maxpacketsize ? */
+ bus_instance->max_endpoints = 1;
+ bus_instance->maxpacketsize = 64;
+ bus_instance->serial_number_str = serial_number;
+
+ /* configuration instance */
+ memset(config_instance, 0, sizeof(struct usb_configuration_instance));
+ config_instance->interfaces = NUM_INTERFACES;
+ config_instance->configuration_descriptor =
+ (struct usb_configuration_descriptor *)&fbt_config_desc;
+ config_instance->interface_instance_array = interface_instance;
+
+ /* XXX: is alternate instance required in case of no alternate ? */
+ /* 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, sizeof(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;
+ /* XXX: following statement to done along with other endpoints
+ at another place ? */
+ udc_setup_ep(device_instance, 0, &endpoint_instance[0]);
+
+ for (i = 1; i <= NUM_ENDPOINTS; i++) {
+ 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)
+ endpoint_instance[i].tx_urb =
+ usbd_alloc_urb(device_instance,
+ &endpoint_instance[i]);
+ else
+ endpoint_instance[i].rcv_urb =
+ usbd_alloc_urb(device_instance,
+ &endpoint_instance[i]);
+ }
+}
+
+/* XXX: ep_descriptor_ptrs can be removed by making better use of
+ fbt_config_desc.endpoint_desc */
+static void fbt_init_endpoint_ptrs(void)
+{
+ ep_descriptor_ptrs[0] = &fbt_config_desc.endpoint_desc[0];
+ ep_descriptor_ptrs[1] = &fbt_config_desc.endpoint_desc[1];
+}
+
+static void fbt_init_endpoints(void)
+{
+ int i;
+
+ /* XXX: should it be moved to some other function ? */
+ bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
+
+ /* XXX: is this for loop required ?, yes for MUSB it is */
+ for (i = 1; i <= NUM_ENDPOINTS; i++) {
+
+ /* configure packetsize based on HS negotiation status */
+ if (device_instance->speed == USB_SPEED_FULL) {
+ FBTINFO("setting up FS USB device ep%x\n",
+ endpoint_instance[i].endpoint_address);
+ ep_descriptor_ptrs[i - 1]->wMaxPacketSize =
+ CONFIG_USBD_FASTBOOT_BULK_PKTSIZE_FS;
+ } else if (device_instance->speed == USB_SPEED_HIGH) {
+ FBTINFO("setting up HS USB device ep%x\n",
+ endpoint_instance[i].endpoint_address);
+ ep_descriptor_ptrs[i - 1]->wMaxPacketSize =
+ CONFIG_USBD_FASTBOOT_BULK_PKTSIZE_HS;
+ }
+
+ endpoint_instance[i].tx_packetSize =
+ le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
+ endpoint_instance[i].rcv_packetSize =
+ le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
+
+ udc_setup_ep(device_instance, i, &endpoint_instance[i]);
+ }
+}
+
+static struct urb *next_urb(struct usb_device_instance *device,
+ struct usb_endpoint_instance *endpoint)
+{
+ struct urb *current_urb;
+ 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;
+}
+
+static void fbt_wait_usb_fifo_flush(void)
+{
+ /* give time to flush FIFO and remote to receive data.
+ * otherwise, USB can get hung. someday we might actually
+ * try checking USB fifo status directly but for now, just
+ * spin for some time.
+ */
+ udelay(USB_FLUSH_DELAY_MICROSECS);
+}
+
+/* FASTBOOT specific */
+
+/*
+ * Android style flash utilties
+ */
+static void set_serial_number(const char *serial_no)
+{
+ strncpy(serial_number, serial_no, sizeof(serial_number));
+ serial_number[sizeof(serial_number) - 1] = '\0';
+ priv.serial_no = serial_number;
+ printf("fastboot serial_number = %s\n", serial_number);
+}
+
+static void create_serial_number(void)
+{
+ char *dieid = getenv("fbt_id#");
+
+ if (dieid == NULL)
+ dieid = getenv("dieid#");
+
+ if (dieid == NULL) {
+ printf("Setting serial number from constant (no dieid info)\n");
+ set_serial_number("00123");
+ } else {
+ printf("Setting serial number from unique id\n");
+ set_serial_number(dieid);
+ }
+}
+
+static int is_env_partition(disk_partition_t *ptn)
+{
+ return !strcmp((char *)ptn->name, CONFIG_ENV_BLK_PARTITION);
+}
+static int is_info_partition(disk_partition_t *ptn)
+{
+ return !strcmp((char *)ptn->name, CONFIG_INFO_PARTITION);
+}
+
+void fbt_add_ptn(disk_partition_t *ptn)
+{
+ if (pcount < MAX_PTN) {
+ memcpy(ptable + pcount, ptn, sizeof(*ptn));
+ pcount++;
+ }
+}
+
+static int fbt_load_partition_table(void)
+{
+ disk_partition_t *info_ptn;
+ unsigned int i;
+
+ if (board_fbt_load_ptbl()) {
+ printf("board_fbt_load_ptbl() failed\n");
+ return -1;
+ }
+
+ /* load device info partition if it exists */
+ info_ptn = fastboot_flash_find_ptn(CONFIG_INFO_PARTITION);
+ if (info_ptn) {
+ struct info_partition_header *info_header;
+ char *name, *next_name;
+ char *value;
+
+ lbaint_t num_blks = 1;
+ i = partition_read_blks(priv.dev_desc, info_ptn,
+ &num_blks, priv.transfer_buffer);
+ if (i) {
+ printf("failed to read info partition. error=%d\n", i);
+ goto no_existing_info;
+ }
+
+ /* parse the info partition read from the device */
+ info_header =
+ (struct info_partition_header *)priv.transfer_buffer;
+ name = (char *)(info_header + 1);
+ value = name;
+
+ if (memcmp(&info_header->magic, info_partition_magic,
+ sizeof(info_partition_magic)) != 0) {
+ printf("info partition magic 0x%x invalid,"
+ " assuming none\n", info_header->magic);
+ goto no_existing_info;
+ }
+ if (info_header->num_values > FASTBOOT_MAX_NUM_DEVICE_INFO) {
+ printf("info partition num values %d too large "
+ " (max %d)\n", info_header->num_values,
+ FASTBOOT_MAX_NUM_DEVICE_INFO);
+ goto no_existing_info;
+ }
+ priv.num_device_info = info_header->num_values;
+ /* the name/value pairs are in the format:
+ * name1=value1\n
+ * name2=value2\n
+ * this makes it easier to read if we dump the partition
+ * to a file
+ */
+ printf("%d device info entries read from %s partition:\n",
+ priv.num_device_info, info_ptn->name);
+ for (i = 0; i < priv.num_device_info; i++) {
+ while (*value != '=')
+ value++;
+ *value++ = '\0';
+ next_name = value;
+ while (*next_name != '\n')
+ next_name++;
+ *next_name++ = '\0';
+ priv.dev_info[i].name = strdup(name);
+ priv.dev_info[i].value = strdup(value);
+ printf("\t%s=%s\n", priv.dev_info[i].name,
+ priv.dev_info[i].value);
+ /* initialize serial number from device info */
+ if (!strcmp(name, FASTBOOT_SERIALNO_BOOTARG))
+ set_serial_number(value);
+ name = next_name;
+ }
+ priv.dev_info_uninitialized = 0;
+ } else {
+no_existing_info:
+ priv.dev_info_uninitialized = 1;
+ printf("No existing device info found.\n");
+ }
+
+ if (priv.serial_no == NULL)
+ create_serial_number();
+
+ return 0;
+}
+
+static disk_partition_t *fastboot_flash_find_ptn(const char *name)
+{
+ unsigned int n;
+
+ if (pcount == 0) {
+ if (fbt_load_partition_table()) {
+ printf("Unable to load partition table, aborting\n");
+ return NULL;
+ }
+ }
+
+ for (n = 0; n < pcount; n++)
+ if (!strcmp((char *)ptable[n].name, name))
+ return ptable + n;
+ return NULL;
+}
+
+void fbt_reset_ptn(void)
+{
+ pcount = 0;
+ if (fbt_load_partition_table())
+ FBTERR("Unable to load partition table\n");
+}
+
+static void fbt_set_unlocked(int unlocked)
+{
+ char *unlocked_string;
+
+ printf("Setting device to %s\n",
+ unlocked ? "unlocked" : "locked");
+ priv.unlocked = unlocked;
+ if (unlocked)
+ unlocked_string = "1";
+ else
+ unlocked_string = "0";
+ setenv(FASTBOOT_UNLOCKED_ENV_NAME, unlocked_string);
+#if defined(CONFIG_CMD_SAVEENV)
+ saveenv();
+#endif
+}
+
+static void fbt_fastboot_init(void)
+{
+ char *fastboot_unlocked_env;
+ priv.flag = 0;
+ priv.d_size = 0;
+ priv.d_bytes = 0;
+ priv.u_size = 0;
+ priv.u_bytes = 0;
+ priv.exit = 0;
+ priv.unlock_pending_start_time = 0;
+
+ priv.unlocked = 1;
+ fastboot_unlocked_env = getenv(FASTBOOT_UNLOCKED_ENV_NAME);
+ if (fastboot_unlocked_env) {
+ unsigned long unlocked;
+ if (!strict_strtoul(fastboot_unlocked_env, 10, &unlocked)) {
+ if (unlocked)
+ priv.unlocked = 1;
+ else
+ priv.unlocked = 0;
+ } else {
+ printf("bad env setting %s of %s,"
+ " initializing to locked\n",
+ fastboot_unlocked_env,
+ FASTBOOT_UNLOCKED_ENV_NAME);
+ fbt_set_unlocked(0);
+ }
+ } else {
+ printf("no existing env setting for %s\n",
+ FASTBOOT_UNLOCKED_ENV_NAME);
+ printf("creating one set to false\n");
+ fbt_set_unlocked(0);
+ }
+ if (priv.unlocked)
+ printf("Device is unlocked\n");
+ else
+ printf("Device is locked\n");
+
+ priv.dev_desc = get_dev_by_name(FASTBOOT_BLKDEV);
+ if (!priv.dev_desc) {
+ FBTERR("%s: fastboot device %s not found\n",
+ __func__, FASTBOOT_BLKDEV);
+ return;
+ }
+
+ /*
+ * We need to be able to run fastboot even if there isn't a partition
+ * table (so we can use "oem format") and fbt_load_partition_table
+ * already printed an error, so just ignore the error return.
+ */
+ (void)fbt_load_partition_table();
+}
+
+static void fbt_handle_erase(char *cmdbuf)
+{
+ disk_partition_t *ptn;
+ int err;
+ char *partition_name = cmdbuf + 6;
+ char *num_blocks_str;
+ lbaint_t num_blocks;
+ lbaint_t *num_blocks_p = NULL;
+
+ /* see if there is an optional num_blocks after the partition name */
+ num_blocks_str = strchr(partition_name, ' ');
+ if (num_blocks_str) {
+ /* null terminate the partition name */
+ *num_blocks_str = 0;
+ num_blocks_str++;
+ num_blocks = simple_strtoull(num_blocks_str, NULL, 10);
+ num_blocks_p = &num_blocks;
+ }
+
+ ptn = fastboot_flash_find_ptn(partition_name);
+ if (ptn == 0) {
+ printf("Partition %s does not exist\n", partition_name);
+ sprintf(priv.response, "FAILpartition does not exist");
+ return;
+ }
+
+#ifndef CONFIG_MFG
+ /* don't allow erasing environment partition or a valid
+ * device info partition in a production u-boot */
+ if (is_env_partition(ptn) ||
+ (is_info_partition(ptn) && (!priv.dev_info_uninitialized))) {
+ printf("Not allowed to erase %s partition\n", ptn->name);
+ strcpy(priv.response, "FAILnot allowed to erase partition");
+ return;
+ }
+#endif
+
+ printf("Erasing partition '%s':\n", ptn->name);
+
+ printf("\tstart blk %lu, blk_cnt %lu of %lu\n", ptn->start,
+ num_blocks_p ? num_blocks : ptn->size, ptn->size);
+
+ err = partition_erase_blks(priv.dev_desc, ptn, num_blocks_p);
+ if (err) {
+ printf("Erasing '%s' FAILED! error=%d\n", ptn->name, err);
+ sprintf(priv.response,
+ "FAILfailed to erase partition (%d)", err);
+ } else {
+ printf("partition '%s' erased\n", ptn->name);
+ sprintf(priv.response, "OKAY");
+ }
+}
+
+#define SPARSE_HEADER_MAJOR_VER 1
+
+static int _unsparse(unsigned char *source,
+ lbaint_t sector, lbaint_t num_blks)
+{
+ sparse_header_t *header = (void *) source;
+ u32 i;
+ unsigned long blksz = priv.dev_desc->blksz;
+ u64 section_size = (u64)num_blks * blksz;
+ u64 outlen = 0;
+
+ FBTINFO("sparse_header:\n");
+ FBTINFO("\t magic=0x%08X\n", header->magic);
+ FBTINFO("\t version=%u.%u\n", header->major_version,
+ header->minor_version);
+ FBTINFO("\t file_hdr_size=%u\n", header->file_hdr_sz);
+ FBTINFO("\tchunk_hdr_size=%u\n", header->chunk_hdr_sz);
+ FBTINFO("\t blk_sz=%u\n", header->blk_sz);
+ FBTINFO("\t total_blks=%u\n", header->total_blks);
+ FBTINFO("\t total_chunks=%u\n", header->total_chunks);
+ FBTINFO("\timage_checksum=%u\n", header->image_checksum);
+
+ if (header->magic != SPARSE_HEADER_MAGIC) {
+ printf("sparse: bad magic\n");
+ return 1;
+ }
+
+ if (((u64)header->total_blks * header->blk_sz) > section_size) {
+ printf("sparse: section size %llu MB limit: exceeded\n",
+ section_size/(1024*1024));
+ return 1;
+ }
+
+ if ((header->major_version != SPARSE_HEADER_MAJOR_VER) ||
+ (header->file_hdr_sz != sizeof(sparse_header_t)) ||
+ (header->chunk_hdr_sz != sizeof(chunk_header_t))) {
+ printf("sparse: incompatible format\n");
+ return 1;
+ }
+
+ /* Skip the header now */
+ source += header->file_hdr_sz;
+
+ for (i = 0; i < header->total_chunks; i++) {
+ u64 clen = 0;
+ lbaint_t blkcnt;
+ chunk_header_t *chunk = (void *) source;
+
+ FBTINFO("chunk_header:\n");
+ FBTINFO("\t chunk_type=%u\n", chunk->chunk_type);
+ FBTINFO("\t chunk_sz=%u\n", chunk->chunk_sz);
+ FBTINFO("\t total_sz=%u\n", chunk->total_sz);
+ /* move to next chunk */
+ source += sizeof(chunk_header_t);
+
+ switch (chunk->chunk_type) {
+ case CHUNK_TYPE_RAW:
+ clen = (u64)chunk->chunk_sz * header->blk_sz;
+ FBTINFO("sparse: RAW blk=%d bsz=%d:"
+ " write(sector=%lu,clen=%llu)\n",
+ chunk->chunk_sz, header->blk_sz, sector, clen);
+
+ if (chunk->total_sz != (clen + sizeof(chunk_header_t))) {
+ printf("sparse: bad chunk size for"
+ " chunk %d, type Raw\n", i);
+ return 1;
+ }
+
+ outlen += clen;
+ if (outlen > section_size) {
+ printf("sparse: section size %llu MB limit:"
+ " exceeded\n", section_size/(1024*1024));
+ return 1;
+ }
+ blkcnt = clen / blksz;
+ FBTDBG("sparse: RAW blk=%d bsz=%d:"
+ " write(sector=%lu,clen=%llu)\n",
+ chunk->chunk_sz, header->blk_sz, sector, clen);
+ if (priv.dev_desc->block_write(priv.dev_desc->dev,
+ sector, blkcnt, source)
+ != blkcnt) {
+ printf("sparse: block write to sector %lu"
+ " of %llu bytes (%ld blkcnt) failed\n",
+ sector, clen, blkcnt);
+ return 1;
+ }
+
+ sector += (clen / blksz);
+ source += clen;
+ break;
+
+ case CHUNK_TYPE_DONT_CARE:
+ if (chunk->total_sz != sizeof(chunk_header_t)) {
+ printf("sparse: bogus DONT CARE chunk\n");
+ return 1;
+ }
+ clen = (u64)chunk->chunk_sz * header->blk_sz;
+ FBTDBG("sparse: DONT_CARE blk=%d bsz=%d:"
+ " skip(sector=%lu,clen=%llu)\n",
+ chunk->chunk_sz, header->blk_sz, sector, clen);
+
+ outlen += clen;
+ if (outlen > section_size) {
+ printf("sparse: section size %llu MB limit:"
+ " exceeded\n", section_size/(1024*1024));
+ return 1;
+ }
+ sector += (clen / blksz);
+ break;
+
+ default:
+ printf("sparse: unknown chunk ID %04x\n",
+ chunk->chunk_type);
+ return 1;
+ }
+ }
+
+ printf("sparse: out-length %llu MB\n", outlen/(1024*1024));
+ return 0;
+}
+
+static int do_unsparse(disk_partition_t *ptn, unsigned char *source,
+ lbaint_t sector, lbaint_t num_blks)
+{
+ int rtn;
+ if (partition_write_pre(ptn))
+ return 1;
+
+ rtn = _unsparse(source, sector, num_blks);
+
+ if (partition_write_post(ptn))
+ return 1;
+
+ return rtn;
+}
+
+static int fbt_save_info(disk_partition_t *info_ptn)
+{
+ struct info_partition_header *info_header;
+ char *name;
+ char *value;
+ int i;
+
+ if (!priv.dev_info_uninitialized) {
+ printf("%s partition already initialized, "
+ " cannot write to it again\n", info_ptn->name);
+ return -1;
+ }
+
+ info_header = (struct info_partition_header *)priv.transfer_buffer;
+ name = (char *)(info_header + 1);
+ memset(info_header, 0, priv.dev_desc->blksz);
+ memcpy(&info_header->magic, info_partition_magic,
+ sizeof(info_partition_magic));
+ info_header->num_values = priv.num_device_info;
+
+ for (i = 0; i < priv.num_device_info; i++) {
+ unsigned int len = strlen(priv.dev_info[i].name);
+ memcpy(name, priv.dev_info[i].name, len);
+ value = name + len;
+ *value++ = '=';
+ if (priv.dev_info[i].value) {
+ len = strlen(priv.dev_info[i].value);
+ memcpy(value, priv.dev_info[i].value, len);
+ name = value + len;
+ *name++ = '\n';
+ }
+ }
+ lbaint_t num_blks = 1;
+ i = partition_write_blks(priv.dev_desc, info_ptn, &num_blks,
+ info_header);
+ if (i) {
+ printf("block write to sector %lu failed, error=%d",
+ info_ptn->start, i);
+ return -1;
+ }
+ priv.dev_info_uninitialized = 0;
+ return 0;
+}
+
+static void fbt_handle_flash(char *cmdbuf, int check_unlock)
+{
+ disk_partition_t *ptn;
+
+ if (check_unlock && !priv.unlocked) {
+ printf("%s: failed, device is locked\n", __func__);
+ sprintf(priv.response, "FAILdevice is locked");
+ return;
+ }
+
+ if (!priv.d_bytes) {
+ printf("%s: failed, no image downloaded\n", __func__);
+ sprintf(priv.response, "FAILno image downloaded");
+ return;
+ }
+
+ ptn = fastboot_flash_find_ptn(cmdbuf + 6);
+ if (ptn == 0) {
+ printf("%s: failed, partition %s does not exist\n",
+ __func__, cmdbuf + 6);
+ sprintf(priv.response, "FAILpartition does not exist");
+ return;
+ }
+
+ /* do board/cpu specific special handling if needed. this
+ * can include modifying priv.image_start_ptr to flash from
+ * an address other than the start of the transfer buffer.
+ */
+ priv.image_start_ptr = priv.transfer_buffer;
+ if (board_fbt_handle_flash(ptn, &priv)) {
+ /* error case, return. expect priv.response to be
+ * set by the board specific handler.
+ */
+ printf("%s: failed, board_fbt_handle_flash() error\n",
+ __func__);
+ return;
+ }
+
+ /* Prevent using flash command to write to device_info partition */
+ if (is_info_partition(ptn)) {
+ printf("%s: failed, partition not writable"
+ " using flash command\n",
+ __func__);
+ sprintf(priv.response,
+ "FAILpartition not writable using flash command");
+ return;
+ }
+
+ /* Check if this is not really a flash write but rather a saveenv */
+ if (is_env_partition(ptn)) {
+ if (!himport_r(&env_htab,
+ (const char *)priv.image_start_ptr,
+ priv.d_bytes, '\n', H_NOCLEAR)) {
+ FBTINFO("Import '%s' FAILED!\n", ptn->name);
+ sprintf(priv.response, "FAIL: Import environment");
+ return;
+ }
+
+#if defined(CONFIG_CMD_SAVEENV)
+ if (saveenv()) {
+ printf("Writing '%s' FAILED!\n", ptn->name);
+ sprintf(priv.response, "FAIL: Write partition");
+ return;
+ }
+ printf("saveenv to '%s' DONE!\n", ptn->name);
+#endif
+ sprintf(priv.response, "OKAY");
+ } else {
+ /* Normal case */
+ printf("writing to partition '%s'\n", ptn->name);
+
+ /* Check if we have sparse compressed image */
+ if (((sparse_header_t *)priv.image_start_ptr)->magic
+ == SPARSE_HEADER_MAGIC) {
+ printf("fastboot: %s is in sparse format\n", ptn->name);
+ if (!do_unsparse(ptn, priv.image_start_ptr,
+ ptn->start, ptn->size)) {
+ printf("Writing sparsed: '%s' DONE!\n",
+ ptn->name);
+ sprintf(priv.response, "OKAY");
+ } else {
+ printf("Writing sparsed '%s' FAILED!\n",
+ ptn->name);
+ sprintf(priv.response, "FAIL: Sparsed Write");
+ }
+ } else {
+ /* Normal image: no sparse */
+ int err;
+ loff_t num_bytes = priv.d_bytes;
+
+ printf("Writing %llu bytes to '%s'\n",
+ num_bytes, ptn->name);
+ err = partition_write_bytes(priv.dev_desc, ptn,
+ &num_bytes, priv.image_start_ptr);
+ if (err) {
+ printf("Writing '%s' FAILED! error=%d\n",
+ ptn->name, err);
+ sprintf(priv.response,
+ "FAILWrite partition, error=%d", err);
+ } else {
+ printf("Writing '%s' DONE!\n", ptn->name);
+ sprintf(priv.response, "OKAY");
+ }
+ }
+ } /* Normal Case */
+}
+
+struct getvar_entry {
+ const char *variable_name;
+ int exact_match;
+ const char *(*getvar_func)(const char *arg);
+};
+
+static const char *getvar_version(const char *unused)
+{
+ return version_string;
+}
+
+static const char *getvar_version_baseband(const char *unused)
+{
+ return "n/a";
+}
+
+static const char *getvar_version_bootloader(const char *unused)
+{
+ return CONFIG_FASTBOOT_VERSION_BOOTLOADER;
+}
+
+static const char *getvar_unlocked(const char *unused)
+{
+ return (priv.unlocked ? "yes" : "no");
+}
+
+static const char *getvar_secure(const char *unused)
+{
+ /* we use the inverse meaning of unlocked */
+ return (priv.unlocked ? "no" : "yes");
+}
+
+#if defined (CONFIG_OMAP)
+static const char *getvar_device_type(const char *unused)
+{
+ switch(get_device_type()) {
+ case TST_DEVICE:
+ return "TST";
+ case EMU_DEVICE:
+ return "EMU";
+ case HS_DEVICE:
+ return "HS";
+ case GP_DEVICE:
+ return "GP";
+ default:
+ return "unknown";
+ }
+}
+#endif
+
+static const char *getvar_product(const char *unused)
+{
+ return FASTBOOT_PRODUCT_NAME;
+}
+
+static const char *getvar_serialno(const char *unused)
+{
+ return priv.serial_no;
+}
+
+static const char *getvar_partition_type(const char *args)
+{
+ const char *partition_name;
+ const char *type;
+
+ if (!strcmp(args, "all")) {
+ int i;
+ for (i = 0; i < pcount; i++) {
+ partition_name = (char*)ptable[i].name;
+ printf("partition \"%s\" has type \"%s\"\n",
+ partition_name,
+ board_fbt_get_partition_type(partition_name));
+ }
+ return NULL;
+ }
+
+ partition_name = args + sizeof("partition-type:") - 1;
+ type = board_fbt_get_partition_type(partition_name);
+ if (type) {
+ return type;
+ }
+ snprintf(priv.response, sizeof(priv.response),
+ "FAILunknown partition %s\n", partition_name);
+ return NULL;
+}
+
+static const char *getvar_partition_size(const char *args)
+{
+ const char *partition_name;
+ disk_partition_t *ptn;
+
+ if (!strcmp(args, "all")) {
+ int i;
+ for (i = 0; i < pcount; i++) {
+ printf("partition \"%s\" has size 0x%016llx bytes\n",
+ ptable[i].name,
+ (uint64_t)ptable[i].size * ptable[i].blksz);
+ }
+ return NULL;
+ }
+
+ partition_name = args + sizeof("partition-size:") - 1;
+ ptn = fastboot_flash_find_ptn(partition_name);
+ if (ptn) {
+ snprintf(priv.response, sizeof(priv.response),
+ "OKAY0x%016llx", (uint64_t)ptn->size * ptn->blksz);
+ } else {
+ snprintf(priv.response, sizeof(priv.response),
+ "FAILunknown partition %s\n", partition_name);
+ }
+ return NULL;
+}
+
+static const struct getvar_entry getvar_table[] = {
+ {"version", 1, getvar_version},
+ {"version-baseband", 1, getvar_version_baseband},
+ {"version-bootloader", 1, getvar_version_bootloader},
+ {"unlocked", 1, getvar_unlocked},
+ {"secure", 1, getvar_secure},
+#if defined (CONFIG_OMAP)
+ {"device_type", 1, getvar_device_type},
+#endif
+ {"product", 1, getvar_product},
+ {"serialno", 1, getvar_serialno},
+ {"partition-type:", 0, getvar_partition_type},
+ {"partition-size:", 0, getvar_partition_size}
+};
+
+static void fbt_handle_getvar(char *cmdbuf)
+{
+ char *subcmd = cmdbuf + sizeof("getvar:") - 1;
+ const char *value = NULL;
+ int do_all;
+ int i;
+ if (!strcmp(subcmd, "all"))
+ do_all = 1;
+ else
+ do_all = 0;
+
+ if (do_all) {
+ for (i = 0; i < ARRAY_SIZE(getvar_table); i++) {
+ value = (getvar_table[i].getvar_func)(subcmd);
+ if (value ) {
+ printf("%s: %s\n",
+ getvar_table[i].variable_name, value);
+ }
+ }
+ strcpy(priv.response, "OKAY");
+ } else {
+ for (i = 0; i < ARRAY_SIZE(getvar_table); i++) {
+ int match;
+ if (getvar_table[i].exact_match) {
+ /* look for exact string match */
+ match = !strcmp(getvar_table[i].variable_name,
+ subcmd);
+ } else {
+ /* look for the target string at the
+ * beginning of the argument passed
+ */
+ match = strstr(subcmd,
+ getvar_table[i].variable_name) ==
+ subcmd;
+ }
+ if (match) {
+ value = (getvar_table[i].getvar_func)(subcmd);
+ if (value == NULL) {
+ /* handler did it all in terms of
+ * creating a response.
+ */
+ return;
+ }
+ /* fall through to let the common code
+ * handle creating a response string.
+ */
+ break;
+ }
+ }
+#ifdef CONFIG_FASTBOOT_UBOOT_GETVAR
+ if (!value) {
+ ENTRY e, *ep;
+
+ e.key = subcmd;
+ e.data = NULL;
+ ep = NULL;
+ if (hsearch_r(e, FIND, &ep, &env_htab) && ep != NULL)
+ value = ep->data;
+ }
+#endif
+ if (value) {
+ /* At first I was reluctant to use strncpy because it
+ * typically pads the whole buffer with nulls, but
+ * U-Boot's strncpy does not do that. However, I
+ * do rely on priv.null_term after priv.response
+ * in the struct cmd_fastboot_interface to ensure
+ * the strlen in fbt_response_process doesn't take
+ * a long time.
+ */
+ strcpy(priv.response, "OKAY");
+ strncpy(priv.response + 4, value,
+ (sizeof(priv.response) - 4));
+ } else {
+ strcpy(priv.response, "FAILunknown variable");
+ }
+ }
+}
+
+static void fbt_handle_reboot(const char *cmdbuf)
+{
+ if (!strcmp(&cmdbuf[6], "-bootloader")) {
+ FBTDBG("%s\n", cmdbuf);
+ board_fbt_set_reboot_type(FASTBOOT_REBOOT_BOOTLOADER);
+ }
+ if (!strcmp(&cmdbuf[6], "-recovery")) {
+ FBTDBG("%s\n", cmdbuf);
+ board_fbt_set_reboot_type(FASTBOOT_REBOOT_RECOVERY);
+ }
+ if (!strcmp(&cmdbuf[6], "-recovery:wipe_data")) {
+ FBTDBG("%s\n", cmdbuf);
+ board_fbt_set_reboot_type(FASTBOOT_REBOOT_RECOVERY_WIPE_DATA);
+ }
+
+ strcpy(priv.response, "OKAY");
+ priv.flag |= FASTBOOT_FLAG_RESPONSE;
+ fbt_handle_response();
+ udelay(1000000); /* 1 sec */
+
+ board_fbt_end();
+
+ do_reset(NULL, 0, 0, NULL);
+}
+
+static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of fastboot cmdbuf */
+
+static void fbt_handle_oem_setinfo(const char *cmdbuf)
+{
+ char *name, *value;
+ struct device_info *di;
+
+ FBTDBG("oem setinfo\n");
+
+ /* this is only allowed if the device info isn't already
+ * initlialized in flash
+ */
+ if (!priv.dev_info_uninitialized) {
+ printf("Not allowed to change device info already in flash\n");
+ strcpy(priv.response, "FAILnot allowed to change"
+ " device info already in flash");
+ return;
+ }
+
+ if (priv.num_device_info == FASTBOOT_MAX_NUM_DEVICE_INFO) {
+ printf("Already at maximum number of device info (%d),"
+ " no more allowed\n", FASTBOOT_MAX_NUM_DEVICE_INFO);
+ strcpy(priv.response, "FAILmax device info reached");
+ return;
+ }
+
+ /* copy to tmp_buf which will be modified by str_tok() */
+ strcpy(tmp_buf, cmdbuf);
+
+ name = strtok(tmp_buf, "=");
+ value = strtok(NULL, "\n");
+ if (!name || !value) {
+ printf("Invalid format for setinfo.\n");
+ printf("Syntax is "
+ "'fastboot oem setinfo <info_name>=<info_value>\n");
+ strcpy(priv.response, "FAILinvalid device info");
+ return;
+ }
+
+ /* we enter new value at end so last slot should be free.
+ * we don't currently allow changing a value already set.
+ */
+ di = &priv.dev_info[priv.num_device_info];
+ if (di->name || di->value) {
+ printf("Error, device info entry not free as expected\n");
+ strcpy(priv.response, "FAILinternal error");
+ return;
+ }
+
+ di->name = strdup(name);
+ di->value = strdup(value);
+ if ((di->name == NULL) || (di->value == NULL)) {
+ printf("strdup() failed, unable to set info\n");
+ strcpy(priv.response, "FAILstrdup() failure\n");
+ free(di->name);
+ free(di->value);
+ return;
+ }
+
+ printf("Set device info %s=%s\n", di->name, di->value);
+ if (!strcmp(di->name, FASTBOOT_SERIALNO_BOOTARG))
+ set_serial_number(di->value);
+ priv.num_device_info++;
+
+ strcpy(priv.response, "OKAY");
+}
+
+static int fbt_send_raw_info(const char *info, int bytes_left)
+{
+ int response_max;
+
+ if (!priv.executing_command)
+ return -1;
+
+ /* break up info into response sized chunks */
+ /* remove trailing '\n' */
+ if (info[bytes_left-1] == '\n')
+ bytes_left--;
+
+ /* -4 for the INFO prefix */
+ response_max = sizeof(priv.response) - 4;
+ strcpy(priv.response, "INFO");
+ while (1) {
+ if (bytes_left >= response_max) {
+ strncpy(priv.response + 4, info,
+ response_max);
+
+ /* flush any data set by command */
+ priv.flag |= FASTBOOT_FLAG_RESPONSE;
+ fbt_handle_response();
+ fbt_wait_usb_fifo_flush();
+
+ info += response_max;
+ bytes_left -= response_max;
+ } else {
+ strncpy(priv.response + 4, info,
+ bytes_left);
+
+ /* in case we stripped '\n',
+ make sure priv.response is
+ terminated */
+ priv.response[4 + bytes_left] = '\0';
+
+ break;
+ }
+ }
+
+ priv.flag |= FASTBOOT_FLAG_RESPONSE;
+ fbt_handle_response();
+ fbt_wait_usb_fifo_flush();
+
+ return 0;
+}
+
+static void fbt_dump_log(char *buf, uint32_t buf_size)
+{
+ /* the log consists of a bunch of printf output, with
+ * logs of '\n' interspersed. to make it format a
+ * bit better when sending it via the INFO
+ * part of the fastboot protocol, which has a limited
+ * buffer, break the log into bits that end
+ * with '\n', like replaying the printfs.
+ */
+ char *line_start = buf;
+
+ if (buf_size == 0) {
+ printf("%s: unexpected buf size of 0\n", __func__);
+ return;
+ }
+
+ /* guarantee null termination for strchr/strlen */
+ buf[buf_size - 1] = 0;
+ while (buf_size) {
+ char *next_line = strchr(line_start, '\n');
+ if (next_line) {
+ int len = next_line - line_start + 1;
+ fbt_send_raw_info(line_start, len);
+ line_start += len;
+ buf_size -= len;
+ } else {
+ fbt_send_raw_info(line_start, strlen(line_start));
+ break;
+ }
+ }
+}
+
+struct ram_console_buffer {
+ uint32_t sig;
+ uint32_t start;
+ uint32_t size;
+ uint8_t data[0];
+};
+#define RAM_CONSOLE_SIG (0x43474244) /* 'DBGC' */
+
+static void fbt_dump_kmsg(void)
+{
+ /* the kmsg log is similar to the log we keep in the bootloader
+ * except that it has a header, is at an address fixed for
+ * each board, and starts with a ram_console_buffer structure.
+ */
+ struct ram_console_buffer *buf;
+#ifndef CONFIG_FASTBOOT_RAMCONSOLE_START
+ printf("No ram console start address defined\n");
+ strcpy(priv.response, "FAILNo ram console start address defined");
+ return;
+#else
+ buf = (struct ram_console_buffer *)CONFIG_FASTBOOT_RAMCONSOLE_START;
+#endif
+ if (buf->sig != RAM_CONSOLE_SIG) {
+ printf("Ram console signature not found\n");
+ strcpy(priv.response, "FAILRam console signature not found\n");
+ return;
+ }
+ printf("Ram console found (size %d, start %d):\n",
+ buf->size, buf->start);
+ fbt_dump_log((char *)&buf->data[0], buf->start);
+ strcpy(priv.response, "OKAY");
+}
+
+static void fbt_handle_oem(char *cmdbuf)
+{
+ cmdbuf += 4;
+
+ /* %fastboot oem log */
+ if (strcmp(cmdbuf, "log") == 0) {
+ FBTDBG("oem %s\n", cmdbuf);
+ fbt_dump_log(log_buffer, log_position);
+ strcpy(priv.response, "OKAY");
+ return;
+ }
+
+ /* %fastboot oem kmsg */
+ if (strcmp(cmdbuf, "kmsg") == 0) {
+ FBTDBG("oem %s\n", cmdbuf);
+ fbt_dump_kmsg();
+ return;
+ }
+
+ /* %fastboot oem recovery */
+ if (strcmp(cmdbuf, "recovery") == 0) {
+ FBTDBG("oem recovery\n");
+ fbt_handle_reboot("reboot-recovery");
+ return;
+ }
+
+ /* %fastboot oem recovery:wipe_data */
+ if (strcmp(cmdbuf, "recovery:wipe_data") == 0) {
+ FBTDBG("oem recovery:wipe_data\n");
+ fbt_handle_reboot("reboot-recovery:wipe_data");
+ return;
+ }
+
+ /* %fastboot oem unlock */
+ if (strcmp(cmdbuf, "unlock") == 0) {
+ FBTDBG("oem unlock\n");
+ if (priv.unlocked) {
+ printf("oem unlock ignored, device already unlocked\n");
+ strcpy(priv.response, "FAILalready unlocked");
+ return;
+ }
+ printf("oem unlock requested:\n");
+ printf("\tUnlocking forces a factory reset and could\n");
+ printf("\topen your device up to a world of hurt. If you\n");
+ printf("\tare sure you know what you're doing, then accept\n");
+ printf("\tin %d seconds via 'fastboot oem unlock_accept'.\n",
+ FASTBOOT_UNLOCK_TIMEOUT_SECS);
+ priv.unlock_pending_start_time = get_timer(0);
+ strcpy(priv.response, "OKAY");
+ return;
+ }
+
+ if (strcmp(cmdbuf, "unlock_accept") == 0) {
+ int err;
+ FBTDBG("oem unlock_accept\n");
+ if (!priv.unlock_pending_start_time) {
+ printf("oem unlock_accept ignored, not pending\n");
+ strcpy(priv.response, "FAILoem unlock not requested");
+ return;
+ }
+ priv.unlock_pending_start_time = 0;
+ printf("Erasing userdata partition\n");
+ err = partition_erase_blks(priv.dev_desc,
+ fastboot_flash_find_ptn("userdata"),
+ NULL);
+ if (err) {
+ printf("Erase failed with error %d\n", err);
+ strcpy(priv.response, "FAILErasing userdata failed");
+ return;
+ }
+ printf("Erasing succeeded\n");
+ fbt_set_unlocked(1);
+ strcpy(priv.response, "OKAY");
+ priv.flag |= FASTBOOT_FLAG_RESPONSE;
+ fbt_handle_response();
+ udelay(1000000); /* 1 sec */
+ /* now reboot into recovery to do a format of the
+ * userdata partition so it's ready to use on next boot
+ */
+ fbt_run_recovery_wipe_data();
+ return;
+ }
+
+ if (strcmp(cmdbuf, "lock") == 0) {
+ FBTDBG("oem lock\n");
+ if (!priv.unlocked) {
+ printf("oem lock ignored, already locked\n");
+ strcpy(priv.response, "FAILalready locked");
+ return;
+ }
+ fbt_set_unlocked(0);
+ strcpy(priv.response, "OKAY");
+ return;
+ }
+
+ /* %fastboot oem erase partition <numblocks>
+ * similar to 'fastboot erase' except an optional number
+ * of blocks can be passed to erase less than the
+ * full partition, for speed
+ */
+ if (strncmp(cmdbuf, "erase ", 6) == 0) {
+ FBTDBG("oem %s\n", cmdbuf);
+ fbt_handle_erase(cmdbuf);
+ return;
+ }
+
+ /* All other oem commands are not allowed if device is locked */
+ if (!priv.unlocked) {
+ sprintf(priv.response, "FAILdevice is locked");
+ return;
+ }
+
+ /* %fastboot oem setinfo <info_name>=<info_value> */
+ if (strncmp(cmdbuf, "setinfo ", 8) == 0) {
+ cmdbuf += 8;
+ fbt_handle_oem_setinfo(cmdbuf);
+ return;
+ }
+
+ /* %fastboot oem saveinfo */
+ if (strcmp(cmdbuf, "saveinfo") == 0) {
+ disk_partition_t *info_ptn;
+ info_ptn = fastboot_flash_find_ptn(CONFIG_INFO_PARTITION);
+
+ if (info_ptn == NULL) {
+ sprintf(priv.response, "FAILpartition does not exist");
+ return;
+ }
+ if (fbt_save_info(info_ptn)) {
+ printf("Writing '%s' FAILED!\n", info_ptn->name);
+ sprintf(priv.response, "FAIL: Write partition");
+ } else {
+ printf("Device info saved to partition '%s'\n",
+ info_ptn->name);
+ sprintf(priv.response, "OKAY");
+ }
+ return;
+ }
+
+ /* %fastboot oem ucmd ... */
+ if (strncmp(cmdbuf, "ucmd ", 5) == 0) {
+ FBTDBG("oem %s\n", cmdbuf);
+ cmdbuf += 5;
+
+ if (run_command(cmdbuf, 0) < 0)
+ strcpy(priv.response, "FAILcommand failed");
+ else
+ strcpy(priv.response, "OKAY");
+ return;
+ }
+
+ /* %fastboot oem [xxx] */
+ FBTDBG("oem %s\n", cmdbuf);
+ if (board_fbt_oem(cmdbuf) >= 0) {
+ strcpy(priv.response, "OKAY");
+ return;
+ }
+
+ printf("\nfastboot: unsupported oem command %s\n", cmdbuf);
+ strcpy(priv.response, "FAILinvalid command");
+}
+
+static void fbt_handle_boot(const char *cmdbuf)
+{
+ if (!priv.unlocked) {
+ sprintf(priv.response, "FAILdevice is locked");
+ return;
+ }
+
+ if ((priv.d_bytes) &&
+ (CONFIG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE < priv.d_bytes)) {
+ char start[32];
+ char *booti[] = { "booti", start };
+ char *go[] = { "go", start };
+
+ /*
+ * 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 *) priv.transfer_buffer;
+
+ board_fbt_end();
+
+ sprintf(start, "%p", fb_hdr);
+
+ /* Execution should jump to kernel so send the response
+ now and wait a bit. */
+ sprintf(priv.response, "OKAY");
+ priv.flag |= FASTBOOT_FLAG_RESPONSE;
+ fbt_handle_response();
+ udelay(1000000); /* 1 sec */
+
+ do_booti(NULL, 0, ARRAY_SIZE(booti), booti);
+
+ printf("do_booti() returned, trying go..\n");
+
+ FBTINFO("Booting raw image..\n");
+ do_go(NULL, 0, ARRAY_SIZE(go), go);
+
+ FBTERR("booting failed, reset the board\n");
+ board_fbt_start();
+ }
+ sprintf(priv.response, "FAILinvalid boot image");
+}
+
+/* XXX: Replace magic number & strings with macros */
+static int fbt_rx_process(unsigned char *buffer, int length)
+{
+ struct usb_endpoint_instance *ep;
+ char *cmdbuf;
+ int clear_cmd_buf;
+
+ if (priv.d_size) {
+ if (length < priv.d_size) {
+ /* don't clear cmd buf because we've replaced it
+ * with our transfer buffer. we'll clear it at
+ * the end of the download.
+ */
+ return 0;
+ }
+
+ /* transfer complete */
+ priv.d_bytes = priv.d_size;
+ priv.d_size = 0;
+ strcpy(priv.response, "OKAY");
+ priv.flag |= FASTBOOT_FLAG_RESPONSE;
+
+ /* restore default buffer in urb */
+ ep = &endpoint_instance[RX_EP_INDEX];
+ ep->rcv_urb->buffer = (u8 *)ep->rcv_urb->buffer_data;
+ ep->rcv_urb->buffer_length = sizeof(ep->rcv_urb->buffer_data);
+
+ FBTINFO("downloaded %llu bytes\n", priv.d_bytes);
+
+ /* clear the cmd buf from last time */
+ return 1;
+ }
+
+ /* command */
+ cmdbuf = (char *) buffer;
+ clear_cmd_buf = 1;
+
+ /* Generic failed response */
+ strcpy(priv.response, "FAIL");
+
+ FBTDBG("command\n");
+
+ printf("cmdbuf = (%s)\n", cmdbuf);
+ priv.executing_command = 1;
+
+ /* %fastboot getvar: <var_name> */
+ if (memcmp(cmdbuf, "getvar:", 7) == 0) {
+ FBTDBG("getvar\n");
+ fbt_handle_getvar(cmdbuf);
+ }
+
+ /* %fastboot oem <cmd> */
+ else if (memcmp(cmdbuf, "oem ", 4) == 0) {
+ FBTDBG("oem\n");
+ fbt_handle_oem(cmdbuf);
+ }
+
+ /* %fastboot erase <partition_name> */
+ else if (memcmp(cmdbuf, "erase:", 6) == 0) {
+ FBTDBG("erase\n");
+ fbt_handle_erase(cmdbuf);
+ }
+
+ /* %fastboot flash:<partition_name> */
+ else if (memcmp(cmdbuf, "flash:", 6) == 0) {
+ FBTDBG("flash\n");
+ fbt_handle_flash(cmdbuf, 1);
+ }
+
+ /* %fastboot reboot
+ * %fastboot reboot-bootloader
+ */
+ else if (memcmp(cmdbuf, "reboot", 6) == 0) {
+ FBTDBG("reboot or reboot-bootloader\n");
+ fbt_handle_reboot(cmdbuf);
+ }
+
+ /* %fastboot continue */
+ else if (strcmp(cmdbuf, "continue") == 0) {
+ FBTDBG("continue\n");
+ strcpy(priv.response, "OKAY");
+ priv.exit = 1;
+ }
+
+ /* %fastboot boot <kernel> [ <ramdisk> ] */
+ else if (memcmp(cmdbuf, "boot", 4) == 0) {
+ FBTDBG("boot\n");
+ fbt_handle_boot(cmdbuf);
+ }
+
+ /* Sent as part of a '%fastboot flash <partname>' command
+ * This sends the data over with byte count:
+ * %download:<num_bytes>
+ */
+ else if (memcmp(cmdbuf, "download:", 9) == 0) {
+ FBTDBG("download\n");
+
+ /* XXX: need any check for size & bytes ? */
+ priv.d_size = simple_strtoul (cmdbuf + 9, NULL, 16);
+ priv.d_bytes = 0;
+
+ FBTINFO("starting download of %llu bytes\n", priv.d_size);
+ if (priv.d_size == 0) {
+ strcpy(priv.response, "FAILdata invalid size");
+ } else if (priv.d_size > priv.transfer_buffer_size) {
+ priv.d_size = 0;
+ strcpy(priv.response, "FAILdata too large");
+ } else {
+ sprintf(priv.response, "DATA%08llx", priv.d_size);
+
+ /* as an optimization, replace the builtin
+ * urb->buffer and urb->buffer_length with our
+ * own so we don't have to do extra copy.
+ */
+ ep = &endpoint_instance[RX_EP_INDEX];
+ ep->rcv_urb->buffer = priv.transfer_buffer;
+ ep->rcv_urb->buffer_length = priv.d_size;
+ ep->rcv_urb->actual_length = 0;
+
+ /* don't poison the cmd buffer because
+ * we've replaced it with our
+ * transfer buffer for the download.
+ */
+ clear_cmd_buf = 0;
+ }
+ }
+ priv.flag |= FASTBOOT_FLAG_RESPONSE;
+ priv.executing_command = 0;
+ return clear_cmd_buf;
+}
+
+static void fbt_handle_rx(void)
+{
+ struct usb_endpoint_instance *ep = &endpoint_instance[RX_EP_INDEX];
+
+ /* XXX: Or update status field, if so,
+ "usbd_rcv_complete" [gadget/core.c] also need to be modified */
+ if (ep->rcv_urb->actual_length) {
+ FBTDBG("rx length: %u\n", ep->rcv_urb->actual_length);
+ if (fbt_rx_process(ep->rcv_urb->buffer,
+ ep->rcv_urb->actual_length)) {
+ /* Poison the command buffer so there's no confusion
+ * when we receive the next one. fastboot commands
+ * are sent w/o NULL termination so we don't want
+ * stale data in the buffer.
+ * Also, it is assumed that at the time of creation of
+ * urb it is poisoned.
+ */
+ memset(ep->rcv_urb->buffer, 0, FASTBOOT_COMMAND_SIZE);
+ ep->rcv_urb->actual_length = 0;
+ }
+ fbt_handle_response();
+ }
+}
+
+static void fbt_response_process(void)
+{
+ struct usb_endpoint_instance *ep = &endpoint_instance[TX_EP_INDEX];
+ struct urb *current_urb = NULL;
+ unsigned char *dest = NULL;
+ int n;
+
+ current_urb = next_urb(device_instance, ep);
+ if (!current_urb) {
+ FBTERR("%s: current_urb NULL", __func__);
+ return;
+ }
+
+ dest = current_urb->buffer + current_urb->actual_length;
+ n = MIN(64, strlen(priv.response));
+ memcpy(dest, priv.response, n);
+ current_urb->actual_length += n;
+ /*
+ * This FBTDBG appears to break communication when DEBUG
+ * is on, so comment it out.
+ FBTDBG("response urb length: %u\n", current_urb->actual_length);
+ */
+ if (ep->last == 0)
+ udc_endpoint_write(ep);
+}
+
+static void fbt_handle_response(void)
+{
+ if (priv.flag & FASTBOOT_FLAG_RESPONSE) {
+ fbt_response_process();
+ priv.flag &= ~FASTBOOT_FLAG_RESPONSE;
+ }
+}
+
+static void fbt_clear_recovery_flag(void)
+{
+ if (getenv(FASTBOOT_RUN_RECOVERY_ENV_NAME)) {
+ setenv(FASTBOOT_RUN_RECOVERY_ENV_NAME, NULL);
+#if defined(CONFIG_CMD_SAVEENV)
+ saveenv();
+#endif
+ }
+}
+
+static void fbt_run_recovery(int do_saveenv)
+{
+ board_fbt_end();
+
+ /* to make recovery (which processes OTAs) more failsafe,
+ * we save the fact that we were asked to boot into
+ * recovery. if power is pulled and then restored, we
+ * will use that info to rerun recovery again and try
+ * to complete the OTA installation.
+ */
+ if (do_saveenv) {
+ setenv(FASTBOOT_RUN_RECOVERY_ENV_NAME, "1");
+#ifdef CONFIG_CMD_SAVEENV
+ saveenv();
+#endif
+ }
+
+ char *const boot_recovery_cmd[] = {"booti", "recovery"};
+ do_booti(NULL, 0, ARRAY_SIZE(boot_recovery_cmd), boot_recovery_cmd);
+
+ /* returns if recovery.img is bad */
+ board_fbt_start();
+ printf("\nfastboot: Error: Invalid recovery img\n");
+
+ /* Always clear so we don't wind up rebooting again into
+ * bad recovery img.
+ */
+ fbt_clear_recovery_flag();
+}
+
+struct bootloader_message {
+ char command[32];
+ char status[32];
+ char recovery[1024];
+};
+
+static void fbt_run_recovery_wipe_data(void)
+{
+ struct bootloader_message *bmsg;
+
+ printf("Rebooting into recovery to do wipe_data\n");
+
+ bmsg = (struct bootloader_message*)priv.transfer_buffer;
+ memset(bmsg, 0, sizeof(*bmsg));
+ bmsg->command[0] = 0;
+ bmsg->status[0] = 0;
+ strcpy(bmsg->recovery, "recovery\n--wipe_data");
+ priv.d_bytes = sizeof(*bmsg);
+
+ /* write this structure to the "misc" partition, no unlock check */
+ fbt_handle_flash("flash:misc", 0);
+
+ /* now reboot to recovery */
+ fbt_run_recovery(1);
+}
+
+/*
+ * default board-specific hooks and defaults
+ */
+static int __def_fbt_oem(const char *cmdbuf)
+{
+ return -1;
+}
+static void __def_fbt_set_reboot_type(enum fbt_reboot_type fre)
+{
+}
+static enum fbt_reboot_type __def_fbt_get_reboot_type(void)
+{
+ return FASTBOOT_REBOOT_NORMAL;
+}
+static int __def_fbt_key_pressed(void)
+{
+ return 0;
+}
+static enum fbt_reboot_type __def_fbt_key_command(void)
+{
+ return FASTBOOT_REBOOT_NONE;
+}
+static int __def_fbt_load_ptbl(void)
+{
+ u64 length;
+ disk_partition_t ptn;
+ int n;
+ int res = -1;
+ block_dev_desc_t *blkdev = priv.dev_desc;
+ unsigned long blksz = blkdev->blksz;
+
+ init_part(blkdev);
+ if (blkdev->part_type == PART_TYPE_UNKNOWN) {
+ printf("unknown partition table on %s\n", FASTBOOT_BLKDEV);
+ return -1;
+ }
+
+ printf("lba size = %lu\n", blksz);
+ printf("lba_start partition_size name\n");
+ printf("========= ====================== ==============\n");
+ for (n = CONFIG_MIN_PARTITION_NUM; n <= CONFIG_MAX_PARTITION_NUM; n++) {
+ if (get_partition_info(blkdev, n, &ptn))
+ continue; /* No partition <n> */
+ if (!ptn.size || !ptn.blksz || !ptn.name[0])
+ continue; /* Partition <n> is empty (or sick) */
+ fbt_add_ptn(&ptn);
+
+ length = (u64)blksz * ptn.size;
+ if (length > (1024 * 1024))
+ printf(" %8lu %12llu(%7lluM) %s\n",
+ ptn.start,
+ length, length/(1024*1024),
+ ptn.name);
+ else
+ printf(" %8lu %12llu(%7lluK) %s\n",
+ ptn.start,
+ length, length/1024,
+ ptn.name);
+ res = 0;
+ }
+ printf("========= ====================== ==============\n");
+ return res;
+}
+static void __def_fbt_start(void)
+{
+}
+static void __def_fbt_end(void)
+{
+}
+static void __def_board_fbt_finalize_bootargs(char* args, size_t buf_sz)
+{
+ return;
+}
+static int __def_board_fbt_handle_flash(disk_partition_t *ptn,
+ struct cmd_fastboot_interface *priv)
+{
+ return 0;
+}
+static const char *__def_board_fbt_get_partition_type(const char *p_name)
+{
+ return NULL;
+}
+
+int board_fbt_oem(const char *cmdbuf)
+ __attribute__((weak, alias("__def_fbt_oem")));
+void board_fbt_set_reboot_type(enum fbt_reboot_type fre)
+ __attribute__((weak, alias("__def_fbt_set_reboot_type")));
+enum fbt_reboot_type board_fbt_get_reboot_type(void)
+ __attribute__((weak, alias("__def_fbt_get_reboot_type")));
+int board_fbt_key_pressed(void)
+ __attribute__((weak, alias("__def_fbt_key_pressed")));
+enum fbt_reboot_type board_fbt_key_command(void)
+ __attribute__((weak, alias("__def_fbt_key_command")));
+int board_fbt_load_ptbl(void)
+ __attribute__((weak, alias("__def_fbt_load_ptbl")));
+void board_fbt_start(void)
+ __attribute__((weak, alias("__def_fbt_start")));
+void board_fbt_end(void)
+ __attribute__((weak, alias("__def_fbt_end")));
+void board_fbt_finalize_bootargs(char* args, size_t buf_sz)
+ __attribute__((weak, alias("__def_board_fbt_finalize_bootargs")));
+int board_fbt_handle_flash(disk_partition_t *ptn,
+ struct cmd_fastboot_interface *priv)
+ __attribute__((weak, alias("__def_board_fbt_handle_flash")));
+const char *board_fbt_get_partition_type(const char *partition_name)
+ __attribute__((weak, alias("__def_board_fbt_get_partition_type")));
+
+/* command */
+static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ int ret;
+
+ if (!priv.dev_desc) {
+ printf("fastboot was not successfully initialized\n");
+ return -1;
+ }
+
+ /* currently we don't allow restarting fastboot if you've run
+ * it before and exited to u-boot prompt. it's possible to
+ * support, but there's are edge cases that we're not
+ * sure the answer to (e.g. do we reload the partition table
+ * or not) and it's just not a common situation so we're
+ * just saying no for now.
+ */
+ if (priv.flag & FASTBOOT_FLAG_HAS_RUN) {
+ printf("fastboot can't be restarted\n");
+ return -1;
+ }
+ priv.flag |= FASTBOOT_FLAG_HAS_RUN;
+
+ printf("Starting fastboot protocol\n");
+
+ board_fbt_start();
+
+ fbt_init_endpoint_ptrs();
+
+ ret = udc_init();
+ if (ret < 0) {
+ FBTERR("%s: MUSB UDC init failure\n", __func__);
+ goto out;
+ }
+
+ fbt_init_strings();
+ fbt_init_instances();
+
+ udc_startup_events(device_instance);
+ udc_connect();
+
+ FBTINFO("fastboot initialized\n");
+
+ while (1) {
+ udc_irq();
+ if (priv.configured) {
+ fbt_handle_rx();
+ if (priv.unlock_pending_start_time) {
+ /* check if unlock pending should expire */
+ if (get_timer(priv.unlock_pending_start_time) >
+ (FASTBOOT_UNLOCK_TIMEOUT_SECS * 1000)) {
+ printf("unlock pending expired\n");
+ priv.unlock_pending_start_time = 0;
+ }
+ }
+ }
+ priv.exit |= ctrlc();
+ if (priv.exit) {
+ FBTINFO("fastboot end\n");
+ break;
+ }
+ switch(board_fbt_key_command()) {
+ case FASTBOOT_REBOOT_NORMAL:
+ printf("rebooting due to key\n");
+ fbt_handle_reboot("reboot");
+ break;
+ case FASTBOOT_REBOOT_BOOTLOADER:
+ printf("rebooting to bootloader due to key\n");
+ fbt_handle_reboot("reboot-bootloader");
+ break;
+ case FASTBOOT_REBOOT_RECOVERY_WIPE_DATA:
+ fbt_run_recovery_wipe_data();
+ break;
+ case FASTBOOT_REBOOT_RECOVERY:
+ printf("starting recovery due to key\n");
+ fbt_run_recovery(1);
+ break;
+ case FASTBOOT_REBOOT_UNKNOWN:
+ case FASTBOOT_REBOOT_NONE:
+ default:
+ break;
+ }
+ }
+
+out:
+ board_fbt_end();
+ return ret;
+}
+
+U_BOOT_CMD(fastboot, 1, 1, do_fastboot,
+ "use USB Fastboot protocol", NULL);
+
+/* Section for Android bootimage format support
+ * Refer:
+ * http://android.git.kernel.org/?p=platform/system/core.git;a=blob;f=mkbootimg/bootimg.h
+ */
+static void bootimg_print_image_hdr(struct fastboot_boot_img_hdr *hdr)
+{
+#ifdef DEBUG
+ int i;
+ printf(" Image magic: %s\n", hdr->magic);
+
+ printf(" kernel_size: 0x%x\n", hdr->kernel_size);
+ printf(" kernel_addr: 0x%x\n", hdr->kernel_addr);
+
+ printf(" rdisk_size: 0x%x\n", hdr->ramdisk_size);
+ printf(" rdisk_addr: 0x%x\n", hdr->ramdisk_addr);
+
+ printf(" second_size: 0x%x\n", hdr->second_size);
+ printf(" second_addr: 0x%x\n", hdr->second_addr);
+
+ printf(" tags_addr: 0x%x\n", hdr->tags_addr);
+ printf(" page_size: 0x%x\n", hdr->page_size);
+
+ printf(" name: %s\n", hdr->name);
+ printf(" cmdline: %s\n", hdr->cmdline);
+
+ for (i = 0; i < 8; i++)
+ printf(" id[%d]: 0x%x\n", i, hdr->id[i]);
+#endif
+}
+
+/* booti [ <addr> | <partition> ] */
+static int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ char *boot_source = "boot";
+ block_dev_desc_t *blkdev = priv.dev_desc;
+ disk_partition_t *ptn;
+ struct fastboot_boot_img_hdr *hdr = NULL;
+ bootm_headers_t images;
+ int need_post_ran = 0;
+
+ if (argc >= 2)
+ boot_source = argv[1];
+
+ if (!blkdev) {
+ printf("fastboot was not successfully initialized\n");
+ return -1;
+ }
+
+ ptn = fastboot_flash_find_ptn(boot_source);
+ if (ptn) {
+ unsigned long blksz;
+ unsigned sector;
+ unsigned blocks;
+
+ if (partition_read_pre(ptn)) {
+ printf("pre-read commands for partition '%s' failed\n",
+ ptn->name);
+ goto fail;
+ }
+ need_post_ran = 1;
+
+ blksz = blkdev->blksz;
+ hdr = malloc(blksz);
+ if (hdr == NULL) {
+ printf("error allocating blksz(%lu) buffer\n", blksz);
+ goto fail;
+ }
+ if (blkdev->block_read(blkdev->dev, ptn->start,
+ 1, (void *) hdr) != 1) {
+ printf("booti: failed to read bootimg header\n");
+ goto fail;
+ }
+ if (memcmp(hdr->magic, FASTBOOT_BOOT_MAGIC,
+ FASTBOOT_BOOT_MAGIC_SIZE)) {
+ printf("booti: bad boot image magic\n");
+ goto fail;
+ }
+
+ bootimg_print_image_hdr(hdr);
+
+ sector = ptn->start + (hdr->page_size / blksz);
+ blocks = DIV_ROUND_UP(hdr->kernel_size, blksz);
+ if (blkdev->block_read(blkdev->dev, sector, blocks,
+ (void *) hdr->kernel_addr) !=
+ blocks) {
+ printf("booti: failed to read kernel\n");
+ goto fail;
+ }
+
+ sector += ALIGN(hdr->kernel_size, hdr->page_size) / blksz;
+ blocks = DIV_ROUND_UP(hdr->ramdisk_size, blksz);
+ if (blkdev->block_read(blkdev->dev, sector, blocks,
+ (void *) hdr->ramdisk_addr) !=
+ blocks) {
+ printf("booti: failed to read ramdisk\n");
+ goto fail;
+ }
+ if (need_post_ran) {
+ need_post_ran = 0;
+ if (partition_read_post(ptn)) {
+ printf("post-read commands for partition '%s' "
+ "failed\n", ptn->name);
+ goto fail;
+ }
+ }
+ } else {
+ unsigned addr;
+ void *kaddr, *raddr;
+ char *ep;
+
+ addr = simple_strtoul(boot_source, &ep, 16);
+ if (ep == boot_source || *ep != '\0') {
+ printf("'%s' does not seem to be a partition nor "
+ "an address\n", boot_source);
+ /* this is most likely due to having no
+ * partition table in factory case, or could
+ * be argument is wrong. in either case, start
+ * fastboot mode.
+ */
+ goto fail;
+ }
+
+ hdr = malloc(sizeof(*hdr));
+ if (hdr == NULL) {
+ printf("error allocating buffer\n");
+ goto fail;
+ }
+
+ /* set this aside somewhere safe */
+ memcpy(hdr, (void *) addr, sizeof(*hdr));
+
+ if (memcmp(hdr->magic, FASTBOOT_BOOT_MAGIC,
+ FASTBOOT_BOOT_MAGIC_SIZE)) {
+ printf("booti: bad boot image magic\n");
+ goto fail;
+ }
+
+ bootimg_print_image_hdr(hdr);
+
+ kaddr = (void *)(addr + hdr->page_size);
+ raddr = (void *)(kaddr + ALIGN(hdr->kernel_size,
+ hdr->page_size));
+ memmove((void *)hdr->kernel_addr, kaddr, hdr->kernel_size);
+ memmove((void *)hdr->ramdisk_addr, raddr, hdr->ramdisk_size);
+ }
+
+ printf("kernel @ %08x (%d)\n", hdr->kernel_addr, hdr->kernel_size);
+ printf("ramdisk @ %08x (%d)\n", hdr->ramdisk_addr, hdr->ramdisk_size);
+
+#ifdef CONFIG_CMDLINE_TAG
+
+#ifdef CONFIG_FASTBOOT_PRESERVE_BOOTARGS
+ setenv("hdr_cmdline", (char *)hdr->cmdline);
+#else
+ {
+ /* static just to be safe when it comes to the stack */
+ static char command_line[1024];
+ int i, amt;
+
+ /* Use the command line in the bootimg header instead of
+ * any hardcoded into u-boot. Also, Android wants the
+ * serial number on the command line instead of via
+ * tags so append the serial number to the bootimg header
+ * value and set the bootargs environment variable.
+ * do_bootm_linux() will use the bootargs environment variable
+ * to pass it to the kernel. Add the bootloader
+ * version too.
+ */
+ amt = snprintf(command_line,
+ sizeof(command_line),
+ "%s androidboot.bootloader=%s",
+ hdr->cmdline,
+ CONFIG_FASTBOOT_VERSION_BOOTLOADER);
+
+ for (i = 0; i < priv.num_device_info; i++) {
+ /* Append device specific information like
+ * MAC addresses and serialno
+ */
+ amt += snprintf(command_line + amt,
+ sizeof(command_line) - amt,
+ " %s=%s",
+ priv.dev_info[i].name,
+ priv.dev_info[i].value);
+ }
+
+ /* append serial number if it wasn't in device_info already */
+ if (!strstr(command_line, FASTBOOT_SERIALNO_BOOTARG)) {
+ snprintf(command_line + amt, sizeof(command_line) - amt,
+ " %s=%s", FASTBOOT_SERIALNO_BOOTARG,
+ priv.serial_no);
+ }
+
+ command_line[sizeof(command_line) - 1] = 0;
+ board_fbt_finalize_bootargs(command_line, sizeof(command_line));
+
+ setenv("bootargs", command_line);
+ }
+#endif /* CONFIG_FASTBOOT_PRESERVE_BOOTARGS */
+#endif /* CONFIG_CMDLINE_TAG */
+
+ memset(&images, 0, sizeof(images));
+ images.ep = hdr->kernel_addr;
+ images.rd_start = hdr->ramdisk_addr;
+ images.rd_end = hdr->ramdisk_addr + hdr->ramdisk_size;
+ free(hdr);
+ do_bootm_linux(0, 0, NULL, &images);
+
+ puts("booti: Control returned to monitor - resetting...\n");
+ do_reset(cmdtp, flag, argc, argv);
+ return 1;
+
+fail:
+ if (need_post_ran && partition_read_post(ptn))
+ printf("post-read commands for partition '%s' failed\n",
+ ptn->name);
+ /* if booti fails, always start fastboot */
+ free(hdr); /* hdr may be NULL, but that's ok. */
+ return do_fastboot(NULL, 0, 0, NULL);
+}
+
+U_BOOT_CMD(
+ booti, 2, 1, do_booti,
+ "boot android bootimg",
+ "[ <addr> | <partition> ]\n - boot application image\n"
+ "\t'addr' should be the address of the boot image which is\n"
+ "\tzImage+ramdisk.img if in memory. 'partition' is the name\n"
+ "\tof the partition to boot from. The default is to boot\n"
+ "\tfrom the 'boot' partition.\n"
+);
+
+static void fbt_request_start_fastboot(void)
+{
+ char buf[512];
+ char *old_preboot = getenv("preboot");
+ printf("old preboot env = %s\n", old_preboot);
+
+ fbt_clear_recovery_flag();
+
+ if (old_preboot) {
+ snprintf(buf, sizeof(buf),
+ "setenv preboot %s; fastboot", old_preboot);
+ setenv("preboot", buf);
+ } else
+ setenv("preboot", "setenv preboot; fastboot");
+
+ printf("%s: setting preboot env to %s\n", __func__, getenv("preboot"));
+}
+
+/*
+ * Determine if we should enter fastboot mode based on board specific
+ * key press or parameter left in memory from previous boot.
+ *
+ * This is also where we initialize fbt private data. Even if we
+ * don't enter fastboot mode, we need our environment setup for
+ * things like unlock state, clearing reboot to recovery flag, etc.
+ */
+void fbt_preboot(void)
+{
+ enum fbt_reboot_type frt;
+
+ /* need to init this ASAP so we know the unlocked state */
+ fbt_fastboot_init();
+
+ if (board_fbt_key_pressed()) {
+ fbt_request_start_fastboot();
+ return;
+ }
+
+ frt = board_fbt_get_reboot_type();
+ if (frt == FASTBOOT_REBOOT_RECOVERY) {
+ printf("\n%s: starting recovery img because of reboot flag\n",
+ __func__);
+
+ return fbt_run_recovery(1);
+ } else if (frt == FASTBOOT_REBOOT_RECOVERY_WIPE_DATA) {
+ printf("\n%s: starting recovery img to wipe data "
+ "because of reboot flag\n",
+ __func__);
+ /* we've not initialized most of our state so don't
+ * save env in this case
+ */
+ return fbt_run_recovery_wipe_data();
+ } else if (frt == FASTBOOT_REBOOT_BOOTLOADER) {
+
+ /* Case: %fastboot reboot-bootloader
+ * Case: %adb reboot bootloader
+ * Case: %adb reboot-bootloader
+ */
+ printf("\n%s: starting fastboot because of reboot flag\n",
+ __func__);
+ fbt_request_start_fastboot();
+ } else if (frt == FASTBOOT_REBOOT_NORMAL) {
+ /* explicit request for a regular reboot */
+ printf("\n%s: request for a normal boot\n",
+ __func__);
+ fbt_clear_recovery_flag();
+ } else {
+ /* unknown reboot cause (typically because of a cold boot).
+ * check if we had flag set to boot recovery and it
+ * was never cleared properly (i.e. recovery didn't finish).
+ * if so, jump to recovery again.
+ */
+ char *run_recovery = getenv(FASTBOOT_RUN_RECOVERY_ENV_NAME);
+ if (run_recovery) {
+ printf("\n%s: starting recovery because of "
+ "saved reboot flag\n", __func__);
+ return fbt_run_recovery(0);
+ }
+ printf("\n%s: no special reboot flags, doing normal boot\n",
+ __func__);
+ }
+}
+
+int fbt_send_info(const char *info)
+{
+ int len;
+ unsigned long space_in_log = CONFIG_FASTBOOT_LOG_SIZE - log_position;
+ unsigned long bytes_to_log;
+
+ len = strlen(info);
+
+ /* check if relocation is done before we can use globals */
+ if (gd->flags & GD_FLG_RELOC) {
+ if (len > space_in_log)
+ bytes_to_log = space_in_log;
+ else
+ bytes_to_log = len;
+
+ if (bytes_to_log) {
+ strncpy(&log_buffer[log_position], info, bytes_to_log);
+ log_position += bytes_to_log;
+ }
+ }
+
+ return fbt_send_raw_info(info, len);
+}
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 04ab0f19b..4d0d75b59 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -462,7 +462,7 @@ static void adjust_size_for_badblocks(loff_t *size, loff_t offset, int dev)
}
}
-static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int i, ret = 0;
ulong addr;
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 5bcc32467..b09dea6dc 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -339,7 +339,7 @@ ulong getenv_hex(const char *varname, ulong default_val)
}
#ifndef CONFIG_SPL_BUILD
-static int do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
if (argc < 2)
return CMD_RET_USAGE;
@@ -684,7 +684,7 @@ ulong getenv_ulong(const char *name, int base, ulong default_val)
#ifndef CONFIG_SPL_BUILD
#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
-static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,
+int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
printf("Saving Environment to %s...\n", env_name_spec);
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index 389c4de59..e3c216891 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -949,7 +949,7 @@ int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
return -EINVAL;
}
} else {
- err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
+ err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW_DETECTION_SW,
mtd->writesize, mtd->oobsize);
}
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index f13b172a6..a9df2193e 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -34,4 +34,14 @@ obj-$(CONFIG_OMAP1610) += omap1510_udc.o
obj-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o
obj-$(CONFIG_CPU_PXA27X) += pxa27x_udc.o
endif
+
+ifdef CONFIG_CMD_FASTBOOT
+obj-y += f_fastboot.o u_fastboot.o
+ifdef CONFIG_FASTBOOT_NAND
+obj-y += u_fastboot_nand.o
+else
+obj-y += u_fastboot_mmc.o
+endif
+endif
+
endif
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
new file mode 100644
index 000000000..fb341d399
--- /dev/null
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -0,0 +1,609 @@
+/*
+ * The file is based on content which was
+ *
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix at windriver.com>
+ *
+ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy at linutronix.de>
+ *
+ * Modified by Vishveshwar Bhat <vishevshwar.bhat@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Some part of this code is based on ideas from Android AOSP project
+ * bootable/bootloader/legacy/
+ * 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
+ * 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 <errno.h>
+#include <usb/fastboot.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/compiler.h>
+
+#include "g_fastboot.h"
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+#define DEVSPEED USB_SPEED_HIGH
+#else
+#define DEVSPEED USB_SPEED_FULL
+#endif
+
+#define CONFIGURATION_NORMAL 1
+#define BULK_ENDPOINT 1
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200)
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040)
+#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
+
+static struct usb_string def_usb_fb_strings[] = {
+ { FB_STR_PRODUCT_IDX, "Default Product" },
+ { FB_STR_SERIAL_IDX, "1234567890" },
+ { FB_STR_CONFIG_IDX, "Android Fastboot" },
+ { FB_STR_INTERFACE_IDX, "Android Fastboot" },
+ { FB_STR_MANUFACTURER_IDX, "Default Manufacturer" },
+ { FB_STR_PROC_REV_IDX, "Default 1.0" },
+ { FB_STR_PROC_TYPE_IDX, "Emulator" },
+ { }
+};
+
+static struct usb_gadget_strings def_fb_strings = {
+ .language = 0x0409, /* en-us */
+ .strings = def_usb_fb_strings,
+};
+
+static struct usb_gadget_strings *vendor_fb_strings;
+
+static unsigned int gadget_is_connected;
+
+static u8 ep0_buffer[512];
+static u8 ep_out_buffer[EP_BUFFER_SIZE];
+static u8 ep_in_buffer[EP_BUFFER_SIZE];
+static int current_config;
+
+/* e1 */
+static struct usb_endpoint_descriptor fs_ep_in = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN, /* IN */
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
+ .bInterval = 0x00,
+};
+
+/* e2 */
+static struct usb_endpoint_descriptor fs_ep_out = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT, /* OUT */
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
+ .bInterval = 0x00,
+};
+
+static struct usb_endpoint_descriptor hs_ep_out = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT, /* OUT */
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
+ .bInterval = 0x00,
+};
+
+const char *fb_find_usb_string(unsigned int id)
+{
+ struct usb_string *s;
+
+ for (s = vendor_fb_strings->strings; s && s->s; s++) {
+ if (s->id == id)
+ break;
+ }
+ if (!s || !s->s) {
+ for (s = def_fb_strings.strings; s && s->s; s++) {
+ if (s->id == id)
+ break;
+ }
+ }
+ if (!s)
+ return NULL;
+ return s->s;
+}
+
+static struct usb_gadget *g;
+static struct usb_request *ep0_req;
+
+struct usb_ep *ep_in;
+struct usb_request *req_in;
+
+struct usb_ep *ep_out;
+struct usb_request *req_out;
+
+static void fastboot_ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ int status = req->status;
+
+ if (!status)
+ return;
+ printf("ep0 status %d\n", status);
+}
+
+static int fastboot_bind(struct usb_gadget *gadget)
+{
+
+ g = gadget;
+ ep0_req = usb_ep_alloc_request(g->ep0, 0);
+ if (!ep0_req)
+ goto err;
+ ep0_req->buf = ep0_buffer;
+ ep0_req->complete = fastboot_ep0_complete;
+
+ ep_in = usb_ep_autoconfig(gadget, &fs_ep_in);
+ if (!ep_in)
+ goto err;
+ ep_in->driver_data = ep_in;
+
+ ep_out = usb_ep_autoconfig(gadget, &fs_ep_out);
+ if (!ep_out)
+ goto err;
+ ep_out->driver_data = ep_out;
+
+ hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+
+ return usb_gadget_connect(gadget);
+err:
+ return -1;
+}
+
+static void fastboot_unbind(struct usb_gadget *gadget)
+{
+ usb_gadget_disconnect(gadget);
+ usb_ep_free_request(g->ep0, ep0_req);
+ ep_in->driver_data = NULL;
+ ep_out->driver_data = NULL;
+}
+
+struct usb_device_descriptor fb_descriptor = {
+ .bLength = sizeof(fb_descriptor),
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = 0x200,
+ .bMaxPacketSize0 = 0x40,
+ .idVendor = FASTBOOT_DEVICE_VENDOR_ID,
+ .idProduct = FASTBOOT_DEVICE_PRODUCT_ID,
+ .bcdDevice = FASTBOOT_DEVICE_BCD,
+ .iManufacturer = FB_STR_MANUFACTURER_IDX,
+ .iProduct = FB_STR_PRODUCT_IDX,
+ .iSerialNumber = FB_STR_SERIAL_IDX,
+ .bNumConfigurations = 1,
+};
+
+#define TOT_CFG_DESC_LEN (USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + \
+ USB_DT_ENDPOINT_SIZE + USB_DT_ENDPOINT_SIZE)
+
+static struct usb_config_descriptor config_desc = {
+ .bLength = USB_DT_CONFIG_SIZE,
+ .bDescriptorType = USB_DT_CONFIG,
+ .wTotalLength = cpu_to_le16(TOT_CFG_DESC_LEN),
+ .bNumInterfaces = 1,
+ .bConfigurationValue = CONFIGURATION_NORMAL,
+ .iConfiguration = FB_STR_CONFIG_IDX,
+ .bmAttributes = 0xc0,
+ .bMaxPower = 0x32,
+};
+
+static struct usb_interface_descriptor interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0x00,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x02,
+ .bInterfaceClass = FASTBOOT_INTERFACE_CLASS,
+ .bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS,
+ .bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL,
+ .iInterface = FB_STR_INTERFACE_IDX,
+};
+
+static struct usb_qualifier_descriptor qual_desc = {
+ .bLength = sizeof(qual_desc),
+ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+ .bcdUSB = 0x200,
+ .bMaxPacketSize0 = 0x40,
+ .bNumConfigurations = 1,
+};
+
+static int fastboot_setup_get_descr(struct usb_gadget *gadget,
+ const struct usb_ctrlrequest *ctrl)
+{
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+ u16 val;
+ int ret;
+ u32 bytes_remaining;
+ u32 bytes_total;
+ u32 this_inc;
+
+ val = w_value >> 8;
+
+ switch (val) {
+ case USB_DT_DEVICE:
+
+ memcpy(ep0_buffer, &fb_descriptor, sizeof(fb_descriptor));
+ ep0_req->length = min(w_length, sizeof(fb_descriptor));
+ ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+ break;
+
+ case USB_DT_CONFIG:
+
+ bytes_remaining = min(w_length, sizeof(ep0_buffer));
+ bytes_total = 0;
+
+ /* config */
+ this_inc = min(bytes_remaining, USB_DT_CONFIG_SIZE);
+ bytes_remaining -= this_inc;
+ memcpy(ep0_buffer + bytes_total, &config_desc, this_inc);
+ bytes_total += this_inc;
+
+ /* interface */
+ this_inc = min(bytes_remaining, USB_DT_INTERFACE_SIZE);
+ bytes_remaining -= this_inc;
+ memcpy(ep0_buffer + bytes_total, &interface_desc, this_inc);
+ bytes_total += this_inc;
+
+ /* ep in */
+ this_inc = min(bytes_remaining, USB_DT_ENDPOINT_SIZE);
+ bytes_remaining -= this_inc;
+ memcpy(ep0_buffer + bytes_total, &fs_ep_in, this_inc);
+ bytes_total += this_inc;
+
+ /* ep out */
+ this_inc = min(bytes_remaining, USB_DT_ENDPOINT_SIZE);
+
+ if (gadget->speed == USB_SPEED_HIGH)
+ memcpy(ep0_buffer + bytes_total, &hs_ep_out,
+ this_inc);
+ else
+ memcpy(ep0_buffer + bytes_total, &fs_ep_out,
+ this_inc);
+ bytes_total += this_inc;
+
+ ep0_req->length = bytes_total;
+ ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+ break;
+
+ case USB_DT_STRING:
+
+ ret = usb_gadget_get_string(vendor_fb_strings,
+ w_value & 0xff, ep0_buffer);
+ if (ret < 0)
+ ret = usb_gadget_get_string(&def_fb_strings,
+ w_value & 0xff, ep0_buffer);
+ if (ret < 0)
+ break;
+
+ ep0_req->length = ret;
+ ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+ break;
+
+ case USB_DT_DEVICE_QUALIFIER:
+
+ memcpy(ep0_buffer, &qual_desc, sizeof(qual_desc));
+ ep0_req->length = min(w_length, sizeof(qual_desc));
+ ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int fastboot_setup_get_conf(struct usb_gadget *gadget,
+ const struct usb_ctrlrequest *ctrl)
+{
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ if (w_length == 0)
+ return -1;
+
+ ep0_buffer[0] = current_config;
+ ep0_req->length = 1;
+ return usb_ep_queue(gadget->ep0, ep0_req, 0);
+}
+
+static void fastboot_complete_in(struct usb_ep *ep, struct usb_request *req)
+{
+ int status = req->status;
+
+ FBTINFO("status: %d ep_in trans: %d\n",
+ status,
+ req->actual);
+}
+
+static int fastboot_disable_ep(struct usb_gadget *gadget)
+{
+ if (req_out) {
+ usb_ep_free_request(ep_out, req_out);
+ req_out = NULL;
+ }
+ if (req_in) {
+ usb_ep_free_request(ep_in, req_in);
+ req_in = NULL;
+ }
+ usb_ep_disable(ep_out);
+ usb_ep_disable(ep_in);
+
+ return 0;
+}
+
+static int fastboot_enable_ep(struct usb_gadget *gadget)
+{
+ int ret;
+
+ /* make sure we don't enable the ep twice */
+ if (gadget->speed == USB_SPEED_HIGH)
+ ret = usb_ep_enable(ep_out, &hs_ep_out);
+ else
+ ret = usb_ep_enable(ep_out, &fs_ep_out);
+ if (ret) {
+ printf("failed to enable out ep\n");
+ goto err;
+ }
+
+ req_out = usb_ep_alloc_request(ep_out, 0);
+ if (!req_out) {
+ printf("failed to alloc out req\n");
+ goto err;
+ }
+
+ ret = usb_ep_enable(ep_in, &fs_ep_in);
+ if (ret) {
+ printf("failed to enable in ep\n");
+ goto err;
+ }
+ req_in = usb_ep_alloc_request(ep_in, 0);
+ if (!req_in) {
+ printf("failed alloc req in\n");
+ goto err;
+ }
+
+ req_out->complete = rx_handler_command;
+ req_out->buf = ep_out_buffer;
+ req_out->length = sizeof(ep_out_buffer);
+
+ req_in->buf = ep_in_buffer;
+ req_in->length = sizeof(ep_in_buffer);
+
+ ret = usb_ep_queue(ep_out, req_out, 0);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ fastboot_disable_ep(gadget);
+ return -1;
+}
+
+static int fastboot_set_interface(struct usb_gadget *gadget, u32 enable)
+{
+ if (enable && req_out)
+ return 0;
+ if (!enable && !req_out)
+ return 0;
+
+ if (enable)
+ return fastboot_enable_ep(gadget);
+ else
+ return fastboot_disable_ep(gadget);
+}
+
+static int fastboot_setup_out_req(struct usb_gadget *gadget,
+ const struct usb_ctrlrequest *req)
+{
+ switch (req->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ switch (req->bRequest) {
+ case USB_REQ_SET_CONFIGURATION:
+
+ ep0_req->length = 0;
+ if (req->wValue == CONFIGURATION_NORMAL) {
+ current_config = CONFIGURATION_NORMAL;
+ fastboot_set_interface(gadget, 1);
+ return usb_ep_queue(gadget->ep0,
+ ep0_req, 0);
+ }
+ if (req->wValue == 0) {
+ current_config = 0;
+ fastboot_set_interface(gadget, 0);
+ return usb_ep_queue(gadget->ep0,
+ ep0_req, 0);
+ }
+ return -1;
+ break;
+ default:
+ return -1;
+ };
+
+ case USB_RECIP_INTERFACE:
+ switch (req->bRequest) {
+ case USB_REQ_SET_INTERFACE:
+
+ ep0_req->length = 0;
+ if (!fastboot_set_interface(gadget, 1))
+ return usb_ep_queue(gadget->ep0,
+ ep0_req, 0);
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ case USB_RECIP_ENDPOINT:
+ switch (req->bRequest) {
+ case USB_REQ_CLEAR_FEATURE:
+
+ return usb_ep_queue(gadget->ep0, ep0_req, 0);
+ break;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+static int fastboot_setup(struct usb_gadget *gadget,
+ const struct usb_ctrlrequest *req)
+{
+ if ((req->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
+ return -1;
+
+ if ((req->bRequestType & USB_DIR_IN) == 0)
+ /* host-to-device */
+ return fastboot_setup_out_req(gadget, req);
+
+ /* device-to-host */
+ if ((req->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+ switch (req->bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ return fastboot_setup_get_descr(gadget, req);
+ break;
+
+ case USB_REQ_GET_CONFIGURATION:
+ return fastboot_setup_get_conf(gadget, req);
+ break;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+static void fastboot_disconnect(struct usb_gadget *gadget)
+{
+ fastboot_disable_ep(gadget);
+ gadget_is_connected = 0;
+}
+
+struct usb_gadget_driver fast_gadget = {
+ .speed = DEVSPEED,
+ .bind = fastboot_bind,
+ .unbind = fastboot_unbind,
+ .setup = fastboot_setup,
+ .disconnect = fastboot_disconnect,
+};
+
+/* FIXME: move this board-specific code somewhere else */
+#define BEAGLEBONEBLACK_U0_LED_GPIO 53
+static void turn_fastboot_led_on(void)
+{
+ printf("olio fastboot enter\n");
+ /*
+ if (!gpio_request(BEAGLEBONEBLACK_U0_LED_GPIO, "fastboot")) {
+ gpio_direction_output(BEAGLEBONEBLACK_U0_LED_GPIO, 0);
+ gpio_set_value(BEAGLEBONEBLACK_U0_LED_GPIO, 1);
+ } else {
+ printf("gpio_request %d failed\n", BEAGLEBONEBLACK_U0_LED_GPIO);
+ }
+ */
+}
+
+static void turn_fastboot_led_off(void)
+{
+ printf("olio fastboot exit\n");
+ //gpio_set_value(BEAGLEBONEBLACK_U0_LED_GPIO, 0);
+}
+
+int fastboot_init(void)
+{
+ int ret;
+
+ printf("func: fastboot_init \n");
+
+ ret = fastboot_board_init(&fastboot_cfg, &vendor_fb_strings);
+ if (ret)
+ return ret;
+ if (!vendor_fb_strings)
+ return -EINVAL;
+
+ set_fb_config(&fastboot_cfg);
+ turn_fastboot_led_on();
+ ret = usb_gadget_register_driver(&fast_gadget);
+ if (ret) {
+ printf("Add gadget failed\n");
+ goto err;
+ }
+
+ gadget_is_connected = 1;
+ usb_gadget_handle_interrupts();
+
+ return 0;
+
+err:
+ fastboot_shutdown();
+ return 1;
+}
+
+int fastboot_poll(void)
+{
+ usb_gadget_handle_interrupts();
+
+ if (gadget_is_connected)
+ return 0;
+ else
+ return 1;
+}
+
+void fastboot_shutdown(void)
+{
+ turn_fastboot_led_off();
+}
+
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
+{
+ int ret = 0;
+
+ if (req_in->complete == NULL)
+ req_in->complete = fastboot_complete_in;
+
+ memcpy(req_in->buf, buffer, buffer_size);
+ req_in->length = buffer_size;
+ ret = usb_ep_queue(ep_in, req_in, 0);
+ if (ret)
+ printf("Error %d on queue\n", ret);
+ return ret;
+}
diff --git a/drivers/usb/gadget/g_fastboot.h b/drivers/usb/gadget/g_fastboot.h
new file mode 100644
index 000000000..e494edf44
--- /dev/null
+++ b/drivers/usb/gadget/g_fastboot.h
@@ -0,0 +1,23 @@
+#ifndef _G_FASTBOOT_H_
+#define _G_FASTBOOT_H_
+
+#define EP_BUFFER_SIZE 4096
+#define FASTBOOT_INTERFACE_CLASS 0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS 0x42
+#define FASTBOOT_INTERFACE_PROTOCOL 0x03
+#define FASTBOOT_VERSION "0.4"
+
+extern struct fastboot_config fastboot_cfg;
+extern struct usb_ep *ep_in;
+extern struct usb_request *req_in;
+extern struct usb_ep *ep_out;
+extern struct usb_request *req_out;
+
+void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size);
+const char *fb_find_usb_string(unsigned int id);
+
+extern int handle_flash(char *part_name, char *response);
+extern int do_format(void);
+
+#endif
diff --git a/drivers/usb/gadget/u_fastboot.c b/drivers/usb/gadget/u_fastboot.c
new file mode 100644
index 000000000..b0b6e0805
--- /dev/null
+++ b/drivers/usb/gadget/u_fastboot.c
@@ -0,0 +1,416 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix at windriver.com>
+ *
+ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy at linutronix.de>
+ *
+ * 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 <common.h>
+#include <command.h>
+#include <usb/fastboot.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include "g_fastboot.h"
+#include <environment.h>
+
+#include <olioh1_reboot.h>
+
+/* The 64 defined bytes plus \0 */
+#define RESPONSE_LEN (64 + 1)
+
+static struct fastboot_config *fb_cfg;
+
+/* To support the Android-style naming of flash */
+#define MAX_PTN 16
+static fastboot_ptentry ptable[MAX_PTN];
+static unsigned int pcount;
+static int static_pcount = -1;
+
+void set_fb_config (struct fastboot_config *cfg)
+{
+ fb_cfg = cfg;
+}
+
+
+/*
+ * Android style flash utilties */
+void fastboot_flash_reset_ptn(void)
+{
+ FBTINFO("fastboot flash reset partition..!!");
+ pcount = 0;
+}
+
+void fastboot_flash_add_ptn(fastboot_ptentry *ptn)
+{
+ if(pcount < MAX_PTN){
+ memcpy(ptable + pcount, ptn, sizeof(*ptn));
+ pcount++;
+ }
+}
+
+void fastboot_flash_dump_ptn(void)
+{
+ unsigned int n;
+ for(n = 0; n < pcount; n++) {
+ fastboot_ptentry *ptn = ptable + n;
+ FBTINFO("ptn %d name='%s' start=%d len=%d\n",
+ n, ptn->name, ptn->start, ptn->length);
+ printf("ptn %d name='%s' start=%d len=%d\n",
+ n, ptn->name, ptn->start, ptn->length);
+ }
+}
+
+fastboot_ptentry *fastboot_flash_find_ptn(const char *name)
+{
+ unsigned int n;
+
+ for(n = 0; n < pcount; n++) {
+ /* Make sure a substring is not accepted */
+ if (strlen(name) == strlen(ptable[n].name))
+ {
+ if(0 == strcmp(ptable[n].name, name))
+ return ptable + n;
+ }
+ }
+ return 0;
+}
+
+static int fastboot_tx_write_str(const char *buffer)
+{
+ return fastboot_tx_write(buffer, strlen(buffer));
+}
+
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+ do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
+{
+ *(unsigned int *)REBOOT_REASON_PA = REBOOT_FLAG_NORMAL;
+ req_in->complete = compl_do_reset;
+ fastboot_tx_write_str("OKAY");
+}
+
+static void cb_reboot_bootloader(struct usb_ep *ep, struct usb_request *req)
+{
+ *(unsigned int *)REBOOT_REASON_PA = REBOOT_FLAG_FASTBOOT;
+ req_in->complete = compl_do_reset;
+ fastboot_tx_write_str("OKAY");
+}
+static int strcmp_l1(const char *s1, const char *s2)
+{
+ return strncmp(s1, s2, strlen(s1));
+}
+
+static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmd = req->buf;
+ char response[RESPONSE_LEN];
+ const char *s;
+
+ strcpy(response, "OKAY");
+ strsep(&cmd, ":");
+ if (!cmd) {
+ fastboot_tx_write_str("FAILmissing var");
+ return;
+ }
+
+ if (!strcmp_l1("version", cmd)) {
+ strncat(response, FASTBOOT_VERSION, sizeof(response));
+
+ } else if (!strcmp_l1("downloadsize", cmd)) {
+ char str_num[12];
+
+ sprintf(str_num, "%08x", fb_cfg->transfer_buffer_size);
+ strncat(response, str_num, sizeof(response));
+
+ } else if (!strcmp_l1("product", cmd)) {
+
+ s = fb_find_usb_string(FB_STR_PRODUCT_IDX);
+ if (s)
+ strncat(response, s, sizeof(response));
+ else
+ strcpy(response, "FAILValue not set");
+
+ } else if (!strcmp_l1("serialno", cmd)) {
+
+ s = fb_find_usb_string(FB_STR_SERIAL_IDX);
+ if (s)
+ strncat(response, s, sizeof(response));
+ else
+ strcpy(response, "FAILValue not set");
+
+ } else if (!strcmp_l1("cpurev", cmd)) {
+
+ s = fb_find_usb_string(FB_STR_PROC_REV_IDX);
+ if (s)
+ strncat(response, s, sizeof(response));
+ else
+ strcpy(response, "FAILValue not set");
+ } else if (!strcmp_l1("secure", cmd)) {
+
+ s = fb_find_usb_string(FB_STR_PROC_TYPE_IDX);
+ if (s)
+ strncat(response, s, sizeof(response));
+ else
+ strcpy(response, "FAILValue not set");
+ } else {
+ strcpy(response, "FAILVariable not implemented");
+ }
+ fastboot_tx_write_str(response);
+}
+
+static unsigned int rx_bytes_expected(void)
+{
+ int rx_remain = fb_cfg->download_size - fb_cfg->download_bytes;
+ if (rx_remain < 0)
+ return 0;
+ if (rx_remain > EP_BUFFER_SIZE)
+ return EP_BUFFER_SIZE;
+ return rx_remain;
+}
+
+#define BYTES_PER_DOT 1048576
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
+{
+ char response[RESPONSE_LEN];
+ unsigned int transfer_size = fb_cfg->download_size - fb_cfg->download_bytes;
+ const unsigned char *buffer = req->buf;
+ unsigned int buffer_size = req->actual;
+ int dnl_complete = 0;
+
+ if (req->status != 0) {
+ printf("Bad status: %d\n", req->status);
+ return;
+ }
+
+ if (buffer_size < transfer_size)
+ transfer_size = buffer_size;
+
+ memcpy(fb_cfg->transfer_buffer + fb_cfg->download_bytes,
+ buffer, transfer_size);
+
+ fb_cfg->download_bytes += transfer_size;
+
+ /* Check if transfer is done */
+ if (fb_cfg->download_bytes >= fb_cfg->download_size) {
+ /*
+ * Reset global transfer variable, keep fb_cfg->download_bytes because
+ * it will be used in the next possible flashing command
+ */
+ fb_cfg->download_size = 0;
+ req->complete = rx_handler_command;
+ req->length = EP_BUFFER_SIZE;
+ dnl_complete = 1;
+ printf("\ndownloading of %d bytes finished\n",
+ fb_cfg->download_bytes);
+ } else
+ req->length = rx_bytes_expected();
+
+ if (fb_cfg->download_bytes && !(fb_cfg->download_bytes % BYTES_PER_DOT)) {
+ printf(".");
+ if (!(fb_cfg->download_bytes % (74 * BYTES_PER_DOT)))
+ printf("\n");
+
+ }
+ if (dnl_complete)
+ {
+ fastboot_tx_write_str("OKAY");
+ }
+ req->actual = 0;
+ usb_ep_queue(ep, req, 0);
+}
+
+static void cb_download(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmd = req->buf;
+ char response[RESPONSE_LEN];
+
+ strsep(&cmd, ":");
+ fb_cfg->download_size = simple_strtoul(cmd, NULL, 16);
+ fb_cfg->download_bytes = 0;
+
+ printf("Starting download of %d bytes\n",
+ fb_cfg->download_size);
+
+ if (0 == fb_cfg->download_size) {
+ sprintf(response, "FAILdata invalid size");
+ } else if (fb_cfg->download_size >
+ fb_cfg->transfer_buffer_size) {
+ fb_cfg->download_size = 0;
+ sprintf(response, "FAILdata too large");
+ } else {
+ sprintf(response, "DATA%08x", fb_cfg->download_size);
+ req->complete = rx_handler_dl_image;
+ req->length = rx_bytes_expected();
+ }
+ fastboot_tx_write_str(response);
+}
+
+static char boot_addr_start[32];
+static char *bootm_args[] = { "bootm", boot_addr_start, NULL };
+
+static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ req->complete = NULL;
+ fastboot_shutdown();
+ printf("Booting kernel..\n");
+
+ do_bootm(NULL, 0, 2, bootm_args);
+
+ /* This only happens if image is somehow faulty so we start over */
+ do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_boot(struct usb_ep *ep, struct usb_request *req)
+{
+ sprintf(boot_addr_start, "0x%p", fb_cfg->transfer_buffer);
+
+ req_in->complete = do_bootm_on_complete;
+ fastboot_tx_write_str("OKAY");
+ return;
+}
+
+
+int fastboot_oem(const char *cmd)
+{
+ printf("fastboot_oem:%s", cmd);
+ if (!strcmp(cmd, "format"))
+ return do_format();
+ return -1;
+}
+
+
+static void cb_oem(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmd = req->buf;
+
+ printf ("calling fastboot oem!! : %s\n", cmd);
+ int r = fastboot_oem(cmd + 4);
+ if (r < 0) {
+ fastboot_tx_write_str("FAIL");
+ } else {
+ fastboot_tx_write_str("OKAY");
+ }
+}
+
+static void cb_flash(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmdbuf = req->buf;
+ char response[32];
+ char part_name[20]={0,};
+ strncpy (part_name, cmdbuf + 6, req->actual - 6);
+ handle_flash(part_name, response);
+ fastboot_tx_write_str(response);
+}
+struct cmd_dispatch_info {
+ char *cmd;
+ void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+
+static struct cmd_dispatch_info cmd_dispatch_info[] = {
+ {
+ .cmd = "reboot-bootloader",
+ .cb = cb_reboot_bootloader,
+ }, {
+ .cmd = "reboot",
+ .cb = cb_reboot,
+ }, {
+ .cmd = "getvar:",
+ .cb = cb_getvar,
+ }, {
+ .cmd = "download:",
+ .cb = cb_download,
+ }, {
+ .cmd = "boot",
+ .cb = cb_boot,
+ }, {
+ .cmd = "oem",
+ .cb = cb_oem,
+ },{
+ .cmd = "flash:",
+ .cb = cb_flash,
+ },
+};
+
+void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
+{
+ char response[RESPONSE_LEN];
+ char *cmdbuf = req->buf;
+ void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
+ int i;
+ sprintf(response, "FAIL");
+
+ *(cmdbuf + req->actual) = '\0';
+ FBTINFO ("Recieved command : %s : req len : %d \n", cmdbuf, req->actual);
+
+ for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
+ if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
+ func_cb = cmd_dispatch_info[i].cb;
+ break;
+ }
+ }
+
+ if (!func_cb)
+ fastboot_tx_write_str("FAILunknown command");
+ else
+ func_cb(ep, req);
+
+ if (req->status == 0) {
+ *cmdbuf = '\0';
+ req->actual = 0;
+ usb_ep_queue(ep, req, 0);
+ }
+}
diff --git a/drivers/usb/gadget/u_fastboot_mmc.c b/drivers/usb/gadget/u_fastboot_mmc.c
new file mode 100644
index 000000000..2ed64efcc
--- /dev/null
+++ b/drivers/usb/gadget/u_fastboot_mmc.c
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * Author : Pankaj Bharadiya <pankaj.bharadiya@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Fastboot is implemented using gadget stack, many of the ideas are
+ * derived from fastboot implemented in OmapZoom by
+ * Tom Rix <Tom.Rix@windriver.com> and Sitara 2011 u-boot by
+ * Mohammed Afzal M A <afzal@ti.com>
+ *
+ * Part of OmapZoom was copied from Android project, Android source
+ * (legacy bootloader) was used indirectly here by using OmapZoom.
+ *
+ * This is Android's 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 <common.h>
+#include <command.h>
+#include <usb/fastboot.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include "g_fastboot.h"
+#include <environment.h>
+#include <mmc.h>
+#include <sparse_format.h>
+
+#define EFI_VERSION 0x00010000
+#define EFI_ENTRIES 128
+#define EFI_NAMELEN 36
+
+struct partition {
+ const char *name;
+ unsigned size_kb;
+};
+
+/* eMMC partition layout (All sizes are in kB)
+ * Modify the below partition table to change the GPT configuration.
+ * The entry for each partition can be modified as per the requirement.
+ */
+static struct partition partitions[] = {
+ { "-", 128 }, /* Master Boot Record and GUID Partition Table */
+ { "spl", 128 }, /* First stage bootloader */
+ { "bootloader", 512 }, /* Second stage bootloader */
+ { "misc", 128 }, /* Rserved for internal purpose */
+ { "-", 128 }, /* Reserved */
+ { "recovery", 8*1024 }, /* Recovery partition */
+ { "boot", 8*1024 }, /* Partition contains kernel + ramdisk images */
+ { "system", 512*1024 }, /* Android file system */
+ { "cache", 256*1024 }, /* Store Application Cache */
+ { "userdata", 1047*1024 }, /* User data */
+ { "media", 0 }, /* Media files */
+ { 0, 0 },
+};
+
+
+static const u8 partition_type[16] = {
+ 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
+ 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7,
+};
+
+static const u8 random_uuid[16] = {
+ 0xff, 0x1f, 0xf2, 0xf9, 0xd4, 0xa8, 0x0e, 0x5f,
+ 0x97, 0x46, 0x59, 0x48, 0x69, 0xae, 0xc3, 0x4e,
+};
+
+struct efi_entry {
+ u8 type_uuid[16];
+ u8 uniq_uuid[16];
+ u64 first_lba;
+ u64 last_lba;
+ u64 attr;
+ u16 name[EFI_NAMELEN];
+};
+
+struct efi_header {
+ u8 magic[8];
+
+ u32 version;
+ u32 header_sz;
+
+ u32 crc32;
+ u32 reserved;
+
+ u64 header_lba;
+ u64 backup_lba;
+ u64 first_lba;
+ u64 last_lba;
+
+ u8 volume_uuid[16];
+
+ u64 entries_lba;
+
+ u32 entries_count;
+ u32 entries_size;
+ u32 entries_crc32;
+} __attribute__((packed));
+
+struct ptable {
+ u8 mbr[512];
+ union {
+ struct efi_header header;
+ u8 block[512];
+ };
+ struct efi_entry entry[EFI_ENTRIES];
+};
+
+static void init_mbr(u8 *mbr, u32 blocks)
+{
+ mbr[0x1be] = 0x00; /* nonbootable */
+ mbr[0x1bf] = 0xFF; /* bogus CHS */
+ mbr[0x1c0] = 0xFF;
+ mbr[0x1c1] = 0xFF;
+
+ mbr[0x1c2] = 0xEE; /* GPT partition */
+ mbr[0x1c3] = 0xFF; /* bogus CHS */
+ mbr[0x1c4] = 0xFF;
+ mbr[0x1c5] = 0xFF;
+
+ mbr[0x1c6] = 0x01; /* start */
+ mbr[0x1c7] = 0x00;
+ mbr[0x1c8] = 0x00;
+ mbr[0x1c9] = 0x00;
+
+ memcpy(mbr + 0x1ca, &blocks, sizeof(u32));
+
+ mbr[0x1fe] = 0x55;
+ mbr[0x1ff] = 0xaa;
+}
+
+static void start_ptbl(struct ptable *ptbl, unsigned blocks)
+{
+ struct efi_header *hdr = &ptbl->header;
+
+ memset(ptbl, 0, sizeof(*ptbl));
+
+ init_mbr(ptbl->mbr, blocks - 1);
+
+ memcpy(hdr->magic, "EFI PART", 8);
+ hdr->version = EFI_VERSION;
+ hdr->header_sz = sizeof(struct efi_header);
+ hdr->header_lba = 1;
+ hdr->backup_lba = blocks - 1;
+ hdr->first_lba = 34;
+ hdr->last_lba = blocks - 1;
+ memcpy(hdr->volume_uuid, random_uuid, 16);
+ hdr->entries_lba = 2;
+ hdr->entries_count = EFI_ENTRIES;
+ hdr->entries_size = sizeof(struct efi_entry);
+}
+
+static void end_ptbl(struct ptable *ptbl)
+{
+ struct efi_header *hdr = &ptbl->header;
+ u32 n;
+
+ n = crc32(0, 0, 0);
+ n = crc32(n, (void *) ptbl->entry, sizeof(ptbl->entry));
+ hdr->entries_crc32 = n;
+
+ n = crc32(0, 0, 0);
+ n = crc32(0, (void *) &ptbl->header, sizeof(ptbl->header));
+ hdr->crc32 = n;
+}
+
+int add_ptn(struct ptable *ptbl, u64 first, u64 last, const char *name)
+{
+ struct efi_header *hdr = &ptbl->header;
+ struct efi_entry *entry = ptbl->entry;
+ unsigned n;
+
+ if (first < 34) {
+ printf("partition '%s' overlaps partition table\n", name);
+ return -1;
+ }
+
+ if (last > hdr->last_lba) {
+ printf("partition '%s' does not fit\n", name);
+ return -1;
+ }
+ for (n = 0; n < EFI_ENTRIES; n++, entry++) {
+ if (entry->last_lba)
+ continue;
+ memcpy(entry->type_uuid, partition_type, 16);
+ memcpy(entry->uniq_uuid, random_uuid, 16);
+ entry->uniq_uuid[0] = n;
+ entry->first_lba = first;
+ entry->last_lba = last;
+ for (n = 0; (n < EFI_NAMELEN) && *name; n++)
+ entry->name[n] = *name++;
+ return 0;
+ }
+ printf("out of partition table entries\n");
+ return -1;
+}
+
+void import_efi_partition(struct efi_entry *entry)
+{
+ struct fastboot_ptentry e;
+ int n;
+ if (memcmp(entry->type_uuid, partition_type, sizeof(partition_type)))
+ return;
+ for (n = 0; n < (sizeof(e.name)-1); n++)
+ e.name[n] = entry->name[n];
+ e.name[n] = 0;
+ e.start = entry->first_lba;
+ e.length = (entry->last_lba - entry->first_lba + 1) * 512;
+ e.flags = 0;
+
+ if (!strcmp(e.name, "environment"))
+ e.flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_ENV;
+ fastboot_flash_add_ptn(&e);
+
+ if (e.length > 0x100000)
+ printf("%8d %7dM %s\n", e.start, e.length/0x100000, e.name);
+ else
+ printf("%8d %7dK %s\n", e.start, e.length/0x400, e.name);
+}
+
+static int load_ptbl(void)
+{
+ static unsigned char data[512];
+ static struct efi_entry entry[4];
+ int n, m;
+ char source[32], dest[32], length[32];
+
+ char *mmc_read[5] = {"mmc", "read", NULL, NULL, NULL};
+
+ /* read mbr */
+ mmc_read[2] = source;
+ mmc_read[3] = dest;
+ mmc_read[4] = length;
+
+ sprintf(source, "0x%x", data);
+ sprintf(dest, "0x%x", 0x1);
+ sprintf(length, "0x%x", 1);
+
+ if (do_mmcops(NULL, 0, 5, mmc_read)) {
+ printf("Reading boot magic FAILED!\n");
+ return -1;
+ }
+
+ if (memcmp(data, "EFI PART", 8)) {
+ printf("efi partition table not found\n");
+ return -1;
+ }
+ for (n = 0; n < (128/4); n++) {
+
+ /* read partition */
+ source[0] = '\0';
+ dest[0] = '\0';
+ length[0] = '\0';
+ mmc_read[2] = source;
+ mmc_read[3] = dest;
+ mmc_read[4] = length;
+
+ sprintf(source, "0x%x", entry);
+ sprintf(dest, "0x%x", 0x1+n);
+ sprintf(length, "0x%x", 1);
+
+ if (do_mmcops(NULL, 0, 5, mmc_read)) {
+ printf("Reading boot magic FAILED!\n");
+ return -1;
+ }
+ for (m = 0; m < 4; m++)
+ import_efi_partition(entry + m);
+ }
+ return 0;
+}
+
+
+static struct ptable the_ptable;
+
+int do_format(void)
+{
+ struct ptable *ptbl = &the_ptable;
+ unsigned sector_sz, blocks;
+ unsigned next;
+ int n;
+
+ printf("\ndo_format ..!!");
+ /* get mmc info */
+ struct mmc *mmc = find_mmc_device(CONFIG_MMC_FASTBOOT_DEV);
+ if (mmc == 0) {
+ printf("no mmc device at slot %d", CONFIG_MMC_FASTBOOT_DEV);
+ return -1;
+ }
+
+ mmc->has_init = 0;
+ if (mmc_init(mmc)) {
+
+ printf("\n mmc init FAILED");
+ return -1;
+ } else{
+ printf("\nmmc capacity is:0x%x", mmc->capacity);
+ printf("\nmmc: number of blocks:0x%x", mmc->block_dev.lba);
+ printf("\nmmc: block size:0x%x", mmc->block_dev.blksz);
+ }
+
+ blocks = mmc->block_dev.lba;
+ sector_sz = mmc->block_dev.blksz;
+
+ start_ptbl(ptbl, blocks);
+ n = 0;
+ next = 0;
+ for (n = 0, next = 0; partitions[n].name; n++) {
+ /* 10/11 : below line change size from KB to no of blocks */
+ unsigned sz = partitions[n].size_kb*2 ;
+ if (!strcmp(partitions[n].name, "-")) {
+ next += sz;
+ continue;
+ }
+ if (sz == 0)
+ sz = blocks - next;
+ if (add_ptn(ptbl, next, next + sz - 1, partitions[n].name))
+ return -1;
+ next += sz;
+ }
+ end_ptbl(ptbl);
+
+ fastboot_flash_reset_ptn();
+
+ /* 10/11:modified as per PSP release support */
+ char *mmc_write[5] = {"mmc", "write", NULL, NULL, NULL};
+ char source[32], dest[32], length[32];
+
+ char dev[2];
+ char *mmc_dev[3] = {"mmc", "dev", NULL};
+
+ mmc_dev[2] = dev;
+ sprintf(dev,"0x%x", CONFIG_MMC_FASTBOOT_DEV);
+
+ if (do_mmcops(NULL, 0, 3, mmc_dev)) {
+ printf("MMC DEV: %d selection FAILED!\n", CONFIG_MMC_FASTBOOT_DEV);
+ return -1;
+ }
+
+ mmc_write[2] = source;
+ mmc_write[3] = dest;
+ mmc_write[4] = length;
+
+ sprintf(source, "0x%x", (void *)ptbl);
+ sprintf(dest, "0x%x", 0x00);
+ sprintf(length, "0x%x", (sizeof(struct ptable)/512)+1);
+
+ if (do_mmcops(NULL, 0, 5, mmc_write)) {
+ printf("Writing mbr is FAILED!\n");
+ return -1;
+ } else {
+ printf("Writing mbr is DONE!\n");
+ }
+
+ printf("\nnew partition table:\n");
+ load_ptbl();
+
+ return 0;
+}
+
+struct fastboot_config fastboot_cfg;
+
+extern env_t *env_ptr;
+//extern int do_env_save (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+
+static int write_mmc_chunk(unsigned int source, unsigned int dest_sector, unsigned int num_sectors)
+{
+ char s_source[32], s_dest[32], s_length[32];
+ char *mmc_write[5] = {"mmc", "write", NULL, NULL, NULL};
+ char dev[12];
+ char *mmc_dev[3] = {"mmc", "dev", NULL};
+
+ sprintf(s_source, "0x%x", source);
+ sprintf(s_dest, "0x%x", dest_sector);
+ sprintf(s_length, "0x%x", num_sectors);
+ mmc_write[2] = s_source;
+ mmc_write[3] = s_dest;
+ mmc_write[4] = s_length;
+ sprintf(dev,"0x%x", CONFIG_MMC_FASTBOOT_DEV);
+ mmc_dev[2] = dev;
+
+// printf("%s %s %s\n", s_source, s_dest, s_length);
+ if (do_mmcops(NULL, 0, 5, mmc_write)) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+static int flash_mmc_sparse_img(unsigned int ptn_start_sector)
+{
+ void *data;
+ unsigned int chunk;
+ unsigned int chunk_data_sz;
+ sparse_header_t *sparse_header;
+ chunk_header_t *chunk_header;
+ uint32_t total_blocks = 0;
+ uint32_t sectors_per_block;
+
+ data = fastboot_cfg.transfer_buffer;
+ sparse_header = (sparse_header_t *)data;
+#ifdef DEBUG_SPARSE
+ printf("=== Sparse Image Header ===\n");
+ printf("magic: 0x%x\n", sparse_header->magic);
+ printf("major_version: 0x%x\n", sparse_header->major_version);
+ printf("minor_version: 0x%x\n", sparse_header->minor_version);
+ printf("file_hdr_sz: %u\n", sparse_header->file_hdr_sz);
+ printf("chunk_hdr_sz: %u\n", sparse_header->chunk_hdr_sz);
+ printf("blk_sz: %u\n", sparse_header->blk_sz);
+ printf("total_blks: %u\n", sparse_header->total_blks);
+ printf("total_chunks: %u\n", sparse_header->total_chunks);
+#endif
+ data += sparse_header->file_hdr_sz;
+
+ sectors_per_block = sparse_header->blk_sz/512;
+
+ for (chunk = 0; chunk < sparse_header->total_chunks; chunk++) {
+ /* Read and skip over chunk header */
+ chunk_header = (chunk_header_t *)data;
+ data += sizeof(chunk_header_t);
+#ifdef DEBUG_SPARSE
+ printf("=== Chunk Header ===\n");
+ printf("chunk_type: 0x%x\n", chunk_header->chunk_type);
+ printf("chunk_data_sz: 0x%x\n", chunk_header->chunk_sz);
+ printf("total_size: 0x%x\n", chunk_header->total_sz);
+#endif
+ chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz;
+ switch (chunk_header->chunk_type) {
+ case CHUNK_TYPE_RAW:
+ if (write_mmc_chunk((unsigned int)data,
+ ptn_start_sector + (total_blocks * sectors_per_block),
+ chunk_header->chunk_sz * sectors_per_block) != 0) {
+ return -1;
+ }
+ data += chunk_data_sz;
+ break;
+ case CHUNK_TYPE_DONT_CARE:
+ break;
+ case CHUNK_TYPE_CRC32:
+ break;
+ default:
+ printf("Unknown chunk type\n");
+ return -1;
+ }
+ total_blocks += chunk_header->chunk_sz;
+ }
+ return 0;
+}
+
+int handle_flash(char *part_name, char *response)
+{
+ int status = 0;
+
+ if (fastboot_cfg.download_bytes) {
+ struct fastboot_ptentry *ptn;
+
+ /* Next is the partition name */
+ ptn = fastboot_flash_find_ptn(part_name);
+
+ if (ptn == 0) {
+ printf("Partition:[%s] does not exist\n", part_name);
+ sprintf(response, "FAILpartition does not exist");
+ } else if ((fastboot_cfg.download_bytes > ptn->length) &&
+ !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
+ printf("Image too large for the partition\n");
+ sprintf(response, "FAILimage too large for partition");
+ } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
+ /* 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)
+ */
+ for (i = 0; i < fastboot_cfg.download_bytes; i++) {
+ if (fastboot_cfg.transfer_buffer[i] == 0x0a)
+ fastboot_cfg.transfer_buffer[i] = 0x00;
+ }
+ memset(env_ptr->data, 0, ENV_SIZE);
+ memcpy(env_ptr->data, fastboot_cfg.transfer_buffer, fastboot_cfg.download_bytes);
+ //do_env_save(NULL, 0, 1, NULL);
+ printf("saveenv to '%s' DONE!\n", ptn->name);
+ sprintf(response, "OKAY");
+ } else {
+ /* Normal case */
+ sparse_header_t *sparse_header;
+ char source[32], dest[32], length[32];
+ source[0] = '\0';
+ dest[0] = '\0';
+ length[0] = '\0';
+
+ char *mmc_write[5] = {"mmc", "write", NULL, NULL, NULL};
+ char *mmc_init[2] = {"mmc", "rescan",};
+ char dev[12];
+ char *mmc_dev[3] = {"mmc", "dev", NULL};
+
+ mmc_dev[2] = dev;
+ sprintf(dev,"0x%x", CONFIG_MMC_FASTBOOT_DEV);
+
+ if (do_mmcops(NULL, 0, 3, mmc_dev)) {
+ printf("MMC DEV: %d selection FAILED!\n", CONFIG_MMC_FASTBOOT_DEV);
+ return -1;
+ }
+
+ printf("Initializing '%s'\n", ptn->name);
+ if (do_mmcops(NULL, 0, 2, mmc_init))
+ sprintf(response, "FAIL:Init of MMC card");
+ else
+ sprintf(response, "OKAY");
+
+ sparse_header = (sparse_header_t *)fastboot_cfg.transfer_buffer;
+ if (sparse_header->magic == SPARSE_HEADER_MAGIC) {
+ printf("Image is sparse format\n");
+ if (flash_mmc_sparse_img(ptn->start) == 0) {
+ sprintf(response, "OKAY");
+ printf("Writing '%s' DONE!\n", ptn->name);
+ } else {
+ sprintf(response, "FAIL: Write partition");
+ printf("Writing '%s' FAILED!\n", ptn->name);
+ }
+ return 0;
+ }
+
+ mmc_write[2] = source;
+ mmc_write[3] = dest;
+ mmc_write[4] = length;
+
+ sprintf(source, "0x%x", fastboot_cfg.transfer_buffer);
+ sprintf(dest, "0x%x", ptn->start);
+ sprintf(length, "0x%x", (fastboot_cfg.download_bytes/512)+1);
+
+ printf("Writing '%s'\n", ptn->name);
+ 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");
+ }
+ return 0;
+}
+
+int board_mmc_fbtptn_init(void)
+{
+ char *mmc_init[2] = {"mmc", "rescan",};
+ char dev[2];
+ char *mmc_dev[3] = {"mmc", "dev", NULL};
+
+ mmc_dev[2] = dev;
+ sprintf(dev,"0x%x", CONFIG_MMC_FASTBOOT_DEV);
+
+ if (do_mmcops(NULL, 0, 3, mmc_dev)) {
+ printf("MMC DEV: %d selection FAILED!\n", CONFIG_MMC_FASTBOOT_DEV);
+ return -1;
+ }
+
+ if (do_mmcops(NULL, 0, 2, mmc_init)) {
+ printf("FAIL:Init of MMC card\n");
+ return 1;
+ }
+
+ printf("Loading efi partition table:\n");
+ return load_ptbl();
+}
+
diff --git a/drivers/usb/gadget/u_fastboot_nand.c b/drivers/usb/gadget/u_fastboot_nand.c
new file mode 100644
index 000000000..29da46dd0
--- /dev/null
+++ b/drivers/usb/gadget/u_fastboot_nand.c
@@ -0,0 +1,838 @@
+/*
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * Author : Pankaj Bharadiya <pankaj.bharadiya@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Fastboot is implemented using gadget stack, many of the ideas are
+ * derived from fastboot implemented in OmapZoom by
+ * Tom Rix <Tom.Rix@windriver.com> and Sitara 2011 u-boot by
+ * Mohammed Afzal M A <afzal@ti.com>
+ *
+ * Part of OmapZoom was copied from Android project, Android source
+ * (legacy bootloader) was used indirectly here by using OmapZoom.
+ *
+ * This is Android's 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 <common.h>
+#include <command.h>
+#include <usb/fastboot.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include "g_fastboot.h"
+
+#include <nand.h>
+#include <environment.h>
+
+#define MAX_PTN 11
+
+/* Initialize the name of fastboot flash name mappings */
+fastboot_ptentry omap3h1_nand_ptn[MAX_PTN] = {
+ {
+ .name = "X-Loader",
+ .start = 0x0000000,
+ .length = 0x0020000, /* 256 K */
+ /* Written into the first 0x40000 blocks
+ Use HW ECC */
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC
+ /* FASTBOOT_PTENTRY_FLAGS_REPEAT_4, */
+ },
+ {
+ .name = "uboot",
+ .start = 0x0080000,
+ .length = 0x01E0000, /* 1.875 M */
+ /* Skip bad blocks on write
+ Use HW ECC */
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC,
+ },
+ {
+ .name = "U-Boot Env",
+ .start = NAND_ENV_OFFSET, /* set in config file */
+ .length = 0x0020000,
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_ENV |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC,
+ },
+ {
+ .name = "kernel",
+ .start = 0x0280000,
+ .length = 0x0500000, /* 5 M */
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC,
+ },
+ {
+ .name = "initramfs",
+ .start = 0x0780000,
+ .length = 0x0A00000, /* 10 M */
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC,
+ },
+ {
+ .name = "devicetree",
+ .start = 0x1180000,
+ .length = 0x020000, /* 128k */
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC,
+ },
+ {
+ .name = "ramdisk",
+ .start = 0x1180000,
+ .length = 0x0C80000, /* 13 M */
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC,
+ },
+ {
+ .name = "system",
+ .start = 0x1E80000,
+ .length = 0x800 * 0x20000, /* >256 M */
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC,
+ },
+ {
+ .name = "cache",
+ .start = 0x11E80000,
+ .length = 0x400 * 0x20000, /* ~50Mb */
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC,
+ },
+ {
+ .name = "recovery",
+ .start = 0x14A80000,
+ .length = 0x200 * 0x20000, /* ~26Mb */
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC,
+ },
+ {
+ .name = "userdata",
+ .start = 0x2f80000,
+ .length = 0x28CC0000, /* ~660 Mb */
+ .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I |
+ FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC,
+ },
+};
+
+
+struct fastboot_config fastboot_cfg;
+
+extern int do_env_save (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+extern int do_switch_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]);
+
+static void set_env(char *var, char *val)
+{
+ char *setenv[4] = { "setenv", NULL, NULL, NULL, };
+
+ setenv[1] = var;
+ setenv[2] = val;
+
+ do_env_set(NULL, 0, 3, setenv);
+}
+
+static void set_ecc(int hw)
+{
+ char ecc_type[2];
+ char ecc_provider[3]; /* make sure there's space */
+ char *ecc[4] = { "nandecc", "hw", "0" , NULL };
+
+ ecc[2] = ecc_type;
+ ecc[1] = ecc_provider;
+
+ if (hw)
+ {
+ /*for hardware ecc : set BCH8*/
+ sprintf(ecc_provider, "hw");
+ }
+ else
+ {
+ sprintf(ecc_provider, "sw");
+ }
+
+/* OLIO: HW = 1bit ECC, SW = BCH8 */
+
+ do_switch_ecc(NULL, 0, 2, ecc);
+}
+
+static void save_env(struct fastboot_ptentry *ptn,
+ char *var, char *val)
+{
+ char *saveenv[2] = { "setenv", NULL, };
+ set_env (var, val);
+
+ if ((ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) &&
+ (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)) {
+ /* Both can not be true */
+ FBTWARN("can not do hw and sw ecc for partition '%s'\n", ptn->name);
+ FBTWARN("Ignoring these flags\n");
+#ifdef OLIO_INVALID
+ } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) {
+ setecc(1);
+
+ } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
+ set_ecc(0);
+#endif /* OLIO_INVALID */
+ }
+
+ /* OLIO: env always saved with SW */
+
+ set_ecc(0);
+ do_env_save(NULL, 0, 1, saveenv);
+}
+
+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 *setenv[4] = { "setenv", NULL, NULL, NULL, };
+ char *saveenv[2] = { "setenv", NULL, };
+
+ setenv[1] = var;
+ setenv[2] = val;
+
+ FBTINFO ("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_env_set (NULL, 0, 3, setenv);
+
+ sprintf (var, "%s_nand_size", ptn->name);
+ sprintf (val, "");
+ do_env_set (NULL, 0, 3, setenv);
+ } else {
+ /* Normal case */
+
+ sprintf (var, "%s_nand_offset", ptn->name);
+ sprintf (val, "0x%x", offset);
+
+ FBTINFO("%s %s %s\n", setenv[0], setenv[1], setenv[2]);
+
+ do_env_set (NULL, 0, 3, setenv);
+
+ sprintf(var, "%s_nand_size", ptn->name);
+
+ sprintf (val, "0x%x", size);
+
+ FBTINFO("%s %s %s\n", setenv[0], setenv[1], setenv[2]);
+
+ do_env_set (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 */
+ if ((env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) &&
+ (env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC))
+ {
+ /* Both can not be true */
+ FBTWARN("can not do hw and sw ecc for partition '%s'\n", ptn->name);
+ FBTWARN("Ignoring these flags\n");
+ }
+ else if (env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC)
+ {
+ set_ecc(1);
+ }
+ else if (env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)
+ {
+ set_ecc(0);
+ }
+
+ sprintf (start, "0x%x", env_ptn->start);
+ sprintf (length, "0x%x", env_ptn->length);
+
+ }
+
+ do_env_save (NULL, 0, 1, saveenv);
+}
+
+/* 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 *)fastboot_cfg.transfer_buffer;
+ unsigned int size = fastboot_cfg.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);
+
+ FBTDBG("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");
+
+ FBTDBG("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);
+
+ FBTDBG("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 (var_end)
+ FBTDBG("Trailing Setting %s %s\n", var, val);
+ else
+ FBTDBG("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)
+{
+ if (((ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC) ||
+ (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC)) &&
+ (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)) {
+ /* Both can not be true */
+ FBTERR("can not do hw and sw ecc for partition '%s'\n",
+ ptn->name);
+ FBTERR("Ignoring these flags\n");
+ } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC) {
+ set_ecc(1);
+ } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) {
+ set_ecc(1);
+ } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
+ set_ecc(0);
+ }
+}
+
+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 *write[6] = { "nand", "write", NULL, NULL, NULL, NULL, };
+ char *erase[5] = { "nand", "erase", NULL, NULL, NULL, };
+
+ erase[2] = start;
+ erase[3] = length;
+
+ write[1] = write_type;
+ write[2] = addr;
+ write[3] = wstart;
+ write[4] = wlength;
+
+ FBTINFO("flashing '%s'\n", ptn->name);
+
+ /* Which flavor of write to use */
+ if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_I)
+ sprintf(write_type, "write.i");
+ else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_JFFS2)
+ sprintf(write_type, "write.jffs2");
+ else
+ sprintf(write_type, "write");
+
+ /* Some flashing requires writing the same data in multiple,
+ consecutive flash partitions */
+ repeat_max = 1;
+ if (FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK(ptn->flags)) {
+ if (ptn->flags &
+ FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) {
+ FBTWARN("can not do both 'contiguous block' and 'repeat' writes for for partition '%s'\n", ptn->name);
+ FBTWARN("Ignoring repeat flag\n");
+ } else {
+ repeat_max = (FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK(ptn->flags));
+ }
+ }
+
+ sprintf(length, "0x%x", ptn->length);
+
+ for (repeat = 0; repeat < repeat_max; repeat++) {
+
+ set_ptn_ecc(ptn);
+ sprintf(start, "0x%x", ptn->start + (repeat * ptn->length));
+
+ 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 */
+ FBTWARN("can not do 'next good block' and 'contiguous block' for partition '%s'\n", ptn->name);
+ FBTWARN("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 (fastboot_cfg.nand_block_size) {
+ unsigned int blocks = fastboot_cfg.download_bytes /
+ fastboot_cfg.nand_block_size;
+ unsigned int i = 0;
+ unsigned int offset = 0;
+
+ sprintf(wlength, "0x%x",
+ fastboot_cfg.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%x",
+ fastboot_cfg.transfer_buffer +
+ (i * fastboot_cfg.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 += fastboot_cfg.nand_block_size;
+ }
+ } else {
+ FBTWARN("nand block size can not be 0 when using 'next good block' for partition '%s'\n", ptn->name);
+ FBTWARN("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 (fastboot_cfg.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];
+
+ FBTINFO("\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) >=
+ fastboot_cfg.download_bytes)
+ break;
+ }
+
+ /* Check if there is enough space */
+ if (ok_start + fastboot_cfg.download_bytes <=
+ ptn->start + ptn->length) {
+ sprintf(addr, "0x%x", fastboot_cfg.transfer_buffer);
+ sprintf(wstart, "0x%x", ok_start);
+ sprintf(wlength, "0x%x", fastboot_cfg.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, fastboot_cfg.download_bytes);
+ }
+ } else {
+ FBTERR("could not find enough contiguous space in partition '%s' \n", ptn->name);
+ FBTERR("Ignoring write request\n");
+ }
+ } else {
+ /* TBD : Generalize flash handling */
+ FBTERR("only handling 1 NAND per board");
+ FBTERR("Ignoring write request\n");
+ }
+ } else {
+ FBTWARN("nand block size can not be 0 when using 'continuous block' for partition '%s'\n", ptn->name);
+ FBTWARN("Ignoring write request\n");
+ }
+ } else {
+ /* Normal case */
+ sprintf(addr, "0x%x", fastboot_cfg.transfer_buffer);
+ sprintf(wstart, "0x%x", ptn->start +
+ (repeat * ptn->length));
+ sprintf(wlength, "0x%x", fastboot_cfg.download_bytes);
+ if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_JFFS2)
+ sprintf(wlength, "0x%x",
+ fastboot_cfg.download_bytes_unpadded);
+
+ 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,
+ fastboot_cfg.download_bytes);
+ }
+ }
+
+
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+int handle_flash(char *part_name , char *response)
+{
+ int status = 0;
+
+
+ fastboot_cfg.download_bytes_unpadded = fastboot_cfg.download_size;
+ /* XXX: Revisit padding handling */
+ if (fastboot_cfg.nand_block_size) {
+ if (fastboot_cfg.download_bytes % fastboot_cfg.nand_block_size) {
+ unsigned int pad = fastboot_cfg.nand_block_size - (fastboot_cfg.download_bytes % fastboot_cfg.nand_block_size);
+ unsigned int i;
+
+ for (i = 0; i < pad; i++) {
+ if (fastboot_cfg.download_bytes >= fastboot_cfg.transfer_buffer_size)
+ break;
+
+ fastboot_cfg.transfer_buffer[fastboot_cfg.download_bytes] = 0;
+ fastboot_cfg.download_bytes++;
+ }
+ }
+ }
+
+
+ if (fastboot_cfg.download_bytes) {
+ struct fastboot_ptentry *ptn;
+
+ ptn = fastboot_flash_find_ptn(part_name);
+ if (ptn == 0) {
+ sprintf(response, "FAILpartition does not exist");
+ } else if ((fastboot_cfg.download_bytes > ptn->length) &&
+ !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
+ sprintf(response, "FAILimage too large for partition");
+ } 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])) {
+ FBTINFO("savenv '%s' failed : %s\n", ptn->name, err_string);
+ sprintf(response, "FAIL%s", err_string);
+ } else {
+ FBTINFO("partition '%s' saveenv-ed\n", ptn->name);
+ sprintf(response, "OKAY");
+ }
+ } else {
+ /* Normal case */
+ if (write_to_ptn(ptn)) {
+ FBTINFO("flashing '%s' failed\n", ptn->name);
+ sprintf(response, "FAILfailed to flash partition");
+ } else {
+ FBTINFO("partition '%s' flashed\n", ptn->name);
+ sprintf(response, "OKAY");
+ }
+ }
+ }
+ } else {
+ sprintf(response, "FAILno image downloaded");
+ }
+
+ return status;
+}
+
+/*This function does nothing with NAND partitioning.
+It only adds partition info to fastboot partition table.
+*/
+int do_format()
+{
+ int indx;
+
+ fastboot_flash_reset_ptn();
+
+ for (indx = 0; indx < MAX_PTN; indx++)
+ {
+ fastboot_flash_add_ptn(&omap3h1_nand_ptn[indx]);
+ }
+
+ fastboot_flash_dump_ptn();
+
+ return 0;
+}
+
+
+static int do_format_nand(void)
+{
+ struct ptable *ptbl = NULL; //&the_ptable;
+ unsigned next;
+ int n;
+ block_dev_desc_t *dev_desc;
+ unsigned long blocks_to_write, result;
+
+ dev_desc = get_dev_by_name(FASTBOOT_BLKDEV);
+ if (!dev_desc) {
+ printf("error getting device %s\n", FASTBOOT_BLKDEV);
+ return -1;
+ }
+ if (!dev_desc->lba) {
+ printf("device %s has no space\n", FASTBOOT_BLKDEV);
+ return -1;
+ }
+
+ printf("blocks %lu\n", dev_desc->lba);
+
+ #if 0
+ start_ptbl(ptbl, dev_desc->lba);
+ for (n = 0, next = 0; fbt_partitions[n].name; n++) {
+ u64 sz = fbt_partitions[n].size_kb * 2;
+ if (fbt_partitions[n].name[0] == '-') {
+ next += sz;
+ continue;
+ }
+ if (sz == 0)
+ sz = dev_desc->lba - next;
+ if (add_ptn(ptbl, next, next + sz - 1, fbt_partitions[n].name))
+ return -1;
+ next += sz;
+ }
+ end_ptbl(ptbl);
+
+ blocks_to_write = DIV_ROUND_UP(sizeof(struct ptable), dev_desc->blksz);
+ result = dev_desc->block_write(dev_desc->dev, 0, blocks_to_write, ptbl);
+ if (result != blocks_to_write) {
+ printf("\nFormat failed, block_write() returned %lu instead of %lu\n", result, blocks_to_write);
+ return -1;
+ }
+
+ printf("\nnew partition table of %lu %lu-byte blocks\n",
+ blocks_to_write, dev_desc->blksz);
+ fbt_reset_ptn();
+ #endif
+
+ return 0;
+}
diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c
index 36681b6fc..3900a9e0c 100644
--- a/drivers/usb/musb-new/musb_core.c
+++ b/drivers/usb/musb-new/musb_core.c
@@ -1532,9 +1532,10 @@ static int __devinit musb_core_init(u16 musb_type, struct musb *musb)
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
- defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500)
+//#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
+// defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500)
+#if 1
static irqreturn_t generic_interrupt(int irq, void *__hci)
{
unsigned long flags;
diff --git a/include/configs/omap3_h1.h b/include/configs/omap3_h1.h
index b406bde99..ebb71ffad 100644
--- a/include/configs/omap3_h1.h
+++ b/include/configs/omap3_h1.h
@@ -20,6 +20,31 @@
#define CONFIG_OMAP_GPIO
#define CONFIG_OMAP_COMMON
+
+/* USB UHH support options */
+#define CONFIG_CMD_USB
+#define CONFIG_USB_HOST
+#define CONFIG_USB_EHCI
+#define CONFIG_USB_EHCI_OMAP
+#define CONFIG_USB_STORAGE
+#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3
+#define CONFIG_EHCI_HCD_INIT_AFTER_RESET
+
+/* #define CONFIG_USB_MUSB_AM35X */
+#define CONFIG_USB_MUSB_OMAP2PLUS
+
+/* USB Composite download gadget - g_dnl */
+#define CONFIG_USB_GADGET
+#define CONFIG_USBDOWNLOAD_GADGET
+
+
+/* USB TI's IDs */
+#define CONFIG_USBD_HS
+#define CONFIG_G_DNL_VENDOR_NUM 0x0403
+#define CONFIG_G_DNL_PRODUCT_NUM 0xBD00
+#define CONFIG_G_DNL_MANUFACTURER "Texas Instruments"
+
+
#define CONFIG_SDRC /* The chip has SDRC controller */
#include <asm/arch/cpu.h> /* get chip and board defs */
@@ -261,6 +286,79 @@
* FLASH and environment organization
*/
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_OMAP_HSMMC
+#define CONFIG_CMD_MMC
+#define CONFIG_DOS_PARTITION
+#define CONFIG_CMD_FAT
+#define CONFIG_FAT_WRITE
+#define CONFIG_CMD_EXT2
+
+#define CONFIG_SPI
+#define CONFIG_OMAP3_SPI
+#define CONFIG_MTD_DEVICE
+#define CONFIG_SPI_FLASH
+#define CONFIG_SPI_FLASH_WINBOND
+#define CONFIG_CMD_SF
+#define CONFIG_SF_DEFAULT_SPEED (24000000)
+
+
+/*
+ * USB configuration
+ */
+#define CONFIG_USB_MUSB_DSPS
+/* #define CONFIG_ARCH_MISC_INIT */
+
+#define CONFIG_CMD_SAVEENV
+#define CONFIG_MUSB_GADGET
+#define CONFIG_MUSB_PIO_ONLY
+#define CONFIG_USB_GADGET_DUALSPEED
+#define CONFIG_USB_GADGET_VBUS_DRAW 2
+
+
+#ifdef CONFIG_MUSB_GADGET
+/* Android fastboot support over USB */
+#define CONFIG_CMD_FASTBOOT
+#define FASTBOOT_DEVICE_VENDOR_ID 0x0451
+#define FASTBOOT_DEVICE_PRODUCT_ID 0xd00e /* TI fastboot PID */
+#define FASTBOOT_DEVICE_BCD 0x0100
+
+#define FASTBOOT_BLKDEV "nand0"
+/*
+ * BeagleBone white, AM335x-SK and old AM335xEVMs have only 256MB RAM
+ * To be compatible with all devices, assume 256MB max RAM.
+ *
+ * The current fastboot implementation assumes maximum 16MB of RAM
+ * will be used by u-boot itself. So the fastboot transfer buffer
+ * becomes (256-16)=240MB
+ */
+
+/* #define CONFIG_FASTBOOT_MAX_TRANSFER_SIZE (SZ_256M - SZ_16M) */
+/* If using BeagleBone Black you can use the full RAM and so
+ flash larger images */
+#define CONFIG_FASTBOOT_MAX_TRANSFER_SIZE (SZ_512M - SZ_16M)
+
+#define FASTBOOT_NAND_BLOCK_SIZE 2048
+#define FASTBOOT_NAND_OOB_SIZE 64
+
+#define CONFIG_MMC_FASTBOOT_DEV 1
+
+/*Uncomment this to enable NAND fastboot*/
+#define CONFIG_FASTBOOT_NAND
+
+/*Uncomment this to support eMMC booting*/
+/* #define CONFIG_STORAGE_EMMC */
+
+#define NAND_ENV_OFFSET 0x260000 /* environment starts here */
+
+/* ethernet gadget conflicts with fastboot, so disabled */
+/*
+#define CONFIG_USB_ETHER
+#define CONFIG_USB_ETH_RNDIS
+#define CONFIG_USBNET_HOST_ADDR "de:ad:be:af:00:00"*/
+#endif /* CONFIG_MUSB_GADGET */
+
/* **** PISMO SUPPORT *** */
/* Configure the PISMO */
@@ -350,7 +448,7 @@
#define CONFIG_SYS_NAND_ECCPOS {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}
#define CONFIG_SYS_NAND_ECCBYTES 3
-#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_HW
+#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_SW
#endif /* BCH8_ECC */
diff --git a/include/olioh1_reboot.h b/include/olioh1_reboot.h
new file mode 100644
index 000000000..1fbea3e74
--- /dev/null
+++ b/include/olioh1_reboot.h
@@ -0,0 +1,32 @@
+/*
+ * (C) Copyright 2014
+ * Chris Simmonds, 2net Ltd. chris@2net.co.uk
+ *
+ * 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
+ */
+
+/* Here we define an address in SRAM that can contain a flag to indicate
+ the reason for a reboot.
+
+ I chose an address 16 bytes from the end of SRAM in the hope that
+ nobody will clobber it between Linux reboot and U-Boot starting */
+#define REBOOT_REASON_PA 0x4030fff0
+
+#define REBOOT_FLAG_RECOVERY 0x52564352
+#define REBOOT_FLAG_FASTBOOT 0x54534146
+#define REBOOT_FLAG_NORMAL 0x4D524F4E
+#define REBOOT_FLAG_POWER_OFF 0x46464F50
+
diff --git a/include/sparse_format.h b/include/sparse_format.h
new file mode 100644
index 000000000..6c62c34c7
--- /dev/null
+++ b/include/sparse_format.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+typedef struct sparse_header {
+ __le32 magic; /* 0xed26ff3a */
+ __le16 major_version; /* (0x1) - reject images with higher major versions */
+ __le16 minor_version; /* (0x0) - allow images with higer minor versions */
+ __le16 file_hdr_sz; /* 28 bytes for first revision of the file format */
+ __le16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */
+ __le32 blk_sz; /* block size in bytes, must be a multiple of 4 (4096) */
+ __le32 total_blks; /* total blocks in the non-sparse output image */
+ __le32 total_chunks; /* total chunks in the sparse input image */
+ __le32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
+ /* as 0. Standard 802.3 polynomial, use a Public Domain */
+ /* table implementation */
+} sparse_header_t;
+
+#define SPARSE_HEADER_MAGIC 0xed26ff3a
+
+#define CHUNK_TYPE_RAW 0xCAC1
+#define CHUNK_TYPE_FILL 0xCAC2
+#define CHUNK_TYPE_DONT_CARE 0xCAC3
+#define CHUNK_TYPE_CRC32 0xCAC4
+
+typedef struct chunk_header {
+ __le16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
+ __le16 reserved1;
+ __le32 chunk_sz; /* in blocks in output image */
+ __le32 total_sz; /* in bytes of chunk input file including chunk header and data */
+} chunk_header_t;
+
+/* Following a Raw or Fill or CRC32 chunk is data.
+ * For a Raw chunk, it's the data in chunk_sz * blk_sz.
+ * For a Fill chunk, it's 4 bytes of the fill data.
+ * For a CRC32 chunk, it's 4 bytes of CRC32
+ */
+
diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
new file mode 100644
index 000000000..9525454bc
--- /dev/null
+++ b/include/usb/fastboot.h
@@ -0,0 +1,213 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix at windriver.com>
+ *
+ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy at linutronix.de>
+ *
+ * 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.
+ *
+ * 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
+ * bootloader/legacy/include/boot/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>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#ifdef DEBUG
+#define FBTDBG(fmt,args...)\
+ printf("DEBUG: [%s]: %d: \n"fmt, __FUNCTION__, __LINE__,##args)
+#else
+#define FBTDBG(fmt,args...) do{}while(0)
+#endif
+
+#ifdef INFO
+#define FBTINFO(fmt,args...)\
+ printf("INFO: [%s]: "fmt, __FUNCTION__, ##args)
+#else
+#define FBTINFO(fmt,args...) do{}while(0)
+#endif
+
+#ifdef WARN
+#define FBTWARN(fmt,args...)\
+ printf("WARNING: [%s]: "fmt, __FUNCTION__, ##args)
+#else
+#define FBTWARN(fmt,args...) do{}while(0)
+#endif
+
+#ifdef ERR
+#define FBTERR(fmt,args...)\
+ printf("ERROR: [%s]: "fmt, __FUNCTION__, ##args)
+#else
+#define FBTERR(fmt,args...) do{}while(0)
+#endif
+
+struct fastboot_config {
+
+ /*
+ * Transfer buffer for storing data sent by the client. It should be
+ * able to hold a kernel image and flash partitions. Care should be
+ * take so it does not overrun bootloader memory
+ */
+ unsigned char *transfer_buffer;
+
+ /* Size of the buffer mentioned above */
+ unsigned int transfer_buffer_size;
+
+ /* Total data to be downloaded */
+ unsigned int download_size;
+
+ /* Data downloaded so far */
+ unsigned int download_bytes;
+
+ unsigned int nand_block_size;
+
+ unsigned int nand_oob_size;
+
+ unsigned int download_bytes_unpadded;
+};
+
+#define FB_STR_PRODUCT_IDX 1
+#define FB_STR_SERIAL_IDX 2
+#define FB_STR_CONFIG_IDX 3
+#define FB_STR_INTERFACE_IDX 4
+#define FB_STR_MANUFACTURER_IDX 5
+#define FB_STR_PROC_REV_IDX 6
+#define FB_STR_PROC_TYPE_IDX 7
+
+#ifdef CONFIG_CMD_FASTBOOT
+
+int fastboot_init(void);
+void fastboot_shutdown(void);
+int fastboot_poll(void);
+
+int fastboot_board_init(struct fastboot_config *interface,
+ struct usb_gadget_strings **str);
+
+
+/* Android-style flash naming */
+typedef struct fastboot_ptentry fastboot_ptentry;
+
+/* flash partitions are defined in terms of blocks
+ ** (flash erase units)
+ */
+struct fastboot_ptentry{
+
+ /* The logical name for this partition, null terminated */
+ char name[16];
+ /* The start wrt the nand part, must be multiple of nand block size */
+ unsigned int start;
+ /* The length of the partition, must be multiple of nand block size */
+ unsigned int length;
+ /* Controls the details of how operations are done on the partition
+ See the FASTBOOT_PTENTRY_FLAGS_*'s defined below */
+ unsigned int flags;
+};
+
+/* Lower byte shows if the read/write/erase operation in
+ repeated. The base address is incremented.
+ Either 0 or 1 is ok for a default */
+
+#define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK(n) (n & 0x0f)
+#define FASTBOOT_PTENTRY_FLAGS_REPEAT_4 0x00000004
+
+/* 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 software before writing
+ HW and SW ECC should not both be set. */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC 0x00000040
+
+/* Sets the ECC to hardware before writing
+ HW and SW ECC should not both be set. */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC 0x00000080
+
+/* Sets the ECC to hardware before writing
+ HW and SW ECC should not both be set. */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH4_ECC 0x00000100
+
+/* Sets the ECC to hardware before writing
+ HW and SW ECC should not both be set. */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC 0x00000200
+
+/* Sets the ECC to hardware before writing
+ HW and SW ECC should not both be set. */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH16_ECC 0x00000400
+
+/* Write the file with write.i */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_I 0x00000800
+
+/* Write the file with write.jffs2 */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_JFFS2 0x00001000
+
+/* Write the file as a series of variable/value pairs
+ using the setenv and saveenv commands */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_ENV 0x00002000
+
+
+/* The Android-style flash handling */
+
+/* tools to populate and query the partition table */
+extern void fastboot_flash_add_ptn(fastboot_ptentry *ptn);
+extern fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
+extern fastboot_ptentry *fastboot_flash_get_ptn(unsigned n);
+extern unsigned int fastboot_flash_get_ptn_count(void);
+extern void fastboot_flash_dump_ptn(void);
+extern int fastboot_oem(const char *cmd);
+
+
+#endif
+#endif