Merge remote-tracking branch 'regulator/topic/core' into regulator-next
[sfrench/cifs-2.6.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 #include <asm/assembler.h>
22
23 #if defined(CONFIG_CPU_PJ4) || defined(CONFIG_CPU_PJ4B)
24 #define PJ4(code...)            code
25 #define XSC(code...)
26 #elif defined(CONFIG_CPU_MOHAWK) || \
27         defined(CONFIG_CPU_XSC3) || \
28         defined(CONFIG_CPU_XSCALE)
29 #define PJ4(code...)
30 #define XSC(code...)            code
31 #else
32 #error "Unsupported iWMMXt architecture"
33 #endif
34
35 #define MMX_WR0                 (0x00)
36 #define MMX_WR1                 (0x08)
37 #define MMX_WR2                 (0x10)
38 #define MMX_WR3                 (0x18)
39 #define MMX_WR4                 (0x20)
40 #define MMX_WR5                 (0x28)
41 #define MMX_WR6                 (0x30)
42 #define MMX_WR7                 (0x38)
43 #define MMX_WR8                 (0x40)
44 #define MMX_WR9                 (0x48)
45 #define MMX_WR10                (0x50)
46 #define MMX_WR11                (0x58)
47 #define MMX_WR12                (0x60)
48 #define MMX_WR13                (0x68)
49 #define MMX_WR14                (0x70)
50 #define MMX_WR15                (0x78)
51 #define MMX_WCSSF               (0x80)
52 #define MMX_WCASF               (0x84)
53 #define MMX_WCGR0               (0x88)
54 #define MMX_WCGR1               (0x8C)
55 #define MMX_WCGR2               (0x90)
56 #define MMX_WCGR3               (0x94)
57
58 #define MMX_SIZE                (0x98)
59
60         .text
61
62 /*
63  * Lazy switching of Concan coprocessor context
64  *
65  * r10 = struct thread_info pointer
66  * r9  = ret_from_exception
67  * lr  = undefined instr exit
68  *
69  * called from prefetch exception handler with interrupts enabled
70  */
71
72 ENTRY(iwmmxt_task_enable)
73         inc_preempt_count r10, r3
74
75         XSC(mrc p15, 0, r2, c15, c1, 0)
76         PJ4(mrc p15, 0, r2, c1, c0, 2)
77         @ CP0 and CP1 accessible?
78         XSC(tst r2, #0x3)
79         PJ4(tst r2, #0xf)
80         bne     4f                              @ if so no business here
81         @ enable access to CP0 and CP1
82         XSC(orr r2, r2, #0x3)
83         XSC(mcr p15, 0, r2, c15, c1, 0)
84         PJ4(orr r2, r2, #0xf)
85         PJ4(mcr p15, 0, r2, c1, c0, 2)
86
87         ldr     r3, =concan_owner
88         add     r0, r10, #TI_IWMMXT_STATE       @ get task Concan save area
89         ldr     r2, [sp, #60]                   @ current task pc value
90         ldr     r1, [r3]                        @ get current Concan owner
91         str     r0, [r3]                        @ this task now owns Concan regs
92         sub     r2, r2, #4                      @ adjust pc back
93         str     r2, [sp, #60]
94
95         mrc     p15, 0, r2, c2, c0, 0
96         mov     r2, r2                          @ cpwait
97         bl      concan_save
98
99 #ifdef CONFIG_PREEMPT_COUNT
100         get_thread_info r10
101 #endif
102 4:      dec_preempt_count r10, r3
103         mov     pc, r9                          @ normal exit from exception
104
105 concan_save:
106
107         teq     r1, #0                          @ test for last ownership
108         beq     concan_load                     @ no owner, skip save
109
110         tmrc    r2, wCon
111
112         @ CUP? wCx
113         tst     r2, #0x1
114         beq     1f
115
116 concan_dump:
117
118         wstrw   wCSSF, [r1, #MMX_WCSSF]
119         wstrw   wCASF, [r1, #MMX_WCASF]
120         wstrw   wCGR0, [r1, #MMX_WCGR0]
121         wstrw   wCGR1, [r1, #MMX_WCGR1]
122         wstrw   wCGR2, [r1, #MMX_WCGR2]
123         wstrw   wCGR3, [r1, #MMX_WCGR3]
124
125 1:      @ MUP? wRn
126         tst     r2, #0x2
127         beq     2f
128
129         wstrd   wR0,  [r1, #MMX_WR0]
130         wstrd   wR1,  [r1, #MMX_WR1]
131         wstrd   wR2,  [r1, #MMX_WR2]
132         wstrd   wR3,  [r1, #MMX_WR3]
133         wstrd   wR4,  [r1, #MMX_WR4]
134         wstrd   wR5,  [r1, #MMX_WR5]
135         wstrd   wR6,  [r1, #MMX_WR6]
136         wstrd   wR7,  [r1, #MMX_WR7]
137         wstrd   wR8,  [r1, #MMX_WR8]
138         wstrd   wR9,  [r1, #MMX_WR9]
139         wstrd   wR10, [r1, #MMX_WR10]
140         wstrd   wR11, [r1, #MMX_WR11]
141         wstrd   wR12, [r1, #MMX_WR12]
142         wstrd   wR13, [r1, #MMX_WR13]
143         wstrd   wR14, [r1, #MMX_WR14]
144         wstrd   wR15, [r1, #MMX_WR15]
145
146 2:      teq     r0, #0                          @ anything to load?
147         moveq   pc, lr                          @ if not, return
148
149 concan_load:
150
151         @ Load wRn
152         wldrd   wR0,  [r0, #MMX_WR0]
153         wldrd   wR1,  [r0, #MMX_WR1]
154         wldrd   wR2,  [r0, #MMX_WR2]
155         wldrd   wR3,  [r0, #MMX_WR3]
156         wldrd   wR4,  [r0, #MMX_WR4]
157         wldrd   wR5,  [r0, #MMX_WR5]
158         wldrd   wR6,  [r0, #MMX_WR6]
159         wldrd   wR7,  [r0, #MMX_WR7]
160         wldrd   wR8,  [r0, #MMX_WR8]
161         wldrd   wR9,  [r0, #MMX_WR9]
162         wldrd   wR10, [r0, #MMX_WR10]
163         wldrd   wR11, [r0, #MMX_WR11]
164         wldrd   wR12, [r0, #MMX_WR12]
165         wldrd   wR13, [r0, #MMX_WR13]
166         wldrd   wR14, [r0, #MMX_WR14]
167         wldrd   wR15, [r0, #MMX_WR15]
168
169         @ Load wCx
170         wldrw   wCSSF, [r0, #MMX_WCSSF]
171         wldrw   wCASF, [r0, #MMX_WCASF]
172         wldrw   wCGR0, [r0, #MMX_WCGR0]
173         wldrw   wCGR1, [r0, #MMX_WCGR1]
174         wldrw   wCGR2, [r0, #MMX_WCGR2]
175         wldrw   wCGR3, [r0, #MMX_WCGR3]
176
177         @ clear CUP/MUP (only if r1 != 0)
178         teq     r1, #0
179         mov     r2, #0
180         moveq   pc, lr
181
182         tmcr    wCon, r2
183         mov     pc, lr
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 /*
236  * Copy Concan state to given memory address
237  *
238  * r0 = struct thread_info pointer of target task
239  * r1 = memory address where to store Concan state
240  *
241  * this is called mainly in the creation of signal stack frames
242  */
243
244 ENTRY(iwmmxt_task_copy)
245
246         mrs     ip, cpsr
247         orr     r2, ip, #PSR_I_BIT              @ disable interrupts
248         msr     cpsr_c, r2
249
250         ldr     r3, =concan_owner
251         add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
252         ldr     r3, [r3]                        @ get current Concan owner
253         teq     r2, r3                          @ does this task own it...
254         beq     1f
255
256         @ current Concan values are in the task save area
257         msr     cpsr_c, ip                      @ restore interrupt mode
258         mov     r0, r1
259         mov     r1, r2
260         mov     r2, #MMX_SIZE
261         b       memcpy
262
263 1:      @ this task owns Concan regs -- grab a copy from there
264         mov     r0, #0                          @ nothing to load
265         mov     r2, #3                          @ save all regs
266         mov     r3, lr                          @ preserve return address
267         bl      concan_dump
268         msr     cpsr_c, ip                      @ restore interrupt mode
269         mov     pc, r3
270
271 /*
272  * Restore Concan state from given memory address
273  *
274  * r0 = struct thread_info pointer of target task
275  * r1 = memory address where to get Concan state from
276  *
277  * this is used to restore Concan state when unwinding a signal stack frame
278  */
279
280 ENTRY(iwmmxt_task_restore)
281
282         mrs     ip, cpsr
283         orr     r2, ip, #PSR_I_BIT              @ disable interrupts
284         msr     cpsr_c, r2
285
286         ldr     r3, =concan_owner
287         add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
288         ldr     r3, [r3]                        @ get current Concan owner
289         bic     r2, r2, #0x7                    @ 64-bit alignment
290         teq     r2, r3                          @ does this task own it...
291         beq     1f
292
293         @ this task doesn't own Concan regs -- use its save area
294         msr     cpsr_c, ip                      @ restore interrupt mode
295         mov     r0, r2
296         mov     r2, #MMX_SIZE
297         b       memcpy
298
299 1:      @ this task owns Concan regs -- load them directly
300         mov     r0, r1
301         mov     r1, #0                          @ don't clear CUP/MUP
302         mov     r3, lr                          @ preserve return address
303         bl      concan_load
304         msr     cpsr_c, ip                      @ restore interrupt mode
305         mov     pc, r3
306
307 /*
308  * Concan handling on task switch
309  *
310  * r0 = next thread_info pointer
311  *
312  * Called only from the iwmmxt notifier with task preemption disabled.
313  */
314 ENTRY(iwmmxt_task_switch)
315
316         XSC(mrc p15, 0, r1, c15, c1, 0)
317         PJ4(mrc p15, 0, r1, c1, c0, 2)
318         @ CP0 and CP1 accessible?
319         XSC(tst r1, #0x3)
320         PJ4(tst r1, #0xf)
321         bne     1f                              @ yes: block them for next task
322
323         ldr     r2, =concan_owner
324         add     r3, r0, #TI_IWMMXT_STATE        @ get next task Concan save area
325         ldr     r2, [r2]                        @ get current Concan owner
326         teq     r2, r3                          @ next task owns it?
327         movne   pc, lr                          @ no: leave Concan disabled
328
329 1:      @ flip Concan access
330         XSC(eor r1, r1, #0x3)
331         XSC(mcr p15, 0, r1, c15, c1, 0)
332         PJ4(eor r1, r1, #0xf)
333         PJ4(mcr p15, 0, r1, c1, c0, 2)
334
335         mrc     p15, 0, r1, c2, c0, 0
336         sub     pc, lr, r1, lsr #32             @ cpwait and return
337
338 /*
339  * Remove Concan ownership of given task
340  *
341  * r0 = struct thread_info pointer
342  */
343 ENTRY(iwmmxt_task_release)
344
345         mrs     r2, cpsr
346         orr     ip, r2, #PSR_I_BIT              @ disable interrupts
347         msr     cpsr_c, ip
348         ldr     r3, =concan_owner
349         add     r0, r0, #TI_IWMMXT_STATE        @ get task Concan save area
350         ldr     r1, [r3]                        @ get current Concan owner
351         eors    r0, r0, r1                      @ if equal...
352         streq   r0, [r3]                        @ then clear ownership
353         msr     cpsr_c, r2                      @ restore interrupts
354         mov     pc, lr
355
356         .data
357 concan_owner:
358         .word   0
359