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