diff options
-rw-r--r-- | arch/arm/mach-tegra/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/clock.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-tegra/common.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/headsmp.S | 6 | ||||
-rw-r--r-- | arch/arm/mach-tegra/hotplug.c | 118 | ||||
-rw-r--r-- | arch/arm/mach-tegra/platsmp.c | 29 | ||||
-rw-r--r-- | arch/arm/mach-tegra/sleep-t20.S | 82 | ||||
-rw-r--r-- | arch/arm/mach-tegra/sleep-t30.S | 107 | ||||
-rw-r--r-- | arch/arm/mach-tegra/sleep.S | 33 | ||||
-rw-r--r-- | arch/arm/mach-tegra/sleep.h | 85 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra20_clocks.c | 70 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra20_clocks_data.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra30_clocks.c | 72 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra30_clocks_data.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra_cpu_car.h | 87 |
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 | |||
15 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o | 15 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o |
16 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o | 16 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o |
17 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o | 17 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o |
18 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-t20.o | ||
18 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o | 19 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o |
19 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o | 20 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o |
21 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-t30.o | ||
20 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | 22 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o |
21 | obj-$(CONFIG_SMP) += reset.o | 23 | obj-$(CONFIG_SMP) += reset.o |
22 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | 24 | obj-$(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 */ | ||
37 | struct 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 | ||
18 | static 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 | |||
40 | static 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 | |||
56 | static 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) {*/ | 20 | static 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 | ||
90 | int platform_cpu_kill(unsigned int cpu) | 22 | int platform_cpu_kill(unsigned int cpu) |
91 | { | 23 | { |
@@ -99,22 +31,20 @@ int platform_cpu_kill(unsigned int cpu) | |||
99 | */ | 31 | */ |
100 | void platform_cpu_die(unsigned int cpu) | 32 | void 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 | ||
120 | int platform_cpu_disable(unsigned int cpu) | 50 | int 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 | ||
60 | extern void tegra20_hotplug_shutdown(void); | ||
61 | void __init tegra20_hotplug_init(void) | ||
62 | { | ||
63 | tegra_hotplug_shutdown = tegra20_hotplug_shutdown; | ||
64 | } | ||
65 | #endif | ||
66 | |||
67 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
68 | extern void tegra30_hotplug_shutdown(void); | ||
69 | void __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 | ||
35 | extern void tegra_secondary_startup(void); | 36 | extern 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 | ||
53 | void __cpuinit platform_secondary_init(unsigned int cpu) | 43 | void __cpuinit platform_secondary_init(unsigned int cpu) |
54 | { | 44 | { |
@@ -63,13 +53,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu) | |||
63 | 53 | ||
64 | static int tegra20_power_up_cpu(unsigned int cpu) | 54 | static 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 | ||
80 | static int tegra30_power_up_cpu(unsigned int cpu) | 65 | static 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(); | ||
160 | done: | 141 | done: |
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 | */ | ||
37 | ENTRY(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 | ||
45 | ENDPROC(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 | */ | ||
60 | ENTRY(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 | ||
81 | ENDPROC(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 | */ | ||
35 | ENTRY(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 | ||
43 | ENDPROC(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 | */ | ||
54 | ENTRY(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 | ||
78 | delay_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 | ||
94 | wfe_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 | |||
106 | ENDPROC(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 | ||
77 | void tegra20_hotplug_init(void); | ||
78 | void tegra30_hotplug_init(void); | ||
79 | #else | ||
80 | static inline void tegra20_hotplug_init(void) {} | ||
81 | static 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 | |||
155 | static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); | 164 | static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); |
156 | static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); | 165 | static 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 */ | ||
1567 | static 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 | |||
1580 | static 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 | |||
1587 | static 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 | |||
1594 | static 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 | |||
1605 | static 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 | |||
1614 | static 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 | |||
1622 | void __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 = { | |||
2221 | struct clk_ops tegra_pciex_clk_ops = { | 2232 | struct 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 */ | ||
2237 | static 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 | |||
2250 | static 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 | |||
2257 | static 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 | |||
2264 | static 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 | |||
2274 | static 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 | |||
2284 | static 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 | |||
2292 | void __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 | */ | ||
34 | struct 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 | |||
42 | extern struct tegra_cpu_car_ops *tegra_cpu_car_ops; | ||
43 | |||
44 | static 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 | |||
52 | static 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 | |||
60 | static 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 | |||
68 | static 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 | |||
76 | static 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 | |||
84 | void tegra20_cpu_car_ops_init(void); | ||
85 | void tegra30_cpu_car_ops_init(void); | ||
86 | |||
87 | #endif /* __MACH_TEGRA_CPU_CAR_H */ | ||