linux/arch/arc/plat-eznps/smp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright(c) 2015 EZchip Technologies.
   4 */
   5
   6#include <linux/smp.h>
   7#include <linux/of_fdt.h>
   8#include <linux/io.h>
   9#include <linux/irqdomain.h>
  10#include <asm/irq.h>
  11#include <plat/ctop.h>
  12#include <plat/smp.h>
  13#include <plat/mtm.h>
  14
  15#define NPS_DEFAULT_MSID        0x34
  16#define NPS_MTM_CPU_CFG         0x90
  17
  18static char smp_cpuinfo_buf[128] = {"Extn [EZNPS-SMP]\t: On\n"};
  19
  20/* Get cpu map from device tree */
  21static int __init eznps_get_map(const char *name, struct cpumask *cpumask)
  22{
  23        unsigned long dt_root = of_get_flat_dt_root();
  24        const char *buf;
  25
  26        buf = of_get_flat_dt_prop(dt_root, name, NULL);
  27        if (!buf)
  28                return 1;
  29
  30        cpulist_parse(buf, cpumask);
  31
  32        return 0;
  33}
  34
  35/* Update board cpu maps */
  36static void __init eznps_init_cpumasks(void)
  37{
  38        struct cpumask cpumask;
  39
  40        if (eznps_get_map("present-cpus", &cpumask)) {
  41                pr_err("Failed to get present-cpus from dtb");
  42                return;
  43        }
  44        init_cpu_present(&cpumask);
  45
  46        if (eznps_get_map("possible-cpus", &cpumask)) {
  47                pr_err("Failed to get possible-cpus from dtb");
  48                return;
  49        }
  50        init_cpu_possible(&cpumask);
  51}
  52
  53static void eznps_init_core(unsigned int cpu)
  54{
  55        u32 sync_value;
  56        struct nps_host_reg_aux_hw_comply hw_comply;
  57        struct nps_host_reg_aux_lpc lpc;
  58
  59        if (NPS_CPU_TO_THREAD_NUM(cpu) != 0)
  60                return;
  61
  62        hw_comply.value = read_aux_reg(CTOP_AUX_HW_COMPLY);
  63        hw_comply.me  = 1;
  64        hw_comply.le  = 1;
  65        hw_comply.te  = 1;
  66        write_aux_reg(CTOP_AUX_HW_COMPLY, hw_comply.value);
  67
  68        /* Enable MMU clock */
  69        lpc.mep = 1;
  70        write_aux_reg(CTOP_AUX_LPC, lpc.value);
  71
  72        /* Boot CPU only */
  73        if (!cpu) {
  74                /* Write to general purpose register in CRG */
  75                sync_value = ioread32be(REG_GEN_PURP_0);
  76                sync_value |= NPS_CRG_SYNC_BIT;
  77                iowrite32be(sync_value, REG_GEN_PURP_0);
  78        }
  79}
  80
  81/*
  82 * Master kick starting another CPU
  83 */
  84static void __init eznps_smp_wakeup_cpu(int cpu, unsigned long pc)
  85{
  86        struct nps_host_reg_mtm_cpu_cfg cpu_cfg;
  87
  88        if (mtm_enable_thread(cpu) == 0)
  89                return;
  90
  91        /* set PC, dmsid, and start CPU */
  92        cpu_cfg.value = (u32)res_service;
  93        cpu_cfg.dmsid = NPS_DEFAULT_MSID;
  94        cpu_cfg.cs = 1;
  95        iowrite32be(cpu_cfg.value, nps_mtm_reg_addr(cpu, NPS_MTM_CPU_CFG));
  96}
  97
  98static void eznps_ipi_send(int cpu)
  99{
 100        struct global_id gid;
 101        struct {
 102                union {
 103                        struct {
 104                                u32 num:8, cluster:8, core:8, thread:8;
 105                        };
 106                        u32 value;
 107                };
 108        } ipi;
 109
 110        gid.value = cpu;
 111        ipi.thread = get_thread(gid);
 112        ipi.core = gid.core;
 113        ipi.cluster = nps_cluster_logic_to_phys(gid.cluster);
 114        ipi.num = NPS_IPI_IRQ;
 115
 116        __asm__ __volatile__(
 117        "       mov r3, %0\n"
 118        "       .word %1\n"
 119        :
 120        : "r"(ipi.value), "i"(CTOP_INST_ASRI_0_R3)
 121        : "r3");
 122}
 123
 124static void eznps_init_per_cpu(int cpu)
 125{
 126        smp_ipi_irq_setup(cpu, NPS_IPI_IRQ);
 127
 128        eznps_init_core(cpu);
 129        mtm_enable_core(cpu);
 130}
 131
 132struct plat_smp_ops plat_smp_ops = {
 133        .info           = smp_cpuinfo_buf,
 134        .init_early_smp = eznps_init_cpumasks,
 135        .cpu_kick       = eznps_smp_wakeup_cpu,
 136        .ipi_send       = eznps_ipi_send,
 137        .init_per_cpu   = eznps_init_per_cpu,
 138};
 139