blob: 7d729bd726743b9858d348c8c78beaf421fb1f13 [file] [log] [blame]
Nicolas Pitree8db2882012-04-12 02:45:22 -04001/*
2 * arch/arm/common/mcpm_head.S -- kernel entry point for multi-cluster PM
3 *
4 * Created by: Nicolas Pitre, March 2012
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.
Dave Martin7fe31d22012-07-17 14:25:42 +010010 *
11 *
12 * Refer to Documentation/arm/cluster-pm-race-avoidance.txt
13 * for details of the synchronisation algorithms used here.
Nicolas Pitree8db2882012-04-12 02:45:22 -040014 */
15
16#include <linux/linkage.h>
17#include <asm/mcpm.h>
18
Dave Martin7fe31d22012-07-17 14:25:42 +010019.if MCPM_SYNC_CLUSTER_CPUS
20.error "cpus must be the first member of struct mcpm_sync_struct"
21.endif
22
Nicolas Pitree8db2882012-04-12 02:45:22 -040023 .macro pr_dbg string
24#if defined(CONFIG_DEBUG_LL) && defined(DEBUG)
25 b 1901f
261902: .asciz "CPU"
271903: .asciz " cluster"
281904: .asciz ": \string"
29 .align
301901: adr r0, 1902b
31 bl printascii
32 mov r0, r9
33 bl printhex8
34 adr r0, 1903b
35 bl printascii
36 mov r0, r10
37 bl printhex8
38 adr r0, 1904b
39 bl printascii
40#endif
41 .endm
42
43 .arm
44 .align
45
46ENTRY(mcpm_entry_point)
47
48 THUMB( adr r12, BSYM(1f) )
49 THUMB( bx r12 )
50 THUMB( .thumb )
511:
52 mrc p15, 0, r0, c0, c0, 5 @ MPIDR
53 ubfx r9, r0, #0, #8 @ r9 = cpu
54 ubfx r10, r0, #8, #8 @ r10 = cluster
55 mov r3, #MAX_CPUS_PER_CLUSTER
56 mla r4, r3, r10, r9 @ r4 = canonical CPU index
57 cmp r4, #(MAX_CPUS_PER_CLUSTER * MAX_NR_CLUSTERS)
58 blo 2f
59
60 /* We didn't expect this CPU. Try to cheaply make it quiet. */
611: wfi
62 wfe
63 b 1b
64
652: pr_dbg "kernel mcpm_entry_point\n"
66
67 /*
Dave Martin7fe31d22012-07-17 14:25:42 +010068 * MMU is off so we need to get to various variables in a
Nicolas Pitree8db2882012-04-12 02:45:22 -040069 * position independent way.
70 */
71 adr r5, 3f
Dave Martin7fe31d22012-07-17 14:25:42 +010072 ldmia r5, {r6, r7, r8}
Nicolas Pitree8db2882012-04-12 02:45:22 -040073 add r6, r5, r6 @ r6 = mcpm_entry_vectors
Dave Martin7fe31d22012-07-17 14:25:42 +010074 ldr r7, [r5, r7] @ r7 = mcpm_power_up_setup_phys
75 add r8, r5, r8 @ r8 = mcpm_sync
76
77 mov r0, #MCPM_SYNC_CLUSTER_SIZE
78 mla r8, r0, r10, r8 @ r8 = sync cluster base
79
80 @ Signal that this CPU is coming UP:
81 mov r0, #CPU_COMING_UP
82 mov r5, #MCPM_SYNC_CPU_SIZE
83 mla r5, r9, r5, r8 @ r5 = sync cpu address
84 strb r0, [r5]
85
86 @ At this point, the cluster cannot unexpectedly enter the GOING_DOWN
87 @ state, because there is at least one active CPU (this CPU).
88
89 @ Note: the following is racy as another CPU might be testing
90 @ the same flag at the same moment. That'll be fixed later.
91 ldrb r0, [r8, #MCPM_SYNC_CLUSTER_CLUSTER]
92 cmp r0, #CLUSTER_UP @ cluster already up?
93 bne mcpm_setup @ if not, set up the cluster
94
95 @ Otherwise, skip setup:
96 b mcpm_setup_complete
97
98mcpm_setup:
99 @ Control dependency implies strb not observable before previous ldrb.
100
101 @ Signal that the cluster is being brought up:
102 mov r0, #INBOUND_COMING_UP
103 strb r0, [r8, #MCPM_SYNC_CLUSTER_INBOUND]
104 dmb
105
106 @ Any CPU trying to take the cluster into CLUSTER_GOING_DOWN from this
107 @ point onwards will observe INBOUND_COMING_UP and abort.
108
109 @ Wait for any previously-pending cluster teardown operations to abort
110 @ or complete:
111mcpm_teardown_wait:
112 ldrb r0, [r8, #MCPM_SYNC_CLUSTER_CLUSTER]
113 cmp r0, #CLUSTER_GOING_DOWN
114 bne first_man_setup
115 wfe
116 b mcpm_teardown_wait
117
118first_man_setup:
119 dmb
120
121 @ If the outbound gave up before teardown started, skip cluster setup:
122
123 cmp r0, #CLUSTER_UP
124 beq mcpm_setup_leave
125
126 @ power_up_setup is now responsible for setting up the cluster:
127
128 cmp r7, #0
129 mov r0, #1 @ second (cluster) affinity level
130 blxne r7 @ Call power_up_setup if defined
131 dmb
132
133 mov r0, #CLUSTER_UP
134 strb r0, [r8, #MCPM_SYNC_CLUSTER_CLUSTER]
135 dmb
136
137mcpm_setup_leave:
138 @ Leave the cluster setup critical section:
139
140 mov r0, #INBOUND_NOT_COMING_UP
141 strb r0, [r8, #MCPM_SYNC_CLUSTER_INBOUND]
142 dsb
143 sev
144
145mcpm_setup_complete:
146 @ If a platform-specific CPU setup hook is needed, it is
147 @ called from here.
148
149 cmp r7, #0
150 mov r0, #0 @ first (CPU) affinity level
151 blxne r7 @ Call power_up_setup if defined
152 dmb
153
154 @ Mark the CPU as up:
155
156 mov r0, #CPU_UP
157 strb r0, [r5]
158
159 @ Observability order of CPU_UP and opening of the gate does not matter.
Nicolas Pitree8db2882012-04-12 02:45:22 -0400160
161mcpm_entry_gated:
162 ldr r5, [r6, r4, lsl #2] @ r5 = CPU entry vector
163 cmp r5, #0
164 wfeeq
165 beq mcpm_entry_gated
Dave Martin7fe31d22012-07-17 14:25:42 +0100166 dmb
167
Nicolas Pitree8db2882012-04-12 02:45:22 -0400168 pr_dbg "released\n"
169 bx r5
170
171 .align 2
172
1733: .word mcpm_entry_vectors - .
Dave Martin7fe31d22012-07-17 14:25:42 +0100174 .word mcpm_power_up_setup_phys - 3b
175 .word mcpm_sync - 3b
Nicolas Pitree8db2882012-04-12 02:45:22 -0400176
177ENDPROC(mcpm_entry_point)
178
179 .bss
180 .align 5
181
182 .type mcpm_entry_vectors, #object
183ENTRY(mcpm_entry_vectors)
184 .space 4 * MAX_NR_CLUSTERS * MAX_CPUS_PER_CLUSTER
Dave Martin7fe31d22012-07-17 14:25:42 +0100185
186 .type mcpm_power_up_setup_phys, #object
187ENTRY(mcpm_power_up_setup_phys)
188 .space 4 @ set by mcpm_sync_init()