| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| /* | |
| * Copyright (C) 2020 Synopsys, Inc. (www.synopsys.com) | |
| * | |
| * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> | |
| */ | |
| #ifndef __ASM_ARC_DSP_IMPL_H | |
| #define __ASM_ARC_DSP_IMPL_H | |
| #include <asm/dsp.h> | |
| #define DSP_CTRL_DISABLED_ALL 0 | |
| #ifdef __ASSEMBLY__ | |
| /* clobbers r5 register */ | |
| .macro DSP_EARLY_INIT | |
| #ifdef CONFIG_ISA_ARCV2 | |
| lr r5, [ARC_AUX_DSP_BUILD] | |
| bmsk r5, r5, 7 | |
| breq r5, 0, 1f | |
| mov r5, DSP_CTRL_DISABLED_ALL | |
| sr r5, [ARC_AUX_DSP_CTRL] | |
| 1: | |
| #endif | |
| .endm | |
| /* clobbers r10, r11 registers pair */ | |
| .macro DSP_SAVE_REGFILE_IRQ | |
| #if defined(CONFIG_ARC_DSP_KERNEL) | |
| /* | |
| * Drop any changes to DSP_CTRL made by userspace so userspace won't be | |
| * able to break kernel - reset it to DSP_CTRL_DISABLED_ALL value | |
| */ | |
| mov r10, DSP_CTRL_DISABLED_ALL | |
| sr r10, [ARC_AUX_DSP_CTRL] | |
| #elif defined(CONFIG_ARC_DSP_SAVE_RESTORE_REGS) | |
| /* | |
| * Save DSP_CTRL register and reset it to value suitable for kernel | |
| * (DSP_CTRL_DISABLED_ALL) | |
| */ | |
| mov r10, DSP_CTRL_DISABLED_ALL | |
| aex r10, [ARC_AUX_DSP_CTRL] | |
| st r10, [sp, PT_DSP_CTRL] | |
| #endif | |
| .endm | |
| /* clobbers r10, r11 registers pair */ | |
| .macro DSP_RESTORE_REGFILE_IRQ | |
| #if defined(CONFIG_ARC_DSP_SAVE_RESTORE_REGS) | |
| ld r10, [sp, PT_DSP_CTRL] | |
| sr r10, [ARC_AUX_DSP_CTRL] | |
| #endif | |
| .endm | |
| #else /* __ASEMBLY__ */ | |
| #include <linux/sched.h> | |
| #include <asm/asserts.h> | |
| #include <asm/switch_to.h> | |
| #ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS | |
| /* | |
| * As we save new and restore old AUX register value in the same place we | |
| * can optimize a bit and use AEX instruction (swap contents of an auxiliary | |
| * register with a core register) instead of LR + SR pair. | |
| */ | |
| #define AUX_SAVE_RESTORE(_saveto, _readfrom, _offt, _aux) \ | |
| do { \ | |
| long unsigned int _scratch; \ | |
| \ | |
| __asm__ __volatile__( \ | |
| "ld %0, [%2, %4] \n" \ | |
| "aex %0, [%3] \n" \ | |
| "st %0, [%1, %4] \n" \ | |
| : \ | |
| "=&r" (_scratch) /* must be early clobber */ \ | |
| : \ | |
| "r" (_saveto), \ | |
| "r" (_readfrom), \ | |
| "Ir" (_aux), \ | |
| "Ir" (_offt) \ | |
| : \ | |
| "memory" \ | |
| ); \ | |
| } while (0) | |
| #define DSP_AUX_SAVE_RESTORE(_saveto, _readfrom, _aux) \ | |
| AUX_SAVE_RESTORE(_saveto, _readfrom, \ | |
| offsetof(struct dsp_callee_regs, _aux), \ | |
| ARC_AUX_##_aux) | |
| static inline void dsp_save_restore(struct task_struct *prev, | |
| struct task_struct *next) | |
| { | |
| long unsigned int *saveto = &prev->thread.dsp.ACC0_GLO; | |
| long unsigned int *readfrom = &next->thread.dsp.ACC0_GLO; | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, ACC0_GLO); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, ACC0_GHI); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, DSP_BFLY0); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, DSP_FFT_CTRL); | |
| #ifdef CONFIG_ARC_DSP_AGU_USERSPACE | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP0); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP1); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP2); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_AP3); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_OS0); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_OS1); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD0); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD1); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD2); | |
| DSP_AUX_SAVE_RESTORE(saveto, readfrom, AGU_MOD3); | |
| #endif /* CONFIG_ARC_DSP_AGU_USERSPACE */ | |
| } | |
| #else /* !CONFIG_ARC_DSP_SAVE_RESTORE_REGS */ | |
| #define dsp_save_restore(p, n) | |
| #endif /* CONFIG_ARC_DSP_SAVE_RESTORE_REGS */ | |
| static inline bool dsp_exist(void) | |
| { | |
| struct bcr_generic bcr; | |
| READ_BCR(ARC_AUX_DSP_BUILD, bcr); | |
| return !!bcr.ver; | |
| } | |
| static inline bool agu_exist(void) | |
| { | |
| struct bcr_generic bcr; | |
| READ_BCR(ARC_AUX_AGU_BUILD, bcr); | |
| return !!bcr.ver; | |
| } | |
| static inline void dsp_config_check(void) | |
| { | |
| CHK_OPT_STRICT(CONFIG_ARC_DSP_HANDLED, dsp_exist()); | |
| CHK_OPT_WEAK(CONFIG_ARC_DSP_AGU_USERSPACE, agu_exist()); | |
| } | |
| #endif /* __ASEMBLY__ */ | |
| #endif /* __ASM_ARC_DSP_IMPL_H */ |