1/*
2 *  FPU helper code to use FPU operations from inside the kernel
3 *
4 *    Copyright (C) 2010 Alexander Graf (agraf@suse.de)
5 *
6 *  This program is free software; you can redistribute it and/or
7 *  modify it under the terms of the GNU General Public License
8 *  as published by the Free Software Foundation; either version
9 *  2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <asm/reg.h>
14#include <asm/page.h>
15#include <asm/mmu.h>
16#include <asm/pgtable.h>
17#include <asm/cputable.h>
18#include <asm/cache.h>
19#include <asm/thread_info.h>
20#include <asm/ppc_asm.h>
21#include <asm/asm-offsets.h>
22
23/* Instructions operating on single parameters */
24
25/*
26 * Single operation with one input operand
27 *
28 * R3 = (double*)&fpscr
29 * R4 = (short*)&result
30 * R5 = (short*)&param1
31 */
32#define FPS_ONE_IN(name) 					\
33_GLOBAL(fps_ ## name);							\
34	lfd	0,0(r3);		/* load up fpscr value */	\
35	MTFSF_L(0);							\
36	lfs	0,0(r5);						\
37									\
38	name	0,0;							\
39									\
40	stfs	0,0(r4);						\
41	mffs	0;							\
42	stfd	0,0(r3);	/* save new fpscr value */	\
43	blr
44
45/*
46 * Single operation with two input operands
47 *
48 * R3 = (double*)&fpscr
49 * R4 = (short*)&result
50 * R5 = (short*)&param1
51 * R6 = (short*)&param2
52 */
53#define FPS_TWO_IN(name) 					\
54_GLOBAL(fps_ ## name);							\
55	lfd	0,0(r3);		/* load up fpscr value */	\
56	MTFSF_L(0);							\
57	lfs	0,0(r5);						\
58	lfs	1,0(r6);						\
59									\
60	name	0,0,1;							\
61									\
62	stfs	0,0(r4);						\
63	mffs	0;							\
64	stfd	0,0(r3);		/* save new fpscr value */	\
65	blr
66
67/*
68 * Single operation with three input operands
69 *
70 * R3 = (double*)&fpscr
71 * R4 = (short*)&result
72 * R5 = (short*)&param1
73 * R6 = (short*)&param2
74 * R7 = (short*)&param3
75 */
76#define FPS_THREE_IN(name) 					\
77_GLOBAL(fps_ ## name);							\
78	lfd	0,0(r3);		/* load up fpscr value */	\
79	MTFSF_L(0);							\
80	lfs	0,0(r5);						\
81	lfs	1,0(r6);						\
82	lfs	2,0(r7);						\
83									\
84	name	0,0,1,2;						\
85									\
86	stfs	0,0(r4);						\
87	mffs	0;							\
88	stfd	0,0(r3);		/* save new fpscr value */	\
89	blr
90
91FPS_ONE_IN(fres)
92FPS_ONE_IN(frsqrte)
93FPS_ONE_IN(fsqrts)
94FPS_TWO_IN(fadds)
95FPS_TWO_IN(fdivs)
96FPS_TWO_IN(fmuls)
97FPS_TWO_IN(fsubs)
98FPS_THREE_IN(fmadds)
99FPS_THREE_IN(fmsubs)
100FPS_THREE_IN(fnmadds)
101FPS_THREE_IN(fnmsubs)
102FPS_THREE_IN(fsel)
103
104
105/* Instructions operating on double parameters */
106
107/*
108 * Beginning of double instruction processing
109 *
110 * R3 = (double*)&fpscr
111 * R4 = (u32*)&cr
112 * R5 = (double*)&result
113 * R6 = (double*)&param1
114 * R7 = (double*)&param2 [load_two]
115 * R8 = (double*)&param3 [load_three]
116 * LR = instruction call function
117 */
118fpd_load_three:
119	lfd	2,0(r8)			/* load param3 */
120fpd_load_two:
121	lfd	1,0(r7)			/* load param2 */
122fpd_load_one:
123	lfd	0,0(r6)			/* load param1 */
124fpd_load_none:
125	lfd	3,0(r3)			/* load up fpscr value */
126	MTFSF_L(3)
127	lwz	r6, 0(r4)		/* load cr */
128	mtcr	r6
129	blr
130
131/*
132 * End of double instruction processing
133 *
134 * R3 = (double*)&fpscr
135 * R4 = (u32*)&cr
136 * R5 = (double*)&result
137 * LR = caller of instruction call function
138 */
139fpd_return:
140	mfcr	r6
141	stfd	0,0(r5)			/* save result */
142	mffs	0
143	stfd	0,0(r3)			/* save new fpscr value */
144	stw	r6,0(r4)		/* save new cr value */
145	blr
146
147/*
148 * Double operation with no input operand
149 *
150 * R3 = (double*)&fpscr
151 * R4 = (u32*)&cr
152 * R5 = (double*)&result
153 */
154#define FPD_NONE_IN(name) 						\
155_GLOBAL(fpd_ ## name);							\
156	mflr	r12;							\
157	bl	fpd_load_none;						\
158	mtlr	r12;							\
159									\
160	name.	0;			/* call instruction */		\
161	b	fpd_return
162
163/*
164 * Double operation with one input operand
165 *
166 * R3 = (double*)&fpscr
167 * R4 = (u32*)&cr
168 * R5 = (double*)&result
169 * R6 = (double*)&param1
170 */
171#define FPD_ONE_IN(name) 						\
172_GLOBAL(fpd_ ## name);							\
173	mflr	r12;							\
174	bl	fpd_load_one;						\
175	mtlr	r12;							\
176									\
177	name.	0,0;			/* call instruction */		\
178	b	fpd_return
179
180/*
181 * Double operation with two input operands
182 *
183 * R3 = (double*)&fpscr
184 * R4 = (u32*)&cr
185 * R5 = (double*)&result
186 * R6 = (double*)&param1
187 * R7 = (double*)&param2
188 * R8 = (double*)&param3
189 */
190#define FPD_TWO_IN(name) 						\
191_GLOBAL(fpd_ ## name);							\
192	mflr	r12;							\
193	bl	fpd_load_two;						\
194	mtlr	r12;							\
195									\
196	name.	0,0,1;			/* call instruction */		\
197	b	fpd_return
198
199/*
200 * CR Double operation with two input operands
201 *
202 * R3 = (double*)&fpscr
203 * R4 = (u32*)&cr
204 * R5 = (double*)&param1
205 * R6 = (double*)&param2
206 * R7 = (double*)&param3
207 */
208#define FPD_TWO_IN_CR(name)						\
209_GLOBAL(fpd_ ## name);							\
210	lfd	1,0(r6);		/* load param2 */		\
211	lfd	0,0(r5);		/* load param1 */		\
212	lfd	3,0(r3);		/* load up fpscr value */	\
213	MTFSF_L(3);							\
214	lwz	r6, 0(r4);		/* load cr */			\
215	mtcr	r6;							\
216									\
217	name	0,0,1;			/* call instruction */		\
218	mfcr	r6;							\
219	mffs	0;							\
220	stfd	0,0(r3);		/* save new fpscr value */	\
221	stw	r6,0(r4);		/* save new cr value */		\
222	blr
223
224/*
225 * Double operation with three input operands
226 *
227 * R3 = (double*)&fpscr
228 * R4 = (u32*)&cr
229 * R5 = (double*)&result
230 * R6 = (double*)&param1
231 * R7 = (double*)&param2
232 * R8 = (double*)&param3
233 */
234#define FPD_THREE_IN(name) 						\
235_GLOBAL(fpd_ ## name);							\
236	mflr	r12;							\
237	bl	fpd_load_three;						\
238	mtlr	r12;							\
239									\
240	name.	0,0,1,2;		/* call instruction */		\
241	b	fpd_return
242
243FPD_ONE_IN(fsqrts)
244FPD_ONE_IN(frsqrtes)
245FPD_ONE_IN(fres)
246FPD_ONE_IN(frsp)
247FPD_ONE_IN(fctiw)
248FPD_ONE_IN(fctiwz)
249FPD_ONE_IN(fsqrt)
250FPD_ONE_IN(fre)
251FPD_ONE_IN(frsqrte)
252FPD_ONE_IN(fneg)
253FPD_ONE_IN(fabs)
254FPD_TWO_IN(fadds)
255FPD_TWO_IN(fsubs)
256FPD_TWO_IN(fdivs)
257FPD_TWO_IN(fmuls)
258FPD_TWO_IN_CR(fcmpu)
259FPD_TWO_IN(fcpsgn)
260FPD_TWO_IN(fdiv)
261FPD_TWO_IN(fadd)
262FPD_TWO_IN(fmul)
263FPD_TWO_IN_CR(fcmpo)
264FPD_TWO_IN(fsub)
265FPD_THREE_IN(fmsubs)
266FPD_THREE_IN(fmadds)
267FPD_THREE_IN(fnmsubs)
268FPD_THREE_IN(fnmadds)
269FPD_THREE_IN(fsel)
270FPD_THREE_IN(fmsub)
271FPD_THREE_IN(fmadd)
272FPD_THREE_IN(fnmsub)
273FPD_THREE_IN(fnmadd)
274
275_GLOBAL(kvm_cvt_fd)
276	lfs	0,0(r3)
277	stfd	0,0(r4)
278	blr
279
280_GLOBAL(kvm_cvt_df)
281	lfd	0,0(r3)
282	stfs	0,0(r4)
283	blr
284