summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/cpu/armv7/mx6/soc.c113
-rw-r--r--arch/arm/cpu/armv7/mx7/soc.c60
-rw-r--r--arch/arm/include/asm/imx-common/boot_mode.h2
-rw-r--r--board/freescale/common/Makefile3
-rw-r--r--board/freescale/common/recovery.c78
-rw-r--r--cmd/fastboot/Kconfig38
-rw-r--r--common/board_r.c25
-rw-r--r--common/image-android.c41
-rw-r--r--common/image-fdt.c31
-rw-r--r--drivers/usb/gadget/f_fastboot.c1766
-rw-r--r--include/fsl_fastboot.h172
-rw-r--r--include/image.h4
-rw-r--r--include/recovery.h20
13 files changed, 2348 insertions, 5 deletions
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c
index 6d46713..b76d9a9 100644
--- a/arch/arm/cpu/armv7/mx6/soc.c
+++ b/arch/arm/cpu/armv7/mx6/soc.c
@@ -22,6 +22,10 @@
#include <dm.h>
#include <imx_thermal.h>
#include <mmc.h>
+#if defined(CONFIG_FSL_FASTBOOT) && defined(CONFIG_ANDROID_RECOVERY)
+#include <recovery.h>
+#endif
+
enum ldo_reg {
LDO_ARM,
@@ -657,6 +661,19 @@ int board_postclk_init(void)
return 0;
}
+#ifdef CONFIG_SERIAL_TAG
+void get_board_serial(struct tag_serialnr *serialnr)
+{
+ struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
+ struct fuse_bank *bank = &ocotp->bank[0];
+ struct fuse_bank0_regs *fuse =
+ (struct fuse_bank0_regs *)bank->fuse_regs;
+
+ serialnr->low = fuse->uid_low;
+ serialnr->high = fuse->uid_high;
+}
+#endif
+
#if defined(CONFIG_FEC_MXC)
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
{
@@ -713,6 +730,49 @@ const struct boot_mode soc_boot_modes[] = {
{NULL, 0},
};
+enum boot_device get_boot_device(void)
+{
+ enum boot_device boot_dev = UNKNOWN_BOOT;
+ uint soc_sbmr = readl(SRC_BASE_ADDR + 0x4);
+ uint bt_mem_ctl = (soc_sbmr & 0x000000FF) >> 4 ;
+ uint bt_mem_type = (soc_sbmr & 0x00000008) >> 3;
+ uint bt_dev_port = (soc_sbmr & 0x00001800) >> 11;
+
+ switch (bt_mem_ctl) {
+ case 0x0:
+ if (bt_mem_type)
+ boot_dev = ONE_NAND_BOOT;
+ else
+ boot_dev = WEIM_NOR_BOOT;
+ break;
+ case 0x2:
+ boot_dev = SATA_BOOT;
+ break;
+ case 0x3:
+ if (bt_mem_type)
+ boot_dev = I2C_BOOT;
+ else
+ boot_dev = SPI_NOR_BOOT;
+ break;
+ case 0x4:
+ case 0x5:
+ boot_dev = bt_dev_port + SD1_BOOT;
+ break;
+ case 0x6:
+ case 0x7:
+ boot_dev = bt_dev_port + MMC1_BOOT;
+ break;
+ case 0x8 ... 0xf:
+ boot_dev = NAND_BOOT;
+ break;
+ default:
+ boot_dev = UNKNOWN_BOOT;
+ break;
+ }
+
+ return boot_dev;
+}
+
void set_wdog_reset(struct wdog_regs *wdog)
{
u32 reg = readw(&wdog->wcr);
@@ -994,3 +1054,56 @@ void finish_anatop_bypass(void)
set_arm_freq_400M(false);
}
#endif
+
+#ifdef CONFIG_FSL_FASTBOOT
+
+#ifdef CONFIG_ANDROID_RECOVERY
+#define ANDROID_RECOVERY_BOOT (1 << 7)
+/* check if the recovery bit is set by kernel, it can be set by kernel
+ * issue a command '# reboot recovery' */
+int recovery_check_and_clean_flag(void)
+{
+ int flag_set = 0;
+ u32 reg;
+ reg = readl(SNVS_BASE_ADDR + SNVS_LPGPR);
+
+ flag_set = !!(reg & ANDROID_RECOVERY_BOOT);
+ printf("check_and_clean: reg %x, flag_set %d\n", reg, flag_set);
+ /* clean it in case looping infinite here.... */
+ if (flag_set) {
+ reg &= ~ANDROID_RECOVERY_BOOT;
+ writel(reg, SNVS_BASE_ADDR + SNVS_LPGPR);
+ }
+
+ return flag_set;
+}
+#endif /*CONFIG_ANDROID_RECOVERY*/
+
+#define ANDROID_FASTBOOT_BOOT (1 << 8)
+/* check if the recovery bit is set by kernel, it can be set by kernel
+ * issue a command '# reboot fastboot' */
+int fastboot_check_and_clean_flag(void)
+{
+ int flag_set = 0;
+ u32 reg;
+
+ reg = readl(SNVS_BASE_ADDR + SNVS_LPGPR);
+
+ flag_set = !!(reg & ANDROID_FASTBOOT_BOOT);
+
+ /* clean it in case looping infinite here.... */
+ if (flag_set) {
+ reg &= ~ANDROID_FASTBOOT_BOOT;
+ writel(reg, SNVS_BASE_ADDR + SNVS_LPGPR);
+ }
+
+ return flag_set;
+}
+
+void fastboot_enable_flag(void)
+{
+ setbits_le32(SNVS_BASE_ADDR + SNVS_LPGPR,
+ ANDROID_FASTBOOT_BOOT);
+}
+#endif /*CONFIG_FSL_FASTBOOT*/
+
diff --git a/arch/arm/cpu/armv7/mx7/soc.c b/arch/arm/cpu/armv7/mx7/soc.c
index 8202145..332d977 100644
--- a/arch/arm/cpu/armv7/mx7/soc.c
+++ b/arch/arm/cpu/armv7/mx7/soc.c
@@ -19,6 +19,9 @@
#include <dm.h>
#include <imx_thermal.h>
#include <fsl_wdog.h>
+#if defined(CONFIG_FSL_FASTBOOT) && defined(CONFIG_ANDROID_RECOVERY)
+#include <recovery.h>
+#endif
#if defined(CONFIG_IMX_THERMAL)
static const struct imx_thermal_plat imx7_thermal_plat = {
@@ -510,3 +513,60 @@ void reset_cpu(ulong addr)
*/
}
}
+
+
+#ifdef CONFIG_FSL_FASTBOOT
+
+#ifdef CONFIG_ANDROID_RECOVERY
+#define ANDROID_RECOVERY_BOOT (1 << 7)
+/*
+ * check if the recovery bit is set by kernel, it can be set by kernel
+ * issue a command '# reboot recovery'
+ */
+int recovery_check_and_clean_flag(void)
+{
+ int flag_set = 0;
+ u32 reg;
+ reg = readl(SNVS_BASE_ADDR + SNVS_LPGPR);
+
+ flag_set = !!(reg & ANDROID_RECOVERY_BOOT);
+ printf("check_and_clean: reg %x, flag_set %d\n", reg, flag_set);
+ /* clean it in case looping infinite here.... */
+ if (flag_set) {
+ reg &= ~ANDROID_RECOVERY_BOOT;
+ writel(reg, SNVS_BASE_ADDR + SNVS_LPGPR);
+ }
+
+ return flag_set;
+}
+#endif /*CONFIG_ANDROID_RECOVERY*/
+
+#define ANDROID_FASTBOOT_BOOT (1 << 8)
+/*
+ * check if the recovery bit is set by kernel, it can be set by kernel
+ * issue a command '# reboot fastboot'
+ */
+int fastboot_check_and_clean_flag(void)
+{
+ int flag_set = 0;
+ u32 reg;
+
+ reg = readl(SNVS_BASE_ADDR + SNVS_LPGPR);
+
+ flag_set = !!(reg & ANDROID_FASTBOOT_BOOT);
+
+ /* clean it in case looping infinite here.... */
+ if (flag_set) {
+ reg &= ~ANDROID_FASTBOOT_BOOT;
+ writel(reg, SNVS_BASE_ADDR + SNVS_LPGPR);
+ }
+
+ return flag_set;
+}
+
+void fastboot_enable_flag(void)
+{
+ setbits_le32(SNVS_BASE_ADDR + SNVS_LPGPR,
+ ANDROID_FASTBOOT_BOOT);
+}
+#endif /*CONFIG_FSL_FASTBOOT*/
diff --git a/arch/arm/include/asm/imx-common/boot_mode.h b/arch/arm/include/asm/imx-common/boot_mode.h
index accfcf9..9599191 100644
--- a/arch/arm/include/asm/imx-common/boot_mode.h
+++ b/arch/arm/include/asm/imx-common/boot_mode.h
@@ -3,6 +3,8 @@
* Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
* Copyright 2017 NXP
*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
diff --git a/board/freescale/common/Makefile b/board/freescale/common/Makefile
index d844831..66cdf0c 100644
--- a/board/freescale/common/Makefile
+++ b/board/freescale/common/Makefile
@@ -65,6 +65,9 @@ obj-$(CONFIG_POWER_MC34VR500) += mc34vr500.o
obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze_dm.o
obj-$(CONFIG_MXC_EPDC) += epdc_setup.o
obj-y += mmc.o
+ifdef CONFIG_FSL_FASTBOOT
+obj-${CONFIG_ANDROID_RECOVERY} += recovery.o
+endif
obj-$(CONFIG_LS102XA_STREAM_ID) += ls102xa_stream_id.o
diff --git a/board/freescale/common/recovery.c b/board/freescale/common/recovery.c
new file mode 100644
index 0000000..396bc73
--- /dev/null
+++ b/board/freescale/common/recovery.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <malloc.h>
+#include <recovery.h>
+#ifdef CONFIG_MXC_KPD
+#include <mxc_keyb.h>
+#endif
+#include <asm/imx-common/boot_mode.h>
+
+#ifdef CONFIG_MXC_KPD
+#define PRESSED_VOL_DOWN 0x01
+#define PRESSED_POWER 0x02
+#define RECOVERY_KEY_MASK (PRESSED_VOL_DOWN | PRESSED_POWER)
+
+inline int test_key(int value, struct kpp_key_info *ki)
+{
+ return (ki->val == value) && (ki->evt == KDepress);
+}
+
+int check_key_pressing(void)
+{
+ struct kpp_key_info *key_info = NULL;
+ int state = 0, keys, i;
+
+ int ret = 0;
+
+ mxc_kpp_init();
+ /* due to glitch suppression circuit,
+ wait sometime to let all keys scanned. */
+ udelay(1000);
+ keys = mxc_kpp_getc(&key_info);
+
+ printf("Detecting VOL_DOWN+POWER key for recovery(%d:%d) ...\n",
+ keys, keys ? key_info->val : 0);
+ if (keys > 1) {
+ for (i = 0; i < keys; i++) {
+ if (test_key(CONFIG_POWER_KEY, &key_info[i]))
+ state |= PRESSED_POWER;
+ else if (test_key(CONFIG_VOL_DOWN_KEY, &key_info[i]))
+ state |= PRESSED_VOL_DOWN;
+ }
+ }
+ if ((state & RECOVERY_KEY_MASK) == RECOVERY_KEY_MASK)
+ ret = 1;
+ if (key_info)
+ free(key_info);
+ return ret;
+}
+#else
+/* If not using mxc keypad, currently we will detect power key on board */
+int check_key_pressing(void)
+{
+ return 0;
+}
+#endif
+
+void setup_recovery_env(void)
+{
+ board_recovery_setup();
+}
+
+/* export to lib_arm/board.c */
+void check_recovery_mode(void)
+{
+ if (check_key_pressing()) {
+ puts("Fastboot: Recovery key pressing got!\n");
+ setup_recovery_env();
+ } else if (check_recovery_cmd_file()) {
+ puts("Fastboot: Recovery command file found!\n");
+ setup_recovery_env();
+ } else {
+ puts("Fastboot: Normal\n");
+ }
+}
diff --git a/cmd/fastboot/Kconfig b/cmd/fastboot/Kconfig
index 89b9e73..4a8f1af 100644
--- a/cmd/fastboot/Kconfig
+++ b/cmd/fastboot/Kconfig
@@ -24,6 +24,44 @@ config ANDROID_BOOT_IMAGE
This enables support for booting images which use the Android
image format header.
+config FSL_FASTBOOT
+ bool "Enable FSL fastboot support"
+ help
+ This enables FSL implementation for Android fastboot.
+
+if FSL_FASTBOOT
+
+config ANDROID_RECOVERY
+ bool "Enable the recovery boot function"
+ help
+ This enables the Android Recovery boot function.
+
+config CMD_BOOTA
+ bool "Enable the boota command"
+ help
+ This enables the boota command for booting android images.
+
+choice
+ prompt "Android Image Storage select"
+ default FASTBOOT_STORAGE_MMC
+
+config FASTBOOT_STORAGE_MMC
+ bool "Using eMMC/SD for Android fastboot storage media"
+
+config FASTBOOT_STORAGE_NAND
+ bool "Using NAND flash for Android fastboot storage media"
+
+config FASTBOOT_STORAGE_SATA
+ bool "Using SATA disk for Android fastboot storage media"
+
+endchoice
+
+config FASTBOOT_SATA_NO
+ int "Sata device index"
+ depends on FASTBOOT_STORAGE_SATA
+
+endif #FSL_FASTBOOT
+
if USB_FUNCTION_FASTBOOT
config FASTBOOT_BUF_ADDR
diff --git a/common/board_r.c b/common/board_r.c
index 5c9e698..014dbff 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -7,6 +7,8 @@
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -66,6 +68,9 @@
#include <asm/arch/mmu.h>
#endif
#include <efi_loader.h>
+#ifdef CONFIG_FSL_FASTBOOT
+#include <fsl_fastboot.h>
+#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -717,6 +722,20 @@ static int initr_kbd(void)
}
#endif
+#ifdef CONFIG_FSL_FASTBOOT
+static int initr_fastboot_setup(void)
+{
+ fastboot_setup();
+ return 0;
+}
+
+static int initr_check_fastboot(void)
+{
+ check_fastboot();
+ return 0;
+}
+#endif
+
static int run_main_loop(void)
{
#ifdef CONFIG_SANDBOX
@@ -894,6 +913,9 @@ static init_fnc_t init_sequence_r[] = {
#ifdef CONFIG_BOARD_LATE_INIT
board_late_init,
#endif
+#ifdef CONFIG_FSL_FASTBOOT
+ initr_fastboot_setup,
+#endif
#if defined(CONFIG_CMD_AMBAPP)
ambapp_init_reloc,
#if defined(CONFIG_SYS_AMBAPP_PRINT_ON_STARTUP)
@@ -942,6 +964,9 @@ static init_fnc_t init_sequence_r[] = {
#if defined(CONFIG_SPARC)
prom_init,
#endif
+#ifdef CONFIG_FSL_FASTBOOT
+ initr_check_fastboot,
+#endif
run_main_loop,
};
diff --git a/common/image-android.c b/common/image-android.c
index ee03b96..12ae345 100644
--- a/common/image-android.c
+++ b/common/image-android.c
@@ -1,6 +1,8 @@
/*
* Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -9,6 +11,7 @@
#include <android_image.h>
#include <malloc.h>
#include <errno.h>
+#include <asm/bootm.h>
#define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000
@@ -68,7 +71,6 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
int len = 0;
if (*hdr->cmdline) {
- printf("Kernel command line: %s\n", hdr->cmdline);
len += strlen(hdr->cmdline);
}
@@ -85,12 +87,25 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
if (bootargs) {
strcpy(newbootargs, bootargs);
- strcat(newbootargs, " ");
- }
- if (*hdr->cmdline)
+ } else if (*hdr->cmdline) {
strcat(newbootargs, hdr->cmdline);
+ }
+ printf("Kernel command line: %s\n", newbootargs);
+#ifdef CONFIG_SERIAL_TAG
+ struct tag_serialnr serialnr;
+ char commandline[ANDR_BOOT_ARGS_SIZE];
+ get_board_serial(&serialnr);
+
+ sprintf(commandline,
+ "%s androidboot.serialno=%08x%08x",
+ newbootargs,
+ serialnr.high,
+ serialnr.low);
+ setenv("bootargs", commandline);
+#else
setenv("bootargs", newbootargs);
+#endif
if (os_data) {
*os_data = (ulong)hdr;
@@ -174,3 +189,21 @@ void android_print_contents(const struct andr_img_hdr *hdr)
printf("%scmdline: %s\n", p, hdr->cmdline);
}
#endif
+
+int android_image_get_fdt(const struct andr_img_hdr *hdr,
+ ulong *fdt_data, ulong *fdt_len)
+{
+ if (!hdr->second_size)
+ return -1;
+
+ printf("FDT load addr 0x%08x size %u KiB\n",
+ hdr->second_addr, DIV_ROUND_UP(hdr->second_size, 1024));
+
+ *fdt_data = (unsigned long)hdr;
+ *fdt_data += hdr->page_size;
+ *fdt_data += ALIGN(hdr->kernel_size, hdr->page_size);
+ *fdt_data += ALIGN(hdr->ramdisk_size, hdr->page_size);
+
+ *fdt_len = hdr->second_size;
+ return 0;
+}
diff --git a/common/image-fdt.c b/common/image-fdt.c
index e7540be..1e86896 100644
--- a/common/image-fdt.c
+++ b/common/image-fdt.c
@@ -6,6 +6,8 @@
* (C) Copyright 2000-2006
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -417,7 +419,34 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,
debug("## No Flattened Device Tree\n");
goto no_fdt;
}
- } else {
+ }
+#ifdef CONFIG_ANDROID_BOOT_IMAGE
+ else if (genimg_get_format((void *)images->os.start) ==
+ IMAGE_FORMAT_ANDROID) {
+ ulong fdt_data, fdt_len;
+ android_image_get_fdt((void *)images->os.start,
+ &fdt_data, &fdt_len);
+
+ if (fdt_len) {
+ fdt_blob = (char *)fdt_data;
+ printf(" Booting using the fdt at 0x%p\n", fdt_blob);
+
+ if (fdt_check_header(fdt_blob) != 0) {
+ fdt_error("image is not a fdt");
+ goto error;
+ }
+
+ if (fdt_totalsize(fdt_blob) != fdt_len) {
+ fdt_error("fdt size != image size");
+ goto error;
+ }
+ } else {
+ debug("## No Flattened Device Tree\n");
+ goto no_fdt;
+ }
+ }
+#endif
+ else {
debug("## No Flattened Device Tree\n");
goto no_fdt;
}
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 2160b1c..153d177 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -8,6 +8,8 @@
* Copyright 2014 Linaro, Ltd.
* Rob Herring <robh@kernel.org>
*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
@@ -28,6 +30,20 @@
#include <fb_nand.h>
#endif
+#ifdef CONFIG_FSL_FASTBOOT
+#include <fsl_fastboot.h>
+#include <mmc.h>
+#include <android_image.h>
+#include <asm/bootm.h>
+#include <nand.h>
+#include <part.h>
+#include <sparse_format.h>
+#include <image-sparse.h>
+#ifdef CONFIG_ANDROID_RECOVERY
+#include <recovery.h>
+#endif
+#endif
+
#define FASTBOOT_VERSION "0.4"
#define FASTBOOT_INTERFACE_CLASS 0xff
@@ -147,6 +163,1690 @@ static struct usb_gadget_strings *fastboot_strings[] = {
NULL,
};
+#ifdef CONFIG_FSL_FASTBOOT
+
+#define ANDROID_BOOT_PARTITION_MMC 1
+#define ANDROID_SYSTEM_PARTITION_MMC 5
+#define ANDROID_RECOVERY_PARTITION_MMC 2
+#define ANDROID_CACHE_PARTITION_MMC 6
+#define ANDROID_DATA_PARTITION_MMC 4
+
+#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,
+ PTN_DATA_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;
+}
+
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+
+static void process_flash_nand(const char *cmdbuf)
+{
+ if (download_bytes) {
+ struct fastboot_ptentry *ptn;
+
+ ptn = fastboot_flash_find_ptn(cmdbuf);
+ if (ptn == 0) {
+ fastboot_fail("partition does not exist");
+ } else if ((download_bytes > ptn->length) &&
+ !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
+ fastboot_fail("image 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);
+ fastboot_fail(err_string);
+ } else {
+ printf("partition '%s' saveenv-ed\n", ptn->name);
+ fastboot_okay("");
+ }
+ } else {
+ /* Normal case */
+ if (write_to_ptn(ptn)) {
+ printf("flashing '%s' failed\n", ptn->name);
+ fastboot_fail("failed to flash partition");
+ } else {
+ printf("partition '%s' flashed\n", ptn->name);
+ fastboot_okay("");
+ }
+ }
+ }
+ } else {
+ fastboot_fail("no image downloaded");
+ }
+
+}
+#endif
+
+#if defined(CONFIG_FASTBOOT_STORAGE_SATA)
+static void process_flash_sata(const char *cmdbuf)
+{
+ 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);
+ fastboot_fail("partition 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");
+ fastboot_fail("image 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);
+ fastboot_fail(err_string);
+ } else {
+ printf("partition '%s' saveenv-ed\n", ptn->name);
+ fastboot_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);
+ fastboot_fail("Write partition failed");
+ } else {
+ printf("Writing '%s' DONE!\n",
+ ptn->name);
+ fastboot_okay("");
+ }
+ }
+ } else {
+ fastboot_fail("no 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))
+ || !strncmp(ptn->name,
+ FASTBOOT_PARTITION_DATA, strlen(FASTBOOT_PARTITION_DATA)))) {
+ printf("support sparse flash partition for %s\n", ptn->name);
+ return 1;
+ } else
+ return 0;
+}
+
+static lbaint_t mmc_sparse_write(struct sparse_storage *info,
+ lbaint_t blk, lbaint_t blkcnt, const void *buffer)
+{
+ struct blk_desc *dev_desc = (struct blk_desc *)info->priv;
+
+ return blk_dwrite(dev_desc, blk, blkcnt, buffer);
+}
+
+static lbaint_t mmc_sparse_reserve(struct sparse_storage *info,
+ lbaint_t blk, lbaint_t blkcnt)
+{
+ return blkcnt;
+}
+
+static void process_flash_mmc(const char *cmdbuf)
+{
+ 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);
+ fastboot_fail("partition 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");
+ fastboot_fail("image 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);
+ fastboot_fail(err_string);
+ } else {
+ printf("partition '%s' saveenv-ed\n", ptn->name);
+ fastboot_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;
+ struct blk_desc *dev_desc;
+ disk_partition_t info;
+ struct sparse_storage sparse;
+
+ 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 = blk_get_dev("mmc", mmc_no);
+ if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+ printf("** Block device MMC %d not supported\n",
+ mmc_no);
+ return;
+ }
+
+ if (part_get_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);
+
+ sparse.blksz = info.blksz;
+ sparse.start = info.start;
+ sparse.size = info.size;
+ sparse.write = mmc_sparse_write;
+ sparse.reserve = mmc_sparse_reserve;
+ printf("Flashing sparse image at offset " LBAFU "\n",
+ sparse.start);
+
+ sparse.priv = dev_desc;
+ write_sparse_image(&sparse, ptn->name, interface.transfer_buffer,
+ download_bytes);
+
+ } 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)
+ fastboot_fail("Init of MMC card failed");
+ else
+ fastboot_okay("");
+
+ printf("Writing '%s'\n", ptn->name);
+ if (run_command(mmc_write, 0)) {
+ printf("Writing '%s' FAILED!\n", ptn->name);
+ fastboot_fail("Write partition failed");
+ } else {
+ printf("Writing '%s' DONE!\n", ptn->name);
+ fastboot_okay("");
+ }
+ }
+ }
+ } else {
+ fastboot_fail("no image downloaded");
+ }
+}
+
+#endif
+
+
+static int rx_process_erase(const char *cmdbuf)
+{
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ struct fastboot_ptentry *ptn;
+
+ ptn = fastboot_flash_find_ptn(cmdbuf);
+ if (ptn == 0) {
+ fastboot_fail("partition 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) {
+ fastboot_fail("failed to erase partition");
+ } else {
+ printf("partition '%s' erased\n", ptn->name);
+ fastboot_okay("");
+ }
+ }
+ return 0;
+#else
+ printf("Not support erase command for EMMC\n");
+ return -1;
+#endif
+
+}
+
+static void rx_process_flash(const char *cmdbuf)
+{
+ switch (fastboot_devinfo.type) {
+#if defined(CONFIG_FASTBOOT_STORAGE_SATA)
+ case DEV_SATA:
+ process_flash_sata(cmdbuf);
+ break;
+#endif
+#if defined(CONFIG_FASTBOOT_STORAGE_MMC)
+ case DEV_MMC:
+ process_flash_mmc(cmdbuf);
+ break;
+#endif
+#if defined(CONFIG_FASTBOOT_STORAGE_NAND)
+ case DEV_NAND:
+ process_flash_nand(cmdbuf);
+ break;
+#endif
+ default:
+ printf("Not support flash command for current device %d\n",
+ fastboot_devinfo.type);
+ fastboot_fail("failed 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_FASTBOOT_BUF_ADDR;
+ interface.transfer_buffer_size =
+ CONFIG_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,
+ struct blk_desc *dev_desc,
+ struct fastboot_ptentry *ptable)
+{
+ disk_partition_t info;
+ strcpy(ptable[ptable_index].name, name);
+
+ if (part_get_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;
+ struct blk_desc *dev_desc;
+ struct fastboot_ptentry ptable[PTN_DATA_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 = blk_get_dev("mmc", mmc_no);
+ if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+ 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_DATA_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,
+ ANDROID_BOOT_PARTITION_MMC,
+ user_partition,
+ FASTBOOT_PARTITION_BOOT , dev_desc, ptable);
+ _fastboot_parts_add_ptable_entry(PTN_RECOVERY_INDEX,
+ ANDROID_RECOVERY_PARTITION_MMC,
+ user_partition,
+ FASTBOOT_PARTITION_RECOVERY, dev_desc, ptable);
+ _fastboot_parts_add_ptable_entry(PTN_SYSTEM_INDEX,
+ ANDROID_SYSTEM_PARTITION_MMC,
+ user_partition,
+ FASTBOOT_PARTITION_SYSTEM, dev_desc, ptable);
+ _fastboot_parts_add_ptable_entry(PTN_DATA_INDEX,
+ ANDROID_DATA_PARTITION_MMC,
+ user_partition,
+ FASTBOOT_PARTITION_DATA, dev_desc, ptable);
+
+ for (i = 0; i <= PTN_DATA_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 <addr> [ mmc0 | mmc1 [ <partition> ] ] */
+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;
+ struct blk_desc *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 = blk_get_dev("mmc", mmcc);
+ if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+ 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(dev_desc, 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(dev_desc, 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(dev_desc, 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(dev_desc, 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*/
+
+
+ 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",
+ "[<addr> | mmc0 | mmc1 | mmc2 | mmcX] [<partition>]\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 int strcmp_l1(const char *s1, const char *s2);
@@ -431,6 +2131,8 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
strncat(response, s, chars_left);
else
strcpy(response, "FAILValue not set");
+ } else if (!strcmp_l1("partition-type", cmd)) {
+ strcpy(response, "FAILVariable not implemented");
} else {
char envstr[32];
@@ -514,6 +2216,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 {
req->length = rx_bytes_expected(ep);
}
@@ -549,7 +2285,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");
@@ -594,6 +2334,10 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req)
fb_response_str = response;
fastboot_fail("no flash device defined");
+
+#ifdef CONFIG_FSL_FASTBOOT
+ rx_process_flash(cmd);
+#else
#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
fb_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR,
download_bytes);
@@ -603,6 +2347,7 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req)
(void *)CONFIG_FASTBOOT_BUF_ADDR,
download_bytes);
#endif
+#endif
fastboot_tx_write_str(response);
}
#endif
@@ -646,22 +2391,43 @@ static void cb_erase(struct usb_ep *ep, struct usb_request *req)
fb_response_str = response;
fastboot_fail("no flash device defined");
+#ifdef CONFIG_FSL_FASTBOOT
+ rx_process_erase(cmd);
+#else
#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
fb_mmc_erase(cmd);
#endif
#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV
fb_nand_erase(cmd);
#endif
+#endif
fastboot_tx_write_str(response);
}
#endif
+#ifdef CONFIG_FSL_FASTBOOT
+static void cb_reboot_bootloader(struct usb_ep *ep, struct usb_request *req)
+{
+ fastboot_tx_write_str("OKAY");
+
+ udelay(1000000);
+ fastboot_enable_flag();
+ do_reset(NULL, 0, 0, NULL);
+}
+#endif
+
struct cmd_dispatch_info {
char *cmd;
void (*cb)(struct usb_ep *ep, struct usb_request *req);
};
static const struct cmd_dispatch_info cmd_dispatch_info[] = {
+#ifdef CONFIG_FSL_FASTBOOT
+ {
+ .cmd = "reboot-bootloader",
+ .cb = cb_reboot_bootloader,
+ },
+#endif
{
.cmd = "reboot",
.cb = cb_reboot,
diff --git a/include/fsl_fastboot.h b/include/fsl_fastboot.h
new file mode 100644
index 0000000..078c873
--- /dev/null
+++ b/include/fsl_fastboot.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef FSL_FASTBOOT_H
+#define FSL_FASTBOOT_H
+
+#define FASTBOOT_PTENTRY_FLAGS_REPEAT(n) (n & 0x0f)
+#define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK 0x0000000F
+
+/* Writes happen a block at a time.
+ If the write fails, go to next block
+ NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK 0x00000010
+
+/* Find a contiguous block big enough for a the whole file
+ NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK 0x00000020
+
+/* Write the file with write.i */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_I 0x00000100
+
+/* Write the file with write.trimffs */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS 0x00000200
+
+/* Write the file as a series of variable/value pairs
+ using the setenv and saveenv commands */
+#define FASTBOOT_PTENTRY_FLAGS_WRITE_ENV 0x00000400
+
+#define FASTBOOT_MMC_BOOT_PARTITION_ID 1
+#define FASTBOOT_MMC_USER_PARTITION_ID 0
+#define FASTBOOT_MMC_NONE_PARTITION_ID -1
+
+#define FASTBOOT_PARTITION_BOOT "boot"
+#define FASTBOOT_PARTITION_RECOVERY "recovery"
+#define FASTBOOT_PARTITION_SYSTEM "system"
+#define FASTBOOT_PARTITION_BOOTLOADER "bootloader"
+#define FASTBOOT_PARTITION_DATA "data"
+
+enum {
+ DEV_SATA,
+ DEV_MMC,
+ DEV_NAND
+};
+
+struct cmd_fastboot_interface {
+ /* This function is called when a buffer has been
+ recieved from the client app.
+ The buffer is a supplied by the board layer and must be unmodified.
+ The buffer_size is how much data is passed in.
+ Returns 0 on success
+ Returns 1 on failure
+
+ Set by cmd_fastboot */
+ int (*rx_handler)(const unsigned char *buffer,
+ unsigned int buffer_size);
+
+ /* This function is called when an exception has
+ occurred in the device code and the state
+ off fastboot needs to be reset
+
+ Set by cmd_fastboot */
+ void (*reset_handler)(void);
+
+ /* A getvar string for the product name
+ It can have a maximum of 60 characters
+
+ Set by board */
+ char *product_name;
+
+ /* A getvar string for the serial number
+ It can have a maximum of 60 characters
+
+ Set by board */
+ char *serial_no;
+
+ /* Nand block size
+ Supports the write option WRITE_NEXT_GOOD_BLOCK
+
+ Set by board */
+ unsigned int nand_block_size;
+
+ /* Nand oob size
+ Set by board */
+ unsigned int nand_oob_size;
+
+ /* Transfer buffer, for handling flash updates
+ Should be multiple of the nand_block_size
+ Care should be take so it does not overrun bootloader memory
+ Controlled by the configure variable CFG_FASTBOOT_TRANSFER_BUFFER
+
+ Set by board */
+ unsigned char *transfer_buffer;
+
+ /* How big is the transfer buffer
+ Controlled by the configure variable
+ CFG_FASTBOOT_TRANSFER_BUFFER_SIZE
+
+ Set by board */
+ unsigned int transfer_buffer_size;
+
+};
+
+/* flash partitions are defined in terms of blocks
+** (flash erase units)
+*/
+struct fastboot_ptentry {
+ /* The logical name for this partition, null terminated */
+ char name[16];
+ /* The start wrt the nand part, must be multiple of nand block size */
+ unsigned int start;
+ /* The length of the partition, must be multiple of nand block size */
+ unsigned int length;
+ /* Controls the details of how operations are done on the partition
+ See the FASTBOOT_PTENTRY_FLAGS_*'s defined below */
+ unsigned int flags;
+ /* partition id: 0 - normal partition; 1 - boot partition */
+ unsigned int partition_id;
+ /* partition number in block device */
+ unsigned int partition_index;
+};
+
+struct fastboot_device_info {
+ unsigned char type;
+ unsigned char dev_id;
+};
+
+extern struct fastboot_device_info fastboot_devinfo;
+
+/* Prepare the fastboot environments,
+ * should be executed before "fastboot" cmd
+ */
+void fastboot_setup(void);
+
+
+/* The Android-style flash handling */
+
+/* tools to populate and query the partition table */
+void fastboot_flash_add_ptn(struct fastboot_ptentry *ptn);
+struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name);
+struct fastboot_ptentry *fastboot_flash_get_ptn(unsigned n);
+unsigned int fastboot_flash_get_ptn_count(void);
+void fastboot_flash_dump_ptn(void);
+
+
+/* Check the board special boot mode reboot to fastboot mode. */
+int fastboot_check_and_clean_flag(void);
+
+/* Set the flag which reboot to fastboot mode*/
+void fastboot_enable_flag(void);
+
+/*check if fastboot mode is requested by user*/
+void check_fastboot(void);
+
+/*Setup board-relative fastboot environment */
+void board_fastboot_setup(void);
+
+#ifdef CONFIG_FASTBOOT_STORAGE_NAND
+/*Save parameters for NAND storage partitions */
+void save_parts_values(struct fastboot_ptentry *ptn,
+ unsigned int offset, unsigned int size);
+
+/* Checks parameters for NAND storage partitions
+ * Return 1 if the parameter is not set
+ * Return 0 if the parameter has been set
+ */
+int check_parts_values(struct fastboot_ptentry *ptn);
+#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/
+
+#endif /* FSL_FASTBOOT_H */
diff --git a/include/image.h b/include/image.h
index 1e686b7..dd4c8e3 100644
--- a/include/image.h
+++ b/include/image.h
@@ -4,6 +4,8 @@
* (C) Copyright 2000-2005
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ *
* SPDX-License-Identifier: GPL-2.0+
********************************************************************
* NOTE: This header file defines an interface to U-Boot. Including
@@ -1238,6 +1240,8 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
ulong *os_data, ulong *os_len);
int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
ulong *rd_data, ulong *rd_len);
+int android_image_get_fdt(const struct andr_img_hdr *hdr,
+ ulong *fdt_data, ulong *fdt_len);
ulong android_image_get_end(const struct andr_img_hdr *hdr);
ulong android_image_get_kload(const struct andr_img_hdr *hdr);
void android_print_contents(const struct andr_img_hdr *hdr);
diff --git a/include/recovery.h b/include/recovery.h
new file mode 100644
index 0000000..4c368c6
--- /dev/null
+++ b/include/recovery.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __RECOVERY_H_
+#define __RECOVERY_H_
+
+struct reco_envs {
+ char *cmd;
+ char *args;
+};
+
+void check_recovery_mode(void);
+int recovery_check_and_clean_flag(void);
+int check_recovery_cmd_file(void);
+void board_recovery_setup(void);
+
+#endif