18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Floating-point, VMX/Altivec and VSX loads and stores
48c2ecf20Sopenharmony_ci * for use in instruction emulation.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <asm/processor.h>
108c2ecf20Sopenharmony_ci#include <asm/ppc_asm.h>
118c2ecf20Sopenharmony_ci#include <asm/ppc-opcode.h>
128c2ecf20Sopenharmony_ci#include <asm/reg.h>
138c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h>
148c2ecf20Sopenharmony_ci#include <asm/asm-compat.h>
158c2ecf20Sopenharmony_ci#include <linux/errno.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define STKFRM	(PPC_MIN_STKFRM + 16)
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* Get the contents of frN into *p; N is in r3 and p is in r4. */
208c2ecf20Sopenharmony_ci_GLOBAL(get_fpr)
218c2ecf20Sopenharmony_ci	mflr	r0
228c2ecf20Sopenharmony_ci	mfmsr	r6
238c2ecf20Sopenharmony_ci	ori	r7, r6, MSR_FP
248c2ecf20Sopenharmony_ci	MTMSRD(r7)
258c2ecf20Sopenharmony_ci	isync
268c2ecf20Sopenharmony_ci	rlwinm	r3,r3,3,0xf8
278c2ecf20Sopenharmony_ci	bcl	20,31,1f
288c2ecf20Sopenharmony_cireg = 0
298c2ecf20Sopenharmony_ci	.rept	32
308c2ecf20Sopenharmony_ci	stfd	reg, 0(r4)
318c2ecf20Sopenharmony_ci	b	2f
328c2ecf20Sopenharmony_cireg = reg + 1
338c2ecf20Sopenharmony_ci	.endr
348c2ecf20Sopenharmony_ci1:	mflr	r5
358c2ecf20Sopenharmony_ci	add	r5,r3,r5
368c2ecf20Sopenharmony_ci	mtctr	r5
378c2ecf20Sopenharmony_ci	mtlr	r0
388c2ecf20Sopenharmony_ci	bctr
398c2ecf20Sopenharmony_ci2:	MTMSRD(r6)
408c2ecf20Sopenharmony_ci	isync
418c2ecf20Sopenharmony_ci	blr
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* Put the contents of *p into frN; N is in r3 and p is in r4. */
448c2ecf20Sopenharmony_ci_GLOBAL(put_fpr)
458c2ecf20Sopenharmony_ci	mflr	r0
468c2ecf20Sopenharmony_ci	mfmsr	r6
478c2ecf20Sopenharmony_ci	ori	r7, r6, MSR_FP
488c2ecf20Sopenharmony_ci	MTMSRD(r7)
498c2ecf20Sopenharmony_ci	isync
508c2ecf20Sopenharmony_ci	rlwinm	r3,r3,3,0xf8
518c2ecf20Sopenharmony_ci	bcl	20,31,1f
528c2ecf20Sopenharmony_cireg = 0
538c2ecf20Sopenharmony_ci	.rept	32
548c2ecf20Sopenharmony_ci	lfd	reg, 0(r4)
558c2ecf20Sopenharmony_ci	b	2f
568c2ecf20Sopenharmony_cireg = reg + 1
578c2ecf20Sopenharmony_ci	.endr
588c2ecf20Sopenharmony_ci1:	mflr	r5
598c2ecf20Sopenharmony_ci	add	r5,r3,r5
608c2ecf20Sopenharmony_ci	mtctr	r5
618c2ecf20Sopenharmony_ci	mtlr	r0
628c2ecf20Sopenharmony_ci	bctr
638c2ecf20Sopenharmony_ci2:	MTMSRD(r6)
648c2ecf20Sopenharmony_ci	isync
658c2ecf20Sopenharmony_ci	blr
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC
688c2ecf20Sopenharmony_ci/* Get the contents of vrN into *p; N is in r3 and p is in r4. */
698c2ecf20Sopenharmony_ci_GLOBAL(get_vr)
708c2ecf20Sopenharmony_ci	mflr	r0
718c2ecf20Sopenharmony_ci	mfmsr	r6
728c2ecf20Sopenharmony_ci	oris	r7, r6, MSR_VEC@h
738c2ecf20Sopenharmony_ci	MTMSRD(r7)
748c2ecf20Sopenharmony_ci	isync
758c2ecf20Sopenharmony_ci	rlwinm	r3,r3,3,0xf8
768c2ecf20Sopenharmony_ci	bcl	20,31,1f
778c2ecf20Sopenharmony_cireg = 0
788c2ecf20Sopenharmony_ci	.rept	32
798c2ecf20Sopenharmony_ci	stvx	reg, 0, r4
808c2ecf20Sopenharmony_ci	b	2f
818c2ecf20Sopenharmony_cireg = reg + 1
828c2ecf20Sopenharmony_ci	.endr
838c2ecf20Sopenharmony_ci1:	mflr	r5
848c2ecf20Sopenharmony_ci	add	r5,r3,r5
858c2ecf20Sopenharmony_ci	mtctr	r5
868c2ecf20Sopenharmony_ci	mtlr	r0
878c2ecf20Sopenharmony_ci	bctr
888c2ecf20Sopenharmony_ci2:	MTMSRD(r6)
898c2ecf20Sopenharmony_ci	isync
908c2ecf20Sopenharmony_ci	blr
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/* Put the contents of *p into vrN; N is in r3 and p is in r4. */
938c2ecf20Sopenharmony_ci_GLOBAL(put_vr)
948c2ecf20Sopenharmony_ci	mflr	r0
958c2ecf20Sopenharmony_ci	mfmsr	r6
968c2ecf20Sopenharmony_ci	oris	r7, r6, MSR_VEC@h
978c2ecf20Sopenharmony_ci	MTMSRD(r7)
988c2ecf20Sopenharmony_ci	isync
998c2ecf20Sopenharmony_ci	rlwinm	r3,r3,3,0xf8
1008c2ecf20Sopenharmony_ci	bcl	20,31,1f
1018c2ecf20Sopenharmony_cireg = 0
1028c2ecf20Sopenharmony_ci	.rept	32
1038c2ecf20Sopenharmony_ci	lvx	reg, 0, r4
1048c2ecf20Sopenharmony_ci	b	2f
1058c2ecf20Sopenharmony_cireg = reg + 1
1068c2ecf20Sopenharmony_ci	.endr
1078c2ecf20Sopenharmony_ci1:	mflr	r5
1088c2ecf20Sopenharmony_ci	add	r5,r3,r5
1098c2ecf20Sopenharmony_ci	mtctr	r5
1108c2ecf20Sopenharmony_ci	mtlr	r0
1118c2ecf20Sopenharmony_ci	bctr
1128c2ecf20Sopenharmony_ci2:	MTMSRD(r6)
1138c2ecf20Sopenharmony_ci	isync
1148c2ecf20Sopenharmony_ci	blr
1158c2ecf20Sopenharmony_ci#endif /* CONFIG_ALTIVEC */
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX
1188c2ecf20Sopenharmony_ci/* Get the contents of vsN into vs0; N is in r3. */
1198c2ecf20Sopenharmony_ci_GLOBAL(get_vsr)
1208c2ecf20Sopenharmony_ci	mflr	r0
1218c2ecf20Sopenharmony_ci	rlwinm	r3,r3,3,0x1f8
1228c2ecf20Sopenharmony_ci	bcl	20,31,1f
1238c2ecf20Sopenharmony_ci	blr			/* vs0 is already in vs0 */
1248c2ecf20Sopenharmony_ci	nop
1258c2ecf20Sopenharmony_cireg = 1
1268c2ecf20Sopenharmony_ci	.rept	63
1278c2ecf20Sopenharmony_ci	XXLOR(0,reg,reg)
1288c2ecf20Sopenharmony_ci	blr
1298c2ecf20Sopenharmony_cireg = reg + 1
1308c2ecf20Sopenharmony_ci	.endr
1318c2ecf20Sopenharmony_ci1:	mflr	r5
1328c2ecf20Sopenharmony_ci	add	r5,r3,r5
1338c2ecf20Sopenharmony_ci	mtctr	r5
1348c2ecf20Sopenharmony_ci	mtlr	r0
1358c2ecf20Sopenharmony_ci	bctr
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* Put the contents of vs0 into vsN; N is in r3. */
1388c2ecf20Sopenharmony_ci_GLOBAL(put_vsr)
1398c2ecf20Sopenharmony_ci	mflr	r0
1408c2ecf20Sopenharmony_ci	rlwinm	r3,r3,3,0x1f8
1418c2ecf20Sopenharmony_ci	bcl	20,31,1f
1428c2ecf20Sopenharmony_ci	blr			/* v0 is already in v0 */
1438c2ecf20Sopenharmony_ci	nop
1448c2ecf20Sopenharmony_cireg = 1
1458c2ecf20Sopenharmony_ci	.rept	63
1468c2ecf20Sopenharmony_ci	XXLOR(reg,0,0)
1478c2ecf20Sopenharmony_ci	blr
1488c2ecf20Sopenharmony_cireg = reg + 1
1498c2ecf20Sopenharmony_ci	.endr
1508c2ecf20Sopenharmony_ci1:	mflr	r5
1518c2ecf20Sopenharmony_ci	add	r5,r3,r5
1528c2ecf20Sopenharmony_ci	mtctr	r5
1538c2ecf20Sopenharmony_ci	mtlr	r0
1548c2ecf20Sopenharmony_ci	bctr
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/* Load VSX reg N from vector doubleword *p.  N is in r3, p in r4. */
1578c2ecf20Sopenharmony_ci_GLOBAL(load_vsrn)
1588c2ecf20Sopenharmony_ci	PPC_STLU r1,-STKFRM(r1)
1598c2ecf20Sopenharmony_ci	mflr	r0
1608c2ecf20Sopenharmony_ci	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
1618c2ecf20Sopenharmony_ci	mfmsr	r6
1628c2ecf20Sopenharmony_ci	oris	r7,r6,MSR_VSX@h
1638c2ecf20Sopenharmony_ci	cmpwi	cr7,r3,0
1648c2ecf20Sopenharmony_ci	li	r8,STKFRM-16
1658c2ecf20Sopenharmony_ci	MTMSRD(r7)
1668c2ecf20Sopenharmony_ci	isync
1678c2ecf20Sopenharmony_ci	beq	cr7,1f
1688c2ecf20Sopenharmony_ci	STXVD2X(0,R1,R8)
1698c2ecf20Sopenharmony_ci1:	LXVD2X(0,R0,R4)
1708c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN__
1718c2ecf20Sopenharmony_ci	XXSWAPD(0,0)
1728c2ecf20Sopenharmony_ci#endif
1738c2ecf20Sopenharmony_ci	beq	cr7,4f
1748c2ecf20Sopenharmony_ci	bl	put_vsr
1758c2ecf20Sopenharmony_ci	LXVD2X(0,R1,R8)
1768c2ecf20Sopenharmony_ci4:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
1778c2ecf20Sopenharmony_ci	mtlr	r0
1788c2ecf20Sopenharmony_ci	MTMSRD(r6)
1798c2ecf20Sopenharmony_ci	isync
1808c2ecf20Sopenharmony_ci	addi	r1,r1,STKFRM
1818c2ecf20Sopenharmony_ci	blr
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci/* Store VSX reg N to vector doubleword *p.  N is in r3, p in r4. */
1848c2ecf20Sopenharmony_ci_GLOBAL(store_vsrn)
1858c2ecf20Sopenharmony_ci	PPC_STLU r1,-STKFRM(r1)
1868c2ecf20Sopenharmony_ci	mflr	r0
1878c2ecf20Sopenharmony_ci	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
1888c2ecf20Sopenharmony_ci	mfmsr	r6
1898c2ecf20Sopenharmony_ci	oris	r7,r6,MSR_VSX@h
1908c2ecf20Sopenharmony_ci	li	r8,STKFRM-16
1918c2ecf20Sopenharmony_ci	MTMSRD(r7)
1928c2ecf20Sopenharmony_ci	isync
1938c2ecf20Sopenharmony_ci	STXVD2X(0,R1,R8)
1948c2ecf20Sopenharmony_ci	bl	get_vsr
1958c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN__
1968c2ecf20Sopenharmony_ci	XXSWAPD(0,0)
1978c2ecf20Sopenharmony_ci#endif
1988c2ecf20Sopenharmony_ci	STXVD2X(0,R0,R4)
1998c2ecf20Sopenharmony_ci	LXVD2X(0,R1,R8)
2008c2ecf20Sopenharmony_ci	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
2018c2ecf20Sopenharmony_ci	mtlr	r0
2028c2ecf20Sopenharmony_ci	MTMSRD(r6)
2038c2ecf20Sopenharmony_ci	isync
2048c2ecf20Sopenharmony_ci	mr	r3,r9
2058c2ecf20Sopenharmony_ci	addi	r1,r1,STKFRM
2068c2ecf20Sopenharmony_ci	blr
2078c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/* Convert single-precision to double, without disturbing FPRs. */
2108c2ecf20Sopenharmony_ci/* conv_sp_to_dp(float *sp, double *dp) */
2118c2ecf20Sopenharmony_ci_GLOBAL(conv_sp_to_dp)
2128c2ecf20Sopenharmony_ci	mfmsr	r6
2138c2ecf20Sopenharmony_ci	ori	r7, r6, MSR_FP
2148c2ecf20Sopenharmony_ci	MTMSRD(r7)
2158c2ecf20Sopenharmony_ci	isync
2168c2ecf20Sopenharmony_ci	stfd	fr0, -16(r1)
2178c2ecf20Sopenharmony_ci	lfs	fr0, 0(r3)
2188c2ecf20Sopenharmony_ci	stfd	fr0, 0(r4)
2198c2ecf20Sopenharmony_ci	lfd	fr0, -16(r1)
2208c2ecf20Sopenharmony_ci	MTMSRD(r6)
2218c2ecf20Sopenharmony_ci	isync
2228c2ecf20Sopenharmony_ci	blr
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/* Convert single-precision to double, without disturbing FPRs. */
2258c2ecf20Sopenharmony_ci/* conv_sp_to_dp(double *dp, float *sp) */
2268c2ecf20Sopenharmony_ci_GLOBAL(conv_dp_to_sp)
2278c2ecf20Sopenharmony_ci	mfmsr	r6
2288c2ecf20Sopenharmony_ci	ori	r7, r6, MSR_FP
2298c2ecf20Sopenharmony_ci	MTMSRD(r7)
2308c2ecf20Sopenharmony_ci	isync
2318c2ecf20Sopenharmony_ci	stfd	fr0, -16(r1)
2328c2ecf20Sopenharmony_ci	lfd	fr0, 0(r3)
2338c2ecf20Sopenharmony_ci	stfs	fr0, 0(r4)
2348c2ecf20Sopenharmony_ci	lfd	fr0, -16(r1)
2358c2ecf20Sopenharmony_ci	MTMSRD(r6)
2368c2ecf20Sopenharmony_ci	isync
2378c2ecf20Sopenharmony_ci	blr
238