Re: Tegra30 work around broken firmware.

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

 



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__


--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [ARM Kernel]     [Linux ARM]     [Linux ARM MSM]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux