blob: 56a4c8522f111cc5221e2ead6b6574100cd3f685 [file] [log] [blame]
Noam Camus4a66d3f2012-08-19 11:54:33 +03001/*
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
Noam Camus4a66d3f2012-08-19 11:54:33 +0300143struct 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,
Noam Camus4a66d3f2012-08-19 11:54:33 +0300149};