[PATCH] ARM: k3: r5: add USB DFU support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds USB support for the k3 SoCs. DFU mode is entered when
the SoC is booted from USB. For continuing the boot we need several
binaries (bl31, OP-TEE, barebox, ti-dm firmware), these can be uploaded
as distinct files or combined together as a FIP image. This patch
also adds the possibility to put a FIP image on the SD/eMMC card which
is then preferred over the distinct files which were previously expected
on SD/eMMC cards.

Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>
---
 Documentation/boards/ti-k3.rst |  35 +++++
 arch/arm/mach-k3/r5.c          | 231 ++++++++++++++++++++++++++++-----
 2 files changed, 236 insertions(+), 30 deletions(-)

diff --git a/Documentation/boards/ti-k3.rst b/Documentation/boards/ti-k3.rst
index a1bf0b92e8..7962491e41 100644
--- a/Documentation/boards/ti-k3.rst
+++ b/Documentation/boards/ti-k3.rst
@@ -69,6 +69,9 @@ OP-TEE is built from https://github.com/OP-TEE/optee_os.git::
         PLATFORM=k3-am62x
   cp out/arm-plat-k3/core/tee-raw.bin $TI_BOOT/optee.bin
 
+OP-TEE is optional. barebox will continue without ``optee.bin`` when the file
+does not exist.
+
 Copying ti-dm.bin
 -----------------
 
@@ -77,3 +80,35 @@ copied to the eMMC/SD as well::
 
   cp $TI_LINUX_FIRMWARE/ti-dm/am62xx/ipc_echo_testb_mcu1_0_release_strip.xer5f $TI_BOOT/ti-dm.bin
 
+Combining binaries into a FIP image
+-----------------------------------
+
+Alternatively to putting the different binaries (``barebox.bin``, ``bl31.bin``, ``optee.bin``
+and ``ti-dm.bin``) into the FAT image the files can be combined into a FIP image named
+``k3.fip``.::
+
+  fiptool create --soc-fw bl31.bin \
+    --tos-fw optee.bin \
+    --nt-fw barebox-beagleplay.img \
+    --blob uuid=9e8c2017-8b94-4e2b-a7b3-a0f88eabb8ae,file=ti-dm.bin k3.fip
+
+USB DFU boot
+------------
+K3 Boards can be booted via USB DFU. When in USB boot mode the initial stage can be uploaded
+using ``dfu-util``::
+
+  dfu-util -D barebox-beagleplay-r5.img -a bootloader
+
+This will start the initial stage which then expects the following stages which can
+be uploaded with ``dfu-util`` as well, either as FIP image::
+
+  dfu-util -D k3.fip -a fip
+
+or as separate files::
+
+  dfu-util -D blb31.bin -a tfa
+  dfu-util -D optee.bin -a optee
+  dfu-util -D ti-dm.bin -a ti-dm
+  dfu-util -D barebox-beagleplay.img -a barebox
+
+Uploading optee.bin can be skipped in case it's not needed.
diff --git a/arch/arm/mach-k3/r5.c b/arch/arm/mach-k3/r5.c
index ae2c8607e5..9bb2aeb6b6 100644
--- a/arch/arm/mach-k3/r5.c
+++ b/arch/arm/mach-k3/r5.c
@@ -6,6 +6,7 @@
 #include <init.h>
 #include <libfile.h>
 #include <fs.h>
+#include <fip.h>
 #include <firmware.h>
 #include <linux/remoteproc.h>
 #include <soc/ti/ti_sci_protocol.h>
@@ -14,6 +15,8 @@
 #include <asm/cache.h>
 #include <linux/sizes.h>
 #include <barebox.h>
+#include <bootsource.h>
+#include <linux/usb/gadget-multi.h>
 
 #define CTRLMMR_LOCK_KICK0_UNLOCK_VAL	0x68ef3490
 #define CTRLMMR_LOCK_KICK1_UNLOCK_VAL	0xd172bc5a
@@ -179,34 +182,175 @@ void am625_early_init(void)
  * The bl31 and optee binaries are relocatable, but these addresses
  * are hardcoded as reserved mem regions in the upstream device trees.
  */
-#define BL31_ADDRESS 0x9e780000
-#define OPTEE_ADDRESS 0x9e800000
+#define BL31_ADDRESS (void *)0x9e780000
+#define BL32_ADDRESS (void *)0x9e800000
+#define BAREBOX_ADDRESS (void *)0x80080000
 
-static int k3_r5_start_image(void)
+static void *k3_ti_dm;
+
+static bool have_bl31;
+static bool have_bl32;
+static bool have_bl33;
+
+#define UUID_TI_DM_FW \
+        UUID_INIT(0x9e8c2017, 0x8b94, 0x4e2b, 0xa7, 0xb3, 0xa0, 0xf8, 0x8e, 0xab, 0xb8, 0xae)
+
+static uuid_t uuid_bl31 = UUID_EL3_RUNTIME_FIRMWARE_BL31;
+static uuid_t uuid_ti_dm_fw = UUID_TI_DM_FW;
+static uuid_t uuid_bl33 = UUID_NON_TRUSTED_FIRMWARE_BL33;
+static uuid_t uuid_bl32 = UUID_SECURE_PAYLOAD_BL32;
+
+static int load_fip(const char *filename)
 {
-	int err;
-	void *ti_dm_buf;
-	ssize_t size;
-	struct firmware fw;
-	const struct ti_sci_handle *ti_sci;
-	void *bl31 = (void *)BL31_ADDRESS;
-	void *barebox = (void *)0x80080000;
-	void *optee = (void *)OPTEE_ADDRESS;
-	struct elf_image *elf;
-	void __noreturn (*ti_dm)(void);
-	struct rproc *arm64_rproc;
+	void *buf, *bufend;
+	fip_toc_header_t *toc_header;
+	fip_toc_entry_t *toc_entry;
+	size_t st_size;
+	int ret;
 
-	ti_sci = ti_sci_get_handle(NULL);
-	if (IS_ERR(ti_sci))
-		return -EINVAL;
+	ret = read_file_2(filename, &st_size, &buf, FILESIZE_MAX);
+	if (ret)
+		return ret;
 
-	arm64_rproc = ti_k3_am64_get_handle();
-	if (!arm64_rproc) {
-		pr_err("Cannot get rproc handle\n");
+	bufend = buf + st_size;
+
+	if (st_size < sizeof(fip_toc_header_t)) {
+		pr_err("FIP %s is truncated\n", filename);
+		return -ENODATA;
+	}
+
+	toc_header = (fip_toc_header_t *)buf;
+	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
+
+	if (toc_header->name != TOC_HEADER_NAME) {
+		pr_err("%s is not a FIP file: unknown magic = 0x%08x\n",
+		       filename, toc_header->name);
 		return -EINVAL;
 	}
 
-	size = read_file_into_buf("/boot/optee.bin", optee, SZ_32M);
+	while ((void *)toc_entry + sizeof(*toc_entry) - 1 < bufend) {
+		/* Found the ToC terminator, we are done. */
+		if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0)
+			break;
+
+		/* Overflow checks before memory copy. */
+		if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address) {
+			pr_err("FIP %s is corrupted: entry size exceeds 64 bit address space\n",
+			       filename);
+			ret = -EINVAL;
+			break;
+		}
+		if (toc_entry->size + toc_entry->offset_address > st_size) {
+			pr_err("FIP %s is corrupted: entry size (0x%llx) exceeds FIP file size (0x%zx)\n",
+				filename, toc_entry->size + toc_entry->offset_address, st_size);
+			ret = -EINVAL;
+			break;
+		}
+
+		if (!memcmp(&toc_entry->uuid, &uuid_bl31, sizeof(uuid_t))) {
+			memcpy(BL31_ADDRESS, buf + toc_entry->offset_address, toc_entry->size);
+			have_bl31 = true;
+		}
+
+		if (!memcmp(&toc_entry->uuid, &uuid_bl33, sizeof(uuid_t))) {
+			memcpy(BAREBOX_ADDRESS, buf + toc_entry->offset_address, toc_entry->size);
+			have_bl33 = true;
+		}
+
+		if (!memcmp(&toc_entry->uuid, &uuid_bl32, sizeof(uuid_t))) {
+			memcpy(BL32_ADDRESS, buf + toc_entry->offset_address, toc_entry->size);
+			have_bl32 = true;
+		}
+
+		if (!memcmp(&toc_entry->uuid, &uuid_ti_dm_fw, sizeof(uuid_t))) {
+			k3_ti_dm = xmemdup(buf + toc_entry->offset_address, toc_entry->size);
+		}
+
+		toc_entry++;
+	}
+
+	free(buf);
+
+	return ret;
+}
+
+static void do_dfu(void)
+{
+	struct usbgadget_funcs funcs = {};
+	int ret;
+	struct stat s;
+	ssize_t size;
+
+	funcs.flags |= USBGADGET_DFU;
+	funcs.dfu_opts = "/optee.bin(optee)c,"
+			 "/bl31.bin(tfa)c,"
+			 "/ti-dm.bin(ti-dm)c,"
+			 "/barebox.bin(barebox)cs,"
+			 "/fip.img(fip)cs";
+
+	ret = usbgadget_prepare_register(&funcs);
+	if (ret)
+		goto err;
+
+	while (1) {
+		if (!have_bl32) {
+			size = read_file_into_buf("/optee.bin", BL32_ADDRESS, SZ_32M);
+			if (size > 0) {
+				printf("Downloaded OP-TEE\n");
+				have_bl32 = true;
+			}
+		}
+
+		if (!have_bl31) {
+			size = read_file_into_buf("/bl31.bin", BL31_ADDRESS, SZ_32M);
+			if (size > 0) {
+				printf("Downloaded TF-A\n");
+				have_bl31 = true;
+			}
+		}
+
+		if (!k3_ti_dm) {
+			ret = read_file_2("/ti-dm.bin", &size, &k3_ti_dm, FILESIZE_MAX);
+			if (!ret) {
+				printf("Downloaded TI-DM\n");
+			}
+		}
+
+		size = read_file_into_buf("/barebox.bin", BAREBOX_ADDRESS, SZ_32M);
+		if (size > 0) {
+			have_bl33 = true;
+			printf("Downloaded barebox image, DFU done\n");
+			break;
+		}
+
+		ret = stat("/fip.img", &s);
+		if (!ret) {
+			printf("Downloaded FIP image, DFU done\n");
+			load_fip("/fip.img");
+			break;
+		}
+
+		command_slice_release();
+		mdelay(50);
+		command_slice_acquire();
+	};
+
+	return;
+
+err:
+	pr_err("DFU failed with: %pe\n", ERR_PTR(ret));
+}
+
+static int load_images(void)
+{
+	ssize_t size;
+	int err;
+
+	err = load_fip("/boot/k3.fip");
+	if (!err)
+		return 0;
+
+	size = read_file_into_buf("/boot/optee.bin", BL32_ADDRESS, SZ_32M);
 	if (size < 0) {
 		if (size != -ENOENT) {
 			pr_err("Cannot load optee.bin: %pe\n", ERR_PTR(size));
@@ -214,31 +358,58 @@ static int k3_r5_start_image(void)
 		}
 		pr_info("optee.bin not found, continue without\n");
 	} else {
-		pr_debug("Loaded optee.bin (size %u) to 0x%p\n", size, optee);
+		pr_debug("Loaded optee.bin (size %u) to 0x%p\n", size, BL32_ADDRESS);
 	}
 
-	size = read_file_into_buf("/boot/barebox.bin", barebox, optee - barebox);
+	size = read_file_into_buf("/boot/barebox.bin", BAREBOX_ADDRESS, SZ_32M);
 	if (size < 0) {
 		pr_err("Cannot load barebox.bin: %pe\n", ERR_PTR(size));
 		return size;
 	}
-	pr_debug("Loaded barebox.bin (size %u) to 0x%p\n", size, barebox);
+	pr_debug("Loaded barebox.bin (size %u) to 0x%p\n", size, BAREBOX_ADDRESS);
 
-	size = read_file_into_buf("/boot/bl31.bin", bl31, barebox - optee);
+	size = read_file_into_buf("/boot/bl31.bin", BL31_ADDRESS, SZ_32M);
 	if (size < 0) {
 		pr_err("Cannot load bl31.bin: %pe\n", ERR_PTR(size));
 		return size;
 	}
-	pr_debug("Loaded bl31.bin (size %u) to 0x%p\n", size, bl31);
+	pr_debug("Loaded bl31.bin (size %u) to 0x%p\n", size, BL31_ADDRESS);
 
-	err = read_file_2("/boot/ti-dm.bin", &size, &ti_dm_buf, FILESIZE_MAX);
+	err = read_file_2("/boot/ti-dm.bin", &size, &k3_ti_dm, FILESIZE_MAX);
 	if (err) {
 		pr_err("Cannot load ti-dm.bin: %pe\n", ERR_PTR(err));
 		return err;
 	}
 	pr_debug("Loaded ti-dm.bin (size %u)\n", size);
 
-	elf = elf_open_binary(ti_dm_buf);
+	return 0;
+}
+
+static int k3_r5_start_image(void)
+{
+	int err;
+	struct firmware fw;
+	const struct ti_sci_handle *ti_sci;
+	struct elf_image *elf;
+	void __noreturn (*ti_dm)(void);
+	struct rproc *arm64_rproc;
+
+	if (IS_ENABLED(CONFIG_USB_GADGET_DFU) && bootsource_get() == BOOTSOURCE_SERIAL)
+		do_dfu();
+	else
+		load_images();
+
+	ti_sci = ti_sci_get_handle(NULL);
+	if (IS_ERR(ti_sci))
+		return -EINVAL;
+
+	arm64_rproc = ti_k3_am64_get_handle();
+	if (!arm64_rproc) {
+		pr_err("Cannot get rproc handle\n");
+		return -EINVAL;
+	}
+
+	elf = elf_open_binary(k3_ti_dm);
 	if (IS_ERR(elf)) {
 		pr_err("Cannot open ELF image %pe\n", elf);
 		return PTR_ERR(elf);
@@ -250,9 +421,9 @@ static int k3_r5_start_image(void)
 		elf_close(elf);
 	}
 
-	free(ti_dm_buf);
+	free(k3_ti_dm);
 
-	fw.data = bl31;
+	fw.data = BL31_ADDRESS;
 
 	/* Release all the exclusive devices held by SPL before starting ATF */
 	pr_info("Starting TF-A on A53 core\n");
-- 
2.39.5





[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux