| /* |
| * Copyright (C) 2010 Samsung Electronics Co. Ltd |
| * |
| * Many parts of this program were copied from the work of Windriver. |
| * Major modifications are as follows: |
| * - Adding default partition table. |
| * - Supporting OneNAND device. |
| * - Supporting SDMMC device. |
| * - Adding new command, sdfuse. |
| * - Removing Lock scheme. |
| * - Removing direct flash operations because they are implemented at others. |
| * - Fixing several bugs |
| * This program is under the same License with the their work. |
| * |
| * This is their Copyright: |
| * |
| * (C) Copyright 2008 - 2009 |
| * Windriver, <www.windriver.com> |
| * Tom Rix <Tom.Rix@windriver.com> |
| * |
| * 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 <asm/arch/movi_partition.h> |
| #include <asm/arch/power.h> |
| #include <fastboot.h> |
| #if defined(CFG_FASTBOOT_SDMMCBSP) |
| #include <mmc.h> |
| #endif |
| #include <decompress_ext4.h> |
| #include <version.h> |
| #include <malloc.h> |
| |
| #if defined(CONFIG_S5P6450) |
| DECLARE_GLOBAL_DATA_PTR; |
| #endif |
| |
| #if defined(CONFIG_EXYNOS4X12) |
| #define OmPin readl(EXYNOS4_POWER_BASE + INFORM3_OFFSET) |
| #elif defined(CONFIG_CPU_EXYNOS4415) || defined(CONFIG_CPU_EXYNOS3250) |
| #define OmPin readl(EXYNOS4_POWER_BASE + INFORM3_OFFSET) |
| #elif defined(CONFIG_CPU_EXYNOS5260) |
| #define OmPin readl(EXYNOS5260_POWER_BASE + INFORM3_OFFSET) |
| #elif defined(CONFIG_CPU_EXYNOS5430) |
| #define OmPin readl(EXYNOS5430_POWER_BASE + INFORM3_OFFSET) |
| #else |
| #define OmPin readl(EXYNOS5_POWER_BASE + INFORM3_OFFSET) |
| #endif |
| |
| #define BASEBAND_VERSION "N/A" |
| |
| #if defined(CONFIG_FASTBOOT) |
| |
| /* Use do_reset for fastboot's 'reboot' command */ |
| //extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); |
| /* Use do_fat_fsload for direct image fusing from sd card */ |
| //extern int do_fat_fsload (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); |
| /* Use do_setenv and do_saveenv to permenantly save data */ |
| int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); |
| int do_setenv ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); |
| /* Use do_bootm and do_go for fastboot's 'boot' command */ |
| //int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); |
| int do_go (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); |
| |
| #if defined(CFG_FASTBOOT_ONENANDBSP) |
| #define CFG_FASTBOOT_FLASHCMD do_onenand |
| /* Use do_onenand for fastboot's flash commands */ |
| extern int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]); |
| #elif defined(CFG_FASTBOOT_NANDBSP) |
| #define CFG_FASTBOOT_FLASHCMD do_nand |
| /* Use do_nand for fastboot's flash commands */ |
| extern int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]); |
| #endif |
| |
| #if defined(CFG_FASTBOOT_SDMMCBSP) |
| int do_movi(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]); |
| int do_mmcops(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]); |
| int do_mmcops_secure(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]); |
| int get_boot_part_info(int dev_num, int part_num, int *start, int *count, unsigned char *pid); |
| struct mmc *find_mmc_device(int dev_num); |
| int write_raw_ramdisk(unsigned char *buffer, unsigned size); |
| int write_raw_kernel(unsigned char *buffer, unsigned size); |
| #endif |
| |
| #ifdef CONFIG_USE_LCD |
| extern void Display_Turnoff(void); |
| extern void LCD_setfgcolor(unsigned int color); |
| extern void LCD_setleftcolor(unsigned int color); |
| extern void LCD_setprogress(int percentage); |
| #endif |
| |
| /* Forward decl */ |
| static int rx_handler (const unsigned char *buffer, unsigned int buffer_size); |
| static void reset_handler (void); |
| |
| /* cmd_fastboot_interface in fastboot.h */ |
| 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, |
| }; |
| #if defined(CONFIG_RAMDUMP_MODE) |
| static unsigned int is_ramdump = 0; |
| #endif |
| static unsigned int download_size; |
| static unsigned int download_bytes; |
| //static unsigned int download_bytes_unpadded; |
| static unsigned int download_error; |
| |
| /* To support the Android-style naming of flash */ |
| #define MAX_PTN 16 |
| static fastboot_ptentry ptable[MAX_PTN]; |
| static unsigned int pcount; |
| static int static_pcount = -1; |
| |
| /* Default partition table (see cpu/.../fastboot.c) */ |
| extern fastboot_ptentry *ptable_default; |
| extern unsigned int ptable_default_size; |
| |
| static unsigned int fastboot_continue_autoboot; |
| |
| static void set_env(char *var, char *val) |
| { |
| char *setenv[4] = { "setenv", NULL, NULL, NULL, }; |
| |
| setenv[1] = var; |
| setenv[2] = val; |
| |
| do_env_set(NULL, 0, 3, setenv); |
| } |
| |
| static void save_env(struct fastboot_ptentry *ptn, |
| char *var, char *val) |
| { |
| #ifndef CFG_FASTBOOT_SDMMCBSP |
| char start[32], length[32]; |
| char ecc_type[32]; |
| |
| char *lock[5] = { "nand", "lock", NULL, NULL, NULL, }; |
| char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL, }; |
| char *ecc[4] = { "nand", "ecc", NULL, NULL, }; |
| char *saveenv[2] = { "setenv", NULL, }; |
| |
| lock[2] = unlock[2] = start; |
| lock[3] = unlock[3] = length; |
| |
| set_env (var, val); |
| |
| /* Some flashing requires the nand's ecc to be set */ |
| ecc[2] = ecc_type; |
| if ((ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) && |
| (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)) { |
| /* Both can not be true */ |
| printf("Warning can not do hw and sw ecc for partition '%s'\n", ptn->name); |
| printf("Ignoring these flags\n"); |
| } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) { |
| sprintf(ecc_type, "hw"); |
| CFG_FASTBOOT_FLASHCMD(NULL, 0, 3, ecc); |
| } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) { |
| sprintf(ecc_type, "sw"); |
| CFG_FASTBOOT_FLASHCMD(NULL, 0, 3, ecc); |
| } |
| sprintf(start, "0x%x", ptn->start); |
| sprintf(length, "0x%x", ptn->length); |
| |
| /* This could be a problem is there is an outstanding lock */ |
| CFG_FASTBOOT_FLASHCMD(NULL, 0, 4, unlock); |
| do_saveenv(NULL, 0, 1, saveenv); |
| CFG_FASTBOOT_FLASHCMD(NULL, 0, 4, lock); |
| #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; |
| } |
| |
| |
| /* 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; |
| unsigned int size = download_bytes; |
| |
| /* 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(CFG_FASTBOOT_ONENANDBSP) || defined(CFG_FASTBOOT_NANDBSP) |
| static int write_to_ptn(struct fastboot_ptentry *ptn, unsigned int addr, unsigned int size) |
| { |
| int ret = 1; |
| char start[32], length[32]; |
| char wstart[32], wlength[32], wbuffer[32]; |
| char write_type[32]; |
| |
| /* do_nand and do_onenand do not check argv[0] */ |
| char *argv_erase[5] = { NULL, "erase", NULL, NULL, NULL, }; |
| char *argv_write[6] = { NULL, NULL, NULL, NULL, NULL, NULL, }; |
| |
| argv_erase[2] = start; |
| argv_erase[3] = length; |
| |
| argv_write[1] = write_type; |
| argv_write[2] = wbuffer; |
| argv_write[3] = wstart; |
| argv_write[4] = wlength; |
| |
| printf("flashing '%s'\n", ptn->name); |
| |
| sprintf(start, "0x%x", ptn->start); |
| if (ptn->length == 0) |
| { |
| CFG_FASTBOOT_FLASHCMD(NULL, 0, 3, argv_erase); |
| } |
| else |
| { |
| if (strcmp(ptn->name, "bootloader")) |
| { |
| sprintf(length, "0x%x", ptn->length); |
| CFG_FASTBOOT_FLASHCMD(NULL, 0, 4, argv_erase); |
| } |
| } |
| /* Which flavor of write to use */ |
| if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS) |
| { |
| sprintf(write_type, "write.yaffs"); |
| sprintf(wlength, "0x%x", size); |
| } |
| else |
| { |
| sprintf(write_type, "write"); |
| if (interface.nand_block_size && |
| (size % interface.nand_block_size)) |
| { |
| size = (size + interface.nand_block_size - 1) |
| / interface.nand_block_size * interface.nand_block_size; |
| } |
| |
| sprintf(wlength, "0x%x", size); |
| } |
| sprintf(wbuffer, "0x%x", addr); |
| sprintf(wstart, "0x%x", ptn->start); |
| |
| if (!strcmp(ptn->name, "bootloader")) |
| { |
| argv_write[2] = "u-boot"; |
| sprintf(wstart, "0x%x", addr); |
| } |
| |
| ret = CFG_FASTBOOT_FLASHCMD(NULL, 0, 5, argv_write); |
| |
| #if 0 |
| if (0 == repeat) { |
| if (ret) /* failed */ |
| save_block_values(ptn, 0, 0); |
| else /* success */ |
| save_block_values(ptn, ptn->start, download_bytes); |
| } |
| #endif |
| |
| return ret; |
| } |
| #endif |
| |
| #if defined(CFG_FASTBOOT_SDMMCBSP) |
| #if defined(CONFIG_S5P6450) && !defined(CONFIG_EMMC_4_4) |
| #define DEV_NUM 1 |
| #else |
| #define DEV_NUM 0 |
| #endif |
| |
| static int write_to_ptn_sdmmc(struct fastboot_ptentry *ptn, unsigned int addr, unsigned int size) |
| { |
| int ret = 1; |
| char cmd[32], device[32], part[32], part2[32]; |
| char start[32], length[32], buffer[32], run_cmd[32]; |
| char dev_num[2]; |
| char *argv[6] = { NULL, NULL, NULL, NULL, NULL, NULL, }; |
| int argc = 0; |
| char *nul_buf; |
| #if defined(CONFIG_MMC_64BIT_BUS) || defined(CONFIG_CPU_EXYNOS5410_EVT2) |
| char *nul_buf_align; |
| #endif |
| struct mmc *mmc; |
| |
| if ((ptn->length != 0) && (size > ptn->length)) |
| { |
| printf("Error: Image size is larger than partition size!\n"); |
| return 1; |
| } |
| |
| printf("flashing '%s'\n", ptn->name); |
| |
| argv[1] = cmd; |
| sprintf(cmd, "write"); |
| |
| if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD) |
| { |
| if (addr && check_compress_ext4((char*)addr,ptn->length) != 0) { |
| argv[2] = device; |
| argv[3] = buffer; |
| argv[4] = start; |
| argv[5] = length; |
| |
| sprintf(device, "%d", DEV_NUM); |
| sprintf(buffer, "0x%x", addr); |
| sprintf(start, "0x%x", (ptn->start / CFG_FASTBOOT_SDMMC_BLOCKSIZE)); |
| sprintf(length, "0x%x", ((size + CFG_FASTBOOT_SDMMC_BLOCKSIZE - 1) |
| / CFG_FASTBOOT_SDMMC_BLOCKSIZE)); |
| |
| ret = do_mmcops(NULL, 0, 6, argv); |
| } else { |
| uint bl_st = ptn->start / CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| uint bl_cnt = ptn->length / CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| |
| printf("Compressed ext4 image\n"); |
| |
| #if defined(CONFIG_MMC_64BIT_BUS) || defined(CONFIG_CPU_EXYNOS5410_EVT2) |
| nul_buf_align = calloc(sizeof(char), 512*1024 + 4); |
| if (((unsigned int)nul_buf_align % 8) == 0) |
| nul_buf = nul_buf_align; |
| else |
| nul_buf = nul_buf_align + 4; |
| #else |
| nul_buf = calloc(sizeof(char), 512*1024); |
| #endif |
| if (nul_buf == NULL) { |
| printf("Error: calloc failed for nul_buf\n"); |
| ret = 1; |
| return ret; |
| } |
| |
| mmc = find_mmc_device(DEV_NUM); |
| |
| if (bl_st&0x3ff) |
| { |
| mmc->block_dev.block_write(DEV_NUM, bl_st, 1024 -(bl_st&0x3ff), nul_buf); |
| |
| printf("*** erase start block 0x%x ***\n", bl_st); |
| |
| bl_cnt = bl_cnt - (1024-(bl_st&0x3ff)); |
| bl_st = (bl_st&(~0x3ff))+1024; |
| } |
| |
| if (bl_cnt&0x3ff) |
| { |
| mmc->block_dev.block_write(DEV_NUM, bl_st+bl_cnt-(bl_cnt&0x3ff), bl_cnt&0x3ff, nul_buf); |
| |
| printf("*** erase block length 0x%x ***\n", bl_cnt); |
| |
| bl_cnt = bl_cnt - (bl_cnt&0x3ff); |
| } |
| |
| #if defined(CONFIG_MMC_64BIT_BUS) || defined(CONFIG_CPU_EXYNOS5410_EVT2) |
| free(nul_buf_align); |
| #else |
| free(nul_buf); |
| #endif |
| |
| if (bl_cnt>>10) |
| { |
| argv[2] = buffer; |
| argv[3] = device; |
| argv[4] = start; |
| argv[5] = length; |
| |
| sprintf(cmd, "erase"); |
| sprintf(buffer, "user"); |
| sprintf(device, "%d", DEV_NUM); |
| sprintf(start, "%x", bl_st); |
| sprintf(length, "%x", bl_cnt); |
| printf("mmc %s %s %s %s %s\n", argv[1], argv[2], argv[3], argv[4], argv[5]); |
| |
| ret = do_mmcops(NULL, 0, 6, argv); |
| } |
| else |
| { |
| printf("*** erase block length too small ***\n"); |
| } |
| if (addr == 0) |
| return 0; |
| |
| ret = write_compressed_ext4((char*)addr, |
| ptn->start / CFG_FASTBOOT_SDMMC_BLOCKSIZE); |
| } |
| } |
| else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD) |
| { |
| int zero = 0; |
| argv[2] = part; |
| argv[3] = dev_num; |
| argv[4] = buffer; |
| sprintf(dev_num, "%d", DEV_NUM); |
| |
| argc = 5; |
| if ((!strcmp(ptn->name, "fwbl1") || !strcmp(ptn->name, "u-boot") || |
| !strcmp(ptn->name, "bl2") || !strcmp(ptn->name, "tzsw"))) { |
| #ifdef CONFIG_AUTO_FW_WRITE |
| zero = 1; |
| #else |
| zero = (OmPin == BOOT_EMMC_4_4) ? 1 : 0; |
| #endif |
| } |
| if (zero) { |
| argv[2] = part2; |
| argv[3] = part; |
| argv[4] = dev_num; |
| argv[5] = buffer; |
| argc = 6; |
| strncpy(part2, "zero", 7); |
| sprintf(run_cmd,"emmc open 0"); |
| run_command(run_cmd, 0); |
| } |
| /* use the partition name that can be understood by a command, movi */ |
| if (!strcmp(ptn->name, "u-boot")) |
| { |
| strncpy(part, "u-boot", 7); |
| } |
| else if (!strcmp(ptn->name, "fwbl1")) |
| { |
| strncpy(part, "fwbl1", 6); |
| } |
| else if (!strcmp(ptn->name, "bl2")) |
| { |
| strncpy(part, "bl2", 4); |
| } |
| else if (!strcmp(ptn->name, "tzsw")) |
| { |
| strncpy(part, "tzsw", 5); |
| } |
| else if (!strcmp(ptn->name, "ramdisk")) |
| { |
| strncpy(part, "rootfs", 7); |
| argv[5] = length; |
| sprintf(length, "0x%x", |
| ((size + CFG_FASTBOOT_SDMMC_BLOCKSIZE - 1) |
| / CFG_FASTBOOT_SDMMC_BLOCKSIZE ) * CFG_FASTBOOT_SDMMC_BLOCKSIZE); |
| |
| #ifdef CONFIG_ROOTFS_ATAGS |
| char ramdisk_size[32]; |
| #ifdef CONFIG_SECURE_ROOTFS |
| sprintf(ramdisk_size, "0x%x", size - 256); |
| #else |
| sprintf(ramdisk_size, "0x%x", size); |
| #endif |
| setenv("rootfslen", ramdisk_size); |
| saveenv_one_variable("rootfslen", ramdisk_size); |
| #endif |
| |
| argc++; |
| } |
| #ifdef CONFIG_CHARGER_LOGO |
| else if (!strcmp(ptn->name, "charger")) |
| { |
| argv[2] = part; |
| strncpy(part, "charger", 7); |
| } |
| #endif |
| #ifdef CONFIG_BOOT_LOGO |
| else if (!strcmp(ptn->name, "bootlogo")) |
| { |
| argv[2] = part; |
| strncpy(part, "logo", 7); |
| } |
| #endif |
| #ifdef CONFIG_BOOT |
| else if (!strcmp(ptn->name, "boot")) |
| { |
| argv[2] = part; |
| strncpy(part, "Boot", 8); |
| |
| } |
| #endif |
| |
| #ifdef CONFIG_KERNEL_RECOVERY_MODE |
| else if (!strcmp(ptn->name, "recovery")) |
| { |
| argv[2] = part; |
| strncpy(part, "Recovery", 8); |
| |
| } |
| #endif |
| else /* kernel */ |
| { |
| argv[2] = ptn->name; |
| } |
| sprintf(buffer, "0x%x", addr); |
| |
| ret = do_movi(NULL, 0, argc, argv); |
| |
| if (zero){ |
| sprintf(run_cmd,"emmc close 0"); |
| run_command(run_cmd, 0); |
| } |
| |
| /* the return value of do_movi is different from usual commands. Hence the followings. */ |
| ret = 1 - ret; |
| } |
| |
| return ret; |
| } |
| #endif |
| |
| #if defined(CONFIG_RAMDUMP_MODE) |
| static void start_ramdump(void *buf) |
| { |
| unsigned *args; |
| args = (unsigned *)buf; |
| |
| printf("\nramdump start address is [0x%x]\n", *args); |
| printf("ramdump size is [0x%x]\n", *(args + 1)); |
| |
| if (!fastboot_tx_mem((const char *)*args, *(args + 1))) |
| printf("Failed ramdump~! \n"); |
| else |
| printf("Finished ramdump~! \n"); |
| } |
| #endif |
| |
| static int get_lock_state(void) |
| { |
| char *fastboot_locked_env; |
| unsigned long lock = 0; |
| |
| fastboot_locked_env = getenv("fastboot_locked"); |
| |
| if (fastboot_locked_env) |
| lock = simple_strtoul(fastboot_locked_env, NULL, 10); |
| |
| return lock; |
| } |
| |
| static void put_lock_state(int lock) |
| { |
| char *str[] = { "0", "1" }; |
| |
| setenv("fastboot_locked", str[lock]); |
| saveenv_one_variable("fastboot_locked", str[lock]); |
| } |
| |
| |
| static int rx_handler (const unsigned char *buffer, unsigned int buffer_size) |
| { |
| struct exynos4_power *pmu = (struct exynos4_power *)EXYNOS4_POWER_BASE; |
| int ret = 1; |
| /* Use 65 instead of 64 |
| null gets dropped |
| strcpy's need the extra byte */ |
| char response[256] __attribute__ ((aligned(8))); |
| char response_tmp[256] __attribute__ ((aligned(8))); |
| int is_all = 0; |
| |
| 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), FASTBOOT_TX_ASYNC); |
| |
| printf("\ndownloading of %d bytes finished\n", download_bytes); |
| #ifdef CONFIG_USE_LCD |
| LCD_setprogress(0); |
| #endif |
| #if defined(CONFIG_RAMDUMP_MODE) |
| if (is_ramdump) { |
| is_ramdump = 0; |
| start_ramdump((void *)buffer); |
| } |
| #endif |
| } |
| |
| /* Provide some feedback */ |
| if (download_bytes && download_size && |
| 0 == (download_bytes & (0x100000 - 1))) |
| { |
| /* Some feeback that the download is happening */ |
| if (download_error) |
| printf("X"); |
| else |
| printf("."); |
| if (0 == (download_bytes % |
| (80 * 0x100000))) |
| printf("\n"); |
| #ifdef CONFIG_USE_LCD |
| LCD_setfgcolor(0x2E8B57); |
| LCD_setprogress(download_bytes / (download_size/100)); |
| #endif |
| } |
| } |
| 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; |
| |
| /* Generic failed response */ |
| sprintf(response, "FAIL"); |
| |
| /* reboot |
| Reboot the board. */ |
| if (memcmp(cmdbuf, "reboot", 6) == 0) |
| { |
| if (!strcmp(cmdbuf + 6, "-bootloader")) |
| { |
| if((readl(&pmu->inform4))!= 0xD) |
| writel(0xD, &pmu->inform4); |
| } |
| else |
| { |
| if((readl(&pmu->inform4)) != 0x6) |
| writel(0x0, &pmu->inform4); |
| |
| memset(interface.transfer_buffer, 0x0, FASTBOOT_REBOOT_MAGIC_SIZE); |
| } |
| |
| sprintf(response,"OKAY"); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| //udelay (1000000); /* 1 sec */ |
| |
| #ifdef CONFIG_USE_LCD |
| /* Turning LCD off before SW reset. */ |
| Display_Turnoff(); |
| #endif |
| do_reset (NULL, 0, 0, NULL); |
| |
| /* 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) |
| { |
| |
| if (!strcmp(cmdbuf + 7, "all")) |
| is_all = 1; |
| |
| if (is_all || !strcmp(cmdbuf + 7, "version")) |
| { |
| if (is_all) |
| sprintf(response,"INFOversion: " FASTBOOT_VERSION ); |
| else |
| sprintf(response,"INFO" FASTBOOT_VERSION ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(cmdbuf + 7, "product")) |
| { |
| if (interface.product_name) { |
| if (is_all) |
| sprintf(response, "INFOproduct: %s",interface.product_name); |
| else |
| sprintf(response, "INFO%s",interface.product_name); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| } |
| if (is_all || !strcmp(cmdbuf + 7, "serialno")) |
| { |
| if (interface.serial_no) |
| { |
| if (is_all) |
| sprintf(response, "INFOserialno: %s", interface.serial_no); |
| else |
| sprintf(response, "INFO%s", interface.serial_no); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| } |
| if (is_all || !strcmp(cmdbuf + 7, "max-download-size")) |
| { |
| if (interface.transfer_buffer_size) |
| { |
| if (is_all) |
| sprintf(response, "INFOmax-download-size: %u", interface.transfer_buffer_size); |
| else |
| sprintf(response, "INFO%u", interface.transfer_buffer_size); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| } |
| if (is_all || !strcmp(cmdbuf + 7, "version-bootloader")) |
| { |
| if (is_all) |
| sprintf(response, "INFOversion-bootloader: " VERSION_BOOTLOADER); |
| else |
| sprintf(response, "INFO" VERSION_BOOTLOADER); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(cmdbuf + 7, "version-uboot")) |
| { |
| if (is_all) |
| sprintf(response, "INFOversion-uboot: " U_BOOT_VERSION); |
| else |
| sprintf(response, "INFO" U_BOOT_VERSION); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(cmdbuf + 7, "version-baseband")) |
| { |
| if (is_all) |
| sprintf(response , "INFOversion-baseband: " BASEBAND_VERSION); |
| else |
| sprintf(response , "INFO" BASEBAND_VERSION); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #ifdef CONFIG_LOCKING |
| if (is_all || !strcmp(cmdbuf + 7, "secure")) |
| { |
| if (get_lock_state()) { |
| if (is_all) |
| sprintf(response,"INFOsecure: yes"); |
| else |
| sprintf(response,"INFOyes"); |
| } else { |
| if (is_all) |
| sprintf(response,"INFOsecure: no"); |
| else |
| sprintf(response, "INFOno"); |
| } |
| |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(cmdbuf + 7, "unlocked")) |
| { |
| if (!get_lock_state()) { |
| if (is_all) |
| sprintf(response,"INFOunlocked: yes"); |
| else |
| sprintf(response, "INFOyes"); |
| } else { |
| if (is_all) |
| sprintf(response,"INFOunlocked: no"); |
| else |
| sprintf(response, "INFOno"); |
| } |
| |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #endif |
| if (is_all || memcmp(cmdbuf + 7, "partition-size:", 15) == 0) |
| { |
| struct fastboot_ptentry *ptn; |
| unsigned long long start, count; |
| unsigned char pid; |
| int dev_num = DEV_NUM; |
| |
| if(!is_all) |
| { |
| ptn = fastboot_flash_find_ptn(cmdbuf + 22); |
| if (ptn == 0) |
| { |
| sprintf(response, "FAILpartition does not exist"); |
| ret = 0; |
| goto send_tx_status; |
| } |
| } |
| |
| if (is_all || !strcmp(ptn->name, "fwbl1")) |
| { |
| if (is_all) |
| sprintf(response, "INFOpartition-size:fwbl1: %x", PART_SIZE_BL1); |
| else |
| sprintf(response, "INFO%x", PART_SIZE_BL1); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(ptn->name, "bl2")) |
| { |
| if (is_all) |
| sprintf(response, "INFOpartition-size:bl2: %x",PART_SIZE_BL2 ); |
| else |
| sprintf(response, "INFO%x",PART_SIZE_BL2 ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(ptn->name, "u-boot")) |
| { |
| if (is_all) |
| sprintf(response, "INFOpartition-size:u-boot: %x",PART_SIZE_UBOOT ); |
| else |
| sprintf(response, "INFO%x",PART_SIZE_UBOOT ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(ptn->name, "tzsw")) |
| { |
| if (is_all) |
| sprintf(response, "INFOpartition-size:tzsw: %x",PART_SIZE_TZSW ); |
| else |
| sprintf(response, "INFO%x",PART_SIZE_TZSW ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(ptn->name, "kernel")) |
| { |
| if (is_all) |
| sprintf(response, "INFOpartition-size:kernel: %x", PART_SIZE_KERNEL); |
| else |
| sprintf(response, "INFO%x", PART_SIZE_KERNEL); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(ptn->name, "ramdisk")) |
| { |
| if (is_all) |
| sprintf(response, "INFOpartition-size:ramdisk: %x",PART_SIZE_ROOTFS ); |
| else |
| sprintf(response, "INFO%x",PART_SIZE_ROOTFS ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #ifdef CONFIG_CHARGER_LOGO |
| if (is_all || !strcmp(ptn->name, "charger")) |
| { |
| if (is_all) |
| sprintf(response, "INFOpartition-size:charger: %x",PART_SIZE_CHARGER_LOGO); |
| else |
| sprintf(response, "INFO%x",PART_SIZE_CHARGER_LOGO); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #endif |
| #ifdef CONFIG_BOOT_LOGO |
| if (is_all || !strcmp(ptn->name, "bootlogo")) |
| { |
| if (is_all) |
| sprintf(response, "INFOpartition-size:bootlogo: %x",PART_SIZE_BOOT_LOGO); |
| else |
| sprintf(response, "INFO%x",PART_SIZE_BOOT_LOGO); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #endif |
| #ifdef CONFIG_BOOT |
| if (is_all || !strcmp(ptn->name, "boot")) |
| { |
| if (is_all) |
| sprintf(response, "INFOpartition-size:boot: %x",PART_SIZE_BOOT); |
| else |
| sprintf(response, "INFO%x",PART_SIZE_BOOT); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #endif |
| #ifdef CONFIG_KERNEL_RECOVERY_MODE |
| if (is_all || !strcmp(ptn->name, "recovery")) |
| { |
| if (is_all) |
| sprintf(response, "INFOpartition-size:recovery: %x",PART_SIZE_RECOVERY_MODE); |
| else |
| sprintf(response, "INFO%x",PART_SIZE_RECOVERY_MODE); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #endif |
| if (is_all || !strcmp(ptn->name, "system")) |
| { |
| get_boot_part_info(dev_num, 2, &start, &count, &pid); |
| if (is_all) |
| sprintf(response, "INFOpartition-size:system: %x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| else |
| sprintf(response, "INFO%x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(ptn->name, "userdata")) |
| { |
| get_boot_part_info(dev_num, 3, &start, &count, &pid); |
| if (is_all) |
| sprintf(response, "INFOpartition-size:userdata: %x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| else |
| sprintf(response, "INFO%x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (is_all || !strcmp(ptn->name, "cache")) |
| { |
| get_boot_part_info(dev_num, 4, &start, &count, &pid); |
| if (is_all) |
| sprintf(response, "INFOpartition-size:cache: %x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| else |
| sprintf(response, "INFO%x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #ifdef CONFIG_MISC |
| if (is_all || !strcmp(ptn->name, "misc")) |
| { |
| get_boot_part_info(dev_num, 5, &start, &count, &pid); |
| if (is_all) |
| sprintf(response, "INFOpartition-size:misc: %x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| else |
| sprintf(response, "INFO%x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #endif |
| if (is_all || !strcmp(ptn->name, "bootloader")) |
| { |
| get_boot_part_info(dev_num, 8, &start, &count, &pid); |
| if (is_all) |
| sprintf(response, "INFOpartition-size:bootloader: %x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| else |
| sprintf(response, "INFO%x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #ifdef CONFIG_FAT |
| if (is_all || !strcmp(ptn->name, "fat")) |
| { |
| get_boot_part_info(dev_num, 1, &start, &count, &pid); |
| if (is_all) |
| sprintf(response, "INFOpartition-size:fat: %x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| else |
| sprintf(response, "INFO%x",count * CFG_FASTBOOT_SDMMC_BLOCKSIZE ); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| #endif |
| } |
| if (is_all || memcmp(cmdbuf + 7, "partition-type:", 15) == 0) |
| { |
| |
| struct fastboot_ptentry *ptn; |
| unsigned long long start, count; |
| unsigned char pid; |
| int max_part = 1, i; |
| int dev_num = DEV_NUM; |
| #if defined (CONFIG_FAT) |
| char *p[]={"fat","system","userdata","cache"}; |
| if(is_all) |
| max_part = 4; |
| #elif defined (CONFIG_CMD_GPT) |
| char *p[]={"recovery","system","userdata","cache", "misc", "boot"}; |
| if(is_all) |
| max_part = 6; |
| #endif |
| |
| for (i = 0; i < max_part; i++) { |
| if (is_all) |
| ptn = fastboot_flash_find_ptn(p[i]); |
| else |
| ptn = fastboot_flash_find_ptn(cmdbuf + 22); |
| |
| sprintf(response, "INFO"); |
| |
| if (ptn == 0 && !is_all) |
| { |
| sprintf(response, "FAIL partition does not exist"); |
| ret = 0; |
| goto send_tx_status; |
| #ifdef CONFIG_FAT |
| } else if (!strcmp(ptn->name, "fat")) { |
| get_boot_part_info(dev_num, 1, &start, &count, &pid); |
| if (pid == 0x0C) |
| strcpy(response + 4, "FAT"); |
| #endif |
| #ifdef CONFIG_KERNEL_RECOVERY_MODE |
| } else if (!strcmp(ptn->name, "recovery")) { |
| get_boot_part_info(dev_num, 1, &start, &count, &pid); |
| if (pid == 0x83 || pid == 0xee) { |
| if (is_all) |
| strcpy(response + 4, "partition-type:recovery: ext4"); |
| else |
| strcpy(response + 4, "ext4"); |
| } |
| #endif |
| } else if (!strcmp(ptn->name, "system")) { |
| get_boot_part_info(dev_num, 2, &start, &count, &pid); |
| if (pid == 0x83 || pid == 0xee) { |
| if (is_all) |
| strcpy(response + 4, "partition-type:system: ext4"); |
| else |
| strcpy(response + 4, "ext4"); |
| } |
| } else if (!strcmp(ptn->name, "userdata")) { |
| get_boot_part_info(dev_num, 3, &start, &count, &pid); |
| if (pid == 0x83 || pid == 0xee) { |
| if (is_all) |
| strcpy(response + 4, "partition-type:userdata: ext4"); |
| else |
| strcpy(response + 4, "ext4"); |
| } |
| } else if (!strcmp(ptn->name, "cache")) { |
| get_boot_part_info(dev_num, 4, &start, &count, &pid); |
| if (pid == 0x83 || pid == 0xee) { |
| if (is_all) |
| strcpy(response + 4, "partition-type:cache: ext4"); |
| else |
| strcpy(response + 4, "ext4"); |
| } |
| #ifdef CONFIG_MISC |
| } else if (!strcmp(ptn->name, "misc")) { |
| get_boot_part_info(dev_num, 5, &start, &count, &pid); |
| if (pid == 0x83 || pid == 0xee) { |
| if (is_all) |
| strcpy(response + 4, "partition-type:misc: ext4"); |
| else |
| strcpy(response + 4, "ext4"); |
| } |
| #endif |
| #ifdef CONFIG_BOOT |
| } else if (!strcmp(ptn->name, "boot")) { |
| get_boot_part_info(dev_num, 6, &start, &count, &pid); |
| if (pid == 0x83 || pid == 0xee) { |
| if (is_all) |
| strcpy(response + 4, "partition-type:boot: ext4"); |
| else |
| strcpy(response + 4, "ext4"); |
| } |
| #endif |
| } else |
| strcpy(response + 4, " NO FILE SYSTEM PRESENT"); |
| |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| } |
| #ifdef CONFIG_FDISK |
| if (!strcmp(cmdbuf + 7, "fdisk")) |
| { |
| sprintf(response,"INFO"); |
| ret = run_command("fdisk -c 0 400 2600 200", 0); |
| if(ret == 0) |
| { |
| strcpy(response + 4, "fdisk ok"); |
| } |
| else |
| { |
| strcpy(response + 4, "fdisk fail"); |
| } |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| if (!strcmp(cmdbuf + 7, "ok")) |
| { |
| sprintf(response,"INFO"); |
| #if defined (CONFIG_CMD_FAT) |
| ret = run_command("fatformat mmc 0:1;ext4format mmc 0:2;ext4format mmc 0:3;ext4format mmc 0:4;", 0); |
| #elif defined (CONFIG_CMD_GPT) |
| ret = run_command("ext4format mmc 0:1;ext4format mmc 0:2;ext4format mmc 0:3;ext4format mmc 0:4;", 0); |
| #endif |
| if(ret == 0) |
| { |
| strcpy(response + 4, "format ok"); |
| } |
| else |
| { |
| strcpy(response + 4, "format fail"); |
| } |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| } |
| else |
| { |
| fastboot_getvar(cmdbuf + 7, response + 4); |
| } |
| #endif |
| ret = 0; |
| if (!is_all) { |
| strcpy(response_tmp, response); |
| sprintf(response,"OKAY"); |
| strcpy(response + 4, response_tmp + 4); |
| } else { |
| sprintf(response,"OKAYdone"); |
| } |
| goto send_tx_status; |
| } |
| |
| /* erase |
| Erase a register flash partition |
| Board has to set up flash partitions */ |
| if (memcmp(cmdbuf, "erase:", 6) == 0) |
| { |
| struct fastboot_ptentry *ptn; |
| |
| ptn = fastboot_flash_find_ptn(cmdbuf + 6); |
| if (ptn == 0) |
| { |
| sprintf(response, "FAILpartition does not exist"); |
| ret = 0; |
| goto send_tx_status; |
| } |
| |
| char start[32], length[32]; |
| int status; |
| |
| if (OmPin == BOOT_MMCSD) { |
| printf("erasing(formatting) '%s'\n", ptn->name); |
| } else if (OmPin == BOOT_EMMC_4_4 || OmPin == BOOT_EMMC) { |
| printf("erasing '%s'\n", ptn->name); |
| } else if (OmPin == BOOT_ONENAND) { |
| printf("erasing '%s'\n", ptn->name); |
| } |
| |
| #ifdef CONFIG_USE_LCD |
| LCD_setfgcolor(0x7FFFD4); |
| LCD_setprogress(100); |
| #endif |
| |
| if (OmPin == BOOT_MMCSD) { |
| // Temporary (but, simplest) implementation |
| char run_cmd[80]; |
| status = 1; |
| if (!strcmp(ptn->name, "system")) |
| { |
| sprintf(run_cmd, "ext4format mmc 0:2"); |
| status = run_command(run_cmd, 0); |
| } |
| else if (!strcmp(ptn->name, "userdata")) |
| { |
| sprintf(run_cmd, "ext4format mmc 0:3"); |
| status = run_command(run_cmd, 0); |
| } |
| else if (!strcmp(ptn->name, "cache")) |
| { |
| sprintf(run_cmd, "ext4format mmc 0:4"); |
| status = run_command(run_cmd, 0); |
| } |
| #ifdef CONFIG_FAT |
| else if (!strcmp(ptn->name, "fat")) |
| { |
| sprintf(run_cmd, "fatformat mmc 0:1"); |
| status = run_command(run_cmd, 0); |
| } |
| #endif |
| #ifdef CONFIG_KERNEL_RECOVERY_MODE |
| else if (!strcmp(ptn->name, "recovery")) |
| { |
| sprintf(run_cmd, "ext4format mmc 0:1"); |
| status = run_command(run_cmd, 0); |
| } |
| #endif |
| #ifdef CONFIG_BOOT |
| else if (!strcmp(ptn->name, "boot")) |
| { |
| sprintf(run_cmd, "ext4format mmc 0:6"); |
| status = run_command(run_cmd, 0); |
| } |
| #endif |
| } else if(OmPin == BOOT_EMMC_4_4 || OmPin == BOOT_EMMC) { |
| #if 0 |
| char run_cmd[80]; |
| status = 1; |
| if (!strcmp(ptn->name, "system")) { |
| sprintf(run_cmd, "ext4format mmc 0:2"); |
| status = run_command(run_cmd, 0); |
| } else if (!strcmp(ptn->name, "userdata")) { |
| sprintf(run_cmd, "ext4format mmc 0:3"); |
| status = run_command(run_cmd, 0); |
| } else if (!strcmp(ptn->name, "cache")) { |
| sprintf(run_cmd, "ext4format mmc 0:4"); |
| status = run_command(run_cmd, 0); |
| #ifdef CONFIG_FAT |
| } else if (!strcmp(ptn->name, "fat")) { |
| sprintf(run_cmd, "fatformat mmc 0:1"); |
| status = run_command(run_cmd, 0); |
| #endif |
| #ifdef CONFIG_KERNEL_RECOVERY_MODE |
| } else if (!strcmp(ptn->name, "recovery")) { |
| sprintf(run_cmd, "ext4format mmc 0:1"); |
| status = run_command(run_cmd, 0); |
| #endif |
| #ifdef CONFIG_BOOT |
| } else if (!strcmp(ptn->name, "boot")) { |
| sprintf(run_cmd, "ext4format mmc 0:6"); |
| status = run_command(run_cmd, 0); |
| #endif |
| } |
| #else |
| status = get_lock_state(); |
| #endif |
| } |
| //#else |
| else if(OmPin == BOOT_ONENAND) { |
| #if defined(CFG_FASTBOOT_ONENANDBSP) |
| int argc_erase = 4; |
| /* do_nand and do_onenand do not check argv[0] */ |
| char *argv_erase[5] = { NULL, "erase", NULL, NULL, NULL, }; |
| |
| argv_erase[2] = start; |
| argv_erase[3] = length; |
| |
| sprintf(start, "0x%x", ptn->start); |
| sprintf(length, "0x%x", ptn->length); |
| |
| if (ptn->length == 0) |
| argc_erase = 3; |
| |
| status = CFG_FASTBOOT_FLASHCMD(NULL, 0, argc_erase, argv_erase); |
| #endif |
| } |
| |
| if (status) |
| { |
| sprintf(response,"FAILfailed to erase partition"); |
| } |
| else |
| { |
| printf("partition '%s' erased\n", ptn->name); |
| sprintf(response, "OKAY"); |
| } |
| ret = 0; |
| goto send_tx_status; |
| } |
| |
| /* 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; |
| goto send_tx_status; |
| } |
| #if 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 |
| ** +-----------------+ |
| ** |
| |
| 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) |
| { |
| if ((download_bytes) && |
| (CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE < download_bytes)) |
| { |
| /* Note: We store zImage and ramdisk at different partitions */ |
| char addr_kernel[32]; |
| char addr_ramdisk[32]; |
| int pageoffset_ramdisk; |
| |
| char *bootz[3] = { "bootz", NULL, NULL, }; |
| //char *go[3] = { "go", NULL, 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]; |
| |
| printf("Kernel size: %08x\n", fb_hdr->kernel_size); |
| printf("Ramdisk size: %08x\n", fb_hdr->ramdisk_size); |
| |
| pageoffset_ramdisk = 1 + (fb_hdr->kernel_size + CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE - 1) / CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE; |
| |
| bootz[1] = addr_kernel; |
| sprintf(addr_kernel, "0x%x", CFG_FASTBOOT_ADDR_KERNEL); |
| memcpy((void *)CFG_FASTBOOT_ADDR_KERNEL, |
| interface.transfer_buffer + CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE, |
| fb_hdr->kernel_size); |
| bootz[2] = addr_ramdisk; |
| sprintf(addr_ramdisk, "0x%x", CFG_FASTBOOT_ADDR_RAMDISK); |
| memcpy((void *)CFG_FASTBOOT_ADDR_RAMDISK, interface.transfer_buffer + |
| (pageoffset_ramdisk * CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE), |
| fb_hdr->ramdisk_size); |
| |
| /* Execution should jump to kernel so send the response |
| now and wait a bit. */ |
| sprintf(response, "OKAY"); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| udelay (1000000); /* 1 sec */ |
| |
| #ifdef CONFIG_ROOTFS_ATAGS |
| char ramdisk_size[32]; |
| sprintf(ramdisk_size, "0x%x", fb_hdr->ramdisk_size); |
| setenv("rootfslen", ramdisk_size); |
| #endif |
| if (ntohl(hdr->ih_magic) == IH_MAGIC) { |
| /* Looks like a kernel.. */ |
| printf("Booting kernel..\n"); |
| |
| /* |
| * Check if the user sent a bootargs down. |
| * If not, do not override what is already there |
| */ |
| if (strlen ((char *) &fb_hdr->cmdline[0])) |
| set_env ("bootargs", (char *) &fb_hdr->cmdline[0]); |
| |
| do_bootz (NULL, 0, 2, bootz); |
| } else { |
| /* Raw image, maybe another uboot */ |
| printf("Booting raw image..\n"); |
| |
| //do_go (NULL, 0, 2, go); |
| do_bootz (NULL, 0, 3, bootz); |
| } |
| printf("ERROR : bootting failed\n"); |
| printf("You should reset the board\n"); |
| } |
| sprintf(response, "FAILinvalid boot image"); |
| ret = 0; |
| } |
| #endif |
| /* flash |
| Flash what was downloaded */ |
| if (memcmp(cmdbuf, "flash:", 6) == 0) |
| { |
| #ifdef CONFIG_LOCKING |
| if(!get_lock_state()) |
| { |
| #endif |
| if (download_bytes == 0) |
| { |
| sprintf(response, "FAILno image downloaded"); |
| ret = 0; |
| goto send_tx_status; |
| } |
| |
| struct fastboot_ptentry *ptn; |
| |
| #ifdef CONFIG_USE_LCD |
| LCD_setfgcolor(0x8B4500); |
| LCD_setprogress(100); |
| #endif |
| |
| if (!strcmp("bootloader", cmdbuf + 6)) |
| { |
| write_bootloader_img(interface.transfer_buffer); |
| } |
| else if (!strcmp("kernel", cmdbuf + 6)) { |
| if (write_raw_kernel(interface.transfer_buffer, download_bytes)==0) |
| sprintf(response, "OKAY"); |
| } |
| else if (!strcmp("ramdisk", cmdbuf + 6)) { |
| if (write_raw_ramdisk(interface.transfer_buffer, download_bytes)==0) |
| sprintf(response, "OKAY"); |
| } |
| else |
| { |
| ptn = fastboot_flash_find_ptn(cmdbuf + 6); |
| if (ptn == NULL) |
| { |
| sprintf(response, "FAILpartition does not exist"); |
| } |
| else if ((download_bytes > ptn->length) && (ptn->length != 0) && |
| !(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 (OmPin == BOOT_ONENAND) { |
| #if defined(CFG_FASTBOOT_ONENANDBSP) |
| if (write_to_ptn(ptn, (unsigned int)interface.transfer_buffer, download_bytes)) |
| { |
| printf("flashing '%s' failed\n", ptn->name); |
| sprintf(response, "FAILfailed to flash partition"); |
| } |
| else |
| { |
| printf("partition '%s' flashed\n", ptn->name); |
| sprintf(response, "OKAY"); |
| } |
| #endif |
| } else if (OmPin == BOOT_MMCSD) { |
| if (write_to_ptn_sdmmc(ptn, (unsigned int)interface.transfer_buffer, download_bytes)) |
| { |
| 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 if (OmPin == BOOT_EMMC_4_4 || OmPin == BOOT_EMMC) { |
| if (write_to_ptn_sdmmc(ptn, (unsigned int)interface.transfer_buffer, download_bytes)) { |
| printf("flashing '%s' failed\n", ptn->name); |
| sprintf(response, "FAILfailed to flash partition"); |
| } else { |
| printf("partition '%s' flashed\n", ptn->name); |
| sprintf(response, "OKAY"); |
| } |
| |
| } |
| |
| } |
| } |
| } |
| #ifdef CONFIG_LOCKING |
| } |
| else |
| sprintf(response, "FAILcannot flash images,locked"); |
| #endif |
| ret = 0; |
| goto send_tx_status; |
| } |
| |
| if (memcmp(cmdbuf, "continue", 8) == 0) |
| { |
| fastboot_continue_autoboot = 1; |
| sprintf(response, "OKAY"); |
| goto send_tx_status; |
| } |
| /* verify */ |
| /* continue */ |
| /* powerdown */ |
| |
| /* oem |
| oem command. */ |
| #ifdef CONFIG_LOCKING |
| if (memcmp(cmdbuf, "flashing ", 9) == 0) { |
| |
| static int unlock_accept = 0; |
| |
| if (memcmp(cmdbuf + 9, "unlock", 6) == 0) |
| { |
| if (unlock_accept) { |
| sprintf(response, "INFOErasing userdata and unlocking the device"); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| |
| // run_command("ext4format mmc 0:3;ext4format mmc 0:4;", 0); |
| write_to_ptn_sdmmc(fastboot_flash_find_ptn("userdata"), 0, 0); |
| write_to_ptn_sdmmc(fastboot_flash_find_ptn("cache"), 0, 0); |
| |
| put_lock_state(0); |
| sprintf(response, "INFORun \"fastboot -w\" to make valid filesystem."); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| |
| unlock_accept = 0; |
| sprintf(response, "OKAY"); |
| } else { |
| if (!get_lock_state()) { |
| sprintf(response, "FAILDevice is already unlocked"); |
| } else { |
| sprintf(response, "INFOUnlock requested."); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| sprintf(response, "INFODevice may encounter problem with unofficial images."); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| sprintf(response, "INFOTo confirm, run \"fastboot flashing unlock\" again."); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| |
| unlock_accept = 1; |
| sprintf(response, "OKAY"); |
| } |
| } |
| } |
| else if (strcmp(cmdbuf + 9, "lock") == 0) { |
| if (get_lock_state()) |
| sprintf(response, "FAILDevice is already locked"); |
| else { |
| put_lock_state(1); |
| |
| sprintf(response, "INFODevice has been locked"); |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_SYNC); |
| sprintf(response, "OKAY"); |
| } |
| } |
| ret = 0; |
| goto send_tx_status; |
| } |
| #endif |
| |
| #if defined(CONFIG_RAMDUMP_MODE) |
| if (memcmp(cmdbuf, "ramdump:", 8) == 0) |
| { |
| printf("\nGot ramdump command\n"); |
| is_ramdump = 1; |
| /* save the size */ |
| download_size = simple_strtoul(cmdbuf + 8, 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; |
| goto send_tx_status; |
| } |
| #endif |
| send_tx_status: |
| fastboot_tx_status(response, strlen(response), FASTBOOT_TX_ASYNC); |
| |
| #ifdef CONFIG_USE_LCD |
| LCD_setprogress(0); |
| #endif |
| } /* End of command */ |
| |
| return ret; |
| } |
| |
| |
| static int check_against_static_partition(struct fastboot_ptentry *ptn) |
| { |
| int ret = 0; |
| struct fastboot_ptentry *c; |
| int i; |
| |
| for (i = 0; i < static_pcount; i++) { |
| c = fastboot_flash_get_ptn((unsigned int) i); |
| |
| if (0 == ptn->length) |
| break; |
| |
| if ((ptn->start >= c->start) && |
| (ptn->start < c->start + c->length)) |
| break; |
| |
| if ((ptn->start + ptn->length > c->start) && |
| (ptn->start + ptn->length <= c->start + c->length)) |
| break; |
| |
| if ((0 == strcmp(ptn->name, c->name)) && |
| (0 == strcmp(c->name, ptn->name))) |
| break; |
| } |
| |
| if (i >= static_pcount) |
| ret = 1; |
| return ret; |
| } |
| |
| |
| 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 add_partition_from_environment(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; |
| } |
| |
| /* test for options */ |
| while (1) { |
| if (strncmp(s, "i", 1) == 0) { |
| flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_I; |
| s += 1; |
| } else if (strncmp(s, "yaffs", 5) == 0) { |
| /* yaffs */ |
| flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS; |
| s += 5; |
| } else if (strncmp(s, "swecc", 5) == 0) { |
| /* swecc */ |
| flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC; |
| s += 5; |
| } else if (strncmp(s, "hwecc", 5) == 0) { |
| /* hwecc */ |
| flags |= FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC; |
| 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; |
| } |
| |
| |
| /* Check if this overlaps a static partition */ |
| if (check_against_static_partition(&part)) { |
| printf("Adding: %s, offset 0x%8.8x, size 0x%8.8x, flags 0x%8.8x\n", |
| part.name, part.start, part.length, part.flags); |
| fastboot_flash_add_ptn(&part); |
| } |
| |
| /* return (updated) pointer command line string */ |
| *retptr = s; |
| |
| /* return partition table */ |
| return 0; |
| } |
| |
| #if defined(CONFIG_FASTBOOT) |
| static int set_partition_table() |
| { |
| char fbparts[4096], *env; |
| |
| /* |
| * Place the runtime partitions at the end of the |
| * static paritions. First save the start off so |
| * it can be saved from run to run. |
| */ |
| if (static_pcount >= 0) |
| { |
| /* Reset */ |
| pcount = static_pcount; |
| } |
| else |
| { |
| /* Save */ |
| static_pcount = pcount; |
| } |
| env = getenv("fbparts"); |
| if (env) |
| { |
| unsigned int len; |
| len = strlen(env); |
| if (len && len < 4096) |
| { |
| 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 (add_partition_from_environment(s, &s)) |
| { |
| printf("Error:Fastboot: Abort adding partitions\n"); |
| /* reset back to static */ |
| pcount = static_pcount; |
| break; |
| } |
| /* Skip a bunch of delimiters */ |
| while (s < e) |
| { |
| if ((' ' == *s) || |
| ('\t' == *s) || |
| ('\n' == *s) || |
| ('\r' == *s) || |
| (',' == *s)) { |
| s++; |
| } |
| else |
| { |
| break; |
| } |
| } |
| } |
| } |
| } |
| else if (ptable_default_size >= sizeof(fastboot_ptentry)) |
| { |
| printf("Fastboot: employ default partition information\n"); |
| //memcpy(ptable, ptable_default, ptable_default_size); |
| memcpy((void*)ptable, (void*)&ptable_default, ptable_default_size); |
| pcount = ptable_default_size / sizeof(fastboot_ptentry); |
| } |
| else |
| { |
| printf("No partition informations!"); |
| return 0; |
| } |
| |
| #if 1 // Debug |
| fastboot_flash_dump_ptn(); |
| #endif |
| #ifdef CONFIG_USE_LCD |
| LCD_setleftcolor(0x1024C0); |
| #endif |
| return 0; |
| } |
| #endif |
| |
| #if defined(CFG_FASTBOOT_SDMMCBSP) |
| static int set_partition_table_sdmmc() |
| { |
| unsigned long start, count; |
| unsigned char pid; |
| int dev_num = DEV_NUM; |
| |
| pcount = 0; |
| |
| /* FW BL1 for fused chip */ |
| strcpy(ptable[pcount].name, "fwbl1"); |
| ptable[pcount].start = 0; |
| ptable[pcount].length = 0; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; |
| pcount++; |
| |
| /* BL2 */ |
| strcpy(ptable[pcount].name, "bl2"); |
| ptable[pcount].start = 0; |
| ptable[pcount].length = 0; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; |
| pcount++; |
| |
| /* u-boot */ |
| strcpy(ptable[pcount].name, "u-boot"); |
| ptable[pcount].start = 0; |
| ptable[pcount].length = 0; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; |
| pcount++; |
| |
| /* TrustZone S/W */ |
| strcpy(ptable[pcount].name, "tzsw"); |
| ptable[pcount].start = 0; |
| ptable[pcount].length = 0; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; |
| pcount++; |
| |
| /* Kernel */ |
| strcpy(ptable[pcount].name, "kernel"); |
| ptable[pcount].start = 0; |
| ptable[pcount].length = 0; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; |
| pcount++; |
| |
| /* Ramdisk */ |
| strcpy(ptable[pcount].name, "ramdisk"); |
| ptable[pcount].start = 0; |
| ptable[pcount].length = PART_SIZE_ROOTFS; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; |
| pcount++; |
| |
| #ifdef CONFIG_CHARGER_LOGO |
| strcpy(ptable[pcount].name, "charger"); |
| ptable[pcount].start = 0; |
| ptable[pcount].length = PART_SIZE_CHARGER_LOGO; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; |
| pcount++; |
| #endif |
| #ifdef CONFIG_BOOT_LOGO |
| strcpy(ptable[pcount].name, "bootlogo"); |
| ptable[pcount].start = 0; |
| ptable[pcount].length = PART_SIZE_BOOT_LOGO; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; |
| pcount++; |
| #endif |
| /* recovery */ |
| get_boot_part_info(dev_num, 1, &start, &count, &pid); |
| if (pid != 0x83 && pid != 0xee) |
| goto part_type_error; |
| strcpy(ptable[pcount].name, "recovery"); |
| ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; |
| pcount++; |
| |
| /* System */ |
| get_boot_part_info(dev_num, 2, &start, &count, &pid); |
| if (pid != 0x83 && pid != 0xee) |
| goto part_type_error; |
| strcpy(ptable[pcount].name, "system"); |
| ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; |
| pcount++; |
| |
| /* Data */ |
| get_boot_part_info(dev_num, 3, &start, &count, &pid); |
| if (pid != 0x83 && pid != 0xee) |
| goto part_type_error; |
| strcpy(ptable[pcount].name, "userdata"); |
| ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; |
| pcount++; |
| |
| /* Cache */ |
| get_boot_part_info(dev_num, 4, &start, &count, &pid); |
| if (pid != 0x83 && pid != 0xee) |
| goto part_type_error; |
| strcpy(ptable[pcount].name, "cache"); |
| ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; |
| pcount++; |
| |
| /* Misc */ |
| get_boot_part_info(dev_num, 5, &start, &count, &pid); |
| if (pid != 0x83 && pid != 0xee) |
| goto part_type_error; |
| strcpy(ptable[pcount].name, "misc"); |
| ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; |
| pcount++; |
| |
| /* boot */ |
| get_boot_part_info(dev_num, 6, &start, &count, &pid); |
| if (pid != 0x83 && pid != 0xee) |
| goto part_type_error; |
| strcpy(ptable[pcount].name, "boot"); |
| ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; |
| pcount++; |
| |
| /* info */ |
| get_boot_part_info(dev_num, 7, &start, &count, &pid); |
| if (pid != 0x83 && pid != 0xee) |
| goto part_type_error; |
| strcpy(ptable[pcount].name, "info"); |
| ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; |
| pcount++; |
| |
| /* bootloader */ |
| get_boot_part_info(dev_num, 8, &start, &count, &pid); |
| if (pid != 0x83 && pid != 0xee) |
| goto part_type_error; |
| strcpy(ptable[pcount].name, "bootloader"); |
| ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; |
| pcount++; |
| |
| #ifdef CONFIG_FAT |
| /* fat */ |
| get_boot_part_info(dev_num, 1, &start, &count, &pid); |
| if (pid != 0xc && pid != 0xee) |
| goto part_type_error; |
| strcpy(ptable[pcount].name, "fat"); |
| ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; |
| ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; |
| pcount++; |
| #endif |
| |
| #if 1 // Debug |
| fastboot_flash_dump_ptn(); |
| #endif |
| #ifdef CONFIG_USE_LCD |
| LCD_setleftcolor(0x8a2be2); |
| #endif |
| return 0; |
| |
| part_type_error: |
| printf("Error: No MBR or GPT is found at SD/MMC.\n"); |
| printf("Hint: use fdisk or gpt command to make partitions.\n"); |
| |
| return -1; |
| } |
| #endif |
| int write_bootloader_img(unsigned char *buffer) |
| { |
| char out[256] __attribute__ ((aligned(8))); |
| |
| int i, ret=0; |
| struct fastboot_ptentry *ptn; |
| struct fastboot_bootldr_img_hdr tmp; |
| struct fastboot_bootldr_img_hdr *bldr_hdr = (struct fastboot_bootldr_img_hdr *) buffer; |
| |
| #if defined(CFG_FASTBOOT_SDMMCBSP) |
| set_partition_table_sdmmc(); |
| #else |
| set_partition_table(); |
| #endif |
| |
| if (memcmp(bldr_hdr->magic, FASTBOOT_BOOTLOADER_MAGIC, 8)) { |
| printf("Magic is not met\n"); |
| sprintf(out, "FAILfailed to flash partition"); |
| goto finish; |
| } |
| /* |
| Name of u-boot partition appended by old mkblimg utility is "bootloader". |
| Rename it to "u-boot" for compatibility. |
| */ |
| if (strcmp("bootloader", bldr_hdr->img_info[0].name) == 0) |
| strcpy(bldr_hdr->img_info[0].name, "u-boot"); |
| |
| for(i = 0; i< bldr_hdr->image_num; i++) |
| { |
| ptn = fastboot_flash_find_ptn(bldr_hdr->img_info[i].name); |
| |
| if (OmPin == BOOT_ONENAND) { |
| #if defined(CFG_FASTBOOT_ONENANDBSP) |
| ret |= write_to_ptn(ptn, (unsigned int)buffer + bldr_hdr->img_info[i].start, bldr_hdr->img_info[i].size); |
| #endif |
| } else if (OmPin == BOOT_MMCSD) { |
| ret |= write_to_ptn_sdmmc(ptn, (unsigned int)buffer + bldr_hdr->img_info[i].start, bldr_hdr->img_info[i].size); |
| } else if (OmPin == BOOT_EMMC_4_4 || OmPin == BOOT_EMMC) { |
| ret |= write_to_ptn_sdmmc(ptn, (unsigned int)buffer + bldr_hdr->img_info[i].start, bldr_hdr->img_info[i].size); |
| } |
| |
| if(!ret) |
| { |
| printf("partition '%s' flashed\n", ptn->name); |
| } |
| else |
| { |
| printf("flashing '%s' failed\n", ptn->name); |
| sprintf(out, "FAILfailed to flash partition"); |
| goto finish; |
| } |
| } |
| sprintf(out, "OKAY"); |
| finish: |
| fastboot_tx_status(out, strlen(out), FASTBOOT_TX_SYNC); |
| |
| return ret; |
| |
| } |
| |
| |
| int do_fastboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) |
| { |
| int ret = 1; |
| int check_timeout = 0; |
| uint64_t timeout_endtime = 0; |
| uint64_t timeout_ticks = 0; |
| long timeout_seconds = -1; |
| int continue_from_disconnect = 0; |
| struct fastboot_ptentry *ptn; |
| unsigned int addr, size; |
| /* checking boot mode before to set partition table */ |
| switch(OmPin) { |
| case BOOT_ONENAND: |
| if (set_partition_table()) { |
| return 1; |
| } |
| break; |
| case BOOT_MMCSD: |
| case BOOT_EMMC_4_4: |
| case BOOT_EMMC: |
| if (set_partition_table_sdmmc()) { |
| return 1; |
| } |
| break; |
| case BOOT_NAND: |
| if (set_partition_table()) { |
| return 1; |
| } |
| break; |
| } |
| |
| #if 0 |
| if (set_partition_table()) |
| return 1; |
| #endif |
| |
| if ((argc > 1) && (0 == strcmp(argv[1], "flash"))){ |
| ptn = fastboot_flash_find_ptn(argv[2]); |
| if(ptn == NULL) { |
| printf("undefined image name !\n"); |
| return -1; |
| } |
| size = 0; |
| if(ptn->name[0] == 'r') |
| size = PART_SIZE_ROOTFS; |
| addr = simple_strtoul(argv[3], NULL, 16); |
| write_to_ptn_sdmmc(ptn, addr, size); |
| return 1; |
| } |
| |
| /* Time out */ |
| if (2 == argc) |
| { |
| long try_seconds; |
| char *try_seconds_end; |
| /* Check for timeout */ |
| try_seconds = simple_strtol(argv[1], &try_seconds_end, 10); |
| if ((try_seconds_end != argv[1]) && (try_seconds >= 0)) |
| { |
| check_timeout = 1; |
| timeout_seconds = try_seconds; |
| printf("Fastboot inactivity timeout %ld seconds\n", timeout_seconds); |
| } |
| } |
| |
| if (1 == check_timeout) |
| { |
| timeout_ticks = (uint64_t) (timeout_seconds * get_tbclk()); |
| } |
| |
| |
| 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; |
| |
| timeout_endtime = get_ticks(); |
| timeout_endtime += timeout_ticks; |
| |
| while (1) |
| { |
| uint64_t current_time = 0; |
| poll_status = fastboot_poll(); |
| |
| if (1 == check_timeout) |
| current_time = get_ticks(); |
| |
| /* Check if the user wanted to terminate with ^C */ |
| if ((poll_status != FASTBOOT_OK) && (ctrlc() || exit_key())) |
| { |
| printf("Fastboot ended by user\n"); |
| continue_from_disconnect = 0; |
| break; |
| } |
| |
| if (fastboot_continue_autoboot) |
| { |
| printf("Continuing with autoboot\n"); |
| continue_from_disconnect = 0; |
| fastboot_continue_autoboot = 0; |
| break; |
| } |
| |
| if (FASTBOOT_ERROR == poll_status) |
| { |
| /* Error */ |
| printf("Fastboot error \n"); |
| break; |
| } |
| else if (FASTBOOT_DISCONNECT == poll_status) |
| { |
| /* break, 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 */ |
| /* Actual works of parsing are done by rx_handler */ |
| if (1 == check_timeout) |
| { |
| /* Update the timeout endtime */ |
| timeout_endtime = current_time; |
| timeout_endtime += timeout_ticks; |
| } |
| } |
| } /* while (1) */ |
| } |
| |
| /* Reset the board specific support */ |
| fastboot_shutdown(); |
| |
| #ifdef CONFIG_USE_LCD |
| LCD_setfgcolor(0x000010); |
| LCD_setleftcolor(0x000010); |
| LCD_setprogress(100); |
| #endif |
| |
| /* restart the loop if a disconnect was detected */ |
| } while (continue_from_disconnect); |
| |
| return ret; |
| } |
| |
| U_BOOT_CMD( |
| fastboot, 4, 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" |
| ); |
| |
| |
| #undef CONFIG_FASTBOOT_SDFUSE // sdfuse is not implemented yet. |
| #ifdef CONFIG_FASTBOOT_SDFUSE |
| |
| #include <part.h> |
| #include <fat.h> |
| #define CFG_FASTBOOT_SDFUSE_DIR "/sdfuse" |
| #ifdef CFG_FASTBOOT_SDMMCBSP |
| #define CFG_FASTBOOT_SDFUSE_MMCDEV 0 |
| #else |
| #define CFG_FASTBOOT_SDFUSE_MMCDEV 0 |
| #endif |
| #define CFG_FASTBOOT_SDFUSE_MMCPART 1 |
| /* |
| * part : partition name (This should be a defined name at ptable) |
| * file : file to read |
| */ |
| static int update_from_sd (char *part, char *file) |
| { |
| int ret = 1; |
| |
| /* Read file */ |
| if (file != NULL) |
| { |
| long size; |
| unsigned long offset; |
| unsigned long count; |
| char filename[32]; |
| block_dev_desc_t *dev_desc=NULL; |
| |
| printf("Partition: %s, File: %s/%s\n", part, CFG_FASTBOOT_SDFUSE_DIR, file); |
| #ifdef CONFIG_USE_LCD |
| LCD_setfgcolor(0x2E8B57); |
| LCD_setprogress(100); |
| #endif |
| dev_desc = get_dev("mmc", CFG_FASTBOOT_SDFUSE_MMCDEV); |
| if (dev_desc == NULL) { |
| printf("** Invalid boot device **\n"); |
| return 1; |
| } |
| if (fat_register_device(dev_desc, CFG_FASTBOOT_SDFUSE_MMCPART) != 0) { |
| printf("** Invalid partition **\n"); |
| return 1; |
| } |
| sprintf(filename, "%s/%s", CFG_FASTBOOT_SDFUSE_DIR, file); |
| offset = CFG_FASTBOOT_TRANSFER_BUFFER; |
| count = 0; |
| size = file_fat_read (filename, (unsigned char *) offset, count); |
| |
| if (size == -1) { |
| printf("Failed to read %s\n", filename); |
| return 1; |
| } |
| |
| download_size = 0; // should be 0 |
| download_bytes = size; |
| |
| printf("%ld (0x%08x) bytes read\n", size, size); |
| } |
| else { |
| printf("Partition: %s\n", part); |
| |
| download_size = 0; // should be 0 |
| download_bytes = 0; |
| } |
| |
| /* Write image into partition */ |
| /* If file is empty or NULL, just erase the part. */ |
| { |
| char command[32]; |
| |
| if (download_bytes == 0) |
| sprintf(command, "%s:%s", "erase", part); |
| else |
| sprintf(command, "%s:%s", "flash", part); |
| |
| ret = rx_handler(command, sizeof(command)); |
| } |
| |
| return ret; |
| } |
| |
| /* SD Fusing : read images from FAT partition of SD Card, and write it to boot device. |
| * |
| * NOTE |
| * - sdfuse is not a original code of fastboot |
| * - Fusing image from SD Card is not a original part of Fastboot protocol. |
| * - This command implemented at this file to re-use an existing code of fastboot */ |
| int do_sdfuse (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) |
| { |
| int ret = 1; |
| int enable_reset = 0; |
| struct mmc *mmc = find_mmc_device(CFG_FASTBOOT_SDFUSE_MMCDEV); |
| |
| interface.nand_block_size = CFG_FASTBOOT_PAGESIZE * 64; |
| interface.transfer_buffer = (unsigned char *) CFG_FASTBOOT_TRANSFER_BUFFER; |
| interface.transfer_buffer_size = CFG_FASTBOOT_TRANSFER_BUFFER_SIZE; |
| |
| printf("[Fusing Image from SD Card.]\n"); |
| |
| if (set_partition_table()) |
| return 1; |
| |
| if ((argc == 2) && !strcmp(argv[1], "info")) |
| { |
| printf("sdfuse will read images from the followings:\n"); |
| printf(" sd/mmc device : mmc %d:%d\n", |
| CFG_FASTBOOT_SDFUSE_MMCDEV, CFG_FASTBOOT_SDFUSE_MMCPART); |
| printf(" directory : %s\n", CFG_FASTBOOT_SDFUSE_DIR); |
| printf(" booting device : %s\n", |
| #if defined(CFG_FASTBOOT_ONENANDBSP) |
| "OneNAND" |
| #elif defined(CFG_FASTBOOT_NANDBSP) |
| "NAND" |
| #elif defined(CFG_FASTBOOT_SDMMCBSP) |
| "MoviNAND" |
| #else |
| #error "Unknown booting device!" |
| #endif |
| #if defined(CONFIG_FUSED) |
| " (on eFused Chip)" |
| #endif |
| ); |
| return 0; |
| } |
| else if ((argc == 2) && !strcmp(argv[1], "flashall")) |
| { |
| #ifdef CONFIG_USE_LCD |
| LCD_turnon(); |
| #endif |
| |
| if (update_from_sd("boot", "boot.img")) |
| goto err_sdfuse; |
| if (update_from_sd("system", "system.img")) |
| goto err_sdfuse; |
| if (update_from_sd("userdata", NULL)) |
| goto err_sdfuse; |
| if (update_from_sd("cache", NULL)) |
| goto err_sdfuse; |
| |
| enable_reset = 1; |
| ret = 0; |
| } |
| else if ((argc == 4) && !strcmp(argv[1], "flash")) |
| { |
| #ifdef CONFIG_USE_LCD |
| LCD_turnon(); |
| #endif |
| |
| if (update_from_sd(argv[2], argv[3])) |
| goto err_sdfuse; |
| |
| ret = 0; |
| } |
| else if ((argc == 3) && !strcmp(argv[1], "erase")) |
| { |
| #ifdef CONFIG_USE_LCD |
| LCD_turnon(); |
| #endif |
| |
| if (update_from_sd(argv[2], NULL)) |
| goto err_sdfuse; |
| |
| ret = 0; |
| } |
| else |
| { |
| printf("Usage:\n%s\n", cmdtp->usage); |
| return 1; |
| } |
| |
| err_sdfuse: |
| #ifdef CONFIG_USE_LCD |
| LCD_setfgcolor(0x000010); |
| LCD_setleftcolor(0x000010); |
| LCD_setprogress(100); |
| #endif |
| |
| if (enable_reset) |
| do_reset (NULL, 0, 0, NULL); |
| |
| return ret; |
| } |
| |
| U_BOOT_CMD( |
| sdfuse, 4, 1, do_sdfuse, |
| "sdfuse - read images from FAT partition of SD card and write them to booting device.\n", |
| "info - print primitive infomation.\n" |
| "sdfuse flashall - flash boot.img, system.img,\n" |
| " erase userdata, cache, and reboot.\n" |
| "sdfuse flash <partition> [ <filename> ] - write a file to a partition.\n" |
| "sdfuse erase <partition> - erase (format) a partition.\n" |
| ); |
| #endif // CONFIG_FASTBOOT_SDFUSE |
| |
| |
| /* |
| * Android style flash utilties */ |
| void fastboot_flash_add_ptn(fastboot_ptentry *ptn) |
| { |
| if (pcount < MAX_PTN) |
| { |
| memcpy(ptable + pcount, ptn, sizeof(*ptn)); |
| pcount++; |
| } |
| } |
| |
| void fastboot_flash_dump_ptn(void) |
| { |
| unsigned int n; |
| |
| printf("[Partition table on "); |
| |
| switch(OmPin) { |
| case BOOT_ONENAND: |
| printf("OneNAND"); |
| break; |
| case BOOT_MMCSD: |
| case BOOT_EMMC_4_4: |
| case BOOT_EMMC: |
| printf("MoviNAND"); |
| break; |
| case BOOT_NAND: |
| printf("NAND"); |
| break; |
| } |
| printf("]\n"); |
| |
| for (n = 0; n < pcount; n++) |
| { |
| fastboot_ptentry *ptn = ptable + n; |
| #if 0 /* old format - decimal */ |
| printf("ptn %d name='%s' start=%d len=%d\n", |
| n, ptn->name, ptn->start, ptn->length); |
| #else |
| printf("ptn %d name='%s' ", n, ptn->name); |
| if (n == 0 || ptn->start) |
| printf("start=0x%lX ", ptn->start); |
| else |
| printf("start=N/A "); |
| if (ptn->length) |
| printf("len=0x%lX (%ld KB) ", ptn->length, ptn->length>>10); |
| else |
| printf("len=N/A "); |
| |
| if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS) |
| printf("(Yaffs)\n"); |
| else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD) |
| printf("(use hard-coded info. (cmd: movi))\n"); |
| else |
| printf("\n"); |
| #endif |
| } |
| } |
| |
| |
| 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; |
| } |
| } |
| return NULL; |
| } |
| |
| fastboot_ptentry *fastboot_flash_get_ptn(unsigned int n) |
| { |
| if (n < pcount) { |
| return ptable + n; |
| } else { |
| return NULL; |
| } |
| } |
| |
| unsigned int fastboot_flash_get_ptn_count(void) |
| { |
| return pcount; |
| } |
| |
| #ifdef CONFIG_AUTO_FW_WRITE |
| |
| void AutoFirmwareUpdate(void) |
| { |
| long file_size; |
| struct fastboot_ptentry *ptn; |
| |
| run_command("movi r f 1 40000000;emmc open 0;movi w z f 0 40000000;emmc close 0;",0); |
| run_command("movi r t 1 40000000;emmc open 0;movi w z t 0 40000000;emmc close 0;",0); |
| |
| run_command("fatload mmc 1:2 0x40000000 bootloader.img",0); |
| write_bootloader_img((unsigned char *)0x40000000); |
| |
| run_command("fatload mmc 1:2 0x40000000 boot.img",0); |
| file_size = getenv_ulong("filesize", 16, 0); |
| if (file_size) { |
| printf("boot size = %ld\n", file_size); |
| ptn = fastboot_flash_find_ptn("boot"); |
| write_to_ptn_sdmmc(ptn, 0x40000000, file_size); |
| } |
| |
| run_command("fatload mmc 1:2 0x40000000 recovery.img",0); |
| file_size = getenv_ulong("filesize", 16, 0); |
| if (file_size) { |
| printf("recovery size = %ld\n", file_size); |
| ptn = fastboot_flash_find_ptn("recovery"); |
| write_to_ptn_sdmmc(ptn, 0x40000000, file_size); |
| } |
| |
| run_command("fatload mmc 1:2 0x40000000 system.img",0); |
| file_size = getenv_ulong("filesize", 16, 0); |
| if (file_size) { |
| printf("system size = %ld\n", file_size); |
| ptn = fastboot_flash_find_ptn("system"); |
| write_to_ptn_sdmmc(ptn, 0x40000000, file_size); |
| } |
| |
| run_command("fatload mmc 1:2 0x40000000 userdata.img",0); |
| file_size = getenv_ulong("filesize", 16, 0); |
| if (file_size) { |
| printf("userdata size = %ld\n", file_size); |
| ptn = fastboot_flash_find_ptn("userdata"); |
| write_to_ptn_sdmmc(ptn, 0x40000000, file_size); |
| } |
| |
| run_command("fatload mmc 1:2 0x40000000 cache.img",0); |
| file_size = getenv_ulong("filesize", 16, 0); |
| if (file_size) { |
| printf("cache size = %ld\n", file_size); |
| ptn = fastboot_flash_find_ptn("cache"); |
| write_to_ptn_sdmmc(ptn, 0x40000000, file_size); |
| } |
| } |
| #endif |
| |
| #endif /* CONFIG_FASTBOOT */ |
| |
| |