From: Jiho Chu Date: Thu, 2 Feb 2017 01:47:40 +0000 (+0900) Subject: cmd: nfsdown: support nfsdown command for Tizen X-Git-Tag: submit/tizen/20170414.042831~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=438376abce483bf51db3c1737062bacf1522dbc6;p=platform%2Fkernel%2Fu-boot.git cmd: nfsdown: support nfsdown command for Tizen nfsdown feature: - enable USB start if CONFIG_CMD_USB and CONFIG_USB_HOST_ETHER enabled - connect to nfs server - download & update Tizen FW according to DFU info Change-Id: I5d0696b051a8b770349bf28b19735f67b3b089d4 Signed-off-by: Jiho Chu --- diff --git a/cmd/Kconfig b/cmd/Kconfig index c3bfea0b3f..d38a9a9568 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -609,6 +609,11 @@ config CMD_LINK_LOCAL help Acquire a network IP address using the link-local protocol +config CMD_NFS_DOWNLOAD + bool "nfsdown" + help + Support the NFS download for tizen Odroid XU3/4 + endmenu menu "Misc commands" diff --git a/cmd/Makefile b/cmd/Makefile index e3a28014dc..90a198c6e4 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -147,6 +147,7 @@ obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.o obj-$(CONFIG_CMD_THOR_DOWNLOAD) += thordown.o +obj-$(CONFIG_CMD_NFS_DOWNLOAD) += nfsdown.o obj-$(CONFIG_CMD_XIMG) += ximg.o obj-$(CONFIG_YAFFS2) += yaffs2.o obj-$(CONFIG_CMD_SPL) += spl.o diff --git a/cmd/nfsdown.c b/cmd/nfsdown.c new file mode 100644 index 0000000000..eced7c3195 --- /dev/null +++ b/cmd/nfsdown.c @@ -0,0 +1,411 @@ +/* + * cmd_nfsdown.c -- Tizen "nfs" Downloader + * + * Copyright (C) 2017 Jiho Chu + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LEN_BUF 128 +#define LEN_NAME 32 + +#ifdef CONFIG_SYS_SDRAM_BASE +#define NFS_DOWNLOAD_ADDR __stringify(CONFIG_SYS_SDRAM_BASE) +#else +#define NFS_DOWNLOAD_ADDR "0x40000000" +#endif + +enum img_type { + IMG_TYPE_RAW, + IMG_TYPE_PART, +}; + +struct img_info { + char name[LEN_NAME]; + enum img_type type; + + /* mmc info */ + uint hwpart; + uint part; + + /* block info */ + uint lba_start; + uint lba_size; + uint lba_blk_size; + + struct list_head list; +}; + +struct img_comp { + char name[LEN_NAME]; + uint size; + + struct list_head list; +}; + +static char *g_update_image_names[] = { + "bl1.bin", + "bl2.bin", + "u-boot-mmc.bin", + "tzsw.bin", + "params.bin", + "boot.img", + "rootfs.img", + "system-data.img", + "user.img", + "modules.img" +}; + +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_HOST_ETHER) +extern char usb_started; + +static void do_usb_ether_start(void) +{ + bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start"); + if (usb_init() < 0) + return; + + bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start"); + usb_host_eth_scan(1); +} +#endif + +#ifdef CONFIG_SET_DFU_ALT_INFO +#ifdef CONFIG_SET_DFU_ALT_BUF_LEN +#define DFU_ALT_BUF_LEN CONFIG_SET_DFU_ALT_BUF_LEN +#else +#define DFU_ALT_BUF_LEN (SZ_1K) +#endif + +static void set_dfu_alt_info(void) +{ + int buf_used; + ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); + + buf_used = snprintf(buf, DFU_ALT_BUF_LEN, "%s", + CONFIG_DFU_ALT_BOOT_EMMC); + + buf_used += snprintf(buf + buf_used, DFU_ALT_BUF_LEN, "%s%s", + buf_used ? ";" : "", CONFIG_DFU_ALT_SYSTEM); + + if (buf_used <= 0) + return; + + setenv("dfu_alt_info", buf); + + return; +} + +#else /* CONFIG_SET_DFU_ALT_INFO */ + +static void set_dfu_alt_info(void) +{ + return; +} + +#endif /* CONFIG_SET_DFU_ALT_INFO */ + +static int do_mmc_init(struct mmc **mmc) +{ + int ret; + + *mmc = find_mmc_device(0); + if (!mmc) { + error("Couldn't find MMC device no. 0.\n"); + return -ENODEV; + } + + ret = mmc_init(*mmc); + if (ret) { + error("Couldn't init MMC device.\n"); + return ret; + } + + return 0; +} + +static int find_mmc_partition_info(struct mmc *mmc, uint hwpart, uint part, + disk_partition_t *partinfo) +{ + int ret; + + if (!mmc) + return -ENODEV; + + ret = blk_select_hwpart_devnum(IF_TYPE_MMC, 0, hwpart); + if (ret) + return ret; + + ret = part_get_info(&mmc->block_dev, part, partinfo); + if (ret) { + error("Couldn't find part #%d on mmc device #%d\n", + part, hwpart); + return ret; + } + + return 0; +} + +static struct img_info *create_img_info(struct mmc *mmc, char *str_info) +{ + struct img_info *info; + char *tok[6]; + int i; + int ret; + + info = calloc(1, sizeof(struct img_info)); + if (!info) { + error("Cannot malloc!!\n"); + return NULL; + } + + for (i = 0; i < 6; i++) + tok[i] = strsep(&str_info, " \t"); + + if (strlen(tok[0]) >= LEN_NAME - 1) { + error("img name is too long: %s\n", tok[0]); + goto create_img_err; + } + + for (i = 0; i < sizeof(g_update_image_names) / sizeof(char *); i++) + if (!strncmp(tok[0], g_update_image_names[i], strlen(tok[0]))) + sprintf(info->name, "%s", g_update_image_names[i]); + + if (!info->name[0]) + goto create_img_err; + + if (!strncmp(tok[1], "raw", 3)) { + info->type = IMG_TYPE_RAW; + info->lba_start = simple_strtoul(tok[2], NULL, 0); + info->lba_size = simple_strtoul(tok[3], NULL, 0); + info->lba_blk_size = 512; + + if (tok[4] && !strncmp(tok[4], "mmcpart", 7)) + info->hwpart = simple_strtoul(tok[5], NULL, 0); + else + info->hwpart = 1; + } else if (!strncmp(tok[1], "part", 4)) { + disk_partition_t partinfo; + uint offset = 0; + + info->type = IMG_TYPE_PART; + info->hwpart = simple_strtoul(tok[2], NULL, 0); + info->part = simple_strtoul(tok[3], NULL, 0); + + ret = find_mmc_partition_info(mmc, info->hwpart, info->part, + &partinfo); + if (ret) { + error("Cannot get partition info: %d\n", info->hwpart); + goto create_img_err; + } + + if (tok[4] && !strcmp(tok[4], "offset")) + offset = simple_strtoul(tok[5], NULL, 0); + + info->lba_start = partinfo.start + offset; + info->lba_size = partinfo.size - offset; + info->lba_blk_size = partinfo.blksz; + } else if (!strncmp(tok[1], "fat", 3)) { + error("nfsdown does not support fat update"); + goto create_img_err; + } else { + error("Unrecognized img type: %s", tok[0]); + goto create_img_err; + } + + return info; + +create_img_err: + free(info); + + return NULL; +} + +struct img_comp *create_img_comp(const char *name, uint size) +{ + struct img_comp *comp; + + comp = malloc(sizeof(struct img_comp)); + if (!comp) { + error("Failed to alloc\n"); + return NULL; + } + + strncpy(comp->name, name, LEN_NAME); + comp->size = size; + + return comp; +} + +/** + * Donwload from nfs file and write to mmc stroage + * + * @param buf_addr Download buffer address from NFS + * @param file_path Download file path from NFS + * @param part MMC partition + * @param offset img block offset + * @param size img block size + * @param blk_size MMC block size + * @return file_size written file size, return -1 if error occurs + */ +static int do_nfs_to_mmc(struct mmc *mmc, char *buf_addr, char *file_path, + uint part, uint offset, uint size, uint blk_size) +{ + char *_argv[3]; + uint _size; + int repeatable; + int ret; + void *addr; + + _argv[0] = "nfs"; + _argv[1] = buf_addr; + _argv[2] = file_path; + + ret = cmd_process(0, 3, _argv, &repeatable, NULL); + if (ret != CMD_RET_SUCCESS) { + puts("nfs download failed!!\n"); + return -1; + } + + _size = (net_boot_file_size % blk_size) ? + net_boot_file_size / blk_size + 1 + : net_boot_file_size / blk_size; + + ret = blk_select_hwpart_devnum(IF_TYPE_MMC, 0, part); + if (ret) { + error("Couldn't change to hwpart: %d\n", part); + return -1; + } + + addr = (void *)simple_strtoul(buf_addr, NULL, 16); + + printf("MMC write: dev # %d, block # %d, count %d ...\n\n", + part, offset, _size); + ret = mmc->block_dev.block_write(&mmc->block_dev, offset, _size, addr); + if (ret != _size) { + error("Failed to write MMC: part(%d), start(%d), size(%d)", + part, offset, _size); + return -1; + } + + return (int)net_boot_file_size; +} + +int do_nfs_down(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char *nfs_path; + char *buf; + char *line; + char src_path[LEN_BUF]; + int size; + int ret; + + struct img_info *info, *tmp_info; + struct img_comp *comp, *tmp_comp; + struct mmc *mmc; + + LIST_HEAD(img_info_list); + LIST_HEAD(img_comp_list); + + puts("TIZEN \"nfs\" Downloader\n"); + + switch (argc) { + case 2: + nfs_path = argv[1]; + break; + default: + return CMD_RET_USAGE; + } + + INIT_LIST_HEAD(&img_info_list); + INIT_LIST_HEAD(&img_comp_list); + + set_dfu_alt_info(); + + buf = getenv("dfu_alt_info"); + if (!buf) { + puts("No Default dfu_alt_info\n"); + return CMD_RET_FAILURE; + } + printf("\ndfu_alt_info = %s\n", buf); + + ret = do_mmc_init(&mmc); + if (ret) { + error("failed to init mmc\n"); + ret = CMD_RET_FAILURE; + goto error_end; + } + +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_HOST_ETHER) + if (!usb_started) + do_usb_ether_start(); +#endif + + line = strtok(buf, ";\n\0"); + while (line) { + struct img_info *new_info; + + new_info = create_img_info(mmc, line); + if (new_info) + list_add_tail(&new_info->list, &img_info_list); + + line = strtok(NULL, ";\n\0"); + } + + list_for_each_entry(info, &img_info_list, list) { + snprintf(src_path, LEN_BUF, "%s/%s", nfs_path, info->name); + + size = do_nfs_to_mmc(mmc, NFS_DOWNLOAD_ADDR, src_path, + info->hwpart, info->lba_start, + info->lba_size, info->lba_blk_size); + if (size > 0) { + struct img_comp *new_comp; + + new_comp = create_img_comp(info->name, size); + if (new_comp) + list_add_tail(&new_comp->list, &img_comp_list); + } else { + printf("SKIP %s\n\n", src_path); + } + } + + puts("########################################\n"); + list_for_each_entry(comp, &img_comp_list, list) + printf("%15s\t-\t%10d Byte\n", comp->name, comp->size); + puts("########################################\n"); + +error_end: + free(buf); + + list_for_each_entry_safe(comp, tmp_comp, &img_comp_list, list) { + list_del(&comp->list); + free(comp); + } + + list_for_each_entry_safe(info, tmp_info, &img_info_list, list) { + list_del(&info->list); + free(info); + } + + return ret; +} + +U_BOOT_CMD(nfsdown, CONFIG_SYS_MAXARGS, 1, do_nfs_down, + "TIZEN \"nfs\" downloader", + ":\n" + " - device firmware upgrade via nfs for Tizen\n" + " fusing images from : to MMC.\n" + "\n" + "(e.g) nfsdown 192.168.0.1:/nfs\n" +);