xref: /optee_os/core/arch/arm/kernel/vfp.c (revision 8e01b4b9824fd8e21edbc40b503679f52277da52)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2abe38974SJens Wiklander /*
3abe38974SJens Wiklander  * Copyright (c) 2015, Linaro Limited
4abe38974SJens Wiklander  */
5abe38974SJens Wiklander 
6abe38974SJens Wiklander #include <arm.h>
78ddf5a4eSEtienne Carriere #include <assert.h>
8abe38974SJens Wiklander #include <kernel/vfp.h>
9abe38974SJens Wiklander #include "vfp_private.h"
10abe38974SJens Wiklander 
11bc46c1c6SJerome Forissier #ifdef ARM32
vfp_is_enabled(void)12abe38974SJens Wiklander bool vfp_is_enabled(void)
13abe38974SJens Wiklander {
14abe38974SJens Wiklander 	return !!(vfp_read_fpexc() & FPEXC_EN);
15abe38974SJens Wiklander }
16abe38974SJens Wiklander 
vfp_enable(void)17abe38974SJens Wiklander void vfp_enable(void)
18abe38974SJens Wiklander {
19abe38974SJens Wiklander 	vfp_write_fpexc(vfp_read_fpexc() | FPEXC_EN);
20abe38974SJens Wiklander }
21abe38974SJens Wiklander 
vfp_disable(void)22abe38974SJens Wiklander void vfp_disable(void)
23abe38974SJens Wiklander {
24abe38974SJens Wiklander 	vfp_write_fpexc(vfp_read_fpexc() & ~FPEXC_EN);
25abe38974SJens Wiklander }
26abe38974SJens Wiklander 
vfp_lazy_save_state_init(struct vfp_state * state)27abe38974SJens Wiklander void vfp_lazy_save_state_init(struct vfp_state *state)
28abe38974SJens Wiklander {
29abe38974SJens Wiklander 	uint32_t fpexc = vfp_read_fpexc();
30abe38974SJens Wiklander 
31abe38974SJens Wiklander 	state->fpexc = fpexc;
32abe38974SJens Wiklander 	vfp_write_fpexc(fpexc & ~FPEXC_EN);
33abe38974SJens Wiklander }
34abe38974SJens Wiklander 
vfp_lazy_save_state_final(struct vfp_state * state,bool force_save)35*8e01b4b9SJens Wiklander void vfp_lazy_save_state_final(struct vfp_state *state, bool force_save)
36abe38974SJens Wiklander {
37*8e01b4b9SJens Wiklander 	if ((state->fpexc & FPEXC_EN) || force_save) {
38abe38974SJens Wiklander 		uint32_t fpexc = vfp_read_fpexc();
39abe38974SJens Wiklander 
40abe38974SJens Wiklander 		assert(!(fpexc & FPEXC_EN));
41abe38974SJens Wiklander 		vfp_write_fpexc(fpexc | FPEXC_EN);
42abe38974SJens Wiklander 		state->fpscr = vfp_read_fpscr();
43abe38974SJens Wiklander 		vfp_save_extension_regs(state->reg);
44abe38974SJens Wiklander 		vfp_write_fpexc(fpexc);
45abe38974SJens Wiklander 	}
46abe38974SJens Wiklander }
47abe38974SJens Wiklander 
vfp_lazy_restore_state(struct vfp_state * state,bool full_state)48abe38974SJens Wiklander void vfp_lazy_restore_state(struct vfp_state *state, bool full_state)
49abe38974SJens Wiklander {
50abe38974SJens Wiklander 
51abe38974SJens Wiklander 	if (full_state) {
52abe38974SJens Wiklander 		/*
53bc46c1c6SJerome Forissier 		 * Only restore VFP registers if they have been touched as they
54abe38974SJens Wiklander 		 * otherwise are intact.
55abe38974SJens Wiklander 		 */
56abe38974SJens Wiklander 
57abe38974SJens Wiklander 		/* FPEXC is restored to what's in state->fpexc below */
58abe38974SJens Wiklander 		vfp_write_fpexc(vfp_read_fpexc() | FPEXC_EN);
59abe38974SJens Wiklander 
60abe38974SJens Wiklander 		vfp_write_fpscr(state->fpscr);
61abe38974SJens Wiklander 		vfp_restore_extension_regs(state->reg);
62abe38974SJens Wiklander 	}
63abe38974SJens Wiklander 	vfp_write_fpexc(state->fpexc);
64abe38974SJens Wiklander }
65bc46c1c6SJerome Forissier #endif /* ARM32 */
66bc46c1c6SJerome Forissier 
67bc46c1c6SJerome Forissier #ifdef ARM64
vfp_is_enabled(void)68bc46c1c6SJerome Forissier bool vfp_is_enabled(void)
69bc46c1c6SJerome Forissier {
70bc46c1c6SJerome Forissier 	return (CPACR_EL1_FPEN(read_cpacr_el1()) & CPACR_EL1_FPEN_EL0EL1);
71bc46c1c6SJerome Forissier }
72bc46c1c6SJerome Forissier 
vfp_enable(void)73bc46c1c6SJerome Forissier void vfp_enable(void)
74bc46c1c6SJerome Forissier {
75bc46c1c6SJerome Forissier 	uint32_t val = read_cpacr_el1();
76bc46c1c6SJerome Forissier 
770de9a5fbSJens Wiklander 	val |= (CPACR_EL1_FPEN_EL0EL1 << CPACR_EL1_FPEN_SHIFT);
78bc46c1c6SJerome Forissier 	write_cpacr_el1(val);
793b6248efSJens Wiklander 	isb();
80bc46c1c6SJerome Forissier }
81bc46c1c6SJerome Forissier 
vfp_disable(void)82bc46c1c6SJerome Forissier void vfp_disable(void)
83bc46c1c6SJerome Forissier {
84bc46c1c6SJerome Forissier 	uint32_t val = read_cpacr_el1();
85bc46c1c6SJerome Forissier 
86bc46c1c6SJerome Forissier 	val &= ~(CPACR_EL1_FPEN_MASK << CPACR_EL1_FPEN_SHIFT);
87bc46c1c6SJerome Forissier 	write_cpacr_el1(val);
883b6248efSJens Wiklander 	isb();
89bc46c1c6SJerome Forissier }
90bc46c1c6SJerome Forissier 
vfp_lazy_save_state_init(struct vfp_state * state)91bc46c1c6SJerome Forissier void vfp_lazy_save_state_init(struct vfp_state *state)
92bc46c1c6SJerome Forissier {
93bc46c1c6SJerome Forissier 	state->cpacr_el1 = read_cpacr_el1();
94bc46c1c6SJerome Forissier 	vfp_disable();
95bc46c1c6SJerome Forissier }
96bc46c1c6SJerome Forissier 
vfp_lazy_save_state_final(struct vfp_state * state,bool force_save)97*8e01b4b9SJens Wiklander void vfp_lazy_save_state_final(struct vfp_state *state, bool force_save)
98bc46c1c6SJerome Forissier {
99bc46c1c6SJerome Forissier 	if ((CPACR_EL1_FPEN(state->cpacr_el1) & CPACR_EL1_FPEN_EL0EL1) ||
100*8e01b4b9SJens Wiklander 	    force_save) {
101bc46c1c6SJerome Forissier 		assert(!vfp_is_enabled());
102bc46c1c6SJerome Forissier 		vfp_enable();
103bc46c1c6SJerome Forissier 		state->fpcr = read_fpcr();
104bc46c1c6SJerome Forissier 		state->fpsr = read_fpsr();
105bc46c1c6SJerome Forissier 		vfp_save_extension_regs(state->reg);
106bc46c1c6SJerome Forissier 		vfp_disable();
107bc46c1c6SJerome Forissier 	}
108bc46c1c6SJerome Forissier }
109bc46c1c6SJerome Forissier 
vfp_lazy_restore_state(struct vfp_state * state,bool full_state)110bc46c1c6SJerome Forissier void vfp_lazy_restore_state(struct vfp_state *state, bool full_state)
111bc46c1c6SJerome Forissier {
112bc46c1c6SJerome Forissier 	if (full_state) {
113bc46c1c6SJerome Forissier 		/*
114bc46c1c6SJerome Forissier 		 * Only restore VFP registers if they have been touched as they
115bc46c1c6SJerome Forissier 		 * otherwise are intact.
116bc46c1c6SJerome Forissier 		 */
117bc46c1c6SJerome Forissier 
118bc46c1c6SJerome Forissier 		/* CPACR_EL1 is restored to what's in state->cpacr_el1 below */
119bc46c1c6SJerome Forissier 		vfp_enable();
120bc46c1c6SJerome Forissier 		write_fpcr(state->fpcr);
121bc46c1c6SJerome Forissier 		write_fpsr(state->fpsr);
122bc46c1c6SJerome Forissier 		vfp_restore_extension_regs(state->reg);
123bc46c1c6SJerome Forissier 	}
124bc46c1c6SJerome Forissier 	write_cpacr_el1(state->cpacr_el1);
1253b6248efSJens Wiklander 	isb();
126bc46c1c6SJerome Forissier }
127bc46c1c6SJerome Forissier #endif /* ARM64 */
128