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 Wiklanderbool vfp_is_enabled(void) 13abe38974SJens Wiklander { 14abe38974SJens Wiklander return !!(vfp_read_fpexc() & FPEXC_EN); 15abe38974SJens Wiklander } 16abe38974SJens Wiklander vfp_enable(void)17abe38974SJens Wiklandervoid vfp_enable(void) 18abe38974SJens Wiklander { 19abe38974SJens Wiklander vfp_write_fpexc(vfp_read_fpexc() | FPEXC_EN); 20abe38974SJens Wiklander } 21abe38974SJens Wiklander vfp_disable(void)22abe38974SJens Wiklandervoid 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 Wiklandervoid 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 Wiklandervoid 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 Wiklandervoid 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 Forissierbool 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 Forissiervoid 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 Forissiervoid 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 Forissiervoid 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 Wiklandervoid 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 Forissiervoid 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