diff options
Diffstat (limited to 'arch/arm/mach-keystone/platsmp.c')
-rw-r--r-- | arch/arm/mach-keystone/platsmp.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/arch/arm/mach-keystone/platsmp.c b/arch/arm/mach-keystone/platsmp.c new file mode 100644 index 00000000000..beeb8d83b8d --- /dev/null +++ b/arch/arm/mach-keystone/platsmp.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Texas Instruments, Inc. | ||
3 | * | ||
4 | * Based on platsmp.c, Copyright 2010-2011 Calxeda, Inc. | ||
5 | * Based on platsmp.c, Copyright (C) 2002 ARM Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/smp.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/of.h> | ||
23 | |||
24 | #include <asm/smp.h> | ||
25 | #include <asm/smp_plat.h> | ||
26 | #include <asm/cacheflush.h> | ||
27 | #include <asm/tlbflush.h> | ||
28 | #include <asm/memory.h> | ||
29 | #include <asm/psci.h> | ||
30 | |||
31 | #include "keystone.h" | ||
32 | asm(".arch_extension sec\n\t"); | ||
33 | |||
34 | static void __cpuinit keystone_smp_secondary_initmem(void) | ||
35 | { | ||
36 | #ifdef CONFIG_ARM_LPAE | ||
37 | pgd_t *pgd0 = pgd_offset_k(0); | ||
38 | cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET); | ||
39 | local_flush_tlb_all(); | ||
40 | #endif | ||
41 | } | ||
42 | |||
43 | static void __cpuinit keystone_smp_secondary_init(unsigned int cpu) | ||
44 | { | ||
45 | keystone_smp_secondary_initmem(); | ||
46 | } | ||
47 | |||
48 | static int __cpuinit | ||
49 | keystone_smp_boot_secondary(unsigned int cpu, struct task_struct *idle) | ||
50 | { | ||
51 | unsigned long start = virt_to_idmap(&secondary_startup); | ||
52 | int error; | ||
53 | |||
54 | pr_debug("keystone-smp: booting cpu %d, vector %08lx\n", | ||
55 | cpu, start); | ||
56 | |||
57 | asm volatile ( | ||
58 | "mov r0, #0\n" /* power on cmd */ | ||
59 | "mov r1, %1\n" /* cpu */ | ||
60 | "mov r2, %2\n" /* start */ | ||
61 | "smc #0\n" /* SMI */ | ||
62 | "mov %0, r0\n" | ||
63 | : "=r" (error) | ||
64 | : "r"(cpu), "r"(start) | ||
65 | : "cc", "r0", "r1", "r2", "memory" | ||
66 | ); | ||
67 | |||
68 | pr_debug("keystone-smp: monitor returned %d\n", error); | ||
69 | |||
70 | return error; | ||
71 | } | ||
72 | |||
73 | #ifdef CONFIG_HOTPLUG_CPU | ||
74 | static void keystone_cpu_die(unsigned int cpu) | ||
75 | { | ||
76 | #ifdef CONFIG_ARM_PSCI | ||
77 | struct psci_power_state pwr_state = {0, 0, 0}; | ||
78 | |||
79 | printk(KERN_INFO "keystone_cpu_die(%d) from %d using PSCI\n", cpu, | ||
80 | smp_processor_id()); | ||
81 | |||
82 | if (psci_ops.cpu_off) | ||
83 | psci_ops.cpu_off(pwr_state); | ||
84 | #else | ||
85 | /* | ||
86 | * We may want to add here a direct smc call to monitor | ||
87 | * if the kernel doesn't support PSCI API | ||
88 | */ | ||
89 | #endif | ||
90 | |||
91 | /* | ||
92 | * we shouldn't come here. But in case something went | ||
93 | * wrong the code below prevents kernel from crush | ||
94 | */ | ||
95 | while (1) | ||
96 | cpu_do_idle(); | ||
97 | } | ||
98 | #endif | ||
99 | |||
100 | struct smp_operations keystone_smp_ops __initdata = { | ||
101 | .smp_secondary_init = keystone_smp_secondary_init, | ||
102 | .smp_boot_secondary = keystone_smp_boot_secondary, | ||
103 | #ifdef CONFIG_HOTPLUG_CPU | ||
104 | .cpu_die = keystone_cpu_die, | ||
105 | #endif | ||
106 | }; | ||