aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/Makefile2
-rw-r--r--arch/arm/mach-tegra/clock.c4
-rw-r--r--arch/arm/mach-tegra/common.c3
-rw-r--r--arch/arm/mach-tegra/headsmp.S6
-rw-r--r--arch/arm/mach-tegra/hotplug.c118
-rw-r--r--arch/arm/mach-tegra/platsmp.c29
-rw-r--r--arch/arm/mach-tegra/sleep-t20.S82
-rw-r--r--arch/arm/mach-tegra/sleep-t30.S107
-rw-r--r--arch/arm/mach-tegra/sleep.S33
-rw-r--r--arch/arm/mach-tegra/sleep.h85
-rw-r--r--arch/arm/mach-tegra/tegra20_clocks.c70
-rw-r--r--arch/arm/mach-tegra/tegra20_clocks_data.c2
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks.c72
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks_data.c3
-rw-r--r--arch/arm/mach-tegra/tegra_cpu_car.h87
15 files changed, 556 insertions, 147 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index f07f99452a98..84d21f514418 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -15,8 +15,10 @@ obj-$(CONFIG_CPU_IDLE) += sleep.o
15obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o 15obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o
16obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o 16obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o
17obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o 17obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
18obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-t20.o
18obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o 19obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
19obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o 20obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o
21obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-t30.o
20obj-$(CONFIG_SMP) += platsmp.o headsmp.o 22obj-$(CONFIG_SMP) += platsmp.o headsmp.o
21obj-$(CONFIG_SMP) += reset.o 23obj-$(CONFIG_SMP) += reset.o
22obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 24obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 632133fc985b..fd82085eca5d 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -31,6 +31,10 @@
31 31
32#include "board.h" 32#include "board.h"
33#include "clock.h" 33#include "clock.h"
34#include "tegra_cpu_car.h"
35
36/* Global data of Tegra CPU CAR ops */
37struct tegra_cpu_car_ops *tegra_cpu_car_ops;
34 38
35/* 39/*
36 * Locking: 40 * Locking:
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index f3654f830991..0560538bf598 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -34,6 +34,7 @@
34#include "fuse.h" 34#include "fuse.h"
35#include "pmc.h" 35#include "pmc.h"
36#include "apbio.h" 36#include "apbio.h"
37#include "sleep.h"
37 38
38/* 39/*
39 * Storage for debug-macro.S's state. 40 * Storage for debug-macro.S's state.
@@ -135,6 +136,7 @@ void __init tegra20_init_early(void)
135 tegra_init_cache(0x331, 0x441); 136 tegra_init_cache(0x331, 0x441);
136 tegra_pmc_init(); 137 tegra_pmc_init();
137 tegra_powergate_init(); 138 tegra_powergate_init();
139 tegra20_hotplug_init();
138} 140}
139#endif 141#endif
140#ifdef CONFIG_ARCH_TEGRA_3x_SOC 142#ifdef CONFIG_ARCH_TEGRA_3x_SOC
@@ -147,6 +149,7 @@ void __init tegra30_init_early(void)
147 tegra_init_cache(0x441, 0x551); 149 tegra_init_cache(0x441, 0x551);
148 tegra_pmc_init(); 150 tegra_pmc_init();
149 tegra_powergate_init(); 151 tegra_powergate_init();
152 tegra30_hotplug_init();
150} 153}
151#endif 154#endif
152 155
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index fef9c2c51370..6addc78cb6b2 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -7,17 +7,13 @@
7 7
8#include "flowctrl.h" 8#include "flowctrl.h"
9#include "reset.h" 9#include "reset.h"
10#include "sleep.h"
10 11
11#define APB_MISC_GP_HIDREV 0x804 12#define APB_MISC_GP_HIDREV 0x804
12#define PMC_SCRATCH41 0x140 13#define PMC_SCRATCH41 0x140
13 14
14#define RESET_DATA(x) ((TEGRA_RESET_##x)*4) 15#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
15 16
16 .macro mov32, reg, val
17 movw \reg, #:lower16:\val
18 movt \reg, #:upper16:\val
19 .endm
20
21 .section ".text.head", "ax" 17 .section ".text.head", "ax"
22 __CPUINIT 18 __CPUINIT
23 19
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index d8dc9ddd6d18..d02a35476135 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -1,91 +1,23 @@
1/* 1/*
2 * linux/arch/arm/mach-realview/hotplug.c
3 * 2 *
4 * Copyright (C) 2002 ARM Ltd. 3 * Copyright (C) 2002 ARM Ltd.
5 * All Rights Reserved 4 * All Rights Reserved
5 * Copyright (c) 2010, 2012 NVIDIA Corporation. All rights reserved.
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation. 9 * published by the Free Software Foundation.
10 */ 10 */
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/errno.h>
13#include <linux/smp.h> 12#include <linux/smp.h>
14 13
15#include <asm/cacheflush.h> 14#include <asm/cacheflush.h>
16#include <asm/cp15.h> 15#include <asm/smp_plat.h>
17 16
18static inline void cpu_enter_lowpower(void) 17#include "sleep.h"
19{ 18#include "tegra_cpu_car.h"
20 unsigned int v;
21
22 flush_cache_all();
23 asm volatile(
24 " mcr p15, 0, %1, c7, c5, 0\n"
25 " mcr p15, 0, %1, c7, c10, 4\n"
26 /*
27 * Turn off coherency
28 */
29 " mrc p15, 0, %0, c1, c0, 1\n"
30 " bic %0, %0, #0x20\n"
31 " mcr p15, 0, %0, c1, c0, 1\n"
32 " mrc p15, 0, %0, c1, c0, 0\n"
33 " bic %0, %0, %2\n"
34 " mcr p15, 0, %0, c1, c0, 0\n"
35 : "=&r" (v)
36 : "r" (0), "Ir" (CR_C)
37 : "cc");
38}
39
40static inline void cpu_leave_lowpower(void)
41{
42 unsigned int v;
43
44 asm volatile(
45 "mrc p15, 0, %0, c1, c0, 0\n"
46 " orr %0, %0, %1\n"
47 " mcr p15, 0, %0, c1, c0, 0\n"
48 " mrc p15, 0, %0, c1, c0, 1\n"
49 " orr %0, %0, #0x20\n"
50 " mcr p15, 0, %0, c1, c0, 1\n"
51 : "=&r" (v)
52 : "Ir" (CR_C)
53 : "cc");
54}
55
56static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
57{
58 /*
59 * there is no power-control hardware on this platform, so all
60 * we can do is put the core into WFI; this is safe as the calling
61 * code will have already disabled interrupts
62 */
63 for (;;) {
64 /*
65 * here's the WFI
66 */
67 asm(".word 0xe320f003\n"
68 :
69 :
70 : "memory", "cc");
71 19
72 /*if (pen_release == cpu) {*/ 20static void (*tegra_hotplug_shutdown)(void);
73 /*
74 * OK, proper wakeup, we're done
75 */
76 break;
77 /*}*/
78
79 /*
80 * Getting here, means that we have come out of WFI without
81 * having been woken up - this shouldn't happen
82 *
83 * Just note it happening - when we're woken, we can report
84 * its occurrence.
85 */
86 (*spurious)++;
87 }
88}
89 21
90int platform_cpu_kill(unsigned int cpu) 22int platform_cpu_kill(unsigned int cpu)
91{ 23{
@@ -99,22 +31,20 @@ int platform_cpu_kill(unsigned int cpu)
99 */ 31 */
100void platform_cpu_die(unsigned int cpu) 32void platform_cpu_die(unsigned int cpu)
101{ 33{
102 int spurious = 0; 34 cpu = cpu_logical_map(cpu);
103 35
104 /* 36 /* Flush the L1 data cache. */
105 * we're ready for shutdown now, so do it 37 flush_cache_all();
106 */
107 cpu_enter_lowpower();
108 platform_do_lowpower(cpu, &spurious);
109 38
110 /* 39 /* Shut down the current CPU. */
111 * bring this CPU back into the world of cache 40 tegra_hotplug_shutdown();
112 * coherency, and then restore interrupts
113 */
114 cpu_leave_lowpower();
115 41
116 if (spurious) 42 /* Clock gate the CPU */
117 pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); 43 tegra_wait_cpu_in_reset(cpu);
44 tegra_disable_cpu_clock(cpu);
45
46 /* Should never return here. */
47 BUG();
118} 48}
119 49
120int platform_cpu_disable(unsigned int cpu) 50int platform_cpu_disable(unsigned int cpu)
@@ -125,3 +55,19 @@ int platform_cpu_disable(unsigned int cpu)
125 */ 55 */
126 return cpu == 0 ? -EPERM : 0; 56 return cpu == 0 ? -EPERM : 0;
127} 57}
58
59#ifdef CONFIG_ARCH_TEGRA_2x_SOC
60extern void tegra20_hotplug_shutdown(void);
61void __init tegra20_hotplug_init(void)
62{
63 tegra_hotplug_shutdown = tegra20_hotplug_shutdown;
64}
65#endif
66
67#ifdef CONFIG_ARCH_TEGRA_3x_SOC
68extern void tegra30_hotplug_shutdown(void);
69void __init tegra30_hotplug_init(void)
70{
71 tegra_hotplug_shutdown = tegra30_hotplug_shutdown;
72}
73#endif
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index 1a208dbf682f..96ed1718eef0 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -31,6 +31,7 @@
31#include "fuse.h" 31#include "fuse.h"
32#include "flowctrl.h" 32#include "flowctrl.h"
33#include "reset.h" 33#include "reset.h"
34#include "tegra_cpu_car.h"
34 35
35extern void tegra_secondary_startup(void); 36extern void tegra_secondary_startup(void);
36 37
@@ -38,17 +39,6 @@ static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
38 39
39#define EVP_CPU_RESET_VECTOR \ 40#define EVP_CPU_RESET_VECTOR \
40 (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100) 41 (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
41#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \
42 (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c)
43#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET \
44 (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
45#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
46 (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
47#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR \
48 (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x34c)
49
50#define CPU_CLOCK(cpu) (0x1<<(8+cpu))
51#define CPU_RESET(cpu) (0x1111ul<<(cpu))
52 42
53void __cpuinit platform_secondary_init(unsigned int cpu) 43void __cpuinit platform_secondary_init(unsigned int cpu)
54{ 44{
@@ -63,13 +53,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
63 53
64static int tegra20_power_up_cpu(unsigned int cpu) 54static int tegra20_power_up_cpu(unsigned int cpu)
65{ 55{
66 u32 reg;
67
68 /* Enable the CPU clock. */ 56 /* Enable the CPU clock. */
69 reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX); 57 tegra_enable_cpu_clock(cpu);
70 writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
71 barrier();
72 reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
73 58
74 /* Clear flow controller CSR. */ 59 /* Clear flow controller CSR. */
75 flowctrl_write_cpu_csr(cpu, 0); 60 flowctrl_write_cpu_csr(cpu, 0);
@@ -79,7 +64,6 @@ static int tegra20_power_up_cpu(unsigned int cpu)
79 64
80static int tegra30_power_up_cpu(unsigned int cpu) 65static int tegra30_power_up_cpu(unsigned int cpu)
81{ 66{
82 u32 reg;
83 int ret, pwrgateid; 67 int ret, pwrgateid;
84 unsigned long timeout; 68 unsigned long timeout;
85 69
@@ -103,8 +87,7 @@ static int tegra30_power_up_cpu(unsigned int cpu)
103 } 87 }
104 88
105 /* CPU partition is powered. Enable the CPU clock. */ 89 /* CPU partition is powered. Enable the CPU clock. */
106 writel(CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); 90 tegra_enable_cpu_clock(cpu);
107 reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
108 udelay(10); 91 udelay(10);
109 92
110 /* Remove I/O clamps. */ 93 /* Remove I/O clamps. */
@@ -128,8 +111,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
128 * via the flow controller). This will have no effect on first boot 111 * via the flow controller). This will have no effect on first boot
129 * of the CPU since it should already be in reset. 112 * of the CPU since it should already be in reset.
130 */ 113 */
131 writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); 114 tegra_put_cpu_in_reset(cpu);
132 dmb();
133 115
134 /* 116 /*
135 * Unhalt the CPU. If the flow controller was used to power-gate the 117 * Unhalt the CPU. If the flow controller was used to power-gate the
@@ -155,8 +137,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
155 goto done; 137 goto done;
156 138
157 /* Take the CPU out of reset. */ 139 /* Take the CPU out of reset. */
158 writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); 140 tegra_cpu_out_of_reset(cpu);
159 wmb();
160done: 141done:
161 return status; 142 return status;
162} 143}
diff --git a/arch/arm/mach-tegra/sleep-t20.S b/arch/arm/mach-tegra/sleep-t20.S
new file mode 100644
index 000000000000..a36ae413e2b8
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep-t20.S
@@ -0,0 +1,82 @@
1/*
2 * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
3 * Copyright (c) 2011, Google, Inc.
4 *
5 * Author: Colin Cross <ccross@android.com>
6 * Gary King <gking@nvidia.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/linkage.h>
22
23#include <asm/assembler.h>
24
25#include <mach/iomap.h>
26
27#include "sleep.h"
28#include "flowctrl.h"
29
30#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
31/*
32 * tegra20_hotplug_shutdown(void)
33 *
34 * puts the current cpu in reset
35 * should never return
36 */
37ENTRY(tegra20_hotplug_shutdown)
38 /* Turn off SMP coherency */
39 exit_smp r4, r5
40
41 /* Put this CPU down */
42 cpu_id r0
43 bl tegra20_cpu_shutdown
44 mov pc, lr @ should never get here
45ENDPROC(tegra20_hotplug_shutdown)
46
47/*
48 * tegra20_cpu_shutdown(int cpu)
49 *
50 * r0 is cpu to reset
51 *
52 * puts the specified CPU in wait-for-event mode on the flow controller
53 * and puts the CPU in reset
54 * can be called on the current cpu or another cpu
55 * if called on the current cpu, does not return
56 * MUST NOT BE CALLED FOR CPU 0.
57 *
58 * corrupts r0-r3, r12
59 */
60ENTRY(tegra20_cpu_shutdown)
61 cmp r0, #0
62 moveq pc, lr @ must not be called for CPU 0
63
64 cpu_to_halt_reg r1, r0
65 ldr r3, =TEGRA_FLOW_CTRL_VIRT
66 mov r2, #FLOW_CTRL_WAITEVENT | FLOW_CTRL_JTAG_RESUME
67 str r2, [r3, r1] @ put flow controller in wait event mode
68 ldr r2, [r3, r1]
69 isb
70 dsb
71 movw r1, 0x1011
72 mov r1, r1, lsl r0
73 ldr r3, =TEGRA_CLK_RESET_VIRT
74 str r1, [r3, #0x340] @ put slave CPU in reset
75 isb
76 dsb
77 cpu_id r3
78 cmp r3, r0
79 beq .
80 mov pc, lr
81ENDPROC(tegra20_cpu_shutdown)
82#endif
diff --git a/arch/arm/mach-tegra/sleep-t30.S b/arch/arm/mach-tegra/sleep-t30.S
new file mode 100644
index 000000000000..777d9cee8b90
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep-t30.S
@@ -0,0 +1,107 @@
1/*
2 * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/linkage.h>
18
19#include <asm/assembler.h>
20
21#include <mach/iomap.h>
22
23#include "sleep.h"
24#include "flowctrl.h"
25
26#define TEGRA30_POWER_HOTPLUG_SHUTDOWN (1 << 27) /* Hotplug shutdown */
27
28#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
29/*
30 * tegra30_hotplug_shutdown(void)
31 *
32 * Powergates the current CPU.
33 * Should never return.
34 */
35ENTRY(tegra30_hotplug_shutdown)
36 /* Turn off SMP coherency */
37 exit_smp r4, r5
38
39 /* Powergate this CPU */
40 mov r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
41 bl tegra30_cpu_shutdown
42 mov pc, lr @ should never get here
43ENDPROC(tegra30_hotplug_shutdown)
44
45/*
46 * tegra30_cpu_shutdown(unsigned long flags)
47 *
48 * Puts the current CPU in wait-for-event mode on the flow controller
49 * and powergates it -- flags (in R0) indicate the request type.
50 * Must never be called for CPU 0.
51 *
52 * corrupts r0-r4, r12
53 */
54ENTRY(tegra30_cpu_shutdown)
55 cpu_id r3
56 cmp r3, #0
57 moveq pc, lr @ Must never be called for CPU 0
58
59 ldr r12, =TEGRA_FLOW_CTRL_VIRT
60 cpu_to_csr_reg r1, r3
61 add r1, r1, r12 @ virtual CSR address for this CPU
62 cpu_to_halt_reg r2, r3
63 add r2, r2, r12 @ virtual HALT_EVENTS address for this CPU
64
65 /*
66 * Clear this CPU's "event" and "interrupt" flags and power gate
67 * it when halting but not before it is in the "WFE" state.
68 */
69 movw r12, \
70 FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \
71 FLOW_CTRL_CSR_ENABLE
72 mov r4, #(1 << 4)
73 orr r12, r12, r4, lsl r3
74 str r12, [r1]
75
76 /* Halt this CPU. */
77 mov r3, #0x400
78delay_1:
79 subs r3, r3, #1 @ delay as a part of wfe war.
80 bge delay_1;
81 cpsid a @ disable imprecise aborts.
82 ldr r3, [r1] @ read CSR
83 str r3, [r1] @ clear CSR
84 tst r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN
85 movne r3, #FLOW_CTRL_WAITEVENT @ For hotplug
86 str r3, [r2]
87 ldr r0, [r2]
88 b wfe_war
89
90__cpu_reset_again:
91 dsb
92 .align 5
93 wfe @ CPU should be power gated here
94wfe_war:
95 b __cpu_reset_again
96
97 /*
98 * 38 nop's, which fills reset of wfe cache line and
99 * 4 more cachelines with nop
100 */
101 .rept 38
102 nop
103 .endr
104 b . @ should never get here
105
106ENDPROC(tegra30_cpu_shutdown)
107#endif
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
index d29b156a8011..ea81554c4833 100644
--- a/arch/arm/mach-tegra/sleep.S
+++ b/arch/arm/mach-tegra/sleep.S
@@ -29,36 +29,5 @@
29#include <mach/iomap.h> 29#include <mach/iomap.h>
30 30
31#include "flowctrl.h" 31#include "flowctrl.h"
32#include "sleep.h"
32 33
33#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
34 + IO_PPSB_VIRT)
35
36/* returns the offset of the flow controller halt register for a cpu */
37.macro cpu_to_halt_reg rd, rcpu
38 cmp \rcpu, #0
39 subne \rd, \rcpu, #1
40 movne \rd, \rd, lsl #3
41 addne \rd, \rd, #0x14
42 moveq \rd, #0
43.endm
44
45/* returns the offset of the flow controller csr register for a cpu */
46.macro cpu_to_csr_reg rd, rcpu
47 cmp \rcpu, #0
48 subne \rd, \rcpu, #1
49 movne \rd, \rd, lsl #3
50 addne \rd, \rd, #0x18
51 moveq \rd, #8
52.endm
53
54/* returns the ID of the current processor */
55.macro cpu_id, rd
56 mrc p15, 0, \rd, c0, c0, 5
57 and \rd, \rd, #0xF
58.endm
59
60/* loads a 32-bit value into a register without a data access */
61.macro mov32, reg, val
62 movw \reg, #:lower16:\val
63 movt \reg, #:upper16:\val
64.endm
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
new file mode 100644
index 000000000000..e25a7cd703d9
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep.h
@@ -0,0 +1,85 @@
1/*
2 * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef __MACH_TEGRA_SLEEP_H
18#define __MACH_TEGRA_SLEEP_H
19
20#include <mach/iomap.h>
21
22#define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \
23 + IO_CPU_VIRT)
24#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
25 + IO_PPSB_VIRT)
26#define TEGRA_CLK_RESET_VIRT (TEGRA_CLK_RESET_BASE - IO_PPSB_PHYS \
27 + IO_PPSB_VIRT)
28
29#ifdef __ASSEMBLY__
30/* returns the offset of the flow controller halt register for a cpu */
31.macro cpu_to_halt_reg rd, rcpu
32 cmp \rcpu, #0
33 subne \rd, \rcpu, #1
34 movne \rd, \rd, lsl #3
35 addne \rd, \rd, #0x14
36 moveq \rd, #0
37.endm
38
39/* returns the offset of the flow controller csr register for a cpu */
40.macro cpu_to_csr_reg rd, rcpu
41 cmp \rcpu, #0
42 subne \rd, \rcpu, #1
43 movne \rd, \rd, lsl #3
44 addne \rd, \rd, #0x18
45 moveq \rd, #8
46.endm
47
48/* returns the ID of the current processor */
49.macro cpu_id, rd
50 mrc p15, 0, \rd, c0, c0, 5
51 and \rd, \rd, #0xF
52.endm
53
54/* loads a 32-bit value into a register without a data access */
55.macro mov32, reg, val
56 movw \reg, #:lower16:\val
57 movt \reg, #:upper16:\val
58.endm
59
60/* Macro to exit SMP coherency. */
61.macro exit_smp, tmp1, tmp2
62 mrc p15, 0, \tmp1, c1, c0, 1 @ ACTLR
63 bic \tmp1, \tmp1, #(1<<6) | (1<<0) @ clear ACTLR.SMP | ACTLR.FW
64 mcr p15, 0, \tmp1, c1, c0, 1 @ ACTLR
65 isb
66 cpu_id \tmp1
67 mov \tmp1, \tmp1, lsl #2
68 mov \tmp2, #0xf
69 mov \tmp2, \tmp2, lsl \tmp1
70 mov32 \tmp1, TEGRA_ARM_PERIF_VIRT + 0xC
71 str \tmp2, [\tmp1] @ invalidate SCU tags for CPU
72 dsb
73.endm
74#else
75
76#ifdef CONFIG_HOTPLUG_CPU
77void tegra20_hotplug_init(void);
78void tegra30_hotplug_init(void);
79#else
80static inline void tegra20_hotplug_init(void) {}
81static inline void tegra30_hotplug_init(void) {}
82#endif
83
84#endif
85#endif
diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c
index 840ab262272a..9273b0dffc66 100644
--- a/arch/arm/mach-tegra/tegra20_clocks.c
+++ b/arch/arm/mach-tegra/tegra20_clocks.c
@@ -33,6 +33,7 @@
33#include "clock.h" 33#include "clock.h"
34#include "fuse.h" 34#include "fuse.h"
35#include "tegra2_emc.h" 35#include "tegra2_emc.h"
36#include "tegra_cpu_car.h"
36 37
37#define RST_DEVICES 0x004 38#define RST_DEVICES 0x004
38#define RST_DEVICES_SET 0x300 39#define RST_DEVICES_SET 0x300
@@ -152,6 +153,14 @@
152#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16 153#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
153#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff 154#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff
154 155
156/* Tegra CPU clock and reset control regs */
157#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c
158#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340
159#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344
160
161#define CPU_CLOCK(cpu) (0x1 << (8 + cpu))
162#define CPU_RESET(cpu) (0x1111ul << (cpu))
163
155static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); 164static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
156static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); 165static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
157 166
@@ -1553,3 +1562,64 @@ struct clk_ops tegra_cdev_clk_ops = {
1553 .disable = tegra20_cdev_clk_disable, 1562 .disable = tegra20_cdev_clk_disable,
1554 .recalc_rate = tegra20_cdev_recalc_rate, 1563 .recalc_rate = tegra20_cdev_recalc_rate,
1555}; 1564};
1565
1566/* Tegra20 CPU clock and reset control functions */
1567static void tegra20_wait_cpu_in_reset(u32 cpu)
1568{
1569 unsigned int reg;
1570
1571 do {
1572 reg = readl(reg_clk_base +
1573 TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
1574 cpu_relax();
1575 } while (!(reg & (1 << cpu))); /* check CPU been reset or not */
1576
1577 return;
1578}
1579
1580static void tegra20_put_cpu_in_reset(u32 cpu)
1581{
1582 writel(CPU_RESET(cpu),
1583 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
1584 dmb();
1585}
1586
1587static void tegra20_cpu_out_of_reset(u32 cpu)
1588{
1589 writel(CPU_RESET(cpu),
1590 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
1591 wmb();
1592}
1593
1594static void tegra20_enable_cpu_clock(u32 cpu)
1595{
1596 unsigned int reg;
1597
1598 reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1599 writel(reg & ~CPU_CLOCK(cpu),
1600 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1601 barrier();
1602 reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1603}
1604
1605static void tegra20_disable_cpu_clock(u32 cpu)
1606{
1607 unsigned int reg;
1608
1609 reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1610 writel(reg | CPU_CLOCK(cpu),
1611 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
1612}
1613
1614static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
1615 .wait_for_reset = tegra20_wait_cpu_in_reset,
1616 .put_in_reset = tegra20_put_cpu_in_reset,
1617 .out_of_reset = tegra20_cpu_out_of_reset,
1618 .enable_clock = tegra20_enable_cpu_clock,
1619 .disable_clock = tegra20_disable_cpu_clock,
1620};
1621
1622void __init tegra20_cpu_car_ops_init(void)
1623{
1624 tegra_cpu_car_ops = &tegra20_cpu_car_ops;
1625}
diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c
index 1a35c003fba8..e81dcd239c95 100644
--- a/arch/arm/mach-tegra/tegra20_clocks_data.c
+++ b/arch/arm/mach-tegra/tegra20_clocks_data.c
@@ -34,6 +34,7 @@
34#include "fuse.h" 34#include "fuse.h"
35#include "tegra2_emc.h" 35#include "tegra2_emc.h"
36#include "tegra20_clocks.h" 36#include "tegra20_clocks.h"
37#include "tegra_cpu_car.h"
37 38
38/* Clock definitions */ 39/* Clock definitions */
39 40
@@ -1139,4 +1140,5 @@ void __init tegra2_init_clocks(void)
1139 } 1140 }
1140 1141
1141 init_audio_sync_clock_mux(); 1142 init_audio_sync_clock_mux();
1143 tegra20_cpu_car_ops_init();
1142} 1144}
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
index 63615dadfbb2..5cd502c27163 100644
--- a/arch/arm/mach-tegra/tegra30_clocks.c
+++ b/arch/arm/mach-tegra/tegra30_clocks.c
@@ -35,6 +35,7 @@
35 35
36#include "clock.h" 36#include "clock.h"
37#include "fuse.h" 37#include "fuse.h"
38#include "tegra_cpu_car.h"
38 39
39#define USE_PLL_LOCK_BITS 0 40#define USE_PLL_LOCK_BITS 0
40 41
@@ -299,6 +300,16 @@
299/* FIXME: recommended safety delay after lock is detected */ 300/* FIXME: recommended safety delay after lock is detected */
300#define PLL_POST_LOCK_DELAY 100 301#define PLL_POST_LOCK_DELAY 100
301 302
303/* Tegra CPU clock and reset control regs */
304#define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c
305#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340
306#define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344
307#define TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR 0x34c
308#define TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470
309
310#define CPU_CLOCK(cpu) (0x1 << (8 + cpu))
311#define CPU_RESET(cpu) (0x1111ul << (cpu))
312
302/** 313/**
303* Structure defining the fields for USB UTMI clocks Parameters. 314* Structure defining the fields for USB UTMI clocks Parameters.
304*/ 315*/
@@ -2221,3 +2232,64 @@ struct clk_ops tegra_cml_clk_ops = {
2221struct clk_ops tegra_pciex_clk_ops = { 2232struct clk_ops tegra_pciex_clk_ops = {
2222 .recalc_rate = tegra30_clk_fixed_recalc_rate, 2233 .recalc_rate = tegra30_clk_fixed_recalc_rate,
2223}; 2234};
2235
2236/* Tegra30 CPU clock and reset control functions */
2237static void tegra30_wait_cpu_in_reset(u32 cpu)
2238{
2239 unsigned int reg;
2240
2241 do {
2242 reg = readl(reg_clk_base +
2243 TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
2244 cpu_relax();
2245 } while (!(reg & (1 << cpu))); /* check CPU been reset or not */
2246
2247 return;
2248}
2249
2250static void tegra30_put_cpu_in_reset(u32 cpu)
2251{
2252 writel(CPU_RESET(cpu),
2253 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
2254 dmb();
2255}
2256
2257static void tegra30_cpu_out_of_reset(u32 cpu)
2258{
2259 writel(CPU_RESET(cpu),
2260 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
2261 wmb();
2262}
2263
2264static void tegra30_enable_cpu_clock(u32 cpu)
2265{
2266 unsigned int reg;
2267
2268 writel(CPU_CLOCK(cpu),
2269 reg_clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
2270 reg = readl(reg_clk_base +
2271 TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
2272}
2273
2274static void tegra30_disable_cpu_clock(u32 cpu)
2275{
2276
2277 unsigned int reg;
2278
2279 reg = readl(reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
2280 writel(reg | CPU_CLOCK(cpu),
2281 reg_clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
2282}
2283
2284static struct tegra_cpu_car_ops tegra30_cpu_car_ops = {
2285 .wait_for_reset = tegra30_wait_cpu_in_reset,
2286 .put_in_reset = tegra30_put_cpu_in_reset,
2287 .out_of_reset = tegra30_cpu_out_of_reset,
2288 .enable_clock = tegra30_enable_cpu_clock,
2289 .disable_clock = tegra30_disable_cpu_clock,
2290};
2291
2292void __init tegra30_cpu_car_ops_init(void)
2293{
2294 tegra_cpu_car_ops = &tegra30_cpu_car_ops;
2295}
diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c
index 34b61a4934a3..c10449603df0 100644
--- a/arch/arm/mach-tegra/tegra30_clocks_data.c
+++ b/arch/arm/mach-tegra/tegra30_clocks_data.c
@@ -32,6 +32,7 @@
32#include "clock.h" 32#include "clock.h"
33#include "fuse.h" 33#include "fuse.h"
34#include "tegra30_clocks.h" 34#include "tegra30_clocks.h"
35#include "tegra_cpu_car.h"
35 36
36#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \ 37#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \
37 _parent_names, _parents, _parent) \ 38 _parent_names, _parents, _parent) \
@@ -1366,4 +1367,6 @@ void __init tegra30_init_clocks(void)
1366 1367
1367 for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) 1368 for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
1368 tegra30_init_one_clock(tegra_clk_out_list[i]); 1369 tegra30_init_one_clock(tegra_clk_out_list[i]);
1370
1371 tegra30_cpu_car_ops_init();
1369} 1372}
diff --git a/arch/arm/mach-tegra/tegra_cpu_car.h b/arch/arm/mach-tegra/tegra_cpu_car.h
new file mode 100644
index 000000000000..30d063ad2bef
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra_cpu_car.h
@@ -0,0 +1,87 @@
1/*
2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef __MACH_TEGRA_CPU_CAR_H
18#define __MACH_TEGRA_CPU_CAR_H
19
20/*
21 * Tegra CPU clock and reset control ops
22 *
23 * wait_for_reset:
24 * keep waiting until the CPU in reset state
25 * put_in_reset:
26 * put the CPU in reset state
27 * out_of_reset:
28 * release the CPU from reset state
29 * enable_clock:
30 * CPU clock un-gate
31 * disable_clock:
32 * CPU clock gate
33 */
34struct tegra_cpu_car_ops {
35 void (*wait_for_reset)(u32 cpu);
36 void (*put_in_reset)(u32 cpu);
37 void (*out_of_reset)(u32 cpu);
38 void (*enable_clock)(u32 cpu);
39 void (*disable_clock)(u32 cpu);
40};
41
42extern struct tegra_cpu_car_ops *tegra_cpu_car_ops;
43
44static inline void tegra_wait_cpu_in_reset(u32 cpu)
45{
46 if (WARN_ON(!tegra_cpu_car_ops->wait_for_reset))
47 return;
48
49 tegra_cpu_car_ops->wait_for_reset(cpu);
50}
51
52static inline void tegra_put_cpu_in_reset(u32 cpu)
53{
54 if (WARN_ON(!tegra_cpu_car_ops->put_in_reset))
55 return;
56
57 tegra_cpu_car_ops->put_in_reset(cpu);
58}
59
60static inline void tegra_cpu_out_of_reset(u32 cpu)
61{
62 if (WARN_ON(!tegra_cpu_car_ops->out_of_reset))
63 return;
64
65 tegra_cpu_car_ops->out_of_reset(cpu);
66}
67
68static inline void tegra_enable_cpu_clock(u32 cpu)
69{
70 if (WARN_ON(!tegra_cpu_car_ops->enable_clock))
71 return;
72
73 tegra_cpu_car_ops->enable_clock(cpu);
74}
75
76static inline void tegra_disable_cpu_clock(u32 cpu)
77{
78 if (WARN_ON(!tegra_cpu_car_ops->disable_clock))
79 return;
80
81 tegra_cpu_car_ops->disable_clock(cpu);
82}
83
84void tegra20_cpu_car_ops_init(void);
85void tegra30_cpu_car_ops_init(void);
86
87#endif /* __MACH_TEGRA_CPU_CAR_H */