18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2013 Imagination Technologies
48c2ecf20Sopenharmony_ci * Author: Paul Burton <paul.burton@mips.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#ifndef _ASM_MSA_H
78c2ecf20Sopenharmony_ci#define _ASM_MSA_H
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <asm/mipsregs.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <asm/inst.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciextern void _save_msa(struct task_struct *);
168c2ecf20Sopenharmony_ciextern void _restore_msa(struct task_struct *);
178c2ecf20Sopenharmony_ciextern void _init_msa_upper(void);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciextern void read_msa_wr_b(unsigned idx, union fpureg *to);
208c2ecf20Sopenharmony_ciextern void read_msa_wr_h(unsigned idx, union fpureg *to);
218c2ecf20Sopenharmony_ciextern void read_msa_wr_w(unsigned idx, union fpureg *to);
228c2ecf20Sopenharmony_ciextern void read_msa_wr_d(unsigned idx, union fpureg *to);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/**
258c2ecf20Sopenharmony_ci * read_msa_wr() - Read a single MSA vector register
268c2ecf20Sopenharmony_ci * @idx:	The index of the vector register to read
278c2ecf20Sopenharmony_ci * @to:		The FPU register union to store the registers value in
288c2ecf20Sopenharmony_ci * @fmt:	The format of the data in the vector register
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * Read the value of MSA vector register idx into the FPU register
318c2ecf20Sopenharmony_ci * union to, using the format fmt.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_cistatic inline void read_msa_wr(unsigned idx, union fpureg *to,
348c2ecf20Sopenharmony_ci			       enum msa_2b_fmt fmt)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	switch (fmt) {
378c2ecf20Sopenharmony_ci	case msa_fmt_b:
388c2ecf20Sopenharmony_ci		read_msa_wr_b(idx, to);
398c2ecf20Sopenharmony_ci		break;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	case msa_fmt_h:
428c2ecf20Sopenharmony_ci		read_msa_wr_h(idx, to);
438c2ecf20Sopenharmony_ci		break;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	case msa_fmt_w:
468c2ecf20Sopenharmony_ci		read_msa_wr_w(idx, to);
478c2ecf20Sopenharmony_ci		break;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	case msa_fmt_d:
508c2ecf20Sopenharmony_ci		read_msa_wr_d(idx, to);
518c2ecf20Sopenharmony_ci		break;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	default:
548c2ecf20Sopenharmony_ci		BUG();
558c2ecf20Sopenharmony_ci	}
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ciextern void write_msa_wr_b(unsigned idx, union fpureg *from);
598c2ecf20Sopenharmony_ciextern void write_msa_wr_h(unsigned idx, union fpureg *from);
608c2ecf20Sopenharmony_ciextern void write_msa_wr_w(unsigned idx, union fpureg *from);
618c2ecf20Sopenharmony_ciextern void write_msa_wr_d(unsigned idx, union fpureg *from);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/**
648c2ecf20Sopenharmony_ci * write_msa_wr() - Write a single MSA vector register
658c2ecf20Sopenharmony_ci * @idx:	The index of the vector register to write
668c2ecf20Sopenharmony_ci * @from:	The FPU register union to take the registers value from
678c2ecf20Sopenharmony_ci * @fmt:	The format of the data in the vector register
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * Write the value from the FPU register union from into MSA vector
708c2ecf20Sopenharmony_ci * register idx, using the format fmt.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_cistatic inline void write_msa_wr(unsigned idx, union fpureg *from,
738c2ecf20Sopenharmony_ci				enum msa_2b_fmt fmt)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	switch (fmt) {
768c2ecf20Sopenharmony_ci	case msa_fmt_b:
778c2ecf20Sopenharmony_ci		write_msa_wr_b(idx, from);
788c2ecf20Sopenharmony_ci		break;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	case msa_fmt_h:
818c2ecf20Sopenharmony_ci		write_msa_wr_h(idx, from);
828c2ecf20Sopenharmony_ci		break;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	case msa_fmt_w:
858c2ecf20Sopenharmony_ci		write_msa_wr_w(idx, from);
868c2ecf20Sopenharmony_ci		break;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	case msa_fmt_d:
898c2ecf20Sopenharmony_ci		write_msa_wr_d(idx, from);
908c2ecf20Sopenharmony_ci		break;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	default:
938c2ecf20Sopenharmony_ci		BUG();
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic inline void enable_msa(void)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	if (cpu_has_msa) {
1008c2ecf20Sopenharmony_ci		set_c0_config5(MIPS_CONF5_MSAEN);
1018c2ecf20Sopenharmony_ci		enable_fpu_hazard();
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic inline void disable_msa(void)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	if (cpu_has_msa) {
1088c2ecf20Sopenharmony_ci		clear_c0_config5(MIPS_CONF5_MSAEN);
1098c2ecf20Sopenharmony_ci		disable_fpu_hazard();
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic inline int is_msa_enabled(void)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	if (!cpu_has_msa)
1168c2ecf20Sopenharmony_ci		return 0;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return read_c0_config5() & MIPS_CONF5_MSAEN;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic inline int thread_msa_context_live(void)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	/*
1248c2ecf20Sopenharmony_ci	 * Check cpu_has_msa only if it's a constant. This will allow the
1258c2ecf20Sopenharmony_ci	 * compiler to optimise out code for CPUs without MSA without adding
1268c2ecf20Sopenharmony_ci	 * an extra redundant check for CPUs with MSA.
1278c2ecf20Sopenharmony_ci	 */
1288c2ecf20Sopenharmony_ci	if (__builtin_constant_p(cpu_has_msa) && !cpu_has_msa)
1298c2ecf20Sopenharmony_ci		return 0;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return test_thread_flag(TIF_MSA_CTX_LIVE);
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic inline void save_msa(struct task_struct *t)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	if (cpu_has_msa)
1378c2ecf20Sopenharmony_ci		_save_msa(t);
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic inline void restore_msa(struct task_struct *t)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	if (cpu_has_msa)
1438c2ecf20Sopenharmony_ci		_restore_msa(t);
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic inline void init_msa_upper(void)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	/*
1498c2ecf20Sopenharmony_ci	 * Check cpu_has_msa only if it's a constant. This will allow the
1508c2ecf20Sopenharmony_ci	 * compiler to optimise out code for CPUs without MSA without adding
1518c2ecf20Sopenharmony_ci	 * an extra redundant check for CPUs with MSA.
1528c2ecf20Sopenharmony_ci	 */
1538c2ecf20Sopenharmony_ci	if (__builtin_constant_p(cpu_has_msa) && !cpu_has_msa)
1548c2ecf20Sopenharmony_ci		return;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	_init_msa_upper();
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci#ifndef TOOLCHAIN_SUPPORTS_MSA
1608c2ecf20Sopenharmony_ci/*
1618c2ecf20Sopenharmony_ci * Define assembler macros using .word for the c[ft]cmsa instructions in order
1628c2ecf20Sopenharmony_ci * to allow compilation with toolchains that do not support MSA. Once all
1638c2ecf20Sopenharmony_ci * toolchains in use support MSA these can be removed.
1648c2ecf20Sopenharmony_ci */
1658c2ecf20Sopenharmony_ci_ASM_MACRO_2R(cfcmsa, rd, cs,
1668c2ecf20Sopenharmony_ci	_ASM_INSN_IF_MIPS(0x787e0019 | __cs << 11 | __rd << 6)
1678c2ecf20Sopenharmony_ci	_ASM_INSN32_IF_MM(0x587e0016 | __cs << 11 | __rd << 6));
1688c2ecf20Sopenharmony_ci_ASM_MACRO_2R(ctcmsa, cd, rs,
1698c2ecf20Sopenharmony_ci	_ASM_INSN_IF_MIPS(0x783e0019 | __rs << 11 | __cd << 6)
1708c2ecf20Sopenharmony_ci	_ASM_INSN32_IF_MM(0x583e0016 | __rs << 11 | __cd << 6));
1718c2ecf20Sopenharmony_ci#define _ASM_SET_MSA ""
1728c2ecf20Sopenharmony_ci#else /* TOOLCHAIN_SUPPORTS_MSA */
1738c2ecf20Sopenharmony_ci#define _ASM_SET_MSA ".set\tfp=64\n\t"				\
1748c2ecf20Sopenharmony_ci		     ".set\tmsa\n\t"
1758c2ecf20Sopenharmony_ci#endif
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci#define __BUILD_MSA_CTL_REG(name, cs)				\
1788c2ecf20Sopenharmony_cistatic inline unsigned int read_msa_##name(void)		\
1798c2ecf20Sopenharmony_ci{								\
1808c2ecf20Sopenharmony_ci	unsigned int reg;					\
1818c2ecf20Sopenharmony_ci	__asm__ __volatile__(					\
1828c2ecf20Sopenharmony_ci	"	.set	push\n"					\
1838c2ecf20Sopenharmony_ci	_ASM_SET_MSA						\
1848c2ecf20Sopenharmony_ci	"	cfcmsa	%0, $" #cs "\n"				\
1858c2ecf20Sopenharmony_ci	"	.set	pop\n"					\
1868c2ecf20Sopenharmony_ci	: "=r"(reg));						\
1878c2ecf20Sopenharmony_ci	return reg;						\
1888c2ecf20Sopenharmony_ci}								\
1898c2ecf20Sopenharmony_ci								\
1908c2ecf20Sopenharmony_cistatic inline void write_msa_##name(unsigned int val)		\
1918c2ecf20Sopenharmony_ci{								\
1928c2ecf20Sopenharmony_ci	__asm__ __volatile__(					\
1938c2ecf20Sopenharmony_ci	"	.set	push\n"					\
1948c2ecf20Sopenharmony_ci	_ASM_SET_MSA						\
1958c2ecf20Sopenharmony_ci	"	ctcmsa	$" #cs ", %0\n"				\
1968c2ecf20Sopenharmony_ci	"	.set	pop\n"					\
1978c2ecf20Sopenharmony_ci	: : "r"(val));						\
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci__BUILD_MSA_CTL_REG(ir, 0)
2018c2ecf20Sopenharmony_ci__BUILD_MSA_CTL_REG(csr, 1)
2028c2ecf20Sopenharmony_ci__BUILD_MSA_CTL_REG(access, 2)
2038c2ecf20Sopenharmony_ci__BUILD_MSA_CTL_REG(save, 3)
2048c2ecf20Sopenharmony_ci__BUILD_MSA_CTL_REG(modify, 4)
2058c2ecf20Sopenharmony_ci__BUILD_MSA_CTL_REG(request, 5)
2068c2ecf20Sopenharmony_ci__BUILD_MSA_CTL_REG(map, 6)
2078c2ecf20Sopenharmony_ci__BUILD_MSA_CTL_REG(unmap, 7)
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci#define MSA_IR		0
2128c2ecf20Sopenharmony_ci#define MSA_CSR		1
2138c2ecf20Sopenharmony_ci#define MSA_ACCESS	2
2148c2ecf20Sopenharmony_ci#define MSA_SAVE	3
2158c2ecf20Sopenharmony_ci#define MSA_MODIFY	4
2168c2ecf20Sopenharmony_ci#define MSA_REQUEST	5
2178c2ecf20Sopenharmony_ci#define MSA_MAP		6
2188c2ecf20Sopenharmony_ci#define MSA_UNMAP	7
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/* MSA Implementation Register (MSAIR) */
2218c2ecf20Sopenharmony_ci#define MSA_IR_REVB		0
2228c2ecf20Sopenharmony_ci#define MSA_IR_REVF		(_ULCAST_(0xff) << MSA_IR_REVB)
2238c2ecf20Sopenharmony_ci#define MSA_IR_PROCB		8
2248c2ecf20Sopenharmony_ci#define MSA_IR_PROCF		(_ULCAST_(0xff) << MSA_IR_PROCB)
2258c2ecf20Sopenharmony_ci#define MSA_IR_WRPB		16
2268c2ecf20Sopenharmony_ci#define MSA_IR_WRPF		(_ULCAST_(0x1) << MSA_IR_WRPB)
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci/* MSA Control & Status Register (MSACSR) */
2298c2ecf20Sopenharmony_ci#define MSA_CSR_RMB		0
2308c2ecf20Sopenharmony_ci#define MSA_CSR_RMF		(_ULCAST_(0x3) << MSA_CSR_RMB)
2318c2ecf20Sopenharmony_ci#define MSA_CSR_RM_NEAREST	0
2328c2ecf20Sopenharmony_ci#define MSA_CSR_RM_TO_ZERO	1
2338c2ecf20Sopenharmony_ci#define MSA_CSR_RM_TO_POS	2
2348c2ecf20Sopenharmony_ci#define MSA_CSR_RM_TO_NEG	3
2358c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGSB		2
2368c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGSF		(_ULCAST_(0x1f) << MSA_CSR_FLAGSB)
2378c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGS_IB	2
2388c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGS_IF	(_ULCAST_(0x1) << MSA_CSR_FLAGS_IB)
2398c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGS_UB	3
2408c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGS_UF	(_ULCAST_(0x1) << MSA_CSR_FLAGS_UB)
2418c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGS_OB	4
2428c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGS_OF	(_ULCAST_(0x1) << MSA_CSR_FLAGS_OB)
2438c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGS_ZB	5
2448c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGS_ZF	(_ULCAST_(0x1) << MSA_CSR_FLAGS_ZB)
2458c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGS_VB	6
2468c2ecf20Sopenharmony_ci#define MSA_CSR_FLAGS_VF	(_ULCAST_(0x1) << MSA_CSR_FLAGS_VB)
2478c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLESB	7
2488c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLESF	(_ULCAST_(0x1f) << MSA_CSR_ENABLESB)
2498c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLES_IB	7
2508c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLES_IF	(_ULCAST_(0x1) << MSA_CSR_ENABLES_IB)
2518c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLES_UB	8
2528c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLES_UF	(_ULCAST_(0x1) << MSA_CSR_ENABLES_UB)
2538c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLES_OB	9
2548c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLES_OF	(_ULCAST_(0x1) << MSA_CSR_ENABLES_OB)
2558c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLES_ZB	10
2568c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLES_ZF	(_ULCAST_(0x1) << MSA_CSR_ENABLES_ZB)
2578c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLES_VB	11
2588c2ecf20Sopenharmony_ci#define MSA_CSR_ENABLES_VF	(_ULCAST_(0x1) << MSA_CSR_ENABLES_VB)
2598c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSEB		12
2608c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSEF		(_ULCAST_(0x3f) << MSA_CSR_CAUSEB)
2618c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_IB	12
2628c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_IF	(_ULCAST_(0x1) << MSA_CSR_CAUSE_IB)
2638c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_UB	13
2648c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_UF	(_ULCAST_(0x1) << MSA_CSR_CAUSE_UB)
2658c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_OB	14
2668c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_OF	(_ULCAST_(0x1) << MSA_CSR_CAUSE_OB)
2678c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_ZB	15
2688c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_ZF	(_ULCAST_(0x1) << MSA_CSR_CAUSE_ZB)
2698c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_VB	16
2708c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_VF	(_ULCAST_(0x1) << MSA_CSR_CAUSE_VB)
2718c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_EB	17
2728c2ecf20Sopenharmony_ci#define MSA_CSR_CAUSE_EF	(_ULCAST_(0x1) << MSA_CSR_CAUSE_EB)
2738c2ecf20Sopenharmony_ci#define MSA_CSR_NXB		18
2748c2ecf20Sopenharmony_ci#define MSA_CSR_NXF		(_ULCAST_(0x1) << MSA_CSR_NXB)
2758c2ecf20Sopenharmony_ci#define MSA_CSR_FSB		24
2768c2ecf20Sopenharmony_ci#define MSA_CSR_FSF		(_ULCAST_(0x1) << MSA_CSR_FSB)
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci#endif /* _ASM_MSA_H */
279