summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget')
-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
6 files changed, 2505 insertions, 0 deletions
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;
+}