[POWERPC] 4xx: Workaround for the 440EP(x)/GR(x) processors identical PVR issue.
authorValentine Barshak <vbarshak@ru.mvista.com>
Thu, 25 Oct 2007 18:16:40 +0000 (04:16 +1000)
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>
Thu, 1 Nov 2007 12:13:43 +0000 (07:13 -0500)
PowerPC 440EP(x) 440GR(x) processors have the same PVR values, since
they have identical cores. However, FPU is not supported on GR(x) and
enabling APU instruction broadcast in the CCR0 register (to enable FPU)
may cause unpredictable results. There's no safe way to detect FPU
support at runtime. This patch provides a workarund for the issue.

We use a POWER6 "logical PVR approach". First, we identify all EP(x)
and GR(x) processors as GR(x) ones (which is safe). Then we check
the device tree cpu path. If we have a EP(x) processor entry,
we call identify_cpu again with PVR | 0x8. This bit is always 0
in the real PVR. This way we enable FPU only for 440EP(x).

Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/prom.c

index d3fb7d0c6c1c255b3569dc845a671962d0e5393f..9ed351f3c96625dd6e4862cb7c40bc5d1393a8bd 100644 (file)
@@ -1104,6 +1104,16 @@ static struct cpu_spec __initdata cpu_specs[] = {
        {
                .pvr_mask               = 0xf0000fff,
                .pvr_value              = 0x40000850,
+               .cpu_name               = "440GR Rev. A",
+               .cpu_features           = CPU_FTRS_44X,
+               .cpu_user_features      = COMMON_USER_BOOKE,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .platform               = "ppc440",
+       },
+       { /* Use logical PVR for 440EP (logical pvr = pvr | 0x8) */
+               .pvr_mask               = 0xf0000fff,
+               .pvr_value              = 0x40000858,
                .cpu_name               = "440EP Rev. A",
                .cpu_features           = CPU_FTRS_44X,
                .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
@@ -1115,28 +1125,27 @@ static struct cpu_spec __initdata cpu_specs[] = {
        {
                .pvr_mask               = 0xf0000fff,
                .pvr_value              = 0x400008d3,
-               .cpu_name               = "440EP Rev. B",
+               .cpu_name               = "440GR Rev. B",
                .cpu_features           = CPU_FTRS_44X,
                .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
-               .cpu_setup              = __setup_cpu_440ep,
                .platform               = "ppc440",
        },
-       { /* 440EPX */
-               .pvr_mask               = 0xf0000ffb,
-               .pvr_value              = 0x200008D0,
-               .cpu_name               = "440EPX",
+       { /* Use logical PVR for 440EP (logical pvr = pvr | 0x8) */
+               .pvr_mask               = 0xf0000fff,
+               .pvr_value              = 0x400008db,
+               .cpu_name               = "440EP Rev. B",
                .cpu_features           = CPU_FTRS_44X,
                .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
-               .cpu_setup              = __setup_cpu_440epx,
+               .cpu_setup              = __setup_cpu_440ep,
                .platform               = "ppc440",
        },
        { /* 440GRX */
                .pvr_mask               = 0xf0000ffb,
-               .pvr_value              = 0x200008D8,
+               .pvr_value              = 0x200008D0,
                .cpu_name               = "440GRX",
                .cpu_features           = CPU_FTRS_44X,
                .cpu_user_features      = COMMON_USER_BOOKE,
@@ -1145,6 +1154,17 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_setup              = __setup_cpu_440grx,
                .platform               = "ppc440",
        },
+       { /* Use logical PVR for 440EPx (logical pvr = pvr | 0x8) */
+               .pvr_mask               = 0xf0000ffb,
+               .pvr_value              = 0x200008D8,
+               .cpu_name               = "440EPX",
+               .cpu_features           = CPU_FTRS_44X,
+               .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .cpu_setup              = __setup_cpu_440epx,
+               .platform               = "ppc440",
+       },
        {       /* 440GP Rev. B */
                .pvr_mask               = 0xf0000fff,
                .pvr_value              = 0x40000440,
index 9f329a8928eaed27f3192e27c729e24bb73ac888..acc0d247d3c3a83920c92cb11f33639a86e8da1b 100644 (file)
@@ -697,6 +697,18 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
                prop = of_get_flat_dt_prop(node, "cpu-version", NULL);
                if (prop && (*prop & 0xff000000) == 0x0f000000)
                        identify_cpu(0, *prop);
+#if defined(CONFIG_44x) && defined(CONFIG_PPC_FPU)
+               /*
+                * Since 440GR(x)/440EP(x) processors have the same pvr,
+                * we check the node path and set bit 28 in the cur_cpu_spec
+                * pvr for EP(x) processor version. This bit is always 0 in
+                * the "real" pvr. Then we call identify_cpu again with
+                * the new logical pvr to enable FPU support.
+                */
+               if (strstr(uname, "440EP")) {
+                       identify_cpu(0, cur_cpu_spec->pvr_value | 0x8);
+               }
+#endif
        }
 
        check_cpu_feature_properties(node);