ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/uboot/common/cmd_fastboot.c b/marvell/uboot/common/cmd_fastboot.c
new file mode 100644
index 0000000..6246589
--- /dev/null
+++ b/marvell/uboot/common/cmd_fastboot.c
@@ -0,0 +1,887 @@
+/*
+ * 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.
+ */
+
+/*
+ * Copyright (c) 2010 Marvell Inc.
+ * Modified by Lei Wen <leiwen@marvell.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * ported from m2011.09 by yizhang@marvell.com, 28-Mar-2014
+ */
+#include <common.h>
+#include <fastboot.h>
+#include <sparse_format.h>
+#include <jffs2/load_kernel.h>
+#include <linux/mtd/mtd.h>
+#include <mmc.h>
+#include <malloc.h>
+
+#ifdef CONFIG_MRVL_BOOT
+#include <mv_boot.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+#define SECTOR_SIZE 512
+
+#ifdef CONFIG_TEE_OS
+#define FB_BUFF_ADDR 0x2800000 /* 40MB offset */
+#else
+#define FB_BUFF_ADDR 0x2000000 /* 32MB offset */
+#endif
+
+enum fb_dev {
+ FB_INVALID = 0,
+ FB_NOR = MTD_DEV_TYPE_NOR,
+ FB_NAND = MTD_DEV_TYPE_NAND,
+ FB_ONENAND = MTD_DEV_TYPE_ONENAND,
+ FB_SPIFLASH,
+ FB_MMC,
+ FB_MAX,
+};
+
+#ifndef CONFIG_FB_RESV
+#define CONFIG_FB_RESV 64
+#endif
+
+#define MAX_NAME_NUM 36
+#define UDC_OUT_PACKET_SIZE 0x200
+block_dev_desc_t *mmc_dev;
+static char commands[CONFIG_SYS_CBSIZE];
+/* For each part has four attributes:
+ * device type, device num, start address, size
+ */
+struct fb_part {
+ char name[MAX_NAME_NUM];
+#define PART_ATTR_YAFFS 1
+#define PART_NUM_MASK 0xE0000000
+#define PART_NUM(x) (((x) & PART_NUM_MASK) >> 29)
+ unsigned int attr;
+ unsigned long long start;
+ unsigned long long size;
+};
+
+struct fb_parts {
+ enum fb_dev dev;
+ int dev_num;
+ int part_num;
+ int align_len;
+ struct fb_part *part;
+};
+
+static struct fb_parts *parts;
+#ifdef CONFIG_MTD_DEVICE
+#ifdef CONFIG_SYS_FB_YAFFS
+static char *part_yaffs[] = CONFIG_SYS_FB_YAFFS;
+#else
+static char *part_yaffs[] = {NULL};
+#endif
+#endif
+
+static char *rcv_buf;
+static unsigned fb_mem, ramdisk_addr, ramdisk_size, kernel_addr, kernel_size;
+static int keep_running, is_yaffs, part_num, onfly;
+static int bootsp, first_rcv, need_unsparse;
+
+#define BOOT_MAGIC "ANDROID!"
+#define BOOT_MAGIC_SIZE 8
+#define BOOT_NAME_SIZE 16
+#define BOOT_ARGS_SIZE 512
+
+struct boot_img_hdr {
+ unsigned char magic[BOOT_MAGIC_SIZE];
+
+ unsigned kernel_size; /* size in bytes */
+ unsigned kernel_addr; /* physical load addr */
+
+ unsigned ramdisk_size; /* size in bytes */
+ unsigned ramdisk_addr; /* physical load addr */
+
+ unsigned second_size; /* size in bytes */
+ unsigned second_addr; /* physical load addr */
+
+ unsigned tags_addr; /* physical addr for kernel tags */
+ unsigned page_size; /* flash page size we assume */
+ unsigned unused[2]; /* future expansion: should be 0 */
+
+ unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
+
+ unsigned char cmdline[BOOT_ARGS_SIZE];
+
+ unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+static unsigned rx_addr;
+static unsigned rx_length;
+static unsigned long long flash_start;
+static unsigned long long flash_len;
+
+static int init_boot_linux(void)
+{
+ struct boot_img_hdr *hdr = (void *)(uintptr_t)fb_mem;
+ unsigned page_mask = 2047;
+ unsigned kernel_actual;
+ unsigned ramdisk_actual;
+ unsigned second_actual;
+
+ if (kernel_size < 2048) {
+ printf("bootimg: bad header, kernel_size is wrong\n");
+ return -1;
+ }
+
+ if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+ printf("bootimg: bad header\n");
+ return -1;
+ }
+
+ if (hdr->page_size != 2048) {
+ printf("bootimg: invalid page size\n");
+ return -1;
+ }
+
+ kernel_actual = (hdr->kernel_size + page_mask) & (~page_mask);
+ ramdisk_actual = (hdr->ramdisk_size + page_mask) & (~page_mask);
+ second_actual = (hdr->second_size + page_mask) & (~page_mask);
+
+ if (kernel_size !=
+ (kernel_actual + ramdisk_actual + second_actual + 2048)) {
+ printf("bootimg: invalid image size");
+ return -1;
+ }
+
+ /* XXX process commandline here */
+ if (hdr->cmdline[0]) {
+ hdr->cmdline[BOOT_ARGS_SIZE - 1] = 0;
+ printf("cmdline is: %s\n", hdr->cmdline);
+ setenv("bootargs", (char *)hdr->cmdline);
+ }
+
+ /* XXX how to validate addresses? */
+ kernel_addr = (uintptr_t)hdr + 2048;
+ kernel_size = hdr->kernel_size;
+ ramdisk_size = hdr->ramdisk_size;
+ if (ramdisk_size > 0)
+ ramdisk_addr = kernel_addr + 2048 + kernel_size;
+ else
+ ramdisk_addr = 0;
+
+ printf("bootimg: kernel addr=0x%x size=0x%x\n",
+ kernel_addr, kernel_size);
+ printf("bootimg: ramdisk addr=0x%x size=0x%x\n",
+ ramdisk_addr, ramdisk_size);
+
+ return 0;
+}
+
+static int composite_command(int is_write)
+{
+ char tmp[CONFIG_SYS_CBSIZE];
+ ulong start, len;
+
+ if (need_unsparse) {
+ need_unsparse = 0;
+ sprintf(commands,
+ "mmc dev %d 0; unsparse mmc %d 0x%x 0x%llx 0x%llx",
+ parts->dev_num, parts->dev_num,
+ fb_mem, flash_start, parts->part[part_num].size);
+ goto DIRECT_BURN;
+ }
+
+ start = (parts->dev == FB_MMC)
+ ? flash_start / SECTOR_SIZE : flash_start;
+ len = (parts->dev == FB_MMC) ? flash_len / SECTOR_SIZE : flash_len;
+ if (is_write) {
+ if (is_yaffs)
+ sprintf(tmp, "write.yaffs 0x%x 0x%lx 0x%lx",
+ fb_mem, start, len);
+ else
+ sprintf(tmp, "write 0x%x 0x%lx 0x%lx",
+ fb_mem, start, len);
+ } else {
+ sprintf(tmp, "erase 0x%lx 0x%lx", start, len);
+ }
+
+ switch (parts->dev) {
+ case FB_NOR:
+ sprintf(commands, "sf %s", tmp); break;
+ case FB_NAND:
+#ifdef CONFIG_PXA182X
+ sprintf(commands, "nand device %d; nand %s",
+ parts->dev_num, tmp);
+#else
+ sprintf(commands, "spi_flash %s", tmp);
+#endif
+ break;
+ case FB_ONENAND:
+ sprintf(commands, "onenand %s", tmp); break;
+ case FB_SPIFLASH:
+ sprintf(commands, "spi_flash %s",
+ parts->dev_num, tmp); break;
+ case FB_MMC:
+ sprintf(commands, "mmc dev %d %d; mmc %s; mmc dev %d 0",
+ parts->dev_num, PART_NUM(parts->part[part_num].attr),
+ tmp, parts->dev_num);
+ break;
+ default:
+ printf("Err dev!! %d\n", parts->dev);
+ return 0;
+ }
+
+DIRECT_BURN:
+ printf("command::%s\n", commands);
+ run_command(commands, 0);
+ return 0;
+}
+
+static void burn_image(int force_burn)
+{
+ int len = rx_addr - fb_mem;
+ int checklen = (is_yaffs) ? ((CONFIG_SYS_FASTBOOT_ONFLY_SZ / 32) * 33)
+ : CONFIG_SYS_FASTBOOT_ONFLY_SZ;
+ if (len == checklen || force_burn) {
+ if (!is_yaffs) {
+ flash_len = len & ~(parts->align_len - 1);
+ if (flash_len != len) {
+ flash_len += parts->align_len;
+ memset((char *)(uintptr_t)rx_addr, 0xff,
+ flash_len - len);
+ }
+ } else {
+ flash_len = len;
+ }
+ composite_command(1);
+ flash_start += CONFIG_SYS_FASTBOOT_ONFLY_SZ;
+ fb_set_buf((void *)(uintptr_t)fb_mem);
+ rx_addr = fb_mem;
+ }
+}
+
+static int check_part(char *name)
+{
+ int i;
+ for (i = 0; i < parts->part_num; i++) {
+ if (strcmp(name, parts->part[i].name) == 0)
+ break;
+ }
+ if (i == parts->part_num) {
+ printf("!!!!!!!!!!There is no such part!\n");
+ fb_tx_status("FAILno such part");
+ return -1;
+ }
+
+ return i;
+}
+
+static int find_devnum(const char *p)
+{
+ int devnum;
+ if (*p == '\0') {
+ printf("no partition number specified\n");
+ return -1;
+ }
+ devnum = simple_strtoul(p, (char **)&p, 0);
+ if (*p != '\0') {
+ printf("unexpected trailing character '%c'\n", *p);
+ return -1;
+ }
+ return devnum;
+}
+
+static int init_partitions(void)
+{
+ struct mmc *mmc;
+ int i, pnum = 0;
+ disk_partition_t info;
+ const char *p;
+
+ mmc_dev = NULL;
+ p = getenv("fbenv");
+ if (0 == strncmp(p, "mmc", 3)) {
+#ifdef CONFIG_MMC
+ parts = malloc(sizeof(struct fb_parts));
+ if (!parts) {
+ printf("Out of memory %s:%d\n", __func__, __LINE__);
+ return 1;
+ }
+ i = find_devnum(p + 3);
+ if (i == -1)
+ return 1;
+ mmc = find_mmc_device(i);
+ if (!mmc)
+ return 1;
+ mmc_init(mmc);
+ parts->part_num = 0;
+ parts->part = 0;
+ parts->align_len = SECTOR_SIZE;
+ parts->dev = FB_MMC;
+ parts->dev_num = i;
+ mmc_dev = mmc_get_dev(i);
+ pnum = get_partition_num(mmc_dev);
+ if (pnum) {
+ parts->part = malloc(sizeof(struct fb_part)*pnum);
+ if (!parts->part) {
+ printf("Out of memory %s:%d\n", __func__, __LINE__);
+ return 1;
+ }
+ } else {
+ parts->part = NULL;
+ }
+ parts->part_num = pnum;
+ if (mmc_dev != NULL && mmc_dev->type != DEV_TYPE_UNKNOWN) {
+ for (i = 1; i <= pnum; i++) {
+ int len;
+ if (get_partition_info(mmc_dev, i, &info))
+ break;
+ len = strlen((char *)info.name);
+ len = (len < MAX_NAME_NUM)
+ ? len : MAX_NAME_NUM - 1;
+ memcpy(parts->part[i - 1].name, info.name, len);
+ parts->part[i - 1].name[len] = 0;
+ parts->part[i - 1].start =
+ (unsigned long long)info.start * info.blksz;
+ parts->part[i - 1].size =
+ (unsigned long long)info.size * info.blksz;
+ parts->part[i - 1].attr = 0;
+ }
+ }
+#else
+ printf("CONFIG_MMC not be defined!!\n");
+ return 1;
+#endif
+ } else {
+#ifdef CONFIG_MTD_DEVICE
+ enum fb_dev type;
+ struct mtd_device *dev;
+ struct part_info *part;
+ int j, align;
+ if (mtdparts_init()) {
+ printf("mtd part init fail!\n");
+ return 1;
+ }
+ if (0 == strncmp(p, "nand", 4)) {
+ p += 4;
+ type = FB_NAND;
+ align = CONFIG_SYS_FASTBOOT_ONFLY_SZ;
+ } else if (0 == strncmp(p, "onenand", 4)) {
+ p += 7;
+ type = FB_ONENAND;
+ align = CONFIG_SYS_FASTBOOT_ONFLY_SZ;
+ } else if (0 == strncmp(p, "nor", 3)) {
+ p += 3;
+ type = FB_NOR;
+ align = 1;
+ } else if (0 == strncmp(p, "spi_flash", 9)) {
+ p += 9;
+ type = MTD_DEV_TYPE_NAND;
+ align = CONFIG_SYS_FASTBOOT_ONFLY_SZ;
+ } else {
+ printf("fbenv must de defined!!");
+ return 1;
+ }
+
+ i = find_devnum(p);
+ if (i == -1)
+ return 1;
+
+ dev = device_find(type, i);
+ if (dev == NULL) {
+ printf("There is no device as %s\n", getenv("fbenv"));
+ return 1;
+ }
+ if (!dev->num_parts) {
+ printf("Dev num parts is 0\n");
+ return 1;
+ }
+ parts = malloc(sizeof(struct fb_parts));
+ if (!parts) {
+ printf("Out of memory %s:%d\n", __func__, __LINE__);
+ return 1;
+ }
+ parts->part = malloc(sizeof(struct fb_part)*dev->num_parts);
+ if (!parts->part) {
+ printf("Out of memory %s:%d\n", __func__, __LINE__);
+ return 1;
+ }
+ parts->dev = type;
+ parts->dev_num = i;
+ parts->part_num = dev->num_parts;
+ parts->align_len = align;
+ pnum = dev->num_parts;
+ for (i = 0; i < dev->num_parts; i++) {
+ part = mtd_part_info(dev, i);
+ if (part) {
+ int len;
+ len = strlen((char *)part->name);
+ len = (len < MAX_NAME_NUM)
+ ? len : MAX_NAME_NUM - 1;
+ memcpy(parts->part[i].name, part->name, len);
+ parts->part[i].name[len] = 0;
+ parts->part[i].start = part->offset;
+ parts->part[i].size = part->size;
+ parts->part[i].attr = 0;
+ for (j = 0; j < ARRAY_SIZE(part_yaffs); j++)
+ if (!memcmp(part_yaffs[j], part->name,
+ strlen(part->name))) {
+ parts->part[i].attr =
+ PART_ATTR_YAFFS;
+ break;
+ }
+ } else {
+ printf("fail to find part: %s\n", part->name);
+ return 1;
+ }
+ }
+#else
+ printf("CONFIG_MTD_DEVICE not be defined!!\n");
+ return 1;
+#endif
+ }
+
+ switch (parts->dev) {
+ case FB_NOR:
+ printf("nor\n"); break;
+ case FB_NAND:
+ printf("nand\n"); break;
+ case FB_ONENAND:
+ printf("onenand\n"); break;
+ case FB_MMC:
+ printf("mmc\n"); break;
+ case FB_SPIFLASH:
+ printf("spi_flash\n"); break;
+ default:
+ printf("error!!!\n"); break;
+ }
+ for (i = 0; i < pnum; i++)
+ printf("part %3d::attr 0x%x::%12s\t start 0x%08llx, size 0x%08llx\n",
+ i, parts->part[i].attr, parts->part[i].name, parts->part[i].start, parts->part[i].size);
+ return 0;
+}
+
+static int modify_part(char *name, unsigned long long x[3])
+{
+ int len = strlen(name);
+ parts->part = realloc(parts->part,
+ sizeof(struct fb_part)*(parts->part_num + 1));
+ if (!parts->part) {
+ printf("Out of memory %s:%d\n", __func__, __LINE__);
+ return 1;
+ }
+ len = (len < MAX_NAME_NUM) ? len : MAX_NAME_NUM - 1;
+ memcpy(parts->part[parts->part_num].name, name, len);
+ parts->part[parts->part_num].name[len] = 0;
+ parts->part[parts->part_num].attr = (unsigned int)x[0];
+ parts->part[parts->part_num].start = x[1];
+ parts->part[parts->part_num].size = x[2];
+ parts->part_num++;
+
+ return 0;
+}
+/* for test */
+/*
+#define RAMDISK_LOADADDR 0x2000000
+#define BOOTIMG_EMMC_ADDR 0x1000000
+#define CONFIG_MMC_BOOT_DEV "mmc dev 2 0"
+*/
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+static int mkbootimg(void *kernel, unsigned kernel_size)
+{
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ unsigned long ramdisk_addr = RAMDISK_LOADADDR;
+#endif
+ struct boot_img_hdr *hdr = (struct boot_img_hdr *)kernel;
+ struct boot_img_hdr *ahdr = (void *)ramdisk_addr;
+ unsigned ramdisk_offsize;
+ char cmd[128];
+ unsigned long base_addr = BOOTIMG_EMMC_ADDR;
+ base_addr /= SECTOR_SIZE;
+
+ /* If the burning image is not bootimg or already have ramdisk*/
+ if (memcmp(BOOT_MAGIC, hdr->magic, BOOT_MAGIC_SIZE) ||
+ hdr->ramdisk_size) {
+ return 0;
+ }
+
+ /* parse the raw image header and read the ramdisk to memory*/
+ sprintf(cmd, "%s; mmc read %lx %lx 0x8",
+ CONFIG_MMC_BOOT_DEV, ramdisk_addr, base_addr);
+ run_command(cmd, 0);
+ if (!memcmp(BOOT_MAGIC, ahdr->magic, BOOT_MAGIC_SIZE) &&
+ ahdr->ramdisk_size) {
+ hdr->ramdisk_size = ahdr->ramdisk_size;
+ ramdisk_offsize = ALIGN(ahdr->kernel_size, ahdr->page_size)
+ + ahdr->page_size;
+ ramdisk_offsize = ramdisk_offsize / SECTOR_SIZE;
+
+ sprintf(cmd, "%s; mmc read 0x%08lx %lx 0x06000",
+ CONFIG_MMC_BOOT_DEV, ramdisk_addr, base_addr + ramdisk_offsize);
+ run_command(cmd, 0);
+ } else {
+ /*In the flash, there is no boot.img*/
+ return 0;
+ }
+ /*write ramdisk.img to flash */
+ ramdisk_offsize = hdr->page_size + ALIGN(hdr->kernel_size, hdr->page_size);
+ ramdisk_offsize = ramdisk_offsize / SECTOR_SIZE;
+ sprintf(cmd, "%s; mmc write %lx %lx 0x06000",
+ CONFIG_MMC_BOOT_DEV, ramdisk_addr, base_addr + ramdisk_offsize);
+ run_command(cmd, 0);
+ return 1;
+}
+#endif
+#define MAX_RESP_SZ 64
+void rcv_cmd(void)
+{
+ char status[MAX_RESP_SZ];
+ int len;
+ static char *cmdbuf;
+
+ len = fb_get_rcv_len();
+ cmdbuf = (char *)fb_get_buf();
+
+ if (rx_length) {
+ if (rx_length > len) {
+ rx_length -= len;
+ rx_addr += len;
+ } else {
+ printf("rx_length: 0x%x\n", rx_length);
+ rx_addr += rx_length;
+ rx_length = 0;
+ }
+
+ fb_set_buf(cmdbuf + len);
+ /* Here we do some check for the downloaded image header */
+#ifdef CONFIG_CMD_UNSPARSE
+ if (first_rcv) {
+ sparse_header_t *header;
+
+ first_rcv = 0;
+ header = (sparse_header_t *)(uintptr_t)fb_mem;
+ if (header->magic == SPARSE_HEADER_MAGIC) {
+ if (parts->dev == FB_MMC) {
+ if (onfly)
+ onfly = 0;
+ need_unsparse = 1;
+ } else {
+ printf("Only mmc support sparsed Image now!\n");
+ }
+ }
+ }
+#endif
+ if (!rx_length) {
+ if (onfly)
+ burn_image(1);
+ fb_tx_status("OKAY");
+ fb_set_buf(rcv_buf);
+ onfly = 0;
+ } else {
+ if (onfly)
+ burn_image(0);
+ }
+
+ return;
+ }
+ if (len >= UDC_OUT_PACKET_SIZE)
+ len = UDC_OUT_PACKET_SIZE - 1;
+ cmdbuf[len] = 0;
+
+ printf("\n> %s\n", cmdbuf);
+
+ if (memcmp(cmdbuf, "download:", 9) == 0) {
+ rx_addr = fb_mem;
+ first_rcv = 1;
+ fb_set_buf((void *)(uintptr_t)rx_addr);
+ rx_length = simple_strtoul(cmdbuf + 9, NULL, 16);
+ if ((onfly && (rx_length > flash_len)) ||
+ (!onfly && (rx_length > (CONFIG_FB_RESV*1024*1024)))) {
+ fb_tx_status("FAILdata too large");
+ rx_length = 0;
+ return;
+ }
+ kernel_size = rx_length;
+ printf("recv data addr=%x size=%x\n", rx_addr, rx_length);
+ strcpy(status, "DATA");
+ sprintf(status + 4, "%08x", rx_length);
+ fb_tx_status(status);
+ return;
+ }
+
+ if (memcmp(cmdbuf, "boot", 4) == 0) {
+ if (init_boot_linux()) {
+ fb_tx_status("FAIL invalid boot image");
+ } else {
+ printf("booting linux...\n");
+ fb_tx_status("OKAY");
+ if (!bootsp) {
+#ifdef CONFIG_MRVL_BOOT
+ image_load_notify(kernel_addr);
+ sprintf(status, "boot");
+#else
+ if (ramdisk_size > 0) {
+ printf("kernel_addr = 0x%x, ramdisk_addr = 0x%x, ramdisk_size = 0x%x",
+ kernel_addr, ramdisk_addr, ramdisk_size);
+ sprintf(status, "bootm 0x%x 0x%x 0x%x",
+ kernel_addr, ramdisk_addr, ramdisk_size);
+ } else {
+ printf("kernel_addr = 0x%x\n", kernel_addr);
+ sprintf(status, "bootm 0x%x", kernel_addr);
+ }
+#endif
+ } else {
+ sprintf(status, "go 0x%x", kernel_addr);
+ }
+
+ printf("cmd:%s\n", status);
+ run_command(status, 0);
+ fb_tx_status("FAILNot zImage, use bootsp oem cmd to boot special app");
+ }
+ return;
+ }
+ onfly = 0;
+ bootsp = 0;
+ if (memcmp(cmdbuf, "flash", 5) == 0) {
+ int ret = 0;
+ if (rx_addr > fb_mem) {
+ part_num = check_part(cmdbuf + 6);
+ if (part_num < 0)
+ return;
+ is_yaffs = parts->part[part_num].attr & PART_ATTR_YAFFS;
+ flash_start = parts->part[part_num].start;
+ flash_len = parts->part[part_num].size;
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ if (mkbootimg((void *)(uintptr_t)fb_mem, kernel_size))
+ flash_len = kernel_size;
+#endif
+ if ((rx_addr - fb_mem) > flash_len) {
+ fb_tx_status("FAILdata too large");
+ return;
+ }
+ burn_image(1);
+ }
+ is_yaffs = 0;
+ if (!ret)
+ fb_tx_status("OKAY");
+ return;
+ }
+
+ if (memcmp(cmdbuf, "senddata", 8) == 0) {
+ int i, ret;
+ char *p;
+
+ ret = sprintf(status, "OKAY");
+ p = status + ret;
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ if (!gd->bd->bi_dram[i].size)
+ continue;
+
+ ret = sprintf(p, "%lx:%lx:",
+ gd->bd->bi_dram[i].start, gd->bd->bi_dram[i].size);
+ p += ret;
+ }
+
+ fb_tx_status(status);
+ return;
+ }
+
+ if (memcmp(cmdbuf, "upload", 6) == 0) {
+ char *s = cmdbuf + 6, *p;
+ unsigned long upload_start, upload_sz;
+
+ p = strchr(s, ':');
+ if (!p) {
+ fb_tx_status("FAILno valid start pos");
+ return;
+ }
+ *p = 0;
+ upload_start = simple_strtoul(s, (char **)&s, 16);
+ s = p + 1;
+ p = strchr(s, ':');
+ if (!p) {
+ fb_tx_status("FAILno valid start pos");
+ return;
+ }
+ *p = 0;
+ upload_sz = simple_strtoul(s, (char **)&s, 16);
+ if (!upload_sz) {
+ fb_tx_status("FAILno valid upload sz");
+ return;
+ }
+
+ fb_tx_data((void *)upload_start, upload_sz);
+ return;
+ }
+
+ if (memcmp(cmdbuf, "erase", 5) == 0) {
+ part_num = check_part(cmdbuf + 6);
+ if (part_num < 0)
+ return;
+ flash_start = parts->part[part_num].start;
+ flash_len = parts->part[part_num].size;
+ composite_command(0);
+ fb_tx_status("OKAY");
+ return;
+ }
+
+ if (memcmp(cmdbuf, "oem", 3) == 0) {
+ if (memcmp(cmdbuf + 4, "onfly", 5) == 0) {
+ onfly = 0;
+ part_num = check_part(cmdbuf + 10);
+ if (part_num < 0)
+ return;
+ is_yaffs = parts->part[part_num].attr & PART_ATTR_YAFFS;
+ flash_start = parts->part[part_num].start;
+ flash_len = parts->part[part_num].size;
+ onfly = 1;
+ fb_tx_status("OKAY");
+ return;
+ }
+ if (memcmp(cmdbuf + 4, "bootsp", 6) == 0) {
+ bootsp = 1;
+ fb_tx_status("OKAY");
+ return;
+ }
+ if (memcmp(cmdbuf + 4, "setno", 5) == 0) {
+ char *s = cmdbuf + 4, *p;
+ p = strchr(s, ':');
+ s = p + 1;
+ if (!p || !s) {
+ fb_tx_status("FAILno valid serial no");
+ return;
+ }
+ setenv("fb_serial", s);
+ fb_tx_status("OKAY");
+ fb_init();
+ return;
+ }
+ if (memcmp(cmdbuf + 4, "part", 4) == 0) {
+ unsigned int i;
+ unsigned long long x[3];
+ char *s = cmdbuf + 8, *p, *name;
+ p = strchr(s, ':');
+ if (p) {
+ s = p + 1;
+ p = strchr(s, ':');
+ *p = 0;
+ name = s;
+ if (!name) {
+ fb_tx_status("FAILno name specified");
+ return;
+ }
+ s = p + 1;
+ for (i = 0; i < 3 && s; i++) {
+ p = strchr(s, ':');
+ if (p)
+ *p = 0;
+ x[i] = simple_strtoull(s,
+ (char **)&s, 0);
+ if (p)
+ s = p + 1;
+ else
+ break;
+ }
+ if (i == 2) {
+ if (modify_part(name, x)) {
+ fb_tx_status("FAILadd part error");
+ return;
+ } else {
+ fb_tx_status("OKAY");
+ return;
+ }
+ }
+ }
+
+ i = 0;
+ init_partitions();
+ sprintf(status, "INFO::there %s %d partition",
+ (parts->part_num == 1) ? "is" : "are",
+ parts->part_num);
+ fb_tx_status(status);
+ do {
+ strcpy(status, "INFO");
+ status[4] = '\0';
+ for (; i < parts->part_num; i++) {
+ strcat(status, parts->part[i].name);
+ strcat(status, ",");
+ if ((i == (parts->part_num - 1)) ||
+ (strlen(status) + strlen(parts->part[i + 1].name) >= (MAX_RESP_SZ - 1))) {
+ i++;
+ fb_tx_status(status);
+ break;
+ }
+ }
+ } while (i < parts->part_num);
+ fb_tx_status("OKAY");
+ return;
+ }
+ fb_tx_status("FAILbad oem command");
+ return;
+ }
+ if (memcmp(cmdbuf, "reboot", 6) == 0) {
+ fb_tx_status("OKAY");
+ if (strncmp(cmdbuf + 6, "-bootloader", 11) == 0)
+ keep_running = 0;
+ else
+ reset_cpu(0);
+ return;
+ }
+
+ fb_tx_status("FAILinvalid command");
+}
+
+int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ALLOC_CACHE_ALIGN_BUFFER(char, cmd_pool, 512);
+ rx_length = 0;
+ part_num = -1;
+ onfly = 0;
+ bootsp = 0;
+ first_rcv = 0;
+ fb_mem = FB_BUFF_ADDR;
+ ramdisk_size = 0;
+ kernel_addr = 0;
+ kernel_size = 0;
+ keep_running = 1;
+ is_yaffs = 0;
+ need_unsparse = 0;
+
+ init_partitions();
+
+ rcv_buf = cmd_pool;
+ fb_init();
+ fb_set_buf((void *)rcv_buf);
+ while (keep_running)
+ fb_run();
+ keep_running = 1;
+ fb_halt();
+ return 0;
+}
+
+U_BOOT_CMD(
+ fb, 1, 1, do_fastboot,
+ "android fastboot client application",
+ ""
+ );