aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/vfp
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2014-11-10 15:56:41 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-11-21 10:24:43 -0500
commit6c96a4a6e249a0580b32893583771149e0611375 (patch)
treed4a695457221a336518c261b5e6601259bf7a510 /arch/arm/vfp
parent6f0f2a9f0f8f420f604e1ae06f1d24cc9b61a9d0 (diff)
ARM: 8197/1: vfp: Fix VFPv3 hwcap detection on CPUID based cpus
The subarchitecture field in the fpsid register is 7 bits wide on ARM CPUs using the CPUID identification scheme, spanning bits 22 to 16. The topmost bit is used to designate that the subarchitecture designer is not ARM when it is set to 1. On non-CPUID scheme CPUs the subarchitecture field is only 4 bits wide and the higher bits are used to indicate no double precision support (bit 20) and the FTSMX/FLDMX format (bits 21-22). The VFP support code only looks at bits 19-16 to determine the VFP version. On Qualcomm's processors (Krait and Scorpion) we should see that we have HWCAP_VFPv3 but we don't because bit 22 is set to 1 to indicate that the subarchitecture is not implemented by ARM and the rest of the bits are left as 0 because this is the first subarchitecture that Qualcomm has designed. Unfortunately we can't just widen the FPSID subarchitecture bitmask to consider all the bits on a CPUID scheme because there may be CPUs without the CPUID scheme that have VFP without double precision support and then the version would be a very wrong and large number. Instead, update the version detection logic to consider if the CPU is using the CPUID scheme. If the CPU is using CPUID scheme, use the MVFR registers to determine what version of VFP is supported. We already do this for VFPv4, so do something similar for VFPv3 and look for single or double precision support in MVFR0. Otherwise fall back to using FPSID to detect VFP support on non-CPUID scheme CPUs. We know that VFPv3 is only present in CPUs that have support for the CPUID scheme so this should be equivalent. Tested-by: Rob Clark <robdclark@gmail.com> Reviewed-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r--arch/arm/vfp/vfpmodule.c93
1 files changed, 52 insertions, 41 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 2f37e1d6cb45..5002d002f6e3 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -722,6 +722,7 @@ static int __init vfp_init(void)
722{ 722{
723 unsigned int vfpsid; 723 unsigned int vfpsid;
724 unsigned int cpu_arch = cpu_architecture(); 724 unsigned int cpu_arch = cpu_architecture();
725 u32 mvfr0;
725 726
726 if (cpu_arch >= CPU_ARCH_ARMv6) 727 if (cpu_arch >= CPU_ARCH_ARMv6)
727 on_each_cpu(vfp_enable, NULL, 1); 728 on_each_cpu(vfp_enable, NULL, 1);
@@ -738,63 +739,73 @@ static int __init vfp_init(void)
738 vfp_vector = vfp_null_entry; 739 vfp_vector = vfp_null_entry;
739 740
740 pr_info("VFP support v0.3: "); 741 pr_info("VFP support v0.3: ");
741 if (VFP_arch) 742 if (VFP_arch) {
742 pr_cont("not present\n"); 743 pr_cont("not present\n");
743 else if (vfpsid & FPSID_NODOUBLE) { 744 return 0;
744 pr_cont("no double precision support\n"); 745 /* Extract the architecture on CPUID scheme */
745 } else { 746 } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
746 hotcpu_notifier(vfp_hotplug, 0); 747 VFP_arch = vfpsid & FPSID_CPUID_ARCH_MASK;
747 748 VFP_arch >>= FPSID_ARCH_BIT;
748 VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */
749 pr_cont("implementor %02x architecture %d part %02x variant %x rev %x\n",
750 (vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT,
751 (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT,
752 (vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT,
753 (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT,
754 (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT);
755
756 vfp_vector = vfp_support_entry;
757
758 thread_register_notifier(&vfp_notifier_block);
759 vfp_pm_init();
760
761 /* 749 /*
762 * We detected VFP, and the support code is 750 * Check for the presence of the Advanced SIMD
763 * in place; report VFP support to userspace. 751 * load/store instructions, integer and single
752 * precision floating point operations. Only check
753 * for NEON if the hardware has the MVFR registers.
764 */ 754 */
765 elf_hwcap |= HWCAP_VFP; 755#ifdef CONFIG_NEON
756 if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
757 elf_hwcap |= HWCAP_NEON;
758#endif
766#ifdef CONFIG_VFPv3 759#ifdef CONFIG_VFPv3
767 if (VFP_arch >= 2) { 760 mvfr0 = fmrx(MVFR0);
761 if (((mvfr0 & MVFR0_DP_MASK) >> MVFR0_DP_BIT) == 0x2 ||
762 ((mvfr0 & MVFR0_SP_MASK) >> MVFR0_SP_BIT) == 0x2) {
768 elf_hwcap |= HWCAP_VFPv3; 763 elf_hwcap |= HWCAP_VFPv3;
769
770 /* 764 /*
771 * Check for VFPv3 D16 and VFPv4 D16. CPUs in 765 * Check for VFPv3 D16 and VFPv4 D16. CPUs in
772 * this configuration only have 16 x 64bit 766 * this configuration only have 16 x 64bit
773 * registers. 767 * registers.
774 */ 768 */
775 if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1) 769 if ((mvfr0 & MVFR0_A_SIMD_MASK) == 1)
776 elf_hwcap |= HWCAP_VFPv3D16; /* also v4-D16 */ 770 /* also v4-D16 */
771 elf_hwcap |= HWCAP_VFPv3D16;
777 else 772 else
778 elf_hwcap |= HWCAP_VFPD32; 773 elf_hwcap |= HWCAP_VFPD32;
779 } 774 }
775
776 if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000)
777 elf_hwcap |= HWCAP_VFPv4;
780#endif 778#endif
781 /* 779 /* Extract the architecture version on pre-cpuid scheme */
782 * Check for the presence of the Advanced SIMD 780 } else {
783 * load/store instructions, integer and single 781 if (vfpsid & FPSID_NODOUBLE) {
784 * precision floating point operations. Only check 782 pr_cont("no double precision support\n");
785 * for NEON if the hardware has the MVFR registers. 783 return 0;
786 */
787 if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
788#ifdef CONFIG_NEON
789 if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
790 elf_hwcap |= HWCAP_NEON;
791#endif
792#ifdef CONFIG_VFPv3
793 if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000)
794 elf_hwcap |= HWCAP_VFPv4;
795#endif
796 } 784 }
785
786 VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT;
797 } 787 }
788
789 hotcpu_notifier(vfp_hotplug, 0);
790
791 vfp_vector = vfp_support_entry;
792
793 thread_register_notifier(&vfp_notifier_block);
794 vfp_pm_init();
795
796 /*
797 * We detected VFP, and the support code is
798 * in place; report VFP support to userspace.
799 */
800 elf_hwcap |= HWCAP_VFP;
801
802 pr_cont("implementor %02x architecture %d part %02x variant %x rev %x\n",
803 (vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT,
804 VFP_arch,
805 (vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT,
806 (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT,
807 (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT);
808
798 return 0; 809 return 0;
799} 810}
800 811