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]
24 1:
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)		\
73 do {									\
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 
97 static 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 
129 static 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 
137 static 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 
145 static 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