diff options
-rw-r--r-- | arch/arm/cpu/armv7/mx6/soc.c | 113 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx7/soc.c | 60 | ||||
-rw-r--r-- | arch/arm/include/asm/imx-common/boot_mode.h | 2 | ||||
-rw-r--r-- | board/freescale/common/Makefile | 3 | ||||
-rw-r--r-- | board/freescale/common/recovery.c | 78 | ||||
-rw-r--r-- | cmd/fastboot/Kconfig | 38 | ||||
-rw-r--r-- | common/board_r.c | 25 | ||||
-rw-r--r-- | common/image-android.c | 41 | ||||
-rw-r--r-- | common/image-fdt.c | 31 | ||||
-rw-r--r-- | drivers/usb/gadget/f_fastboot.c | 1766 | ||||
-rw-r--r-- | include/fsl_fastboot.h | 172 | ||||
-rw-r--r-- | include/image.h | 4 | ||||
-rw-r--r-- | include/recovery.h | 20 |
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 |