Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/arch/arm/kernel/pj4-cp0.c
0004  *
0005  * PJ4 iWMMXt coprocessor context switching and handling
0006  *
0007  * Copyright (c) 2010 Marvell International Inc.
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          * flush_thread() zeroes thread->fpstate, so no need
0027          * to do anything here.
0028          *
0029          * FALLTHROUGH: Ensure we don't try to overwrite our newly
0030          * initialised state information on the first fault.
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     /* check if coprocessor 0 and 1 are available */
0084     if ((pj4_cp_access_read() & 0xf) != 0xf) {
0085         pj4_cp_access_write(cp_access);
0086         return -ENODEV;
0087     }
0088 
0089     /* read iWMMXt coprocessor id register p1, c0 */
0090     __asm__ __volatile__ ("mrc    p1, 0, %0, c0, c0, 0\n" : "=r" (wcid));
0091 
0092     pj4_cp_access_write(cp_access);
0093 
0094     /* iWMMXt v1 */
0095     if ((wcid & 0xffffff00) == 0x56051000)
0096         return 1;
0097     /* iWMMXt v2 */
0098     if ((wcid & 0xffffff00) == 0x56052000)
0099         return 2;
0100 
0101     return -EINVAL;
0102 }
0103 
0104 /*
0105  * Disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy
0106  * switch code handle iWMMXt context switching.
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);