blob: 62465896db9beee89d7c7da6ad8c8278ecde87e0 [file] [log] [blame]
/*
* 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",
""
);