* [PATCH v2 01/14] pbl: add panic_no_stacktrace()
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 02/14] arch: Allow data_abort_mask() in PBL Sascha Hauer
` (13 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX
ARM code calls panic_no_stacktrace() when exceptions are enabled.
In order to to add exception handling support for PBL introduce
panic_no_stacktrace() for PBL as an alias to panic().
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
pbl/misc.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pbl/misc.c b/pbl/misc.c
index 1f0d992ce08b5c45e8416885de7395f065ab7666..075c6a854bc8c0e01000087bd2a957a7abe92d0d 100644
--- a/pbl/misc.c
+++ b/pbl/misc.c
@@ -20,3 +20,6 @@ void __noreturn panic(const char *fmt, ...)
va_end(args);
while(1);
}
+
+void __noreturn panic_no_stacktrace(const char *fmt, ...)
+ __alias(panic);
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 02/14] arch: Allow data_abort_mask() in PBL
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 01/14] pbl: add panic_no_stacktrace() Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 03/14] ARM: add exception handling support for PBL Sascha Hauer
` (12 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX
With this architecures which want to support data_abort_mask() in
PBL can select ARCH_HAS_DATA_ABORT_MASK_PBL.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/Kconfig | 3 +++
include/abort.h | 3 ++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/Kconfig b/arch/Kconfig
index 446c4b8fd9605cdd84e66514570a2088b0885ff7..919c8cfebab51d1d2623c82360a30cf5173ffe78 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -68,6 +68,9 @@ config ARCH_HAS_STACK_DUMP
config ARCH_HAS_DATA_ABORT_MASK
bool
+config ARCH_HAS_DATA_ABORT_MASK_PBL
+ bool
+
config ARCH_HAS_ZERO_PAGE
bool
diff --git a/include/abort.h b/include/abort.h
index 95db1b54d6d9f361c9607c6a8ea1f96b4c5f18d0..c623a4c510414c9e92f21e911473bbe8565cace5 100644
--- a/include/abort.h
+++ b/include/abort.h
@@ -2,7 +2,8 @@
#ifndef __ABORT_H
#define __ABORT_H
-#if defined CONFIG_ARCH_HAS_DATA_ABORT_MASK && IN_PROPER
+#if (defined CONFIG_ARCH_HAS_DATA_ABORT_MASK && IN_PROPER) || \
+ (defined CONFIG_ARCH_HAS_DATA_ABORT_MASK_PBL && IN_PBL)
/*
* data_abort_mask - ignore data aborts
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 03/14] ARM: add exception handling support for PBL
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 01/14] pbl: add panic_no_stacktrace() Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 02/14] arch: Allow data_abort_mask() in PBL Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 8:54 ` Marco Felsch
2025-06-30 7:45 ` [PATCH v2 04/14] ARM: i.MX6QDL: add imxcfg helper to configure the TZASC1/2 Sascha Hauer
` (11 subsequent siblings)
14 siblings, 1 reply; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
Exception handling in PBL can be very useful for debugging PBL code.
This patch adds support for it.
This is currently only implemented for ARMv7 and ARMv8. Only on these
architectures we can tell the CPU where the exception table is. On ARMv6
and older we would have to copy the exception table either to 0x0 or
0xffff0000. Not all SoCs have writable memory at these locations, so we
would have to utilize the MMU to map writable memory there. We are not
there yet, so for now skip exception handling support on these older
architectures.
Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/Kconfig | 10 ++++++++++
arch/arm/cpu/Makefile | 1 +
arch/arm/cpu/interrupts_32.c | 14 +++++++++++++-
arch/arm/cpu/interrupts_64.c | 10 +++++++++-
arch/arm/cpu/uncompress.c | 2 ++
arch/arm/include/asm/barebox-arm.h | 8 ++++++++
arch/arm/lib/pbl.lds.S | 4 ++++
7 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d283ef7793a1f13e6428d3b1037460cb806b566f..9b67f823807f2610ba9f6c6741031f1be18a9a2c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -376,6 +376,16 @@ config ARM_EXCEPTIONS
bool "enable arm exception handling support"
default y
+config ARM_EXCEPTIONS_PBL
+ select ARCH_HAS_DATA_ABORT_MASK_PBL
+ depends on CPU_V7 || CPU_V8
+ bool "enable arm exception handling support in PBL"
+ help
+ Say yes here to enable exception handling in PBL. Note that the exception
+ table has to be initialized by calling arm_pbl_init_exceptions(). This is
+ done in barebox_pbl_start(). If you need exception handling earlier then
+ you have to call arm_pbl_init_exceptions() earlier from your board code.
+
config ARM_UNWIND
bool "enable stack unwinding support"
depends on AEABI
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index 39e59c2a2f733d668d57a2f28bdd99f69a016229..9550592796702759f950a3bc4de385100ef2b2e8 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -3,6 +3,7 @@
obj-pbl-y += cpu.o
obj-$(CONFIG_ARM_EXCEPTIONS) += exceptions_$(S64_32).o interrupts_$(S64_32).o
+pbl-$(CONFIG_ARM_EXCEPTIONS_PBL) += exceptions_$(S64_32).o interrupts_$(S64_32).o
obj-$(CONFIG_MMU) += mmu-common.o
obj-pbl-$(CONFIG_MMU) += mmu_$(S64_32).o
obj-$(CONFIG_MMU) += dma_$(S64_32).o
diff --git a/arch/arm/cpu/interrupts_32.c b/arch/arm/cpu/interrupts_32.c
index 623efb3966f0c34632e678d9e1edf2b6affcb4c5..cd503b38eeea551f27bbab0663bbfabdda7ffeea 100644
--- a/arch/arm/cpu/interrupts_32.c
+++ b/arch/arm/cpu/interrupts_32.c
@@ -12,6 +12,7 @@
#include <asm/ptrace.h>
#include <asm/barebox-arm.h>
#include <asm/unwind.h>
+#include <asm/system_info.h>
#include <init.h>
/* Avoid missing prototype warning, called from assembly */
@@ -61,7 +62,7 @@ void show_regs (struct pt_regs *regs)
fast_interrupts_enabled (regs) ? "on" : "off",
processor_modes[processor_mode (regs)],
thumb_mode (regs) ? " (T)" : "");
-#ifdef CONFIG_ARM_UNWIND
+#if defined CONFIG_ARM_UNWIND && IN_PROPER
unwind_backtrace(regs);
#endif
}
@@ -181,3 +182,14 @@ int data_abort_unmask(void)
return arm_data_abort_occurred != 0;
}
+
+#if IS_ENABLED(CONFIG_ARM_EXCEPTIONS_PBL)
+void arm_pbl_init_exceptions(void)
+{
+ if (cpu_architecture() < CPU_ARCH_ARMv7)
+ return;
+
+ set_vbar((unsigned long)__exceptions_start);
+ arm_fixup_vectors();
+}
+#endif
diff --git a/arch/arm/cpu/interrupts_64.c b/arch/arm/cpu/interrupts_64.c
index 4d4ef2bab88ef46a7be1cd4add8f3e51423a283b..574ab6a7ec220d2239b6e27c05426e2d4c67d426 100644
--- a/arch/arm/cpu/interrupts_64.c
+++ b/arch/arm/cpu/interrupts_64.c
@@ -88,7 +88,8 @@ static void __noreturn do_exception(struct pt_regs *pt_regs)
{
show_regs(pt_regs);
- unwind_backtrace(pt_regs);
+ if (IN_PROPER)
+ unwind_backtrace(pt_regs);
panic_no_stacktrace("panic: unhandled exception");
}
@@ -226,3 +227,10 @@ static int aarch64_init_vectors(void)
return 0;
}
core_initcall(aarch64_init_vectors);
+
+#if IS_ENABLED(CONFIG_ARM_EXCEPTIONS_PBL)
+void arm_pbl_init_exceptions(void)
+{
+ aarch64_init_vectors();
+}
+#endif
diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c
index 4657a4828e67e1b0acfa9dec3aef33bc4c525468..4529ef5e3821e5b31a3673de6285d2f37e0ecba2 100644
--- a/arch/arm/cpu/uncompress.c
+++ b/arch/arm/cpu/uncompress.c
@@ -63,6 +63,8 @@ void __noreturn barebox_pbl_start(unsigned long membase, unsigned long memsize,
pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize);
+ arm_pbl_init_exceptions();
+
if (IS_ENABLED(CONFIG_MMU))
mmu_early_enable(membase, memsize);
else if (IS_ENABLED(CONFIG_ARMV7R_MPU))
diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h
index 1ad863681a04b3172be5ecd3f7fbc5ca11f3c3d7..0abdd297a2ceaa76254186ea777efd86f557de70 100644
--- a/arch/arm/include/asm/barebox-arm.h
+++ b/arch/arm/include/asm/barebox-arm.h
@@ -52,6 +52,14 @@ static inline void arm_fixup_vectors(void)
}
#endif
+#if IS_ENABLED(CONFIG_ARM_EXCEPTIONS_PBL)
+void arm_pbl_init_exceptions(void);
+#else
+static inline void arm_pbl_init_exceptions(void)
+{
+}
+#endif
+
void *barebox_arm_boot_dtb(void);
/*
diff --git a/arch/arm/lib/pbl.lds.S b/arch/arm/lib/pbl.lds.S
index dad37c9e9bca98beb4f34360fa53a0421662f03c..9c51f5eb3a3d8256752a78e03fed851c84d92edb 100644
--- a/arch/arm/lib/pbl.lds.S
+++ b/arch/arm/lib/pbl.lds.S
@@ -52,6 +52,10 @@ SECTIONS
__bare_init_start = .;
*(.text_bare_init*)
__bare_init_end = .;
+ . = ALIGN(0x20);
+ __exceptions_start = .;
+ KEEP(*(.text_exceptions*))
+ __exceptions_stop = .;
*(.text*)
}
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2 03/14] ARM: add exception handling support for PBL
2025-06-30 7:45 ` [PATCH v2 03/14] ARM: add exception handling support for PBL Sascha Hauer
@ 2025-06-30 8:54 ` Marco Felsch
0 siblings, 0 replies; 17+ messages in thread
From: Marco Felsch @ 2025-06-30 8:54 UTC (permalink / raw)
To: Sascha Hauer; +Cc: BAREBOX, Ahmad Fatoum
On 25-06-30, Sascha Hauer wrote:
> Exception handling in PBL can be very useful for debugging PBL code.
> This patch adds support for it.
>
> This is currently only implemented for ARMv7 and ARMv8. Only on these
> architectures we can tell the CPU where the exception table is. On ARMv6
> and older we would have to copy the exception table either to 0x0 or
> 0xffff0000. Not all SoCs have writable memory at these locations, so we
> would have to utilize the MMU to map writable memory there. We are not
> there yet, so for now skip exception handling support on these older
> architectures.
>
> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Reviewed-by: Marco Felsch <m.felsch@pengutronix.de>
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 04/14] ARM: i.MX6QDL: add imxcfg helper to configure the TZASC1/2
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (2 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 03/14] ARM: add exception handling support for PBL Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 05/14] ARM: i.MX6Q: add imx6_get_mmdc_sdram_size Sascha Hauer
` (10 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Marco Felsch
From: Marco Felsch <m.felsch@pengutronix.de>
On i.MX6 platforms we need to set the bypass mode within the DCD unlike
the i.MX8M platforms which uses the PBL lowlevel code
(imx8m_tzc380_init()).
Add a helper for this to make the integration easier.
Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
include/mach/imx/imx6q-tzasc.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/include/mach/imx/imx6q-tzasc.h b/include/mach/imx/imx6q-tzasc.h
new file mode 100644
index 0000000000000000000000000000000000000000..968b17d5ec3f74674d3a2049423d71a978e675e9
--- /dev/null
+++ b/include/mach/imx/imx6q-tzasc.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Per default all clocks are on, except for TZASC1/2 CG11/2, so enable them
+ * before activate the modules (disable the bypass mode).
+ */
+wm 32 0x020c4070 0xffffffff
+/* Disable TZASC1/2 bypass */
+wm 32 0x020E0024 0x00000003
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 05/14] ARM: i.MX6Q: add imx6_get_mmdc_sdram_size
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (3 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 04/14] ARM: i.MX6QDL: add imxcfg helper to configure the TZASC1/2 Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 06/14] ARM: i.MX: add config symbol for TZASC Sascha Hauer
` (9 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Marco Felsch
From: Marco Felsch <m.felsch@pengutronix.de>
Add a helper to query the MMDC configured SDRAM size.
Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-imx/esdctl.c | 5 +++++
include/mach/imx/esdctl.h | 1 +
2 files changed, 6 insertions(+)
diff --git a/arch/arm/mach-imx/esdctl.c b/arch/arm/mach-imx/esdctl.c
index 4b67b52ca45eea178889dfc5554a8a9a8ddf51b7..4c4c3528e1a6e68c508edc48ad38c9e2e6324c1c 100644
--- a/arch/arm/mach-imx/esdctl.c
+++ b/arch/arm/mach-imx/esdctl.c
@@ -286,6 +286,11 @@ static inline resource_size_t imx6_mmdc_sdram_size(void __iomem *mmdcbase)
return size;
}
+resource_size_t imx6_get_mmdc_sdram_size(void)
+{
+ return imx6_mmdc_sdram_size(IOMEM(MX6_MMDC_P0_BASE_ADDR));
+}
+
static int imx6_mmdc_add_mem(void *mmdcbase, const struct imx_esdctl_data *data)
{
return arm_add_mem_device("ram0", data->base0,
diff --git a/include/mach/imx/esdctl.h b/include/mach/imx/esdctl.h
index d79bf17959e6d46d19af35be8c10003007d21223..97bd444b1a4ca2defdeb9f82180c0366296a32a0 100644
--- a/include/mach/imx/esdctl.h
+++ b/include/mach/imx/esdctl.h
@@ -151,6 +151,7 @@ void __noreturn imx7d_barebox_entry(void *boarddata);
void __noreturn imx93_barebox_entry(void *boarddata);
#define imx6sx_barebox_entry(boarddata) imx6ul_barebox_entry(boarddata)
void imx_esdctl_disable(void);
+resource_size_t imx6_get_mmdc_sdram_size(void);
resource_size_t imx8m_barebox_earlymem_size(unsigned buswidth);
resource_size_t imx9_ddrc_sdram_size(void);
#endif
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 06/14] ARM: i.MX: add config symbol for TZASC
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (4 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 05/14] ARM: i.MX6Q: add imx6_get_mmdc_sdram_size Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 07/14] ARM: mach-imx: tzasc: add region configure helpers Sascha Hauer
` (8 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX
So far we build tzasc.c by default on i.MX8M. We need this only when
CONFIG_PBL_OPTEE is enabled though, so add a config symbol for the TZASC
and let it depend on PBL_OPTEE.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-imx/Kconfig | 5 +++++
arch/arm/mach-imx/Makefile | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 02b9fb4dac9f6fa1f4b64799a17a7c642dc96ed7..34c8a077d32d0b87d0b804fd36c6a1693f0071a9 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -46,6 +46,11 @@ config ARCH_IMX_SCRATCHMEM
def_bool y
depends on ARCH_IMX8M || ARCH_IMX9
+config ARCH_IMX_TZASC
+ bool
+ depends on ARCH_IMX8M
+ default y if PBL_OPTEE
+
#
# PMIC configuration found on i.MX51 Babbadge board
#
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 23f51fc660197c2da923697e0c303eec8c85e2b4..f81fa18e9214d7c3b60d04454bfb73eda0a6b5f4 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -21,7 +21,7 @@ obj-pbl-$(CONFIG_ARCH_IMX8M) += imx8m.o
obj-pbl-$(CONFIG_ARCH_IMX_SCRATCHMEM) += scratch.o
obj-$(CONFIG_ARCH_IMX9) += imx9.o imx-v3-image.o
lwl-$(CONFIG_ARCH_IMX_ATF) += atf.o
-obj-pbl-$(CONFIG_ARCH_IMX8M) += tzasc.o
+obj-pbl-$(CONFIG_ARCH_IMX_TZASC) += tzasc.o
obj-pbl-$(CONFIG_ARCH_IMX_ROMAPI) += romapi.o
obj-$(CONFIG_IMX_IIM) += iim.o
obj-$(CONFIG_NAND_IMX) += nand.o
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 07/14] ARM: mach-imx: tzasc: add region configure helpers
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (5 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 06/14] ARM: i.MX: add config symbol for TZASC Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 08/14] ARM: mach-imx: tzasc: add imx6[q|ul]_tzc380_early_ns_region1() Sascha Hauer
` (7 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Marco Felsch
From: Marco Felsch <m.felsch@pengutronix.de>
At the moment the TZC380 driver is very limited and focused on minimal
platform setup unlike the TZC400 driver.
This commit adds helper functions to setup any number of TZASC regions
of any size which is required by later commits to setup an early
non-secure TZASC region1.
The code is based on the TZC400 barebox driver and the TZC380 OP-TEE
driver.
Acked-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-imx/tzasc.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 236 insertions(+)
diff --git a/arch/arm/mach-imx/tzasc.c b/arch/arm/mach-imx/tzasc.c
index 4cb4d7c5cffc17dc56e77124df2b2df0ed67251c..2a48f841af49d3f14bc017950d2553f7f52b7416 100644
--- a/arch/arm/mach-imx/tzasc.c
+++ b/arch/arm/mach-imx/tzasc.c
@@ -1,11 +1,76 @@
// SPDX-License-Identifier: GPL-2.0-only
+#define pr_fmt(fmt) "tzc380: " fmt
+
+#include <common.h>
#include <mach/imx/generic.h>
#include <mach/imx/tzasc.h>
+#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/log2.h>
+#include <linux/sizes.h>
#include <mach/imx/imx8m-regs.h>
#include <io.h>
+/*******************************************************************************
+ * TZC380 defines
+ ******************************************************************************/
+
+#define TZC380_BUILD_CONFIG 0x000
+#define TZC380_BUILD_CONFIG_AW GENMASK(13, 8)
+#define TZC380_BUILD_CONFIG_NR GENMASK(4, 0)
+
+/*
+ * All TZC region configuration registers are placed one after another. It
+ * depicts size of block of registers for programming each region.
+ */
+#define TZC380_REGION_REG_SIZE 0x10
+
+#define TZC380_REGION_SETUP_LOW_0 0x100
+#define TZC380_REGION_SETUP_HIGH_0 0x104
+#define TZC380_REGION_ATTR_0 0x108
+#define TZC380_REGION_SP GENMASK(31, 28)
+#define TZC380_SUBREGION_DIS_MASK GENMASK(15, 8)
+#define TZC380_REGION_SIZE GENMASK(6, 1)
+#define TZC380_REGION_EN BIT(0)
+
+/* ID Registers */
+#define TZC380_PID0_OFF 0xfe0
+#define TZC380_PID1_OFF 0xfe4
+#define TZC380_PERIPHERAL_ID 0x380
+#define TZC380_PID2_OFF 0xfe8
+#define TZC380_PID3_OFF 0xfec
+#define TZC380_PID4_OFF 0xfd0
+#define TZC380_CID0_OFF 0xff0
+#define TZC380_CID1_OFF 0xff4
+#define TZC380_CID2_OFF 0xff8
+
+#define TZC380_REGION_OFFSET(region_no) \
+ (TZC380_REGION_REG_SIZE * (region_no))
+#define TZC380_REGION_SETUP_LOW(region_no) \
+ (TZC380_REGION_OFFSET(region_no) + TZC380_REGION_SETUP_LOW_0)
+#define TZC380_REGION_SETUP_HIGH(region_no) \
+ (TZC380_REGION_OFFSET(region_no) + TZC380_REGION_SETUP_HIGH_0)
+#define TZC380_REGION_ATTR(region_no) \
+ (TZC380_REGION_OFFSET(region_no) + TZC380_REGION_ATTR_0)
+
+#define TZC380_REGION_SP_NS_W FIELD_PREP(TZC380_REGION_SP, BIT(0))
+#define TZC380_REGION_SP_NS_R FIELD_PREP(TZC380_REGION_SP, BIT(1))
+#define TZC380_REGION_SP_S_W FIELD_PREP(TZC380_REGION_SP, BIT(2))
+#define TZC380_REGION_SP_S_R FIELD_PREP(TZC380_REGION_SP, BIT(3))
+
+#define TZC380_REGION_SP_ALL \
+ (TZC380_REGION_SP_NS_W | TZC380_REGION_SP_NS_R | \
+ TZC380_REGION_SP_S_W | TZC380_REGION_SP_S_R)
+#define TZC380_REGION_SP_S_RW \
+ (TZC380_REGION_SP_S_W | TZC380_REGION_SP_S_R)
+#define TZC380_REGION_SP_NS_RW \
+ (TZC380_REGION_SP_NS_W | TZC380_REGION_SP_NS_R)
+
+/*******************************************************************************
+ * SoC specific defines
+ ******************************************************************************/
+
#define GPR_TZASC_EN BIT(0)
#define GPR_TZASC_ID_SWAP_BYPASS BIT(1)
#define GPR_TZASC_EN_LOCK BIT(16)
@@ -14,6 +79,177 @@
#define MX8M_TZASC_REGION_ATTRIBUTES_0 (MX8M_TZASC_BASE_ADDR + 0x108)
#define MX8M_TZASC_REGION_ATTRIBUTES_0_SP GENMASK(31, 28)
+/*
+ * Implementation defined values used to validate inputs later.
+ * Filters : max of 4 ; 0 to 3
+ * Regions : max of 9 ; 0 to 8
+ * Address width : Values between 32 to 64
+ */
+struct tzc380_instance {
+ void __iomem *base;
+ uint8_t addr_width;
+ uint8_t num_regions;
+};
+
+/* Some platforms like i.MX6 does have two tzc380 controllers */
+static struct tzc380_instance tzc380_inst[2];
+
+static inline unsigned int tzc_read_peripheral_id(void __iomem *base)
+{
+ unsigned int id;
+
+ id = in_le32(base + TZC380_PID0_OFF);
+ /* Masks DESC part in PID1 */
+ id |= ((in_le32(base + TZC380_PID1_OFF) & 0xFU) << 8U);
+
+ return id;
+}
+
+static struct tzc380_instance *tzc380_init(void __iomem *base)
+{
+ struct tzc380_instance *tzc380 = &tzc380_inst[0];
+ unsigned int tzc380_id;
+ unsigned int tzc380_build;
+
+ if (tzc380->base)
+ tzc380 = &tzc380_inst[1];
+
+ if (tzc380->base)
+ panic("TZC-380: No free memory\n");
+
+ tzc380->base = base;
+
+ tzc380_id = tzc_read_peripheral_id(base);
+ if (tzc380_id != TZC380_PERIPHERAL_ID)
+ panic("TZC-380 : Wrong device ID (0x%x).\n", tzc380_id);
+
+ /* Save values we will use later. */
+ tzc380_build = in_le32(base + TZC380_BUILD_CONFIG);
+ tzc380->addr_width = FIELD_GET(TZC380_BUILD_CONFIG_AW, tzc380_build) + 1;
+ tzc380->num_regions = FIELD_GET(TZC380_BUILD_CONFIG_NR, tzc380_build) + 1;
+
+ return tzc380;
+}
+
+static void
+tzc380_configure_region(struct tzc380_instance *tzc380, unsigned int region,
+ uint64_t region_base, unsigned int region_attr)
+{
+ void __iomem *base = tzc380->base;
+
+ /* Do range checks on regions */
+ ASSERT((region < tzc380->num_regions));
+
+ pr_debug("Configuring region %u\n", region);
+ pr_debug("... base = %#llx\n", region_base);
+ pr_debug("... sp = %#x\n",
+ (unsigned int)FIELD_GET(TZC380_REGION_SP, region_attr));
+ pr_debug("... subregion dis-mask = %#x\n",
+ (unsigned int)FIELD_GET(TZC380_SUBREGION_DIS_MASK, region_attr));
+ pr_debug("... size = %#x\n",
+ (unsigned int)FIELD_GET(TZC380_REGION_SIZE, region_attr));
+ pr_debug("... enable = %#x\n",
+ (unsigned int)FIELD_GET(TZC380_REGION_EN, region_attr));
+
+ /***************************************************/
+ /* Inputs look ok, start programming registers. */
+ /* The address registers are 32 bits wide and */
+ /* have a LOW and HIGH */
+ /* component used to construct an address up to a */
+ /* 64bit. */
+ /***************************************************/
+ out_le32(base + TZC380_REGION_SETUP_LOW(region), (uint32_t)region_base);
+ out_le32(base + TZC380_REGION_SETUP_HIGH(region), (uint32_t)(region_base >> 32));
+
+ /* Set region attributes */
+ out_le32(base + TZC380_REGION_ATTR(region), region_attr);
+}
+
+static int
+tzc380_auto_configure(struct tzc380_instance *tzc380, unsigned int region,
+ uint64_t base, uint64_t size,
+ unsigned int attr)
+{
+ uint64_t sub_region_size = 0;
+ uint64_t area = 0;
+ uint8_t lregion = region;
+ uint64_t region_size = 0;
+ uint64_t sub_address = 0;
+ uint64_t address = base;
+ uint64_t lsize = size;
+ unsigned int lattr;
+ uint32_t mask = 0;
+ uint64_t reminder;
+ int i = 0;
+ uint8_t pow = 0;
+
+ ASSERT(tzc380->base);
+
+ /*
+ * TZC380 RM
+ * For region_attributes_<n> registers, region_size:
+ * Note: The AXI address width, that is AXI_ADDRESS_MSB+1, controls the
+ * upper limit value of the field.
+ */
+ pow = tzc380->addr_width;
+
+ while (lsize != 0 && pow >= 15) {
+ region_size = 1ULL << pow;
+
+ /* Case region fits alignment and covers requested area */
+ if ((address % region_size == 0) &&
+ ((address + lsize) % region_size == 0)) {
+ lattr = attr;
+ lattr |= FIELD_PREP(TZC380_REGION_SIZE, (pow - 1));
+ lattr |= TZC380_REGION_EN;
+
+ tzc380_configure_region(tzc380, lregion, address, lattr);
+
+ lregion++;
+ address += region_size;
+ lsize -= region_size;
+ pow = tzc380->addr_width;
+ continue;
+ }
+
+ /* Cover area using several subregions */
+ sub_region_size = div_u64(region_size, 8);
+ div64_u64_rem(address, sub_region_size, &reminder);
+ if (reminder == 0 && lsize > 2 * sub_region_size) {
+ sub_address = div64_u64(address, region_size) * region_size;
+ mask = 0;
+ for (i = 0; i < 8; i++) {
+ area = (i + 1) * sub_region_size;
+ if (sub_address + area <= address ||
+ sub_address + area > address + lsize) {
+ mask |= FIELD_PREP(TZC380_SUBREGION_DIS_MASK, BIT(i));
+ } else {
+ address += sub_region_size;
+ lsize -= sub_region_size;
+ }
+ }
+
+ lattr = mask | attr;
+ lattr |= FIELD_PREP(TZC380_REGION_SIZE, (pow - 1));
+ lattr |= TZC380_REGION_EN;
+
+ tzc380_configure_region(tzc380, lregion, sub_address, lattr);
+
+ lregion++;
+ pow = tzc380->addr_width;
+ continue;
+ }
+ pow--;
+ }
+ ASSERT(lsize == 0);
+ ASSERT(address == base + size);
+ return lregion;
+}
+
+/******************************************************************************
+ * SoC specific helpers
+ ******************************************************************************/
+
void imx8m_tzc380_init(void)
{
u32 __iomem *gpr = IOMEM(MX8M_IOMUXC_GPR_BASE_ADDR);
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 08/14] ARM: mach-imx: tzasc: add imx6[q|ul]_tzc380_early_ns_region1()
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (6 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 07/14] ARM: mach-imx: tzasc: add region configure helpers Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 09/14] ARM: mach-imx: tzasc: add imx6[q|ul]_tzc380_is_bypassed() Sascha Hauer
` (6 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Marco Felsch
Add a helper function which can be used by the board code to setup an
early non-secure TZASC region1 which covers the whole SDRAM size.
This eliminates the current workaround of configuring region0 as
non-secure/secure region.
tzasc.c can now be used for i.MX6 as well, so expand ARCH_IMX_TZASC
accordingly.
Acked-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-imx/Kconfig | 2 +-
arch/arm/mach-imx/tzasc.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++
include/mach/imx/tzasc.h | 2 ++
3 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 34c8a077d32d0b87d0b804fd36c6a1693f0071a9..bb6bad169831b03879527ef9f676ff99b955a6fd 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -48,7 +48,7 @@ config ARCH_IMX_SCRATCHMEM
config ARCH_IMX_TZASC
bool
- depends on ARCH_IMX8M
+ depends on ARCH_IMX6 || ARCH_IMX8M
default y if PBL_OPTEE
#
diff --git a/arch/arm/mach-imx/tzasc.c b/arch/arm/mach-imx/tzasc.c
index 2a48f841af49d3f14bc017950d2553f7f52b7416..169c4b9801e5fdd01edd3c5661418a945cf21c55 100644
--- a/arch/arm/mach-imx/tzasc.c
+++ b/arch/arm/mach-imx/tzasc.c
@@ -3,8 +3,10 @@
#define pr_fmt(fmt) "tzc380: " fmt
#include <common.h>
+#include <mach/imx/esdctl.h>
#include <mach/imx/generic.h>
#include <mach/imx/tzasc.h>
+#include <mach/imx/imx6-regs.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/log2.h>
@@ -71,6 +73,9 @@
* SoC specific defines
******************************************************************************/
+#define MX6_TZASC1_BASE 0x21d0000
+#define MX6_TZASC2_BASE 0x21d4000
+
#define GPR_TZASC_EN BIT(0)
#define GPR_TZASC_ID_SWAP_BYPASS BIT(1)
#define GPR_TZASC_EN_LOCK BIT(16)
@@ -250,6 +255,54 @@ tzc380_auto_configure(struct tzc380_instance *tzc380, unsigned int region,
* SoC specific helpers
******************************************************************************/
+static void imx_tzc380_init_and_setup(void __iomem *base, unsigned int region,
+ resource_size_t region_base,
+ resource_size_t region_size,
+ unsigned int region_attr)
+{
+ struct tzc380_instance *tzasc = tzc380_init(base);
+
+ tzc380_auto_configure(tzasc, region, region_base, region_size,
+ region_attr);
+}
+
+/*
+ * imx6q_tzc380_early_ns_region1 - configure the whole DRAM as non-secure
+ * region1
+ *
+ * Passing data between TEE and barebox need to follow some requirements:
+ * - the location can be accessed by the normal and secure world
+ * - the mapping in the normal and secure world must be the same to avoid
+ * manual cache maintenance.
+ *
+ * Therefore this function reads the DRAM size out of the MMDC controller and
+ * configures the whole size as non-secure TZC380 region1. This allows the
+ * early TEE code to map the location as non-secure to while writing the data
+ * e.g. device-tee-overlays. Later on the TEE may reconfigure and lock the
+ * TZC380 regions. The reconfiguration needs to ensure that the exchange data
+ * location is still accessible by the normal world.
+ */
+void imx6q_tzc380_early_ns_region1(void)
+{
+ resource_size_t ram_sz = imx6_get_mmdc_sdram_size();
+
+ imx_tzc380_init_and_setup(IOMEM(MX6_TZASC1_BASE), 1,
+ MX6_MMDC_PORT01_BASE_ADDR, ram_sz,
+ TZC380_REGION_SP_NS_RW);
+ imx_tzc380_init_and_setup(IOMEM(MX6_TZASC2_BASE), 1,
+ MX6_MMDC_PORT01_BASE_ADDR, ram_sz,
+ TZC380_REGION_SP_NS_RW);
+}
+
+void imx6ul_tzc380_early_ns_region1(void)
+{
+ resource_size_t ram_sz = imx6_get_mmdc_sdram_size();
+
+ imx_tzc380_init_and_setup(IOMEM(MX6_TZASC1_BASE), 1,
+ MX6_MMDC_PORT0_BASE_ADDR, ram_sz,
+ TZC380_REGION_SP_NS_RW);
+}
+
void imx8m_tzc380_init(void)
{
u32 __iomem *gpr = IOMEM(MX8M_IOMUXC_GPR_BASE_ADDR);
diff --git a/include/mach/imx/tzasc.h b/include/mach/imx/tzasc.h
index 51c86f168ee41db8659c0ad5f48ca1f102cb76d3..eb479ad55c9c101a5fb47fc4a7178b3669b9e44f 100644
--- a/include/mach/imx/tzasc.h
+++ b/include/mach/imx/tzasc.h
@@ -6,6 +6,8 @@
#include <linux/types.h>
#include <asm/system.h>
+void imx6q_tzc380_early_ns_region1(void);
+void imx6ul_tzc380_early_ns_region1(void);
void imx8m_tzc380_init(void);
bool imx8m_tzc380_is_enabled(void);
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 09/14] ARM: mach-imx: tzasc: add imx6[q|ul]_tzc380_is_bypassed()
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (7 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 08/14] ARM: mach-imx: tzasc: add imx6[q|ul]_tzc380_early_ns_region1() Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 10/14] ARM: i.MX: add imx6_can_access_tzasc() Sascha Hauer
` (5 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Marco Felsch
From: Marco Felsch <m.felsch@pengutronix.de>
The TZASC_BYP bits default to not bypass DDR transactions from the
TZASC. These bits must be set while the DDR controller is inactive, so
when the DDR controller is initialized in the DCD table and barebox is
directly loaded and startes in DDR we must set the bits in the DCD.
As this is board specific it's easy to forget this setting and the whole
DDR is accessible by the normal world regardless of the TZASC
configuration. This patch adds a check if the bits have been set
correctly so that we can warn the user if necessary.
Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-imx/tzasc.c | 26 ++++++++++++++++++++++++++
include/mach/imx/tzasc.h | 2 ++
2 files changed, 28 insertions(+)
diff --git a/arch/arm/mach-imx/tzasc.c b/arch/arm/mach-imx/tzasc.c
index 169c4b9801e5fdd01edd3c5661418a945cf21c55..ed20ad8803a2e91b67b5d8c3ab1a4265c4228ec7 100644
--- a/arch/arm/mach-imx/tzasc.c
+++ b/arch/arm/mach-imx/tzasc.c
@@ -76,6 +76,9 @@
#define MX6_TZASC1_BASE 0x21d0000
#define MX6_TZASC2_BASE 0x21d4000
+#define MX6_GPR_TZASC1_EN BIT(0)
+#define MX6_GPR_TZASC2_EN BIT(1)
+
#define GPR_TZASC_EN BIT(0)
#define GPR_TZASC_ID_SWAP_BYPASS BIT(1)
#define GPR_TZASC_EN_LOCK BIT(16)
@@ -303,6 +306,29 @@ void imx6ul_tzc380_early_ns_region1(void)
TZC380_REGION_SP_NS_RW);
}
+bool imx6q_tzc380_is_bypassed(void)
+{
+ u32 __iomem *gpr = IOMEM(MX6_IOMUXC_BASE_ADDR);
+
+ /*
+ * MX6_GPR_TZASC1_EN and MX6_GPR_TZASC2_EN are sticky bits which
+ * preserve their values once set until the next power-up cycle.
+ */
+ return (readl(&gpr[9]) & (MX6_GPR_TZASC1_EN | MX6_GPR_TZASC2_EN)) !=
+ (MX6_GPR_TZASC1_EN | MX6_GPR_TZASC2_EN);
+}
+
+bool imx6ul_tzc380_is_bypassed(void)
+{
+ u32 __iomem *gpr = IOMEM(MX6_IOMUXC_BASE_ADDR + 0x4000);
+
+ /*
+ * MX6_GPR_TZASC1_EN is a sticky bit which preserves its value
+ * once set until the next power-up cycle.
+ */
+ return !(readl(&gpr[9]) & MX6_GPR_TZASC1_EN);
+}
+
void imx8m_tzc380_init(void)
{
u32 __iomem *gpr = IOMEM(MX8M_IOMUXC_GPR_BASE_ADDR);
diff --git a/include/mach/imx/tzasc.h b/include/mach/imx/tzasc.h
index eb479ad55c9c101a5fb47fc4a7178b3669b9e44f..0fbcdc2150e63864366a8dddeed2d1b97685903d 100644
--- a/include/mach/imx/tzasc.h
+++ b/include/mach/imx/tzasc.h
@@ -8,6 +8,8 @@
void imx6q_tzc380_early_ns_region1(void);
void imx6ul_tzc380_early_ns_region1(void);
+bool imx6q_tzc380_is_bypassed(void);
+bool imx6ul_tzc380_is_bypassed(void);
void imx8m_tzc380_init(void);
bool imx8m_tzc380_is_enabled(void);
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 10/14] ARM: i.MX: add imx6_can_access_tzasc()
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (8 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 09/14] ARM: mach-imx: tzasc: add imx6[q|ul]_tzc380_is_bypassed() Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 11/14] ARM: optee-early: add mx6_start_optee_early helper Sascha Hauer
` (4 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX
On ARMv7 there is no direct way to detect if we are in the secure or non
secure world. Add a imx6_can_access_tzasc() for this purpose. When
accessing the TZASC triggers a data abort then we are in the non secure
world, because OP-TEE configures the CSU to forbid accesses to the TZASC
from the normal world. This function can be used later to detect if we
have to load OP-TEE or not.
We'll need CONFIG_ARM_EXCEPTIONS_PBL for this functionality, so select
this symbol in Kconfig.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-imx/Kconfig | 1 +
arch/arm/mach-imx/tzasc.c | 13 +++++++++++++
include/mach/imx/tzasc.h | 1 +
3 files changed, 15 insertions(+)
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index bb6bad169831b03879527ef9f676ff99b955a6fd..38ef55727678855591bf41cecca76947434381e8 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -50,6 +50,7 @@ config ARCH_IMX_TZASC
bool
depends on ARCH_IMX6 || ARCH_IMX8M
default y if PBL_OPTEE
+ select ARM_EXCEPTIONS_PBL
#
# PMIC configuration found on i.MX51 Babbadge board
diff --git a/arch/arm/mach-imx/tzasc.c b/arch/arm/mach-imx/tzasc.c
index ed20ad8803a2e91b67b5d8c3ab1a4265c4228ec7..0fe7f6eb7f4ac67b6db63ee78b5fc867d17df9cc 100644
--- a/arch/arm/mach-imx/tzasc.c
+++ b/arch/arm/mach-imx/tzasc.c
@@ -13,6 +13,8 @@
#include <linux/sizes.h>
#include <mach/imx/imx8m-regs.h>
#include <io.h>
+#include <abort.h>
+#include <asm/barebox-arm.h>
/*******************************************************************************
* TZC380 defines
@@ -329,6 +331,17 @@ bool imx6ul_tzc380_is_bypassed(void)
return !(readl(&gpr[9]) & MX6_GPR_TZASC1_EN);
}
+bool imx6_can_access_tzasc(void)
+{
+ arm_pbl_init_exceptions();
+
+ data_abort_mask();
+
+ readl(IOMEM(MX6_TZASC1_BASE));
+
+ return !data_abort_unmask();
+}
+
void imx8m_tzc380_init(void)
{
u32 __iomem *gpr = IOMEM(MX8M_IOMUXC_GPR_BASE_ADDR);
diff --git a/include/mach/imx/tzasc.h b/include/mach/imx/tzasc.h
index 0fbcdc2150e63864366a8dddeed2d1b97685903d..ca85704a8f459ab6e0cdc975940d855929f3d6f7 100644
--- a/include/mach/imx/tzasc.h
+++ b/include/mach/imx/tzasc.h
@@ -10,6 +10,7 @@ void imx6q_tzc380_early_ns_region1(void);
void imx6ul_tzc380_early_ns_region1(void);
bool imx6q_tzc380_is_bypassed(void);
bool imx6ul_tzc380_is_bypassed(void);
+bool imx6_can_access_tzasc(void);
void imx8m_tzc380_init(void);
bool imx8m_tzc380_is_enabled(void);
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 11/14] ARM: optee-early: add mx6_start_optee_early helper
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (9 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 10/14] ARM: i.MX: add imx6_can_access_tzasc() Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 12/14] ARM: i.MX: tqma6ulx: fix barebox chainloading with OP-TEE enabled Sascha Hauer
` (3 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX; +Cc: Marco Felsch
From: Marco Felsch <m.felsch@pengutronix.de>
Add a i.MX6 specific helper function which covers most of the steps
usually done within the board lowlevel code. All new i.MX6 boards are
encouraged to use this helper to load OP-TEE since the helper validates
that the TZC380 is enabled and setup the TZC380 region properly.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Documentation/user/optee.rst | 22 +++++++++++++++-------
arch/arm/lib32/optee-early.c | 42 ++++++++++++++++++++++++++++++++++++++++++
include/tee/optee.h | 4 ++++
3 files changed, 61 insertions(+), 7 deletions(-)
diff --git a/Documentation/user/optee.rst b/Documentation/user/optee.rst
index 2729d21d2e441c8c9ba8171544ace8f516ceefdf..88e651ddec57b50f1013aafdd8d72b8a73032740 100644
--- a/Documentation/user/optee.rst
+++ b/Documentation/user/optee.rst
@@ -19,14 +19,22 @@ During the PBL
^^^^^^^^^^^^^^
To start OP-TEE during the lowlevel initialization of your board in the ``PBL``,
-enable the ``CONFIG_PBL_OPTEE`` configuration variable. your board should then
+enable the ``CONFIG_PBL_OPTEE`` configuration variable. Your board should then
call the function ``start_optee_early(void* tee, void* fdt)`` with a valid tee
-and FDT. Ensure that your OP-TEE is compiled with ``CFG_NS_ENTRY_ADDR`` unset,
-otherwise OP-TEE will not correctly return to barebox after startup.
-Since OP-TEE in the default configuration also modifies the device tree, don't
-pass the barebox internal device tree, instead copy it into a different memory
-location and pass it to OP-TEE afterwards.
-The modified device tree can then be passed to the main barebox start function.
+and FDT. If you're running on an i.MX6 platform your board code should call
+``imx6q_start_optee_early()`` or ``imx6ul_start_optee_early()`` instead since it
+validates that the TZASC not bypassed and is configured as expected by OP-TEE.
+
+Ensure that your OP-TEE is compiled with ``CFG_NS_ENTRY_ADDR`` unset, otherwise
+OP-TEE will not correctly return to barebox after startup. Since OP-TEE in the
+default configuration also modifies the device tree, don't pass the barebox
+internal device tree, instead copy it into a different memory location and pass
+it to OP-TEE afterwards. The modified device tree can then be passed to the
+main barebox start function.
+
+.. note:: Modification of the device tree usually makes it bigger.
+ Some spare space must be left after the end of the device tree to
+ accommodate this.
Before Linux start
^^^^^^^^^^^^^^^^^^
diff --git a/arch/arm/lib32/optee-early.c b/arch/arm/lib32/optee-early.c
index c9959b5e41b88a1b91179546bc6e0239809cfb11..ab5d581aa6b6835e8e551762d0b2ce1ffa2b75c4 100644
--- a/arch/arm/lib32/optee-early.c
+++ b/arch/arm/lib32/optee-early.c
@@ -12,6 +12,8 @@
#include <linux/bug.h>
#include <debug_ll.h>
#include <string.h>
+#include <mach/imx/imx6.h>
+#include <mach/imx/tzasc.h>
static jmp_buf tee_buf;
@@ -41,3 +43,43 @@ int start_optee_early(void *fdt, void *tee)
return 0;
}
+
+int imx6q_start_optee_early(void *fdt, void *tee, void *data_location,
+ unsigned int data_location_size)
+{
+ if (imx6q_tzc380_is_bypassed())
+ panic("TZC380 is bypassed, abort OP-TEE loading\n");
+
+ /* Add early non-secure TZASC region1 to pass DTO */
+ imx6q_tzc380_early_ns_region1();
+
+ /*
+ * Set the OP-TEE <-> barebox exchange data location to zero.
+ * This is optional since recent OP-TEE versions perform the
+ * memset too.
+ */
+ if (data_location)
+ memset(data_location, 0, data_location_size);
+
+ return start_optee_early(fdt, tee);
+}
+
+int imx6ul_start_optee_early(void *fdt, void *tee, void *data_location,
+ unsigned int data_location_size)
+{
+ if (imx6ul_tzc380_is_bypassed())
+ panic("TZC380 is bypassed, abort OP-TEE loading\n");
+
+ /* Add early non-secure TZASC region1 to pass DTO */
+ imx6ul_tzc380_early_ns_region1();
+
+ /*
+ * Set the OP-TEE <-> barebox exchange data location to zero.
+ * This is optional since recent OP-TEE versions perform the
+ * memset too.
+ */
+ if (data_location)
+ memset(data_location, 0, data_location_size);
+
+ return start_optee_early(fdt, tee);
+}
diff --git a/include/tee/optee.h b/include/tee/optee.h
index f52775dab5b40f306075bc2d302938c584a6f5ec..943dbb8fdab6a11e25fb27e3487fe6fdec59a182 100644
--- a/include/tee/optee.h
+++ b/include/tee/optee.h
@@ -54,6 +54,10 @@ static inline int optee_get_membase(u64 *membase)
#ifdef __PBL__
int start_optee_early(void* fdt, void* tee);
+int imx6q_start_optee_early(void *fdt, void *tee, void *data_location,
+ unsigned int data_location_size);
+int imx6ul_start_optee_early(void *fdt, void *tee, void *data_location,
+ unsigned int data_location_size);
#endif /* __PBL__ */
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 12/14] ARM: i.MX: tqma6ulx: fix barebox chainloading with OP-TEE enabled
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (10 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 11/14] ARM: optee-early: add mx6_start_optee_early helper Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 13/14] ARM: i.MX: Webasto ccbv2: " Sascha Hauer
` (2 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum, Marco Felsch
When barebox starts we have to guess if we have to start OP-TEE or not.
The current detection works by checking if the first stage passed us a
device tree pointer. This is not robust and might have security issues
[1], so replace that with the check with imx6_can_access_tzasc(). If we
can access the TZASC then we are the first stage and configure it and
start OP-TEE, otherwise assume that we are chainloaded and continue
without starting OP-TEE.
Chainloading barebox with OP-TEE enabled contained several bugs, so it
never actually worked. This patch fixes them.
[1] https://lore.kernel.org/70b41f3b-4329-48f7-827f-1924e002ab04@pengutronix.de
Reviewed-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/boards/tqma6ulx/lowlevel.c | 22 +++++++++-------------
1 file changed, 9 insertions(+), 13 deletions(-)
diff --git a/arch/arm/boards/tqma6ulx/lowlevel.c b/arch/arm/boards/tqma6ulx/lowlevel.c
index 5fd997d2ec7e79c7319237a4ae52216e584ba5cd..da67e67537167096477de2b905ee5c42c653c3af 100644
--- a/arch/arm/boards/tqma6ulx/lowlevel.c
+++ b/arch/arm/boards/tqma6ulx/lowlevel.c
@@ -16,6 +16,8 @@
#include <pbl/i2c.h>
#include <boards/tq/tq_eeprom.h>
#include <tee/optee.h>
+#include <mach/imx/tzasc.h>
+#include <tee/optee.h>
#include "tqma6ulx.h"
@@ -66,7 +68,7 @@ static void *read_eeprom(void)
return fdt;
}
-static void noinline start_mba6ulx(u32 r0)
+static void noinline start_mba6ulx(void)
{
void *fdt;
int tee_size;
@@ -76,21 +78,15 @@ static void noinline start_mba6ulx(u32 r0)
fdt = read_eeprom();
- /* Enable normal/secure r/w for TZC380 region0 */
- writel(0xf0000000, 0x021D0108);
-
/*
- * Chainloading barebox will pass a device tree within the RAM in r0,
- * skip OP-TEE early loading in this case
+ * Skip loading barebox when we are chainloaded. We can detect that by detecting
+ * if we can access the TZASC.
*/
- if (IS_ENABLED(CONFIG_FIRMWARE_TQMA6UL_OPTEE) &&
- !(r0 > MX6_MMDC_P0_BASE_ADDR &&
- r0 < MX6_MMDC_P0_BASE_ADDR + SZ_256M)) {
- get_builtin_firmware(mba6ul_optee_bin, &tee, &tee_size);
+ if (IS_ENABLED(CONFIG_FIRMWARE_TQMA6UL_OPTEE) && imx6_can_access_tzasc()) {
- memset((void *)OPTEE_OVERLAY_LOCATION, 0, 0x1000);
+ get_builtin_firmware(mba6ul_optee_bin, &tee, &tee_size);
- start_optee_early(NULL, tee);
+ imx6ul_start_optee_early(NULL, tee, (void *)OPTEE_OVERLAY_LOCATION, 0x1000);
}
imx6ul_barebox_entry(fdt);
@@ -112,5 +108,5 @@ ENTRY_FUNCTION(start_imx6ul_mba6ulx, r0, r1, r2)
setup_c();
barrier();
- start_mba6ulx(r0);
+ start_mba6ulx();
}
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 13/14] ARM: i.MX: Webasto ccbv2: fix barebox chainloading with OP-TEE enabled
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (11 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 12/14] ARM: i.MX: tqma6ulx: fix barebox chainloading with OP-TEE enabled Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-06-30 7:45 ` [PATCH v2 14/14] ARM: i.MX: tqma6ulx: use ENTRY_FUNCTION_WITHSTACK Sascha Hauer
2025-07-02 6:13 ` [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
When barebox starts we have to guess if we have to start OP-TEE or not.
The current detection works by checking if the first stage passed us a
device tree pointer. This is not robust and might have security issues
[1], so replace that with the check with imx6_can_access_tzasc(). If we
can access the TZASC then we are the first stage and configure it and
start OP-TEE, otherwise assume that we are chainloaded and continue
without starting OP-TEE.
Chainloading barebox with OP-TEE enabled contained several bugs, so it
never actually worked. This patch fixes them.
Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/boards/webasto-ccbv2/lowlevel.c | 24 +++++++++---------------
1 file changed, 9 insertions(+), 15 deletions(-)
diff --git a/arch/arm/boards/webasto-ccbv2/lowlevel.c b/arch/arm/boards/webasto-ccbv2/lowlevel.c
index 7a198bd801d41e61e6ab4b3c284948154b61d1ca..c25f8a9cb3ce58742576aa05193f1cf730e2e2c7 100644
--- a/arch/arm/boards/webasto-ccbv2/lowlevel.c
+++ b/arch/arm/boards/webasto-ccbv2/lowlevel.c
@@ -13,6 +13,7 @@
#include <mach/imx/iomux-mx6ul.h>
#include <asm/cache.h>
#include <tee/optee.h>
+#include <mach/imx/tzasc.h>
#include "ccbv2.h"
@@ -31,28 +32,21 @@ static void configure_uart(void)
}
-static void noinline start_ccbv2(u32 r0, unsigned long mem_size, char *fdt)
+static void noinline start_ccbv2(unsigned long mem_size, char *fdt)
{
int tee_size;
void *tee;
- /* Enable normal/secure r/w for TZC380 region0 */
- writel(0xf0000000, 0x021D0108);
-
configure_uart();
/*
- * Chainloading barebox will pass a device tree within the RAM in r0,
- * skip OP-TEE early loading in this case
+ * Skip loading barebox when we are chainloaded. We can detect that by detecting
+ * if we can access the TZASC.
*/
- if(IS_ENABLED(CONFIG_FIRMWARE_CCBV2_OPTEE)
- && !(r0 > MX6_MMDC_P0_BASE_ADDR
- && r0 < MX6_MMDC_P0_BASE_ADDR + mem_size)) {
+ if (IS_ENABLED(CONFIG_FIRMWARE_TQMA6UL_OPTEE) && imx6_can_access_tzasc()) {
get_builtin_firmware(ccbv2_optee_bin, &tee, &tee_size);
- memset((void *)OPTEE_OVERLAY_LOCATION, 0, 0x1000);
-
- start_optee_early(NULL, tee);
+ imx6ul_start_optee_early(NULL, tee, (void *)OPTEE_OVERLAY_LOCATION, 0x1000);
}
imx6ul_barebox_entry(fdt);
@@ -70,7 +64,7 @@ ENTRY_FUNCTION(start_imx6ul_ccbv2_256m, r0, r1, r2)
setup_c();
barrier();
- start_ccbv2(r0, SZ_256M, __dtb_z_imx6ul_webasto_ccbv2_start);
+ start_ccbv2(SZ_256M, __dtb_z_imx6ul_webasto_ccbv2_start);
}
ENTRY_FUNCTION(start_imx6ul_ccbv2_512m, r0, r1, r2)
@@ -83,7 +77,7 @@ ENTRY_FUNCTION(start_imx6ul_ccbv2_512m, r0, r1, r2)
setup_c();
barrier();
- start_ccbv2(r0, SZ_512M, __dtb_z_imx6ul_webasto_ccbv2_start);
+ start_ccbv2(SZ_512M, __dtb_z_imx6ul_webasto_ccbv2_start);
}
extern char __dtb_z_imx6ul_webasto_marvel_start[];
@@ -97,5 +91,5 @@ ENTRY_FUNCTION(start_imx6ul_marvel, r0, r1, r2)
setup_c();
barrier();
- start_ccbv2(r0, SZ_512M, __dtb_z_imx6ul_webasto_marvel_start);
+ start_ccbv2(SZ_512M, __dtb_z_imx6ul_webasto_marvel_start);
}
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2 14/14] ARM: i.MX: tqma6ulx: use ENTRY_FUNCTION_WITHSTACK
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (12 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 13/14] ARM: i.MX: Webasto ccbv2: " Sascha Hauer
@ 2025-06-30 7:45 ` Sascha Hauer
2025-07-02 6:13 ` [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-06-30 7:45 UTC (permalink / raw)
To: BAREBOX; +Cc: Ahmad Fatoum
The first thing the tqma6ulx lowlevel code does is setting up the stack.
Use ENTRY_FUNCTION_WITHSTACK() which is specifically for this purpose.
Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/boards/tqma6ulx/lowlevel.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/arch/arm/boards/tqma6ulx/lowlevel.c b/arch/arm/boards/tqma6ulx/lowlevel.c
index da67e67537167096477de2b905ee5c42c653c3af..57639f8a84e7680c4ee0608abf31ae8b6f1cfd28 100644
--- a/arch/arm/boards/tqma6ulx/lowlevel.c
+++ b/arch/arm/boards/tqma6ulx/lowlevel.c
@@ -92,13 +92,10 @@ static void noinline start_mba6ulx(void)
imx6ul_barebox_entry(fdt);
}
-ENTRY_FUNCTION(start_imx6ul_mba6ulx, r0, r1, r2)
+ENTRY_FUNCTION_WITHSTACK(start_imx6ul_mba6ulx, 0x00910000, r0, r1, r2)
{
-
imx6ul_cpu_lowlevel_init();
- arm_setup_stack(0x00910000);
-
if (IS_ENABLED(CONFIG_DEBUG_LL)) {
imx6_uart_setup_ll();
putc_ll('>');
--
2.39.5
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers
2025-06-30 7:45 [PATCH v2 00/14] i.MX6 TZASC and OP-TEE early helpers Sascha Hauer
` (13 preceding siblings ...)
2025-06-30 7:45 ` [PATCH v2 14/14] ARM: i.MX: tqma6ulx: use ENTRY_FUNCTION_WITHSTACK Sascha Hauer
@ 2025-07-02 6:13 ` Sascha Hauer
14 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2025-07-02 6:13 UTC (permalink / raw)
To: BAREBOX, Sascha Hauer; +Cc: Ahmad Fatoum, Marco Felsch
On Mon, 30 Jun 2025 09:45:42 +0200, Sascha Hauer wrote:
> This series combines Marcos "i.MX6Q TZASC and OP-TEE early helpers" [1]
> and my series fixing chainloading barebox on OP-TEE enabled i.MX6ul
> platforms [2] into one.
>
> Changes to Marcos series are:
>
> - rename imx6q_tzc380_is_enabled() to imx6q_tzc380_is_bypassed() as the
> function really only detects if the bypass bits are set correctly and
> not if the tzc380 is enabled.
> - Add i.MX6UL variants of the functions Marco created for i.MX6DQ
> - Marco created a mx6_start_optee_early() function that has a
> switch/case for the actual SoC type. I have split that into SoC
> specific functions so that we don't have to carry the binary weight
> when only one specific SoC is needed
>
> [...]
Applied, thanks!
[01/14] pbl: add panic_no_stacktrace()
https://git.pengutronix.de/cgit/barebox/commit/?id=f5fd3cdae3db (link may not be stable)
[02/14] arch: Allow data_abort_mask() in PBL
https://git.pengutronix.de/cgit/barebox/commit/?id=556b99617e63 (link may not be stable)
[03/14] ARM: add exception handling support for PBL
https://git.pengutronix.de/cgit/barebox/commit/?id=f33372b459da (link may not be stable)
[04/14] ARM: i.MX6QDL: add imxcfg helper to configure the TZASC1/2
https://git.pengutronix.de/cgit/barebox/commit/?id=91676c7f402b (link may not be stable)
[05/14] ARM: i.MX6Q: add imx6_get_mmdc_sdram_size
https://git.pengutronix.de/cgit/barebox/commit/?id=b026f6e83284 (link may not be stable)
[06/14] ARM: i.MX: add config symbol for TZASC
https://git.pengutronix.de/cgit/barebox/commit/?id=836d9a5660a6 (link may not be stable)
[07/14] ARM: mach-imx: tzasc: add region configure helpers
https://git.pengutronix.de/cgit/barebox/commit/?id=c1c7be3b9abc (link may not be stable)
[08/14] ARM: mach-imx: tzasc: add imx6[q|ul]_tzc380_early_ns_region1()
https://git.pengutronix.de/cgit/barebox/commit/?id=fe96d6d530c5 (link may not be stable)
[09/14] ARM: mach-imx: tzasc: add imx6[q|ul]_tzc380_is_bypassed()
https://git.pengutronix.de/cgit/barebox/commit/?id=e841bfdaaa61 (link may not be stable)
[10/14] ARM: i.MX: add imx6_can_access_tzasc()
https://git.pengutronix.de/cgit/barebox/commit/?id=0ae719a914f3 (link may not be stable)
[11/14] ARM: optee-early: add mx6_start_optee_early helper
https://git.pengutronix.de/cgit/barebox/commit/?id=5f233de5e090 (link may not be stable)
[12/14] ARM: i.MX: tqma6ulx: fix barebox chainloading with OP-TEE enabled
https://git.pengutronix.de/cgit/barebox/commit/?id=1dcba06ff316 (link may not be stable)
[13/14] ARM: i.MX: Webasto ccbv2: fix barebox chainloading with OP-TEE enabled
https://git.pengutronix.de/cgit/barebox/commit/?id=710fcf4bbdd5 (link may not be stable)
[14/14] ARM: i.MX: tqma6ulx: use ENTRY_FUNCTION_WITHSTACK
https://git.pengutronix.de/cgit/barebox/commit/?id=0935e23f8e10 (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 17+ messages in thread