arm: mach-k3: sysfw-loader: Add support to download SYSFW via DFU
[oweals/u-boot.git] / arch / arm / mach-k3 / sysfw-loader.c
index 2ede82004ab64c217d9128510f54cab8cc728f17..94dbeb9437d9472ca3e469a741c82156bf44c896 100644 (file)
 #include <malloc.h>
 #include <remoteproc.h>
 #include <linux/soc/ti/ti_sci_protocol.h>
+#include <g_dnl.h>
+#include <usb.h>
+#include <dfu.h>
+
 #include <asm/arch/sys_proto.h>
+#include "common.h"
+
+DECLARE_GLOBAL_DATA_PTR;
 
 /* Name of the FIT image nodes for SYSFW and its config data */
 #define SYSFW_FIRMWARE                 "sysfw.bin"
@@ -169,6 +176,27 @@ static void k3_sysfw_configure_using_fit(void *fit,
                      ret);
 }
 
+#if CONFIG_IS_ENABLED(DFU)
+static int k3_sysfw_dfu_download(void *addr)
+{
+       char dfu_str[50];
+       int ret;
+
+       sprintf(dfu_str, "sysfw.itb ram 0x%p 0x%x", addr,
+               CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
+       ret = dfu_config_entities(dfu_str, "ram", "0");
+       if (ret) {
+               dfu_free_entities();
+               goto exit;
+       }
+
+       run_usb_dnl_gadget(0, "usb_dnl_dfu");
+exit:
+       dfu_free_entities();
+       return ret;
+}
+#endif
+
 void k3_sysfw_loader(void (*config_pm_done_callback)(void))
 {
        struct spl_image_info spl_image = { 0 };
@@ -214,6 +242,29 @@ void k3_sysfw_loader(void (*config_pm_done_callback)(void))
                                   0);
 #endif
                break;
+#endif
+#if CONFIG_IS_ENABLED(YMODEM_SUPPORT)
+       case BOOT_DEVICE_UART:
+#ifdef CONFIG_K3_EARLY_CONS
+               /*
+                * Establish a serial console if not yet available as required
+                * for UART-based boot. For this use the early console feature
+                * that allows setting up a UART for use before SYSFW has been
+                * brought up. Note that the associated UART module's clocks
+                * must have gotten enabled by the ROM bootcode which will be
+                * the case when continuing to boot serially from the same
+                * UART that the ROM loaded the initial bootloader from.
+                */
+               if (!gd->have_console)
+                       early_console_init();
+#endif
+               ret = spl_ymodem_load_image(&spl_image, &bootdev);
+               break;
+#endif
+#if CONFIG_IS_ENABLED(DFU)
+       case BOOT_DEVICE_DFU:
+               ret = k3_sysfw_dfu_download(sysfw_load_address);
+               break;
 #endif
        default:
                panic("Loading SYSFW image from device %u not supported!\n",
@@ -251,10 +302,21 @@ void k3_sysfw_loader(void (*config_pm_done_callback)(void))
        if (config_pm_done_callback)
                config_pm_done_callback();
 
-       /* Output System Firmware version info */
-       printf("SYSFW ABI: %d.%d (firmware rev 0x%04x '%.*s')\n",
+       /*
+        * Output System Firmware version info. Note that since the
+        * 'firmware_description' field is not guaranteed to be zero-
+        * terminated we manually add a \0 terminator if needed. Further
+        * note that we intentionally no longer rely on the extended
+        * printf() formatter '%.*s' to not having to require a more
+        * full-featured printf() implementation.
+        */
+       char fw_desc[sizeof(ti_sci->version.firmware_description) + 1];
+
+       strncpy(fw_desc, ti_sci->version.firmware_description,
+               sizeof(ti_sci->version.firmware_description));
+       fw_desc[sizeof(fw_desc) - 1] = '\0';
+
+       printf("SYSFW ABI: %d.%d (firmware rev 0x%04x '%s')\n",
               ti_sci->version.abi_major, ti_sci->version.abi_minor,
-              ti_sci->version.firmware_revision,
-              sizeof(ti_sci->version.firmware_description),
-              ti_sci->version.firmware_description);
+              ti_sci->version.firmware_revision, fw_desc);
 }