diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/mtd/nand/omap_gpmc.c | 2 | ||||
| -rw-r--r-- | drivers/usb/gadget/Makefile | 10 | ||||
| -rw-r--r-- | drivers/usb/gadget/f_fastboot.c | 609 | ||||
| -rw-r--r-- | drivers/usb/gadget/g_fastboot.h | 23 | ||||
| -rw-r--r-- | drivers/usb/gadget/u_fastboot.c | 416 | ||||
| -rw-r--r-- | drivers/usb/gadget/u_fastboot_mmc.c | 609 | ||||
| -rw-r--r-- | drivers/usb/gadget/u_fastboot_nand.c | 838 | ||||
| -rw-r--r-- | drivers/usb/musb-new/musb_core.c | 5 |
8 files changed, 2509 insertions, 3 deletions
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; |