linux/arch/sh/kernel/cpu/sh4a/smp-shx3.c
<<
>>
Prefs
   1/*
   2 * SH-X3 SMP
   3 *
   4 *  Copyright (C) 2007 - 2008  Paul Mundt
   5 *  Copyright (C) 2007  Magnus Damm
   6 *
   7 * This file is subject to the terms and conditions of the GNU General Public
   8 * License.  See the file "COPYING" in the main directory of this archive
   9 * for more details.
  10 */
  11#include <linux/init.h>
  12#include <linux/cpumask.h>
  13#include <linux/smp.h>
  14#include <linux/interrupt.h>
  15#include <linux/io.h>
  16
  17static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
  18{
  19        unsigned int message = (unsigned int)(long)arg;
  20        unsigned int cpu = hard_smp_processor_id();
  21        unsigned int offs = 4 * cpu;
  22        unsigned int x;
  23
  24        x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
  25        x &= (1 << (message << 2));
  26        ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
  27
  28        smp_message_recv(message);
  29
  30        return IRQ_HANDLED;
  31}
  32
  33void __init plat_smp_setup(void)
  34{
  35        unsigned int cpu = 0;
  36        int i, num;
  37
  38        init_cpu_possible(cpumask_of(cpu));
  39
  40        __cpu_number_map[0] = 0;
  41        __cpu_logical_map[0] = 0;
  42
  43        /*
  44         * Do this stupidly for now.. we don't have an easy way to probe
  45         * for the total number of cores.
  46         */
  47        for (i = 1, num = 0; i < NR_CPUS; i++) {
  48                set_cpu_possible(i, true);
  49                __cpu_number_map[i] = ++num;
  50                __cpu_logical_map[num] = i;
  51        }
  52
  53        printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
  54}
  55
  56void __init plat_prepare_cpus(unsigned int max_cpus)
  57{
  58        int i;
  59
  60        local_timer_setup(0);
  61
  62        BUILD_BUG_ON(SMP_MSG_NR >= 8);
  63
  64        for (i = 0; i < SMP_MSG_NR; i++)
  65                request_irq(104 + i, ipi_interrupt_handler, IRQF_DISABLED,
  66                            "IPI", (void *)(long)i);
  67}
  68
  69#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
  70#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
  71
  72#define STBCR_MSTP      0x00000001
  73#define STBCR_RESET     0x00000002
  74#define STBCR_LTSLP     0x80000000
  75
  76#define STBCR_AP_VAL    (STBCR_RESET | STBCR_LTSLP)
  77
  78void plat_start_cpu(unsigned int cpu, unsigned long entry_point)
  79{
  80        ctrl_outl(entry_point, RESET_REG(cpu));
  81
  82        if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
  83                ctrl_outl(STBCR_MSTP, STBCR_REG(cpu));
  84
  85        while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
  86                cpu_relax();
  87
  88        /* Start up secondary processor by sending a reset */
  89        ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu));
  90}
  91
  92int plat_smp_processor_id(void)
  93{
  94        return ctrl_inl(0xff000048); /* CPIDR */
  95}
  96
  97void plat_send_ipi(unsigned int cpu, unsigned int message)
  98{
  99        unsigned long addr = 0xfe410070 + (cpu * 4);
 100
 101        BUG_ON(cpu >= 4);
 102
 103        ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
 104}
 105