aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Martin <dave.martin@linaro.org>2012-07-17 09:25:44 -0400
committerNicolas Pitre <nicolas.pitre@linaro.org>2013-05-29 15:50:35 -0400
commitd41418c0c0c0dc8a367af96b8e547f31477d9aa0 (patch)
treee1017c887fc5bfcc06f891732b69369e7e4a656e
parent2f2df895ee3518fbef28dfa6736dfd1e1c04ee1c (diff)
ARM: vexpress/dcscb: handle platform coherency exit/setup and CCI
Add the required code to properly handle race free platform coherency exit to the DCSCB power down method. The power_up_setup callback is used to enable the CCI interface for the cluster being brought up. This must be done in assembly before the kernel environment is entered. Thanks to Achin Gupta and Nicolas Pitre for their help and contributions. Signed-off-by: Dave Martin <dave.martin@linaro.org> Signed-off-by: Nicolas Pitre <nico@linaro.org> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Acked-by: Pawel Moll <pawel.moll@arm.com>
-rw-r--r--arch/arm/mach-vexpress/Kconfig1
-rw-r--r--arch/arm/mach-vexpress/Makefile2
-rw-r--r--arch/arm/mach-vexpress/dcscb.c77
-rw-r--r--arch/arm/mach-vexpress/dcscb_setup.S38
4 files changed, 98 insertions, 20 deletions
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 2f46385c2819..b8bbabec6310 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -60,6 +60,7 @@ config ARCH_VEXPRESS_CA9X4
60config ARCH_VEXPRESS_DCSCB 60config ARCH_VEXPRESS_DCSCB
61 bool "Dual Cluster System Control Block (DCSCB) support" 61 bool "Dual Cluster System Control Block (DCSCB) support"
62 depends on MCPM 62 depends on MCPM
63 select ARM_CCI
63 help 64 help
64 Support for the Dual Cluster System Configuration Block (DCSCB). 65 Support for the Dual Cluster System Configuration Block (DCSCB).
65 This is needed to provide CPU and cluster power management 66 This is needed to provide CPU and cluster power management
diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile
index 518519f57a5e..48ba89a8149f 100644
--- a/arch/arm/mach-vexpress/Makefile
+++ b/arch/arm/mach-vexpress/Makefile
@@ -6,6 +6,6 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
6 6
7obj-y := v2m.o 7obj-y := v2m.o
8obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o 8obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o
9obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o 9obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o
10obj-$(CONFIG_SMP) += platsmp.o 10obj-$(CONFIG_SMP) += platsmp.o
11obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 11obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-vexpress/dcscb.c b/arch/arm/mach-vexpress/dcscb.c
index 44aa7b040e82..16d57a8a9d5a 100644
--- a/arch/arm/mach-vexpress/dcscb.c
+++ b/arch/arm/mach-vexpress/dcscb.c
@@ -16,6 +16,7 @@
16#include <linux/errno.h> 16#include <linux/errno.h>
17#include <linux/of_address.h> 17#include <linux/of_address.h>
18#include <linux/vexpress.h> 18#include <linux/vexpress.h>
19#include <linux/arm-cci.h>
19 20
20#include <asm/mcpm.h> 21#include <asm/mcpm.h>
21#include <asm/proc-fns.h> 22#include <asm/proc-fns.h>
@@ -105,7 +106,10 @@ static void dcscb_power_down(void)
105 pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); 106 pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
106 BUG_ON(cpu >= 4 || cluster >= 2); 107 BUG_ON(cpu >= 4 || cluster >= 2);
107 108
109 __mcpm_cpu_going_down(cpu, cluster);
110
108 arch_spin_lock(&dcscb_lock); 111 arch_spin_lock(&dcscb_lock);
112 BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
109 dcscb_use_count[cpu][cluster]--; 113 dcscb_use_count[cpu][cluster]--;
110 if (dcscb_use_count[cpu][cluster] == 0) { 114 if (dcscb_use_count[cpu][cluster] == 0) {
111 rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); 115 rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4);
@@ -125,31 +129,59 @@ static void dcscb_power_down(void)
125 skip_wfi = true; 129 skip_wfi = true;
126 } else 130 } else
127 BUG(); 131 BUG();
128 arch_spin_unlock(&dcscb_lock);
129
130 /*
131 * Now let's clean our L1 cache and shut ourself down.
132 * If we're the last CPU in this cluster then clean L2 too.
133 */
134 132
135 /* 133 if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
136 * A15/A7 can hit in the cache with SCTLR.C=0, so we don't need 134 arch_spin_unlock(&dcscb_lock);
137 * a preliminary flush here for those CPUs. At least, that's
138 * the theory -- without the extra flush, Linux explodes on
139 * RTSM (to be investigated)..
140 */
141 flush_cache_louis();
142 set_cr(get_cr() & ~CR_C);
143 135
144 if (!last_man) { 136 /*
145 flush_cache_louis(); 137 * Flush all cache levels for this cluster.
146 } else { 138 *
139 * A15/A7 can hit in the cache with SCTLR.C=0, so we don't need
140 * a preliminary flush here for those CPUs. At least, that's
141 * the theory -- without the extra flush, Linux explodes on
142 * RTSM (to be investigated).
143 */
144 flush_cache_all();
145 set_cr(get_cr() & ~CR_C);
147 flush_cache_all(); 146 flush_cache_all();
147
148 /*
149 * This is a harmless no-op. On platforms with a real
150 * outer cache this might either be needed or not,
151 * depending on where the outer cache sits.
152 */
148 outer_flush_all(); 153 outer_flush_all();
154
155 /* Disable local coherency by clearing the ACTLR "SMP" bit: */
156 set_auxcr(get_auxcr() & ~(1 << 6));
157
158 /*
159 * Disable cluster-level coherency by masking
160 * incoming snoops and DVM messages:
161 */
162 cci_disable_port_by_cpu(mpidr);
163
164 __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
165 } else {
166 arch_spin_unlock(&dcscb_lock);
167
168 /*
169 * Flush the local CPU cache.
170 *
171 * A15/A7 can hit in the cache with SCTLR.C=0, so we don't need
172 * a preliminary flush here for those CPUs. At least, that's
173 * the theory -- without the extra flush, Linux explodes on
174 * RTSM (to be investigated).
175 */
176 flush_cache_louis();
177 set_cr(get_cr() & ~CR_C);
178 flush_cache_louis();
179
180 /* Disable local coherency by clearing the ACTLR "SMP" bit: */
181 set_auxcr(get_auxcr() & ~(1 << 6));
149 } 182 }
150 183
151 /* Disable local coherency by clearing the ACTLR "SMP" bit: */ 184 __mcpm_cpu_down(cpu, cluster);
152 set_auxcr(get_auxcr() & ~(1 << 6));
153 185
154 /* Now we are prepared for power-down, do it: */ 186 /* Now we are prepared for power-down, do it: */
155 dsb(); 187 dsb();
@@ -177,12 +209,17 @@ static void __init dcscb_usage_count_init(void)
177 dcscb_use_count[cpu][cluster] = 1; 209 dcscb_use_count[cpu][cluster] = 1;
178} 210}
179 211
212extern void dcscb_power_up_setup(unsigned int affinity_level);
213
180static int __init dcscb_init(void) 214static int __init dcscb_init(void)
181{ 215{
182 struct device_node *node; 216 struct device_node *node;
183 unsigned int cfg; 217 unsigned int cfg;
184 int ret; 218 int ret;
185 219
220 if (!cci_probed())
221 return -ENODEV;
222
186 node = of_find_compatible_node(NULL, NULL, "arm,rtsm,dcscb"); 223 node = of_find_compatible_node(NULL, NULL, "arm,rtsm,dcscb");
187 if (!node) 224 if (!node)
188 return -ENODEV; 225 return -ENODEV;
@@ -195,6 +232,8 @@ static int __init dcscb_init(void)
195 dcscb_usage_count_init(); 232 dcscb_usage_count_init();
196 233
197 ret = mcpm_platform_register(&dcscb_power_ops); 234 ret = mcpm_platform_register(&dcscb_power_ops);
235 if (!ret)
236 ret = mcpm_sync_init(dcscb_power_up_setup);
198 if (ret) { 237 if (ret) {
199 iounmap(dcscb_base); 238 iounmap(dcscb_base);
200 return ret; 239 return ret;
diff --git a/arch/arm/mach-vexpress/dcscb_setup.S b/arch/arm/mach-vexpress/dcscb_setup.S
new file mode 100644
index 000000000000..4bb7fbe0f621
--- /dev/null
+++ b/arch/arm/mach-vexpress/dcscb_setup.S
@@ -0,0 +1,38 @@
1/*
2 * arch/arm/include/asm/dcscb_setup.S
3 *
4 * Created by: Dave Martin, 2012-06-22
5 * Copyright: (C) 2012-2013 Linaro Limited
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 version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/linkage.h>
13
14
15ENTRY(dcscb_power_up_setup)
16
17 cmp r0, #0 @ check affinity level
18 beq 2f
19
20/*
21 * Enable cluster-level coherency, in preparation for turning on the MMU.
22 * The ACTLR SMP bit does not need to be set here, because cpu_resume()
23 * already restores that.
24 *
25 * A15/A7 may not require explicit L2 invalidation on reset, dependent
26 * on hardware integration decisions.
27 * For now, this code assumes that L2 is either already invalidated,
28 * or invalidation is not required.
29 */
30
31 b cci_enable_port_for_self
32
332: @ Implementation-specific local CPU setup operations should go here,
34 @ if any. In this case, there is nothing to do.
35
36 bx lr
37
38ENDPROC(dcscb_power_up_setup)