cmd: add generic Tizen Download (NFS & USB) command
authorMarek Szyprowski <m.szyprowski@samsung.com>
Mon, 27 Apr 2020 06:45:02 +0000 (08:45 +0200)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Mon, 15 Nov 2021 14:17:44 +0000 (15:17 +0100)
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 <m.szyprowski@samsung.com>
[sw0312.kim: remove newline from command name]
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
cmd/Kconfig
cmd/Makefile
cmd/net.c
cmd/tizendown.c [new file with mode: 0644]
include/configs/rpi.h

index 3a857b3..6bbf93c 100644 (file)
@@ -1360,6 +1360,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
index ed36694..fdc04b1 100644 (file)
@@ -174,6 +174,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
index dd158ff..44ea869 100644 (file)
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -290,7 +290,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 (file)
index 0000000..4084182
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * cmd_tizendown.c -- Tizen Downloader
+ *
+ * Copyright (C) 2020 Marek Szyprowski <m.szyprowski@samsung.com>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <malloc.h>
+#include <bootstage.h>
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <memalign.h>
+#include <net.h>
+#include <usb.h>
+#include <dfu.h>
+#include <fs.h>
+
+#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 [<IP_ADDR>:]<IMG_PATH> [image file name]\n"
+          "  - device firmware upgrade via nfs for Tizen\n"
+          "    fusing images from <IP_ADDR>:<IMG_PATH> 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"
+);
index 78e70c6..11e0c0b 100644 (file)
@@ -70,8 +70,8 @@
 #define CONFIG_LCD_DT_SIMPLEFB
 #define CONFIG_VIDEO_BCM2835
 
-/* DFU over USB/UDC */
-#if defined(CONFIG_CMD_DFU) || defined(CONFIG_CMD_THOR)
+/* DFU over USB/UDC or NFS*/
+#ifdef CONFIG_DFU
 #ifdef CONFIG_ARM64
 #define KERNEL_FILENAME                "Image"
 #else