Merge remote-tracking branches 'asoc/topic/samsung', 'asoc/topic/sgtl5000', 'asoc...
[firefly-linux-kernel-4.4.55.git] / arch / arm / kernel / iwmmxt.S
1 /*
2  *  linux/arch/arm/kernel/iwmmxt.S
3  *
4  *  XScale iWMMXt (Concan) context switching and handling
5  *
6  *  Initial code:
7  *  Copyright (c) 2003, Intel Corporation
8  *
9  *  Full lazy switching support, optimizations and more, by Nicolas Pitre
10 *   Copyright (c) 2003-2004, MontaVista Software, Inc.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License version 2 as
14  * published by the Free Software Foundation.
15  */
16
17 #include <linux/linkage.h>
18 #include <asm/ptrace.h>
19 #include <asm/thread_info.h>
20 #include <asm/asm-offsets.h>
21
22 #if defined(CONFIG_CPU_PJ4) || defined(CONFIG_CPU_PJ4B)
23 #define PJ4(code...)            code
24 #define XSC(code...)
25 #elif defined(CONFIG_CPU_MOHAWK) || \
26         defined(CONFIG_CPU_XSC3) || \
27         defined(CONFIG_CPU_XSCALE)
28 #define PJ4(code...)
29 #define XSC(code...)            code
30 #else
31 #error "Unsupported iWMMXt architecture"
32 #endif
33
34 #define MMX_WR0                 (0x00)
35 #define MMX_WR1                 (0x08)
36 #define MMX_WR2                 (0x10)
37 #define MMX_WR3                 (0x18)
38 #define MMX_WR4                 (0x20)
39 #define MMX_WR5                 (0x28)
40 #define MMX_WR6                 (0x30)
41 #define MMX_WR7                 (0x38)
42 #define MMX_WR8                 (0x40)
43 #define MMX_WR9                 (0x48)
44 #define MMX_WR10                (0x50)
45 #define MMX_WR11                (0x58)
46 #define MMX_WR12                (0x60)
47 #define MMX_WR13                (0x68)
48 #define MMX_WR14                (0x70)
49 #define MMX_WR15                (0x78)
50 #define MMX_WCSSF               (0x80)
51 #define MMX_WCASF               (0x84)
52 #define MMX_WCGR0               (0x88)
53 #define MMX_WCGR1               (0x8C)
54 #define MMX_WCGR2               (0x90)
55 #define MMX_WCGR3               (0x94)
56
57 #define MMX_SIZE                (0x98)
58
59         .text
60
61 /*
62  * Lazy switching of Concan coprocessor context
63  *
64  * r10 = struct thread_info pointer
65  * r9  = ret_from_exception
66  * lr  = undefined instr exit
67  *
68  * called from prefetch exception handler with interrupts disabled
69  */
70
71 ENTRY(iwmmxt_task_enable)
72
73         XSC(mrc p15, 0, r2, c15, c1, 0)
74         PJ4(mrc p15, 0, r2, c1, c0, 2)
75         @ CP0 and CP1 accessible?
76         XSC(tst r2, #0x3)
77         PJ4(tst r2, #0xf)
78         movne   pc, lr                          @ if so no business here
79         @ enable access to CP0 and CP1
80         XSC(orr r2, r2, #0x3)
81         XSC(mcr p15, 0, r2, c15, c1, 0)
82         PJ4(orr r2, r2, #0xf)
83         PJ4(mcr p15, 0, r2, c1, c0, 2)
84
85         ldr     r3, =concan_owner
86         add     r0, r10, #TI_IWMMXT_STATE       @ get task Concan save area
87         ldr     r2, [sp, #60]                   @ current task pc value
88         ldr     r1, [r3]                        @ get current Concan owner
89         str     r0, [r3]                        @ this task now owns Concan regs
90         sub     r2, r2, #4                      @ adjust pc back
91         str     r2, [sp, #60]
92
93         mrc     p15, 0, r2, c2, c0, 0
94         mov     r2, r2                          @ cpwait
95
96         teq     r1, #0                          @ test for last ownership
97         mov     lr, r9                          @ normal exit from exception
98         beq     concan_load                     @ no owner, skip save
99
100 concan_save:
101
102         tmrc    r2, wCon
103
104         @ CUP? wCx
105         tst     r2, #0x1
106         beq     1f
107
108 concan_dump:
109
110         wstrw   wCSSF, [r1, #MMX_WCSSF]
111         wstrw   wCASF, [r1, #MMX_WCASF]
112         wstrw   wCGR0, [r1, #MMX_WCGR0]
113         wstrw   wCGR1, [r1, #MMX_WCGR1]
114         wstrw   wCGR2, [r1, #MMX_WCGR2]
115         wstrw   wCGR3, [r1, #MMX_WCGR3]
116
117 1:      @ MUP? wRn
118         tst     r2, #0x2
119         beq     2f
120
121         wstrd   wR0,  [r1, #MMX_WR0]
122         wstrd   wR1,  [r1, #MMX_WR1]
123         wstrd   wR2,  [r1, #MMX_WR2]
124         wstrd   wR3,  [r1, #MMX_WR3]
125         wstrd   wR4,  [r1, #MMX_WR4]
126         wstrd   wR5,  [r1, #MMX_WR5]
127         wstrd   wR6,  [r1, #MMX_WR6]
128         wstrd   wR7,  [r1, #MMX_WR7]
129         wstrd   wR8,  [r1, #MMX_WR8]
130         wstrd   wR9,  [r1, #MMX_WR9]
131         wstrd   wR10, [r1, #MMX_WR10]
132         wstrd   wR11, [r1, #MMX_WR11]
133         wstrd   wR12, [r1, #MMX_WR12]
134         wstrd   wR13, [r1, #MMX_WR13]
135         wstrd   wR14, [r1, #MMX_WR14]
136         wstrd   wR15, [r1, #MMX_WR15]
137
138 2:      teq     r0, #0                          @ anything to load?
139         moveq   pc, lr
140
141 concan_load:
142
143         @ Load wRn
144         wldrd   wR0,  [r0, #MMX_WR0]
145         wldrd   wR1,  [r0, #MMX_WR1]
146         wldrd   wR2,  [r0, #MMX_WR2]
147         wldrd   wR3,  [r0, #MMX_WR3]
148         wldrd   wR4,  [r0, #MMX_WR4]
149         wldrd   wR5,  [r0, #MMX_WR5]
150         wldrd   wR6,  [r0, #MMX_WR6]
151         wldrd   wR7,  [r0, #MMX_WR7]
152         wldrd   wR8,  [r0, #MMX_WR8]
153         wldrd   wR9,  [r0, #MMX_WR9]
154         wldrd   wR10, [r0, #MMX_WR10]
155         wldrd   wR11, [r0, #MMX_WR11]
156         wldrd   wR12, [r0, #MMX_WR12]
157         wldrd   wR13, [r0, #MMX_WR13]
158         wldrd   wR14, [r0, #MMX_WR14]
159         wldrd   wR15, [r0, #MMX_WR15]
160
161         @ Load wCx
162         wldrw   wCSSF, [r0, #MMX_WCSSF]
163         wldrw   wCASF, [r0, #MMX_WCASF]
164         wldrw   wCGR0, [r0, #MMX_WCGR0]
165         wldrw   wCGR1, [r0, #MMX_WCGR1]
166         wldrw   wCGR2, [r0, #MMX_WCGR2]
167         wldrw   wCGR3, [r0, #MMX_WCGR3]
168
169         @ clear CUP/MUP (only if r1 != 0)
170         teq     r1, #0
171         mov     r2, #0
172         moveq   pc, lr
173         tmcr    wCon, r2
174         mov     pc, lr
175
176 /*
177  * Back up Concan regs to save area and disable access to them
178  * (mainly for gdb or sleep mode usage)
179  *
180  * r0 = struct thread_info pointer of target task or NULL for any
181  */
182
183 ENTRY(iwmmxt_task_disable)
184
185         stmfd   sp!, {r4, lr}
186
187         mrs     ip, cpsr
188         orr     r2, ip, #PSR_I_BIT              @ disable interrupts
189         msr     cpsr_c, r2
190
191         ldr     r3, =concan_owner
192         add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
193         ldr     r1, [r3]                        @ get current Concan owner
194         teq     r1, #0                          @ any current owner?
195         beq     1f                              @ no: quit
196         teq     r0, #0                          @ any owner?
197         teqne   r1, r2                          @ or specified one?
198         bne     1f                              @ no: quit
199
200         @ enable access to CP0 and CP1
201         XSC(mrc p15, 0, r4, c15, c1, 0)
202         XSC(orr r4, r4, #0x3)
203         XSC(mcr p15, 0, r4, c15, c1, 0)
204         PJ4(mrc p15, 0, r4, c1, c0, 2)
205         PJ4(orr r4, r4, #0xf)
206         PJ4(mcr p15, 0, r4, c1, c0, 2)
207
208         mov     r0, #0                          @ nothing to load
209         str     r0, [r3]                        @ no more current owner
210         mrc     p15, 0, r2, c2, c0, 0
211         mov     r2, r2                          @ cpwait
212         bl      concan_save
213
214         @ disable access to CP0 and CP1
215         XSC(bic r4, r4, #0x3)
216         XSC(mcr p15, 0, r4, c15, c1, 0)
217         PJ4(bic r4, r4, #0xf)
218         PJ4(mcr p15, 0, r4, c1, c0, 2)
219
220         mrc     p15, 0, r2, c2, c0, 0
221         mov     r2, r2                          @ cpwait
222
223 1:      msr     cpsr_c, ip                      @ restore interrupt mode
224         ldmfd   sp!, {r4, pc}
225
226 /*
227  * Copy Concan state to given memory address
228  *
229  * r0 = struct thread_info pointer of target task
230  * r1 = memory address where to store Concan state
231  *
232  * this is called mainly in the creation of signal stack frames
233  */
234
235 ENTRY(iwmmxt_task_copy)
236
237         mrs     ip, cpsr
238         orr     r2, ip, #PSR_I_BIT              @ disable interrupts
239         msr     cpsr_c, r2
240
241         ldr     r3, =concan_owner
242         add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
243         ldr     r3, [r3]                        @ get current Concan owner
244         teq     r2, r3                          @ does this task own it...
245         beq     1f
246
247         @ current Concan values are in the task save area
248         msr     cpsr_c, ip                      @ restore interrupt mode
249         mov     r0, r1
250         mov     r1, r2
251         mov     r2, #MMX_SIZE
252         b       memcpy
253
254 1:      @ this task owns Concan regs -- grab a copy from there
255         mov     r0, #0                          @ nothing to load
256         mov     r2, #3                          @ save all regs
257         mov     r3, lr                          @ preserve return address
258         bl      concan_dump
259         msr     cpsr_c, ip                      @ restore interrupt mode
260         mov     pc, r3
261
262 /*
263  * Restore Concan state from given memory address
264  *
265  * r0 = struct thread_info pointer of target task
266  * r1 = memory address where to get Concan state from
267  *
268  * this is used to restore Concan state when unwinding a signal stack frame
269  */
270
271 ENTRY(iwmmxt_task_restore)
272
273         mrs     ip, cpsr
274         orr     r2, ip, #PSR_I_BIT              @ disable interrupts
275         msr     cpsr_c, r2
276
277         ldr     r3, =concan_owner
278         add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
279         ldr     r3, [r3]                        @ get current Concan owner
280         bic     r2, r2, #0x7                    @ 64-bit alignment
281         teq     r2, r3                          @ does this task own it...
282         beq     1f
283
284         @ this task doesn't own Concan regs -- use its save area
285         msr     cpsr_c, ip                      @ restore interrupt mode
286         mov     r0, r2
287         mov     r2, #MMX_SIZE
288         b       memcpy
289
290 1:      @ this task owns Concan regs -- load them directly
291         mov     r0, r1
292         mov     r1, #0                          @ don't clear CUP/MUP
293         mov     r3, lr                          @ preserve return address
294         bl      concan_load
295         msr     cpsr_c, ip                      @ restore interrupt mode
296         mov     pc, r3
297
298 /*
299  * Concan handling on task switch
300  *
301  * r0 = next thread_info pointer
302  *
303  * Called only from the iwmmxt notifier with task preemption disabled.
304  */
305 ENTRY(iwmmxt_task_switch)
306
307         XSC(mrc p15, 0, r1, c15, c1, 0)
308         PJ4(mrc p15, 0, r1, c1, c0, 2)
309         @ CP0 and CP1 accessible?
310         XSC(tst r1, #0x3)
311         PJ4(tst r1, #0xf)
312         bne     1f                              @ yes: block them for next task
313
314         ldr     r2, =concan_owner
315         add     r3, r0, #TI_IWMMXT_STATE        @ get next task Concan save area
316         ldr     r2, [r2]                        @ get current Concan owner
317         teq     r2, r3                          @ next task owns it?
318         movne   pc, lr                          @ no: leave Concan disabled
319
320 1:      @ flip Concan access
321         XSC(eor r1, r1, #0x3)
322         XSC(mcr p15, 0, r1, c15, c1, 0)
323         PJ4(eor r1, r1, #0xf)
324         PJ4(mcr p15, 0, r1, c1, c0, 2)
325
326         mrc     p15, 0, r1, c2, c0, 0
327         sub     pc, lr, r1, lsr #32             @ cpwait and return
328
329 /*
330  * Remove Concan ownership of given task
331  *
332  * r0 = struct thread_info pointer
333  */
334 ENTRY(iwmmxt_task_release)
335
336         mrs     r2, cpsr
337         orr     ip, r2, #PSR_I_BIT              @ disable interrupts
338         msr     cpsr_c, ip
339         ldr     r3, =concan_owner
340         add     r0, r0, #TI_IWMMXT_STATE        @ get task Concan save area
341         ldr     r1, [r3]                        @ get current Concan owner
342         eors    r0, r0, r1                      @ if equal...
343         streq   r0, [r3]                        @ then clear ownership
344         msr     cpsr_c, r2                      @ restore interrupts
345         mov     pc, lr
346
347         .data
348 concan_owner:
349         .word   0
350