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