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