summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/common.c
diff options
context:
space:
mode:
authorChris Johnson <cwj@nvidia.com>2011-11-18 16:14:07 -0800
committerVarun Wadekar <vwadekar@nvidia.com>2011-12-08 17:59:13 +0530
commit644d1fbf85ef31720cfefbe1f332767fe572e93a (patch)
treee79dae0187c03fef575bee42306e63ced5d668d7 /arch/arm/mach-tegra/common.c
parentd4808f8257f2868ac5dc29da2a266e975156c583 (diff)
arm: tegra: add Trusted Foundations hooks and driver
Add CONFIG_TRUSTED_FOUNDATIONS build option and calls to issue SMCs to the TL secure monitor (used when needing to update state not writable by non-secure code). Make security/tf_driver an optional part of the build, which is part of the TL framework to interact with secure services. Bug 883391 Change-Id: I9c6c14ff457fb3a0c612d558fe731a17c2480750 Signed-off-by: Chris Johnson <cwj@nvidia.com> Reviewed-on: http://git-master/r/65616 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/common.c')
-rw-r--r--arch/arm/mach-tegra/common.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 7fcf13117204..642d0aea76a8 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -27,6 +27,7 @@
#include <linux/highmem.h>
#include <linux/memblock.h>
#include <linux/bitops.h>
+#include <linux/sched.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/system.h>
@@ -185,12 +186,95 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
{ NULL, NULL, 0, 0},
};
+#if defined(CONFIG_TRUSTED_FOUNDATIONS) && defined(CONFIG_CACHE_L2X0)
+static void tegra_cache_smc(bool enable, u32 arg)
+{
+ void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
+ bool need_affinity_switch;
+ bool can_switch_affinity;
+ bool l2x0_enabled;
+ cpumask_t local_cpu_mask;
+ cpumask_t saved_cpu_mask;
+ unsigned long flags;
+ long ret;
+
+ /*
+ * ISSUE : Some registers of PL310 controler must be written
+ * from Secure context (and from CPU0)!
+ *
+ * When called form Normal we obtain an abort or do nothing.
+ * Instructions that must be called in Secure:
+ * - Write to Control register (L2X0_CTRL==0x100)
+ * - Write in Auxiliary controler (L2X0_AUX_CTRL==0x104)
+ * - Invalidate all entries (L2X0_INV_WAY==0x77C),
+ * mandatory at boot time.
+ * - Tag and Data RAM Latency Control Registers
+ * (0x108 & 0x10C) must be written in Secure.
+ */
+ need_affinity_switch = (smp_processor_id() != 0);
+ can_switch_affinity = !irqs_disabled();
+
+ WARN_ON(need_affinity_switch && !can_switch_affinity);
+ if (need_affinity_switch && can_switch_affinity) {
+ cpu_set(0, local_cpu_mask);
+ sched_getaffinity(0, &saved_cpu_mask);
+ ret = sched_setaffinity(0, &local_cpu_mask);
+ WARN_ON(ret != 0);
+ }
+
+ local_irq_save(flags);
+ l2x0_enabled = readl_relaxed(p + L2X0_CTRL) & 1;
+ if (enable && !l2x0_enabled)
+ tegra_generic_smc(0xFFFFF100, 0x00000001, arg);
+ else if (!enable && l2x0_enabled)
+ tegra_generic_smc(0xFFFFF100, 0x00000002, arg);
+ local_irq_restore(flags);
+
+ if (need_affinity_switch && can_switch_affinity) {
+ ret = sched_setaffinity(0, &saved_cpu_mask);
+ WARN_ON(ret != 0);
+ }
+}
+
+static void tegra_l2x0_disable(void)
+{
+ unsigned long flags;
+ static u32 l2x0_way_mask;
+
+ if (!l2x0_way_mask) {
+ void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
+ u32 aux_ctrl;
+ u32 ways;
+
+ aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL);
+ ways = (aux_ctrl & (1 << 16)) ? 16 : 8;
+ l2x0_way_mask = (1 << ways) - 1;
+ }
+
+ local_irq_save(flags);
+ tegra_cache_smc(false, l2x0_way_mask);
+ local_irq_restore(flags);
+}
+#endif /* CONFIG_TRUSTED_FOUNDATIONS && defined(CONFIG_CACHE_L2X0) */
+
void tegra_init_cache(bool init)
{
#ifdef CONFIG_CACHE_L2X0
void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
u32 aux_ctrl;
+#ifdef CONFIG_TRUSTED_FOUNDATIONS
+ /* issue the SMC to enable the L2 */
+ aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL);
+ tegra_cache_smc(true, aux_ctrl);
+
+ /* after init, reread aux_ctrl and register handlers */
+ aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL);
+ l2x0_init(p, aux_ctrl, 0xFFFFFFFF);
+
+ /* override outer_disable() with our disable */
+ outer_cache.disable = tegra_l2x0_disable;
+#else
#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
writel_relaxed(0x331, p + L2X0_TAG_LATENCY_CTRL);
writel_relaxed(0x441, p + L2X0_DATA_LATENCY_CTRL);
@@ -219,6 +303,8 @@ void tegra_init_cache(bool init)
aux_ctrl |= 0x7C000001;
l2x0_init(p, aux_ctrl, 0x8200c3fe);
}
+ l2x0_enable();
+#endif
#endif
}