aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bus
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2013-05-21 23:34:41 -0400
committerNicolas Pitre <nicolas.pitre@linaro.org>2013-05-29 15:50:34 -0400
commit62158f817ad3e0368480b8e9480be34bffd8c74a (patch)
tree98dd2c84a505af7ee30f2b57389a27f1dd701f1e /drivers/bus
parented69bdd8fd9b2db68b915ce5f60fc51d4744a9b1 (diff)
drivers/bus: arm-cci: function to enable CCI ports from early boot code
This provides cci_enable_port_for_self(). This is the counterpart to cci_disable_port_by_cpu(self). This is meant to be called from the MCPM machine specific power_up_setup callback code when the appropriate affinity level needs to be initialized. The code therefore has to be position independent as the MMU is still off and it cannot rely on any stack space. Signed-off-by: Nicolas Pitre <nico@linaro.org> Reviewed-by: Dave Martin <dave.martin@linaro.org>
Diffstat (limited to 'drivers/bus')
-rw-r--r--drivers/bus/arm-cci.c119
1 files changed, 113 insertions, 6 deletions
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index ea81fa4a28db..380319ebf729 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -43,6 +43,7 @@ enum cci_ace_port_type {
43 43
44struct cci_ace_port { 44struct cci_ace_port {
45 void __iomem *base; 45 void __iomem *base;
46 unsigned long phys;
46 enum cci_ace_port_type type; 47 enum cci_ace_port_type type;
47 struct device_node *dn; 48 struct device_node *dn;
48}; 49};
@@ -51,11 +52,13 @@ static struct cci_ace_port *ports;
51static unsigned int nb_cci_ports; 52static unsigned int nb_cci_ports;
52 53
53static void __iomem *cci_ctrl_base; 54static void __iomem *cci_ctrl_base;
55static unsigned long cci_ctrl_phys;
54 56
55struct cpu_port { 57struct cpu_port {
56 u64 mpidr; 58 u64 mpidr;
57 u32 port; 59 u32 port;
58}; 60};
61
59/* 62/*
60 * Use the port MSB as valid flag, shift can be made dynamic 63 * Use the port MSB as valid flag, shift can be made dynamic
61 * by computing number of bits required for port indexes. 64 * by computing number of bits required for port indexes.
@@ -230,6 +233,102 @@ int notrace cci_disable_port_by_cpu(u64 mpidr)
230EXPORT_SYMBOL_GPL(cci_disable_port_by_cpu); 233EXPORT_SYMBOL_GPL(cci_disable_port_by_cpu);
231 234
232/** 235/**
236 * cci_enable_port_for_self() - enable a CCI port for calling CPU
237 *
238 * Enabling a CCI port for the calling CPU implies enabling the CCI
239 * port controlling that CPU's cluster. Caller must make sure that the
240 * CPU running the code is the first active CPU in the cluster and all
241 * other CPUs are quiescent in a low power state or waiting for this CPU
242 * to complete the CCI initialization.
243 *
244 * Because this is called when the MMU is still off and with no stack,
245 * the code must be position independent and ideally rely on callee
246 * clobbered registers only. To achieve this we must code this function
247 * entirely in assembler.
248 *
249 * On success this returns with the proper CCI port enabled. In case of
250 * any failure this never returns as the inability to enable the CCI is
251 * fatal and there is no possible recovery at this stage.
252 */
253asmlinkage void __naked cci_enable_port_for_self(void)
254{
255 asm volatile ("\n"
256
257" mrc p15, 0, r0, c0, c0, 5 @ get MPIDR value \n"
258" and r0, r0, #"__stringify(MPIDR_HWID_BITMASK)" \n"
259" adr r1, 5f \n"
260" ldr r2, [r1] \n"
261" add r1, r1, r2 @ &cpu_port \n"
262" add ip, r1, %[sizeof_cpu_port] \n"
263
264 /* Loop over the cpu_port array looking for a matching MPIDR */
265"1: ldr r2, [r1, %[offsetof_cpu_port_mpidr_lsb]] \n"
266" cmp r2, r0 @ compare MPIDR \n"
267" bne 2f \n"
268
269 /* Found a match, now test port validity */
270" ldr r3, [r1, %[offsetof_cpu_port_port]] \n"
271" tst r3, #"__stringify(PORT_VALID)" \n"
272" bne 3f \n"
273
274 /* no match, loop with the next cpu_port entry */
275"2: add r1, r1, %[sizeof_struct_cpu_port] \n"
276" cmp r1, ip @ done? \n"
277" blo 1b \n"
278
279 /* CCI port not found -- cheaply try to stall this CPU */
280"cci_port_not_found: \n"
281" wfi \n"
282" wfe \n"
283" b cci_port_not_found \n"
284
285 /* Use matched port index to look up the corresponding ports entry */
286"3: bic r3, r3, #"__stringify(PORT_VALID)" \n"
287" adr r0, 6f \n"
288" ldmia r0, {r1, r2} \n"
289" sub r1, r1, r0 @ virt - phys \n"
290" ldr r0, [r0, r2] @ *(&ports) \n"
291" mov r2, %[sizeof_struct_ace_port] \n"
292" mla r0, r2, r3, r0 @ &ports[index] \n"
293" sub r0, r0, r1 @ virt_to_phys() \n"
294
295 /* Enable the CCI port */
296" ldr r0, [r0, %[offsetof_port_phys]] \n"
297" mov r3, #"__stringify(CCI_ENABLE_REQ)" \n"
298" str r3, [r0, #"__stringify(CCI_PORT_CTRL)"] \n"
299
300 /* poll the status reg for completion */
301" adr r1, 7f \n"
302" ldr r0, [r1] \n"
303" ldr r0, [r0, r1] @ cci_ctrl_base \n"
304"4: ldr r1, [r0, #"__stringify(CCI_CTRL_STATUS)"] \n"
305" tst r1, #1 \n"
306" bne 4b \n"
307
308" mov r0, #0 \n"
309" bx lr \n"
310
311" .align 2 \n"
312"5: .word cpu_port - . \n"
313"6: .word . \n"
314" .word ports - 6b \n"
315"7: .word cci_ctrl_phys - . \n"
316 : :
317 [sizeof_cpu_port] "i" (sizeof(cpu_port)),
318#ifndef __ARMEB__
319 [offsetof_cpu_port_mpidr_lsb] "i" (offsetof(struct cpu_port, mpidr)),
320#else
321 [offsetof_cpu_port_mpidr_lsb] "i" (offsetof(struct cpu_port, mpidr)+4),
322#endif
323 [offsetof_cpu_port_port] "i" (offsetof(struct cpu_port, port)),
324 [sizeof_struct_cpu_port] "i" (sizeof(struct cpu_port)),
325 [sizeof_struct_ace_port] "i" (sizeof(struct cci_ace_port)),
326 [offsetof_port_phys] "i" (offsetof(struct cci_ace_port, phys)) );
327
328 unreachable();
329}
330
331/**
233 * __cci_control_port_by_device() - function to control a CCI port by device 332 * __cci_control_port_by_device() - function to control a CCI port by device
234 * reference 333 * reference
235 * 334 *
@@ -306,6 +405,7 @@ static int __init cci_probe(void)
306 struct cci_nb_ports const *cci_config; 405 struct cci_nb_ports const *cci_config;
307 int ret, i, nb_ace = 0, nb_ace_lite = 0; 406 int ret, i, nb_ace = 0, nb_ace_lite = 0;
308 struct device_node *np, *cp; 407 struct device_node *np, *cp;
408 struct resource res;
309 const char *match_str; 409 const char *match_str;
310 bool is_ace; 410 bool is_ace;
311 411
@@ -323,9 +423,12 @@ static int __init cci_probe(void)
323 if (!ports) 423 if (!ports)
324 return -ENOMEM; 424 return -ENOMEM;
325 425
326 cci_ctrl_base = of_iomap(np, 0); 426 ret = of_address_to_resource(np, 0, &res);
327 427 if (!ret) {
328 if (!cci_ctrl_base) { 428 cci_ctrl_base = ioremap(res.start, resource_size(&res));
429 cci_ctrl_phys = res.start;
430 }
431 if (ret || !cci_ctrl_base) {
329 WARN(1, "unable to ioremap CCI ctrl\n"); 432 WARN(1, "unable to ioremap CCI ctrl\n");
330 ret = -ENXIO; 433 ret = -ENXIO;
331 goto memalloc_err; 434 goto memalloc_err;
@@ -353,9 +456,12 @@ static int __init cci_probe(void)
353 continue; 456 continue;
354 } 457 }
355 458
356 ports[i].base = of_iomap(cp, 0); 459 ret = of_address_to_resource(cp, 0, &res);
357 460 if (!ret) {
358 if (!ports[i].base) { 461 ports[i].base = ioremap(res.start, resource_size(&res));
462 ports[i].phys = res.start;
463 }
464 if (ret || !ports[i].base) {
359 WARN(1, "unable to ioremap CCI port %d\n", i); 465 WARN(1, "unable to ioremap CCI port %d\n", i);
360 continue; 466 continue;
361 } 467 }
@@ -382,6 +488,7 @@ static int __init cci_probe(void)
382 * cluster power-up/power-down. Make sure it reaches main memory. 488 * cluster power-up/power-down. Make sure it reaches main memory.
383 */ 489 */
384 sync_cache_w(&cci_ctrl_base); 490 sync_cache_w(&cci_ctrl_base);
491 sync_cache_w(&cci_ctrl_phys);
385 sync_cache_w(&ports); 492 sync_cache_w(&ports);
386 sync_cache_w(&cpu_port); 493 sync_cache_w(&cpu_port);
387 __sync_cache_range_w(ports, sizeof(*ports) * nb_cci_ports); 494 __sync_cache_range_w(ports, sizeof(*ports) * nb_cci_ports);