aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile/smp-r8a7779.c
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2012-01-10 03:44:39 -0500
committerPaul Mundt <lethal@linux-sh.org>2012-01-11 21:00:27 -0500
commitf40aaf6da14a4043d6361e0c7d74ada18e866059 (patch)
tree655a02f6a7a0ef50772c13c00fef992924bdeb78 /arch/arm/mach-shmobile/smp-r8a7779.c
parentf0a217a31a745421df98db0d14ebdadef11d734c (diff)
ARM: mach-shmobile: r8a7779 SMP support V3
This patch contains r8a7779 SMP support V3 - now including CPU hotplug offine and online support. The r8a7779 power domain code is tied together with SMP glue code which allows us to control the power domains via CPU hotplug. At this point the kernel boots with the 4 Cortex-A9 cores in SMP mode and all CPU cores except CPU0 can be hotplugged. The code in platsmp.c is quite far from pretty, but it is kept like that intentionally to avoid creating layers of code that will go away in the near future anyway. The code needs to be updated when some per-SoC handling code will be added to the ARM architecture, see the following patch for more information: "[RFC PATCH 0/3] Per SoC descriptor" Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/arm/mach-shmobile/smp-r8a7779.c')
-rw-r--r--arch/arm/mach-shmobile/smp-r8a7779.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c
new file mode 100644
index 00000000000..cc97ef892d1
--- /dev/null
+++ b/arch/arm/mach-shmobile/smp-r8a7779.c
@@ -0,0 +1,153 @@
1/*
2 * SMP support for R-Mobile / SH-Mobile - r8a7779 portion
3 *
4 * Copyright (C) 2011 Renesas Solutions Corp.
5 * Copyright (C) 2011 Magnus Damm
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/smp.h>
23#include <linux/spinlock.h>
24#include <linux/io.h>
25#include <linux/delay.h>
26#include <mach/common.h>
27#include <mach/r8a7779.h>
28#include <asm/smp_scu.h>
29#include <asm/smp_twd.h>
30#include <asm/hardware/gic.h>
31
32#define AVECR 0xfe700040
33
34static struct r8a7779_pm_ch r8a7779_ch_cpu1 = {
35 .chan_offs = 0x40, /* PWRSR0 .. PWRER0 */
36 .chan_bit = 1, /* ARM1 */
37 .isr_bit = 1, /* ARM1 */
38};
39
40static struct r8a7779_pm_ch r8a7779_ch_cpu2 = {
41 .chan_offs = 0x40, /* PWRSR0 .. PWRER0 */
42 .chan_bit = 2, /* ARM2 */
43 .isr_bit = 2, /* ARM2 */
44};
45
46static struct r8a7779_pm_ch r8a7779_ch_cpu3 = {
47 .chan_offs = 0x40, /* PWRSR0 .. PWRER0 */
48 .chan_bit = 3, /* ARM3 */
49 .isr_bit = 3, /* ARM3 */
50};
51
52static struct r8a7779_pm_ch *r8a7779_ch_cpu[4] = {
53 [1] = &r8a7779_ch_cpu1,
54 [2] = &r8a7779_ch_cpu2,
55 [3] = &r8a7779_ch_cpu3,
56};
57
58static void __iomem *scu_base_addr(void)
59{
60 return (void __iomem *)0xf0000000;
61}
62
63static DEFINE_SPINLOCK(scu_lock);
64static unsigned long tmp;
65
66static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
67{
68 void __iomem *scu_base = scu_base_addr();
69
70 spin_lock(&scu_lock);
71 tmp = __raw_readl(scu_base + 8);
72 tmp &= ~clr;
73 tmp |= set;
74 spin_unlock(&scu_lock);
75
76 /* disable cache coherency after releasing the lock */
77 __raw_writel(tmp, scu_base + 8);
78}
79
80unsigned int __init r8a7779_get_core_count(void)
81{
82 void __iomem *scu_base = scu_base_addr();
83
84#ifdef CONFIG_HAVE_ARM_TWD
85 /* twd_base needs to be initialized before percpu_timer_setup() */
86 twd_base = (void __iomem *)0xf0000600;
87#endif
88
89 return scu_get_core_count(scu_base);
90}
91
92int r8a7779_platform_cpu_kill(unsigned int cpu)
93{
94 struct r8a7779_pm_ch *ch = NULL;
95 int ret = -EIO;
96
97 cpu = cpu_logical_map(cpu);
98
99 /* disable cache coherency */
100 modify_scu_cpu_psr(3 << (cpu * 8), 0);
101
102 if (cpu < ARRAY_SIZE(r8a7779_ch_cpu))
103 ch = r8a7779_ch_cpu[cpu];
104
105 if (ch)
106 ret = r8a7779_sysc_power_down(ch);
107
108 return ret ? ret : 1;
109}
110
111void __cpuinit r8a7779_secondary_init(unsigned int cpu)
112{
113 gic_secondary_init(0);
114}
115
116int __cpuinit r8a7779_boot_secondary(unsigned int cpu)
117{
118 struct r8a7779_pm_ch *ch = NULL;
119 int ret = -EIO;
120
121 cpu = cpu_logical_map(cpu);
122
123 /* enable cache coherency */
124 modify_scu_cpu_psr(0, 3 << (cpu * 8));
125
126 if (cpu < ARRAY_SIZE(r8a7779_ch_cpu))
127 ch = r8a7779_ch_cpu[cpu];
128
129 if (ch)
130 ret = r8a7779_sysc_power_up(ch);
131
132 return ret;
133}
134
135void __init r8a7779_smp_prepare_cpus(void)
136{
137 int cpu = cpu_logical_map(0);
138
139 scu_enable(scu_base_addr());
140
141 /* Map the reset vector (in headsmp.S) */
142 __raw_writel(__pa(shmobile_secondary_vector), __io(AVECR));
143
144 /* enable cache coherency on CPU0 */
145 modify_scu_cpu_psr(0, 3 << (cpu * 8));
146
147 r8a7779_pm_init();
148
149 /* power off secondary CPUs */
150 r8a7779_platform_cpu_kill(1);
151 r8a7779_platform_cpu_kill(2);
152 r8a7779_platform_cpu_kill(3);
153}