• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 static char smp_cpuinfo_buf[128] = {"Extn [EZNPS-SMP]\t: On\n"};
19 
20 /* Get cpu map from device tree */
eznps_get_map(const char * name,struct cpumask * cpumask)21 static 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 */
eznps_init_cpumasks(void)36 static 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 
eznps_init_core(unsigned int cpu)53 static 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  */
eznps_smp_wakeup_cpu(int cpu,unsigned long pc)84 static 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 
eznps_ipi_send(int cpu)98 static 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 
eznps_init_per_cpu(int cpu)124 static 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 
132 struct 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