0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/types.h>
0009 #include <linux/kernel.h>
0010 #include <linux/signal.h>
0011 #include <linux/sched.h>
0012 #include <linux/init.h>
0013 #include <linux/io.h>
0014 #include <asm/thread_notify.h>
0015 #include <asm/cputype.h>
0016
0017 asm(" .arch armv5te\n");
0018
0019 static inline void dsp_save_state(u32 *state)
0020 {
0021 __asm__ __volatile__ (
0022 "mrrc p0, 0, %0, %1, c0\n"
0023 : "=r" (state[0]), "=r" (state[1]));
0024 }
0025
0026 static inline void dsp_load_state(u32 *state)
0027 {
0028 __asm__ __volatile__ (
0029 "mcrr p0, 0, %0, %1, c0\n"
0030 : : "r" (state[0]), "r" (state[1]));
0031 }
0032
0033 static int dsp_do(struct notifier_block *self, unsigned long cmd, void *t)
0034 {
0035 struct thread_info *thread = t;
0036
0037 switch (cmd) {
0038 case THREAD_NOTIFY_FLUSH:
0039 thread->cpu_context.extra[0] = 0;
0040 thread->cpu_context.extra[1] = 0;
0041 break;
0042
0043 case THREAD_NOTIFY_SWITCH:
0044 dsp_save_state(current_thread_info()->cpu_context.extra);
0045 dsp_load_state(thread->cpu_context.extra);
0046 break;
0047 }
0048
0049 return NOTIFY_DONE;
0050 }
0051
0052 static struct notifier_block dsp_notifier_block = {
0053 .notifier_call = dsp_do,
0054 };
0055
0056
0057 #ifdef CONFIG_IWMMXT
0058 static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
0059 {
0060 struct thread_info *thread = t;
0061
0062 switch (cmd) {
0063 case THREAD_NOTIFY_FLUSH:
0064
0065
0066
0067
0068
0069
0070
0071
0072 case THREAD_NOTIFY_EXIT:
0073 iwmmxt_task_release(thread);
0074 break;
0075
0076 case THREAD_NOTIFY_SWITCH:
0077 iwmmxt_task_switch(thread);
0078 break;
0079 }
0080
0081 return NOTIFY_DONE;
0082 }
0083
0084 static struct notifier_block iwmmxt_notifier_block = {
0085 .notifier_call = iwmmxt_do,
0086 };
0087 #endif
0088
0089
0090 static u32 __init xscale_cp_access_read(void)
0091 {
0092 u32 value;
0093
0094 __asm__ __volatile__ (
0095 "mrc p15, 0, %0, c15, c1, 0\n\t"
0096 : "=r" (value));
0097
0098 return value;
0099 }
0100
0101 static void __init xscale_cp_access_write(u32 value)
0102 {
0103 u32 temp;
0104
0105 __asm__ __volatile__ (
0106 "mcr p15, 0, %1, c15, c1, 0\n\t"
0107 "mrc p15, 0, %0, c15, c1, 0\n\t"
0108 "mov %0, %0\n\t"
0109 "sub pc, pc, #4\n\t"
0110 : "=r" (temp) : "r" (value));
0111 }
0112
0113
0114
0115
0116
0117
0118
0119 static int __init cpu_has_iwmmxt(void)
0120 {
0121 u32 lo;
0122 u32 hi;
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133 __asm__ __volatile__ (
0134 "mcrr p0, 0, %2, %3, c0\n"
0135 "mrrc p0, 0, %0, %1, c0\n"
0136 : "=r" (lo), "=r" (hi)
0137 : "r" (0), "r" (0x100));
0138
0139 return !!hi;
0140 }
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151 static int __init xscale_cp0_init(void)
0152 {
0153 u32 cp_access;
0154
0155
0156 if (!cpu_is_xscale_family())
0157 return 0;
0158
0159 cp_access = xscale_cp_access_read() & ~3;
0160 xscale_cp_access_write(cp_access | 1);
0161
0162 if (cpu_has_iwmmxt()) {
0163 #ifndef CONFIG_IWMMXT
0164 pr_warn("CAUTION: XScale iWMMXt coprocessor detected, but kernel support is missing.\n");
0165 #else
0166 pr_info("XScale iWMMXt coprocessor detected.\n");
0167 elf_hwcap |= HWCAP_IWMMXT;
0168 thread_register_notifier(&iwmmxt_notifier_block);
0169 #endif
0170 } else {
0171 pr_info("XScale DSP coprocessor detected.\n");
0172 thread_register_notifier(&dsp_notifier_block);
0173 cp_access |= 1;
0174 }
0175
0176 xscale_cp_access_write(cp_access);
0177
0178 return 0;
0179 }
0180
0181 late_initcall(xscale_cp0_init);