On 02.03.2018 16:27, Peter Geis wrote:
Good Morning,
I have an OUYA console that I am attempting to get the 4.14 kernel booted on.
It is a Tegra30-Cardhu based system, which from what I can tell had as many
corners cut during development as possible.
I do not have access to the firmware itself, and the firmware does not support
anything beyond 3.1.10, so I am using a kernel appended DTB.
The issue I'm running into right now is I cannot get the layer 2 cache
controller, a PL310, to init correctly.
I can disable the function, and I boot till DMA starts accessing hardware and go
into a hard lock.
If I have the L2C enabled, it kernel panics during L2c310_configure, while
trying to write the secure registers.
I am pretty sure the firmware is not using secure mode at all, and in the
cache-l2x0.c source the function states "By default, we write directly to secure
registers. Platforms must override this if they are running non-secure."
I unfortunately cannot figure out how to override this function.
I would like to keep all or as much as possible any code modification to the
device tree and kernel configuration only.
Is there a way via the device tree to override secure mode?
I have included a full boot log up until the panic.
Hello Peter,
Your device uses fastboot, so it's likely to be proprietary bootloader that
boots kernel under secure monitor. Upstream kernel doesn't support the secured
L2. Michał implemented the support about a half year ago, but the patches
required some rework to get into upstream. Unfortunately seems Michał haven't
had time to address the review comments and send a new version of the patches,
so they are stuck since then.
Michał, are you planning to continue working on the patches? If not, I may try
to refresh them and re-send. (CC'ed Michał)
Below is the summarized diff against linux-next (you may need to do some
backporting to 4.14) that you need to apply to get things working. Also don't
forget to add TF node to your DT:
firmware {
trusted-foundations {
compatible = "tlm,trusted-foundations";
tlm,version-major = <0x2>;
tlm,version-minor = <0x8>;
};
};
If you are going to try a newer kernel, note that it may not work with the
proprietary bootloader without this patch [0].
[0] https://patchwork.ozlabs.org/patch/858304/
Also, if you'll experience some odd memory-controller errors, try to disable
CONFIG_TEGRA_IOMMU_SMMU in the kernel config.
diff --git a/arch/arm/firmware/trusted_foundations.c
b/arch/arm/firmware/trusted_foundations.c
index 3fb1b5a1dce9..44e9cac57e78 100644
--- a/arch/arm/firmware/trusted_foundations.c
+++ b/arch/arm/firmware/trusted_foundations.c
@@ -17,11 +17,19 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h>
+#include <asm/io.h>
#include <asm/firmware.h>
+#include <asm/outercache.h>
+#include <asm/hardware/cache-l2x0.h>
#include <asm/trusted_foundations.h>
+#define TF_CACHE_MAINT 0xfffff100
#define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200
+#define TF_CACHE_INIT 1
+#define TF_CACHE_FLUSH 2
+#define TF_CACHE_REENABLE 4
+
#define TF_CPU_PM 0xfffffffc
#define TF_CPU_PM_S3 0xffffffe3
#define TF_CPU_PM_S2 0xffffffe6
@@ -63,9 +71,48 @@ static int tf_prepare_idle(void)
return 0;
}
+#ifdef CONFIG_CACHE_L2X0
+static void tf_write_sec(unsigned long val, unsigned reg)
+{
+ unsigned long cur = readl_relaxed(l2x0_base + reg);
+
+ pr_warn("TF: ignoring write_sec[0x%x]: 0x%08lx -> 0x%08lx\n",
+ reg, cur, val);
+}
+
+static void tf_disable_cache(void)
+{
+ tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_FLUSH, l2x0_way_mask);
+}
+
+static void tf_resume_cache(void)
+{
+ unsigned long aux_val = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
+ tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_REENABLE, aux_val);
+}
+
+static void tf_configure_cache(const struct l2x0_regs *regs)
+{
+ outer_cache.disable = tf_disable_cache;
+ outer_cache.resume = tf_resume_cache;
+}
+
+static int tf_init_cache(void)
+{
+ tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_INIT, 0);
+
+ outer_cache.write_sec = tf_write_sec;
+ outer_cache.configure = tf_configure_cache;
+ return 0;
+}
+#endif /* CONFIG_CACHE_L2X0 */
+
static const struct firmware_ops trusted_foundations_ops = {
.set_cpu_boot_addr = tf_set_cpu_boot_addr,
.prepare_idle = tf_prepare_idle,
+#ifdef CONFIG_CACHE_L2X0
+ .l2x0_init = tf_init_cache,
+#endif
};
void register_trusted_foundations(struct trusted_foundations_platform_data *pd)
@@ -96,4 +143,6 @@ void of_register_trusted_foundations(void)
if (err != 0)
panic("Trusted Foundation: missing version-minor property\n");
register_trusted_foundations(&pdata);
+
+ of_node_put(node);
}
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h
b/arch/arm/include/asm/hardware/cache-l2x0.h
index 736292b42fca..603cc55edbd0 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -193,6 +193,8 @@ struct l2x0_regs {
unsigned long aux2_ctrl;
};
+extern void __iomem *l2x0_base;
+extern u32 l2x0_way_mask;
extern struct l2x0_regs l2x0_saved_regs;
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 808efbb89b88..1b29b769b6a9 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -30,6 +30,7 @@
#include <asm/cp15.h>
#include <asm/cputype.h>
#include <asm/hardware/cache-l2x0.h>
+#include <asm/firmware.h>
#include "cache-tauros3.h"
#include "cache-aurora-l2.h"
@@ -37,6 +38,7 @@ struct l2c_init_data {
const char *type;
unsigned way_size_0;
unsigned num_lock;
+ void (*init)(void __iomem *, u32 *, u32 *);
void (*of_parse)(const struct device_node *, u32 *, u32 *);
void (*enable)(void __iomem *, unsigned);
void (*fixup)(void __iomem *, u32, struct outer_cache_fns *);
@@ -48,13 +50,13 @@ struct l2c_init_data {
#define CACHE_LINE_SIZE 32
-static void __iomem *l2x0_base;
static const struct l2c_init_data *l2x0_data;
static DEFINE_RAW_SPINLOCK(l2x0_lock);
-static u32 l2x0_way_mask; /* Bitmask of active ways */
static u32 l2x0_size;
static unsigned long sync_reg_offset = L2X0_CACHE_SYNC;
+void __iomem *l2x0_base;
+u32 l2x0_way_mask; /* Bitmask of active ways */
struct l2x0_regs l2x0_saved_regs;
static bool l2x0_bresp_disable;
@@ -1758,6 +1760,7 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
u32 cache_id, old_aux;
u32 cache_level = 2;
bool nosync = false;
+ int err;
np = of_find_matching_node(NULL, l2x0_ids);
if (!np)
@@ -1798,6 +1801,11 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
nosync = of_property_read_bool(np, "arm,outer-sync-disable");
+ /* Call firmware init */
+ err = call_firmware_op(l2x0_init);
+ if (err && err != -ENOSYS)
+ return err;
+
/* Read back current (default) hardware configuration */
if (data->save)
data->save(l2x0_base);
diff --git a/arch/arm/mach-tegra/reset-handler.S
b/arch/arm/mach-tegra/reset-handler.S
index 805f306fa6f7..9a92bbf8b5b0 100644
--- a/arch/arm/mach-tegra/reset-handler.S
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -80,6 +80,28 @@ ENTRY(tegra_resume)
#endif
#ifdef CONFIG_CACHE_L2X0
+#ifdef CONFIG_TRUSTED_FOUNDATIONS
+ adr r3, __tegra_cpu_reset_handler_data
+ ldr r0, [r3, #RESET_DATA(TF_PRESENT)]
+ cmp r0, #0
+ beq ca9_scu_l2_resume
+
+ adr r3, __tegra_smc_stack
+ stmia r3, {r4-r12, sp, lr}
+
+ mov r0, #3 // local wake
+ mov r3, #0
+ mov r4, #0
+ dsb
+ .arch_extension sec
+ smc #0
+
+ adr r3, __tegra_smc_stack
+ ldmia r3, {r4-r12, sp, pc}
+
+ b end_ca9_scu_l2_resume
+ca9_scu_l2_resume:
+#endif
/* L2 cache resume & re-enable */
bl l2c310_early_resume
#endif
@@ -92,6 +114,16 @@ end_ca9_scu_l2_resume:
ENDPROC(tegra_resume)
#endif
+#ifdef CONFIG_TRUSTED_FOUNDATIONS
+ .align L1_CACHE_SHIFT
+ .type __tegra_smc_stack, %object
+__tegra_smc_stack:
+ .rept 11
+ .long 0
+ .endr
+ .size __tegra_smc_stack, . - __tegra_smc_stack
+#endif /* CONFIG_TRUSTED_FOUNDATIONS */
+
.align L1_CACHE_SHIFT
ENTRY(__tegra_cpu_reset_handler_start)
@@ -121,6 +153,12 @@ ENTRY(__tegra_cpu_reset_handler)
cpsid aif, 0x13 @ SVC mode, interrupts disabled
tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
+
+ adr r5, __tegra_cpu_reset_handler_data
+ ldr r0, [r5, #RESET_DATA(TF_PRESENT)]
+ cmp r0, #0
+ bne after_errata
+
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
t20_check:
cmp r6, #TEGRA20
@@ -285,6 +323,10 @@ __tegra_cpu_reset_handler_data:
.equ __tegra20_cpu1_resettable_status_offset, \
. - __tegra_cpu_reset_handler_start
.byte 0
+ .align 4
+ .globl __tegra_tf_present
+ .equ __tegra_tf_present, . - __tegra_cpu_reset_handler_start
+ .long 0
.align L1_CACHE_SHIFT
ENTRY(__tegra_cpu_reset_handler_end)
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
index dc558892753c..9b6558a69308 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -18,6 +18,7 @@
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <soc/tegra/fuse.h>
@@ -89,6 +90,15 @@ static void __init tegra_cpu_reset_handler_enable(void)
void __init tegra_cpu_reset_handler_init(void)
{
+#ifdef CONFIG_TRUSTED_FOUNDATIONS
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations");
+ if (np) {
+ __tegra_cpu_reset_handler_data[TEGRA_RESET_TF_PRESENT] = true;
+ of_node_put(np);
+ }
+#endif
#ifdef CONFIG_SMP
__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
diff --git a/arch/arm/mach-tegra/reset.h b/arch/arm/mach-tegra/reset.h
index 9c479c7925b8..0d9ddc022ece 100644
--- a/arch/arm/mach-tegra/reset.h
+++ b/arch/arm/mach-tegra/reset.h
@@ -25,7 +25,9 @@
#define TEGRA_RESET_STARTUP_SECONDARY 3
#define TEGRA_RESET_STARTUP_LP2 4
#define TEGRA_RESET_STARTUP_LP1 5
-#define TEGRA_RESET_DATA_SIZE 6
+#define TEGRA_RESET_RESETTABLE_STATUS 6
+#define TEGRA_RESET_TF_PRESENT 7
+#define TEGRA_RESET_DATA_SIZE 8
#ifndef __ASSEMBLY__