linux/arch/sh/kernel/cpu/sh2/smp-j2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * SMP support for J2 processor
   4 *
   5 * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
   6 */
   7
   8#include <linux/smp.h>
   9#include <linux/interrupt.h>
  10#include <linux/io.h>
  11#include <linux/of_address.h>
  12#include <linux/of_irq.h>
  13#include <asm/cmpxchg.h>
  14
  15DEFINE_PER_CPU(unsigned, j2_ipi_messages);
  16
  17extern u32 *sh2_cpuid_addr;
  18static u32 *j2_ipi_trigger;
  19static int j2_ipi_irq;
  20
  21static irqreturn_t j2_ipi_interrupt_handler(int irq, void *arg)
  22{
  23        unsigned cpu = hard_smp_processor_id();
  24        volatile unsigned *pmsg = &per_cpu(j2_ipi_messages, cpu);
  25        unsigned messages, i;
  26
  27        do messages = *pmsg;
  28        while (cmpxchg(pmsg, messages, 0) != messages);
  29
  30        if (!messages) return IRQ_NONE;
  31
  32        for (i=0; i<SMP_MSG_NR; i++)
  33                if (messages & (1U<<i))
  34                        smp_message_recv(i);
  35
  36        return IRQ_HANDLED;
  37}
  38
  39static void j2_smp_setup(void)
  40{
  41}
  42
  43static void j2_prepare_cpus(unsigned int max_cpus)
  44{
  45        struct device_node *np;
  46        unsigned i, max = 1;
  47
  48        np = of_find_compatible_node(NULL, NULL, "jcore,ipi-controller");
  49        if (!np)
  50                goto out;
  51
  52        j2_ipi_irq = irq_of_parse_and_map(np, 0);
  53        j2_ipi_trigger = of_iomap(np, 0);
  54        if (!j2_ipi_irq || !j2_ipi_trigger)
  55                goto out;
  56
  57        np = of_find_compatible_node(NULL, NULL, "jcore,cpuid-mmio");
  58        if (!np)
  59                goto out;
  60
  61        sh2_cpuid_addr = of_iomap(np, 0);
  62        if (!sh2_cpuid_addr)
  63                goto out;
  64
  65        if (request_irq(j2_ipi_irq, j2_ipi_interrupt_handler, IRQF_PERCPU,
  66                        "ipi", (void *)j2_ipi_interrupt_handler) != 0)
  67                goto out;
  68
  69        max = max_cpus;
  70out:
  71        /* Disable any cpus past max_cpus, or all secondaries if we didn't
  72         * get the necessary resources to support SMP. */
  73        for (i=max; i<NR_CPUS; i++) {
  74                set_cpu_possible(i, false);
  75                set_cpu_present(i, false);
  76        }
  77}
  78
  79static void j2_start_cpu(unsigned int cpu, unsigned long entry_point)
  80{
  81        struct device_node *np;
  82        u32 regs[2];
  83        void __iomem *release, *initpc;
  84
  85        if (!cpu) return;
  86
  87        np = of_get_cpu_node(cpu, NULL);
  88        if (!np) return;
  89
  90        if (of_property_read_u32_array(np, "cpu-release-addr", regs, 2)) return;
  91        release = ioremap(regs[0], sizeof(u32));
  92        initpc = ioremap(regs[1], sizeof(u32));
  93
  94        __raw_writel(entry_point, initpc);
  95        __raw_writel(1, release);
  96
  97        iounmap(initpc);
  98        iounmap(release);
  99
 100        pr_info("J2 SMP: requested start of cpu %u\n", cpu);
 101}
 102
 103static unsigned int j2_smp_processor_id(void)
 104{
 105        return __raw_readl(sh2_cpuid_addr);
 106}
 107
 108static void j2_send_ipi(unsigned int cpu, unsigned int message)
 109{
 110        volatile unsigned *pmsg;
 111        unsigned old;
 112        unsigned long val;
 113
 114        /* There is only one IPI interrupt shared by all messages, so
 115         * we keep a separate interrupt flag per message type in sw. */
 116        pmsg = &per_cpu(j2_ipi_messages, cpu);
 117        do old = *pmsg;
 118        while (cmpxchg(pmsg, old, old|(1U<<message)) != old);
 119
 120        /* Generate the actual interrupt by writing to CCRn bit 28. */
 121        val = __raw_readl(j2_ipi_trigger + cpu);
 122        __raw_writel(val | (1U<<28), j2_ipi_trigger + cpu);
 123}
 124
 125static struct plat_smp_ops j2_smp_ops = {
 126        .smp_setup              = j2_smp_setup,
 127        .prepare_cpus           = j2_prepare_cpus,
 128        .start_cpu              = j2_start_cpu,
 129        .smp_processor_id       = j2_smp_processor_id,
 130        .send_ipi               = j2_send_ipi,
 131        .cpu_die                = native_cpu_die,
 132        .cpu_disable            = native_cpu_disable,
 133        .play_dead              = native_play_dead,
 134};
 135
 136CPU_METHOD_OF_DECLARE(j2_cpu_method, "jcore,spin-table", &j2_smp_ops);
 137