diff options
| -rw-r--r-- | arch/arm/mach-tegra/Makefile | 3 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/common.c | 3 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/headsmp.S | 221 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/platsmp.c | 1 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/reset-handler.S | 239 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/reset.c | 2 |
6 files changed, 246 insertions, 223 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index bd5d3120cb4b..a839bb3d9703 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile | |||
| @@ -8,6 +8,8 @@ obj-y += flowctrl.o | |||
| 8 | obj-y += powergate.o | 8 | obj-y += powergate.o |
| 9 | obj-y += apbio.o | 9 | obj-y += apbio.o |
| 10 | obj-y += pm.o | 10 | obj-y += pm.o |
| 11 | obj-y += reset.o | ||
| 12 | obj-y += reset-handler.o | ||
| 11 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o | 13 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o |
| 12 | obj-$(CONFIG_CPU_IDLE) += sleep.o | 14 | obj-$(CONFIG_CPU_IDLE) += sleep.o |
| 13 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o | 15 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o |
| @@ -26,7 +28,6 @@ ifeq ($(CONFIG_CPU_IDLE),y) | |||
| 26 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o | 28 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o |
| 27 | endif | 29 | endif |
| 28 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | 30 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o |
| 29 | obj-$(CONFIG_SMP) += reset.o | ||
| 30 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | 31 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o |
| 31 | obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o | 32 | obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o |
| 32 | obj-$(CONFIG_TEGRA_PCI) += pcie.o | 33 | obj-$(CONFIG_TEGRA_PCI) += pcie.o |
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index d54cfc54b9fe..3efe80b2af28 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include "apbio.h" | 37 | #include "apbio.h" |
| 38 | #include "sleep.h" | 38 | #include "sleep.h" |
| 39 | #include "pm.h" | 39 | #include "pm.h" |
| 40 | #include "reset.h" | ||
| 40 | 41 | ||
| 41 | /* | 42 | /* |
| 42 | * Storage for debug-macro.S's state. | 43 | * Storage for debug-macro.S's state. |
| @@ -137,6 +138,7 @@ static void __init tegra_init_cache(void) | |||
| 137 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | 138 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC |
| 138 | void __init tegra20_init_early(void) | 139 | void __init tegra20_init_early(void) |
| 139 | { | 140 | { |
| 141 | tegra_cpu_reset_handler_init(); | ||
| 140 | tegra_apb_io_init(); | 142 | tegra_apb_io_init(); |
| 141 | tegra_init_fuse(); | 143 | tegra_init_fuse(); |
| 142 | tegra2_init_clocks(); | 144 | tegra2_init_clocks(); |
| @@ -150,6 +152,7 @@ void __init tegra20_init_early(void) | |||
| 150 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | 152 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC |
| 151 | void __init tegra30_init_early(void) | 153 | void __init tegra30_init_early(void) |
| 152 | { | 154 | { |
| 155 | tegra_cpu_reset_handler_init(); | ||
| 153 | tegra_apb_io_init(); | 156 | tegra_apb_io_init(); |
| 154 | tegra_init_fuse(); | 157 | tegra_init_fuse(); |
| 155 | tegra30_init_clocks(); | 158 | tegra30_init_clocks(); |
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S index 23f487da7a57..b2834810b02b 100644 --- a/arch/arm/mach-tegra/headsmp.S +++ b/arch/arm/mach-tegra/headsmp.S | |||
| @@ -1,21 +1,10 @@ | |||
| 1 | #include <linux/linkage.h> | 1 | #include <linux/linkage.h> |
| 2 | #include <linux/init.h> | 2 | #include <linux/init.h> |
| 3 | 3 | ||
| 4 | #include <asm/cache.h> | ||
| 5 | #include <asm/asm-offsets.h> | ||
| 6 | #include <asm/hardware/cache-l2x0.h> | ||
| 7 | |||
| 8 | #include "flowctrl.h" | ||
| 9 | #include "iomap.h" | ||
| 10 | #include "reset.h" | ||
| 11 | #include "sleep.h" | 4 | #include "sleep.h" |
| 12 | 5 | ||
| 13 | #define APB_MISC_GP_HIDREV 0x804 | ||
| 14 | #define PMC_SCRATCH41 0x140 | ||
| 15 | |||
| 16 | #define RESET_DATA(x) ((TEGRA_RESET_##x)*4) | ||
| 17 | |||
| 18 | .section ".text.head", "ax" | 6 | .section ".text.head", "ax" |
| 7 | |||
| 19 | /* | 8 | /* |
| 20 | * Tegra specific entry point for secondary CPUs. | 9 | * Tegra specific entry point for secondary CPUs. |
| 21 | * The secondary kernel init calls v7_flush_dcache_all before it enables | 10 | * The secondary kernel init calls v7_flush_dcache_all before it enables |
| @@ -59,7 +48,6 @@ ENTRY(v7_invalidate_l1) | |||
| 59 | mov pc, lr | 48 | mov pc, lr |
| 60 | ENDPROC(v7_invalidate_l1) | 49 | ENDPROC(v7_invalidate_l1) |
| 61 | 50 | ||
| 62 | |||
| 63 | ENTRY(tegra_secondary_startup) | 51 | ENTRY(tegra_secondary_startup) |
| 64 | bl v7_invalidate_l1 | 52 | bl v7_invalidate_l1 |
| 65 | /* Enable coresight */ | 53 | /* Enable coresight */ |
| @@ -67,210 +55,3 @@ ENTRY(tegra_secondary_startup) | |||
| 67 | mcr p14, 0, r0, c7, c12, 6 | 55 | mcr p14, 0, r0, c7, c12, 6 |
| 68 | b secondary_startup | 56 | b secondary_startup |
| 69 | ENDPROC(tegra_secondary_startup) | 57 | ENDPROC(tegra_secondary_startup) |
| 70 | |||
| 71 | #ifdef CONFIG_PM_SLEEP | ||
| 72 | /* | ||
| 73 | * tegra_resume | ||
| 74 | * | ||
| 75 | * CPU boot vector when restarting the a CPU following | ||
| 76 | * an LP2 transition. Also branched to by LP0 and LP1 resume after | ||
| 77 | * re-enabling sdram. | ||
| 78 | */ | ||
| 79 | ENTRY(tegra_resume) | ||
| 80 | bl v7_invalidate_l1 | ||
| 81 | /* Enable coresight */ | ||
| 82 | mov32 r0, 0xC5ACCE55 | ||
| 83 | mcr p14, 0, r0, c7, c12, 6 | ||
| 84 | |||
| 85 | cpu_id r0 | ||
| 86 | cmp r0, #0 @ CPU0? | ||
| 87 | bne cpu_resume @ no | ||
| 88 | |||
| 89 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
| 90 | /* Are we on Tegra20? */ | ||
| 91 | mov32 r6, TEGRA_APB_MISC_BASE | ||
| 92 | ldr r0, [r6, #APB_MISC_GP_HIDREV] | ||
| 93 | and r0, r0, #0xff00 | ||
| 94 | cmp r0, #(0x20 << 8) | ||
| 95 | beq 1f @ Yes | ||
| 96 | /* Clear the flow controller flags for this CPU. */ | ||
| 97 | mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR | ||
| 98 | ldr r1, [r2] | ||
| 99 | /* Clear event & intr flag */ | ||
| 100 | orr r1, r1, \ | ||
| 101 | #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | ||
| 102 | movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps | ||
| 103 | bic r1, r1, r0 | ||
| 104 | str r1, [r2] | ||
| 105 | 1: | ||
| 106 | #endif | ||
| 107 | |||
| 108 | #ifdef CONFIG_HAVE_ARM_SCU | ||
| 109 | /* enable SCU */ | ||
| 110 | mov32 r0, TEGRA_ARM_PERIF_BASE | ||
| 111 | ldr r1, [r0] | ||
| 112 | orr r1, r1, #1 | ||
| 113 | str r1, [r0] | ||
| 114 | #endif | ||
| 115 | |||
| 116 | /* L2 cache resume & re-enable */ | ||
| 117 | l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr | ||
| 118 | |||
| 119 | b cpu_resume | ||
| 120 | ENDPROC(tegra_resume) | ||
| 121 | #endif | ||
| 122 | |||
| 123 | #ifdef CONFIG_CACHE_L2X0 | ||
| 124 | .globl l2x0_saved_regs_addr | ||
| 125 | l2x0_saved_regs_addr: | ||
| 126 | .long 0 | ||
| 127 | #endif | ||
| 128 | |||
| 129 | .align L1_CACHE_SHIFT | ||
| 130 | ENTRY(__tegra_cpu_reset_handler_start) | ||
| 131 | |||
| 132 | /* | ||
| 133 | * __tegra_cpu_reset_handler: | ||
| 134 | * | ||
| 135 | * Common handler for all CPU reset events. | ||
| 136 | * | ||
| 137 | * Register usage within the reset handler: | ||
| 138 | * | ||
| 139 | * R7 = CPU present (to the OS) mask | ||
| 140 | * R8 = CPU in LP1 state mask | ||
| 141 | * R9 = CPU in LP2 state mask | ||
| 142 | * R10 = CPU number | ||
| 143 | * R11 = CPU mask | ||
| 144 | * R12 = pointer to reset handler data | ||
| 145 | * | ||
| 146 | * NOTE: This code is copied to IRAM. All code and data accesses | ||
| 147 | * must be position-independent. | ||
| 148 | */ | ||
| 149 | |||
| 150 | .align L1_CACHE_SHIFT | ||
| 151 | ENTRY(__tegra_cpu_reset_handler) | ||
| 152 | |||
| 153 | cpsid aif, 0x13 @ SVC mode, interrupts disabled | ||
| 154 | mrc p15, 0, r10, c0, c0, 5 @ MPIDR | ||
| 155 | and r10, r10, #0x3 @ R10 = CPU number | ||
| 156 | mov r11, #1 | ||
| 157 | mov r11, r11, lsl r10 @ R11 = CPU mask | ||
| 158 | adr r12, __tegra_cpu_reset_handler_data | ||
| 159 | |||
| 160 | #ifdef CONFIG_SMP | ||
| 161 | /* Does the OS know about this CPU? */ | ||
| 162 | ldr r7, [r12, #RESET_DATA(MASK_PRESENT)] | ||
| 163 | tst r7, r11 @ if !present | ||
| 164 | bleq __die @ CPU not present (to OS) | ||
| 165 | #endif | ||
| 166 | |||
| 167 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
| 168 | /* Are we on Tegra20? */ | ||
| 169 | mov32 r6, TEGRA_APB_MISC_BASE | ||
| 170 | ldr r0, [r6, #APB_MISC_GP_HIDREV] | ||
| 171 | and r0, r0, #0xff00 | ||
| 172 | cmp r0, #(0x20 << 8) | ||
| 173 | bne 1f | ||
| 174 | /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */ | ||
| 175 | mov32 r6, TEGRA_PMC_BASE | ||
| 176 | mov r0, #0 | ||
| 177 | cmp r10, #0 | ||
| 178 | strne r0, [r6, #PMC_SCRATCH41] | ||
| 179 | 1: | ||
| 180 | #endif | ||
| 181 | |||
| 182 | /* Waking up from LP2? */ | ||
| 183 | ldr r9, [r12, #RESET_DATA(MASK_LP2)] | ||
| 184 | tst r9, r11 @ if in_lp2 | ||
| 185 | beq __is_not_lp2 | ||
| 186 | ldr lr, [r12, #RESET_DATA(STARTUP_LP2)] | ||
| 187 | cmp lr, #0 | ||
| 188 | bleq __die @ no LP2 startup handler | ||
| 189 | bx lr | ||
| 190 | |||
| 191 | __is_not_lp2: | ||
| 192 | |||
| 193 | #ifdef CONFIG_SMP | ||
| 194 | /* | ||
| 195 | * Can only be secondary boot (initial or hotplug) but CPU 0 | ||
| 196 | * cannot be here. | ||
| 197 | */ | ||
| 198 | cmp r10, #0 | ||
| 199 | bleq __die @ CPU0 cannot be here | ||
| 200 | ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)] | ||
| 201 | cmp lr, #0 | ||
| 202 | bleq __die @ no secondary startup handler | ||
| 203 | bx lr | ||
| 204 | #endif | ||
| 205 | |||
| 206 | /* | ||
| 207 | * We don't know why the CPU reset. Just kill it. | ||
| 208 | * The LR register will contain the address we died at + 4. | ||
| 209 | */ | ||
| 210 | |||
| 211 | __die: | ||
| 212 | sub lr, lr, #4 | ||
| 213 | mov32 r7, TEGRA_PMC_BASE | ||
| 214 | str lr, [r7, #PMC_SCRATCH41] | ||
| 215 | |||
| 216 | mov32 r7, TEGRA_CLK_RESET_BASE | ||
| 217 | |||
| 218 | /* Are we on Tegra20? */ | ||
| 219 | mov32 r6, TEGRA_APB_MISC_BASE | ||
| 220 | ldr r0, [r6, #APB_MISC_GP_HIDREV] | ||
| 221 | and r0, r0, #0xff00 | ||
| 222 | cmp r0, #(0x20 << 8) | ||
| 223 | bne 1f | ||
| 224 | |||
| 225 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
| 226 | mov32 r0, 0x1111 | ||
| 227 | mov r1, r0, lsl r10 | ||
| 228 | str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET | ||
| 229 | #endif | ||
| 230 | 1: | ||
| 231 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
| 232 | mov32 r6, TEGRA_FLOW_CTRL_BASE | ||
| 233 | |||
| 234 | cmp r10, #0 | ||
| 235 | moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS | ||
| 236 | moveq r2, #FLOW_CTRL_CPU0_CSR | ||
| 237 | movne r1, r10, lsl #3 | ||
| 238 | addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8) | ||
| 239 | addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8) | ||
| 240 | |||
| 241 | /* Clear CPU "event" and "interrupt" flags and power gate | ||
| 242 | it when halting but not before it is in the "WFI" state. */ | ||
| 243 | ldr r0, [r6, +r2] | ||
| 244 | orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | ||
| 245 | orr r0, r0, #FLOW_CTRL_CSR_ENABLE | ||
| 246 | str r0, [r6, +r2] | ||
| 247 | |||
| 248 | /* Unconditionally halt this CPU */ | ||
| 249 | mov r0, #FLOW_CTRL_WAITEVENT | ||
| 250 | str r0, [r6, +r1] | ||
| 251 | ldr r0, [r6, +r1] @ memory barrier | ||
| 252 | |||
| 253 | dsb | ||
| 254 | isb | ||
| 255 | wfi @ CPU should be power gated here | ||
| 256 | |||
| 257 | /* If the CPU didn't power gate above just kill it's clock. */ | ||
| 258 | |||
| 259 | mov r0, r11, lsl #8 | ||
| 260 | str r0, [r7, #348] @ CLK_CPU_CMPLX_SET | ||
| 261 | #endif | ||
| 262 | |||
| 263 | /* If the CPU still isn't dead, just spin here. */ | ||
| 264 | b . | ||
| 265 | ENDPROC(__tegra_cpu_reset_handler) | ||
| 266 | |||
| 267 | .align L1_CACHE_SHIFT | ||
| 268 | .type __tegra_cpu_reset_handler_data, %object | ||
| 269 | .globl __tegra_cpu_reset_handler_data | ||
| 270 | __tegra_cpu_reset_handler_data: | ||
| 271 | .rept TEGRA_RESET_DATA_SIZE | ||
| 272 | .long 0 | ||
| 273 | .endr | ||
| 274 | .align L1_CACHE_SHIFT | ||
| 275 | |||
| 276 | ENTRY(__tegra_cpu_reset_handler_end) | ||
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 5882da0f4d8a..60daf9f945cb 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c | |||
| @@ -202,7 +202,6 @@ static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) | |||
| 202 | /* Always mark the boot CPU (CPU0) as initialized. */ | 202 | /* Always mark the boot CPU (CPU0) as initialized. */ |
| 203 | cpumask_set_cpu(0, &tegra_cpu_init_mask); | 203 | cpumask_set_cpu(0, &tegra_cpu_init_mask); |
| 204 | 204 | ||
| 205 | tegra_cpu_reset_handler_init(); | ||
| 206 | scu_enable(scu_base); | 205 | scu_enable(scu_base); |
| 207 | } | 206 | } |
| 208 | 207 | ||
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S new file mode 100644 index 000000000000..54382ceade4a --- /dev/null +++ b/arch/arm/mach-tegra/reset-handler.S | |||
| @@ -0,0 +1,239 @@ | |||
| 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 | #include <linux/init.h> | ||
| 19 | |||
| 20 | #include <asm/cache.h> | ||
| 21 | #include <asm/asm-offsets.h> | ||
| 22 | #include <asm/hardware/cache-l2x0.h> | ||
| 23 | |||
| 24 | #include "flowctrl.h" | ||
| 25 | #include "iomap.h" | ||
| 26 | #include "reset.h" | ||
| 27 | #include "sleep.h" | ||
| 28 | |||
| 29 | #define APB_MISC_GP_HIDREV 0x804 | ||
| 30 | #define PMC_SCRATCH41 0x140 | ||
| 31 | |||
| 32 | #define RESET_DATA(x) ((TEGRA_RESET_##x)*4) | ||
| 33 | |||
| 34 | #ifdef CONFIG_PM_SLEEP | ||
| 35 | /* | ||
| 36 | * tegra_resume | ||
| 37 | * | ||
| 38 | * CPU boot vector when restarting the a CPU following | ||
| 39 | * an LP2 transition. Also branched to by LP0 and LP1 resume after | ||
| 40 | * re-enabling sdram. | ||
| 41 | */ | ||
| 42 | ENTRY(tegra_resume) | ||
| 43 | bl v7_invalidate_l1 | ||
| 44 | /* Enable coresight */ | ||
| 45 | mov32 r0, 0xC5ACCE55 | ||
| 46 | mcr p14, 0, r0, c7, c12, 6 | ||
| 47 | |||
| 48 | cpu_id r0 | ||
| 49 | cmp r0, #0 @ CPU0? | ||
| 50 | bne cpu_resume @ no | ||
| 51 | |||
| 52 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
| 53 | /* Are we on Tegra20? */ | ||
| 54 | mov32 r6, TEGRA_APB_MISC_BASE | ||
| 55 | ldr r0, [r6, #APB_MISC_GP_HIDREV] | ||
| 56 | and r0, r0, #0xff00 | ||
| 57 | cmp r0, #(0x20 << 8) | ||
| 58 | beq 1f @ Yes | ||
| 59 | /* Clear the flow controller flags for this CPU. */ | ||
| 60 | mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR | ||
| 61 | ldr r1, [r2] | ||
| 62 | /* Clear event & intr flag */ | ||
| 63 | orr r1, r1, \ | ||
| 64 | #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | ||
| 65 | movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps | ||
| 66 | bic r1, r1, r0 | ||
| 67 | str r1, [r2] | ||
| 68 | 1: | ||
| 69 | #endif | ||
| 70 | |||
| 71 | #ifdef CONFIG_HAVE_ARM_SCU | ||
| 72 | /* enable SCU */ | ||
| 73 | mov32 r0, TEGRA_ARM_PERIF_BASE | ||
| 74 | ldr r1, [r0] | ||
| 75 | orr r1, r1, #1 | ||
| 76 | str r1, [r0] | ||
| 77 | #endif | ||
| 78 | |||
| 79 | /* L2 cache resume & re-enable */ | ||
| 80 | l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr | ||
| 81 | |||
| 82 | b cpu_resume | ||
| 83 | ENDPROC(tegra_resume) | ||
| 84 | #endif | ||
| 85 | |||
| 86 | #ifdef CONFIG_CACHE_L2X0 | ||
| 87 | .globl l2x0_saved_regs_addr | ||
| 88 | l2x0_saved_regs_addr: | ||
| 89 | .long 0 | ||
| 90 | #endif | ||
| 91 | |||
| 92 | .align L1_CACHE_SHIFT | ||
| 93 | ENTRY(__tegra_cpu_reset_handler_start) | ||
| 94 | |||
| 95 | /* | ||
| 96 | * __tegra_cpu_reset_handler: | ||
| 97 | * | ||
| 98 | * Common handler for all CPU reset events. | ||
| 99 | * | ||
| 100 | * Register usage within the reset handler: | ||
| 101 | * | ||
| 102 | * R7 = CPU present (to the OS) mask | ||
| 103 | * R8 = CPU in LP1 state mask | ||
| 104 | * R9 = CPU in LP2 state mask | ||
| 105 | * R10 = CPU number | ||
| 106 | * R11 = CPU mask | ||
| 107 | * R12 = pointer to reset handler data | ||
| 108 | * | ||
| 109 | * NOTE: This code is copied to IRAM. All code and data accesses | ||
| 110 | * must be position-independent. | ||
| 111 | */ | ||
| 112 | |||
| 113 | .align L1_CACHE_SHIFT | ||
| 114 | ENTRY(__tegra_cpu_reset_handler) | ||
| 115 | |||
| 116 | cpsid aif, 0x13 @ SVC mode, interrupts disabled | ||
| 117 | mrc p15, 0, r10, c0, c0, 5 @ MPIDR | ||
| 118 | and r10, r10, #0x3 @ R10 = CPU number | ||
| 119 | mov r11, #1 | ||
| 120 | mov r11, r11, lsl r10 @ R11 = CPU mask | ||
| 121 | adr r12, __tegra_cpu_reset_handler_data | ||
| 122 | |||
| 123 | #ifdef CONFIG_SMP | ||
| 124 | /* Does the OS know about this CPU? */ | ||
| 125 | ldr r7, [r12, #RESET_DATA(MASK_PRESENT)] | ||
| 126 | tst r7, r11 @ if !present | ||
| 127 | bleq __die @ CPU not present (to OS) | ||
| 128 | #endif | ||
| 129 | |||
| 130 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
| 131 | /* Are we on Tegra20? */ | ||
| 132 | mov32 r6, TEGRA_APB_MISC_BASE | ||
| 133 | ldr r0, [r6, #APB_MISC_GP_HIDREV] | ||
| 134 | and r0, r0, #0xff00 | ||
| 135 | cmp r0, #(0x20 << 8) | ||
| 136 | bne 1f | ||
| 137 | /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */ | ||
| 138 | mov32 r6, TEGRA_PMC_BASE | ||
| 139 | mov r0, #0 | ||
| 140 | cmp r10, #0 | ||
| 141 | strne r0, [r6, #PMC_SCRATCH41] | ||
| 142 | 1: | ||
| 143 | #endif | ||
| 144 | |||
| 145 | /* Waking up from LP2? */ | ||
| 146 | ldr r9, [r12, #RESET_DATA(MASK_LP2)] | ||
| 147 | tst r9, r11 @ if in_lp2 | ||
| 148 | beq __is_not_lp2 | ||
| 149 | ldr lr, [r12, #RESET_DATA(STARTUP_LP2)] | ||
| 150 | cmp lr, #0 | ||
| 151 | bleq __die @ no LP2 startup handler | ||
| 152 | bx lr | ||
| 153 | |||
| 154 | __is_not_lp2: | ||
| 155 | |||
| 156 | #ifdef CONFIG_SMP | ||
| 157 | /* | ||
| 158 | * Can only be secondary boot (initial or hotplug) but CPU 0 | ||
| 159 | * cannot be here. | ||
| 160 | */ | ||
| 161 | cmp r10, #0 | ||
| 162 | bleq __die @ CPU0 cannot be here | ||
| 163 | ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)] | ||
| 164 | cmp lr, #0 | ||
| 165 | bleq __die @ no secondary startup handler | ||
| 166 | bx lr | ||
| 167 | #endif | ||
| 168 | |||
| 169 | /* | ||
| 170 | * We don't know why the CPU reset. Just kill it. | ||
| 171 | * The LR register will contain the address we died at + 4. | ||
| 172 | */ | ||
| 173 | |||
| 174 | __die: | ||
| 175 | sub lr, lr, #4 | ||
| 176 | mov32 r7, TEGRA_PMC_BASE | ||
| 177 | str lr, [r7, #PMC_SCRATCH41] | ||
| 178 | |||
| 179 | mov32 r7, TEGRA_CLK_RESET_BASE | ||
| 180 | |||
| 181 | /* Are we on Tegra20? */ | ||
| 182 | mov32 r6, TEGRA_APB_MISC_BASE | ||
| 183 | ldr r0, [r6, #APB_MISC_GP_HIDREV] | ||
| 184 | and r0, r0, #0xff00 | ||
| 185 | cmp r0, #(0x20 << 8) | ||
| 186 | bne 1f | ||
| 187 | |||
| 188 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
| 189 | mov32 r0, 0x1111 | ||
| 190 | mov r1, r0, lsl r10 | ||
| 191 | str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET | ||
| 192 | #endif | ||
| 193 | 1: | ||
| 194 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
| 195 | mov32 r6, TEGRA_FLOW_CTRL_BASE | ||
| 196 | |||
| 197 | cmp r10, #0 | ||
| 198 | moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS | ||
| 199 | moveq r2, #FLOW_CTRL_CPU0_CSR | ||
| 200 | movne r1, r10, lsl #3 | ||
| 201 | addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8) | ||
| 202 | addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8) | ||
| 203 | |||
| 204 | /* Clear CPU "event" and "interrupt" flags and power gate | ||
| 205 | it when halting but not before it is in the "WFI" state. */ | ||
| 206 | ldr r0, [r6, +r2] | ||
| 207 | orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | ||
| 208 | orr r0, r0, #FLOW_CTRL_CSR_ENABLE | ||
| 209 | str r0, [r6, +r2] | ||
| 210 | |||
| 211 | /* Unconditionally halt this CPU */ | ||
| 212 | mov r0, #FLOW_CTRL_WAITEVENT | ||
| 213 | str r0, [r6, +r1] | ||
| 214 | ldr r0, [r6, +r1] @ memory barrier | ||
| 215 | |||
| 216 | dsb | ||
| 217 | isb | ||
| 218 | wfi @ CPU should be power gated here | ||
| 219 | |||
| 220 | /* If the CPU didn't power gate above just kill it's clock. */ | ||
| 221 | |||
| 222 | mov r0, r11, lsl #8 | ||
| 223 | str r0, [r7, #348] @ CLK_CPU_CMPLX_SET | ||
| 224 | #endif | ||
| 225 | |||
| 226 | /* If the CPU still isn't dead, just spin here. */ | ||
| 227 | b . | ||
| 228 | ENDPROC(__tegra_cpu_reset_handler) | ||
| 229 | |||
| 230 | .align L1_CACHE_SHIFT | ||
| 231 | .type __tegra_cpu_reset_handler_data, %object | ||
| 232 | .globl __tegra_cpu_reset_handler_data | ||
| 233 | __tegra_cpu_reset_handler_data: | ||
| 234 | .rept TEGRA_RESET_DATA_SIZE | ||
| 235 | .long 0 | ||
| 236 | .endr | ||
| 237 | .align L1_CACHE_SHIFT | ||
| 238 | |||
| 239 | ENTRY(__tegra_cpu_reset_handler_end) | ||
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c index 3fd89ecd158e..1ac434e0068f 100644 --- a/arch/arm/mach-tegra/reset.c +++ b/arch/arm/mach-tegra/reset.c | |||
| @@ -75,7 +75,7 @@ void __init tegra_cpu_reset_handler_init(void) | |||
| 75 | 75 | ||
| 76 | #ifdef CONFIG_SMP | 76 | #ifdef CONFIG_SMP |
| 77 | __tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] = | 77 | __tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] = |
| 78 | *((u32 *)cpu_present_mask); | 78 | *((u32 *)cpu_possible_mask); |
| 79 | __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] = | 79 | __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] = |
| 80 | virt_to_phys((void *)tegra_secondary_startup); | 80 | virt_to_phys((void *)tegra_secondary_startup); |
| 81 | #endif | 81 | #endif |
