ARM: pxa: add iwmmx support for PJ4
authorHaojian Zhuang <haojian.zhuang@marvell.com>
Wed, 24 Nov 2010 03:54:25 +0000 (11:54 +0800)
committerEric Miao <eric.y.miao@gmail.com>
Mon, 20 Dec 2010 15:07:36 +0000 (23:07 +0800)
iwmmxt is used in XScale, XScale3, Mohawk and PJ4 core. But the instructions
of accessing CP0 and CP1 is changed in PJ4. Append more files to support
iwmmxt in PJ4 core.

Signed-off-by: Zhou Zhu <zzhu3@marvell.com>
Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
Acked-by: Nicolas Pitre <nico@fluxnic.net>
Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
arch/arm/Kconfig
arch/arm/kernel/Makefile
arch/arm/kernel/iwmmxt.S
arch/arm/kernel/pj4-cp0.c [new file with mode: 0644]

index d56d21c..e2c79a2 100644 (file)
@@ -999,8 +999,8 @@ source arch/arm/mm/Kconfig
 
 config IWMMXT
        bool "Enable iWMMXt support"
-       depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK
-       default y if PXA27x || PXA3xx || ARCH_MMP
+       depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_PJ4
+       default y if PXA27x || PXA3xx || PXA95x || ARCH_MMP
        help
          Enable support for iWMMXt context switching at run time if
          running on a CPU that supports it.
index 5b9b268..b0f11fa 100644 (file)
@@ -50,6 +50,7 @@ AFLAGS_crunch-bits.o          := -Wa,-mcpu=ep9312
 obj-$(CONFIG_CPU_XSCALE)       += xscale-cp0.o
 obj-$(CONFIG_CPU_XSC3)         += xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)       += xscale-cp0.o
+obj-$(CONFIG_CPU_PJ4)          += pj4-cp0.o
 obj-$(CONFIG_IWMMXT)           += iwmmxt.o
 obj-$(CONFIG_CPU_HAS_PMU)      += pmu.o
 obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event.o
index b63b528..7fa3bb0 100644 (file)
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
 
+#if defined(CONFIG_CPU_PJ4)
+#define PJ4(code...)           code
+#define XSC(code...)
+#else
+#define PJ4(code...)
+#define XSC(code...)           code
+#endif
+
 #define MMX_WR0                        (0x00)
 #define MMX_WR1                        (0x08)
 #define MMX_WR2                        (0x10)
 
 ENTRY(iwmmxt_task_enable)
 
-       mrc     p15, 0, r2, c15, c1, 0
-       tst     r2, #0x3                        @ CP0 and CP1 accessible?
+       XSC(mrc p15, 0, r2, c15, c1, 0)
+       PJ4(mrc p15, 0, r2, c1, c0, 2)
+       @ CP0 and CP1 accessible?
+       XSC(tst r2, #0x3)
+       PJ4(tst r2, #0xf)
        movne   pc, lr                          @ if so no business here
-       orr     r2, r2, #0x3                    @ enable access to CP0 and CP1
-       mcr     p15, 0, r2, c15, c1, 0
+       @ enable access to CP0 and CP1
+       XSC(orr r2, r2, #0x3)
+       XSC(mcr p15, 0, r2, c15, c1, 0)
+       PJ4(orr r2, r2, #0xf)
+       PJ4(mcr p15, 0, r2, c1, c0, 2)
 
        ldr     r3, =concan_owner
        add     r0, r10, #TI_IWMMXT_STATE       @ get task Concan save area
@@ -179,17 +193,26 @@ ENTRY(iwmmxt_task_disable)
        teqne   r1, r2                          @ or specified one?
        bne     1f                              @ no: quit
 
-       mrc     p15, 0, r4, c15, c1, 0
-       orr     r4, r4, #0x3                    @ enable access to CP0 and CP1
-       mcr     p15, 0, r4, c15, c1, 0
+       @ enable access to CP0 and CP1
+       XSC(mrc p15, 0, r4, c15, c1, 0)
+       XSC(orr r4, r4, #0xf)
+       XSC(mcr p15, 0, r4, c15, c1, 0)
+       PJ4(mrc p15, 0, r4, c1, c0, 2)
+       PJ4(orr r4, r4, #0x3)
+       PJ4(mcr p15, 0, r4, c1, c0, 2)
+
        mov     r0, #0                          @ nothing to load
        str     r0, [r3]                        @ no more current owner
        mrc     p15, 0, r2, c2, c0, 0
        mov     r2, r2                          @ cpwait
        bl      concan_save
 
-       bic     r4, r4, #0x3                    @ disable access to CP0 and CP1
-       mcr     p15, 0, r4, c15, c1, 0
+       @ disable access to CP0 and CP1
+       XSC(bic r4, r4, #0x3)
+       XSC(mcr p15, 0, r4, c15, c1, 0)
+       PJ4(bic r4, r4, #0xf)
+       PJ4(mcr p15, 0, r4, c1, c0, 2)
+
        mrc     p15, 0, r2, c2, c0, 0
        mov     r2, r2                          @ cpwait
 
@@ -277,8 +300,11 @@ ENTRY(iwmmxt_task_restore)
  */
 ENTRY(iwmmxt_task_switch)
 
-       mrc     p15, 0, r1, c15, c1, 0
-       tst     r1, #0x3                        @ CP0 and CP1 accessible?
+       XSC(mrc p15, 0, r1, c15, c1, 0)
+       PJ4(mrc p15, 0, r1, c1, c0, 2)
+       @ CP0 and CP1 accessible?
+       XSC(tst r1, #0x3)
+       PJ4(tst r1, #0xf)
        bne     1f                              @ yes: block them for next task
 
        ldr     r2, =concan_owner
@@ -287,8 +313,11 @@ ENTRY(iwmmxt_task_switch)
        teq     r2, r3                          @ next task owns it?
        movne   pc, lr                          @ no: leave Concan disabled
 
-1:     eor     r1, r1, #3                      @ flip Concan access
-       mcr     p15, 0, r1, c15, c1, 0
+1:     @ flip Conan access
+       XSC(eor r1, r1, #0x3)
+       XSC(mcr p15, 0, r1, c15, c1, 0)
+       PJ4(eor r1, r1, #0xf)
+       PJ4(mcr p15, 0, r1, c1, c0, 2)
 
        mrc     p15, 0, r1, c2, c0, 0
        sub     pc, lr, r1, lsr #32             @ cpwait and return
diff --git a/arch/arm/kernel/pj4-cp0.c b/arch/arm/kernel/pj4-cp0.c
new file mode 100644 (file)
index 0000000..a4b1b07
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * linux/arch/arm/kernel/pj4-cp0.c
+ *
+ * PJ4 iWMMXt coprocessor context switching and handling
+ *
+ * Copyright (c) 2010 Marvell International Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/thread_notify.h>
+
+static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
+{
+       struct thread_info *thread = t;
+
+       switch (cmd) {
+       case THREAD_NOTIFY_FLUSH:
+               /*
+                * flush_thread() zeroes thread->fpstate, so no need
+                * to do anything here.
+                *
+                * FALLTHROUGH: Ensure we don't try to overwrite our newly
+                * initialised state information on the first fault.
+                */
+
+       case THREAD_NOTIFY_EXIT:
+               iwmmxt_task_release(thread);
+               break;
+
+       case THREAD_NOTIFY_SWITCH:
+               iwmmxt_task_switch(thread);
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block iwmmxt_notifier_block = {
+       .notifier_call  = iwmmxt_do,
+};
+
+
+static u32 __init pj4_cp_access_read(void)
+{
+       u32 value;
+
+       __asm__ __volatile__ (
+               "mrc    p15, 0, %0, c1, c0, 2\n\t"
+               : "=r" (value));
+       return value;
+}
+
+static void __init pj4_cp_access_write(u32 value)
+{
+       u32 temp;
+
+       __asm__ __volatile__ (
+               "mcr    p15, 0, %1, c1, c0, 2\n\t"
+               "mrc    p15, 0, %0, c1, c0, 2\n\t"
+               "mov    %0, %0\n\t"
+               "sub    pc, pc, #4\n\t"
+               : "=r" (temp) : "r" (value));
+}
+
+
+/*
+ * Disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy
+ * switch code handle iWMMXt context switching.
+ */
+static int __init pj4_cp0_init(void)
+{
+       u32 cp_access;
+
+       cp_access = pj4_cp_access_read() & ~0xf;
+       pj4_cp_access_write(cp_access);
+
+       printk(KERN_INFO "PJ4 iWMMXt coprocessor enabled.\n");
+       elf_hwcap |= HWCAP_IWMMXT;
+       thread_register_notifier(&iwmmxt_notifier_block);
+
+       return 0;
+}
+
+late_initcall(pj4_cp0_init);