162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Floating-point, VMX/Altivec and VSX loads and stores
462306a36Sopenharmony_ci * for use in instruction emulation.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <asm/processor.h>
1062306a36Sopenharmony_ci#include <asm/ppc_asm.h>
1162306a36Sopenharmony_ci#include <asm/ppc-opcode.h>
1262306a36Sopenharmony_ci#include <asm/reg.h>
1362306a36Sopenharmony_ci#include <asm/asm-offsets.h>
1462306a36Sopenharmony_ci#include <asm/asm-compat.h>
1562306a36Sopenharmony_ci#include <linux/errno.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define STKFRM	(PPC_MIN_STKFRM + 16)
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* Get the contents of frN into *p; N is in r3 and p is in r4. */
2062306a36Sopenharmony_ci_GLOBAL(get_fpr)
2162306a36Sopenharmony_ci	mflr	r0
2262306a36Sopenharmony_ci	mfmsr	r6
2362306a36Sopenharmony_ci	ori	r7, r6, MSR_FP
2462306a36Sopenharmony_ci	MTMSRD(r7)
2562306a36Sopenharmony_ci	isync
2662306a36Sopenharmony_ci	rlwinm	r3,r3,3,0xf8
2762306a36Sopenharmony_ci	bcl	20,31,1f
2862306a36Sopenharmony_cireg = 0
2962306a36Sopenharmony_ci	.rept	32
3062306a36Sopenharmony_ci	stfd	reg, 0(r4)
3162306a36Sopenharmony_ci	b	2f
3262306a36Sopenharmony_cireg = reg + 1
3362306a36Sopenharmony_ci	.endr
3462306a36Sopenharmony_ci1:	mflr	r5
3562306a36Sopenharmony_ci	add	r5,r3,r5
3662306a36Sopenharmony_ci	mtctr	r5
3762306a36Sopenharmony_ci	mtlr	r0
3862306a36Sopenharmony_ci	bctr
3962306a36Sopenharmony_ci2:	MTMSRD(r6)
4062306a36Sopenharmony_ci	isync
4162306a36Sopenharmony_ci	blr
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* Put the contents of *p into frN; N is in r3 and p is in r4. */
4462306a36Sopenharmony_ci_GLOBAL(put_fpr)
4562306a36Sopenharmony_ci	mflr	r0
4662306a36Sopenharmony_ci	mfmsr	r6
4762306a36Sopenharmony_ci	ori	r7, r6, MSR_FP
4862306a36Sopenharmony_ci	MTMSRD(r7)
4962306a36Sopenharmony_ci	isync
5062306a36Sopenharmony_ci	rlwinm	r3,r3,3,0xf8
5162306a36Sopenharmony_ci	bcl	20,31,1f
5262306a36Sopenharmony_cireg = 0
5362306a36Sopenharmony_ci	.rept	32
5462306a36Sopenharmony_ci	lfd	reg, 0(r4)
5562306a36Sopenharmony_ci	b	2f
5662306a36Sopenharmony_cireg = reg + 1
5762306a36Sopenharmony_ci	.endr
5862306a36Sopenharmony_ci1:	mflr	r5
5962306a36Sopenharmony_ci	add	r5,r3,r5
6062306a36Sopenharmony_ci	mtctr	r5
6162306a36Sopenharmony_ci	mtlr	r0
6262306a36Sopenharmony_ci	bctr
6362306a36Sopenharmony_ci2:	MTMSRD(r6)
6462306a36Sopenharmony_ci	isync
6562306a36Sopenharmony_ci	blr
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC
6862306a36Sopenharmony_ci/* Get the contents of vrN into *p; N is in r3 and p is in r4. */
6962306a36Sopenharmony_ci_GLOBAL(get_vr)
7062306a36Sopenharmony_ci	mflr	r0
7162306a36Sopenharmony_ci	mfmsr	r6
7262306a36Sopenharmony_ci	oris	r7, r6, MSR_VEC@h
7362306a36Sopenharmony_ci	MTMSRD(r7)
7462306a36Sopenharmony_ci	isync
7562306a36Sopenharmony_ci	rlwinm	r3,r3,3,0xf8
7662306a36Sopenharmony_ci	bcl	20,31,1f
7762306a36Sopenharmony_cireg = 0
7862306a36Sopenharmony_ci	.rept	32
7962306a36Sopenharmony_ci	stvx	reg, 0, r4
8062306a36Sopenharmony_ci	b	2f
8162306a36Sopenharmony_cireg = reg + 1
8262306a36Sopenharmony_ci	.endr
8362306a36Sopenharmony_ci1:	mflr	r5
8462306a36Sopenharmony_ci	add	r5,r3,r5
8562306a36Sopenharmony_ci	mtctr	r5
8662306a36Sopenharmony_ci	mtlr	r0
8762306a36Sopenharmony_ci	bctr
8862306a36Sopenharmony_ci2:	MTMSRD(r6)
8962306a36Sopenharmony_ci	isync
9062306a36Sopenharmony_ci	blr
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* Put the contents of *p into vrN; N is in r3 and p is in r4. */
9362306a36Sopenharmony_ci_GLOBAL(put_vr)
9462306a36Sopenharmony_ci	mflr	r0
9562306a36Sopenharmony_ci	mfmsr	r6
9662306a36Sopenharmony_ci	oris	r7, r6, MSR_VEC@h
9762306a36Sopenharmony_ci	MTMSRD(r7)
9862306a36Sopenharmony_ci	isync
9962306a36Sopenharmony_ci	rlwinm	r3,r3,3,0xf8
10062306a36Sopenharmony_ci	bcl	20,31,1f
10162306a36Sopenharmony_cireg = 0
10262306a36Sopenharmony_ci	.rept	32
10362306a36Sopenharmony_ci	lvx	reg, 0, r4
10462306a36Sopenharmony_ci	b	2f
10562306a36Sopenharmony_cireg = reg + 1
10662306a36Sopenharmony_ci	.endr
10762306a36Sopenharmony_ci1:	mflr	r5
10862306a36Sopenharmony_ci	add	r5,r3,r5
10962306a36Sopenharmony_ci	mtctr	r5
11062306a36Sopenharmony_ci	mtlr	r0
11162306a36Sopenharmony_ci	bctr
11262306a36Sopenharmony_ci2:	MTMSRD(r6)
11362306a36Sopenharmony_ci	isync
11462306a36Sopenharmony_ci	blr
11562306a36Sopenharmony_ci#endif /* CONFIG_ALTIVEC */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#ifdef CONFIG_VSX
11862306a36Sopenharmony_ci/* Get the contents of vsN into vs0; N is in r3. */
11962306a36Sopenharmony_ci_GLOBAL(get_vsr)
12062306a36Sopenharmony_ci	mflr	r0
12162306a36Sopenharmony_ci	rlwinm	r3,r3,3,0x1f8
12262306a36Sopenharmony_ci	bcl	20,31,1f
12362306a36Sopenharmony_ci	blr			/* vs0 is already in vs0 */
12462306a36Sopenharmony_ci	nop
12562306a36Sopenharmony_cireg = 1
12662306a36Sopenharmony_ci	.rept	63
12762306a36Sopenharmony_ci	XXLOR(0,reg,reg)
12862306a36Sopenharmony_ci	blr
12962306a36Sopenharmony_cireg = reg + 1
13062306a36Sopenharmony_ci	.endr
13162306a36Sopenharmony_ci1:	mflr	r5
13262306a36Sopenharmony_ci	add	r5,r3,r5
13362306a36Sopenharmony_ci	mtctr	r5
13462306a36Sopenharmony_ci	mtlr	r0
13562306a36Sopenharmony_ci	bctr
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/* Put the contents of vs0 into vsN; N is in r3. */
13862306a36Sopenharmony_ci_GLOBAL(put_vsr)
13962306a36Sopenharmony_ci	mflr	r0
14062306a36Sopenharmony_ci	rlwinm	r3,r3,3,0x1f8
14162306a36Sopenharmony_ci	bcl	20,31,1f
14262306a36Sopenharmony_ci	blr			/* v0 is already in v0 */
14362306a36Sopenharmony_ci	nop
14462306a36Sopenharmony_cireg = 1
14562306a36Sopenharmony_ci	.rept	63
14662306a36Sopenharmony_ci	XXLOR(reg,0,0)
14762306a36Sopenharmony_ci	blr
14862306a36Sopenharmony_cireg = reg + 1
14962306a36Sopenharmony_ci	.endr
15062306a36Sopenharmony_ci1:	mflr	r5
15162306a36Sopenharmony_ci	add	r5,r3,r5
15262306a36Sopenharmony_ci	mtctr	r5
15362306a36Sopenharmony_ci	mtlr	r0
15462306a36Sopenharmony_ci	bctr
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/* Load VSX reg N from vector doubleword *p.  N is in r3, p in r4. */
15762306a36Sopenharmony_ci_GLOBAL(load_vsrn)
15862306a36Sopenharmony_ci	PPC_STLU r1,-STKFRM(r1)
15962306a36Sopenharmony_ci	mflr	r0
16062306a36Sopenharmony_ci	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
16162306a36Sopenharmony_ci	mfmsr	r6
16262306a36Sopenharmony_ci	oris	r7,r6,MSR_VSX@h
16362306a36Sopenharmony_ci	cmpwi	cr7,r3,0
16462306a36Sopenharmony_ci	li	r8,STKFRM-16
16562306a36Sopenharmony_ci	MTMSRD(r7)
16662306a36Sopenharmony_ci	isync
16762306a36Sopenharmony_ci	beq	cr7,1f
16862306a36Sopenharmony_ci	STXVD2X(0,R1,R8)
16962306a36Sopenharmony_ci1:	LXVD2X(0,R0,R4)
17062306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__
17162306a36Sopenharmony_ci	XXSWAPD(0,0)
17262306a36Sopenharmony_ci#endif
17362306a36Sopenharmony_ci	beq	cr7,4f
17462306a36Sopenharmony_ci	bl	put_vsr
17562306a36Sopenharmony_ci	LXVD2X(0,R1,R8)
17662306a36Sopenharmony_ci4:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
17762306a36Sopenharmony_ci	mtlr	r0
17862306a36Sopenharmony_ci	MTMSRD(r6)
17962306a36Sopenharmony_ci	isync
18062306a36Sopenharmony_ci	addi	r1,r1,STKFRM
18162306a36Sopenharmony_ci	blr
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/* Store VSX reg N to vector doubleword *p.  N is in r3, p in r4. */
18462306a36Sopenharmony_ci_GLOBAL(store_vsrn)
18562306a36Sopenharmony_ci	PPC_STLU r1,-STKFRM(r1)
18662306a36Sopenharmony_ci	mflr	r0
18762306a36Sopenharmony_ci	PPC_STL	r0,STKFRM+PPC_LR_STKOFF(r1)
18862306a36Sopenharmony_ci	mfmsr	r6
18962306a36Sopenharmony_ci	oris	r7,r6,MSR_VSX@h
19062306a36Sopenharmony_ci	li	r8,STKFRM-16
19162306a36Sopenharmony_ci	MTMSRD(r7)
19262306a36Sopenharmony_ci	isync
19362306a36Sopenharmony_ci	STXVD2X(0,R1,R8)
19462306a36Sopenharmony_ci	bl	get_vsr
19562306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__
19662306a36Sopenharmony_ci	XXSWAPD(0,0)
19762306a36Sopenharmony_ci#endif
19862306a36Sopenharmony_ci	STXVD2X(0,R0,R4)
19962306a36Sopenharmony_ci	LXVD2X(0,R1,R8)
20062306a36Sopenharmony_ci	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
20162306a36Sopenharmony_ci	mtlr	r0
20262306a36Sopenharmony_ci	MTMSRD(r6)
20362306a36Sopenharmony_ci	isync
20462306a36Sopenharmony_ci	mr	r3,r9
20562306a36Sopenharmony_ci	addi	r1,r1,STKFRM
20662306a36Sopenharmony_ci	blr
20762306a36Sopenharmony_ci#endif /* CONFIG_VSX */
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci/* Convert single-precision to double, without disturbing FPRs. */
21062306a36Sopenharmony_ci/* conv_sp_to_dp(float *sp, double *dp) */
21162306a36Sopenharmony_ci_GLOBAL(conv_sp_to_dp)
21262306a36Sopenharmony_ci	mfmsr	r6
21362306a36Sopenharmony_ci	ori	r7, r6, MSR_FP
21462306a36Sopenharmony_ci	MTMSRD(r7)
21562306a36Sopenharmony_ci	isync
21662306a36Sopenharmony_ci	stfd	fr0, -16(r1)
21762306a36Sopenharmony_ci	lfs	fr0, 0(r3)
21862306a36Sopenharmony_ci	stfd	fr0, 0(r4)
21962306a36Sopenharmony_ci	lfd	fr0, -16(r1)
22062306a36Sopenharmony_ci	MTMSRD(r6)
22162306a36Sopenharmony_ci	isync
22262306a36Sopenharmony_ci	blr
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci/* Convert single-precision to double, without disturbing FPRs. */
22562306a36Sopenharmony_ci/* conv_sp_to_dp(double *dp, float *sp) */
22662306a36Sopenharmony_ci_GLOBAL(conv_dp_to_sp)
22762306a36Sopenharmony_ci	mfmsr	r6
22862306a36Sopenharmony_ci	ori	r7, r6, MSR_FP
22962306a36Sopenharmony_ci	MTMSRD(r7)
23062306a36Sopenharmony_ci	isync
23162306a36Sopenharmony_ci	stfd	fr0, -16(r1)
23262306a36Sopenharmony_ci	lfd	fr0, 0(r3)
23362306a36Sopenharmony_ci	stfs	fr0, 0(r4)
23462306a36Sopenharmony_ci	lfd	fr0, -16(r1)
23562306a36Sopenharmony_ci	MTMSRD(r6)
23662306a36Sopenharmony_ci	isync
23762306a36Sopenharmony_ci	blr
238