From 90c56bcaff95da95f3d591a7f565b3969358a6ad Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 27 Apr 2020 08:45:02 +0200 Subject: [PATCH] cmd: add generic Tizen Download (NFS & USB) command This is a quick replacement of the NFSdown and USBdown commands, rewritten on top of the generic DFU framework. This removes a few limitation of both obsoleted commands. Change-Id: Id8a311eabd2bab7d90aeee6adabbd6461897b4e3 Signed-off-by: Marek Szyprowski [sw0312.kim: remove newline from command name] Signed-off-by: Seung-Woo Kim Signed-off-by: Jaehoon Chung --- cmd/Kconfig | 9 ++ cmd/Makefile | 1 + cmd/net.c | 2 +- cmd/tizendown.c | 308 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/configs/rpi.h | 4 +- 5 files changed, 321 insertions(+), 3 deletions(-) create mode 100644 cmd/tizendown.c diff --git a/cmd/Kconfig b/cmd/Kconfig index 0c984d7..f592d5c 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1395,6 +1395,15 @@ config CMD_PVBLOCK help Xen para-virtualized block device support +config CMD_TIZEN_DOWNLOAD + bool "Tizen Downloader (NFS & USB)" + select DFU + select CMD_NFS + depends on NET && !CMD_NFS_DOWNLOAD && !CMD_USB_DOWNLOAD + help + Generic DFU based system image downloader for Tizen project. Supports + NFS and USB download: nfsdown and usbdown commands. + config CMD_VIRTIO bool "virtio" depends on VIRTIO diff --git a/cmd/Makefile b/cmd/Makefile index 3a9c974..219add1 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -163,6 +163,7 @@ obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.o obj-$(CONFIG_CMD_USB_SDP) += usb_gadget_sdp.o obj-$(CONFIG_CMD_THOR_DOWNLOAD) += thordown.o +obj-$(CONFIG_CMD_TIZEN_DOWNLOAD) += tizendown.o obj-$(CONFIG_CMD_XIMG) += ximg.o obj-$(CONFIG_CMD_YAFFS2) += yaffs2.o obj-$(CONFIG_CMD_SPL) += spl.o diff --git a/cmd/net.c b/cmd/net.c index 877ec4d..13b0a81 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -287,7 +287,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, return rcode; } -#if defined(CONFIG_CMD_NFS_DOWNLOAD) +#if defined(CONFIG_CMD_TIZEN_DOWNLOAD) || defined(CONFIG_CMD_NFS_DOWNLOAD) int netboot_nfs(unsigned long addr, const char *filename, unsigned long offset, unsigned long limit) { diff --git a/cmd/tizendown.c b/cmd/tizendown.c new file mode 100644 index 0000000..4084182 --- /dev/null +++ b/cmd/tizendown.c @@ -0,0 +1,308 @@ +/* + * cmd_tizendown.c -- Tizen Downloader + * + * Copyright (C) 2020 Marek Szyprowski + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SYS_SDRAM_BASE +#define DOWNLOAD_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_64K) +/* 64K shift to avoid 0 (NULL) DOWNLOAD_ADDR on RPi3/4 */ +#else +#define DOWNLOAD_ADDR 0x40000000 +#endif + +#define TRANSFER_SIZE SZ_128M + +#define LEN_BUF 128 +#define LEN_NAME 32 + +#define HASHES_PER_LINE 64 /* Number of "loading" hashes per line */ + +#if defined(CONFIG_TARGET_RPI_3) || \ + defined(CONFIG_TARGET_RPI_4) || \ + defined(CONFIG_TARGET_RPI_3_32B) || \ + defined(CONFIG_TARGET_RPI_4_32B) +static char *g_update_image_names[] = { + "boot.img", + "rootfs.img", + "system-data.img", + "user.img", + "modules.img", + "ramdisk.img", + "ramdisk-recovery.img" +}; +#elif defined(CONFIG_TARGET_ODROID_XU3) || defined(CONFIG_TARGET_TIZEN) +static char *g_update_image_names[] = { + "u-boot-mmc.bin", + "params.bin", + "boot.img", + "rootfs.img", + "system-data.img", + "user.img", + "modules.img", + "ramdisk.img" +}; +#else +#error "Tizen Download is not supported for this board" +#endif + +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_HOST_ETHER) && !defined(CONFIG_DM_ETH) +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 + +static int do_nfs_to_dfu(char *file, char *name) +{ + int cnt = 0, alt = dfu_get_alt(name); + struct dfu_entity *de; + uint done = 0, wdone = 0; + int ret; + void *buf = (void *)DOWNLOAD_ADDR; + int buf_size = TRANSFER_SIZE; + + if (alt < 0) { + printf("DFU entity for file %s not found\n", name); + return -1; + } + de = dfu_get_entity(alt); + + do { + printf("Downloading %s, offset %u...\n", file, done); + ret = netboot_nfs((unsigned long)buf, file, done, buf_size); + if (ret != CMD_RET_SUCCESS) { + printf("NFS download of file %s failed!!\n", file); + return -1; + } + + puts("Writing: "); + wdone = 0; + do { + int write_size = min_t(int, dfu_get_buf_size(), + net_boot_file_size); + + ret = dfu_write(de, buf + wdone, write_size, cnt++); + if (ret) + goto done; + wdone += write_size; + if (cnt % HASHES_PER_LINE == 0) + puts("\n\t "); + } while (wdone < net_boot_file_size); + puts("\n"); + + done += net_boot_file_size; + } while (net_boot_file_size == buf_size); + + ret = dfu_flush(de, buf, 0, cnt); + puts(""); +done: + if (ret) { + printk("DFU entity write failed\n"); + return -1; + } + return (int)done; +} + +static int do_usb_to_dfu(char *file, char *name) +{ + int cnt = 0, alt = dfu_get_alt(name); + int chunk = 0, chunk_count; + struct dfu_entity *de; + uint done = 0, wdone = 0; + int ret; + void *buf = (void *)DOWNLOAD_ADDR; + int buf_size = TRANSFER_SIZE; + loff_t size = 0; + char *fsdev; + + if (alt < 0) { + printf("DFU entity for file %s not found\n", name); + return -1; + } + + fsdev = "0:1"; + if (fs_set_blk_dev("usb", fsdev, FS_TYPE_ANY)) { + fsdev = "0:0"; + if (fs_set_blk_dev("usb", fsdev, FS_TYPE_ANY)) { + printf("Unsupported USB block device..\n"); + return -1; + } + } + + ret = fs_size(file, &size); + if (ret < 0) { + printf("File usb%s%s not found\n", fsdev, file); + return -1; + } + + chunk_count = 1 + size / buf_size; + de = dfu_get_entity(alt); + + do { + printf("Reading %s, chunk %d/%d (offset %u) ...\n", file, + ++chunk, chunk_count, done); + + if (fs_set_blk_dev("usb", fsdev, FS_TYPE_ANY)) { + printf("%d: Unknown block device..\n", __LINE__); + return -1; + } + + ret = fs_read(file, (unsigned long)buf, done, buf_size, &size); + if (ret < 0) { + printf("Failed to read %s file %lld.\n", file, size); + return -1; + } + + puts("Writing: "); + wdone = 0; + do { + int write_size = min_t(int, dfu_get_buf_size(), + size); + ret = dfu_write(de, buf + wdone, write_size, cnt++); + if (ret) + goto done; + wdone += write_size; + if (cnt % HASHES_PER_LINE == 0) + puts("\n\t "); + } while (wdone < size); + puts("\n"); + + done += size; + } while (size == buf_size); + + ret = dfu_flush(de, buf, 0, cnt); + puts("\n"); +done: + if (ret) { + printk("DFU entity write failed\n"); + return -1; + } + return (int)done; +} + + +static int do_tizen_down(char *path, char *file, int (*func)(char *, char *)) +{ + char src_path[LEN_BUF]; + int i, ret = 0; + char **images; + int image_count; + int done_count = 0; + int done_bytes[ARRAY_SIZE(g_update_image_names)]; + char *done_images[ARRAY_SIZE(g_update_image_names)]; + + if (file) { + images = &file; + image_count = 1; + } else { + images = g_update_image_names; + image_count = ARRAY_SIZE(g_update_image_names); + } + +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_HOST_ETHER) && !defined(CONFIG_DM_ETH) + if (!usb_started) + do_usb_ether_start(); +#endif + + ret = dfu_init_env_entities("mmc", "0"); + if (ret) { + printf("DFU init entities failed\n"); + return ret; + } + + for (i = 0; i < image_count; i++) { + char *file_name = images[i]; + int size; + + snprintf(src_path, LEN_BUF, "%s/%s", path, file_name); + size = func(src_path, file_name); + + if (size > 0) { + done_images[done_count] = file_name; + done_bytes[done_count] = size; + done_count++; + } else { + printf("SKIP %s\n", src_path); + } + } + + dfu_free_entities(); + + puts("########################################\n"); + for (i = 0; i < done_count; i++) + printf("%20s -\t%10d Bytes\n", done_images[i], done_bytes[i]); + puts("########################################\n"); + + return CMD_RET_SUCCESS; +} + +int do_nfs_down(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + puts("TIZEN \"NFS\" Downloader\n"); + + switch (argc) { + case 2: + return do_tizen_down(argv[1], NULL, do_nfs_to_dfu); + case 3: + return do_tizen_down(argv[1], argv[2], do_nfs_to_dfu); + default: + return CMD_RET_USAGE; + } +} + +U_BOOT_CMD(nfsdown, CONFIG_SYS_MAXARGS, 1, do_nfs_down, + "TIZEN \"NFS\" downloader", + "nfsdown [:] [image file name]\n" + " - device firmware upgrade via nfs for Tizen\n" + " fusing images from : to MMC.\n" + " - required to set env for ipaddr, serverip, gatewayip,\n" + " and netmask.\n" + "\n" + "(e.g) nfsdown 192.168.0.1:/nfs [rootfs.img]\n" +); + +int do_usb_down(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + puts("TIZEN \"USB\" Downloader\n"); + + switch (argc) { + case 1: + return do_tizen_down("/updateTizen", NULL, do_usb_to_dfu); + case 2: + return do_tizen_down("/updateTizen", argv[1], do_usb_to_dfu); + default: + return CMD_RET_USAGE; + } +} + +U_BOOT_CMD(usbdown, CONFIG_SYS_MAXARGS, 1, do_usb_down, + "TIZEN \"USB\" downloader", + "usbdown [image file name]\n" + " - device firmware upgrade via USB mass-storage for Tizen\n" + " fusing images from \"updateTizen\" USB directory to MMC.\n" + " - \"updateTizen\" directory has to be on the first partition\n" + " of the USB storage\n" + "(e.g) tizendown [rootfs.img]\n\n" +); diff --git a/include/configs/rpi.h b/include/configs/rpi.h index 28e4423..924964a 100644 --- a/include/configs/rpi.h +++ b/include/configs/rpi.h @@ -77,8 +77,8 @@ #define CONFIG_TFTP_TSIZE #endif -/* DFU over USB/UDC */ -#if defined(CONFIG_CMD_DFU) || defined(CONFIG_CMD_THOR) +/* DFU over USB/UDC or NFS*/ +#ifdef CONFIG_DFU #define CONFIG_SYS_DFU_DATA_BUF_SIZE SZ_1M #define CONFIG_SYS_DFU_MAX_FILE_SIZE SZ_2M -- 2.7.4