linux/arch/sh/kernel/cpu/sh4a/smp-shx3.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * SH-X3 SMP
   4 *
   5 *  Copyright (C) 2007 - 2010  Paul Mundt
   6 *  Copyright (C) 2007  Magnus Damm
   7 */
   8#include <linux/init.h>
   9#include <linux/kernel.h>
  10#include <linux/cpumask.h>
  11#include <linux/smp.h>
  12#include <linux/interrupt.h>
  13#include <linux/io.h>
  14#include <linux/sched.h>
  15#include <linux/delay.h>
  16#include <linux/cpu.h>
  17#include <asm/sections.h>
  18
  19#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
  20#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
  21
  22#define STBCR_MSTP      0x00000001
  23#define STBCR_RESET     0x00000002
  24#define STBCR_SLEEP     0x00000004
  25#define STBCR_LTSLP     0x80000000
  26
  27static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
  28{
  29        unsigned int message = (unsigned int)(long)arg;
  30        unsigned int cpu = hard_smp_processor_id();
  31        unsigned int offs = 4 * cpu;
  32        unsigned int x;
  33
  34        x = __raw_readl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
  35        x &= (1 << (message << 2));
  36        __raw_writel(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
  37
  38        smp_message_recv(message);
  39
  40        return IRQ_HANDLED;
  41}
  42
  43static void shx3_smp_setup(void)
  44{
  45        unsigned int cpu = 0;
  46        int i, num;
  47
  48        init_cpu_possible(cpumask_of(cpu));
  49
  50        /* Enable light sleep for the boot CPU */
  51        __raw_writel(__raw_readl(STBCR_REG(cpu)) | STBCR_LTSLP, STBCR_REG(cpu));
  52
  53        __cpu_number_map[0] = 0;
  54        __cpu_logical_map[0] = 0;
  55
  56        /*
  57         * Do this stupidly for now.. we don't have an easy way to probe
  58         * for the total number of cores.
  59         */
  60        for (i = 1, num = 0; i < NR_CPUS; i++) {
  61                set_cpu_possible(i, true);
  62                __cpu_number_map[i] = ++num;
  63                __cpu_logical_map[num] = i;
  64        }
  65
  66        printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
  67}
  68
  69static void shx3_prepare_cpus(unsigned int max_cpus)
  70{
  71        int i;
  72
  73        BUILD_BUG_ON(SMP_MSG_NR >= 8);
  74
  75        for (i = 0; i < SMP_MSG_NR; i++)
  76                request_irq(104 + i, ipi_interrupt_handler,
  77                            IRQF_PERCPU, "IPI", (void *)(long)i);
  78
  79        for (i = 0; i < max_cpus; i++)
  80                set_cpu_present(i, true);
  81}
  82
  83static void shx3_start_cpu(unsigned int cpu, unsigned long entry_point)
  84{
  85        if (__in_29bit_mode())
  86                __raw_writel(entry_point, RESET_REG(cpu));
  87        else
  88                __raw_writel(virt_to_phys(entry_point), RESET_REG(cpu));
  89
  90        if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
  91                __raw_writel(STBCR_MSTP, STBCR_REG(cpu));
  92
  93        while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
  94                cpu_relax();
  95
  96        /* Start up secondary processor by sending a reset */
  97        __raw_writel(STBCR_RESET | STBCR_LTSLP, STBCR_REG(cpu));
  98}
  99
 100static unsigned int shx3_smp_processor_id(void)
 101{
 102        return __raw_readl(0xff000048); /* CPIDR */
 103}
 104
 105static void shx3_send_ipi(unsigned int cpu, unsigned int message)
 106{
 107        unsigned long addr = 0xfe410070 + (cpu * 4);
 108
 109        BUG_ON(cpu >= 4);
 110
 111        __raw_writel(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
 112}
 113
 114static void shx3_update_boot_vector(unsigned int cpu)
 115{
 116        __raw_writel(STBCR_MSTP, STBCR_REG(cpu));
 117        while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
 118                cpu_relax();
 119        __raw_writel(STBCR_RESET, STBCR_REG(cpu));
 120}
 121
 122static int shx3_cpu_prepare(unsigned int cpu)
 123{
 124        shx3_update_boot_vector(cpu);
 125        return 0;
 126}
 127
 128static int register_shx3_cpu_notifier(void)
 129{
 130        cpuhp_setup_state_nocalls(CPUHP_SH_SH3X_PREPARE, "sh/shx3:prepare",
 131                                  shx3_cpu_prepare, NULL);
 132        return 0;
 133}
 134late_initcall(register_shx3_cpu_notifier);
 135
 136struct plat_smp_ops shx3_smp_ops = {
 137        .smp_setup              = shx3_smp_setup,
 138        .prepare_cpus           = shx3_prepare_cpus,
 139        .start_cpu              = shx3_start_cpu,
 140        .smp_processor_id       = shx3_smp_processor_id,
 141        .send_ipi               = shx3_send_ipi,
 142        .cpu_die                = native_cpu_die,
 143        .cpu_disable            = native_cpu_disable,
 144        .play_dead              = native_play_dead,
 145};
 146