162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/vfp/vfphw.S 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004 ARM Limited. 662306a36Sopenharmony_ci * Written by Deep Blue Solutions Limited. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/linkage.h> 1062306a36Sopenharmony_ci#include <asm/thread_info.h> 1162306a36Sopenharmony_ci#include <asm/vfpmacros.h> 1262306a36Sopenharmony_ci#include <linux/kern_levels.h> 1362306a36Sopenharmony_ci#include <asm/assembler.h> 1462306a36Sopenharmony_ci#include <asm/asm-offsets.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci .macro DBGSTR1, str, arg 1762306a36Sopenharmony_ci#ifdef DEBUG 1862306a36Sopenharmony_ci stmfd sp!, {r0-r3, ip, lr} 1962306a36Sopenharmony_ci mov r1, \arg 2062306a36Sopenharmony_ci ldr r0, =1f 2162306a36Sopenharmony_ci bl _printk 2262306a36Sopenharmony_ci ldmfd sp!, {r0-r3, ip, lr} 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci .pushsection .rodata, "a" 2562306a36Sopenharmony_ci1: .ascii KERN_DEBUG "VFP: \str\n" 2662306a36Sopenharmony_ci .byte 0 2762306a36Sopenharmony_ci .previous 2862306a36Sopenharmony_ci#endif 2962306a36Sopenharmony_ci .endm 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciENTRY(vfp_load_state) 3262306a36Sopenharmony_ci @ Load the current VFP state 3362306a36Sopenharmony_ci @ r0 - load location 3462306a36Sopenharmony_ci @ returns FPEXC 3562306a36Sopenharmony_ci DBGSTR1 "load VFP state %p", r0 3662306a36Sopenharmony_ci @ Load the saved state back into the VFP 3762306a36Sopenharmony_ci VFPFLDMIA r0, r1 @ reload the working registers while 3862306a36Sopenharmony_ci @ FPEXC is in a safe state 3962306a36Sopenharmony_ci ldmia r0, {r0-r3} @ load FPEXC, FPSCR, FPINST, FPINST2 4062306a36Sopenharmony_ci tst r0, #FPEXC_EX @ is there additional state to restore? 4162306a36Sopenharmony_ci beq 1f 4262306a36Sopenharmony_ci VFPFMXR FPINST, r2 @ restore FPINST (only if FPEXC.EX is set) 4362306a36Sopenharmony_ci tst r0, #FPEXC_FP2V @ is there an FPINST2 to write? 4462306a36Sopenharmony_ci beq 1f 4562306a36Sopenharmony_ci VFPFMXR FPINST2, r3 @ FPINST2 if needed (and present) 4662306a36Sopenharmony_ci1: 4762306a36Sopenharmony_ci VFPFMXR FPSCR, r1 @ restore status 4862306a36Sopenharmony_ci ret lr 4962306a36Sopenharmony_ciENDPROC(vfp_load_state) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciENTRY(vfp_save_state) 5262306a36Sopenharmony_ci @ Save the current VFP state 5362306a36Sopenharmony_ci @ r0 - save location 5462306a36Sopenharmony_ci @ r1 - FPEXC 5562306a36Sopenharmony_ci DBGSTR1 "save VFP state %p", r0 5662306a36Sopenharmony_ci VFPFSTMIA r0, r2 @ save the working registers 5762306a36Sopenharmony_ci VFPFMRX r2, FPSCR @ current status 5862306a36Sopenharmony_ci tst r1, #FPEXC_EX @ is there additional state to save? 5962306a36Sopenharmony_ci beq 1f 6062306a36Sopenharmony_ci VFPFMRX r3, FPINST @ FPINST (only if FPEXC.EX is set) 6162306a36Sopenharmony_ci tst r1, #FPEXC_FP2V @ is there an FPINST2 to read? 6262306a36Sopenharmony_ci beq 1f 6362306a36Sopenharmony_ci VFPFMRX r12, FPINST2 @ FPINST2 if needed (and present) 6462306a36Sopenharmony_ci1: 6562306a36Sopenharmony_ci stmia r0, {r1, r2, r3, r12} @ save FPEXC, FPSCR, FPINST, FPINST2 6662306a36Sopenharmony_ci ret lr 6762306a36Sopenharmony_ciENDPROC(vfp_save_state) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci .macro tbl_branch, base, tmp, shift 7062306a36Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL 7162306a36Sopenharmony_ci adr \tmp, 1f 7262306a36Sopenharmony_ci add \tmp, \tmp, \base, lsl \shift 7362306a36Sopenharmony_ci ret \tmp 7462306a36Sopenharmony_ci#else 7562306a36Sopenharmony_ci add pc, pc, \base, lsl \shift 7662306a36Sopenharmony_ci mov r0, r0 7762306a36Sopenharmony_ci#endif 7862306a36Sopenharmony_ci1: 7962306a36Sopenharmony_ci .endm 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ciENTRY(vfp_get_float) 8262306a36Sopenharmony_ci tbl_branch r0, r3, #3 8362306a36Sopenharmony_ci .fpu vfpv2 8462306a36Sopenharmony_ci .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 8562306a36Sopenharmony_ci1: vmov r0, s\dr 8662306a36Sopenharmony_ci ret lr 8762306a36Sopenharmony_ci .org 1b + 8 8862306a36Sopenharmony_ci .endr 8962306a36Sopenharmony_ci .irp dr,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 9062306a36Sopenharmony_ci1: vmov r0, s\dr 9162306a36Sopenharmony_ci ret lr 9262306a36Sopenharmony_ci .org 1b + 8 9362306a36Sopenharmony_ci .endr 9462306a36Sopenharmony_ciENDPROC(vfp_get_float) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ciENTRY(vfp_put_float) 9762306a36Sopenharmony_ci tbl_branch r1, r3, #3 9862306a36Sopenharmony_ci .fpu vfpv2 9962306a36Sopenharmony_ci .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 10062306a36Sopenharmony_ci1: vmov s\dr, r0 10162306a36Sopenharmony_ci ret lr 10262306a36Sopenharmony_ci .org 1b + 8 10362306a36Sopenharmony_ci .endr 10462306a36Sopenharmony_ci .irp dr,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 10562306a36Sopenharmony_ci1: vmov s\dr, r0 10662306a36Sopenharmony_ci ret lr 10762306a36Sopenharmony_ci .org 1b + 8 10862306a36Sopenharmony_ci .endr 10962306a36Sopenharmony_ciENDPROC(vfp_put_float) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciENTRY(vfp_get_double) 11262306a36Sopenharmony_ci tbl_branch r0, r3, #3 11362306a36Sopenharmony_ci .fpu vfpv2 11462306a36Sopenharmony_ci .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 11562306a36Sopenharmony_ci1: vmov r0, r1, d\dr 11662306a36Sopenharmony_ci ret lr 11762306a36Sopenharmony_ci .org 1b + 8 11862306a36Sopenharmony_ci .endr 11962306a36Sopenharmony_ci#ifdef CONFIG_VFPv3 12062306a36Sopenharmony_ci @ d16 - d31 registers 12162306a36Sopenharmony_ci .fpu vfpv3 12262306a36Sopenharmony_ci .irp dr,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 12362306a36Sopenharmony_ci1: vmov r0, r1, d\dr 12462306a36Sopenharmony_ci ret lr 12562306a36Sopenharmony_ci .org 1b + 8 12662306a36Sopenharmony_ci .endr 12762306a36Sopenharmony_ci#endif 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci @ virtual register 16 (or 32 if VFPv3) for compare with zero 13062306a36Sopenharmony_ci mov r0, #0 13162306a36Sopenharmony_ci mov r1, #0 13262306a36Sopenharmony_ci ret lr 13362306a36Sopenharmony_ciENDPROC(vfp_get_double) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ciENTRY(vfp_put_double) 13662306a36Sopenharmony_ci tbl_branch r2, r3, #3 13762306a36Sopenharmony_ci .fpu vfpv2 13862306a36Sopenharmony_ci .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 13962306a36Sopenharmony_ci1: vmov d\dr, r0, r1 14062306a36Sopenharmony_ci ret lr 14162306a36Sopenharmony_ci .org 1b + 8 14262306a36Sopenharmony_ci .endr 14362306a36Sopenharmony_ci#ifdef CONFIG_VFPv3 14462306a36Sopenharmony_ci .fpu vfpv3 14562306a36Sopenharmony_ci @ d16 - d31 registers 14662306a36Sopenharmony_ci .irp dr,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 14762306a36Sopenharmony_ci1: vmov d\dr, r0, r1 14862306a36Sopenharmony_ci ret lr 14962306a36Sopenharmony_ci .org 1b + 8 15062306a36Sopenharmony_ci .endr 15162306a36Sopenharmony_ci#endif 15262306a36Sopenharmony_ciENDPROC(vfp_put_double) 153