From ae7ffee7fe9f9b2e217d051971a98e1f28290cb1 Mon Sep 17 00:00:00 2001 From: "Ye.Li" Date: Thu, 9 Jul 2015 11:19:13 +0800 Subject: MLK-11228-1 android: Integrate community fastboot with FSL i.MX fastboot 1. Replace the UDC driver with community's USB gadget d_dnl driver. 2. Integrate the FSL SD/SATA/NAND flash operations, since the GPT and EFI partitions are not support by i.MX. 3. Add FDT support to community's android image. 4. Change the booti command to boota, due to the booti has been used for ARM64 image boot. 5. Modify boota implementation to load ramdisk and fdt to their loading addresses specified in boot.img header, while bootm won't do it for android image. 6. Modify the android image HAB implementation. Authenticate the boot.img on the "load_addr" for both SD and NAND. 7. Enable new configuration CONFIG_FSL_FASTBOOT for Freescale's fastboot with relevant header file "fsl_fastboot.h". While disabling the configuration, the community fastboot is used. 8. Use community's way to combine cmdline in boot.img and u-boot environment, not overwrite the cmdline in boot.img Signed-off-by: Ye.Li --- drivers/fastboot/fastboot.c | 1127 ------------------------- drivers/usb/gadget/ci_udc.c | 2 +- drivers/usb/gadget/f_fastboot.c | 1746 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 1746 insertions(+), 1129 deletions(-) delete mode 100644 drivers/fastboot/fastboot.c (limited to 'drivers') diff --git a/drivers/fastboot/fastboot.c b/drivers/fastboot/fastboot.c deleted file mode 100644 index 0b5bebb..0000000 --- a/drivers/fastboot/fastboot.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* - * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. All Rights Reserved. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_ANDROID_RECOVERY -#include -#endif - -/* - * Defines - */ -#define NUM_ENDPOINTS 2 - -#define CONFIG_USBD_OUT_PKTSIZE 0x200 -#define CONFIG_USBD_IN_PKTSIZE 0x200 -#define MAX_BUFFER_SIZE 0x200 - -/* - * imx family android layout - * mbr - 0 ~ 0x3FF byte - * bootloader - 0x400 ~ 0xFFFFF byte - * kernel - 0x100000 ~ 5FFFFF byte - * uramedisk - 0x600000 ~ 0x6FFFFF supposing 1M temporarily - * SYSTEM partition - /dev/mmcblk0p2 or /dev/sda2 - * RECOVERY parittion - dev/mmcblk0p4 or /dev/sda4 - */ -#define ANDROID_MBR_OFFSET 0 -#define ANDROID_MBR_SIZE 0x200 -#define ANDROID_BOOTLOADER_OFFSET 0x400 -#define ANDROID_BOOTLOADER_SIZE 0xFFC00 -#define ANDROID_KERNEL_OFFSET 0x100000 -#define ANDROID_KERNEL_SIZE 0x500000 -#define ANDROID_URAMDISK_OFFSET 0x600000 -#define ANDROID_URAMDISK_SIZE 0x100000 - -#define STR_LANG_INDEX 0x00 -#define STR_MANUFACTURER_INDEX 0x01 -#define STR_PRODUCT_INDEX 0x02 -#define STR_SERIAL_INDEX 0x03 -#define STR_CONFIG_INDEX 0x04 -#define STR_DATA_INTERFACE_INDEX 0x05 -#define STR_CTRL_INTERFACE_INDEX 0x06 -#define STR_COUNT 0x07 - -#define FASTBOOT_FBPARTS_ENV_MAX_LEN 1024 -/* To support the Android-style naming of flash */ -#define MAX_PTN 16 - - -/*pentry index internally*/ -enum { - PTN_MBR_INDEX = 0, - PTN_BOOTLOADER_INDEX, - PTN_KERNEL_INDEX, - PTN_URAMDISK_INDEX, - PTN_SYSTEM_INDEX, - PTN_RECOVERY_INDEX -}; - -struct fastboot_device_info fastboot_devinfo; - -/* defined and used by gadget/ep0.c */ -extern struct usb_string_descriptor **usb_strings; - -static struct usb_device_instance device_instance[1]; -static struct usb_bus_instance bus_instance[1]; -static struct usb_configuration_instance config_instance[1]; -static struct usb_interface_instance interface_instance[1]; -static struct usb_alternate_instance alternate_instance[1]; -/* one extra for control endpoint */ -static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1]; - -static struct cmd_fastboot_interface *fastboot_interface; -static int fastboot_configured_flag; -static int usb_disconnected; - -/* Indicies, References */ -static u8 rx_endpoint; -static u8 tx_endpoint; -static struct usb_string_descriptor *fastboot_string_table[STR_COUNT]; - -/* USB Descriptor Strings */ -static u8 wstrLang[4] = {4, USB_DT_STRING, 0x9, 0x4}; -static u8 wstrManufacturer[2 * (sizeof(CONFIG_FASTBOOT_MANUFACTURER_STR))]; -static u8 wstrProduct[2 * (sizeof(CONFIG_FASTBOOT_PRODUCT_NAME_STR))]; -static u8 wstrSerial[2*(sizeof(CONFIG_FASTBOOT_SERIAL_NUM))]; -static u8 wstrConfiguration[2 * (sizeof(CONFIG_FASTBOOT_CONFIGURATION_STR))]; -static u8 wstrDataInterface[2 * (sizeof(CONFIG_FASTBOOT_INTERFACE_STR))]; - -/* Standard USB Data Structures */ -static struct usb_interface_descriptor interface_descriptors[1]; -static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS]; -static struct usb_configuration_descriptor *configuration_descriptor; -static struct usb_device_descriptor device_descriptor = { - .bLength = sizeof(struct usb_device_descriptor), - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = cpu_to_le16(USB_BCD_VERSION), - .bDeviceClass = 0xff, - .bDeviceSubClass = 0xff, - .bDeviceProtocol = 0xff, - .bMaxPacketSize0 = 0x40, - .idVendor = cpu_to_le16(CONFIG_FASTBOOT_VENDOR_ID), - .idProduct = cpu_to_le16(CONFIG_FASTBOOT_PRODUCT_ID), - .bcdDevice = cpu_to_le16(CONFIG_FASTBOOT_BCD_DEVICE), - .iManufacturer = STR_MANUFACTURER_INDEX, - .iProduct = STR_PRODUCT_INDEX, - .iSerialNumber = STR_SERIAL_INDEX, - .bNumConfigurations = 1 -}; - -/* - * Static Generic Serial specific data - */ - -struct fastboot_config_desc { - struct usb_configuration_descriptor configuration_desc; - struct usb_interface_descriptor interface_desc[1]; - struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS]; -}; - -static struct fastboot_config_desc -fastboot_configuration_descriptors[1] = { - { - .configuration_desc = { - .bLength = sizeof(struct usb_configuration_descriptor), - .bDescriptorType = USB_DT_CONFIG, - .wTotalLength = - cpu_to_le16(sizeof(struct fastboot_config_desc)), - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = STR_CONFIG_INDEX, - .bmAttributes = - BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, - .bMaxPower = 0x32 - }, - .interface_desc = { - { - .bLength = - sizeof(struct usb_interface_descriptor), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = NUM_ENDPOINTS, - .bInterfaceClass = - FASTBOOT_INTERFACE_CLASS, - .bInterfaceSubClass = - FASTBOOT_INTERFACE_SUB_CLASS, - .bInterfaceProtocol = - FASTBOOT_INTERFACE_PROTOCOL, - .iInterface = STR_DATA_INTERFACE_INDEX - }, - }, - .data_endpoints = { - { - .bLength = - sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = UDC_OUT_ENDPOINT | - USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = - cpu_to_le16(CONFIG_USBD_OUT_PKTSIZE), - .bInterval = 0x00, - }, - { - .bLength = - sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = UDC_IN_ENDPOINT | - USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = - cpu_to_le16(CONFIG_USBD_IN_PKTSIZE), - .bInterval = 0x00, - }, - }, - }, -}; - - - -static struct fastboot_ptentry ptable[MAX_PTN]; -static unsigned int pcount; - - -/* Static Function Prototypes */ -static void _fastboot_init_strings(void); -static void _fastboot_init_instances(void); -static void _fastboot_init_endpoints(void); -static void _fastboot_event_handler(struct usb_device_instance *device, - usb_device_event_t event, int data); -static int _fastboot_cdc_setup(struct usb_device_request *request, - struct urb *urb); -static int _fastboot_usb_configured(void); -#if defined(CONFIG_FASTBOOT_STORAGE_SATA) \ - || defined(CONFIG_FASTBOOT_STORAGE_MMC) -static int _fastboot_parts_load_from_ptable(void); -#endif -#if defined(CONFIG_FASTBOOT_STORAGE_NAND) -static int _fastboot_parts_load_from_env(void); -#endif -static int _fastboot_setup_dev(void); -static void _fastboot_load_partitions(void); - -/* utility function for converting char* to wide string used by USB */ -static void str2wide(char *str, u16 * wide) -{ - int i; - for (i = 0; i < strlen(str) && str[i]; i++) { - #if defined(__LITTLE_ENDIAN) - wide[i] = (u16) str[i]; - #elif defined(__BIG_ENDIAN) - wide[i] = ((u16)(str[i])<<8); - #else - #error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined" - #endif - } -} - -/* - Get mmc control number from passed string, eg, "mmc1" mean device 1. Only - support "mmc0" to "mmc9" currently. It will be treated as device 0 for - other string. -*/ -static int _fastboot_get_mmc_no(char *env_str) -{ - int digit = 0; - unsigned char a; - - if (env_str && (strlen(env_str) >= 4) && - !strncmp(env_str, "mmc", 3)) { - a = env_str[3]; - if (a >= '0' && a <= '9') - digit = a - '0'; - } - - return digit; -} - -static int _fastboot_setup_dev(void) -{ - char *fastboot_env; - fastboot_env = getenv("fastboot_dev"); - - if (fastboot_env) { - if (!strcmp(fastboot_env, "sata")) { - fastboot_devinfo.type = DEV_SATA; - fastboot_devinfo.dev_id = 0; - } else if (!strcmp(fastboot_env, "nand")) { - fastboot_devinfo.type = DEV_NAND; - fastboot_devinfo.dev_id = 0; - } else if (!strncmp(fastboot_env, "mmc", 3)) { - fastboot_devinfo.type = DEV_MMC; - fastboot_devinfo.dev_id = _fastboot_get_mmc_no(fastboot_env); - } - } else { - return 1; - } - - return 0; -} - - -/* - * Initialize fastboot - */ -int fastboot_init(struct cmd_fastboot_interface *interface) -{ - printf("fastboot is in init......"); - - fastboot_interface = interface; - fastboot_interface->product_name = CONFIG_FASTBOOT_PRODUCT_NAME_STR; - fastboot_interface->serial_no = CONFIG_FASTBOOT_SERIAL_NUM; - fastboot_interface->nand_block_size = 4096; - fastboot_interface->transfer_buffer = - (unsigned char *)CONFIG_FASTBOOT_TRANSFER_BUF; - fastboot_interface->transfer_buffer_size = - CONFIG_FASTBOOT_TRANSFER_BUF_SIZE; - - _fastboot_init_strings(); - /* Basic USB initialization */ - udc_init(); - - _fastboot_init_instances(); - - udc_startup_events(device_instance); - udc_connect(); /* Enable pullup for host detection */ - - return 0; -} - -static void _fastboot_init_strings(void) -{ - struct usb_string_descriptor *string; - - fastboot_string_table[STR_LANG_INDEX] = - (struct usb_string_descriptor *)wstrLang; - - string = (struct usb_string_descriptor *)wstrManufacturer; - string->bLength = sizeof(wstrManufacturer); - string->bDescriptorType = USB_DT_STRING; - str2wide(CONFIG_FASTBOOT_MANUFACTURER_STR, string->wData); - fastboot_string_table[STR_MANUFACTURER_INDEX] = string; - - string = (struct usb_string_descriptor *)wstrProduct; - string->bLength = sizeof(wstrProduct); - string->bDescriptorType = USB_DT_STRING; - str2wide(CONFIG_FASTBOOT_PRODUCT_NAME_STR, string->wData); - fastboot_string_table[STR_PRODUCT_INDEX] = string; - - string = (struct usb_string_descriptor *)wstrSerial; - string->bLength = sizeof(wstrSerial); - string->bDescriptorType = USB_DT_STRING; - str2wide(CONFIG_FASTBOOT_SERIAL_NUM, string->wData); - fastboot_string_table[STR_SERIAL_INDEX] = string; - - string = (struct usb_string_descriptor *)wstrConfiguration; - string->bLength = sizeof(wstrConfiguration); - string->bDescriptorType = USB_DT_STRING; - str2wide(CONFIG_FASTBOOT_CONFIGURATION_STR, string->wData); - fastboot_string_table[STR_CONFIG_INDEX] = string; - - string = (struct usb_string_descriptor *) wstrDataInterface; - string->bLength = sizeof(wstrDataInterface); - string->bDescriptorType = USB_DT_STRING; - str2wide(CONFIG_FASTBOOT_INTERFACE_STR, string->wData); - fastboot_string_table[STR_DATA_INTERFACE_INDEX] = string; - - /* Now, initialize the string table for ep0 handling */ - usb_strings = fastboot_string_table; -} - -static void _fastboot_init_instances(void) -{ - int i; - u16 temp; - - /* Assign endpoint descriptors */ - ep_descriptor_ptrs[0] = - &fastboot_configuration_descriptors[0].data_endpoints[0]; - ep_descriptor_ptrs[1] = - &fastboot_configuration_descriptors[0].data_endpoints[1]; - - /* Configuration Descriptor */ - configuration_descriptor = - (struct usb_configuration_descriptor *) - &fastboot_configuration_descriptors; - - fastboot_configured_flag = 0; - - /* initialize device instance */ - memset(device_instance, 0, sizeof(struct usb_device_instance)); - device_instance->device_state = STATE_INIT; - device_instance->device_descriptor = &device_descriptor; - device_instance->event = _fastboot_event_handler; - device_instance->cdc_recv_setup = _fastboot_cdc_setup; - device_instance->bus = bus_instance; - device_instance->configurations = 1; - device_instance->configuration_instance_array = config_instance; - - /* initialize bus instance */ - memset(bus_instance, 0, sizeof(struct usb_bus_instance)); - bus_instance->device = device_instance; - bus_instance->endpoint_array = endpoint_instance; - bus_instance->max_endpoints = NUM_ENDPOINTS + 1; - bus_instance->maxpacketsize = 0xFF; - bus_instance->serial_number_str = CONFIG_FASTBOOT_SERIAL_NUM; - - /* configuration instance */ - memset(config_instance, 0, - sizeof(struct usb_configuration_instance)); - config_instance->interfaces = 1; - config_instance->configuration_descriptor = configuration_descriptor; - config_instance->interface_instance_array = interface_instance; - - /* interface instance */ - memset(interface_instance, 0, - sizeof(struct usb_interface_instance)); - interface_instance->alternates = 1; - interface_instance->alternates_instance_array = alternate_instance; - - /* alternates instance */ - memset(alternate_instance, 0, - sizeof(struct usb_alternate_instance)); - alternate_instance->interface_descriptor = interface_descriptors; - alternate_instance->endpoints = NUM_ENDPOINTS; - alternate_instance->endpoints_descriptor_array = ep_descriptor_ptrs; - - /* endpoint instances */ - memset(&endpoint_instance[0], 0, - sizeof(struct usb_endpoint_instance)); - endpoint_instance[0].endpoint_address = 0; - endpoint_instance[0].rcv_packetSize = EP0_MAX_PACKET_SIZE; - endpoint_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL; - endpoint_instance[0].tx_packetSize = EP0_MAX_PACKET_SIZE; - endpoint_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL; - udc_setup_ep(device_instance, 0, &endpoint_instance[0]); - - for (i = 1; i <= NUM_ENDPOINTS; i++) { - memset(&endpoint_instance[i], 0, - sizeof(struct usb_endpoint_instance)); - - endpoint_instance[i].endpoint_address = - ep_descriptor_ptrs[i - 1]->bEndpointAddress; - - endpoint_instance[i].rcv_attributes = - ep_descriptor_ptrs[i - 1]->bmAttributes; - - /*fix the abort caused by unalignment*/ - temp = *(u8 *)&ep_descriptor_ptrs[i - 1]->wMaxPacketSize; - temp |= - (*(((u8 *)&ep_descriptor_ptrs[i - 1]->wMaxPacketSize) + 1) << 8); - - endpoint_instance[i].rcv_packetSize = - le16_to_cpu(temp); - - endpoint_instance[i].tx_attributes = - ep_descriptor_ptrs[i - 1]->bmAttributes; - - endpoint_instance[i].tx_packetSize = - le16_to_cpu(temp); - - endpoint_instance[i].tx_attributes = - ep_descriptor_ptrs[i - 1]->bmAttributes; - - urb_link_init(&endpoint_instance[i].rcv); - urb_link_init(&endpoint_instance[i].rdy); - urb_link_init(&endpoint_instance[i].tx); - urb_link_init(&endpoint_instance[i].done); - - if (endpoint_instance[i].endpoint_address & USB_DIR_IN) { - tx_endpoint = i; - endpoint_instance[i].tx_urb = - usbd_alloc_urb(device_instance, - &endpoint_instance[i]); - } else { - rx_endpoint = i; - endpoint_instance[i].rcv_urb = - usbd_alloc_urb(device_instance, - &endpoint_instance[i]); - } - } -} - -static void _fastboot_init_endpoints(void) -{ - int i; - - bus_instance->max_endpoints = NUM_ENDPOINTS + 1; - for (i = 1; i <= NUM_ENDPOINTS; i++) - udc_setup_ep(device_instance, i, &endpoint_instance[i]); -} - -static void _fastboot_destroy_endpoints(void) -{ - int i; - struct urb *tx_urb; - - for (i = 1; i <= NUM_ENDPOINTS; i++) { - /*dealloc urb*/ - if (endpoint_instance[i].endpoint_address & USB_DIR_IN) { - if (endpoint_instance[i].tx_urb) - usbd_dealloc_urb(endpoint_instance[i].tx_urb); - - while (endpoint_instance[i].tx_queue) { - tx_urb = first_urb_detached(&endpoint_instance[i].tx); - if (tx_urb) { - usbd_dealloc_urb(tx_urb); - endpoint_instance[i].tx_queue--; - } else { - break; - } - } - endpoint_instance[i].tx_queue = 0; - - do { - tx_urb = first_urb_detached(&endpoint_instance[i].done); - if (tx_urb) - usbd_dealloc_urb(tx_urb); - } while (tx_urb); - - } else { - if (endpoint_instance[i].rcv_urb) - usbd_dealloc_urb(endpoint_instance[i].rcv_urb); - } - - udc_destroy_ep(device_instance, &endpoint_instance[i]); - } -} - - -static int _fill_buffer(u8 *buf) -{ - struct usb_endpoint_instance *endpoint = - &endpoint_instance[rx_endpoint]; - - if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) { - unsigned int nb = 0; - char *src = (char *)endpoint->rcv_urb->buffer; - unsigned int rx_avail = MAX_BUFFER_SIZE; - - if (rx_avail >= endpoint->rcv_urb->actual_length) { - nb = endpoint->rcv_urb->actual_length; - memcpy(buf, src, nb); - endpoint->rcv_urb->actual_length = 0; - } - return nb; - } - return 0; -} - -static struct urb *_next_urb(struct usb_device_instance *device, - struct usb_endpoint_instance *endpoint) -{ - struct urb *current_urb = NULL; - int space; - - /* If there's a queue, then we should add to the last urb */ - if (!endpoint->tx_queue) - current_urb = endpoint->tx_urb; - else - /* Last urb from tx chain */ - current_urb = - p2surround(struct urb, link, endpoint->tx.prev); - - /* Make sure this one has enough room */ - space = current_urb->buffer_length - current_urb->actual_length; - if (space > 0) - return current_urb; - else { /* No space here */ - /* First look at done list */ - current_urb = first_urb_detached(&endpoint->done); - if (!current_urb) - current_urb = usbd_alloc_urb(device, endpoint); - - urb_append(&endpoint->tx, current_urb); - endpoint->tx_queue++; - } - return current_urb; -} - -static int _fastboot_usb_configured(void) -{ - return fastboot_configured_flag; -} - -static void _fastboot_event_handler(struct usb_device_instance *device, - usb_device_event_t event, int data) -{ - switch (event) { - case DEVICE_RESET: - case DEVICE_BUS_INACTIVE: - fastboot_configured_flag = 0; - break; - case DEVICE_CONFIGURED: - fastboot_configured_flag = 1; - _fastboot_init_endpoints(); - break; - case DEVICE_ADDRESS_ASSIGNED: - default: - break; - } -} - -static int _fastboot_cdc_setup(struct usb_device_request *request, - struct urb *urb) -{ - return 0; -} - - -/*! - * Function to receive data from host through channel - * - * @buf buffer to fill in - * @count read data size - * - * @return 0 - */ -int fastboot_usb_recv(u8 *buf, int count) -{ - int len = 0; - - while (!_fastboot_usb_configured()) - udc_irq(); - - /* update rxqueue to wait new data */ - mxc_udc_rxqueue_update(2, count); - - while (!len) { - if (is_usb_disconnected()) { - /*it will not unconfigure when disconnect - from host, so here needs manual unconfigure - anyway, it's just a workaround*/ - fastboot_configured_flag = 0; - usb_disconnected = 1; - return 0; - } - udc_irq(); - if (_fastboot_usb_configured()) - len = _fill_buffer(buf); - } - return len; -} - -int fastboot_getvar(const char *rx_buffer, char *tx_buffer) -{ - /* Place board specific variables here */ - return 0; -} - -int fastboot_poll() -{ - u8 buffer[MAX_BUFFER_SIZE]; - int length = 0; - - memset(buffer, 0, MAX_BUFFER_SIZE); - - length = fastboot_usb_recv(buffer, MAX_BUFFER_SIZE); - - /* If usb disconnected, blocked here to wait */ - if (usb_disconnected) { - udc_disconnect(); - udc_connect(); - /*the udc_connect will be blocked until connect to host - so, the usb_disconnect should be 0 after udc_connect, - and should be set manually. Anyway, it's just a workaround*/ - usb_disconnected = 0; - } - - if (!length) - return FASTBOOT_INACTIVE; - - /* Pass this up to the interface's handler */ - if (fastboot_interface && fastboot_interface->rx_handler) { - if (!fastboot_interface->rx_handler(buffer, length)) - return FASTBOOT_OK; - } - return FASTBOOT_OK; -} - -int fastboot_tx(unsigned char *buffer, unsigned int buffer_size) -{ - /* Not realized yet */ - return 0; -} - -static int _fastboot_write_buffer(const char *buffer, - unsigned int buffer_size) -{ - struct usb_endpoint_instance *endpoint = - (struct usb_endpoint_instance *)&endpoint_instance[tx_endpoint]; - struct urb *current_urb = NULL; - - if (!_fastboot_usb_configured()) - return 0; - - current_urb = _next_urb(device_instance, endpoint); - if (buffer_size) { - char *dest; - int space_avail, popnum, count, total = 0; - - /* Break buffer into urb sized pieces, - * and link each to the endpoint - */ - count = buffer_size; - while (count > 0) { - if (!current_urb) { - printf("current_urb is NULL, buffer_size %d\n", - buffer_size); - return total; - } - - dest = (char *)current_urb->buffer + - current_urb->actual_length; - - space_avail = current_urb->buffer_length - - current_urb->actual_length; - popnum = min(space_avail, count); - if (popnum == 0) - break; - - memcpy(dest, buffer + total, popnum); - printf("send: %s\n", (char *)buffer); - - current_urb->actual_length += popnum; - total += popnum; - - if (udc_endpoint_write(endpoint)) - /* Write pre-empted by RX */ - return 0; - count -= popnum; - } /* end while */ - return total; - } - return 0; -} - -int fastboot_tx_status(const char *buffer, unsigned int buffer_size) -{ - int len = 0; - - while (buffer_size > 0) { - len = _fastboot_write_buffer(buffer + len, buffer_size); - buffer_size -= len; - - udc_irq(); - } - udc_irq(); - - return 0; -} - -void fastboot_shutdown(void) -{ - usb_shutdown(); - - /* Reset interface*/ - if (fastboot_interface && - fastboot_interface->reset_handler) { - fastboot_interface->reset_handler(); - } - - /* Reset some globals */ - _fastboot_destroy_endpoints(); - fastboot_interface = NULL; - fastboot_configured_flag = 0; - usb_disconnected = 0; - - /*free memory*/ - udc_destroy(); -} - -/* - * CPU and board-specific fastboot initializations. Aliased function - * signals caller to move on - */ -static void __def_fastboot_setup(void) -{ - /*do nothing here*/ -} -void board_fastboot_setup(void) \ - __attribute__((weak, alias("__def_fastboot_setup"))); - - -void fastboot_setup(void) -{ - /*execute board relevant initilizations for preparing fastboot */ - board_fastboot_setup(); - - /*get the fastboot dev*/ - _fastboot_setup_dev(); - - /*check if we need to setup recovery*/ -#ifdef CONFIG_ANDROID_RECOVERY - check_recovery_mode(); -#endif - - /*load partitions information for the fastboot dev*/ - _fastboot_load_partitions(); -} - -/* export to lib_arm/board.c */ -void check_fastboot(void) -{ - if (fastboot_check_and_clean_flag()) - do_fastboot(NULL, 0, 0, 0); -} - -#if defined(CONFIG_FASTBOOT_STORAGE_SATA) \ - || defined(CONFIG_FASTBOOT_STORAGE_MMC) -/** - @mmc_dos_partition_index: the partition index in mbr. - @mmc_partition_index: the boot partition or user partition index, - not related to the partition table. - */ -static int _fastboot_parts_add_ptable_entry(int ptable_index, - int mmc_dos_partition_index, - int mmc_partition_index, - const char *name, - block_dev_desc_t *dev_desc, - struct fastboot_ptentry *ptable) -{ - disk_partition_t info; - strcpy(ptable[ptable_index].name, name); - - if (get_partition_info(dev_desc, - mmc_dos_partition_index, &info)) { - printf("Bad partition index:%d for partition:%s\n", - mmc_dos_partition_index, name); - return -1; - } else { - ptable[ptable_index].start = info.start; - ptable[ptable_index].length = info.size; - ptable[ptable_index].partition_id = mmc_partition_index; - } - return 0; -} - -static int _fastboot_parts_load_from_ptable(void) -{ - int i; -#ifdef CONFIG_CMD_SATA - int sata_device_no; -#endif - - /* mmc boot partition: -1 means no partition, 0 user part., 1 boot part. - * default is no partition, for emmc default user part, except emmc*/ - int boot_partition = FASTBOOT_MMC_NONE_PARTITION_ID; - int user_partition = FASTBOOT_MMC_NONE_PARTITION_ID; - - struct mmc *mmc; - block_dev_desc_t *dev_desc; - struct fastboot_ptentry ptable[PTN_RECOVERY_INDEX + 1]; - - /* sata case in env */ - if (fastboot_devinfo.type == DEV_SATA) { -#ifdef CONFIG_CMD_SATA - puts("flash target is SATA\n"); - if (sata_initialize()) - return -1; - sata_device_no = CONFIG_FASTBOOT_SATA_NO; - if (sata_device_no >= CONFIG_SYS_SATA_MAX_DEVICE) { - printf("Unknown SATA(%d) device for fastboot\n", - sata_device_no); - return -1; - } - dev_desc = sata_get_dev(sata_device_no); -#else /*! CONFIG_CMD_SATA*/ - puts("SATA isn't buildin\n"); - return -1; -#endif /*! CONFIG_CMD_SATA*/ - } else if (fastboot_devinfo.type == DEV_MMC) { - int mmc_no = 0; - mmc_no = fastboot_devinfo.dev_id; - - printf("flash target is MMC:%d\n", mmc_no); - mmc = find_mmc_device(mmc_no); - if (mmc && mmc_init(mmc)) - printf("MMC card init failed!\n"); - - dev_desc = get_dev("mmc", mmc_no); - if (NULL == dev_desc) { - printf("** Block device MMC %d not supported\n", - mmc_no); - return -1; - } - - /* multiple boot paritions for eMMC 4.3 later */ - if (mmc->part_config != MMCPART_NOAVAILABLE) { - boot_partition = FASTBOOT_MMC_BOOT_PARTITION_ID; - user_partition = FASTBOOT_MMC_USER_PARTITION_ID; - } - } else { - printf("Can't setup partition table on this device %d\n", - fastboot_devinfo.type); - return -1; - } - - memset((char *)ptable, 0, - sizeof(struct fastboot_ptentry) * (PTN_RECOVERY_INDEX + 1)); - /* MBR */ - strcpy(ptable[PTN_MBR_INDEX].name, "mbr"); - ptable[PTN_MBR_INDEX].start = ANDROID_MBR_OFFSET / dev_desc->blksz; - ptable[PTN_MBR_INDEX].length = ANDROID_MBR_SIZE / dev_desc->blksz; - ptable[PTN_MBR_INDEX].partition_id = user_partition; - /* Bootloader */ - strcpy(ptable[PTN_BOOTLOADER_INDEX].name, "bootloader"); - ptable[PTN_BOOTLOADER_INDEX].start = - ANDROID_BOOTLOADER_OFFSET / dev_desc->blksz; - ptable[PTN_BOOTLOADER_INDEX].length = - ANDROID_BOOTLOADER_SIZE / dev_desc->blksz; - ptable[PTN_BOOTLOADER_INDEX].partition_id = boot_partition; - - _fastboot_parts_add_ptable_entry(PTN_KERNEL_INDEX, - CONFIG_ANDROID_BOOT_PARTITION_MMC, - user_partition, "boot", dev_desc, ptable); - _fastboot_parts_add_ptable_entry(PTN_RECOVERY_INDEX, - CONFIG_ANDROID_RECOVERY_PARTITION_MMC, - user_partition, - "recovery", dev_desc, ptable); - _fastboot_parts_add_ptable_entry(PTN_SYSTEM_INDEX, - CONFIG_ANDROID_SYSTEM_PARTITION_MMC, - user_partition, - "system", dev_desc, ptable); - - for (i = 0; i <= PTN_RECOVERY_INDEX; i++) - fastboot_flash_add_ptn(&ptable[i]); - - return 0; -} -#endif /*CONFIG_FASTBOOT_STORAGE_SATA || CONFIG_FASTBOOT_STORAGE_MMC*/ - -#if defined(CONFIG_FASTBOOT_STORAGE_NAND) -static unsigned long long _memparse(char *ptr, char **retptr) -{ - char *endptr; /* local pointer to end of parsed string */ - - unsigned long ret = simple_strtoul(ptr, &endptr, 0); - - switch (*endptr) { - case 'M': - case 'm': - ret <<= 10; - case 'K': - case 'k': - ret <<= 10; - endptr++; - default: - break; - } - - if (retptr) - *retptr = endptr; - - return ret; -} - -static int _fastboot_parts_add_env_entry(char *s, char **retptr) -{ - unsigned long size; - unsigned long offset = 0; - char *name; - int name_len; - int delim; - unsigned int flags; - struct fastboot_ptentry part; - - size = _memparse(s, &s); - if (0 == size) { - printf("Error:FASTBOOT size of parition is 0\n"); - return 1; - } - - /* fetch partition name and flags */ - flags = 0; /* this is going to be a regular partition */ - delim = 0; - /* check for offset */ - if (*s == '@') { - s++; - offset = _memparse(s, &s); - } else { - printf("Error:FASTBOOT offset of parition is not given\n"); - return 1; - } - - /* now look for name */ - if (*s == '(') - delim = ')'; - - if (delim) { - char *p; - - name = ++s; - p = strchr((const char *)name, delim); - if (!p) { - printf("Error:FASTBOOT no closing %c found in partition name\n", - delim); - return 1; - } - name_len = p - name; - s = p + 1; - } else { - printf("Error:FASTBOOT no partition name for \'%s\'\n", s); - return 1; - } - - /* check for options */ - while (1) { - if (strncmp(s, "i", 1) == 0) { - flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_I; - s += 1; - } else if (strncmp(s, "ubifs", 5) == 0) { - /* ubifs */ - flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS; - s += 5; - } else { - break; - } - if (strncmp(s, "|", 1) == 0) - s += 1; - } - - /* enter this partition (offset will be calculated later if it is zero at this point) */ - part.length = size; - part.start = offset; - part.flags = flags; - - if (name) { - if (name_len >= sizeof(part.name)) { - printf("Error:FASTBOOT partition name is too long\n"); - return 1; - } - strncpy(&part.name[0], name, name_len); - /* name is not null terminated */ - part.name[name_len] = '\0'; - } else { - printf("Error:FASTBOOT no name\n"); - return 1; - } - - fastboot_flash_add_ptn(&part); - - /*if the nand partitions envs are not initialized, try to init them*/ - if (check_parts_values(&part)) - save_parts_values(&part, part.start, part.length); - - /* return (updated) pointer command line string */ - *retptr = s; - - /* return partition table */ - return 0; -} - -static int _fastboot_parts_load_from_env(void) -{ - char fbparts[FASTBOOT_FBPARTS_ENV_MAX_LEN], *env; - - env = getenv("fbparts"); - if (env) { - unsigned int len; - len = strlen(env); - if (len && len < FASTBOOT_FBPARTS_ENV_MAX_LEN) { - char *s, *e; - - memcpy(&fbparts[0], env, len + 1); - printf("Fastboot: Adding partitions from environment\n"); - s = &fbparts[0]; - e = s + len; - while (s < e) { - if (_fastboot_parts_add_env_entry(s, &s)) { - printf("Error:Fastboot: Abort adding partitions\n"); - pcount = 0; - return 1; - } - /* Skip a bunch of delimiters */ - while (s < e) { - if ((' ' == *s) || - ('\t' == *s) || - ('\n' == *s) || - ('\r' == *s) || - (',' == *s)) { - s++; - } else { - break; - } - } - } - } - } - - return 0; -} -#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/ - -static void _fastboot_load_partitions(void) -{ - pcount = 0; -#if defined(CONFIG_FASTBOOT_STORAGE_NAND) - _fastboot_parts_load_from_env(); -#elif defined(CONFIG_FASTBOOT_STORAGE_SATA) \ - || defined(CONFIG_FASTBOOT_STORAGE_MMC) - _fastboot_parts_load_from_ptable(); -#endif -} - -/* - * Android style flash utilties */ -void fastboot_flash_add_ptn(struct fastboot_ptentry *ptn) -{ - if (pcount < MAX_PTN) { - memcpy(ptable + pcount, ptn, sizeof(struct fastboot_ptentry)); - pcount++; - } -} - -void fastboot_flash_dump_ptn(void) -{ - unsigned int n; - for (n = 0; n < pcount; n++) { - struct fastboot_ptentry *ptn = ptable + n; - printf("ptn %d name='%s' start=%d len=%d\n", - n, ptn->name, ptn->start, ptn->length); - } -} - - -struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name) -{ - unsigned int n; - - for (n = 0; n < pcount; n++) { - /* Make sure a substring is not accepted */ - if (strlen(name) == strlen(ptable[n].name)) { - if (0 == strcmp(ptable[n].name, name)) - return ptable + n; - } - } - - printf("can't find partition: %s, dump the partition table\n", name); - fastboot_flash_dump_ptn(); - return 0; -} - -struct fastboot_ptentry *fastboot_flash_get_ptn(unsigned int n) -{ - if (n < pcount) - return ptable + n; - else - return 0; -} - -unsigned int fastboot_flash_get_ptn_count(void) -{ - return pcount; -} diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index b0ef35e..1dd8b11 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -888,7 +888,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) return ret; ret = ci_udc_probe(); -#if defined(CONFIG_USB_EHCI_MX6) || defined(CONFIG_USB_EHCI_MXS) +#if defined(CONFIG_USB_EHCI_MX6) || defined(CONFIG_USB_EHCI_MXS) || defined(CONFIG_USB_EHCI_MX7) /* * FIXME: usb_lowlevel_init()->ehci_hcd_init() should be doing all * HW-specific initialization, e.g. ULPI-vs-UTMI PHY selection diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 751ec9e..cbe4236 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -24,6 +24,18 @@ #include #endif +#ifdef CONFIG_FSL_FASTBOOT +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_ANDROID_RECOVERY +#include +#endif +#endif + #define FASTBOOT_VERSION "0.4" #define FASTBOOT_INTERFACE_CLASS 0xff @@ -122,6 +134,1691 @@ static struct usb_gadget_strings *fastboot_strings[] = { NULL, }; +#ifdef CONFIG_FSL_FASTBOOT + +#define ANDROID_MBR_OFFSET 0 +#define ANDROID_MBR_SIZE 0x200 +#define ANDROID_BOOTLOADER_OFFSET 0x400 +#define ANDROID_BOOTLOADER_SIZE 0xFFC00 +#define ANDROID_KERNEL_OFFSET 0x100000 +#define ANDROID_KERNEL_SIZE 0x500000 +#define ANDROID_URAMDISK_OFFSET 0x600000 +#define ANDROID_URAMDISK_SIZE 0x100000 + + + +#define MMC_SATA_BLOCK_SIZE 512 +#define FASTBOOT_FBPARTS_ENV_MAX_LEN 1024 +/* To support the Android-style naming of flash */ +#define MAX_PTN 16 + + +/*pentry index internally*/ +enum { + PTN_MBR_INDEX = 0, + PTN_BOOTLOADER_INDEX, + PTN_KERNEL_INDEX, + PTN_URAMDISK_INDEX, + PTN_SYSTEM_INDEX, + PTN_RECOVERY_INDEX +}; + +static unsigned int download_bytes_unpadded; + +static struct cmd_fastboot_interface interface = { + .rx_handler = NULL, + .reset_handler = NULL, + .product_name = NULL, + .serial_no = NULL, + .nand_block_size = 0, + .transfer_buffer = (unsigned char *)0xffffffff, + .transfer_buffer_size = 0, +}; + + +#ifdef CONFIG_FASTBOOT_STORAGE_NAND +static void save_env(struct fastboot_ptentry *ptn, + char *var, char *val) +{ +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + char lock[128], unlock[128]; +#endif + + setenv(var, val); + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + sprintf(lock, "nand lock 0x%x 0x%x", ptn->start, ptn->length); + sprintf(unlock, "nand unlock 0x%x 0x%x", ptn->start, ptn->length); + + /* This could be a problem is there is an outstanding lock */ + run_command(unlock, 0); +#endif + saveenv(); + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + run_command(lock, 0); +#endif +} + +void save_parts_values(struct fastboot_ptentry *ptn, + unsigned int offset, + unsigned int size) +{ + char var[64], val[32]; +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + char lock[128], unlock[128]; + struct fastboot_ptentry *env_ptn; +#endif + + printf("saving it..\n"); + + + sprintf(var, "%s_nand_offset", ptn->name); + sprintf(val, "0x%x", offset); + + printf("setenv %s %s\n", var, val); + + setenv(var, val); + + sprintf(var, "%s_nand_size", ptn->name); + sprintf(val, "0x%x", size); + + printf("setenv %s %s\n", var, val); + + setenv(var, val); + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + /* 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) { + sprintf(lock, "nand lock 0x%x 0x%x", + env_ptn->start, env_ptn->length); + sprintf(unlock, "nand unlock 0x%x 0x%x", + env_ptn->start, env_ptn->length); + + run_command(unlock, 0); + } +#endif + saveenv(); + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + if (env_ptn) + run_command(lock, 0); +#endif +} + +int check_parts_values(struct fastboot_ptentry *ptn) +{ + char var[64]; + + sprintf(var, "%s_nand_offset", ptn->name); + if (!getenv(var)) + return 1; + + sprintf(var, "%s_nand_size", ptn->name); + if (!getenv(var)) + return 1; + + return 0; +} + +static int write_to_ptn(struct fastboot_ptentry *ptn) +{ + int ret = 1; + char length[32]; + char write_type[32]; + int repeat, repeat_max; + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + char lock[128]; + char unlock[128]; +#endif + char write[128]; + char erase[128]; + + printf("flashing '%s'\n", ptn->name); + + /* Which flavor of write to use */ + if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_I) + sprintf(write_type, "write.i"); +#ifdef CONFIG_CMD_NAND_TRIMFFS + else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS) + sprintf(write_type, "write.trimffs"); +#endif + else + sprintf(write_type, "write"); + + /* Some flashing requires writing the same data in multiple, + consecutive flash partitions */ + repeat_max = 1; + if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK) { + if (ptn->flags & + FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) { + printf("Warning can not do both 'contiguous block' " + "and 'repeat' writes for for partition '%s'\n", ptn->name); + printf("Ignoring repeat flag\n"); + } else { + repeat_max = ptn->flags & + FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK; + } + } + + /* Unlock the whole partition instead of trying to + manage special cases */ + sprintf(length, "0x%x", ptn->length * repeat_max); + + for (repeat = 0; repeat < repeat_max; repeat++) { +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + sprintf(lock, "nand lock 0x%x %s", + ptn->start + (repeat * ptn->length), length); + sprintf(unlock, "nand unlock 0x%x %s", + ptn->start + (repeat * ptn->length), length); +#endif + sprintf(erase, "nand erase 0x%x %s", + ptn->start + (repeat * ptn->length), length); + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + run_command(unlock, 0); +#endif + run_command(erase, 0); + + if ((ptn->flags & + FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) && + (ptn->flags & + FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK)) { + /* Both can not be true */ + printf("Warning can not do 'next good block' and \ + 'contiguous block' for partition '%s'\n", + ptn->name); + printf("Ignoring these flags\n"); + } else if (ptn->flags & + FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) { + /* Keep writing until you get a good block + transfer_buffer should already be aligned */ + if (interface.nand_block_size) { + unsigned int blocks = download_bytes / + interface.nand_block_size; + unsigned int i = 0; + unsigned int offset = 0; + + while (i < blocks) { + /* Check for overflow */ + if (offset >= ptn->length) + break; + + /* download's address only advance + if last write was successful */ + + /* nand's address always advances */ + sprintf(write, "nand %s 0x%p 0x%x 0x%x", write_type, + interface.transfer_buffer + + (i * interface.nand_block_size), + ptn->start + (repeat * ptn->length) + offset, + interface.nand_block_size); + + ret = run_command(write, 0); + if (ret) + break; + else + i++; + + /* Go to next nand block */ + offset += interface.nand_block_size; + } + } else { + printf("Warning nand block size can not be 0 \ + when using 'next good block' for \ + partition '%s'\n", ptn->name); + printf("Ignoring write request\n"); + } + } else if (ptn->flags & + FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) { + /* Keep writing until you get a good block + transfer_buffer should already be aligned */ + if (interface.nand_block_size) { + if (0 == nand_curr_device) { + nand_info_t *nand; + unsigned long off; + unsigned int ok_start; + + nand = &nand_info[nand_curr_device]; + + printf("\nDevice %d bad blocks:\n", + nand_curr_device); + + /* Initialize the ok_start to the + start of the partition + Then try to find a block large + enough for the download */ + ok_start = ptn->start; + + /* It is assumed that the start and + length are multiples of block size */ + for (off = ptn->start; + off < ptn->start + ptn->length; + off += nand->erasesize) { + if (nand_block_isbad(nand, off)) { + /* Reset the ok_start + to the next block */ + ok_start = off + + nand->erasesize; + } + + /* Check if we have enough + blocks */ + if ((ok_start - off) >= + download_bytes) + break; + } + + /* Check if there is enough space */ + if (ok_start + download_bytes <= + ptn->start + ptn->length) { + + sprintf(write, "nand %s 0x%p 0x%x 0x%x", write_type, + interface.transfer_buffer, + ok_start, + download_bytes); + + ret = run_command(write, 0); + + /* Save the results into an + environment variable on the + format + ptn_name + 'offset' + ptn_name + 'size' */ + if (ret) { + /* failed */ + save_parts_values(ptn, ptn->start, 0); + } else { + /* success */ + save_parts_values(ptn, ok_start, download_bytes); + } + } else { + printf("Error could not find enough contiguous space " + "in partition '%s'\n", ptn->name); + printf("Ignoring write request\n"); + } + } else { + /* TBD : Generalize flash handling */ + printf("Error only handling 1 NAND per board"); + printf("Ignoring write request\n"); + } + } else { + printf("Warning nand block size can not be 0 \ + when using 'continuous block' for \ + partition '%s'\n", ptn->name); + printf("Ignoring write request\n"); + } + } else { + /* Normal case */ + sprintf(write, "nand %s 0x%p 0x%x 0x%x", write_type, + interface.transfer_buffer, + ptn->start + (repeat * ptn->length), + download_bytes); +#ifdef CONFIG_CMD_NAND_TRIMFFS + if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS) { + sprintf(write, "nand %s 0x%p 0x%x 0x%x", write_type, + interface.transfer_buffer, + ptn->start + (repeat * ptn->length), + download_bytes_unpadded); + } +#endif + + ret = run_command(write, 0); + + if (0 == repeat) { + if (ret) /* failed */ + save_parts_values(ptn, ptn->start, 0); + else /* success */ + save_parts_values(ptn, ptn->start, + download_bytes); + } + } + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + run_command(lock, 0); +#endif + + if (ret) + break; + } + + return ret; +} +#else +static void save_env(struct fastboot_ptentry *ptn, + char *var, char *val) +{ + setenv(var, val); + saveenv(); +} +#endif + +/* When save = 0, just parse. The input is unchanged + When save = 1, parse and do the save. The input is changed */ +static int parse_env(void *ptn, char *err_string, int save, int debug) +{ + int ret = 1; + unsigned int sets = 0; + unsigned int comment_start = 0; + char *var = NULL; + char *var_end = NULL; + char *val = NULL; + char *val_end = NULL; + unsigned int i; + + char *buff = (char *)interface.transfer_buffer; + unsigned int size = download_bytes_unpadded; + + /* The input does not have to be null terminated. + This will cause a problem in the corner case + where the last line does not have a new line. + Put a null after the end of the input. + + WARNING : Input buffer is assumed to be bigger + than the size of the input */ + if (save) + buff[size] = 0; + + for (i = 0; i < size; i++) { + + if (NULL == var) { + + /* + * Check for comments, comment ok only on + * mostly empty lines + */ + if (buff[i] == '#') + comment_start = 1; + + if (comment_start) { + if ((buff[i] == '\r') || + (buff[i] == '\n')) { + comment_start = 0; + } + } else { + if (!((buff[i] == ' ') || + (buff[i] == '\t') || + (buff[i] == '\r') || + (buff[i] == '\n'))) { + /* + * Normal whitespace before the + * variable + */ + var = &buff[i]; + } + } + + } else if (((NULL == var_end) || (NULL == val)) && + ((buff[i] == '\r') || (buff[i] == '\n'))) { + + /* This is the case when a variable + is unset. */ + + if (save) { + /* Set the var end to null so the + normal string routines will work + + WARNING : This changes the input */ + buff[i] = '\0'; + + save_env(ptn, var, val); + + if (debug) + printf("Unsetting %s\n", var); + } + + /* Clear the variable so state is parse is back + to initial. */ + var = NULL; + var_end = NULL; + sets++; + } else if (NULL == var_end) { + if ((buff[i] == ' ') || + (buff[i] == '\t')) + var_end = &buff[i]; + } else if (NULL == val) { + if (!((buff[i] == ' ') || + (buff[i] == '\t'))) + val = &buff[i]; + } else if (NULL == val_end) { + if ((buff[i] == '\r') || + (buff[i] == '\n')) { + /* look for escaped cr or ln */ + if ('\\' == buff[i - 1]) { + /* check for dos */ + if ((buff[i] == '\r') && + (buff[i+1] == '\n')) + buff[i + 1] = ' '; + buff[i - 1] = buff[i] = ' '; + } else { + val_end = &buff[i]; + } + } + } else { + sprintf(err_string, "Internal Error"); + + if (debug) + printf("Internal error at %s %d\n", + __FILE__, __LINE__); + return 1; + } + /* Check if a var / val pair is ready */ + if (NULL != val_end) { + if (save) { + /* Set the end's with nulls so + normal string routines will + work. + + WARNING : This changes the input */ + *var_end = '\0'; + *val_end = '\0'; + + save_env(ptn, var, val); + + if (debug) + printf("Setting %s %s\n", var, val); + } + + /* Clear the variable so state is parse is back + to initial. */ + var = NULL; + var_end = NULL; + val = NULL; + val_end = NULL; + + sets++; + } + } + + /* Corner case + Check for the case that no newline at end of the input */ + if ((NULL != var) && + (NULL == val_end)) { + if (save) { + /* case of val / val pair */ + if (var_end) + *var_end = '\0'; + /* else case handled by setting 0 past + the end of buffer. + Similar for val_end being null */ + save_env(ptn, var, val); + + if (debug) { + if (var_end) + printf("Trailing Setting %s %s\n", var, val); + else + printf("Trailing Unsetting %s\n", var); + } + } + sets++; + } + /* Did we set anything ? */ + if (0 == sets) + sprintf(err_string, "No variables set"); + else + ret = 0; + + return ret; +} + +static int saveenv_to_ptn(struct fastboot_ptentry *ptn, char *err_string) +{ + int ret = 1; + int save = 0; + int debug = 0; + + /* err_string is only 32 bytes + Initialize with a generic error message. */ + sprintf(err_string, "%s", "Unknown Error"); + + /* Parse the input twice. + Only save to the enviroment if the entire input if correct */ + save = 0; + if (0 == parse_env(ptn, err_string, save, debug)) { + save = 1; + ret = parse_env(ptn, err_string, save, debug); + } + return ret; +} + +static char result_str[RESPONSE_LEN]; + +void fastboot_fail(const char *s) +{ + strncpy(result_str, "FAIL\0", 5); + strncat(result_str, s, RESPONSE_LEN - 4 - 1); +} + +void fastboot_okay(const char *s) +{ + strncpy(result_str, "OKAY\0", 5); + strncat(result_str, s, RESPONSE_LEN - 4 - 1); +} + +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + +static void process_flash_nand(const char *cmdbuf, char *response) +{ + if (download_bytes) { + struct fastboot_ptentry *ptn; + + ptn = fastboot_flash_find_ptn(cmdbuf); + if (ptn == 0) { + sprintf(response, "FAILpartition does not exist"); + } else if ((download_bytes > ptn->length) && + !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { + sprintf(response, "FAILimage too large for partition"); + /* TODO : Improve check for yaffs write */ + } else { + /* Check if this is not really a flash write + but rather a saveenv */ + if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) { + /* Since the response can only be 64 bytes, + there is no point in having a large error message. */ + char err_string[32]; + if (saveenv_to_ptn(ptn, &err_string[0])) { + printf("savenv '%s' failed : %s\n", + ptn->name, err_string); + sprintf(response, "FAIL%s", err_string); + } else { + printf("partition '%s' saveenv-ed\n", ptn->name); + sprintf(response, "OKAY"); + } + } else { + /* Normal case */ + if (write_to_ptn(ptn)) { + printf("flashing '%s' failed\n", ptn->name); + sprintf(response, "FAILfailed to flash partition"); + } else { + printf("partition '%s' flashed\n", ptn->name); + sprintf(response, "OKAY"); + } + } + } + } else { + sprintf(response, "FAILno image downloaded"); + } + +} +#endif + +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) +static void process_flash_sata(const char *cmdbuf, char *response) +{ + if (download_bytes) { + struct fastboot_ptentry *ptn; + + /* Next is the partition name */ + ptn = fastboot_flash_find_ptn(cmdbuf); + if (ptn == 0) { + printf("Partition:'%s' does not exist\n", ptn->name); + sprintf(response, "FAILpartition does not exist"); + } else if ((download_bytes > + ptn->length * MMC_SATA_BLOCK_SIZE) && + !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { + printf("Image too large for the partition\n"); + sprintf(response, "FAILimage too large for partition"); + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) { + /* Since the response can only be 64 bytes, + there is no point in having a large error message. */ + char err_string[32]; + if (saveenv_to_ptn(ptn, &err_string[0])) { + printf("savenv '%s' failed : %s\n", ptn->name, err_string); + sprintf(response, "FAIL%s", err_string); + } else { + printf("partition '%s' saveenv-ed\n", ptn->name); + sprintf(response, "OKAY"); + } + } else { + unsigned int temp; + char sata_write[128]; + + /* block count */ + temp = (download_bytes + + MMC_SATA_BLOCK_SIZE - 1) / + MMC_SATA_BLOCK_SIZE; + + sprintf(sata_write, "sata write 0x%x 0x%x 0x%x", + (unsigned int)interface.transfer_buffer, + ptn->start, + temp) + + if (run_command(sata_write, 0)) { + printf("Writing '%s' FAILED!\n", + ptn->name); + sprintf(response, + "FAIL: Write partition"); + } else { + printf("Writing '%s' DONE!\n", + ptn->name); + sprintf(response, "OKAY"); + } + } + } else { + sprintf(response, "FAILno image downloaded"); + } + +} +#endif + +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) +static int is_sparse_partition(struct fastboot_ptentry *ptn) +{ + if (ptn && !strncmp(ptn->name, + FASTBOOT_PARTITION_SYSTEM, strlen(FASTBOOT_PARTITION_SYSTEM))) { + printf("support sparse flash partition for %s\n", ptn->name); + return 1; + } else + return 0; +} + +static void process_flash_mmc(const char *cmdbuf, char *response) +{ + if (download_bytes) { + struct fastboot_ptentry *ptn; + + /* Next is the partition name */ + ptn = fastboot_flash_find_ptn(cmdbuf); + if (ptn == 0) { + printf("Partition:'%s' does not exist\n", ptn->name); + sprintf(response, "FAILpartition does not exist"); + } else if ((download_bytes > + ptn->length * MMC_SATA_BLOCK_SIZE) && + !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { + printf("Image too large for the partition\n"); + sprintf(response, "FAILimage too large for partition"); + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) { + /* Since the response can only be 64 bytes, + there is no point in having a large error message. */ + char err_string[32]; + if (saveenv_to_ptn(ptn, &err_string[0])) { + printf("savenv '%s' failed : %s\n", ptn->name, err_string); + sprintf(response, "FAIL%s", err_string); + } else { + printf("partition '%s' saveenv-ed\n", ptn->name); + sprintf(response, "OKAY"); + } + } else { + unsigned int temp; + + char mmc_dev[128]; + char mmc_write[128]; + int mmcret; + + printf("writing to partition '%s'\n", ptn->name); + + if (ptn->partition_id != FASTBOOT_MMC_NONE_PARTITION_ID) + sprintf(mmc_dev, "mmc dev %x %x", + fastboot_devinfo.dev_id, /*slot no*/ + ptn->partition_id /*part no*/); + else + sprintf(mmc_dev, "mmc dev %x", + fastboot_devinfo.dev_id /*slot no*/); + + if (is_sparse_partition(ptn) && + is_sparse_image(interface.transfer_buffer)) { + int mmc_no = 0; + struct mmc *mmc; + block_dev_desc_t *dev_desc; + disk_partition_t info; + mmc_no = fastboot_devinfo.dev_id; + + printf("sparse flash target is MMC:%d\n", mmc_no); + mmc = find_mmc_device(mmc_no); + if (mmc && mmc_init(mmc)) + printf("MMC card init failed!\n"); + + dev_desc = get_dev("mmc", mmc_no); + if (NULL == dev_desc) { + printf("** Block device MMC %d not supported\n", + mmc_no); + return; + } + + if (get_partition_info(dev_desc, + ptn->partition_index, &info)) { + printf("Bad partition index:%d for partition:%s\n", + ptn->partition_index, ptn->name); + return; + } + + printf("writing to partition '%s' for sparse, buffer size %d\n", + ptn->name, download_bytes); + write_sparse_image(dev_desc, &info, ptn->name, + interface.transfer_buffer, download_bytes); + strcpy(response, result_str); + } else { + /* block count */ + temp = (download_bytes + + MMC_SATA_BLOCK_SIZE - 1) / + MMC_SATA_BLOCK_SIZE; + + sprintf(mmc_write, "mmc write 0x%x 0x%x 0x%x", + (unsigned int)interface.transfer_buffer, /*source*/ + ptn->start, /*dest*/ + temp /*length*/); + + printf("Initializing '%s'\n", ptn->name); + + mmcret = run_command(mmc_dev, 0); + if (mmcret) + sprintf(response, "FAIL:Init of MMC card"); + else + sprintf(response, "OKAY"); + + printf("Writing '%s'\n", ptn->name); + if (run_command(mmc_write, 0)) { + printf("Writing '%s' FAILED!\n", ptn->name); + sprintf(response, "FAIL: Write partition"); + } else { + printf("Writing '%s' DONE!\n", ptn->name); + sprintf(response, "OKAY"); + } + } + } + } else { + sprintf(response, "FAILno image downloaded"); + } +} + +#endif + + +static int rx_process_erase(const char *cmdbuf, char *response) +{ +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + struct fastboot_ptentry *ptn; + + ptn = fastboot_flash_find_ptn(cmdbuf); + if (ptn == 0) { + sprintf(response, "FAILpartition does not exist"); + } else { + int status, repeat, repeat_max; + + printf("erasing '%s'\n", ptn->name); + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + char lock[128]; + char unlock[128]; +#endif + char erase[128]; + + repeat_max = 1; + if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK) + repeat_max = ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK; + + for (repeat = 0; repeat < repeat_max; + repeat++) { +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + sprintf(lock, "nand lock 0x%x 0x%x", + ptn->start + (repeat * ptn->length), + ptn->length); + sprintf(unlock, "nand unlock 0x%x 0x%x", + ptn->start + (repeat * ptn->length), + ptn->length); +#endif + sprintf(erase, "nand erase 0x%x 0x%x", + ptn->start + (repeat * ptn->length), + ptn->length); + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + run_command(unlock, 0); +#endif + status = run_command(erase, 0); +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + run_command(lock, 0); +#endif + + if (status) + break; + } + + if (status) { + sprintf(response, + "FAILfailed to erase partition"); + } else { + printf("partition '%s' erased\n", ptn->name); + sprintf(response, "OKAY"); + } + } + return 0; +#else + printf("Not support erase command for EMMC\n"); + return -1; +#endif + +} + +static void rx_process_flash(const char *cmdbuf, char *response) +{ + switch (fastboot_devinfo.type) { +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) + case DEV_SATA: + process_flash_sata(cmdbuf, response); + break; +#endif +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case DEV_MMC: + process_flash_mmc(cmdbuf, response); + break; +#endif +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + case DEV_NAND: + process_flash_nand(cmdbuf, response); + break; +#endif + default: + printf("Not support flash command for current device %d\n", + fastboot_devinfo.type); + sprintf(response, + "FAILfailed to flash device"); + break; + } +} + + +static void parameters_setup(void) +{ + interface.nand_block_size = 0; +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + nand_info_t *nand = &nand_info[0]; + if (nand) + interface.nand_block_size = nand->writesize; +#endif + interface.transfer_buffer = + (unsigned char *)CONFIG_USB_FASTBOOT_BUF_ADDR; + interface.transfer_buffer_size = + CONFIG_USB_FASTBOOT_BUF_SIZE; +} + +static struct fastboot_ptentry ptable[MAX_PTN]; +static unsigned int pcount; +struct fastboot_device_info fastboot_devinfo; + +/* + Get mmc control number from passed string, eg, "mmc1" mean device 1. Only + support "mmc0" to "mmc9" currently. It will be treated as device 0 for + other string. +*/ +static int _fastboot_get_mmc_no(char *env_str) +{ + int digit = 0; + unsigned char a; + + if (env_str && (strlen(env_str) >= 4) && + !strncmp(env_str, "mmc", 3)) { + a = env_str[3]; + if (a >= '0' && a <= '9') + digit = a - '0'; + } + + return digit; +} +static int _fastboot_setup_dev(void) +{ + char *fastboot_env; + fastboot_env = getenv("fastboot_dev"); + + if (fastboot_env) { + if (!strcmp(fastboot_env, "sata")) { + fastboot_devinfo.type = DEV_SATA; + fastboot_devinfo.dev_id = 0; + } else if (!strcmp(fastboot_env, "nand")) { + fastboot_devinfo.type = DEV_NAND; + fastboot_devinfo.dev_id = 0; + } else if (!strncmp(fastboot_env, "mmc", 3)) { + fastboot_devinfo.type = DEV_MMC; + fastboot_devinfo.dev_id = _fastboot_get_mmc_no(fastboot_env); + } + } else { + return 1; + } + + return 0; +} + +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) \ + || defined(CONFIG_FASTBOOT_STORAGE_MMC) +/** + @mmc_dos_partition_index: the partition index in mbr. + @mmc_partition_index: the boot partition or user partition index, + not related to the partition table. + */ +static int _fastboot_parts_add_ptable_entry(int ptable_index, + int mmc_dos_partition_index, + int mmc_partition_index, + const char *name, + block_dev_desc_t *dev_desc, + struct fastboot_ptentry *ptable) +{ + disk_partition_t info; + strcpy(ptable[ptable_index].name, name); + + if (get_partition_info(dev_desc, + mmc_dos_partition_index, &info)) { + printf("Bad partition index:%d for partition:%s\n", + mmc_dos_partition_index, name); + return -1; + } else { + ptable[ptable_index].start = info.start; + ptable[ptable_index].length = info.size; + ptable[ptable_index].partition_id = mmc_partition_index; + ptable[ptable_index].partition_index = mmc_dos_partition_index; + } + return 0; +} + +static int _fastboot_parts_load_from_ptable(void) +{ + int i; +#ifdef CONFIG_CMD_SATA + int sata_device_no; +#endif + + /* mmc boot partition: -1 means no partition, 0 user part., 1 boot part. + * default is no partition, for emmc default user part, except emmc*/ + int boot_partition = FASTBOOT_MMC_NONE_PARTITION_ID; + int user_partition = FASTBOOT_MMC_NONE_PARTITION_ID; + + struct mmc *mmc; + block_dev_desc_t *dev_desc; + struct fastboot_ptentry ptable[PTN_RECOVERY_INDEX + 1]; + + /* sata case in env */ + if (fastboot_devinfo.type == DEV_SATA) { +#ifdef CONFIG_CMD_SATA + puts("flash target is SATA\n"); + if (sata_initialize()) + return -1; + sata_device_no = CONFIG_FASTBOOT_SATA_NO; + if (sata_device_no >= CONFIG_SYS_SATA_MAX_DEVICE) { + printf("Unknown SATA(%d) device for fastboot\n", + sata_device_no); + return -1; + } + dev_desc = sata_get_dev(sata_device_no); +#else /*! CONFIG_CMD_SATA*/ + puts("SATA isn't buildin\n"); + return -1; +#endif /*! CONFIG_CMD_SATA*/ + } else if (fastboot_devinfo.type == DEV_MMC) { + int mmc_no = 0; + mmc_no = fastboot_devinfo.dev_id; + + printf("flash target is MMC:%d\n", mmc_no); + mmc = find_mmc_device(mmc_no); + if (mmc && mmc_init(mmc)) + printf("MMC card init failed!\n"); + + dev_desc = get_dev("mmc", mmc_no); + if (NULL == dev_desc) { + printf("** Block device MMC %d not supported\n", + mmc_no); + return -1; + } + + /* multiple boot paritions for eMMC 4.3 later */ + if (mmc->part_config != MMCPART_NOAVAILABLE) { + boot_partition = FASTBOOT_MMC_BOOT_PARTITION_ID; + user_partition = FASTBOOT_MMC_USER_PARTITION_ID; + } + } else { + printf("Can't setup partition table on this device %d\n", + fastboot_devinfo.type); + return -1; + } + + memset((char *)ptable, 0, + sizeof(struct fastboot_ptentry) * (PTN_RECOVERY_INDEX + 1)); + /* MBR */ + strcpy(ptable[PTN_MBR_INDEX].name, "mbr"); + ptable[PTN_MBR_INDEX].start = ANDROID_MBR_OFFSET / dev_desc->blksz; + ptable[PTN_MBR_INDEX].length = ANDROID_MBR_SIZE / dev_desc->blksz; + ptable[PTN_MBR_INDEX].partition_id = user_partition; + /* Bootloader */ + strcpy(ptable[PTN_BOOTLOADER_INDEX].name, FASTBOOT_PARTITION_BOOTLOADER); + ptable[PTN_BOOTLOADER_INDEX].start = + ANDROID_BOOTLOADER_OFFSET / dev_desc->blksz; + ptable[PTN_BOOTLOADER_INDEX].length = + ANDROID_BOOTLOADER_SIZE / dev_desc->blksz; + ptable[PTN_BOOTLOADER_INDEX].partition_id = boot_partition; + + _fastboot_parts_add_ptable_entry(PTN_KERNEL_INDEX, + CONFIG_ANDROID_BOOT_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_BOOT , dev_desc, ptable); + _fastboot_parts_add_ptable_entry(PTN_RECOVERY_INDEX, + CONFIG_ANDROID_RECOVERY_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_RECOVERY, dev_desc, ptable); + _fastboot_parts_add_ptable_entry(PTN_SYSTEM_INDEX, + CONFIG_ANDROID_SYSTEM_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_SYSTEM, dev_desc, ptable); + + for (i = 0; i <= PTN_RECOVERY_INDEX; i++) + fastboot_flash_add_ptn(&ptable[i]); + + return 0; +} +#endif /*CONFIG_FASTBOOT_STORAGE_SATA || CONFIG_FASTBOOT_STORAGE_MMC*/ + +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) +static unsigned long long _memparse(char *ptr, char **retptr) +{ + char *endptr; /* local pointer to end of parsed string */ + + unsigned long ret = simple_strtoul(ptr, &endptr, 0); + + switch (*endptr) { + case 'M': + case 'm': + ret <<= 10; + case 'K': + case 'k': + ret <<= 10; + endptr++; + default: + break; + } + + if (retptr) + *retptr = endptr; + + return ret; +} + +static int _fastboot_parts_add_env_entry(char *s, char **retptr) +{ + unsigned long size; + unsigned long offset = 0; + char *name; + int name_len; + int delim; + unsigned int flags; + struct fastboot_ptentry part; + + size = _memparse(s, &s); + if (0 == size) { + printf("Error:FASTBOOT size of parition is 0\n"); + return 1; + } + + /* fetch partition name and flags */ + flags = 0; /* this is going to be a regular partition */ + delim = 0; + /* check for offset */ + if (*s == '@') { + s++; + offset = _memparse(s, &s); + } else { + printf("Error:FASTBOOT offset of parition is not given\n"); + return 1; + } + + /* now look for name */ + if (*s == '(') + delim = ')'; + + if (delim) { + char *p; + + name = ++s; + p = strchr((const char *)name, delim); + if (!p) { + printf("Error:FASTBOOT no closing %c found in partition name\n", + delim); + return 1; + } + name_len = p - name; + s = p + 1; + } else { + printf("Error:FASTBOOT no partition name for \'%s\'\n", s); + return 1; + } + + /* check for options */ + while (1) { + if (strncmp(s, "i", 1) == 0) { + flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_I; + s += 1; + } else if (strncmp(s, "ubifs", 5) == 0) { + /* ubifs */ + flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS; + s += 5; + } else { + break; + } + if (strncmp(s, "|", 1) == 0) + s += 1; + } + + /* enter this partition (offset will be calculated later if it is zero at this point) */ + part.length = size; + part.start = offset; + part.flags = flags; + + if (name) { + if (name_len >= sizeof(part.name)) { + printf("Error:FASTBOOT partition name is too long\n"); + return 1; + } + strncpy(&part.name[0], name, name_len); + /* name is not null terminated */ + part.name[name_len] = '\0'; + } else { + printf("Error:FASTBOOT no name\n"); + return 1; + } + + fastboot_flash_add_ptn(&part); + + /*if the nand partitions envs are not initialized, try to init them*/ + if (check_parts_values(&part)) + save_parts_values(&part, part.start, part.length); + + /* return (updated) pointer command line string */ + *retptr = s; + + /* return partition table */ + return 0; +} + +static int _fastboot_parts_load_from_env(void) +{ + char fbparts[FASTBOOT_FBPARTS_ENV_MAX_LEN], *env; + + env = getenv("fbparts"); + if (env) { + unsigned int len; + len = strlen(env); + if (len && len < FASTBOOT_FBPARTS_ENV_MAX_LEN) { + char *s, *e; + + memcpy(&fbparts[0], env, len + 1); + printf("Fastboot: Adding partitions from environment\n"); + s = &fbparts[0]; + e = s + len; + while (s < e) { + if (_fastboot_parts_add_env_entry(s, &s)) { + printf("Error:Fastboot: Abort adding partitions\n"); + pcount = 0; + return 1; + } + /* Skip a bunch of delimiters */ + while (s < e) { + if ((' ' == *s) || + ('\t' == *s) || + ('\n' == *s) || + ('\r' == *s) || + (',' == *s)) { + s++; + } else { + break; + } + } + } + } + } + + return 0; +} +#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/ + +static void _fastboot_load_partitions(void) +{ + pcount = 0; +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + _fastboot_parts_load_from_env(); +#elif defined(CONFIG_FASTBOOT_STORAGE_SATA) \ + || defined(CONFIG_FASTBOOT_STORAGE_MMC) + _fastboot_parts_load_from_ptable(); +#endif +} + +/* + * Android style flash utilties */ +void fastboot_flash_add_ptn(struct fastboot_ptentry *ptn) +{ + if (pcount < MAX_PTN) { + memcpy(ptable + pcount, ptn, sizeof(struct fastboot_ptentry)); + pcount++; + } +} + +void fastboot_flash_dump_ptn(void) +{ + unsigned int n; + for (n = 0; n < pcount; n++) { + struct fastboot_ptentry *ptn = ptable + n; + printf("ptn %d name='%s' start=%d len=%d\n", + n, ptn->name, ptn->start, ptn->length); + } +} + + +struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name) +{ + unsigned int n; + + for (n = 0; n < pcount; n++) { + /* Make sure a substring is not accepted */ + if (strlen(name) == strlen(ptable[n].name)) { + if (0 == strcmp(ptable[n].name, name)) + return ptable + n; + } + } + + printf("can't find partition: %s, dump the partition table\n", name); + fastboot_flash_dump_ptn(); + return 0; +} + +struct fastboot_ptentry *fastboot_flash_get_ptn(unsigned int n) +{ + if (n < pcount) + return ptable + n; + else + return 0; +} + +unsigned int fastboot_flash_get_ptn_count(void) +{ + return pcount; +} + +/* + * CPU and board-specific fastboot initializations. Aliased function + * signals caller to move on + */ +static void __def_fastboot_setup(void) +{ + /*do nothing here*/ +} +void board_fastboot_setup(void) \ + __attribute__((weak, alias("__def_fastboot_setup"))); + + +void fastboot_setup(void) +{ + struct tag_serialnr serialnr; + char serial[17]; + + get_board_serial(&serialnr); + sprintf(serial, "%u%u", serialnr.high, serialnr.low); + g_dnl_set_serialnumber(serial); + + /*execute board relevant initilizations for preparing fastboot */ + board_fastboot_setup(); + + /*get the fastboot dev*/ + _fastboot_setup_dev(); + + /*check if we need to setup recovery*/ +#ifdef CONFIG_ANDROID_RECOVERY + check_recovery_mode(); +#endif + + /*load partitions information for the fastboot dev*/ + _fastboot_load_partitions(); + + parameters_setup(); +} + +/* export to lib_arm/board.c */ +void check_fastboot(void) +{ + if (fastboot_check_and_clean_flag()) + run_command("fastboot", 0); +} + +#ifdef CONFIG_CMD_BOOTA + /* Section for Android bootimage format support + * Refer: + * http://android.git.kernel.org/?p=platform/system/core.git;a=blob; + * f=mkbootimg/bootimg.h + */ + +void +bootimg_print_image_hdr(struct andr_img_hdr *hdr) +{ +#ifdef DEBUG + int i; + printf(" Image magic: %s\n", hdr->magic); + + printf(" kernel_size: 0x%x\n", hdr->kernel_size); + printf(" kernel_addr: 0x%x\n", hdr->kernel_addr); + + printf(" rdisk_size: 0x%x\n", hdr->ramdisk_size); + printf(" rdisk_addr: 0x%x\n", hdr->ramdisk_addr); + + printf(" second_size: 0x%x\n", hdr->second_size); + printf(" second_addr: 0x%x\n", hdr->second_addr); + + printf(" tags_addr: 0x%x\n", hdr->tags_addr); + printf(" page_size: 0x%x\n", hdr->page_size); + + printf(" name: %s\n", hdr->name); + printf(" cmdline: %s%x\n", hdr->cmdline); + + for (i = 0; i < 8; i++) + printf(" id[%d]: 0x%x\n", i, hdr->id[i]); +#endif +} + +static struct andr_img_hdr boothdr __aligned(ARCH_DMA_MINALIGN); + +/* boota [ mmc0 | mmc1 [ ] ] */ +int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + ulong addr = 0; + char *ptn = "boot"; + int mmcc = -1; + struct andr_img_hdr *hdr = &boothdr; + ulong image_size; +#ifdef CONFIG_SECURE_BOOT +#define IVT_SIZE 0x20 +#define CSF_PAD_SIZE CONFIG_CSF_SIZE +/* Max of bootimage size to be 16MB */ +#define MAX_ANDROID_BOOT_AUTH_SIZE 0x1000000 +/* Size appended to boot.img with boot_signer */ +#define BOOTIMAGE_SIGNATURE_SIZE 0x100 +#endif + int i = 0; + + for (i = 0; i < argc; i++) + printf("%s ", argv[i]); + printf("\n"); + + if (argc < 2) + return -1; + + if (!strncmp(argv[1], "mmc", 3)) + mmcc = simple_strtoul(argv[1]+3, NULL, 10); + else + addr = simple_strtoul(argv[1], NULL, 16); + + if (argc > 2) + ptn = argv[2]; + + if (mmcc != -1) { +#ifdef CONFIG_MMC + struct fastboot_ptentry *pte; + struct mmc *mmc; + disk_partition_t info; + block_dev_desc_t *dev_desc = NULL; + unsigned sector; + unsigned bootimg_sectors; + + memset((void *)&info, 0 , sizeof(disk_partition_t)); + /* i.MX use MBR as partition table, so this will have + to find the start block and length for the + partition name and register the fastboot pte we + define the partition number of each partition in + config file + */ + mmc = find_mmc_device(mmcc); + if (!mmc) { + printf("boota: cannot find '%d' mmc device\n", mmcc); + goto fail; + } + dev_desc = get_dev("mmc", mmcc); + if (NULL == dev_desc) { + printf("** Block device MMC %d not supported\n", mmcc); + goto fail; + } + + /* below was i.MX mmc operation code */ + if (mmc_init(mmc)) { + printf("mmc%d init failed\n", mmcc); + goto fail; + } + + pte = fastboot_flash_find_ptn(ptn); + if (!pte) { + printf("boota: cannot find '%s' partition\n", ptn); + goto fail; + } + + if (mmc->block_dev.block_read(mmcc, pte->start, + 1, (void *)hdr) < 0) { + printf("boota: mmc failed to read bootimg header\n"); + goto fail; + } + + if (android_image_check_header(hdr)) { + printf("boota: bad boot image magic\n"); + goto fail; + } + + image_size = android_image_get_end(hdr) - (ulong)hdr; + bootimg_sectors = image_size/512; + +#ifdef CONFIG_SECURE_BOOT + /* Default boot.img should be padded to 0x1000 + before appended with IVT&CSF data. Set the threshold of + boot image for athendication as 16MB + */ + image_size += BOOTIMAGE_SIGNATURE_SIZE; + image_size = ALIGN(image_size, 0x1000); + if (image_size > MAX_ANDROID_BOOT_AUTH_SIZE) { + printf("The image size is too large for athenticated boot!\n"); + return 1; + } + /* Make sure all data boot.img + IVT + CSF been read to memory */ + bootimg_sectors = image_size/512 + + ALIGN(IVT_SIZE + CSF_PAD_SIZE, 512)/512; +#endif + + if (mmc->block_dev.block_read(mmcc, pte->start, + bootimg_sectors, + (void *)load_addr) < 0) { + printf("boota: mmc failed to read kernel\n"); + goto fail; + } + /* flush cache after read */ + flush_cache((ulong)load_addr, bootimg_sectors * 512); /* FIXME */ + + addr = load_addr; + +#ifdef CONFIG_SECURE_BOOT + extern uint32_t authenticate_image(uint32_t ddr_start, + uint32_t image_size); + + if (authenticate_image(load_addr, image_size)) { + printf("Authenticate OK\n"); + } else { + printf("Authenticate image Fail, Please check\n\n"); + return 1; + } +#endif /*CONFIG_SECURE_BOOT*/ + + sector = pte->start + (hdr->page_size / 512); + sector += ALIGN(hdr->kernel_size, hdr->page_size) / 512; + if (mmc->block_dev.block_read(mmcc, sector, + (hdr->ramdisk_size / 512) + 1, + (void *)hdr->ramdisk_addr) < 0) { + printf("boota: mmc failed to read ramdisk\n"); + goto fail; + } + /* flush cache after read */ + flush_cache((ulong)hdr->ramdisk_addr, hdr->ramdisk_size); /* FIXME */ + +#ifdef CONFIG_OF_LIBFDT + /* load the dtb file */ + if (hdr->second_size && hdr->second_addr) { + sector += ALIGN(hdr->ramdisk_size, hdr->page_size) / 512; + if (mmc->block_dev.block_read(mmcc, sector, + (hdr->second_size / 512) + 1, + (void *)hdr->second_addr) < 0) { + printf("boota: mmc failed to dtb\n"); + goto fail; + } + /* flush cache after read */ + flush_cache((ulong)hdr->second_addr, hdr->second_size); /* FIXME */ + } +#endif /*CONFIG_OF_LIBFDT*/ + +#else /*! CONFIG_MMC*/ + return -1; +#endif /*! CONFIG_MMC*/ + } else { + unsigned raddr, end; +#ifdef CONFIG_OF_LIBFDT + unsigned fdtaddr = 0; +#endif + + /* set this aside somewhere safe */ + memcpy(hdr, (void *)addr, sizeof(*hdr)); + + if (android_image_check_header(hdr)) { + printf("boota: bad boot image magic\n"); + return 1; + } + + bootimg_print_image_hdr(hdr); + + image_size = hdr->page_size + + ALIGN(hdr->kernel_size, hdr->page_size) + + ALIGN(hdr->ramdisk_size, hdr->page_size) + + ALIGN(hdr->second_size, hdr->page_size); + +#ifdef CONFIG_SECURE_BOOT + image_size = image_size + BOOTIMAGE_SIGNATURE_SIZE; + if (image_size > MAX_ANDROID_BOOT_AUTH_SIZE) { + printf("The image size is too large for athenticated boot!\n"); + return 1; + } +#endif /*CONFIG_SECURE_BOOT*/ + +#ifdef CONFIG_SECURE_BOOT + extern uint32_t authenticate_image(uint32_t ddr_start, + uint32_t image_size); + + if (authenticate_image(addr, image_size)) { + printf("Authenticate OK\n"); + } else { + printf("Authenticate image Fail, Please check\n\n"); + return 1; + } +#endif + + raddr = addr + hdr->page_size; + raddr += ALIGN(hdr->kernel_size, hdr->page_size); + end = raddr + hdr->ramdisk_size; +#ifdef CONFIG_OF_LIBFDT + if (hdr->second_size) { + fdtaddr = raddr + ALIGN(hdr->ramdisk_size, hdr->page_size); + end = fdtaddr + hdr->second_size; + } +#endif /*CONFIG_OF_LIBFDT*/ + + if (raddr != hdr->ramdisk_addr) { + /*check overlap*/ + if (((hdr->ramdisk_addr >= addr) && + (hdr->ramdisk_addr <= end)) || + ((addr >= hdr->ramdisk_addr) && + (addr <= hdr->ramdisk_addr + hdr->ramdisk_size))) { + printf("Fail: boota address overlap with ramdisk address\n"); + return 1; + } + memmove((void *) hdr->ramdisk_addr, + (void *)raddr, hdr->ramdisk_size); + } + +#ifdef CONFIG_OF_LIBFDT + if (hdr->second_size && fdtaddr != hdr->second_addr) { + /*check overlap*/ + if (((hdr->second_addr >= addr) && + (hdr->second_addr <= end)) || + ((addr >= hdr->second_addr) && + (addr <= hdr->second_addr + hdr->second_size))) { + printf("Fail: boota address overlap with FDT address\n"); + return 1; + } + memmove((void *) hdr->second_addr, + (void *)fdtaddr, hdr->second_size); + } +#endif /*CONFIG_OF_LIBFDT*/ + } + + printf("kernel @ %08x (%d)\n", hdr->kernel_addr, hdr->kernel_size); + printf("ramdisk @ %08x (%d)\n", hdr->ramdisk_addr, hdr->ramdisk_size); +#ifdef CONFIG_OF_LIBFDT + if (hdr->second_size) + printf("fdt @ %08x (%d)\n", hdr->second_addr, hdr->second_size); +#endif /*CONFIG_OF_LIBFDT*/ + +#ifdef CONFIG_SERIAL_TAG + struct tag_serialnr serialnr; + char bootargs[ANDR_BOOT_ARGS_SIZE]; + char *commandline = getenv("bootargs"); + get_board_serial(&serialnr); + + if (commandline) { + sprintf(bootargs, + "%s androidboot.serialno=%08x%08x", + commandline, + serialnr.high, + serialnr.low); + } else { + sprintf(bootargs, + "androidboot.serialno=%08x%08x", + serialnr.high, + serialnr.low); + } + setenv("bootargs", bootargs); +#endif + + char boot_addr_start[12]; + char ramdisk_addr[25]; + char fdt_addr[12]; + + char *bootm_args[] = { "bootm", boot_addr_start, ramdisk_addr, fdt_addr}; + + sprintf(boot_addr_start, "0x%lx", addr); + sprintf(ramdisk_addr, "0x%x:0x%x", hdr->ramdisk_addr, hdr->ramdisk_size); + sprintf(fdt_addr, "0x%x", hdr->second_addr); + + do_bootm(NULL, 0, 4, bootm_args); + + /* This only happens if image is somehow faulty so we start over */ + do_reset(NULL, 0, 0, NULL); + + return 1; + +fail: +#ifdef CONFIG_FSL_FASTBOOT + return run_command("fastboot", 0); +#else /*! CONFIG_FSL_FASTBOOT*/ + return -1; +#endif /*! CONFIG_FSL_FASTBOOT*/ +} + +U_BOOT_CMD( + boota, 3, 1, do_boota, + "boota - boot android bootimg from memory\n", + "[ | mmc0 | mmc1 | mmc2 | mmcX] []\n " + "- boot application image stored in memory or mmc\n" + "\t'addr' should be the address of boot image " + "which is zImage+ramdisk.img\n" + "\t'mmcX' is the mmc device you store your boot.img, " + "which will read the boot.img from 1M offset('/boot' partition)\n" + "\t 'partition' (optional) is the partition id of your device, " + "if no partition give, will going to 'boot' partition\n" +); +#endif /* CONFIG_CMD_BOOTA */ + + +#endif + + static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) @@ -441,6 +2138,40 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) fastboot_tx_write_str(response); printf("\ndownloading of %d bytes finished\n", download_bytes); + +#ifdef CONFIG_FSL_FASTBOOT +#ifdef CONFIG_FASTBOOT_STORAGE_NAND + /* Pad to block length + In most cases, padding the download to be + block aligned is correct. The exception is + when the following flash writes to the oob + area. This happens when the image is a + YAFFS image. Since we do not know what + the download is until it is flashed, + go ahead and pad it, but save the true + size in case if should have + been unpadded */ + download_bytes_unpadded = download_bytes; + if (interface.nand_block_size) { + if (download_bytes % + interface.nand_block_size) { + unsigned int pad = + interface.nand_block_size - + (download_bytes % interface.nand_block_size); + unsigned int i; + + for (i = 0; i < pad; i++) { + if (download_bytes >= + interface.transfer_buffer_size) + break; + + interface.transfer_buffer[download_bytes] = 0; + download_bytes++; + } + } + } +#endif +#endif } else { max = is_high_speed ? hs_ep_out.wMaxPacketSize : fs_ep_out.wMaxPacketSize; @@ -485,7 +2216,11 @@ static void cb_download(struct usb_ep *ep, struct usb_request *req) static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) { char boot_addr_start[12]; +#ifdef CONFIG_FSL_FASTBOOT + char *bootm_args[] = { "boota", boot_addr_start, NULL }; +#else char *bootm_args[] = { "bootm", boot_addr_start, NULL }; +#endif puts("Booting kernel..\n"); @@ -527,10 +2262,15 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req) } strcpy(response, "FAILno flash device defined"); + +#ifdef CONFIG_FSL_FASTBOOT + rx_process_flash(cmd, response); +#else #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV fb_mmc_flash_write(cmd, (void *)CONFIG_USB_FASTBOOT_BUF_ADDR, download_bytes, response); #endif +#endif fastboot_tx_write_str(response); } #endif @@ -538,7 +2278,7 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req) static void cb_oem(struct usb_ep *ep, struct usb_request *req) { char *cmd = req->buf; -#ifdef CONFIG_FASTBOOT_FLASH +#if defined(CONFIG_FASTBOOT_FLASH) && defined(CONFIG_FASTBOOT_FLASH_MMC_DEV) if (strncmp("format", cmd + 4, 6) == 0) { char cmdbuf[32]; sprintf(cmdbuf, "gpt write mmc %x $partitions", @@ -572,9 +2312,13 @@ static void cb_erase(struct usb_ep *ep, struct usb_request *req) strcpy(response, "FAILno flash device defined"); +#ifdef CONFIG_FSL_FASTBOOT + rx_process_erase(cmd, response); +#else #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV fb_mmc_erase(cmd, response); #endif +#endif fastboot_tx_write_str(response); } #endif -- cgit v1.1