From: Jaehoon Chung Date: Tue, 16 Aug 2016 07:17:06 +0000 (+0900) Subject: cmd: usbdown: support the usbdown from usb storage to mmc X-Git-Tag: submit/tizen/20170414.042831~17 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=79aa3069c8ca6ac2e3ed9dc577efbcfcdf8ee33d;p=platform%2Fkernel%2Fu-boot.git cmd: usbdown: support the usbdown from usb storage to mmc This command is to support the download mode from usb storage to mmc block device. XU4 didn't support the thor download, so this solution might be replaced to thor download. * How to use this command 1. Assume that Block number of eMMC block device is "0" 2. If you want to flash the rootfs.img, $update 0:0 mmc rootfs.img - 0:0 -> usb block 0 devices and partitioin 0 if you just enter "0" instead of "0:0", that check the partition 1 by default. - mmc -> interface to flash the image - rootfs.img -> filename to flash (directory is "/" by default.) If you want to use the directory, can use likes "/tizen/rootfs.img". (There is rootfs.img under "tizen" directory.) 3. Use "update all" command $usbdown all - directory is "/updateTizen/ by default. *Recommendation - Use "usbdown all" Change-Id: I267c9b871741e9e1f6aef29965f1f846e19864f1 Signed-off-by: Jaehoon Chung --- diff --git a/cmd/Kconfig b/cmd/Kconfig index ef53156314..c3bfea0b3f 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -467,6 +467,11 @@ config CMD_USB bool "usb" help USB support. + +config CMD_USBDOWN + bool "usbdown" + help + USB stroage download support for tizen config CMD_DFU bool "dfu" diff --git a/cmd/Makefile b/cmd/Makefile index 685952e74f..e3a28014dc 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -141,6 +141,7 @@ obj-$(CONFIG_CMD_LZMADEC) += lzmadec.o endif obj-$(CONFIG_CMD_USB) += usb.o disk.o +obj-$(CONFIG_CMD_USBDOWN) += usbdown.o obj-$(CONFIG_CMD_FASTBOOT) += fastboot.o obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o diff --git a/cmd/usbdown.c b/cmd/usbdown.c new file mode 100644 index 0000000000..4046254050 --- /dev/null +++ b/cmd/usbdown.c @@ -0,0 +1,533 @@ +/* + * usbdown.c -- Download the image from USB storage + * + * Copyright (C) 2016 Jaehoon Chung + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_BLK_COUNT 0x2000000 /* 65536 * 512 */ + +#ifdef CONFIG_USB_STORAGE +static int usb_stor_curr_dev = -1; /* current device */ +#endif + +static LIST_HEAD(usbdown_list); + +static int alt_num_count; +static int is_config; +extern char usb_started; + +#define NAME_SIZE 32 +enum usbdown_layout { + RAW_ADDR = 1, + FS_FAT, + FS_EXT2, + FS_EXT3, + FS_EXT4, + RAM_ADDR, +}; + +struct usbdown_entity { + int dev_num; + char name[NAME_SIZE]; + int layout; + + /* RAW programming */ + unsigned int lba_start; + unsigned int lba_size; + unsigned int lba_blk_size; + + int alt_num; + + /* eMMC HW partition access */ + int hw_partition; + + /* FAT/EXT */ + unsigned int dev; + unsigned int part; + + struct list_head list; +}; + +static int find_alt_num(const char *s) +{ + int i = 0; + + for (; *s; s++) + if (*s == ';') + i++; + + return ++i; +} + +struct usbdown_entity *usbdown_get_entity(int alt) +{ + struct usbdown_entity *usb; + + list_for_each_entry(usb, &usbdown_list, list) { + if (usb->alt_num == alt) + return usb; + } + + return NULL; +} + +int usbdown_get_alt(const char *name) +{ + struct usbdown_entity *usb; + const char *argv[3]; + const char **parg = argv; + char *name_bkp; + const char *find_name; + char *str; + + if (name[0] == '/') { + name_bkp = strdup(name); + for (; parg < argv + sizeof(argv) / sizeof(*argv); ++parg) { + *parg = strsep(&name_bkp, "/"); + if (*parg == NULL) { + error("Invalid number of arguments.\n"); + return -ENODEV; + } + } + + find_name = argv[2]; + } else { + find_name = name; + } + + list_for_each_entry(usb, &usbdown_list, list) { + if (usb->name[0] != '/') { + if (!strncmp(usb->name, find_name, strlen(usb->name))) + return usb->alt_num; + } else { + str = strstr(usb->name, find_name); + if (!str) + continue; + if (strlen(usb->name) == + ((str - usb->name) + strlen(find_name))) + return usb->alt_num; + } + } + + return -ENODEV; +} + +static int usb_fill_entity(struct usbdown_entity *usb, char *s, int alt_num, + char *interface, char *devstr) +{ + const char *entity_type; + const char *argv[3]; + const char **parg = argv; + size_t second_arg; + size_t third_arg; + struct mmc *mmc; + + mmc = find_mmc_device(0); + if (mmc == NULL) { + error("Couldn't find MMC device no. 0.\n"); + return -ENODEV; + } + + if (mmc_init(mmc)) { + error("Couldn't init MMC device.\n"); + return -ENODEV; + } + + for (; parg < argv + sizeof(argv) / sizeof(*argv); ++parg) { + *parg = strsep(&s, " "); + if (*parg == NULL) { + error("Invalid number of arguments.\n"); + return -ENODEV; + } + } + + entity_type = argv[0]; + second_arg = simple_strtoul(argv[1], NULL, 0); + third_arg = simple_strtoul(argv[2], NULL, 0); + usb->alt_num = alt_num; + + if (!strncmp(entity_type, "raw", 3)) { + usb->layout = RAW_ADDR; + usb->lba_start = second_arg; + usb->lba_size = third_arg; + usb->lba_blk_size = 512; /* Set to 512 bytes */ + + if (s && !strcmp(strsep(&s, " "), "mmcpart")) + usb->hw_partition = simple_strtoul(s, NULL, 0); + + } else if (!strncmp(entity_type, "part", 4)) { + disk_partition_t partinfo; + struct blk_desc *blk_dev = &mmc->block_dev; + int mmcdev = second_arg; + int mmcpart = third_arg; + int offset = 0; + + if (part_get_info(blk_dev, mmcpart, &partinfo) != 0) { + error("Couldn't find part #%d on mmc device #%d\n", + mmcpart, mmcdev); + return -ENODEV; + } + + /* + * Check for an extra entry at dfu_alt_info env variable + * specifying the mmc HW defined partition number + */ + if (s && !strcmp(strsep(&s, " "), "offset")) + offset = simple_strtoul(s, NULL, 0); + + usb->layout = RAW_ADDR; + usb->lba_start = partinfo.start + offset; + usb->lba_size = partinfo.size - offset; + usb->lba_blk_size = partinfo.blksz; + + } else if (!strncmp(entity_type, "fat", 3)) { + usb->layout = FS_FAT; + usb->dev = second_arg; + usb->part = third_arg; + } else if (!strncmp(entity_type, "ext4", 4)) { + usb->layout = FS_EXT4; + usb->dev = second_arg; + usb->part = third_arg; + } else { + printf("layout (%s) not supported!\n", entity_type); + return -ENODEV; + } + + return 0; +} + +static void fill_entity_usbdown(char *interface, char *devstr) +{ + struct usbdown_entity *usbdown; + int alt_num, i, ret, offset = 0; + char *alt_setting, *alt_sep, *s, *st, *setting; + size_t buf_size = CONFIG_SET_DFU_ALT_BUF_LEN; + ALLOC_CACHE_ALIGN_BUFFER(char, buf, buf_size); + +#ifdef CONFIG_SET_DFU_ALT_INFO + /* Reuse dfu information. Use the eMMC by default */ + setenv("dfu_alt_boot", CONFIG_DFU_ALT_BOOT_EMMC); + offset = snprintf(buf, buf_size, "%s", CONFIG_DFU_ALT_BOOT_EMMC); + + /* Reset the dfu_alt_boot environment for thor download */ + setenv("dfu_alt_boot", "Not supported!"); + + alt_setting = getenv("dfu_alt_system"); + if (alt_setting) { + if (offset) + alt_sep = ";"; + else + alt_sep = ""; + + offset += snprintf(buf + offset, buf_size - offset, + "%s%s", alt_sep, alt_setting); + } + + setenv("dfu_alt_info", buf); +#endif + setting = getenv("dfu_alt_info"); + + alt_num = find_alt_num(setting); + + usbdown = calloc(sizeof(*usbdown), alt_num); + if (!usbdown) { + printf("%s: Failed to allocate.\n", __func__); + return; + } + + for (i = 0; i < alt_num; i++) { + /* Parsing file name */ + s = strsep(&setting, ";"); + st = strsep(&s, " "); + strcpy(usbdown[i].name, st); + + ret = usb_fill_entity(&usbdown[i], s, alt_num_count, + interface, devstr); + if (ret) { + printf("%s Failed.\n", __func__); + return; + } + + list_add_tail(&usbdown[i].list, &usbdown_list); + alt_num_count++; + } +} + +static void do_usb_start(void) +{ + bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start"); + + if (usb_init() < 0) + return; + + /* Driver model will probe the devices as they are found */ +#ifndef CONFIG_DM_USB +# ifdef CONFIG_USB_STORAGE + /* try to recognize storage devices immediately */ + usb_stor_curr_dev = usb_stor_scan(1); +# endif +#endif /* !CONFIG_DM_USB */ +} + +int do_update(cmd_tbl_t *cmdtp, int flags, int argc, char * const argv[]) +{ + struct usbdown_entity *usbdown; + +#ifdef CONFIG_USB_STORAGE + struct blk_desc *stor_dev; +#endif + if (argc < 4) + return CMD_RET_USAGE; + + if (!usb_started) { + printf("\nUSB is stopped..starting USB first.\n\n"); + do_usb_start(); + } + + if (argc == 4) { + int dev = (int)simple_strtoul(argv[1], NULL, 10); + char *interface = argv[2]; + const char *filename = argv[3]; + loff_t len_read = 0, size = 0, offset = 0; + unsigned long addr = CONFIG_SYS_SDRAM_BASE; + int alt_num, ret = 0; + unsigned long len = 0; + struct mmc *mmc; + const char *fsname, *opname; + char cmd_buf[128]; + int part_num_bkp = 0; + const char *from = "usb"; + + /* Default MMC 0 */ + mmc = find_mmc_device(0); + if (!mmc) { + error("Device MMC %d - not found!", 0); + return -ENODEV; + } + + if (mmc_init(mmc)) { + error("Couldn't init MMC device.\n"); + return -ENODEV; + } + + /* Used the mmc 0 by default */ + if (!is_config) { + fill_entity_usbdown(interface, "0"); + is_config = 1; + + printf("USB device %d: ", dev); + stor_dev = blk_get_devnum_by_type(IF_TYPE_USB, dev); + if (stor_dev == NULL) { + printf("unknown device\n"); + return -ENODEV; + } + + printf("\n Device %d: ", dev); + dev_print(stor_dev); + if (stor_dev->type == DEV_TYPE_UNKNOWN) + return 1; + usb_stor_curr_dev = dev; + printf("... is now current device\n"); + } + + if (fs_set_blk_dev(from, argv[1], FS_TYPE_ANY)) { + printf("%d: Unknown block device..\n", __LINE__); + return -ENODEV; + } + + alt_num = usbdown_get_alt(filename); + if (alt_num < 0) { + printf("There is no %s information\n", filename); + return -EINVAL; + } + + ret = fs_size(filename, &size); + if (ret < 0) { + printf("There is no %s\n", filename); + return -EINVAL; + } + + usbdown = usbdown_get_entity(alt_num); + if (!usbdown) { + printf("there is no information for %d\n", alt_num); + return -EINVAL; + } + + if (usbdown->layout == FS_FAT) { + /* loading File */ + fsname = "fat"; + opname = "load"; + + sprintf(cmd_buf, "%s%s usb %s", fsname, + opname, argv[1]); + sprintf(cmd_buf + strlen(cmd_buf), + " %p", (void *)addr); + sprintf(cmd_buf + strlen(cmd_buf), + " %s", usbdown->name); + + run_command(cmd_buf, 0); + + /* Write file */ + opname = "write"; + sprintf(cmd_buf, "%s%s mmc %d:%d", fsname, opname, + usbdown->dev, usbdown->part); + sprintf(cmd_buf + strlen(cmd_buf), + " %p", (void *)addr); + sprintf(cmd_buf + strlen(cmd_buf), + " %s", usbdown->name); + sprintf(cmd_buf + strlen(cmd_buf), + " %llx", size); + + run_command(cmd_buf, 0); + + } else if (usbdown->layout == RAW_ADDR) { + if (usbdown->hw_partition >= 0) { + part_num_bkp = mmc->block_dev.hwpart; + ret = blk_select_hwpart_devnum(IF_TYPE_MMC, + usbdown->dev_num, + usbdown->hw_partition); + if (ret) + return ret; + } + + while (size > 0) { + if (fs_set_blk_dev(from, argv[1], + FS_TYPE_ANY)) { + printf("Unknown block device..\n"); + if (usbdown->hw_partition >= 0) + blk_select_hwpart_devnum(IF_TYPE_MMC, + usbdown->dev_num, + part_num_bkp); + return -ENODEV; + } + if (size < MAX_BLK_COUNT) + len = size; + else + len = MAX_BLK_COUNT; + + ret = fs_read(filename, addr, offset, len, + &len_read); + if (ret < 0) { + printf("Failed to read %s file.\n", filename); + if (usbdown->hw_partition >= 0) + blk_select_hwpart_devnum(IF_TYPE_MMC, + usbdown->dev_num, + part_num_bkp); + return -EIO; + } + + mmc->block_dev.block_write(&mmc->block_dev, + usbdown->lba_start + offset / 512, + len_read / 512, (void *)addr); + + offset += len_read; + size -= len_read; + } + printf("Read %s Total %llu bytes\n", filename, offset); + } + + if (usbdown->hw_partition >= 0) { + ret = blk_select_hwpart_devnum(IF_TYPE_MMC, usbdown->dev_num, + part_num_bkp); + if (ret) + return ret; + } + + return 0; + } + + return CMD_RET_USAGE; +} + +U_BOOT_CMD(update, 5, 1, do_update, + "Manually download Images with USB storage for Tizen", + " \n" + " (e,g update 0:0 mmc rootfs.img)\n" +); + +/* Only release image files are described */ +static char *name[] = { + "u-boot-mmc.bin", + "params.bin", + "boot.img", + "rootfs.img", + "system-data.img", + "user.img", + "modules.img", +}; + +int do_usb_down(cmd_tbl_t *cmdtp, int flags, int argc, char * const argv[]) +{ + if (argc < 1) + return CMD_RET_USAGE; + + if (argc == 2) { + char cmd_buf[128]; + const char *interface, *dir, *part, *cmd; + int ret, i; + int files = sizeof(name) / sizeof(name[0]); + + if (!usb_started) { + printf("\nUSB is stopped..starting USB first.\n\n"); + do_usb_start(); + } + + /* Use command "update" */ + cmd = "update"; + + /* Fixed direcotry as /updateTizen */ + dir = "/updateTizen"; + + /* interface is fixed "mmc" by default */ + interface = "mmc"; + + /* Checking part 0:0 */ + part = "0:0"; + ret = file_exists("usb", part, dir, FS_TYPE_ANY); + if (!ret) { + part = "0:1"; + ret = file_exists("usb", part, dir, FS_TYPE_ANY); + if (!ret) { + printf("Can't find partition or directory\n"); + return CMD_RET_USAGE; + } + } + + for (i = 0; i < files; i++) { + sprintf(cmd_buf, "%s %s %s %s", + cmd, part, interface, dir); + sprintf(cmd_buf + strlen(cmd_buf), "/%s", name[i]); + run_command(cmd_buf, 0); + printf("\n"); + } + + return 0; + } + + return CMD_RET_USAGE; +} + +U_BOOT_CMD(usbdown, 2, 1, do_usb_down, + "Download automantically all image with USB storage for Tizen", + "all\n" + " (e,g usbdown all)\n" + "Note: All images have to be located in /updateTizen/ directory.\n" + " And part number is 0 or 1. - eg sdb or sdb1\n" +); diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index dc1d923fba..b0c55f3453 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -14,6 +14,7 @@ CONFIG_SYS_PROMPT="ODROID-XU3 # " CONFIG_CMD_MMC=y CONFIG_CMD_I2C=y CONFIG_CMD_USB=y +CONFIG_CMD_USBDOWN=y CONFIG_CMD_DFU=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_GPIO=y