1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright (C) 2020 Synopsys, Inc. (www.synopsys.com)
4 *
5 * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
6 */
7#ifndef __ASM_ARC_DSP_IMPL_H
8#define __ASM_ARC_DSP_IMPL_H
9
10#include <asm/dsp.h>
11
12#define DSP_CTRL_DISABLED_ALL		0
13
14#ifdef __ASSEMBLY__
15
16/* clobbers r5 register */
17.macro DSP_EARLY_INIT
18#ifdef CONFIG_ISA_ARCV2
19	lr	r5, [ARC_AUX_DSP_BUILD]
20	bmsk	r5, r5, 7
21	breq    r5, 0, 1f
22	mov	r5, DSP_CTRL_DISABLED_ALL
23	sr	r5, [ARC_AUX_DSP_CTRL]
241:
25#endif
26.endm
27
28/* clobbers r10, r11 registers pair */
29.macro DSP_SAVE_REGFILE_IRQ
30#if defined(CONFIG_ARC_DSP_KERNEL)
31	/*
32	 * Drop any changes to DSP_CTRL made by userspace so userspace won't be
33	 * able to break kernel - reset it to DSP_CTRL_DISABLED_ALL value
34	 */
35	mov	r10, DSP_CTRL_DISABLED_ALL
36	sr	r10, [ARC_AUX_DSP_CTRL]
37
38#elif defined(CONFIG_ARC_DSP_SAVE_RESTORE_REGS)
39	/*
40	 * Save DSP_CTRL register and reset it to value suitable for kernel
41	 * (DSP_CTRL_DISABLED_ALL)
42	 */
43	mov	r10, DSP_CTRL_DISABLED_ALL
44	aex	r10, [ARC_AUX_DSP_CTRL]
45	st	r10, [sp, PT_DSP_CTRL]
46
47#endif
48.endm
49
50/* clobbers r10, r11 registers pair */
51.macro DSP_RESTORE_REGFILE_IRQ
52#if defined(CONFIG_ARC_DSP_SAVE_RESTORE_REGS)
53	ld	r10, [sp, PT_DSP_CTRL]
54	sr	r10, [ARC_AUX_DSP_CTRL]
55
56#endif
57.endm
58
59#else /* __ASEMBLY__ */
60
61#include <linux/sched.h>
62#include <asm/asserts.h>
63#include <asm/switch_to.h>
64
65#ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
66
67/*
68 * As we save new and restore old AUX register value in the same place we
69 * can optimize a bit and use AEX instruction (swap contents of an auxiliary
70 * register with a core register) instead of LR + SR pair.
71 */
72#define AUX_SAVE_RESTORE(_saveto, _readfrom, _offt, _aux)		\
73do {									\
74	long unsigned int _scratch;					\
75									\
76	__asm__ __volatile__(						\
77		"ld	%0, [%2, %4]			\n"		\
78		"aex	%0, [%3]			\n"		\
79		"st	%0, [%1, %4]			\n"		\
80		:							\
81		  "=&r" (_scratch)	/* must be early clobber */	\
82		:							\
83		   "r" (_saveto),					\
84		   "r" (_readfrom),					\
85		   "Ir" (_aux),						\
86		   "Ir" (_offt)						\
87		:							\
88		  "memory"						\
89	);								\
90} while (0)
91
92#define DSP_AUX_SAVE_RESTORE(_saveto, _readfrom, _aux)			\
93	AUX_SAVE_RESTORE(_saveto, _readfrom,				\
94		offsetof(struct dsp_callee_regs, _aux),			\
95		ARC_AUX_##_aux)
96
97static inline void dsp_save_restore(struct task_struct *prev,
98					struct task_struct *next)
99{
100	long unsigned int *saveto = &prev->thread.dsp.ACC0_GLO;
101	long unsigned int *readfrom = &next->thread.dsp.ACC0_GLO;
102
103	DSP_AUX_SAVE_RESTORE(saveto, readfrom, ACC0_GLO);
104	DSP_AUX_SAVE_RESTORE(saveto, readfrom, ACC0_GHI);
105
106	DSP_AUX_SAVE_RESTORE(saveto, readfrom, DSP_BFLY0);
107	DSP_AUX_SAVE_RESTORE(saveto, readfrom, DSP_FFT_CTRL);
108
109#ifdef CONFIG_ARC_DSP_AGU_USERSPACE
110	DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP0);
111	DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP1);
112	DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP2);
113	DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP3);
114
115	DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_OS0);
116	DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_OS1);
117
118	DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD0);
119	DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD1);
120	DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD2);
121	DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD3);
122#endif /* CONFIG_ARC_DSP_AGU_USERSPACE */
123}
124
125#else /* !CONFIG_ARC_DSP_SAVE_RESTORE_REGS */
126#define dsp_save_restore(p, n)
127#endif /* CONFIG_ARC_DSP_SAVE_RESTORE_REGS */
128
129static inline bool dsp_exist(void)
130{
131	struct bcr_generic bcr;
132
133	READ_BCR(ARC_AUX_DSP_BUILD, bcr);
134	return !!bcr.ver;
135}
136
137static inline bool agu_exist(void)
138{
139	struct bcr_generic bcr;
140
141	READ_BCR(ARC_AUX_AGU_BUILD, bcr);
142	return !!bcr.ver;
143}
144
145static inline void dsp_config_check(void)
146{
147	CHK_OPT_STRICT(CONFIG_ARC_DSP_HANDLED, dsp_exist());
148	CHK_OPT_WEAK(CONFIG_ARC_DSP_AGU_USERSPACE, agu_exist());
149}
150
151#endif /* __ASEMBLY__ */
152#endif /* __ASM_ARC_DSP_IMPL_H */
153