diff options
| -rw-r--r-- | arch/arm/Kconfig | 7 | ||||
| -rw-r--r-- | arch/arm/vfp/vfp.h | 4 | ||||
| -rw-r--r-- | arch/arm/vfp/vfphw.S | 22 | ||||
| -rw-r--r-- | arch/arm/vfp/vfpinstr.h | 6 | ||||
| -rw-r--r-- | include/asm-arm/fpstate.h | 9 | ||||
| -rw-r--r-- | include/asm-arm/vfp.h | 6 | ||||
| -rw-r--r-- | include/asm-arm/vfpmacros.h | 18 |
7 files changed, 60 insertions, 12 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a04f507e7f2c..f4eeb03bc6a9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -951,7 +951,7 @@ config FPE_FASTFPE | |||
| 951 | 951 | ||
| 952 | config VFP | 952 | config VFP |
| 953 | bool "VFP-format floating point maths" | 953 | bool "VFP-format floating point maths" |
| 954 | depends on CPU_V6 || CPU_ARM926T | 954 | depends on CPU_V6 || CPU_ARM926T || CPU_V7 |
| 955 | help | 955 | help |
| 956 | Say Y to include VFP support code in the kernel. This is needed | 956 | Say Y to include VFP support code in the kernel. This is needed |
| 957 | if your hardware includes a VFP unit. | 957 | if your hardware includes a VFP unit. |
| @@ -961,6 +961,11 @@ config VFP | |||
| 961 | 961 | ||
| 962 | Say N if your target does not have VFP hardware. | 962 | Say N if your target does not have VFP hardware. |
| 963 | 963 | ||
| 964 | config VFPv3 | ||
| 965 | bool | ||
| 966 | depends on VFP | ||
| 967 | default y if CPU_V7 | ||
| 968 | |||
| 964 | endmenu | 969 | endmenu |
| 965 | 970 | ||
| 966 | menu "Userspace binary formats" | 971 | menu "Userspace binary formats" |
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h index 791d0238c68f..c85860bad585 100644 --- a/arch/arm/vfp/vfp.h +++ b/arch/arm/vfp/vfp.h | |||
| @@ -265,7 +265,11 @@ struct vfp_double { | |||
| 265 | * which returns (double)0.0. This is useful for the compare with | 265 | * which returns (double)0.0. This is useful for the compare with |
| 266 | * zero instructions. | 266 | * zero instructions. |
| 267 | */ | 267 | */ |
| 268 | #ifdef CONFIG_VFPv3 | ||
| 269 | #define VFP_REG_ZERO 32 | ||
| 270 | #else | ||
| 268 | #define VFP_REG_ZERO 16 | 271 | #define VFP_REG_ZERO 16 |
| 272 | #endif | ||
| 269 | extern u64 vfp_get_double(unsigned int reg); | 273 | extern u64 vfp_get_double(unsigned int reg); |
| 270 | extern void vfp_put_double(u64 val, unsigned int reg); | 274 | extern void vfp_put_double(u64 val, unsigned int reg); |
| 271 | 275 | ||
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 53d9f8e8fac3..353f9e5c7919 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S | |||
| @@ -99,12 +99,12 @@ vfp_support_entry: | |||
| 99 | DBGSTR1 "save old state %p", r4 | 99 | DBGSTR1 "save old state %p", r4 |
| 100 | cmp r4, #0 | 100 | cmp r4, #0 |
| 101 | beq no_old_VFP_process | 101 | beq no_old_VFP_process |
| 102 | VFPFSTMIA r4, r5 @ save the working registers | ||
| 102 | VFPFMRX r5, FPSCR @ current status | 103 | VFPFMRX r5, FPSCR @ current status |
| 103 | tst r1, #FPEXC_EX @ is there additional state to save? | 104 | tst r1, #FPEXC_EX @ is there additional state to save? |
| 104 | VFPFMRX r6, FPINST, NE @ FPINST (only if FPEXC.EX is set) | 105 | VFPFMRX r6, FPINST, NE @ FPINST (only if FPEXC.EX is set) |
| 105 | tstne r1, #FPEXC_FP2V @ is there an FPINST2 to read? | 106 | tstne r1, #FPEXC_FP2V @ is there an FPINST2 to read? |
| 106 | VFPFMRX r8, FPINST2, NE @ FPINST2 if needed (and present) | 107 | VFPFMRX r8, FPINST2, NE @ FPINST2 if needed (and present) |
| 107 | VFPFSTMIA r4 @ save the working registers | ||
| 108 | stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2 | 108 | stmia r4, {r1, r5, r6, r8} @ save FPEXC, FPSCR, FPINST, FPINST2 |
| 109 | @ and point r4 at the word at the | 109 | @ and point r4 at the word at the |
| 110 | @ start of the register dump | 110 | @ start of the register dump |
| @@ -114,7 +114,7 @@ no_old_VFP_process: | |||
| 114 | DBGSTR1 "load state %p", r10 | 114 | DBGSTR1 "load state %p", r10 |
| 115 | str r10, [r3, r11, lsl #2] @ update the last_VFP_context pointer | 115 | str r10, [r3, r11, lsl #2] @ update the last_VFP_context pointer |
| 116 | @ Load the saved state back into the VFP | 116 | @ Load the saved state back into the VFP |
| 117 | VFPFLDMIA r10 @ reload the working registers while | 117 | VFPFLDMIA r10, r5 @ reload the working registers while |
| 118 | @ FPEXC is in a safe state | 118 | @ FPEXC is in a safe state |
| 119 | ldmia r10, {r1, r5, r6, r8} @ load FPEXC, FPSCR, FPINST, FPINST2 | 119 | ldmia r10, {r1, r5, r6, r8} @ load FPEXC, FPSCR, FPINST, FPINST2 |
| 120 | tst r1, #FPEXC_EX @ is there additional state to restore? | 120 | tst r1, #FPEXC_EX @ is there additional state to restore? |
| @@ -174,12 +174,12 @@ vfp_save_state: | |||
| 174 | @ r0 - save location | 174 | @ r0 - save location |
| 175 | @ r1 - FPEXC | 175 | @ r1 - FPEXC |
| 176 | DBGSTR1 "save VFP state %p", r0 | 176 | DBGSTR1 "save VFP state %p", r0 |
| 177 | VFPFSTMIA r0, r2 @ save the working registers | ||
| 177 | VFPFMRX r2, FPSCR @ current status | 178 | VFPFMRX r2, FPSCR @ current status |
| 178 | tst r1, #FPEXC_EX @ is there additional state to save? | 179 | tst r1, #FPEXC_EX @ is there additional state to save? |
| 179 | VFPFMRX r3, FPINST, NE @ FPINST (only if FPEXC.EX is set) | 180 | VFPFMRX r3, FPINST, NE @ FPINST (only if FPEXC.EX is set) |
| 180 | tstne r1, #FPEXC_FP2V @ is there an FPINST2 to read? | 181 | tstne r1, #FPEXC_FP2V @ is there an FPINST2 to read? |
| 181 | VFPFMRX r12, FPINST2, NE @ FPINST2 if needed (and present) | 182 | VFPFMRX r12, FPINST2, NE @ FPINST2 if needed (and present) |
| 182 | VFPFSTMIA r0 @ save the working registers | ||
| 183 | stmia r0, {r1, r2, r3, r12} @ save FPEXC, FPSCR, FPINST, FPINST2 | 183 | stmia r0, {r1, r2, r3, r12} @ save FPEXC, FPSCR, FPINST, FPINST2 |
| 184 | mov pc, lr | 184 | mov pc, lr |
| 185 | #endif | 185 | #endif |
| @@ -217,8 +217,15 @@ vfp_get_double: | |||
| 217 | fmrrd r0, r1, d\dr | 217 | fmrrd r0, r1, d\dr |
| 218 | mov pc, lr | 218 | mov pc, lr |
| 219 | .endr | 219 | .endr |
| 220 | #ifdef CONFIG_VFPv3 | ||
| 221 | @ d16 - d31 registers | ||
| 222 | .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 | ||
| 223 | mrrc p11, 3, r0, r1, c\dr @ fmrrd r0, r1, d\dr | ||
| 224 | mov pc, lr | ||
| 225 | .endr | ||
| 226 | #endif | ||
| 220 | 227 | ||
| 221 | @ virtual register 16 for compare with zero | 228 | @ virtual register 16 (or 32 if VFPv3) for compare with zero |
| 222 | mov r0, #0 | 229 | mov r0, #0 |
| 223 | mov r1, #0 | 230 | mov r1, #0 |
| 224 | mov pc, lr | 231 | mov pc, lr |
| @@ -231,3 +238,10 @@ vfp_put_double: | |||
| 231 | fmdrr d\dr, r0, r1 | 238 | fmdrr d\dr, r0, r1 |
| 232 | mov pc, lr | 239 | mov pc, lr |
| 233 | .endr | 240 | .endr |
| 241 | #ifdef CONFIG_VFPv3 | ||
| 242 | @ d16 - d31 registers | ||
| 243 | .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 | ||
| 244 | mcrr p11, 3, r1, r2, c\dr @ fmdrr r1, r2, d\dr | ||
| 245 | mov pc, lr | ||
| 246 | .endr | ||
| 247 | #endif | ||
diff --git a/arch/arm/vfp/vfpinstr.h b/arch/arm/vfp/vfpinstr.h index 7f343a4beca0..15b95b5ab97e 100644 --- a/arch/arm/vfp/vfpinstr.h +++ b/arch/arm/vfp/vfpinstr.h | |||
| @@ -52,11 +52,11 @@ | |||
| 52 | #define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) | 52 | #define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) |
| 53 | 53 | ||
| 54 | #define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22) | 54 | #define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22) |
| 55 | #define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12) | 55 | #define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18) |
| 56 | #define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5) | 56 | #define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5) |
| 57 | #define vfp_get_dm(inst) ((inst & 0x0000000f)) | 57 | #define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1) |
| 58 | #define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) | 58 | #define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) |
| 59 | #define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16) | 59 | #define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3) |
| 60 | 60 | ||
| 61 | #define vfp_single(inst) (((inst) & 0x0000f00) == 0xa00) | 61 | #define vfp_single(inst) (((inst) & 0x0000f00) == 0xa00) |
| 62 | 62 | ||
diff --git a/include/asm-arm/fpstate.h b/include/asm-arm/fpstate.h index f31cda5a55ee..392eb5332323 100644 --- a/include/asm-arm/fpstate.h +++ b/include/asm-arm/fpstate.h | |||
| @@ -17,14 +17,18 @@ | |||
| 17 | /* | 17 | /* |
| 18 | * VFP storage area has: | 18 | * VFP storage area has: |
| 19 | * - FPEXC, FPSCR, FPINST and FPINST2. | 19 | * - FPEXC, FPSCR, FPINST and FPINST2. |
| 20 | * - 16 double precision data registers | 20 | * - 16 or 32 double precision data registers |
| 21 | * - an implementation-dependant word of state for FLDMX/FSTMX | 21 | * - an implementation-dependant word of state for FLDMX/FSTMX (pre-ARMv6) |
| 22 | * | 22 | * |
| 23 | * FPEXC will always be non-zero once the VFP has been used in this process. | 23 | * FPEXC will always be non-zero once the VFP has been used in this process. |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | struct vfp_hard_struct { | 26 | struct vfp_hard_struct { |
| 27 | #ifdef CONFIG_VFPv3 | ||
| 28 | __u64 fpregs[32]; | ||
| 29 | #else | ||
| 27 | __u64 fpregs[16]; | 30 | __u64 fpregs[16]; |
| 31 | #endif | ||
| 28 | #if __LINUX_ARM_ARCH__ < 6 | 32 | #if __LINUX_ARM_ARCH__ < 6 |
| 29 | __u32 fpmx_state; | 33 | __u32 fpmx_state; |
| 30 | #endif | 34 | #endif |
| @@ -35,6 +39,7 @@ struct vfp_hard_struct { | |||
| 35 | */ | 39 | */ |
| 36 | __u32 fpinst; | 40 | __u32 fpinst; |
| 37 | __u32 fpinst2; | 41 | __u32 fpinst2; |
| 42 | |||
| 38 | #ifdef CONFIG_SMP | 43 | #ifdef CONFIG_SMP |
| 39 | __u32 cpu; | 44 | __u32 cpu; |
| 40 | #endif | 45 | #endif |
diff --git a/include/asm-arm/vfp.h b/include/asm-arm/vfp.h index 9d474d47b266..5f9a2cb3d452 100644 --- a/include/asm-arm/vfp.h +++ b/include/asm-arm/vfp.h | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | 7 | ||
| 8 | #define FPSID cr0 | 8 | #define FPSID cr0 |
| 9 | #define FPSCR cr1 | 9 | #define FPSCR cr1 |
| 10 | #define MVFR1 cr6 | ||
| 11 | #define MVFR0 cr7 | ||
| 10 | #define FPEXC cr8 | 12 | #define FPEXC cr8 |
| 11 | #define FPINST cr9 | 13 | #define FPINST cr9 |
| 12 | #define FPINST2 cr10 | 14 | #define FPINST2 cr10 |
| @@ -70,6 +72,10 @@ | |||
| 70 | #define FPSCR_IXC (1<<4) | 72 | #define FPSCR_IXC (1<<4) |
| 71 | #define FPSCR_IDC (1<<7) | 73 | #define FPSCR_IDC (1<<7) |
| 72 | 74 | ||
| 75 | /* MVFR0 bits */ | ||
| 76 | #define MVFR0_A_SIMD_BIT (0) | ||
| 77 | #define MVFR0_A_SIMD_MASK (0xf << MVFR0_A_SIMD_BIT) | ||
| 78 | |||
| 73 | /* Bit patterns for decoding the packaged operation descriptors */ | 79 | /* Bit patterns for decoding the packaged operation descriptors */ |
| 74 | #define VFPOPDESC_LENGTH_BIT (9) | 80 | #define VFPOPDESC_LENGTH_BIT (9) |
| 75 | #define VFPOPDESC_LENGTH_MASK (0x07 << VFPOPDESC_LENGTH_BIT) | 81 | #define VFPOPDESC_LENGTH_MASK (0x07 << VFPOPDESC_LENGTH_BIT) |
diff --git a/include/asm-arm/vfpmacros.h b/include/asm-arm/vfpmacros.h index 27fe028b4e72..cccb3892e73c 100644 --- a/include/asm-arm/vfpmacros.h +++ b/include/asm-arm/vfpmacros.h | |||
| @@ -15,19 +15,33 @@ | |||
| 15 | .endm | 15 | .endm |
| 16 | 16 | ||
| 17 | @ read all the working registers back into the VFP | 17 | @ read all the working registers back into the VFP |
| 18 | .macro VFPFLDMIA, base | 18 | .macro VFPFLDMIA, base, tmp |
| 19 | #if __LINUX_ARM_ARCH__ < 6 | 19 | #if __LINUX_ARM_ARCH__ < 6 |
| 20 | LDC p11, cr0, [\base],#33*4 @ FLDMIAX \base!, {d0-d15} | 20 | LDC p11, cr0, [\base],#33*4 @ FLDMIAX \base!, {d0-d15} |
| 21 | #else | 21 | #else |
| 22 | LDC p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d0-d15} | 22 | LDC p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d0-d15} |
| 23 | #endif | 23 | #endif |
| 24 | #ifdef CONFIG_VFPv3 | ||
| 25 | VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 | ||
| 26 | and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field | ||
| 27 | cmp \tmp, #2 @ 32 x 64bit registers? | ||
| 28 | ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} | ||
| 29 | addne \base, \base, #32*4 @ step over unused register space | ||
| 30 | #endif | ||
| 24 | .endm | 31 | .endm |
| 25 | 32 | ||
| 26 | @ write all the working registers out of the VFP | 33 | @ write all the working registers out of the VFP |
| 27 | .macro VFPFSTMIA, base | 34 | .macro VFPFSTMIA, base, tmp |
| 28 | #if __LINUX_ARM_ARCH__ < 6 | 35 | #if __LINUX_ARM_ARCH__ < 6 |
| 29 | STC p11, cr0, [\base],#33*4 @ FSTMIAX \base!, {d0-d15} | 36 | STC p11, cr0, [\base],#33*4 @ FSTMIAX \base!, {d0-d15} |
| 30 | #else | 37 | #else |
| 31 | STC p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d0-d15} | 38 | STC p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d0-d15} |
| 32 | #endif | 39 | #endif |
| 40 | #ifdef CONFIG_VFPv3 | ||
| 41 | VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 | ||
| 42 | and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field | ||
| 43 | cmp \tmp, #2 @ 32 x 64bit registers? | ||
| 44 | stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} | ||
| 45 | addne \base, \base, #32*4 @ step over unused register space | ||
| 46 | #endif | ||
| 33 | .endm | 47 | .endm |
