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