7d729bd726743b9858d348c8c78beaf421fb1f13
[firefly-linux-kernel-4.4.55.git] / arch / arm / common / mcpm_head.S
1 /*
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.
10  *
11  *
12  * Refer to Documentation/arm/cluster-pm-race-avoidance.txt
13  * for details of the synchronisation algorithms used here.
14  */
15
16 #include <linux/linkage.h>
17 #include <asm/mcpm.h>
18
19 .if MCPM_SYNC_CLUSTER_CPUS
20 .error "cpus must be the first member of struct mcpm_sync_struct"
21 .endif
22
23         .macro  pr_dbg  string
24 #if defined(CONFIG_DEBUG_LL) && defined(DEBUG)
25         b       1901f
26 1902:   .asciz  "CPU"
27 1903:   .asciz  " cluster"
28 1904:   .asciz  ": \string"
29         .align
30 1901:   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
46 ENTRY(mcpm_entry_point)
47
48  THUMB( adr     r12, BSYM(1f)   )
49  THUMB( bx      r12             )
50  THUMB( .thumb                  )
51 1:
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. */
61 1:      wfi
62         wfe
63         b       1b
64
65 2:      pr_dbg  "kernel mcpm_entry_point\n"
66
67         /*
68          * MMU is off so we need to get to various variables in a
69          * position independent way.
70          */
71         adr     r5, 3f
72         ldmia   r5, {r6, r7, r8}
73         add     r6, r5, r6                      @ r6 = mcpm_entry_vectors
74         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
98 mcpm_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:
111 mcpm_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
118 first_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
137 mcpm_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
145 mcpm_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.
160
161 mcpm_entry_gated:
162         ldr     r5, [r6, r4, lsl #2]            @ r5 = CPU entry vector
163         cmp     r5, #0
164         wfeeq
165         beq     mcpm_entry_gated
166         dmb
167
168         pr_dbg  "released\n"
169         bx      r5
170
171         .align  2
172
173 3:      .word   mcpm_entry_vectors - .
174         .word   mcpm_power_up_setup_phys - 3b
175         .word   mcpm_sync - 3b
176
177 ENDPROC(mcpm_entry_point)
178
179         .bss
180         .align  5
181
182         .type   mcpm_entry_vectors, #object
183 ENTRY(mcpm_entry_vectors)
184         .space  4 * MAX_NR_CLUSTERS * MAX_CPUS_PER_CLUSTER
185
186         .type   mcpm_power_up_setup_phys, #object
187 ENTRY(mcpm_power_up_setup_phys)
188         .space  4               @ set by mcpm_sync_init()