diff options
author | Tony Lindgren <tony@atomide.com> | 2010-07-01 08:41:05 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-07-09 09:41:34 -0400 |
commit | 5aaf254409f8d58229107b59507a8235b715a960 (patch) | |
tree | 30b3a289808a34a1db28a0eb6d92bc160be3bc0c /arch | |
parent | e513f8bf240d34bd6e732ba2f74df9ab84686ce6 (diff) |
ARM: 6203/1: Make VFPv3 usable on ARMv6
MVFR0 and MVFR1 are only available starting with ARM1136 r1p0 release
according to "B.5 VFP changes" in DDI0211F_arm1136_r1p0_trm.pdf. This is
also when TLS register got added, so we can use HAS_TLS also to test for
MVFR0 and MVFR1.
Otherwise VFPFMRX and VFPFMXR access fails and we get:
Internal error: Oops - undefined instruction: 0 [#1]
PC is at no_old_VFP_process+0x8/0x3c
LR is at __und_svc+0x48/0x80
...
Signed-off-by: Tony Lindgren <tony@atomide.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/vfpmacros.h | 18 | ||||
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 10 |
2 files changed, 25 insertions, 3 deletions
diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h index 422f3cc204a2..3d5fc41ae8d3 100644 --- a/arch/arm/include/asm/vfpmacros.h +++ b/arch/arm/include/asm/vfpmacros.h | |||
@@ -3,6 +3,8 @@ | |||
3 | * | 3 | * |
4 | * Assembler-only file containing VFP macros and register definitions. | 4 | * Assembler-only file containing VFP macros and register definitions. |
5 | */ | 5 | */ |
6 | #include <asm/hwcap.h> | ||
7 | |||
6 | #include "vfp.h" | 8 | #include "vfp.h" |
7 | 9 | ||
8 | @ Macros to allow building with old toolkits (with no VFP support) | 10 | @ Macros to allow building with old toolkits (with no VFP support) |
@@ -22,12 +24,20 @@ | |||
22 | LDC p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d0-d15} | 24 | LDC p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d0-d15} |
23 | #endif | 25 | #endif |
24 | #ifdef CONFIG_VFPv3 | 26 | #ifdef CONFIG_VFPv3 |
27 | #if __LINUX_ARM_ARCH__ <= 6 | ||
28 | ldr \tmp, =elf_hwcap @ may not have MVFR regs | ||
29 | ldr \tmp, [\tmp, #0] | ||
30 | tst \tmp, #HWCAP_VFPv3D16 | ||
31 | ldceq p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} | ||
32 | addne \base, \base, #32*4 @ step over unused register space | ||
33 | #else | ||
25 | VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 | 34 | VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 |
26 | and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field | 35 | and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field |
27 | cmp \tmp, #2 @ 32 x 64bit registers? | 36 | cmp \tmp, #2 @ 32 x 64bit registers? |
28 | ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} | 37 | ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} |
29 | addne \base, \base, #32*4 @ step over unused register space | 38 | addne \base, \base, #32*4 @ step over unused register space |
30 | #endif | 39 | #endif |
40 | #endif | ||
31 | .endm | 41 | .endm |
32 | 42 | ||
33 | @ write all the working registers out of the VFP | 43 | @ write all the working registers out of the VFP |
@@ -38,10 +48,18 @@ | |||
38 | STC p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d0-d15} | 48 | STC p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d0-d15} |
39 | #endif | 49 | #endif |
40 | #ifdef CONFIG_VFPv3 | 50 | #ifdef CONFIG_VFPv3 |
51 | #if __LINUX_ARM_ARCH__ <= 6 | ||
52 | ldr \tmp, =elf_hwcap @ may not have MVFR regs | ||
53 | ldr \tmp, [\tmp, #0] | ||
54 | tst \tmp, #HWCAP_VFPv3D16 | ||
55 | stceq p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} | ||
56 | addne \base, \base, #32*4 @ step over unused register space | ||
57 | #else | ||
41 | VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 | 58 | VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 |
42 | and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field | 59 | and \tmp, \tmp, #MVFR0_A_SIMD_MASK @ A_SIMD field |
43 | cmp \tmp, #2 @ 32 x 64bit registers? | 60 | cmp \tmp, #2 @ 32 x 64bit registers? |
44 | stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} | 61 | stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} |
45 | addne \base, \base, #32*4 @ step over unused register space | 62 | addne \base, \base, #32*4 @ step over unused register space |
46 | #endif | 63 | #endif |
64 | #endif | ||
47 | .endm | 65 | .endm |
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 315a540c7ce5..8063a322c790 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | 17 | ||
18 | #include <asm/cputype.h> | ||
18 | #include <asm/thread_notify.h> | 19 | #include <asm/thread_notify.h> |
19 | #include <asm/vfp.h> | 20 | #include <asm/vfp.h> |
20 | 21 | ||
@@ -549,10 +550,13 @@ static int __init vfp_init(void) | |||
549 | /* | 550 | /* |
550 | * Check for the presence of the Advanced SIMD | 551 | * Check for the presence of the Advanced SIMD |
551 | * load/store instructions, integer and single | 552 | * load/store instructions, integer and single |
552 | * precision floating point operations. | 553 | * precision floating point operations. Only check |
554 | * for NEON if the hardware has the MVFR registers. | ||
553 | */ | 555 | */ |
554 | if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) | 556 | if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { |
555 | elf_hwcap |= HWCAP_NEON; | 557 | if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100) |
558 | elf_hwcap |= HWCAP_NEON; | ||
559 | } | ||
556 | #endif | 560 | #endif |
557 | } | 561 | } |
558 | return 0; | 562 | return 0; |