0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/signal.h>
0013 #include <linux/sched.h>
0014 #include <linux/init.h>
0015 #include <linux/io.h>
0016 #include <asm/thread_notify.h>
0017 #include <asm/cputype.h>
0018
0019 static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
0020 {
0021 struct thread_info *thread = t;
0022
0023 switch (cmd) {
0024 case THREAD_NOTIFY_FLUSH:
0025
0026
0027
0028
0029
0030
0031
0032
0033 case THREAD_NOTIFY_EXIT:
0034 iwmmxt_task_release(thread);
0035 break;
0036
0037 case THREAD_NOTIFY_SWITCH:
0038 iwmmxt_task_switch(thread);
0039 break;
0040 }
0041
0042 return NOTIFY_DONE;
0043 }
0044
0045 static struct notifier_block __maybe_unused iwmmxt_notifier_block = {
0046 .notifier_call = iwmmxt_do,
0047 };
0048
0049
0050 static u32 __init pj4_cp_access_read(void)
0051 {
0052 u32 value;
0053
0054 __asm__ __volatile__ (
0055 "mrc p15, 0, %0, c1, c0, 2\n\t"
0056 : "=r" (value));
0057 return value;
0058 }
0059
0060 static void __init pj4_cp_access_write(u32 value)
0061 {
0062 u32 temp;
0063
0064 __asm__ __volatile__ (
0065 "mcr p15, 0, %1, c1, c0, 2\n\t"
0066 #ifdef CONFIG_THUMB2_KERNEL
0067 "isb\n\t"
0068 #else
0069 "mrc p15, 0, %0, c1, c0, 2\n\t"
0070 "mov %0, %0\n\t"
0071 "sub pc, pc, #4\n\t"
0072 #endif
0073 : "=r" (temp) : "r" (value));
0074 }
0075
0076 static int __init pj4_get_iwmmxt_version(void)
0077 {
0078 u32 cp_access, wcid;
0079
0080 cp_access = pj4_cp_access_read();
0081 pj4_cp_access_write(cp_access | 0xf);
0082
0083
0084 if ((pj4_cp_access_read() & 0xf) != 0xf) {
0085 pj4_cp_access_write(cp_access);
0086 return -ENODEV;
0087 }
0088
0089
0090 __asm__ __volatile__ ("mrc p1, 0, %0, c0, c0, 0\n" : "=r" (wcid));
0091
0092 pj4_cp_access_write(cp_access);
0093
0094
0095 if ((wcid & 0xffffff00) == 0x56051000)
0096 return 1;
0097
0098 if ((wcid & 0xffffff00) == 0x56052000)
0099 return 2;
0100
0101 return -EINVAL;
0102 }
0103
0104
0105
0106
0107
0108 static int __init pj4_cp0_init(void)
0109 {
0110 u32 __maybe_unused cp_access;
0111 int vers;
0112
0113 if (!cpu_is_pj4())
0114 return 0;
0115
0116 vers = pj4_get_iwmmxt_version();
0117 if (vers < 0)
0118 return 0;
0119
0120 #ifndef CONFIG_IWMMXT
0121 pr_info("PJ4 iWMMXt coprocessor detected, but kernel support is missing.\n");
0122 #else
0123 cp_access = pj4_cp_access_read() & ~0xf;
0124 pj4_cp_access_write(cp_access);
0125
0126 pr_info("PJ4 iWMMXt v%d coprocessor enabled.\n", vers);
0127 elf_hwcap |= HWCAP_IWMMXT;
0128 thread_register_notifier(&iwmmxt_notifier_block);
0129 #endif
0130
0131 return 0;
0132 }
0133
0134 late_initcall(pj4_cp0_init);