14827d0cfSEugeniy Paltsev /* SPDX-License-Identifier: GPL-2.0-only */
24827d0cfSEugeniy Paltsev /*
34827d0cfSEugeniy Paltsev * Copyright (C) 2020 Synopsys, Inc. (www.synopsys.com)
44827d0cfSEugeniy Paltsev *
54827d0cfSEugeniy Paltsev * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
64827d0cfSEugeniy Paltsev */
74827d0cfSEugeniy Paltsev #ifndef __ASM_ARC_DSP_IMPL_H
84827d0cfSEugeniy Paltsev #define __ASM_ARC_DSP_IMPL_H
94827d0cfSEugeniy Paltsev
107321e2eaSEugeniy Paltsev #include <asm/dsp.h>
117321e2eaSEugeniy Paltsev
124827d0cfSEugeniy Paltsev #define DSP_CTRL_DISABLED_ALL 0
134827d0cfSEugeniy Paltsev
144827d0cfSEugeniy Paltsev #ifdef __ASSEMBLY__
154827d0cfSEugeniy Paltsev
164827d0cfSEugeniy Paltsev /* clobbers r5 register */
174827d0cfSEugeniy Paltsev .macro DSP_EARLY_INIT
18*40db9367SEugeniy Paltsev #ifdef CONFIG_ISA_ARCV2
194827d0cfSEugeniy Paltsev lr r5, [ARC_AUX_DSP_BUILD]
204827d0cfSEugeniy Paltsev bmsk r5, r5, 7
214827d0cfSEugeniy Paltsev breq r5, 0, 1f
224827d0cfSEugeniy Paltsev mov r5, DSP_CTRL_DISABLED_ALL
234827d0cfSEugeniy Paltsev sr r5, [ARC_AUX_DSP_CTRL]
244827d0cfSEugeniy Paltsev 1:
25*40db9367SEugeniy Paltsev #endif
264827d0cfSEugeniy Paltsev .endm
274827d0cfSEugeniy Paltsev
284827d0cfSEugeniy Paltsev /* clobbers r10, r11 registers pair */
294827d0cfSEugeniy Paltsev .macro DSP_SAVE_REGFILE_IRQ
304827d0cfSEugeniy Paltsev #if defined(CONFIG_ARC_DSP_KERNEL)
314827d0cfSEugeniy Paltsev /*
324827d0cfSEugeniy Paltsev * Drop any changes to DSP_CTRL made by userspace so userspace won't be
334827d0cfSEugeniy Paltsev * able to break kernel - reset it to DSP_CTRL_DISABLED_ALL value
344827d0cfSEugeniy Paltsev */
354827d0cfSEugeniy Paltsev mov r10, DSP_CTRL_DISABLED_ALL
364827d0cfSEugeniy Paltsev sr r10, [ARC_AUX_DSP_CTRL]
377321e2eaSEugeniy Paltsev
387321e2eaSEugeniy Paltsev #elif defined(CONFIG_ARC_DSP_SAVE_RESTORE_REGS)
397321e2eaSEugeniy Paltsev /*
407321e2eaSEugeniy Paltsev * Save DSP_CTRL register and reset it to value suitable for kernel
417321e2eaSEugeniy Paltsev * (DSP_CTRL_DISABLED_ALL)
427321e2eaSEugeniy Paltsev */
437321e2eaSEugeniy Paltsev mov r10, DSP_CTRL_DISABLED_ALL
447321e2eaSEugeniy Paltsev aex r10, [ARC_AUX_DSP_CTRL]
457321e2eaSEugeniy Paltsev st r10, [sp, PT_DSP_CTRL]
467321e2eaSEugeniy Paltsev
477321e2eaSEugeniy Paltsev #endif
487321e2eaSEugeniy Paltsev .endm
497321e2eaSEugeniy Paltsev
507321e2eaSEugeniy Paltsev /* clobbers r10, r11 registers pair */
517321e2eaSEugeniy Paltsev .macro DSP_RESTORE_REGFILE_IRQ
527321e2eaSEugeniy Paltsev #if defined(CONFIG_ARC_DSP_SAVE_RESTORE_REGS)
537321e2eaSEugeniy Paltsev ld r10, [sp, PT_DSP_CTRL]
547321e2eaSEugeniy Paltsev sr r10, [ARC_AUX_DSP_CTRL]
557321e2eaSEugeniy Paltsev
567321e2eaSEugeniy Paltsev #endif
574827d0cfSEugeniy Paltsev .endm
584827d0cfSEugeniy Paltsev
594827d0cfSEugeniy Paltsev #else /* __ASEMBLY__ */
604827d0cfSEugeniy Paltsev
617321e2eaSEugeniy Paltsev #include <linux/sched.h>
624827d0cfSEugeniy Paltsev #include <asm/asserts.h>
637321e2eaSEugeniy Paltsev #include <asm/switch_to.h>
647321e2eaSEugeniy Paltsev
657321e2eaSEugeniy Paltsev #ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
667321e2eaSEugeniy Paltsev
677321e2eaSEugeniy Paltsev /*
687321e2eaSEugeniy Paltsev * As we save new and restore old AUX register value in the same place we
697321e2eaSEugeniy Paltsev * can optimize a bit and use AEX instruction (swap contents of an auxiliary
707321e2eaSEugeniy Paltsev * register with a core register) instead of LR + SR pair.
717321e2eaSEugeniy Paltsev */
727321e2eaSEugeniy Paltsev #define AUX_SAVE_RESTORE(_saveto, _readfrom, _offt, _aux) \
737321e2eaSEugeniy Paltsev do { \
747321e2eaSEugeniy Paltsev long unsigned int _scratch; \
757321e2eaSEugeniy Paltsev \
767321e2eaSEugeniy Paltsev __asm__ __volatile__( \
777321e2eaSEugeniy Paltsev "ld %0, [%2, %4] \n" \
787321e2eaSEugeniy Paltsev "aex %0, [%3] \n" \
797321e2eaSEugeniy Paltsev "st %0, [%1, %4] \n" \
807321e2eaSEugeniy Paltsev : \
817321e2eaSEugeniy Paltsev "=&r" (_scratch) /* must be early clobber */ \
827321e2eaSEugeniy Paltsev : \
837321e2eaSEugeniy Paltsev "r" (_saveto), \
847321e2eaSEugeniy Paltsev "r" (_readfrom), \
857321e2eaSEugeniy Paltsev "Ir" (_aux), \
867321e2eaSEugeniy Paltsev "Ir" (_offt) \
877321e2eaSEugeniy Paltsev : \
887321e2eaSEugeniy Paltsev "memory" \
897321e2eaSEugeniy Paltsev ); \
907321e2eaSEugeniy Paltsev } while (0)
917321e2eaSEugeniy Paltsev
927321e2eaSEugeniy Paltsev #define DSP_AUX_SAVE_RESTORE(_saveto, _readfrom, _aux) \
937321e2eaSEugeniy Paltsev AUX_SAVE_RESTORE(_saveto, _readfrom, \
947321e2eaSEugeniy Paltsev offsetof(struct dsp_callee_regs, _aux), \
957321e2eaSEugeniy Paltsev ARC_AUX_##_aux)
967321e2eaSEugeniy Paltsev
dsp_save_restore(struct task_struct * prev,struct task_struct * next)977321e2eaSEugeniy Paltsev static inline void dsp_save_restore(struct task_struct *prev,
987321e2eaSEugeniy Paltsev struct task_struct *next)
997321e2eaSEugeniy Paltsev {
1007321e2eaSEugeniy Paltsev long unsigned int *saveto = &prev->thread.dsp.ACC0_GLO;
1017321e2eaSEugeniy Paltsev long unsigned int *readfrom = &next->thread.dsp.ACC0_GLO;
1027321e2eaSEugeniy Paltsev
1037321e2eaSEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, ACC0_GLO);
1047321e2eaSEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, ACC0_GHI);
1057321e2eaSEugeniy Paltsev
1067321e2eaSEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, DSP_BFLY0);
1077321e2eaSEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, DSP_FFT_CTRL);
108f09d3174SEugeniy Paltsev
109f09d3174SEugeniy Paltsev #ifdef CONFIG_ARC_DSP_AGU_USERSPACE
110f09d3174SEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP0);
111f09d3174SEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP1);
112f09d3174SEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP2);
113f09d3174SEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP3);
114f09d3174SEugeniy Paltsev
115f09d3174SEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_OS0);
116f09d3174SEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_OS1);
117f09d3174SEugeniy Paltsev
118f09d3174SEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD0);
119f09d3174SEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD1);
120f09d3174SEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD2);
121f09d3174SEugeniy Paltsev DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD3);
122f09d3174SEugeniy Paltsev #endif /* CONFIG_ARC_DSP_AGU_USERSPACE */
1237321e2eaSEugeniy Paltsev }
1247321e2eaSEugeniy Paltsev
1257321e2eaSEugeniy Paltsev #else /* !CONFIG_ARC_DSP_SAVE_RESTORE_REGS */
1267321e2eaSEugeniy Paltsev #define dsp_save_restore(p, n)
1277321e2eaSEugeniy Paltsev #endif /* CONFIG_ARC_DSP_SAVE_RESTORE_REGS */
1284827d0cfSEugeniy Paltsev
dsp_exist(void)1294827d0cfSEugeniy Paltsev static inline bool dsp_exist(void)
1304827d0cfSEugeniy Paltsev {
1314827d0cfSEugeniy Paltsev struct bcr_generic bcr;
1324827d0cfSEugeniy Paltsev
1334827d0cfSEugeniy Paltsev READ_BCR(ARC_AUX_DSP_BUILD, bcr);
1344827d0cfSEugeniy Paltsev return !!bcr.ver;
1354827d0cfSEugeniy Paltsev }
1364827d0cfSEugeniy Paltsev
agu_exist(void)137f09d3174SEugeniy Paltsev static inline bool agu_exist(void)
138f09d3174SEugeniy Paltsev {
139f09d3174SEugeniy Paltsev struct bcr_generic bcr;
140f09d3174SEugeniy Paltsev
141f09d3174SEugeniy Paltsev READ_BCR(ARC_AUX_AGU_BUILD, bcr);
142f09d3174SEugeniy Paltsev return !!bcr.ver;
143f09d3174SEugeniy Paltsev }
144f09d3174SEugeniy Paltsev
dsp_config_check(void)1454827d0cfSEugeniy Paltsev static inline void dsp_config_check(void)
1464827d0cfSEugeniy Paltsev {
1474827d0cfSEugeniy Paltsev CHK_OPT_STRICT(CONFIG_ARC_DSP_HANDLED, dsp_exist());
148f09d3174SEugeniy Paltsev CHK_OPT_WEAK(CONFIG_ARC_DSP_AGU_USERSPACE, agu_exist());
1494827d0cfSEugeniy Paltsev }
1504827d0cfSEugeniy Paltsev
1514827d0cfSEugeniy Paltsev #endif /* __ASEMBLY__ */
1524827d0cfSEugeniy Paltsev #endif /* __ASM_ARC_DSP_IMPL_H */
153