diff options
author | Ye.Li <B37916@freescale.com> | 2013-12-24 15:51:34 +0800 |
---|---|---|
committer | Ye.Li <B37916@freescale.com> | 2013-12-27 11:45:46 +0800 |
commit | 92d33d1d1b29fc8143a12443fde983359895d3c0 (patch) | |
tree | cb9e1bb4797161a07ace974f809721fb1e99310b | |
parent | 14fdf5d545ef769a9a4d59e3042cd960efe608a3 (diff) | |
download | u-boot-imx-92d33d1d1b29fc8143a12443fde983359895d3c0.zip u-boot-imx-92d33d1d1b29fc8143a12443fde983359895d3c0.tar.gz u-boot-imx-92d33d1d1b29fc8143a12443fde983359895d3c0.tar.bz2 |
ENGR00292902 ARM:imx6:sabresd/sabreauto Add android fastboot supporting
Support android features:
fastboot, booti command and recovery for sabresd SD, sabresd eMMC,
sabreauto SD, sabreauto NAND.
For all booting media (SD, eMMC, NAND), inherits the partitions layout
from v2009.08. Fastboot will detect the booting media to replace
hardcoding fastboot device. SATA is not supported.
FDT is supported to use the "unused" fields in bootimg header which
requires the FDT to be combined into the boot.img.
For non-FDT boot.img, the "unused" fields should left to NULL and is
compatible to boot.
Signed-off-by: Ye.Li <B37916@freescale.com>
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx6/soc.c | 94 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-mx6/imx-regs.h | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/imx-common/boot_mode.h | 21 | ||||
-rw-r--r-- | arch/arm/lib/board.c | 12 | ||||
-rw-r--r-- | board/freescale/common/Makefile | 3 | ||||
-rw-r--r-- | board/freescale/common/recovery.c | 93 | ||||
-rw-r--r-- | board/freescale/mx6qsabreauto/mx6qsabreauto.c | 115 | ||||
-rw-r--r-- | board/freescale/mx6qsabresd/mx6qsabresd.c | 123 | ||||
-rw-r--r-- | boards.cfg | 9 | ||||
-rw-r--r-- | common/Makefile | 1 | ||||
-rw-r--r-- | common/cmd_fastboot.c | 1762 | ||||
-rw-r--r-- | drivers/fastboot/Makefile | 47 | ||||
-rw-r--r-- | drivers/fastboot/fastboot.c | 1148 | ||||
-rw-r--r-- | include/configs/mx6qsabre_common.h | 4 | ||||
-rw-r--r-- | include/configs/mx6qsabreandroid_common.h | 69 | ||||
-rw-r--r-- | include/fastboot.h | 376 | ||||
-rw-r--r-- | include/recovery.h | 35 |
18 files changed, 3914 insertions, 0 deletions
@@ -321,6 +321,7 @@ LIBS-y += drivers/usb/phy/libusb_phy.o LIBS-y += drivers/usb/ulpi/libusb_ulpi.o LIBS-y += drivers/video/libvideo.o LIBS-y += drivers/watchdog/libwatchdog.o +LIBS-y += drivers/fastboot/libfastboot.o LIBS-y += common/libcommon.o LIBS-y += lib/libfdt/libfdt.o LIBS-y += api/libapi.o diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 011463d..63ac9d9 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -37,6 +37,11 @@ #include <libfdt.h> #include <stdbool.h> #include <asm/arch/mxc_hdmi.h> +#ifdef CONFIG_FASTBOOT +#ifdef CONFIG_ANDROID_RECOVERY +#include <recovery.h> +#endif +#endif #ifdef CONFIG_IMX_UDC #include <asm/arch/mx6_usbphy.h> #include <usb/imx_udc.h> @@ -450,6 +455,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 s_init(void) { } @@ -866,6 +914,52 @@ void imx_setup_hdmi(void) } #endif +#ifdef CONFIG_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; +} +#endif /*CONFIG_FASTBOOT*/ + #ifdef CONFIG_IMX_UDC void set_usboh3_clk(void) { diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h index 8d8edac..30d3b2d 100644 --- a/arch/arm/include/asm/arch-mx6/imx-regs.h +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h @@ -243,6 +243,7 @@ #define IRAM_SIZE 0x00040000 #define IMX_IIM_BASE OCOTP_BASE_ADDR #define FEC_QUIRK_ENET_MAC +#define SNVS_LPGPR 0x68 #if !(defined(__KERNEL_STRICT_NAMES) || defined(__ASSEMBLY__)) #include <asm/types.h> diff --git a/arch/arm/include/asm/imx-common/boot_mode.h b/arch/arm/include/asm/imx-common/boot_mode.h index 6d2df74..a037cd4 100644 --- a/arch/arm/include/asm/imx-common/boot_mode.h +++ b/arch/arm/include/asm/imx-common/boot_mode.h @@ -25,6 +25,26 @@ #define MAKE_CFGVAL(cfg1, cfg2, cfg3, cfg4) \ ((cfg4) << 24) | ((cfg3) << 16) | ((cfg2) << 8) | (cfg1) +enum boot_device { + WEIM_NOR_BOOT, + ONE_NAND_BOOT, + PATA_BOOT, + SATA_BOOT, + I2C_BOOT, + SPI_NOR_BOOT, + SD1_BOOT, + SD2_BOOT, + SD3_BOOT, + SD4_BOOT, + MMC1_BOOT, + MMC2_BOOT, + MMC3_BOOT, + MMC4_BOOT, + NAND_BOOT, + UNKNOWN_BOOT, + BOOT_DEV_NUM = UNKNOWN_BOOT, +}; + struct boot_mode { const char *name; unsigned cfg_val; @@ -32,5 +52,6 @@ struct boot_mode { void add_board_boot_modes(const struct boot_mode *p); void boot_mode_apply(unsigned cfg_val); +enum boot_device get_boot_device(void); extern const struct boot_mode soc_boot_modes[]; #endif diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 0521178..51b8628 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -59,6 +59,10 @@ #include <miiphy.h> #endif +#ifdef CONFIG_FASTBOOT +#include <fastboot.h> +#endif + DECLARE_GLOBAL_DATA_PTR; ulong monitor_flash_len; @@ -660,6 +664,10 @@ void board_init_r(gd_t *id, ulong dest_addr) board_late_init(); #endif +#ifdef CONFIG_FASTBOOT + fastboot_setup(); +#endif + #ifdef CONFIG_BITBANGMII bb_miiphy_init(); #endif @@ -699,6 +707,10 @@ void board_init_r(gd_t *id, ulong dest_addr) } #endif +#ifdef CONFIG_FASTBOOT + check_fastboot(); +#endif + /* main_loop() can return to retry autoboot, if so just run it again. */ for (;;) { main_loop(); diff --git a/board/freescale/common/Makefile b/board/freescale/common/Makefile index 75725b4..6509865 100644 --- a/board/freescale/common/Makefile +++ b/board/freescale/common/Makefile @@ -55,6 +55,9 @@ COBJS-$(CONFIG_P4080DS) += ics307_clk.o COBJS-$(CONFIG_P5020DS) += ics307_clk.o COBJS-$(CONFIG_P5040DS) += ics307_clk.o COBJS-$(CONFIG_VSC_CROSSBAR) += vsc3316_3308.o +ifdef CONFIG_FASTBOOT +COBJS-${CONFIG_ANDROID_RECOVERY} += recovery.o +endif # deal with common files for P-series corenet based devices SUBLIB-$(CONFIG_P2041RDB) += p_corenet/libp_corenet.o diff --git a/board/freescale/common/recovery.c b/board/freescale/common/recovery.c new file mode 100644 index 0000000..68ae655 --- /dev/null +++ b/board/freescale/common/recovery.c @@ -0,0 +1,93 @@ +/* + * Freescale Android Recovery mode checking routing + * + * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#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 founded!\n"); + setup_recovery_env(); + } else { + puts("Fastboot: Normal\n"); + } +} diff --git a/board/freescale/mx6qsabreauto/mx6qsabreauto.c b/board/freescale/mx6qsabreauto/mx6qsabreauto.c index 4073542..9a2b280 100644 --- a/board/freescale/mx6qsabreauto/mx6qsabreauto.c +++ b/board/freescale/mx6qsabreauto/mx6qsabreauto.c @@ -42,6 +42,13 @@ #include <linux/fb.h> #include <ipu_pixfmt.h> +#ifdef CONFIG_FASTBOOT +#include <fastboot.h> +#ifdef CONFIG_ANDROID_RECOVERY +#include <recovery.h> +#endif +#endif /*CONFIG_FASTBOOT*/ + DECLARE_GLOBAL_DATA_PTR; #define I2C_EXP_RST IMX_GPIO_NR(1, 15) @@ -772,6 +779,114 @@ int board_late_init(void) return 0; } +#ifdef CONFIG_FASTBOOT + +void board_fastboot_setup(void) +{ + switch (get_boot_device()) { +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) + case SATA_BOOT: + if (!getenv("fastboot_dev")) + setenv("fastboot_dev", "sata"); + if (!getenv("bootcmd")) + setenv("bootcmd", "booti sata"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_SATA*/ +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case SD3_BOOT: + case MMC3_BOOT: + if (!getenv("fastboot_dev")) + setenv("fastboot_dev", "mmc0"); + if (!getenv("bootcmd")) + setenv("bootcmd", "booti mmc0"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/ +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + case NAND_BOOT: + if (!getenv("fastboot_dev")) + setenv("fastboot_dev", "nand"); + if (!getenv("fbparts")) + setenv("fbparts", + "16m@16m(boot) 128m@32m(recovery) 810m@160m(android_root)ubifs"); + if (!getenv("bootcmd")) + setenv("bootcmd", + "nand read ${loadaddr} ${boot_nand_offset} " + "${boot_nand_size};booti ${loadaddr}"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/ + default: + printf("unsupported boot devices\n"); + break; + } +} + +#ifdef CONFIG_ANDROID_RECOVERY + +#define GPIO_VOL_DN_KEY IMX_GPIO_NR(5, 14) +iomux_v3_cfg_t const recovery_key_pads[] = { + (MX6_PAD_DISP0_DAT20__GPIO_5_14 | MUX_PAD_CTRL(NO_PAD_CTRL)), +}; + +int check_recovery_cmd_file(void) +{ + int button_pressed = 0; + int recovery_mode = 0; + + recovery_mode = recovery_check_and_clean_flag(); + + /* Check Recovery Combo Button press or not. */ + imx_iomux_v3_setup_multiple_pads(recovery_key_pads, + ARRAY_SIZE(recovery_key_pads)); + + gpio_direction_input(GPIO_VOL_DN_KEY); + + if (gpio_get_value(GPIO_VOL_DN_KEY) == 0) { /* VOL_DN key is low assert */ + button_pressed = 1; + printf("Recovery key pressed\n"); + } + + return recovery_mode || button_pressed; +} + +void board_recovery_setup(void) +{ + int bootdev = get_boot_device(); + + switch (bootdev) { +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) + case SATA_BOOT: + if (!getenv("bootcmd_android_recovery")) + setenv("bootcmd_android_recovery", "booti sata recovery"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_SATA*/ +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case SD3_BOOT: + case MMC3_BOOT: + if (!getenv("bootcmd_android_recovery")) + setenv("bootcmd_android_recovery", "booti mmc0 recovery"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/ +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + case NAND_BOOT: + if (!getenv("bootcmd_android_recovery")) + setenv("bootcmd_android_recovery", + "nand read ${loadaddr} ${recovery_nand_offset} " + "${recovery_nand_size};booti ${loadaddr}"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/ + default: + printf("Unsupported bootup device for recovery: dev: %d\n", + bootdev); + return; + } + + printf("setup env for recovery..\n"); + setenv("bootcmd", "run bootcmd_android_recovery"); +} +#endif /*CONFIG_ANDROID_RECOVERY*/ + +#endif /*CONFIG_FASTBOOT*/ + int checkboard(void) { int rev = mx6sabre_rev(); diff --git a/board/freescale/mx6qsabresd/mx6qsabresd.c b/board/freescale/mx6qsabresd/mx6qsabresd.c index 4a014da..7f80411 100644 --- a/board/freescale/mx6qsabresd/mx6qsabresd.c +++ b/board/freescale/mx6qsabresd/mx6qsabresd.c @@ -48,6 +48,14 @@ #include <ipu_pixfmt.h> #include <asm/io.h> #include <asm/arch/sys_proto.h> + +#ifdef CONFIG_FASTBOOT +#include <fastboot.h> +#ifdef CONFIG_ANDROID_RECOVERY +#include <recovery.h> +#endif +#endif /*CONFIG_FASTBOOT*/ + DECLARE_GLOBAL_DATA_PTR; #define UART_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \ @@ -1069,6 +1077,121 @@ int board_late_init(void) return 0; } +#ifdef CONFIG_FASTBOOT + +void board_fastboot_setup(void) +{ + switch (get_boot_device()) { +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) + case SATA_BOOT: + if (!getenv("fastboot_dev")) + setenv("fastboot_dev", "sata"); + if (!getenv("bootcmd")) + setenv("bootcmd", "booti sata"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_SATA*/ +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case SD2_BOOT: + case MMC2_BOOT: + if (!getenv("fastboot_dev")) + setenv("fastboot_dev", "mmc0"); + if (!getenv("bootcmd")) + setenv("bootcmd", "booti mmc0"); + break; + case SD3_BOOT: + case MMC3_BOOT: + if (!getenv("fastboot_dev")) + setenv("fastboot_dev", "mmc1"); + if (!getenv("bootcmd")) + setenv("bootcmd", "booti mmc1"); + break; + case MMC4_BOOT: + if (!getenv("fastboot_dev")) + setenv("fastboot_dev", "mmc2"); + if (!getenv("bootcmd")) + setenv("bootcmd", "booti mmc2"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/ + default: + printf("unsupported boot devices\n"); + break; + } + +} + +#ifdef CONFIG_ANDROID_RECOVERY + +#define GPIO_VOL_DN_KEY IMX_GPIO_NR(1, 5) +iomux_v3_cfg_t const recovery_key_pads[] = { + (MX6_PAD_GPIO_5__GPIO_1_5 | MUX_PAD_CTRL(NO_PAD_CTRL)), +}; + +int check_recovery_cmd_file(void) +{ + int button_pressed = 0; + int recovery_mode = 0; + + recovery_mode = recovery_check_and_clean_flag(); + + /* Check Recovery Combo Button press or not. */ + imx_iomux_v3_setup_multiple_pads(recovery_key_pads, + ARRAY_SIZE(recovery_key_pads)); + + gpio_direction_input(GPIO_VOL_DN_KEY); + + if (gpio_get_value(GPIO_VOL_DN_KEY) == 0) { /* VOL_DN key is low assert */ + button_pressed = 1; + printf("Recovery key pressed\n"); + } + + return recovery_mode || button_pressed; +} + +void board_recovery_setup(void) +{ + int bootdev = get_boot_device(); + + switch (bootdev) { +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) + case SATA_BOOT: + if (!getenv("bootcmd_android_recovery")) + setenv("bootcmd_android_recovery", + "booti sata recovery"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_SATA*/ +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case SD2_BOOT: + case MMC2_BOOT: + if (!getenv("bootcmd_android_recovery")) + setenv("bootcmd_android_recovery", + "booti mmc0 recovery"); + break; + case SD3_BOOT: + case MMC3_BOOT: + if (!getenv("bootcmd_android_recovery")) + setenv("bootcmd_android_recovery", + "booti mmc1 recovery"); + break; + case MMC4_BOOT: + if (!getenv("bootcmd_android_recovery")) + setenv("bootcmd_android_recovery", + "booti mmc2 recovery"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/ + default: + printf("Unsupported bootup device for recovery: dev: %d\n", + bootdev); + return; + } + + printf("setup env for recovery..\n"); + setenv("bootcmd", "run bootcmd_android_recovery"); +} + +#endif /*CONFIG_ANDROID_RECOVERY*/ + +#endif /*CONFIG_FASTBOOT*/ + int checkboard(void) { puts("Board: MX6Q/SDL-SabreSD\n"); @@ -260,7 +260,10 @@ mx6dlsabreauto arm armv7 mx6qsabreauto freesca mx6dlsabreauto_spinor arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6dl.cfg,MX6DL,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=2048,SYS_BOOT_SPINOR mx6dlsabreauto_eimnor arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6dl.cfg,MX6DL,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=2048,SYS_BOOT_EIMNOR mx6dlsabreauto_nand arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6dl.cfg,MX6DL,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=2048,SYS_BOOT_NAND +mx6dlsabreautoandroid arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6dl.cfg,MX6DL,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=2048,SYS_USE_SPINOR,ANDROID_SUPPORT +mx6dlsabreautoandroid_nand arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6dl.cfg,MX6DL,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=2048,SYS_BOOT_NAND,ANDROID_SUPPORT mx6dlsabresd arm armv7 mx6qsabresd freescale mx6 mx6qsabresd:IMX_CONFIG=board/freescale/mx6qsabresd/mx6dl_4x_mt41j128.cfg,MX6DL,DEFAULT_FDT_FILE="imx6dl-sabresd.dtb",DDR_MB=1024,SYS_USE_SPINOR +mx6dlsabresdandroid arm armv7 mx6qsabresd freescale mx6 mx6qsabresd:IMX_CONFIG=board/freescale/mx6qsabresd/mx6dl_4x_mt41j128.cfg,MX6DL,DEFAULT_FDT_FILE="imx6dl-sabresd.dtb",DDR_MB=1024,SYS_USE_SPINOR,ANDROID_SUPPORT mx6qsabresd_mfg arm armv7 mx6qsabresd freescale mx6 mx6qsabresd_mfg:IMX_CONFIG=board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg,MX6Q,DEFAULT_FDT_FILE="imx6q-sabresd.dtb",DDR_MB=1024,SYS_USE_SPINOR mx6qarm2 arm armv7 mx6qarm2 freescale mx6 mx6qarm2:IMX_CONFIG=board/freescale/mx6qarm2/imximage.cfg,MX6Q mx6qsabreauto arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6q.cfg,MX6Q,DEFAULT_FDT_FILE="imx6q-sabreauto.dtb",DDR_MB=2048,SYS_USE_SPINOR @@ -268,14 +271,20 @@ mx6qsabreauto_spinor arm armv7 mx6qsabreauto freesca mx6qsabreauto_eimnor arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6q.cfg,MX6Q,DEFAULT_FDT_FILE="imx6q-sabreauto.dtb",DDR_MB=2048,SYS_BOOT_EIMNOR mx6qsabreauto_nand arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6q.cfg,MX6Q,DEFAULT_FDT_FILE="imx6q-sabreauto.dtb",DDR_MB=2048,SYS_BOOT_NAND mx6qsabreauto_sata arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6q.cfg,MX6Q,DEFAULT_FDT_FILE="imx6q-sabreauto.dtb",DDR_MB=2048,SYS_BOOT_SATA +mx6qsabreautoandroid arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6q.cfg,MX6Q,DEFAULT_FDT_FILE="imx6q-sabreauto.dtb",DDR_MB=2048,SYS_USE_SPINOR,ANDROID_SUPPORT +mx6qsabreautoandroid_nand arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6q.cfg,MX6Q,DEFAULT_FDT_FILE="imx6q-sabreauto.dtb",DDR_MB=2048,SYS_BOOT_NAND,ANDROID_SUPPORT mx6qsabrelite arm armv7 mx6qsabrelite freescale mx6 mx6qsabrelite:IMX_CONFIG=board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg mx6qsabresd arm armv7 mx6qsabresd freescale mx6 mx6qsabresd:IMX_CONFIG=board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg,MX6Q,DEFAULT_FDT_FILE="imx6q-sabresd.dtb",DDR_MB=1024,SYS_USE_SPINOR mx6qsabresd_sata arm armv7 mx6qsabresd freescale mx6 mx6qsabresd:IMX_CONFIG=board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg,MX6Q,DEFAULT_FDT_FILE="imx6q-sabresd.dtb",DDR_MB=1024,SYS_USE_SPINOR,SYS_BOOT_SATA +mx6qsabresdandroid arm armv7 mx6qsabresd freescale mx6 mx6qsabresd:IMX_CONFIG=board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg,MX6Q,DEFAULT_FDT_FILE="imx6q-sabresd.dtb",DDR_MB=1024,SYS_USE_SPINOR,ANDROID_SUPPORT mx6solosabresd arm armv7 mx6qsabresd freescale mx6 mx6qsabresd:IMX_CONFIG=board/freescale/mx6qsabresd/mx6solo_4x_mt41j128.cfg,MX6SOLO,DEFAULT_FDT_FILE="imx6dl-sabresd.dtb",DDR_MB=512,SYS_USE_SPINOR,SYS_NOSMP="nosmp" +mx6solosabresdandroid arm armv7 mx6qsabresd freescale mx6 mx6qsabresd:IMX_CONFIG=board/freescale/mx6qsabresd/mx6solo_4x_mt41j128.cfg,MX6SOLO,DEFAULT_FDT_FILE="imx6dl-sabresd.dtb",DDR_MB=512,SYS_USE_SPINOR,SYS_NOSMP="nosmp",ANDROID_SUPPORT mx6solosabreauto arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6solo.cfg,MX6SOLO,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=1024,SYS_USE_SPINOR,SYS_NOSMP="nosmp" mx6solosabreauto_spinor arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6solo.cfg,MX6SOLO,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=1024,SYS_BOOT_SPINOR,SYS_NOSMP="nosmp" mx6solosabreauto_eimnor arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6solo.cfg,MX6SOLO,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=1024,SYS_BOOT_EIMNOR,SYS_NOSMP="nosmp" mx6solosabreauto_nand arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6solo.cfg,MX6SOLO,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=1024,SYS_BOOT_NAND,SYS_NOSMP="nosmp" +mx6solosabreautoandroid arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6solo.cfg,MX6SOLO,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=1024,SYS_USE_SPINOR,SYS_NOSMP="nosmp",ANDROID_SUPPORT +mx6solosabreautoandroid_nand arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6solo.cfg,MX6SOLO,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=1024,SYS_BOOT_NAND,SYS_NOSMP="nosmp",ANDROID_SUPPORT mx6slevk arm armv7 mx6slevk freescale mx6 mx6slevk:IMX_CONFIG=board/freescale/mx6slevk/imximage.cfg,MX6SL eco5pk arm armv7 eco5pk 8dtech omap3 nitrogen6dl arm armv7 nitrogen6x boundary mx6 nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL,DDR_MB=1024 diff --git a/common/Makefile b/common/Makefile index bc71681..ff09ca7 100644 --- a/common/Makefile +++ b/common/Makefile @@ -211,6 +211,7 @@ COBJS-$(CONFIG_MENU) += menu.o COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o COBJS-$(CONFIG_UPDATE_TFTP) += update.o COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o +COBJS-$(CONFIG_FASTBOOT) += cmd_fastboot.o COBJS-$(CONFIG_CMD_DFU) += cmd_dfu.o COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o endif diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c new file mode 100644 index 0000000..7d07978 --- /dev/null +++ b/common/cmd_fastboot.c @@ -0,0 +1,1762 @@ +/* + * Copyright 2008 - 2009 (C) Wind River Systems, Inc. + * Tom Rix <Tom.Rix@windriver.com> + * + * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Part of the rx_handler were copied from the Android project. + * Specifically rx command parsing in the usb_rx_data_complete + * function of the file bootable/bootloader/legacy/usbloader/usbloader.c + * + * The logical naming of flash comes from the Android project + * Thse structures and functions that look like fastboot_flash_* + * They come from bootable/bootloader/legacy/libboot/flash.c + * + * This is their Copyright: + * + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <asm/byteorder.h> +#include <common.h> +#include <command.h> +#include <nand.h> +#include <fastboot.h> +#include <environment.h> +#include <mmc.h> + + +#ifdef CONFIG_FASTBOOT + +int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +extern int do_bootm_linux(int flag, int argc, + char *argv[], bootm_headers_t *images); + +/* Forward decl */ +static int tx_handler(void); +static int rx_handler(const unsigned char *buffer, unsigned int buffer_size); +static void reset_handler(void); + +static struct cmd_fastboot_interface interface = { + .rx_handler = rx_handler, + .reset_handler = reset_handler, + .product_name = NULL, + .serial_no = NULL, + .nand_block_size = 0, + .transfer_buffer = (unsigned char *)0xffffffff, + .transfer_buffer_size = 0, +}; + +static unsigned int download_size; +static unsigned int download_bytes; +static unsigned int download_bytes_unpadded; +static unsigned int download_error; +static unsigned int continue_booting; +static unsigned int upload_size; +static unsigned int upload_bytes; +static unsigned int upload_error; + +#define MMC_SATA_BLOCK_SIZE 512 + +#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, char *response) +{ + if (download_bytes) { + struct fastboot_ptentry *ptn; + + ptn = fastboot_flash_find_ptn(cmdbuf + 6); + if (ptn == 0) { + sprintf(response, "FAILpartition does not exist"); + } else if ((download_bytes > ptn->length) && + !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { + sprintf(response, "FAILimage too large for partition"); + /* TODO : Improve check for yaffs write */ + } else { + /* Check if this is not really a flash write + but rather a saveenv */ + if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) { + /* Since the response can only be 64 bytes, + there is no point in having a large error message. */ + char err_string[32]; + if (saveenv_to_ptn(ptn, &err_string[0])) { + printf("savenv '%s' failed : %s\n", + ptn->name, err_string); + sprintf(response, "FAIL%s", err_string); + } else { + printf("partition '%s' saveenv-ed\n", ptn->name); + sprintf(response, "OKAY"); + } + } else { + /* Normal case */ + if (write_to_ptn(ptn)) { + printf("flashing '%s' failed\n", ptn->name); + sprintf(response, "FAILfailed to flash partition"); + } else { + printf("partition '%s' flashed\n", ptn->name); + sprintf(response, "OKAY"); + } + } + } + } else { + sprintf(response, "FAILno image downloaded"); + } + +} +#endif + +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) +static void process_flash_sata(const char *cmdbuf, char *response) +{ + if (download_bytes) { + struct fastboot_ptentry *ptn; + + /* Next is the partition name */ + ptn = fastboot_flash_find_ptn(cmdbuf + 6); + if (ptn == 0) { + printf("Partition:'%s' does not exist\n", ptn->name); + sprintf(response, "FAILpartition does not exist"); + } else if ((download_bytes > + ptn->length * MMC_SATA_BLOCK_SIZE) && + !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { + printf("Image too large for the partition\n"); + sprintf(response, "FAILimage too large for partition"); + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) { + /* Since the response can only be 64 bytes, + there is no point in having a large error message. */ + char err_string[32]; + if (saveenv_to_ptn(ptn, &err_string[0])) { + printf("savenv '%s' failed : %s\n", ptn->name, err_string); + sprintf(response, "FAIL%s", err_string); + } else { + printf("partition '%s' saveenv-ed\n", ptn->name); + sprintf(response, "OKAY"); + } + } else { + unsigned int temp; + char sata_write[128]; + + /* block count */ + temp = (download_bytes + + MMC_SATA_BLOCK_SIZE - 1) / + MMC_SATA_BLOCK_SIZE; + + sprintf(sata_write, "sata write 0x%x 0x%x 0x%x", + (unsigned int)interface.transfer_buffer, + ptn->start, + temp) + + if (run_command(sata_write, 0)) { + printf("Writing '%s' FAILED!\n", + ptn->name); + sprintf(response, + "FAIL: Write partition"); + } else { + printf("Writing '%s' DONE!\n", + ptn->name); + sprintf(response, "OKAY"); + } + } + } else { + sprintf(response, "FAILno image downloaded"); + } + +} +#endif + +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) +static void process_flash_mmc(const char *cmdbuf, char *response) +{ + if (download_bytes) { + struct fastboot_ptentry *ptn; + + /* Next is the partition name */ + ptn = fastboot_flash_find_ptn(cmdbuf + 6); + if (ptn == 0) { + printf("Partition:'%s' does not exist\n", ptn->name); + sprintf(response, "FAILpartition does not exist"); + } else if ((download_bytes > + ptn->length * MMC_SATA_BLOCK_SIZE) && + !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { + printf("Image too large for the partition\n"); + sprintf(response, "FAILimage too large for partition"); + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) { + /* Since the response can only be 64 bytes, + there is no point in having a large error message. */ + char err_string[32]; + if (saveenv_to_ptn(ptn, &err_string[0])) { + printf("savenv '%s' failed : %s\n", ptn->name, err_string); + sprintf(response, "FAIL%s", err_string); + } else { + printf("partition '%s' saveenv-ed\n", ptn->name); + sprintf(response, "OKAY"); + } + } else { + unsigned int temp; + + char mmc_dev[128]; + char mmc_write[128]; + int mmcret; + + printf("writing to partition '%s'\n", ptn->name); + + if (ptn->partition_id != FASTBOOT_MMC_NONE_PARTITION_ID) + sprintf(mmc_dev, "mmc dev %x %x", + fastboot_devinfo.dev_id, /*slot no*/ + ptn->partition_id /*part no*/); + else + sprintf(mmc_dev, "mmc dev %x", + fastboot_devinfo.dev_id /*slot no*/); + + /* block count */ + temp = (download_bytes + + MMC_SATA_BLOCK_SIZE - 1) / + MMC_SATA_BLOCK_SIZE; + + sprintf(mmc_write, "mmc write 0x%x 0x%x 0x%x", + (unsigned int)interface.transfer_buffer, /*source*/ + ptn->start, /*dest*/ + temp /*length*/); + + printf("Initializing '%s'\n", ptn->name); + + mmcret = run_command(mmc_dev, 0); + if (mmcret) + sprintf(response, "FAIL:Init of MMC card"); + else + sprintf(response, "OKAY"); + + printf("Writing '%s'\n", ptn->name); + if (run_command(mmc_write, 0)) { + printf("Writing '%s' FAILED!\n", ptn->name); + sprintf(response, "FAIL: Write partition"); + } else { + printf("Writing '%s' DONE!\n", ptn->name); + sprintf(response, "OKAY"); + } + } + } else { + sprintf(response, "FAILno image downloaded"); + } +} + +#endif + +static void reset_handler () +{ + /* If there was a download going on, bail */ + download_size = 0; + download_bytes = 0; + download_bytes_unpadded = 0; + download_error = 0; + continue_booting = 0; + upload_size = 0; + upload_bytes = 0; + upload_error = 0; +} + +static void rx_process_getvar(const char *cmdbuf, char *response) +{ + int temp_len = 0; + + strcpy(response, "OKAY"); + + temp_len = strlen("getvar:"); + if (!strcmp(cmdbuf + temp_len, "version")) { + strcpy(response + 4, FASTBOOT_VERSION); + } else if (!strcmp(cmdbuf + temp_len, + "product")) { + if (interface.product_name) + strcpy(response + 4, interface.product_name); + + } else if (!strcmp(cmdbuf + temp_len, + "serialno")) { + if (interface.serial_no) + strcpy(response + 4, interface.serial_no); + + } else if (!strcmp(cmdbuf + temp_len, + "downloadsize")) { + if (interface.transfer_buffer_size) + sprintf(response + 4, "0x%x", + interface.transfer_buffer_size); + } else { + fastboot_getvar(cmdbuf + 7, response + 4); + } +} + +static void rx_process_reboot(const char *cmdbuf, char *response) +{ + sprintf(response, "OKAY"); + fastboot_tx_status(response, strlen(response)); + udelay(1000000); /* 1 sec */ + + do_reset(NULL, 0, 0, NULL); +} + +static int rx_process_erase(const char *cmdbuf, char *response) +{ +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + struct fastboot_ptentry *ptn; + + ptn = fastboot_flash_find_ptn(cmdbuf + 6); + if (ptn == 0) { + sprintf(response, "FAILpartition does not exist"); + } else { + int status, repeat, repeat_max; + + printf("erasing '%s'\n", ptn->name); + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + char lock[128]; + char unlock[128]; +#endif + char erase[128]; + + repeat_max = 1; + if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK) + repeat_max = ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK; + + for (repeat = 0; repeat < repeat_max; + repeat++) { +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + sprintf(lock, "nand lock 0x%x 0x%x", + ptn->start + (repeat * ptn->length), + ptn->length); + sprintf(unlock, "nand unlock 0x%x 0x%x", + ptn->start + (repeat * ptn->length), + ptn->length); +#endif + sprintf(erase, "nand erase 0x%x 0x%x", + ptn->start + (repeat * ptn->length), + ptn->length); + +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + run_command(unlock, 0); +#endif + status = run_command(erase, 0); +#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK + run_command(lock, 0); +#endif + + if (status) + break; + } + + if (status) { + sprintf(response, + "FAILfailed to erase partition"); + } else { + printf("partition '%s' erased\n", ptn->name); + sprintf(response, "OKAY"); + } + } + return 0; +#else + printf("Not support erase command for EMMC\n"); + return -1; +#endif + +} + +static void rx_process_flash(const char *cmdbuf, char *response) +{ + switch (fastboot_devinfo.type) { +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) + case DEV_SATA: + process_flash_sata(cmdbuf, response); + break; +#endif +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case DEV_MMC: + process_flash_mmc(cmdbuf, response); + break; +#endif +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + case DEV_NAND: + process_flash_nand(cmdbuf, response); + break; +#endif + default: + printf("Not support flash command for current device %d\n", + fastboot_devinfo.type); + sprintf(response, + "FAILfailed to flash device"); + break; + } +} + +static void rx_process_boot(const char *cmdbuf, char *response) +{ + if ((download_bytes) && + (CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE < + download_bytes)) { + char start[32]; + char *booti_args[4] = {"booti", NULL, "boot", NULL}; + + /* + * Use this later to determine if a command line was passed + * for the kernel. + */ + /* struct fastboot_boot_img_hdr *fb_hdr = */ + /* (struct fastboot_boot_img_hdr *) interface.transfer_buffer; */ + + /* Skip the mkbootimage header */ + /* image_header_t *hdr = */ + /* (image_header_t *) */ + /* &interface.transfer_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE]; */ + + booti_args[1] = start; + sprintf(start, "0x%x", (unsigned int)interface.transfer_buffer); + + /* Execution should jump to kernel so send the response + now and wait a bit. */ + sprintf(response, "OKAY"); + fastboot_tx_status(response, strlen(response)); + + printf("Booting kernel...\n"); + + + /* Reserve for further use, this can + * be more convient for developer. */ + /* if (strlen ((char *) &fb_hdr->cmdline[0])) */ + /* set_env("bootargs", (char *) &fb_hdr->cmdline[0]); */ + + /* boot the boot.img */ + do_booti(NULL, 0, 3, booti_args); + + + } + sprintf(response, "FAILinvalid boot image"); +} + +static void rx_process_upload(const char *cmdbuf, char *response) +{ +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + unsigned int adv, delim_index, len; + struct fastboot_ptentry *ptn; + unsigned int is_raw = 0; + + /* Is this a raw read ? */ + if (memcmp(cmdbuf, "uploadraw:", 10) == 0) { + is_raw = 1; + adv = 10; + } else { + adv = 7; + } + + /* Scan to the next ':' to find when the size starts */ + len = strlen(cmdbuf); + for (delim_index = adv; + delim_index < len; delim_index++) { + if (cmdbuf[delim_index] == ':') { + /* WARNING, cmdbuf is being modified. */ + *((char *) &cmdbuf[delim_index]) = 0; + break; + } + } + + ptn = fastboot_flash_find_ptn(cmdbuf + adv); + if (ptn == 0) { + sprintf(response, + "FAILpartition does not exist"); + } else { + /* This is how much the user is expecting */ + unsigned int user_size; + /* + * This is the maximum size needed for + * this partition + */ + unsigned int size; + /* This is the length of the data */ + unsigned int length; + /* + * Used to check previous write of + * the parition + */ + char env_ptn_length_var[128]; + char *env_ptn_length_val; + + user_size = 0; + if (delim_index < len) + user_size = + simple_strtoul(cmdbuf + delim_index + 1, + NULL, 16); + + /* Make sure output is padded to block size */ + length = ptn->length; + sprintf(env_ptn_length_var, + "%s_nand_size", ptn->name); + env_ptn_length_val = getenv(env_ptn_length_var); + if (env_ptn_length_val) { + length = + simple_strtoul(env_ptn_length_val, + NULL, 16); + /* Catch possible problems */ + if (!length) + length = ptn->length; + } + + size = length / interface.nand_block_size; + size *= interface.nand_block_size; + if (length % interface.nand_block_size) + size += interface.nand_block_size; + + if (is_raw) + size += (size / + interface.nand_block_size) * + interface.nand_oob_size; + + if (size > interface.transfer_buffer_size) { + + sprintf(response, "FAILdata too large"); + + } else if (user_size == 0) { + + /* Send the data response */ + sprintf(response, "DATA%08x", size); + + } else if (user_size != size) { + /* This is the wrong size */ + sprintf(response, "FAIL"); + } else { + /* + * This is where the transfer + * buffer is populated + */ + unsigned char *buf = + interface.transfer_buffer; + char read[128]; + + /* + * Setting upload_size causes + * transfer to happen in main loop + */ + upload_size = size; + upload_bytes = 0; + upload_error = 0; + + /* + * Poison the transfer buffer, 0xff + * is erase value of nand + */ + memset(buf, 0xff, upload_size); + + /* Which flavor of read to use */ + if (is_raw) + sprintf(read, "nand read.raw 0x%x 0x%x 0x%x", + (unsigned int)(interface.transfer_buffer), + ptn->start, + upload_size); + else + sprintf(read, "nand read.i 0x%x 0x%x 0x%x", + (unsigned int)(interface.transfer_buffer), + ptn->start, + upload_size); + + run_command(read, 0); + + /* Send the data response */ + sprintf(response, "DATA%08x", size); + } + } +#endif + +} + +static int tx_handler(void) +{ + if (upload_size) { + + int bytes_written; + bytes_written = fastboot_tx(interface.transfer_buffer + + upload_bytes, upload_size - + upload_bytes); + if (bytes_written > 0) { + + upload_bytes += bytes_written; + /* Check if this is the last */ + if (upload_bytes == upload_size) { + + /* Reset upload */ + upload_size = 0; + upload_bytes = 0; + upload_error = 0; + } + } + } + return upload_error; +} + +static int rx_handler (const unsigned char *buffer, unsigned int buffer_size) +{ + int ret = 1; + + /*response buffer, Use 65 instead of 64 + null gets dropped. strcpy's need the extra byte */ + char response[FASTBOOT_RESPONSE_SIZE]; + + if (download_size) { + /* Something to download */ + + if (buffer_size) { + /* Handle possible overflow */ + unsigned int transfer_size = + download_size - download_bytes; + + if (buffer_size < transfer_size) + transfer_size = buffer_size; + + /* Save the data to the transfer buffer */ + memcpy(interface.transfer_buffer + download_bytes, + buffer, transfer_size); + + download_bytes += transfer_size; + + /* Check if transfer is done */ + if (download_bytes >= download_size) { + /* Reset global transfer variable, + Keep download_bytes because it will be + used in the next possible flashing command */ + download_size = 0; + + if (download_error) { + /* There was an earlier error */ + sprintf(response, "ERROR"); + } else { + /* Everything has transferred, + send the OK response */ + sprintf(response, "OKAY"); + } + fastboot_tx_status(response, strlen(response)); + + printf("\ndownloading of %d bytes finished\n", + download_bytes); + +#if defined(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 + } + + /* Provide some feedback */ + if (download_bytes && + 0 == (download_bytes % + (16 * interface.nand_block_size))) { + /* Some feeback that the + download is happening */ + if (download_error) + printf("X"); + else + printf("."); + if (0 == (download_bytes % + (80 * 16 * + interface.nand_block_size))) + printf("\n"); + + } + } else { + /* Ignore empty buffers */ + printf("Warning empty download buffer\n"); + printf("Ignoring\n"); + } + ret = 0; + } else { + /* A command */ + + /* Cast to make compiler happy with string functions */ + const char *cmdbuf = (char *) buffer; + printf("cmdbuf: %s\n", cmdbuf); + + /* Generic failed response */ + sprintf(response, "FAIL"); + + /* reboot + Reboot the board. */ + if (memcmp(cmdbuf, "reboot", 6) == 0) { + rx_process_reboot(cmdbuf, response); + /* This code is unreachable, + leave it to make the compiler happy */ + return 0; + } + + /* getvar + Get common fastboot variables + Board has a chance to handle other variables */ + if (memcmp(cmdbuf, "getvar:", 7) == 0) { + rx_process_getvar(cmdbuf, response); + ret = 0; + } + + /* erase + Erase a register flash partition + Board has to set up flash partitions */ + if (memcmp(cmdbuf, "erase:", 6) == 0) + ret = rx_process_erase(cmdbuf, response); + + /* download + download something .. + What happens to it depends on the next command after data */ + + if (memcmp(cmdbuf, "download:", 9) == 0) { + + /* save the size */ + download_size = simple_strtoul(cmdbuf + 9, NULL, 16); + /* Reset the bytes count, now it is safe */ + download_bytes = 0; + /* Reset error */ + download_error = 0; + + printf("Starting download of %d bytes\n", + download_size); + + if (0 == download_size) { + /* bad user input */ + sprintf(response, "FAILdata invalid size"); + } else if (download_size > + interface.transfer_buffer_size) { + /* set download_size to 0 because this is an error */ + download_size = 0; + sprintf(response, "FAILdata too large"); + } else { + /* The default case, the transfer fits + completely in the interface buffer */ + sprintf(response, "DATA%08x", download_size); + } + ret = 0; + } + + /* boot + boot what was downloaded + + WARNING WARNING WARNING + + This is not what you expect. + The fastboot client does its own packaging of the + kernel. The layout is defined in the android header + file bootimage.h. This layeout is copiedlooks like this, + + ** + ** +-----------------+ + ** | boot header | 1 page + ** +-----------------+ + ** | kernel | n pages + ** +-----------------+ + ** | ramdisk | m pages + ** +-----------------+ + ** | second stage | o pages + ** +-----------------+ + ** + + We only care about the kernel. + So we have to jump past a page. + + What is a page size ? + The fastboot client uses 2048 + + The is the default value of + + CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE + + */ + + if (memcmp(cmdbuf, "boot", 4) == 0) { + rx_process_boot(cmdbuf, response); + ret = 0; + } + + /* flash + Flash what was downloaded */ + if (memcmp(cmdbuf, "flash:", 6) == 0) { + rx_process_flash(cmdbuf, response); + ret = 0; + } + + /* continue + Stop doing fastboot */ + if (memcmp(cmdbuf, "continue", 8) == 0) { + sprintf(response, "OKAY"); + continue_booting = 1; + ret = 0; + } + + /* upload + Upload just the data in a partition */ + if ((memcmp(cmdbuf, "upload:", 7) == 0) || + (memcmp(cmdbuf, "uploadraw:", 10) == 0)) { + rx_process_upload(cmdbuf, response); + ret = 0; + } + + fastboot_tx_status(response, strlen(response)); + + } /* End of command */ + + return ret; +} + +int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int ret = 1; + int check_timeout = 0; + uint64_t timeout_endtime = 0; + uint64_t timeout_ticks = 1000; + int continue_from_disconnect = 0; + + do { + continue_from_disconnect = 0; + + /* Initialize the board specific support */ + if (0 == fastboot_init(&interface)) { + + int poll_status; + + /* If we got this far, we are a success */ + ret = 0; + printf("fastboot initialized\n"); + + timeout_endtime = get_timer(0); + timeout_endtime += timeout_ticks; + + while (1) { + uint64_t current_time = 0; + poll_status = fastboot_poll(); + + if (1 == check_timeout) + current_time = get_timer(0); + + if (FASTBOOT_ERROR == poll_status) { + /* Error */ + break; + } else if (FASTBOOT_DISCONNECT == poll_status) { + /* beak, cleanup and re-init */ + printf("Fastboot disconnect detected\n"); + continue_from_disconnect = 1; + break; + } else if ((1 == check_timeout) && + (FASTBOOT_INACTIVE == poll_status)) { + + /* No activity */ + if (current_time >= timeout_endtime) { + printf("Fastboot inactivity detected\n"); + break; + } + } else { + /* Something happened */ + if (1 == check_timeout) { + /* Update the timeout endtime */ + timeout_endtime = current_time; + timeout_endtime += timeout_ticks; + } + } + + /* Check if the user wanted to terminate with ^C */ + if ((FASTBOOT_INACTIVE == poll_status) && + (ctrlc())) { + printf("Fastboot ended by user\n"); + break; + } + + /* + * Check if the fastboot client wanted to + * continue booting + */ + if (continue_booting) { + printf("Fastboot ended by client\n"); + break; + } + + /* Check if there is something to upload */ + tx_handler(); + } + } + + /* Reset the board specific support */ + fastboot_shutdown(); + + /* restart the loop if a disconnect was detected */ + } while (continue_from_disconnect); + + return ret; +} + +U_BOOT_CMD( + fastboot, 2, 1, do_fastboot, + "fastboot- use USB Fastboot protocol\n", + "[inactive timeout]\n" + " - Run as a fastboot usb device.\n" + " - The optional inactive timeout is the decimal seconds before\n" + " - the normal console resumes\n" +); + + +#ifdef CONFIG_CMD_BOOTI + /* 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 fastboot_boot_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 unsigned char boothdr[512] __aligned(ARCH_DMA_MINALIGN); + +#define ALIGN_SECTOR(n, pagesz) ((n + (pagesz - 1)) & (~(pagesz - 1))) + +/* booti <addr> [ mmc0 | mmc1 [ <partition> ] ] */ +int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + unsigned addr = 0; + char *ptn = "boot"; + int mmcc = -1; + struct fastboot_boot_img_hdr *hdr = (void *)boothdr; +#ifdef CONFIG_SECURE_BOOT + u_int32_t load_addr; + uint32_t image_size; +#endif + int i = 0; + bootm_headers_t images; + + for (i = 0; i < argc; i++) + printf("%s ", argv[i]); + printf("\n"); + + if (argc < 2) + return -1; + + if (!strncmp(argv[1], "mmc", 3)) + mmcc = simple_strtoul(argv[1]+3, NULL, 10); + else + addr = simple_strtoul(argv[1], NULL, 16); + + if (argc > 2) + ptn = argv[2]; + + if (mmcc != -1) { +#ifdef CONFIG_MMC + struct fastboot_ptentry *pte; + struct mmc *mmc; + disk_partition_t info; + block_dev_desc_t *dev_desc = NULL; + unsigned sector; + + 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("booti: cannot find '%d' mmc device\n", mmcc); + goto fail; + } + dev_desc = get_dev("mmc", mmcc); + if (NULL == dev_desc) { + printf("** Block device MMC %d not supported\n", mmcc); + goto fail; + } + + /* below was i.MX mmc operation code */ + if (mmc_init(mmc)) { + printf("mmc%d init failed\n", mmcc); + goto fail; + } + + pte = fastboot_flash_find_ptn(ptn); + if (!pte) { + printf("booti: cannot find '%s' partition\n", ptn); + goto fail; + } + + if (mmc->block_dev.block_read(mmcc, pte->start, + 1, (void *)hdr) < 0) { + printf("booti: mmc failed to read bootimg header\n"); + goto fail; + } + + if (memcmp(hdr->magic, FASTBOOT_BOOT_MAGIC, 8)) { + printf("booti: bad boot image magic\n"); + goto fail; + } + + sector = pte->start + (hdr->page_size / 512); + + if (mmc->block_dev.block_read(mmcc, sector, + (hdr->kernel_size / 512) + 1, + (void *)hdr->kernel_addr) < 0) { + printf("booti: mmc failed to read kernel\n"); + goto fail; + } + /* flush cache after read */ + flush_cache((ulong)hdr->kernel_addr, hdr->kernel_size); /* FIXME */ + sector += ALIGN_SECTOR(hdr->kernel_size, hdr->page_size) / 512; + if (mmc->block_dev.block_read(mmcc, sector, + (hdr->ramdisk_size / 512) + 1, + (void *)hdr->ramdisk_addr) < 0) { + printf("booti: 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->unused[0] && hdr->unused[1]) { + sector += ALIGN_SECTOR(hdr->ramdisk_size, hdr->page_size) / 512; + if (mmc->block_dev.block_read(mmcc, sector, + (hdr->unused[0] / 512) + 1, + (void *)hdr->unused[1]) < 0) { + printf("booti: mmc failed to dtb\n"); + goto fail; + } + /* flush cache after read */ + flush_cache((ulong)hdr->unused[1], hdr->unused[0]); /* FIXME */ + } +#endif /*CONFIG_OF_LIBFDT*/ + +#else /*! CONFIG_MMC*/ + return -1; +#endif /*! CONFIG_MMC*/ + } else { + unsigned kaddr, raddr, end; +#ifdef CONFIG_OF_LIBFDT + unsigned fdtaddr = 0; +#endif + + /* set this aside somewhere safe */ + memcpy(hdr, (void *) addr, sizeof(*hdr)); + + if (memcmp(hdr->magic, FASTBOOT_BOOT_MAGIC, 8)) { + printf("booti: bad boot image magic\n"); + return 1; + } + + bootimg_print_image_hdr(hdr); + + kaddr = addr + hdr->page_size; + raddr = kaddr + ALIGN_SECTOR(hdr->kernel_size, hdr->page_size); + end = raddr + hdr->ramdisk_size; +#ifdef CONFIG_OF_LIBFDT + if (hdr->unused[0]) { + fdtaddr = raddr + ALIGN_SECTOR(hdr->ramdisk_size, hdr->page_size); + end = fdtaddr + hdr->unused[0]; + } +#endif /*CONFIG_OF_LIBFDT*/ + if (kaddr != hdr->kernel_addr) { + /*check overlap*/ + if (((hdr->kernel_addr >= addr) && + (hdr->kernel_addr <= end)) || + ((addr >= hdr->kernel_addr) && + (addr <= hdr->kernel_addr + hdr->kernel_size))) { + printf("Fail: booti address overlap with kernel address\n"); + return 1; + } + memmove((void *) hdr->kernel_addr, + (void *)kaddr, hdr->kernel_size); + } + 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: booti address overlap with ramdisk address\n"); + return 1; + } + memmove((void *) hdr->ramdisk_addr, + (void *)raddr, hdr->ramdisk_size); + } + +#ifdef CONFIG_OF_LIBFDT + if (hdr->unused[0] && fdtaddr != hdr->unused[1]) { + /*check overlap*/ + if (((hdr->unused[1] >= addr) && + (hdr->unused[1] <= end)) || + ((addr >= hdr->unused[1]) && + (addr <= hdr->unused[1] + hdr->unused[0]))) { + printf("Fail: booti address overlap with FDT address\n"); + return 1; + } + memmove((void *) hdr->unused[1], + (void *)fdtaddr, hdr->unused[0]); + } +#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->unused[0]) + printf("fdt @ %08x (%d)\n", hdr->unused[1], hdr->unused[0]); +#endif /*CONFIG_OF_LIBFDT*/ + +#ifdef CONFIG_SECURE_BOOT +#define IVT_SIZE 0x20 +#define CSF_PAD_SIZE 0x2000 + extern uint32_t authenticate_image(uint32_t ddr_start, + uint32_t image_size); + + image_size = hdr->ramdisk_addr + hdr->ramdisk_size - hdr->kernel_addr - + IVT_SIZE - CSF_PAD_SIZE; + + if (authenticate_image(hdr->kernel_addr, image_size)) { + printf("Authenticate OK\n"); + } else { + printf("Authenticate image Fail, Please check\n\n"); + return 1; + } +#endif /*CONFIG_SECURE_BOOT*/ + +#ifdef CONFIG_CMDLINE_TAG + /* XXX: in production, you should always use boot.img 's cmdline !!! */ + char *commandline = (char *)hdr->cmdline; + setenv("bootargs", commandline); + + printf("kernel cmdline:\n"); + printf("\tuse boot.img "); + printf("command line:\n\t%s\n", commandline); +#endif /*CONFIG_CMDLINE_TAG*/ + + memset(&images, 0, sizeof(images)); + images.ep = hdr->kernel_addr; + images.rd_start = hdr->ramdisk_addr; + images.rd_end = hdr->ramdisk_addr + hdr->ramdisk_size; + +#ifdef CONFIG_OF_LIBFDT + /*use unused fields for fdt, unused[0] = fdt size, unused[1] = fdt addr*/ + images.ft_addr = (char *)(hdr->unused[1]); + images.ft_len = (ulong)(hdr->unused[0]); +#endif /*CONFIG_OF_LIBFDT*/ + + do_bootm_linux(0, 0, NULL, &images); + + puts("booti: Control returned to monitor - resetting...\n"); + do_reset(cmdtp, flag, argc, argv); + return 1; + +fail: +#ifdef CONFIG_FASTBOOT + return do_fastboot(NULL, 0, 0, NULL); +#else /*! CONFIG_FASTBOOT*/ + return -1; +#endif /*! CONFIG_FASTBOOT*/ +} + +U_BOOT_CMD( + booti, 3, 1, do_booti, + "booti - 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_BOOTI */ + +#endif /* CONFIG_FASTBOOT */ diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile new file mode 100644 index 0000000..2625508 --- /dev/null +++ b/drivers/fastboot/Makefile @@ -0,0 +1,47 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB := $(obj)libfastboot.o + +# ohci +COBJS-$(CONFIG_FASTBOOT) += fastboot.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/fastboot/fastboot.c b/drivers/fastboot/fastboot.c new file mode 100644 index 0000000..03386a6 --- /dev/null +++ b/drivers/fastboot/fastboot.c @@ -0,0 +1,1148 @@ +/* + * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <common.h> +#include <config.h> +#include <malloc.h> +#include <fastboot.h> +#include <usb/imx_udc.h> +#include <asm/io.h> +#include <usbdevice.h> +#include <mmc.h> +#include <sata.h> +#ifdef CONFIG_ANDROID_RECOVERY +#include <recovery.h> +#endif + +/* + * Defines + */ +#define NUM_ENDPOINTS 2 + +#define CONFIG_USBD_OUT_PKTSIZE 0x200 +#define CONFIG_USBD_IN_PKTSIZE 0x200 +#define MAX_BUFFER_SIZE 0x200 + +/* + * imx family android layout + * mbr - 0 ~ 0x3FF byte + * bootloader - 0x400 ~ 0xFFFFF byte + * kernel - 0x100000 ~ 5FFFFF byte + * uramedisk - 0x600000 ~ 0x6FFFFF supposing 1M temporarily + * SYSTEM partition - /dev/mmcblk0p2 or /dev/sda2 + * RECOVERY parittion - dev/mmcblk0p4 or /dev/sda4 + */ +#define ANDROID_MBR_OFFSET 0 +#define ANDROID_MBR_SIZE 0x200 +#define ANDROID_BOOTLOADER_OFFSET 0x400 +#define ANDROID_BOOTLOADER_SIZE 0xFFC00 +#define ANDROID_KERNEL_OFFSET 0x100000 +#define ANDROID_KERNEL_SIZE 0x500000 +#define ANDROID_URAMDISK_OFFSET 0x600000 +#define ANDROID_URAMDISK_SIZE 0x100000 + +#define STR_LANG_INDEX 0x00 +#define STR_MANUFACTURER_INDEX 0x01 +#define STR_PRODUCT_INDEX 0x02 +#define STR_SERIAL_INDEX 0x03 +#define STR_CONFIG_INDEX 0x04 +#define STR_DATA_INTERFACE_INDEX 0x05 +#define STR_CTRL_INTERFACE_INDEX 0x06 +#define STR_COUNT 0x07 + +#define FASTBOOT_FBPARTS_ENV_MAX_LEN 1024 +/* To support the Android-style naming of flash */ +#define MAX_PTN 16 + + +/*pentry index internally*/ +enum { + PTN_MBR_INDEX = 0, + PTN_BOOTLOADER_INDEX, + PTN_KERNEL_INDEX, + PTN_URAMDISK_INDEX, + PTN_SYSTEM_INDEX, + PTN_RECOVERY_INDEX +}; + +struct fastboot_device_info fastboot_devinfo; + +/* defined and used by gadget/ep0.c */ +extern struct usb_string_descriptor **usb_strings; + +static struct usb_device_instance device_instance[1]; +static struct usb_bus_instance bus_instance[1]; +static struct usb_configuration_instance config_instance[1]; +static struct usb_interface_instance interface_instance[1]; +static struct usb_alternate_instance alternate_instance[1]; +/* one extra for control endpoint */ +static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1]; + +static struct cmd_fastboot_interface *fastboot_interface; +static int fastboot_configured_flag; +static int usb_disconnected; + +/* Indicies, References */ +static u8 rx_endpoint; +static u8 tx_endpoint; +static struct usb_string_descriptor *fastboot_string_table[STR_COUNT]; + +/* USB Descriptor Strings */ +static u8 wstrLang[4] = {4, USB_DT_STRING, 0x9, 0x4}; +static u8 wstrManufacturer[2 * (sizeof(CONFIG_FASTBOOT_MANUFACTURER_STR))]; +static u8 wstrProduct[2 * (sizeof(CONFIG_FASTBOOT_PRODUCT_NAME_STR))]; +static u8 wstrSerial[2*(sizeof(CONFIG_FASTBOOT_SERIAL_NUM))]; +static u8 wstrConfiguration[2 * (sizeof(CONFIG_FASTBOOT_CONFIGURATION_STR))]; +static u8 wstrDataInterface[2 * (sizeof(CONFIG_FASTBOOT_INTERFACE_STR))]; + +/* Standard USB Data Structures */ +static struct usb_interface_descriptor interface_descriptors[1]; +static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS]; +static struct usb_configuration_descriptor *configuration_descriptor; +static struct usb_device_descriptor device_descriptor = { + .bLength = sizeof(struct usb_device_descriptor), + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = cpu_to_le16(USB_BCD_VERSION), + .bDeviceClass = 0xff, + .bDeviceSubClass = 0xff, + .bDeviceProtocol = 0xff, + .bMaxPacketSize0 = 0x40, + .idVendor = cpu_to_le16(CONFIG_FASTBOOT_VENDOR_ID), + .idProduct = cpu_to_le16(CONFIG_FASTBOOT_PRODUCT_ID), + .bcdDevice = cpu_to_le16(CONFIG_FASTBOOT_BCD_DEVICE), + .iManufacturer = STR_MANUFACTURER_INDEX, + .iProduct = STR_PRODUCT_INDEX, + .iSerialNumber = STR_SERIAL_INDEX, + .bNumConfigurations = 1 +}; + +/* + * Static Generic Serial specific data + */ + +struct fastboot_config_desc { + struct usb_configuration_descriptor configuration_desc; + struct usb_interface_descriptor interface_desc[1]; + struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS]; +}; + +static struct fastboot_config_desc +fastboot_configuration_descriptors[1] = { + { + .configuration_desc = { + .bLength = sizeof(struct usb_configuration_descriptor), + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = + cpu_to_le16(sizeof(struct fastboot_config_desc)), + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_INDEX, + .bmAttributes = + BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, + .bMaxPower = 0x32 + }, + .interface_desc = { + { + .bLength = + sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = NUM_ENDPOINTS, + .bInterfaceClass = + FASTBOOT_INTERFACE_CLASS, + .bInterfaceSubClass = + FASTBOOT_INTERFACE_SUB_CLASS, + .bInterfaceProtocol = + FASTBOOT_INTERFACE_PROTOCOL, + .iInterface = STR_DATA_INTERFACE_INDEX + }, + }, + .data_endpoints = { + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = UDC_OUT_ENDPOINT | + USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_OUT_PKTSIZE), + .bInterval = 0x00, + }, + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = UDC_IN_ENDPOINT | + USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_IN_PKTSIZE), + .bInterval = 0x00, + }, + }, + }, +}; + + + +static struct fastboot_ptentry ptable[MAX_PTN]; +static unsigned int pcount; + + +/* Static Function Prototypes */ +static void _fastboot_init_strings(void); +static void _fastboot_init_instances(void); +static void _fastboot_init_endpoints(void); +static void _fastboot_event_handler(struct usb_device_instance *device, + usb_device_event_t event, int data); +static int _fastboot_cdc_setup(struct usb_device_request *request, + struct urb *urb); +static int _fastboot_usb_configured(void); +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) \ + || defined(CONFIG_FASTBOOT_STORAGE_MMC) +static int _fastboot_parts_load_from_ptable(void); +#endif +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) +static int _fastboot_parts_load_from_env(void); +#endif +static int _fastboot_setup_dev(void); +static void _fastboot_load_partitions(void); + +/* utility function for converting char* to wide string used by USB */ +static void str2wide(char *str, u16 * wide) +{ + int i; + for (i = 0; i < strlen(str) && str[i]; i++) { + #if defined(__LITTLE_ENDIAN) + wide[i] = (u16) str[i]; + #elif defined(__BIG_ENDIAN) + wide[i] = ((u16)(str[i])<<8); + #else + #error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined" + #endif + } +} + +/* + Get mmc control number from passed string, eg, "mmc1" mean device 1. Only + support "mmc0" to "mmc9" currently. It will be treated as device 0 for + other string. +*/ +static int _fastboot_get_mmc_no(char *env_str) +{ + int digit = 0; + unsigned char a; + + if (env_str && (strlen(env_str) >= 4) && + !strncmp(env_str, "mmc", 3)) { + a = env_str[3]; + if (a >= '0' && a <= '9') + digit = a - '0'; + } + + return digit; +} + +static int _fastboot_setup_dev(void) +{ + char *fastboot_env; + fastboot_env = getenv("fastboot_dev"); + + if (fastboot_env) { + if (!strcmp(fastboot_env, "sata")) { + fastboot_devinfo.type = DEV_SATA; + fastboot_devinfo.dev_id = 0; + } else if (!strcmp(fastboot_env, "nand")) { + fastboot_devinfo.type = DEV_NAND; + fastboot_devinfo.dev_id = 0; + } else if (!strncmp(fastboot_env, "mmc", 3)) { + fastboot_devinfo.type = DEV_MMC; + fastboot_devinfo.dev_id = _fastboot_get_mmc_no(fastboot_env); + } + } else { + return 1; + } + + return 0; +} + + +/* + * Initialize fastboot + */ +int fastboot_init(struct cmd_fastboot_interface *interface) +{ + printf("fastboot is in init......"); + + fastboot_interface = interface; + fastboot_interface->product_name = CONFIG_FASTBOOT_PRODUCT_NAME_STR; + fastboot_interface->serial_no = CONFIG_FASTBOOT_SERIAL_NUM; + fastboot_interface->nand_block_size = 4096; + fastboot_interface->transfer_buffer = + (unsigned char *)CONFIG_FASTBOOT_TRANSFER_BUF; + fastboot_interface->transfer_buffer_size = + CONFIG_FASTBOOT_TRANSFER_BUF_SIZE; + + _fastboot_init_strings(); + /* Basic USB initialization */ + udc_init(); + + _fastboot_init_instances(); + + udc_startup_events(device_instance); + udc_connect(); /* Enable pullup for host detection */ + + return 0; +} + +static void _fastboot_init_strings(void) +{ + struct usb_string_descriptor *string; + + fastboot_string_table[STR_LANG_INDEX] = + (struct usb_string_descriptor *)wstrLang; + + string = (struct usb_string_descriptor *)wstrManufacturer; + string->bLength = sizeof(wstrManufacturer); + string->bDescriptorType = USB_DT_STRING; + str2wide(CONFIG_FASTBOOT_MANUFACTURER_STR, string->wData); + fastboot_string_table[STR_MANUFACTURER_INDEX] = string; + + string = (struct usb_string_descriptor *)wstrProduct; + string->bLength = sizeof(wstrProduct); + string->bDescriptorType = USB_DT_STRING; + str2wide(CONFIG_FASTBOOT_PRODUCT_NAME_STR, string->wData); + fastboot_string_table[STR_PRODUCT_INDEX] = string; + + string = (struct usb_string_descriptor *)wstrSerial; + string->bLength = sizeof(wstrSerial); + string->bDescriptorType = USB_DT_STRING; + str2wide(CONFIG_FASTBOOT_SERIAL_NUM, string->wData); + fastboot_string_table[STR_SERIAL_INDEX] = string; + + string = (struct usb_string_descriptor *)wstrConfiguration; + string->bLength = sizeof(wstrConfiguration); + string->bDescriptorType = USB_DT_STRING; + str2wide(CONFIG_FASTBOOT_CONFIGURATION_STR, string->wData); + fastboot_string_table[STR_CONFIG_INDEX] = string; + + string = (struct usb_string_descriptor *) wstrDataInterface; + string->bLength = sizeof(wstrDataInterface); + string->bDescriptorType = USB_DT_STRING; + str2wide(CONFIG_FASTBOOT_INTERFACE_STR, string->wData); + fastboot_string_table[STR_DATA_INTERFACE_INDEX] = string; + + /* Now, initialize the string table for ep0 handling */ + usb_strings = fastboot_string_table; +} + +static void _fastboot_init_instances(void) +{ + int i; + u16 temp; + + /* Assign endpoint descriptors */ + ep_descriptor_ptrs[0] = + &fastboot_configuration_descriptors[0].data_endpoints[0]; + ep_descriptor_ptrs[1] = + &fastboot_configuration_descriptors[0].data_endpoints[1]; + + /* Configuration Descriptor */ + configuration_descriptor = + (struct usb_configuration_descriptor *) + &fastboot_configuration_descriptors; + + fastboot_configured_flag = 0; + + /* initialize device instance */ + memset(device_instance, 0, sizeof(struct usb_device_instance)); + device_instance->device_state = STATE_INIT; + device_instance->device_descriptor = &device_descriptor; + device_instance->event = _fastboot_event_handler; + device_instance->cdc_recv_setup = _fastboot_cdc_setup; + device_instance->bus = bus_instance; + device_instance->configurations = 1; + device_instance->configuration_instance_array = config_instance; + + /* initialize bus instance */ + memset(bus_instance, 0, sizeof(struct usb_bus_instance)); + bus_instance->device = device_instance; + bus_instance->endpoint_array = endpoint_instance; + bus_instance->max_endpoints = NUM_ENDPOINTS + 1; + bus_instance->maxpacketsize = 0xFF; + bus_instance->serial_number_str = CONFIG_FASTBOOT_SERIAL_NUM; + + /* configuration instance */ + memset(config_instance, 0, + sizeof(struct usb_configuration_instance)); + config_instance->interfaces = 1; + config_instance->configuration_descriptor = configuration_descriptor; + config_instance->interface_instance_array = interface_instance; + + /* interface instance */ + memset(interface_instance, 0, + sizeof(struct usb_interface_instance)); + interface_instance->alternates = 1; + interface_instance->alternates_instance_array = alternate_instance; + + /* alternates instance */ + memset(alternate_instance, 0, + sizeof(struct usb_alternate_instance)); + alternate_instance->interface_descriptor = interface_descriptors; + alternate_instance->endpoints = NUM_ENDPOINTS; + alternate_instance->endpoints_descriptor_array = ep_descriptor_ptrs; + + /* endpoint instances */ + memset(&endpoint_instance[0], 0, + sizeof(struct usb_endpoint_instance)); + endpoint_instance[0].endpoint_address = 0; + endpoint_instance[0].rcv_packetSize = EP0_MAX_PACKET_SIZE; + endpoint_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL; + endpoint_instance[0].tx_packetSize = EP0_MAX_PACKET_SIZE; + endpoint_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL; + udc_setup_ep(device_instance, 0, &endpoint_instance[0]); + + for (i = 1; i <= NUM_ENDPOINTS; i++) { + memset(&endpoint_instance[i], 0, + sizeof(struct usb_endpoint_instance)); + + endpoint_instance[i].endpoint_address = + ep_descriptor_ptrs[i - 1]->bEndpointAddress; + + endpoint_instance[i].rcv_attributes = + ep_descriptor_ptrs[i - 1]->bmAttributes; + + /*fix the abort caused by unalignment*/ + temp = *(u8 *)&ep_descriptor_ptrs[i - 1]->wMaxPacketSize; + temp |= + (*(((u8 *)&ep_descriptor_ptrs[i - 1]->wMaxPacketSize) + 1) << 8); + + endpoint_instance[i].rcv_packetSize = + le16_to_cpu(temp); + + endpoint_instance[i].tx_attributes = + ep_descriptor_ptrs[i - 1]->bmAttributes; + + endpoint_instance[i].tx_packetSize = + le16_to_cpu(temp); + + endpoint_instance[i].tx_attributes = + ep_descriptor_ptrs[i - 1]->bmAttributes; + + urb_link_init(&endpoint_instance[i].rcv); + urb_link_init(&endpoint_instance[i].rdy); + urb_link_init(&endpoint_instance[i].tx); + urb_link_init(&endpoint_instance[i].done); + + if (endpoint_instance[i].endpoint_address & USB_DIR_IN) { + tx_endpoint = i; + endpoint_instance[i].tx_urb = + usbd_alloc_urb(device_instance, + &endpoint_instance[i]); + } else { + rx_endpoint = i; + endpoint_instance[i].rcv_urb = + usbd_alloc_urb(device_instance, + &endpoint_instance[i]); + } + } +} + +static void _fastboot_init_endpoints(void) +{ + int i; + + bus_instance->max_endpoints = NUM_ENDPOINTS + 1; + for (i = 1; i <= NUM_ENDPOINTS; i++) + udc_setup_ep(device_instance, i, &endpoint_instance[i]); +} + +static void _fastboot_destroy_endpoints(void) +{ + int i; + struct urb *tx_urb; + + for (i = 1; i <= NUM_ENDPOINTS; i++) { + /*dealloc urb*/ + if (endpoint_instance[i].endpoint_address & USB_DIR_IN) { + if (endpoint_instance[i].tx_urb) + usbd_dealloc_urb(endpoint_instance[i].tx_urb); + + while (endpoint_instance[i].tx_queue) { + tx_urb = first_urb_detached(&endpoint_instance[i].tx); + if (tx_urb) { + usbd_dealloc_urb(tx_urb); + endpoint_instance[i].tx_queue--; + } else { + break; + } + } + endpoint_instance[i].tx_queue = 0; + + do { + tx_urb = first_urb_detached(&endpoint_instance[i].done); + if (tx_urb) + usbd_dealloc_urb(tx_urb); + } while (tx_urb); + + } else { + if (endpoint_instance[i].rcv_urb) + usbd_dealloc_urb(endpoint_instance[i].rcv_urb); + } + + udc_destroy_ep(device_instance, &endpoint_instance[i]); + } +} + + +static int _fill_buffer(u8 *buf) +{ + struct usb_endpoint_instance *endpoint = + &endpoint_instance[rx_endpoint]; + + if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) { + unsigned int nb = 0; + char *src = (char *)endpoint->rcv_urb->buffer; + unsigned int rx_avail = MAX_BUFFER_SIZE; + + if (rx_avail >= endpoint->rcv_urb->actual_length) { + nb = endpoint->rcv_urb->actual_length; + memcpy(buf, src, nb); + endpoint->rcv_urb->actual_length = 0; + } + return nb; + } + return 0; +} + +static struct urb *_next_urb(struct usb_device_instance *device, + struct usb_endpoint_instance *endpoint) +{ + struct urb *current_urb = NULL; + int space; + + /* If there's a queue, then we should add to the last urb */ + if (!endpoint->tx_queue) + current_urb = endpoint->tx_urb; + else + /* Last urb from tx chain */ + current_urb = + p2surround(struct urb, link, endpoint->tx.prev); + + /* Make sure this one has enough room */ + space = current_urb->buffer_length - current_urb->actual_length; + if (space > 0) + return current_urb; + else { /* No space here */ + /* First look at done list */ + current_urb = first_urb_detached(&endpoint->done); + if (!current_urb) + current_urb = usbd_alloc_urb(device, endpoint); + + urb_append(&endpoint->tx, current_urb); + endpoint->tx_queue++; + } + return current_urb; +} + +static int _fastboot_usb_configured(void) +{ + return fastboot_configured_flag; +} + +static void _fastboot_event_handler(struct usb_device_instance *device, + usb_device_event_t event, int data) +{ + switch (event) { + case DEVICE_RESET: + case DEVICE_BUS_INACTIVE: + fastboot_configured_flag = 0; + break; + case DEVICE_CONFIGURED: + fastboot_configured_flag = 1; + _fastboot_init_endpoints(); + break; + case DEVICE_ADDRESS_ASSIGNED: + default: + break; + } +} + +static int _fastboot_cdc_setup(struct usb_device_request *request, + struct urb *urb) +{ + return 0; +} + + +/*! + * Function to receive data from host through channel + * + * @buf buffer to fill in + * @count read data size + * + * @return 0 + */ +int fastboot_usb_recv(u8 *buf, int count) +{ + int len = 0; + + while (!_fastboot_usb_configured()) + udc_irq(); + + /* update rxqueue to wait new data */ + mxc_udc_rxqueue_update(2, count); + + while (!len) { + if (is_usb_disconnected()) { + /*it will not unconfigure when disconnect + from host, so here needs manual unconfigure + anyway, it's just a workaround*/ + fastboot_configured_flag = 0; + usb_disconnected = 1; + return 0; + } + udc_irq(); + if (_fastboot_usb_configured()) + len = _fill_buffer(buf); + } + return len; +} + +int fastboot_getvar(const char *rx_buffer, char *tx_buffer) +{ + /* Place board specific variables here */ + return 0; +} + +int fastboot_poll() +{ + u8 buffer[MAX_BUFFER_SIZE]; + int length = 0; + + memset(buffer, 0, MAX_BUFFER_SIZE); + + length = fastboot_usb_recv(buffer, MAX_BUFFER_SIZE); + + /* If usb disconnected, blocked here to wait */ + if (usb_disconnected) { + udc_disconnect(); + udc_connect(); + /*the udc_connect will be blocked until connect to host + so, the usb_disconnect should be 0 after udc_connect, + and should be set manually. Anyway, it's just a workaround*/ + usb_disconnected = 0; + } + + if (!length) + return FASTBOOT_INACTIVE; + + /* Pass this up to the interface's handler */ + if (fastboot_interface && fastboot_interface->rx_handler) { + if (!fastboot_interface->rx_handler(buffer, length)) + return FASTBOOT_OK; + } + return FASTBOOT_OK; +} + +int fastboot_tx(unsigned char *buffer, unsigned int buffer_size) +{ + /* Not realized yet */ + return 0; +} + +static int _fastboot_write_buffer(const char *buffer, + unsigned int buffer_size) +{ + struct usb_endpoint_instance *endpoint = + (struct usb_endpoint_instance *)&endpoint_instance[tx_endpoint]; + struct urb *current_urb = NULL; + + if (!_fastboot_usb_configured()) + return 0; + + current_urb = _next_urb(device_instance, endpoint); + if (buffer_size) { + char *dest; + int space_avail, popnum, count, total = 0; + + /* Break buffer into urb sized pieces, + * and link each to the endpoint + */ + count = buffer_size; + while (count > 0) { + if (!current_urb) { + printf("current_urb is NULL, buffer_size %d\n", + buffer_size); + return total; + } + + dest = (char *)current_urb->buffer + + current_urb->actual_length; + + space_avail = current_urb->buffer_length - + current_urb->actual_length; + popnum = MIN(space_avail, count); + if (popnum == 0) + break; + + memcpy(dest, buffer + total, popnum); + printf("send: %s\n", (char *)buffer); + + current_urb->actual_length += popnum; + total += popnum; + + if (udc_endpoint_write(endpoint)) + /* Write pre-empted by RX */ + return 0; + count -= popnum; + } /* end while */ + return total; + } + return 0; +} + +int fastboot_tx_status(const char *buffer, unsigned int buffer_size) +{ + int len = 0; + + while (buffer_size > 0) { + len = _fastboot_write_buffer(buffer + len, buffer_size); + buffer_size -= len; + + udc_irq(); + } + udc_irq(); + + return 0; +} + +void fastboot_shutdown(void) +{ + usb_shutdown(); + + /* Reset interface*/ + if (fastboot_interface && + fastboot_interface->reset_handler) { + fastboot_interface->reset_handler(); + } + + /* Reset some globals */ + _fastboot_destroy_endpoints(); + fastboot_interface = NULL; + fastboot_configured_flag = 0; + usb_disconnected = 0; + + /*free memory*/ + udc_destroy(); +} + +/* + * CPU and board-specific fastboot initializations. Aliased function + * signals caller to move on + */ +static void __def_fastboot_setup(void) +{ + /*do nothing here*/ +} +void board_fastboot_setup(void) \ + __attribute__((weak, alias("__def_fastboot_setup"))); + + +void fastboot_setup(void) +{ + /*execute board relevant initilizations for preparing fastboot */ + board_fastboot_setup(); + + /*get the fastboot dev*/ + _fastboot_setup_dev(); + + /*check if we need to setup recovery*/ +#ifdef CONFIG_ANDROID_RECOVERY + check_recovery_mode(); +#endif + + /*load partitions information for the fastboot dev*/ + _fastboot_load_partitions(); +} + +/* export to lib_arm/board.c */ +void check_fastboot(void) +{ + if (fastboot_check_and_clean_flag()) + do_fastboot(NULL, 0, 0, 0); +} + +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) \ + || defined(CONFIG_FASTBOOT_STORAGE_MMC) +/** + @mmc_dos_partition_index: the partition index in mbr. + @mmc_partition_index: the boot partition or user partition index, + not related to the partition table. + */ +static int _fastboot_parts_add_ptable_entry(int ptable_index, + int mmc_dos_partition_index, + int mmc_partition_index, + const char *name, + block_dev_desc_t *dev_desc, + struct fastboot_ptentry *ptable) +{ + disk_partition_t info; + strcpy(ptable[ptable_index].name, name); + + if (get_partition_info(dev_desc, + mmc_dos_partition_index, &info)) { + printf("Bad partition index:%d for partition:%s\n", + mmc_dos_partition_index, name); + return -1; + } else { + ptable[ptable_index].start = info.start; + ptable[ptable_index].length = info.size; + ptable[ptable_index].partition_id = mmc_partition_index; + } + return 0; +} + +static int _fastboot_parts_load_from_ptable(void) +{ + int i; +#ifdef CONFIG_CMD_SATA + int sata_device_no; +#endif + + /* mmc boot partition: -1 means no partition, 0 user part., 1 boot part. + * default is no partition, for emmc default user part, except emmc*/ + int boot_partition = FASTBOOT_MMC_NONE_PARTITION_ID; + int user_partition = FASTBOOT_MMC_NONE_PARTITION_ID; + + struct mmc *mmc; + block_dev_desc_t *dev_desc; + struct fastboot_ptentry ptable[PTN_RECOVERY_INDEX + 1]; + + /* sata case in env */ + if (fastboot_devinfo.type == DEV_SATA) { +#ifdef CONFIG_CMD_SATA + puts("flash target is SATA\n"); + if (sata_initialize()) + return -1; + sata_device_no = CONFIG_FASTBOOT_SATA_NO; + if (sata_device_no >= CONFIG_SYS_SATA_MAX_DEVICE) { + printf("Unknown SATA(%d) device for fastboot\n", + sata_device_no); + return -1; + } + dev_desc = sata_get_dev(sata_device_no); +#else /*! CONFIG_CMD_SATA*/ + puts("SATA isn't buildin\n"); + return -1; +#endif /*! CONFIG_CMD_SATA*/ + } else if (fastboot_devinfo.type == DEV_MMC) { + int mmc_no = 0; + mmc_no = fastboot_devinfo.dev_id; + + printf("flash target is MMC:%d\n", mmc_no); + mmc = find_mmc_device(mmc_no); + if (mmc && mmc_init(mmc)) + printf("MMC card init failed!\n"); + + dev_desc = get_dev("mmc", mmc_no); + if (NULL == dev_desc) { + printf("** Block device MMC %d not supported\n", + mmc_no); + return -1; + } + + /* multiple boot paritions for eMMC 4.3 later */ + if (mmc->part_config != MMCPART_NOAVAILABLE) { + boot_partition = FASTBOOT_MMC_BOOT_PARTITION_ID; + user_partition = FASTBOOT_MMC_USER_PARTITION_ID; + } + } else { + printf("Can't setup partition table on this device %d\n", + fastboot_devinfo.type); + return -1; + } + + memset((char *)ptable, 0, + sizeof(struct fastboot_ptentry) * (PTN_RECOVERY_INDEX + 1)); + /* MBR */ + strcpy(ptable[PTN_MBR_INDEX].name, "mbr"); + ptable[PTN_MBR_INDEX].start = ANDROID_MBR_OFFSET / dev_desc->blksz; + ptable[PTN_MBR_INDEX].length = ANDROID_MBR_SIZE / dev_desc->blksz; + ptable[PTN_MBR_INDEX].partition_id = user_partition; + /* Bootloader */ + strcpy(ptable[PTN_BOOTLOADER_INDEX].name, "bootloader"); + ptable[PTN_BOOTLOADER_INDEX].start = + ANDROID_BOOTLOADER_OFFSET / dev_desc->blksz; + ptable[PTN_BOOTLOADER_INDEX].length = + ANDROID_BOOTLOADER_SIZE / dev_desc->blksz; + ptable[PTN_BOOTLOADER_INDEX].partition_id = boot_partition; + + _fastboot_parts_add_ptable_entry(PTN_KERNEL_INDEX, + CONFIG_ANDROID_BOOT_PARTITION_MMC, + user_partition, "boot", dev_desc, ptable); + _fastboot_parts_add_ptable_entry(PTN_RECOVERY_INDEX, + CONFIG_ANDROID_RECOVERY_PARTITION_MMC, + user_partition, + "recovery", dev_desc, ptable); + _fastboot_parts_add_ptable_entry(PTN_SYSTEM_INDEX, + CONFIG_ANDROID_SYSTEM_PARTITION_MMC, + user_partition, + "system", dev_desc, ptable); + + for (i = 0; i <= PTN_RECOVERY_INDEX; i++) + fastboot_flash_add_ptn(&ptable[i]); + + return 0; +} +#endif /*CONFIG_FASTBOOT_STORAGE_SATA || CONFIG_FASTBOOT_STORAGE_MMC*/ + +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) +static unsigned long long _memparse(char *ptr, char **retptr) +{ + char *endptr; /* local pointer to end of parsed string */ + + unsigned long ret = simple_strtoul(ptr, &endptr, 0); + + switch (*endptr) { + case 'M': + case 'm': + ret <<= 10; + case 'K': + case 'k': + ret <<= 10; + endptr++; + default: + break; + } + + if (retptr) + *retptr = endptr; + + return ret; +} + +static int _fastboot_parts_add_env_entry(char *s, char **retptr) +{ + unsigned long size; + unsigned long offset = 0; + char *name; + int name_len; + int delim; + unsigned int flags; + struct fastboot_ptentry part; + + size = _memparse(s, &s); + if (0 == size) { + printf("Error:FASTBOOT size of parition is 0\n"); + return 1; + } + + /* fetch partition name and flags */ + flags = 0; /* this is going to be a regular partition */ + delim = 0; + /* check for offset */ + if (*s == '@') { + s++; + offset = _memparse(s, &s); + } else { + printf("Error:FASTBOOT offset of parition is not given\n"); + return 1; + } + + /* now look for name */ + if (*s == '(') + delim = ')'; + + if (delim) { + char *p; + + name = ++s; + p = strchr((const char *)name, delim); + if (!p) { + printf("Error:FASTBOOT no closing %c found in partition name\n", + delim); + return 1; + } + name_len = p - name; + s = p + 1; + } else { + printf("Error:FASTBOOT no partition name for \'%s\'\n", s); + return 1; + } + + /* check for options */ + while (1) { + if (strncmp(s, "i", 1) == 0) { + flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_I; + s += 1; + } else if (strncmp(s, "ubifs", 5) == 0) { + /* ubifs */ + flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS; + s += 5; + } else { + break; + } + if (strncmp(s, "|", 1) == 0) + s += 1; + } + + /* enter this partition (offset will be calculated later if it is zero at this point) */ + part.length = size; + part.start = offset; + part.flags = flags; + + if (name) { + if (name_len >= sizeof(part.name)) { + printf("Error:FASTBOOT partition name is too long\n"); + return 1; + } + strncpy(&part.name[0], name, name_len); + /* name is not null terminated */ + part.name[name_len] = '\0'; + } else { + printf("Error:FASTBOOT no name\n"); + return 1; + } + + fastboot_flash_add_ptn(&part); + + /*if the nand partitions envs are not initialized, try to init them*/ + if (check_parts_values(&part)) + save_parts_values(&part, part.start, part.length); + + /* return (updated) pointer command line string */ + *retptr = s; + + /* return partition table */ + return 0; +} + +static int _fastboot_parts_load_from_env(void) +{ + char fbparts[FASTBOOT_FBPARTS_ENV_MAX_LEN], *env; + + env = getenv("fbparts"); + if (env) { + unsigned int len; + len = strlen(env); + if (len && len < FASTBOOT_FBPARTS_ENV_MAX_LEN) { + char *s, *e; + + memcpy(&fbparts[0], env, len + 1); + printf("Fastboot: Adding partitions from environment\n"); + s = &fbparts[0]; + e = s + len; + while (s < e) { + if (_fastboot_parts_add_env_entry(s, &s)) { + printf("Error:Fastboot: Abort adding partitions\n"); + pcount = 0; + return 1; + } + /* Skip a bunch of delimiters */ + while (s < e) { + if ((' ' == *s) || + ('\t' == *s) || + ('\n' == *s) || + ('\r' == *s) || + (',' == *s)) { + s++; + } else { + break; + } + } + } + } + } + + return 0; +} +#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/ + +static void _fastboot_load_partitions(void) +{ + pcount = 0; +#if defined(CONFIG_FASTBOOT_STORAGE_NAND) + _fastboot_parts_load_from_env(); +#elif defined(CONFIG_FASTBOOT_STORAGE_SATA) \ + || defined(CONFIG_FASTBOOT_STORAGE_MMC) + _fastboot_parts_load_from_ptable(); +#endif +} + +/* + * Android style flash utilties */ +void fastboot_flash_add_ptn(struct fastboot_ptentry *ptn) +{ + if (pcount < MAX_PTN) { + memcpy(ptable + pcount, ptn, sizeof(struct fastboot_ptentry)); + pcount++; + } +} + +void fastboot_flash_dump_ptn(void) +{ + unsigned int n; + for (n = 0; n < pcount; n++) { + struct fastboot_ptentry *ptn = ptable + n; + printf("ptn %d name='%s' start=%d len=%d\n", + n, ptn->name, ptn->start, ptn->length); + } +} + + +struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name) +{ + unsigned int n; + + for (n = 0; n < pcount; n++) { + /* Make sure a substring is not accepted */ + if (strlen(name) == strlen(ptable[n].name)) { + if (0 == strcmp(ptable[n].name, name)) + return ptable + n; + } + } + + printf("can't find partition: %s, dump the partition table\n", name); + fastboot_flash_dump_ptn(); + return 0; +} + +struct fastboot_ptentry *fastboot_flash_get_ptn(unsigned int n) +{ + if (n < pcount) + return ptable + n; + else + return 0; +} + +unsigned int fastboot_flash_get_ptn_count(void) +{ + return pcount; +} diff --git a/include/configs/mx6qsabre_common.h b/include/configs/mx6qsabre_common.h index 5d30d60..178ece4 100644 --- a/include/configs/mx6qsabre_common.h +++ b/include/configs/mx6qsabre_common.h @@ -419,4 +419,8 @@ #endif #define CONFIG_IMX_HDMI +#if defined(CONFIG_ANDROID_SUPPORT) +#include "mx6qsabreandroid_common.h" +#endif + #endif /* __MX6QSABRE_COMMON_CONFIG_H */ diff --git a/include/configs/mx6qsabreandroid_common.h b/include/configs/mx6qsabreandroid_common.h new file mode 100644 index 0000000..d024c01 --- /dev/null +++ b/include/configs/mx6qsabreandroid_common.h @@ -0,0 +1,69 @@ + +/* + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * Configuration android settings for the MX6Q Sabre Freescale board. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef MX6Q_SABRE_ANDROID_H +#define MX6Q_SABRE_ANDROID_H + +#define CONFIG_USB_DEVICE +#define CONFIG_IMX_UDC 1 + +#define CONFIG_FASTBOOT 1 +#define CONFIG_FASTBOOT_VENDOR_ID 0x18d1 +#define CONFIG_FASTBOOT_PRODUCT_ID 0x0d02 +#define CONFIG_FASTBOOT_BCD_DEVICE 0x311 +#define CONFIG_FASTBOOT_MANUFACTURER_STR "Freescale" +#define CONFIG_FASTBOOT_PRODUCT_NAME_STR "i.mx6 Sabre Board" +#define CONFIG_FASTBOOT_INTERFACE_STR "Android fastboot" +#define CONFIG_FASTBOOT_CONFIGURATION_STR "Android fastboot" +#define CONFIG_FASTBOOT_SERIAL_NUM "12345" +#define CONFIG_FASTBOOT_SATA_NO 0 + +#if defined CONFIG_SYS_BOOT_NAND +#define CONFIG_FASTBOOT_STORAGE_NAND +#elif defined CONFIG_SYS_BOOT_SATA +#define CONFIG_FASTBOOT_STORAGE_SATA +#else +#define CONFIG_FASTBOOT_STORAGE_MMC +#endif + +/* For system.img growing up more than 256MB, more buffer needs +* to receive the system.img*/ +#define CONFIG_FASTBOOT_TRANSFER_BUF 0x2c000000 +#define CONFIG_FASTBOOT_TRANSFER_BUF_SIZE 0x19000000 /* 400M byte */ + + +#define CONFIG_CMD_BOOTI +#define CONFIG_ANDROID_RECOVERY +/* which mmc bus is your main storage ? */ +#define CONFIG_ANDROID_MAIN_MMC_BUS 2 +#define CONFIG_ANDROID_BOOT_PARTITION_MMC 1 +#define CONFIG_ANDROID_SYSTEM_PARTITION_MMC 5 +#define CONFIG_ANDROID_RECOVERY_PARTITION_MMC 2 +#define CONFIG_ANDROID_CACHE_PARTITION_MMC 6 + +#undef CONFIG_EXTRA_ENV_SETTINGS +#undef CONFIG_BOOTCOMMAND + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "splashpos=m,m\0" + +#endif diff --git a/include/fastboot.h b/include/fastboot.h new file mode 100644 index 0000000..c81abcf --- /dev/null +++ b/include/fastboot.h @@ -0,0 +1,376 @@ +/* + * (C) Copyright 2008 - 2009 + * Windriver, <www.windriver.com> + * Tom Rix <Tom.Rix@windriver.com> + * + * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * The logical naming of flash comes from the Android project + * Thse structures and functions that look like fastboot_flash_* + * They come from bootloader/legacy/include/boot/flash.h + * + * The boot_img_hdr structure and associated magic numbers also + * come from the Android project. They are from + * system/core/mkbootimg/bootimg.h + * + * Here are their copyrights + * + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef FASTBOOT_H +#define FASTBOOT_H + +#include <common.h> +#include <command.h> + +/* This is the interface file between the common cmd_fastboot.c and + the board specific support. + + To use this interface, define CONFIG_FASTBOOT in your board config file. + An example is include/configs/mx6slevkandroid.h + ... + #define CONFIG_FASTBOOT 1 / * Using fastboot interface * / + ... + +*/ + +/* From fastboot client.. */ +#define FASTBOOT_INTERFACE_CLASS 0xff +#define FASTBOOT_INTERFACE_SUB_CLASS 0x42 +#define FASTBOOT_INTERFACE_PROTOCOL 0x03 + +#define FASTBOOT_VERSION "0.5" + +/* Max size of responses from us to host */ +#define FASTBOOT_RESPONSE_SIZE 65 + +/* The fastboot client uses a value of 2048 for the + page size of it boot.img file format. + Reset this in your board config file as needed. */ +#ifndef CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE +#define CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE 2048 +#endif + +/* Lower byte shows if the read/write/erase operation in + repeated. The base address is incremented. + Either 0 or 1 is ok for a default */ + +#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 + +/* Status values */ +#define FASTBOOT_OK 0 +#define FASTBOOT_ERROR -1 +#define FASTBOOT_DISCONNECT 1 +#define FASTBOOT_INACTIVE 2 + +/* Android bootimage file format */ +#define FASTBOOT_BOOT_MAGIC "ANDROID!" +#define FASTBOOT_BOOT_MAGIC_SIZE 8 +#define FASTBOOT_BOOT_NAME_SIZE 16 +#define FASTBOOT_BOOT_ARGS_SIZE 512 + +#define FASTBOOT_MMC_BOOT_PARTITION_ID 1 +#define FASTBOOT_MMC_USER_PARTITION_ID 0 +#define FASTBOOT_MMC_NONE_PARTITION_ID -1 + +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; +}; + +struct fastboot_device_info { + unsigned char type; + unsigned char dev_id; +}; + +/* Boot img hdr structure comes from the Android project + * See it in: system/core/mkbootimg/bootimg.h + */ +struct fastboot_boot_img_hdr { + unsigned char magic[FASTBOOT_BOOT_MAGIC_SIZE]; + + unsigned kernel_size; /* size in bytes */ + unsigned kernel_addr; /* physical load addr */ + + unsigned ramdisk_size; /* size in bytes */ + unsigned ramdisk_addr; /* physical load addr */ + + unsigned second_size; /* size in bytes */ + unsigned second_addr; /* physical load addr */ + + unsigned tags_addr; /* physical addr for kernel tags */ + unsigned page_size; /* flash page size we assume */ + unsigned unused[2]; /* future expansion: should be 0 */ + + unsigned char name[FASTBOOT_BOOT_NAME_SIZE]; /* asciiz product name */ + + unsigned char cmdline[FASTBOOT_BOOT_ARGS_SIZE]; + + unsigned id[8]; /* timestamp / checksum / sha1 / etc */ +}; + +#ifdef CONFIG_FASTBOOT + +extern struct fastboot_device_info fastboot_devinfo; + +/* Prepare the fastboot environments, + * should be executed before "fastboot" cmd + */ +void fastboot_setup(void); + +/* Initizes the board specific fastboot + * Returns 0 on success + * Returns 1 on failure + */ +int fastboot_init(struct cmd_fastboot_interface *interface); + +/* Cleans up the board specific fastboot */ +void fastboot_shutdown(void); + +/* + * Handles board specific usb protocol exchanges + * Returns 0 on success + * Returns 1 on disconnects, break out of loop + * Returns 2 if no USB activity detected + * Returns -1 on failure, unhandled usb requests and other error conditions +*/ +int fastboot_poll(void); + +/* Is this high speed (2.0) or full speed (1.1) ? + * Returns 0 on full speed + * Returns 1 on high speed + */ +int fastboot_is_highspeed(void); + +/* Return the size of the fifo */ +int fastboot_fifo_size(void); + +/* Send a status reply to the client app + * buffer does not have to be null terminated. + * buffer_size must be not be larger than what is returned by + * fastboot_fifo_size + * Returns 0 on success + * Returns 1 on failure + */ +int fastboot_tx_status(const char *buffer, unsigned int buffer_size); + +/* + * Send some data to the client app + * buffer does not have to be null terminated. + * buffer_size can be larger than what is returned by + * fastboot_fifo_size + * Returns number of bytes written + */ +int fastboot_tx(unsigned char *buffer, unsigned int buffer_size); + +/* A board specific variable handler. + * The size of the buffers is governed by the fastboot spec. + * rx_buffer is at most 57 bytes + * tx_buffer is at most 60 bytes + * Returns 0 on success + * Returns 1 on failure + */ +int fastboot_getvar(const char *rx_buffer, char *tx_buffer); + +/* 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); + +/*fastboot command handling function*/ +int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + +/*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*/ + +#else /*! CONFIG_FASTBOOT*/ + +/* Stubs for when CONFIG_FASTBOOT is not defined */ +#define fastboot_setup() 0 +#define fastboot_init(a) 1 +#define fastboot_shutdown() +#define fastboot_poll() 1 +#define fastboot_is_highspeed() 0 +#define fastboot_fifo_size() 0 +#define fastboot_tx_status(a, b) 1 +#define fastboot_getvar(a, b) 1 +#define fastboot_tx(a, b) 1 + +#define fastboot_flash_add_ptn(a) +#define fastboot_flash_find_ptn(a) NULL +#define fastboot_flash_get_ptn(a) NULL +#define fastboot_flash_get_ptn_count() 0 +#define fastboot_flash_dump_ptn() +#define do_fastboot(a, b, c, d) 0 + +#define fastboot_quick(a) 0 +#define fastboot_get_ep_num(a, b) 0 +#define fastboot_dump_memory(a, b) 0 +#define DBG_ALWS(x...) +#define DBG_ERR(x...) +#define DBG_DEBUG(x...) +#define DBG_INFO(x...) + + +#endif /*! CONFIG_FASTBOOT*/ +#endif /* FASTBOOT_H */ diff --git a/include/recovery.h b/include/recovery.h new file mode 100644 index 0000000..448ef1e --- /dev/null +++ b/include/recovery.h @@ -0,0 +1,35 @@ +/* + * Android Recovery supported header file + * + * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#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 |