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 
29 static char smp_cpuinfo_buf[128] = {"Extn [EZNPS-SMP]\t: On\n"};
30 
31 /* Get cpu map from device tree */
eznps_get_map(const char * name,struct cpumask * cpumask)32 static 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 */
eznps_init_cpumasks(void)47 static 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 
eznps_init_core(unsigned int cpu)64 static 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  */
eznps_smp_wakeup_cpu(int cpu,unsigned long pc)95 static 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 
eznps_ipi_send(int cpu)109 static 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 
eznps_init_per_cpu(int cpu)135 static 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 
143 struct 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