From c34f30e588d310a70f994659c06f0a31dfdcfc15 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 4 Mar 2013 17:05:56 -0700 Subject: ARM: tegra: add CPU errata WARs to Tegra reset handler The CPU cores in Tegra contain some errata. Workarounds must be applied for these every time a CPU boots. Implement those workarounds directly in the Tegra-specific CPU reset vector. Many of these workarounds duplicate code in the core ARM kernel. However, the core ARM kernel cannot enable those workarounds when building a multi-platform kernel, since they require writing to secure- only registers, and a multi-platform kernel often does not run in secure mode, and also cannot generically/architecturally detect whether it is running in secure mode, and hence cannot either unconditionally or conditionally apply these workarounds. Instead, the workarounds must be applied in architecture-specific reset code, which is able to have more direct knowledge of the secure/normal state. On Tegra, we will be able to detect this using a non-architected register in the future, although we currently assume the kernel runs only in secure mode. Other SoCs may never run the kernel in secure mode, and hence always rely on a secure monitor to enable the workarounds, and hence never implement them in the kernel. Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/reset-handler.S | 45 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S index 54382ceade4a..ff7b45c6c2a0 100644 --- a/arch/arm/mach-tegra/reset-handler.S +++ b/arch/arm/mach-tegra/reset-handler.S @@ -99,6 +99,8 @@ ENTRY(__tegra_cpu_reset_handler_start) * * Register usage within the reset handler: * + * Others: scratch + * R6 = SoC ID << 8 * R7 = CPU present (to the OS) mask * R8 = CPU in LP1 state mask * R9 = CPU in LP2 state mask @@ -114,6 +116,40 @@ ENTRY(__tegra_cpu_reset_handler_start) ENTRY(__tegra_cpu_reset_handler) cpsid aif, 0x13 @ SVC mode, interrupts disabled + + mov32 r6, TEGRA_APB_MISC_BASE + ldr r6, [r6, #APB_MISC_GP_HIDREV] + and r6, r6, #0xff00 +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +t20_check: + cmp r6, #(0x20 << 8) + bne after_t20_check +t20_errata: + # Tegra20 is a Cortex-A9 r1p1 + mrc p15, 0, r0, c1, c0, 0 @ read system control register + orr r0, r0, #1 << 14 @ erratum 716044 + mcr p15, 0, r0, c1, c0, 0 @ write system control register + mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register + orr r0, r0, #1 << 4 @ erratum 742230 + orr r0, r0, #1 << 11 @ erratum 751472 + mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register + b after_errata +after_t20_check: +#endif +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +t30_check: + cmp r6, #(0x30 << 8) + bne after_t30_check +t30_errata: + # Tegra30 is a Cortex-A9 r2p9 + mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register + orr r0, r0, #1 << 6 @ erratum 743622 + orr r0, r0, #1 << 11 @ erratum 751472 + mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register + b after_errata +after_t30_check: +#endif +after_errata: mrc p15, 0, r10, c0, c0, 5 @ MPIDR and r10, r10, #0x3 @ R10 = CPU number mov r11, #1 @@ -129,16 +165,13 @@ ENTRY(__tegra_cpu_reset_handler) #ifdef CONFIG_ARCH_TEGRA_2x_SOC /* Are we on Tegra20? */ - mov32 r6, TEGRA_APB_MISC_BASE - ldr r0, [r6, #APB_MISC_GP_HIDREV] - and r0, r0, #0xff00 - cmp r0, #(0x20 << 8) + cmp r6, #(0x20 << 8) bne 1f /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */ - mov32 r6, TEGRA_PMC_BASE + mov32 r5, TEGRA_PMC_BASE mov r0, #0 cmp r10, #0 - strne r0, [r6, #PMC_SCRATCH41] + strne r0, [r5, #PMC_SCRATCH41] 1: #endif -- cgit v1.2.3 From 02e75d648899df96b79a4f98380679f48b91e3d4 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 4 Mar 2013 17:05:57 -0700 Subject: ARM: tegra: remove save/restore of CPU diag register Prior to this change, {save,restore}_cpu_arch_register() collaborated to maintain the value of the CPU diagnostic register across power cycles. This was required to maintain any CPU errata workaround enable bits in that register. However, now that the Tegra reset vector code always enables all required workarounds, there is no need to save and restore the diagnostic register; it is always explicitly programmed in the required manner. Hence, remove the save/restore logic. This has the advantage that the kernel always directly controls the value of this register every boot, rather than relying on a bootloader or other kernel code having previously written the correct value into it. This makes CPU0 (which was previously saved/restored) and CPUn (which should have been set up by the reset vector) be controlled in exactly the same way, which is easier to debug/find/... In particular, when converting Tegra to a multi-platform kernel, the CPU0 diagnostic register value initially comes from the bootloader. Most Tegra bootloaders don't yet enable all required CPU bug workarounds. The previous commit updates the kernel to do so on any CPU power cycle. However, the save/restore code ends up over-writing the value with the old bootloader-driven value instead of the now more-likely-to-be-correct kernel value! Even irrespective of multi-platform conversion, this change limits the kernel's exposure to any WARs the bootloader didn't enable for CPU0: on the very first LP2 transition (CPU power-saving which power-cycles the CPU), the correct value will be enabled. Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/cpuidle-tegra30.c | 4 ---- arch/arm/mach-tegra/pm.c | 19 ------------------- 2 files changed, 23 deletions(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index 8b50cf4ddd6f..80445ed33d95 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -102,12 +102,8 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, smp_wmb(); - save_cpu_arch_register(); - cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); - restore_cpu_arch_register(); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); return true; diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 523604de666f..0494f739c95f 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -46,26 +46,11 @@ #define PMC_CPUPWROFF_TIMER 0xcc #ifdef CONFIG_PM_SLEEP -static unsigned int g_diag_reg; static DEFINE_SPINLOCK(tegra_lp2_lock); static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); static struct clk *tegra_pclk; void (*tegra_tear_down_cpu)(void); -void save_cpu_arch_register(void) -{ - /* read diagnostic register */ - asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc"); - return; -} - -void restore_cpu_arch_register(void) -{ - /* write diagnostic register */ - asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc"); - return; -} - static void set_power_timers(unsigned long us_on, unsigned long us_off) { unsigned long long ticks; @@ -119,8 +104,6 @@ static void restore_cpu_complex(void) tegra_cpu_clock_resume(); flowctrl_cpu_suspend_exit(cpu); - - restore_cpu_arch_register(); } /* @@ -145,8 +128,6 @@ static void suspend_cpu_complex(void) tegra_cpu_clock_suspend(); flowctrl_cpu_suspend_enter(cpu); - - save_cpu_arch_register(); } void tegra_clear_cpu_in_lp2(int phy_cpu_id) -- cgit v1.2.3 From b095ae2b9f35c838257786de27e550d62bd7c763 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Tue, 19 Feb 2013 18:16:13 +0800 Subject: ARM: tegra: don't unlock MMIO access to DBGLAR There is no need to unlock MMIO access to the DBGLAR all the time. Doing so may even cause problems if a SW bug causes writes to that MMIO region. Cortex-A15 processors do not support the CP14 register write the code currently uses to unlock the DBGLAR; the instruction throws an undefined instruction exceptions. This prevents tegra_secondary_startup() from executing on Tegra114, and hence prevents SMP. Remove the code that unlocks this access. Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/headsmp.S | 3 --- arch/arm/mach-tegra/reset-handler.S | 3 --- 2 files changed, 6 deletions(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S index fd473f2b4c3d..045c16f2dd51 100644 --- a/arch/arm/mach-tegra/headsmp.S +++ b/arch/arm/mach-tegra/headsmp.S @@ -7,8 +7,5 @@ ENTRY(tegra_secondary_startup) bl v7_invalidate_l1 - /* Enable coresight */ - mov32 r0, 0xC5ACCE55 - mcr p14, 0, r0, c7, c12, 6 b secondary_startup ENDPROC(tegra_secondary_startup) diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S index ff7b45c6c2a0..1676aba5e7b8 100644 --- a/arch/arm/mach-tegra/reset-handler.S +++ b/arch/arm/mach-tegra/reset-handler.S @@ -41,9 +41,6 @@ */ ENTRY(tegra_resume) bl v7_invalidate_l1 - /* Enable coresight */ - mov32 r0, 0xC5ACCE55 - mcr p14, 0, r0, c7, c12, 6 cpu_id r0 cmp r0, #0 @ CPU0? -- cgit v1.2.3 From b4c25cc38260950f9ede38a88f932c7958adb2ec Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Fri, 22 Feb 2013 14:24:25 +0800 Subject: ARM: tegra: Fix unchecked return value Check a return value for tegra_powergate_remove_clamping(). Signed-off-by: Hiroshi Doyu Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/platsmp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 2c6b3d55213b..4dfc75e118ff 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -124,6 +124,9 @@ remove_clamps: /* Remove I/O clamps. */ ret = tegra_powergate_remove_clamping(pwrgateid); + if (ret) + return ret; + udelay(10); /* Clear flow controller CSR. */ -- cgit v1.2.3 From 2be8951e145eacf2a951288ea8e752e3b21acefd Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Fri, 22 Feb 2013 14:24:26 +0800 Subject: ARM: tegra: fix the logical detection of power on sequence of warm boot CPUs The warm boot sequence of Tegra30 secondary CPUs should wait for the power ready then removing the clamps. This did not fix any known or unknown issue, but nice to have this fix. Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/platsmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 4dfc75e118ff..e78d52d83acd 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -91,7 +91,7 @@ static int tegra30_power_up_cpu(unsigned int cpu) if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { timeout = jiffies + msecs_to_jiffies(50); do { - if (!tegra_powergate_is_powered(pwrgateid)) + if (tegra_powergate_is_powered(pwrgateid)) goto remove_clamps; udelay(10); } while (time_before(jiffies, timeout)); -- cgit v1.2.3 From 84b808da2dea7020211f1d73d015ff6c3ac207c4 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 6 Mar 2013 17:16:25 -0700 Subject: ARM: tegra: fix ignored return value of regulator_enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes: arch/arm/mach-tegra/board-harmony-pcie.c: In function ‘harmony_pcie_init’: arch/arm/mach-tegra/board-harmony-pcie.c:65:18: warning: ignoring return value of ‘regulator_enable’, declared with attribute warn_unused_result [-Wunused-result] Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/board-harmony-pcie.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c index 3cdc1bb8254c..d195db09ea32 100644 --- a/arch/arm/mach-tegra/board-harmony-pcie.c +++ b/arch/arm/mach-tegra/board-harmony-pcie.c @@ -62,7 +62,11 @@ int __init harmony_pcie_init(void) goto err_reg; } - regulator_enable(regulator); + err = regulator_enable(regulator); + if (err) { + pr_err("%s: regulator_enable failed: %d\n", __func__, err); + goto err_en; + } err = tegra_pcie_init(true, true); if (err) { @@ -74,6 +78,7 @@ int __init harmony_pcie_init(void) err_pcie: regulator_disable(regulator); +err_en: regulator_put(regulator); err_reg: gpio_free(en_vdd_1v05); -- cgit v1.2.3 From 99f69fea23d3c87c4f3067cb69499ff76499d93b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 28 Mar 2013 21:35:03 +0100 Subject: ARM: tegra: Export tegra_powergate_sequence_power_up() This function can be used by drivers to enable power to the hardware blocks that they drive. Most of the drivers can be built as a module and therefore require this function to be exported. Signed-off-by: Thierry Reding Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/powergate.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index c6bc8f85759c..c472bed3245e 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -168,6 +169,7 @@ err_clk: err_power: return ret; } +EXPORT_SYMBOL(tegra_powergate_sequence_power_up); int tegra_cpu_powergate_id(int cpuid) { -- cgit v1.2.3 From eebd1fda2342014a50ed3fd132e5dc6e8b5251e8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 28 Mar 2013 21:35:04 +0100 Subject: ARM: tegra: powergate: Don't error out if new state == old state Don't treat it as an error if a partition is already in the same power state when a user wants to power it on or off. This allows code to proceed if no state change is required. Signed-off-by: Thierry Reding Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/powergate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index c472bed3245e..af9067e2867c 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -76,7 +76,7 @@ static int tegra_powergate_set(int id, bool new_state) if (status == new_state) { spin_unlock_irqrestore(&tegra_powergate_lock, flags); - return -EINVAL; + return 0; } pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); -- cgit v1.2.3