aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/platsmp.c
diff options
context:
space:
mode:
authorPeter De Schrijver <pdeschrijver@nvidia.com>2012-02-09 18:47:45 -0500
committerOlof Johansson <olof@lixom.net>2012-02-26 17:44:44 -0500
commitb36ab9754efbd7429d214b3b03dc9843882571bd (patch)
tree4829030d17f9c03d78b3d065bd04c4c63814c8e1 /arch/arm/mach-tegra/platsmp.c
parent26fe681fdaa5c800f1f99e8181631866e50ed8a1 (diff)
ARM: tegra: rework Tegra secondary CPU core bringup
Prepare the Tegra secondary CPU core bringup code for other Tegra variants. The reset handler is also generalized to allow for future introduction of powersaving modes which turn off the CPU cores. Based on work by: Scott Williams <scwilliams@nvidia.com> Chris Johnson <cwj@nvidia.com> Colin Cross <ccross@android.com> Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> Acked-by: Stephen Warren <swarren@nvidia.com> Tested-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/mach-tegra/platsmp.c')
-rw-r--r--arch/arm/mach-tegra/platsmp.c97
1 files changed, 52 insertions, 45 deletions
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 7d2b5d03c1df..79a241a6320f 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -26,18 +26,26 @@
26 26
27#include <mach/iomap.h> 27#include <mach/iomap.h>
28 28
29#include "fuse.h"
30#include "flowctrl.h"
31#include "reset.h"
32
29extern void tegra_secondary_startup(void); 33extern void tegra_secondary_startup(void);
30 34
31static DEFINE_SPINLOCK(boot_lock);
32static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); 35static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
33 36
34#define EVP_CPU_RESET_VECTOR \ 37#define EVP_CPU_RESET_VECTOR \
35 (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100) 38 (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
36#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \ 39#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \
37 (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c) 40 (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c)
41#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET \
42 (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
38#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \ 43#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
39 (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344) 44 (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
40 45
46#define CPU_CLOCK(cpu) (0x1<<(8+cpu))
47#define CPU_RESET(cpu) (0x1111ul<<(cpu))
48
41void __cpuinit platform_secondary_init(unsigned int cpu) 49void __cpuinit platform_secondary_init(unsigned int cpu)
42{ 50{
43 /* 51 /*
@@ -47,63 +55,62 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
47 */ 55 */
48 gic_secondary_init(0); 56 gic_secondary_init(0);
49 57
50 /*
51 * Synchronise with the boot thread.
52 */
53 spin_lock(&boot_lock);
54 spin_unlock(&boot_lock);
55} 58}
56 59
57int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 60static int tegra20_power_up_cpu(unsigned int cpu)
58{ 61{
59 unsigned long old_boot_vector;
60 unsigned long boot_vector;
61 unsigned long timeout;
62 u32 reg; 62 u32 reg;
63 63
64 /* 64 /* Enable the CPU clock. */
65 * set synchronisation state between this boot processor 65 reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
66 * and the secondary one 66 writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
67 */ 67 barrier();
68 spin_lock(&boot_lock);
69
70
71 /* set the reset vector to point to the secondary_startup routine */
72
73 boot_vector = virt_to_phys(tegra_secondary_startup);
74 old_boot_vector = readl(EVP_CPU_RESET_VECTOR);
75 writel(boot_vector, EVP_CPU_RESET_VECTOR);
76
77 /* enable cpu clock on cpu1 */
78 reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX); 68 reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
79 writel(reg & ~(1<<9), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
80
81 reg = (1<<13) | (1<<9) | (1<<5) | (1<<1);
82 writel(reg, CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
83 69
84 smp_wmb(); 70 /* Clear flow controller CSR. */
85 flush_cache_all(); 71 flowctrl_write_cpu_csr(cpu, 0);
86 72
87 /* unhalt the cpu */ 73 return 0;
88 writel(0, IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x14); 74}
89 75
90 timeout = jiffies + (1 * HZ); 76int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
91 while (time_before(jiffies, timeout)) { 77{
92 if (readl(EVP_CPU_RESET_VECTOR) != boot_vector) 78 int status;
93 break;
94 udelay(10);
95 }
96 79
97 /* put the old boot vector back */ 80 /* Force the CPU into reset. The CPU must remain in reset when the
98 writel(old_boot_vector, EVP_CPU_RESET_VECTOR); 81 * flow controller state is cleared (which will cause the flow
82 * controller to stop driving reset if the CPU has been power-gated
83 * via the flow controller). This will have no effect on first boot
84 * of the CPU since it should already be in reset.
85 */
86 writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
87 dmb();
99 88
100 /* 89 /*
101 * now the secondary core is starting up let it run its 90 * Unhalt the CPU. If the flow controller was used to power-gate the
102 * calibrations, then wait for it to finish 91 * CPU this will cause the flow controller to stop driving reset.
92 * The CPU will remain in reset because the clock and reset block
93 * is now driving reset.
103 */ 94 */
104 spin_unlock(&boot_lock); 95 flowctrl_write_cpu_halt(cpu, 0);
96
97 switch (tegra_chip_id) {
98 case TEGRA20:
99 status = tegra20_power_up_cpu(cpu);
100 break;
101 default:
102 status = -EINVAL;
103 break;
104 }
105 105
106 return 0; 106 if (status)
107 goto done;
108
109 /* Take the CPU out of reset. */
110 writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
111 wmb();
112done:
113 return status;
107} 114}
108 115
109/* 116/*
@@ -128,6 +135,6 @@ void __init smp_init_cpus(void)
128 135
129void __init platform_smp_prepare_cpus(unsigned int max_cpus) 136void __init platform_smp_prepare_cpus(unsigned int max_cpus)
130{ 137{
131 138 tegra_cpu_reset_handler_init();
132 scu_enable(scu_base); 139 scu_enable(scu_base);
133} 140}