153 lines
3.8 KiB
C
153 lines
3.8 KiB
C
|
/* 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 */
|