linux/arch/arm/kernel/pj4-cp0.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/kernel/pj4-cp0.c
   3 *
   4 * PJ4 iWMMXt coprocessor context switching and handling
   5 *
   6 * Copyright (c) 2010 Marvell International Inc.
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/types.h>
  14#include <linux/kernel.h>
  15#include <linux/signal.h>
  16#include <linux/sched.h>
  17#include <linux/init.h>
  18#include <linux/io.h>
  19#include <asm/thread_notify.h>
  20#include <asm/cputype.h>
  21
  22static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
  23{
  24        struct thread_info *thread = t;
  25
  26        switch (cmd) {
  27        case THREAD_NOTIFY_FLUSH:
  28                /*
  29                 * flush_thread() zeroes thread->fpstate, so no need
  30                 * to do anything here.
  31                 *
  32                 * FALLTHROUGH: Ensure we don't try to overwrite our newly
  33                 * initialised state information on the first fault.
  34                 */
  35
  36        case THREAD_NOTIFY_EXIT:
  37                iwmmxt_task_release(thread);
  38                break;
  39
  40        case THREAD_NOTIFY_SWITCH:
  41                iwmmxt_task_switch(thread);
  42                break;
  43        }
  44
  45        return NOTIFY_DONE;
  46}
  47
  48static struct notifier_block __maybe_unused iwmmxt_notifier_block = {
  49        .notifier_call  = iwmmxt_do,
  50};
  51
  52
  53static u32 __init pj4_cp_access_read(void)
  54{
  55        u32 value;
  56
  57        __asm__ __volatile__ (
  58                "mrc    p15, 0, %0, c1, c0, 2\n\t"
  59                : "=r" (value));
  60        return value;
  61}
  62
  63static void __init pj4_cp_access_write(u32 value)
  64{
  65        u32 temp;
  66
  67        __asm__ __volatile__ (
  68                "mcr    p15, 0, %1, c1, c0, 2\n\t"
  69#ifdef CONFIG_THUMB2_KERNEL
  70                "isb\n\t"
  71#else
  72                "mrc    p15, 0, %0, c1, c0, 2\n\t"
  73                "mov    %0, %0\n\t"
  74                "sub    pc, pc, #4\n\t"
  75#endif
  76                : "=r" (temp) : "r" (value));
  77}
  78
  79static int __init pj4_get_iwmmxt_version(void)
  80{
  81        u32 cp_access, wcid;
  82
  83        cp_access = pj4_cp_access_read();
  84        pj4_cp_access_write(cp_access | 0xf);
  85
  86        /* check if coprocessor 0 and 1 are available */
  87        if ((pj4_cp_access_read() & 0xf) != 0xf) {
  88                pj4_cp_access_write(cp_access);
  89                return -ENODEV;
  90        }
  91
  92        /* read iWMMXt coprocessor id register p1, c0 */
  93        __asm__ __volatile__ ("mrc    p1, 0, %0, c0, c0, 0\n" : "=r" (wcid));
  94
  95        pj4_cp_access_write(cp_access);
  96
  97        /* iWMMXt v1 */
  98        if ((wcid & 0xffffff00) == 0x56051000)
  99                return 1;
 100        /* iWMMXt v2 */
 101        if ((wcid & 0xffffff00) == 0x56052000)
 102                return 2;
 103
 104        return -EINVAL;
 105}
 106
 107/*
 108 * Disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy
 109 * switch code handle iWMMXt context switching.
 110 */
 111static int __init pj4_cp0_init(void)
 112{
 113        u32 __maybe_unused cp_access;
 114        int vers;
 115
 116        if (!cpu_is_pj4())
 117                return 0;
 118
 119        vers = pj4_get_iwmmxt_version();
 120        if (vers < 0)
 121                return 0;
 122
 123#ifndef CONFIG_IWMMXT
 124        pr_info("PJ4 iWMMXt coprocessor detected, but kernel support is missing.\n");
 125#else
 126        cp_access = pj4_cp_access_read() & ~0xf;
 127        pj4_cp_access_write(cp_access);
 128
 129        pr_info("PJ4 iWMMXt v%d coprocessor enabled.\n", vers);
 130        elf_hwcap |= HWCAP_IWMMXT;
 131        thread_register_notifier(&iwmmxt_notifier_block);
 132#endif
 133
 134        return 0;
 135}
 136
 137late_initcall(pj4_cp0_init);
 138