From: Sascha Hauer <s.hauer@pengutronix.de>
To: Barebox List <barebox@lists.infradead.org>
Subject: [PATCH] ARM: k3: r5: add USB DFU support
Date: Thu, 30 Jan 2025 13:29:17 +0100 [thread overview]
Message-ID: <20250130122917.3809977-1-s.hauer@pengutronix.de> (raw)
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@pengutronix.de>
---
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
reply other threads:[~2025-01-30 12:29 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250130122917.3809977-1-s.hauer@pengutronix.de \
--to=s.hauer@pengutronix.de \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox