1 /*
2  * Copyright (c) 2019 Synopsys.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief ARCv2 ARC CONNECT driver
10  *
11  */
12 
13 #include <zephyr/kernel.h>
14 #include <zephyr/arch/cpu.h>
15 #include <zephyr/spinlock.h>
16 #include <kernel_internal.h>
17 
18 static struct k_spinlock arc_connect_spinlock;
19 
20 /* Generate an inter-core interrupt to the target core */
z_arc_connect_ici_generate(uint32_t core)21 void z_arc_connect_ici_generate(uint32_t core)
22 {
23 	K_SPINLOCK(&arc_connect_spinlock) {
24 		z_arc_connect_cmd(ARC_CONNECT_CMD_INTRPT_GENERATE_IRQ, core);
25 	}
26 }
27 
28 /* Acknowledge the inter-core interrupt raised by core */
z_arc_connect_ici_ack(uint32_t core)29 void z_arc_connect_ici_ack(uint32_t core)
30 {
31 	K_SPINLOCK(&arc_connect_spinlock) {
32 		z_arc_connect_cmd(ARC_CONNECT_CMD_INTRPT_GENERATE_ACK, core);
33 	}
34 }
35 
36 /* Read inter-core interrupt status */
z_arc_connect_ici_read_status(uint32_t core)37 uint32_t z_arc_connect_ici_read_status(uint32_t core)
38 {
39 	uint32_t ret = 0;
40 
41 	K_SPINLOCK(&arc_connect_spinlock) {
42 		z_arc_connect_cmd(ARC_CONNECT_CMD_INTRPT_READ_STATUS, core);
43 		ret = z_arc_connect_cmd_readback();
44 	}
45 
46 	return ret;
47 }
48 
49 /* Check the source of inter-core interrupt */
z_arc_connect_ici_check_src(void)50 uint32_t z_arc_connect_ici_check_src(void)
51 {
52 	uint32_t ret = 0;
53 
54 	K_SPINLOCK(&arc_connect_spinlock) {
55 		z_arc_connect_cmd(ARC_CONNECT_CMD_INTRPT_CHECK_SOURCE, 0);
56 		ret = z_arc_connect_cmd_readback();
57 	}
58 
59 	return ret;
60 }
61 
62 /* Clear the inter-core interrupt */
z_arc_connect_ici_clear(void)63 void z_arc_connect_ici_clear(void)
64 {
65 	uint32_t cpu, c;
66 
67 	K_SPINLOCK(&arc_connect_spinlock) {
68 
69 		z_arc_connect_cmd(ARC_CONNECT_CMD_INTRPT_CHECK_SOURCE, 0);
70 		cpu = z_arc_connect_cmd_readback(); /* 1,2,4,8... */
71 	/*
72 	 * In rare case, multiple concurrent ICIs sent to same target can
73 	 * possibly be coalesced by MCIP into 1 asserted IRQ, so @cpu can be
74 	 * "vectored" (multiple bits sets) as opposed to typical single bit
75 	 */
76 		while (cpu) {
77 			c = find_lsb_set(cpu) - 1;
78 			z_arc_connect_cmd(
79 				ARC_CONNECT_CMD_INTRPT_GENERATE_ACK, c);
80 			cpu &= ~(1U << c);
81 		}
82 	}
83 }
84 
85 /* Reset the cores in core_mask */
z_arc_connect_debug_reset(uint32_t core_mask)86 void z_arc_connect_debug_reset(uint32_t core_mask)
87 {
88 	K_SPINLOCK(&arc_connect_spinlock) {
89 		z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_RESET,
90 			0, core_mask);
91 	}
92 }
93 
94 /* Halt the cores in core_mask */
z_arc_connect_debug_halt(uint32_t core_mask)95 void z_arc_connect_debug_halt(uint32_t core_mask)
96 {
97 	K_SPINLOCK(&arc_connect_spinlock) {
98 		z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_HALT,
99 			0, core_mask);
100 	}
101 }
102 
103 /* Run the cores in core_mask */
z_arc_connect_debug_run(uint32_t core_mask)104 void z_arc_connect_debug_run(uint32_t core_mask)
105 {
106 	K_SPINLOCK(&arc_connect_spinlock) {
107 		z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_RUN,
108 			0, core_mask);
109 	}
110 }
111 
112 /* Set core mask */
z_arc_connect_debug_mask_set(uint32_t core_mask,uint32_t mask)113 void z_arc_connect_debug_mask_set(uint32_t core_mask, uint32_t mask)
114 {
115 	K_SPINLOCK(&arc_connect_spinlock) {
116 		z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_SET_MASK,
117 			mask, core_mask);
118 	}
119 }
120 
121 /* Read core mask */
z_arc_connect_debug_mask_read(uint32_t core_mask)122 uint32_t z_arc_connect_debug_mask_read(uint32_t core_mask)
123 {
124 	uint32_t ret = 0;
125 
126 	K_SPINLOCK(&arc_connect_spinlock) {
127 		z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_READ_MASK,
128 			0, core_mask);
129 		ret = z_arc_connect_cmd_readback();
130 	}
131 
132 	return ret;
133 }
134 
135 /*
136  * Select cores that should be halted if the core issuing the command is halted
137  */
z_arc_connect_debug_select_set(uint32_t core_mask)138 void z_arc_connect_debug_select_set(uint32_t core_mask)
139 {
140 	K_SPINLOCK(&arc_connect_spinlock) {
141 		z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_SET_SELECT,
142 			0, core_mask);
143 	}
144 }
145 
146 /* Read the select value */
z_arc_connect_debug_select_read(void)147 uint32_t z_arc_connect_debug_select_read(void)
148 {
149 	uint32_t ret = 0;
150 
151 	K_SPINLOCK(&arc_connect_spinlock) {
152 		z_arc_connect_cmd(ARC_CONNECT_CMD_DEBUG_READ_SELECT, 0);
153 		ret = z_arc_connect_cmd_readback();
154 	}
155 
156 	return ret;
157 }
158 
159 /* Read the status, halt or run of all cores in the system */
z_arc_connect_debug_en_read(void)160 uint32_t z_arc_connect_debug_en_read(void)
161 {
162 	uint32_t ret = 0;
163 
164 	K_SPINLOCK(&arc_connect_spinlock) {
165 		z_arc_connect_cmd(ARC_CONNECT_CMD_DEBUG_READ_EN, 0);
166 		ret = z_arc_connect_cmd_readback();
167 	}
168 
169 	return ret;
170 }
171 
172 /* Read the last command sent */
z_arc_connect_debug_cmd_read(void)173 uint32_t z_arc_connect_debug_cmd_read(void)
174 {
175 	uint32_t ret = 0;
176 
177 	K_SPINLOCK(&arc_connect_spinlock) {
178 		z_arc_connect_cmd(ARC_CONNECT_CMD_DEBUG_READ_CMD, 0);
179 		ret = z_arc_connect_cmd_readback();
180 	}
181 
182 	return ret;
183 }
184 
185 /* Read the value of internal MCD_CORE register */
z_arc_connect_debug_core_read(void)186 uint32_t z_arc_connect_debug_core_read(void)
187 {
188 	uint32_t ret = 0;
189 
190 	K_SPINLOCK(&arc_connect_spinlock) {
191 		z_arc_connect_cmd(ARC_CONNECT_CMD_DEBUG_READ_CORE, 0);
192 		ret = z_arc_connect_cmd_readback();
193 	}
194 
195 	return ret;
196 }
197 
198 /* Clear global free running counter */
z_arc_connect_gfrc_clear(void)199 void z_arc_connect_gfrc_clear(void)
200 {
201 	K_SPINLOCK(&arc_connect_spinlock) {
202 		z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_CLEAR, 0);
203 	}
204 }
205 
206 /* Read total 64 bits of global free running counter */
z_arc_connect_gfrc_read(void)207 uint64_t z_arc_connect_gfrc_read(void)
208 {
209 	uint32_t low;
210 	uint32_t high;
211 	uint32_t key;
212 
213 	/*
214 	 * each core has its own arc connect interface, i.e.,
215 	 * CMD/READBACK. So several concurrent commands to ARC
216 	 * connect are of if they are trying to access different
217 	 * sub-components. For GFRC, HW allows simultaneously accessing to
218 	 * counters. So an irq lock is enough.
219 	 */
220 	key = arch_irq_lock();
221 
222 	z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_READ_LO, 0);
223 	low = z_arc_connect_cmd_readback();
224 
225 	z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_READ_HI, 0);
226 	high = z_arc_connect_cmd_readback();
227 
228 	arch_irq_unlock(key);
229 
230 	return (((uint64_t)high) << 32) | low;
231 }
232 
233 /* Enable global free running counter */
z_arc_connect_gfrc_enable(void)234 void z_arc_connect_gfrc_enable(void)
235 {
236 	K_SPINLOCK(&arc_connect_spinlock) {
237 		z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_ENABLE, 0);
238 	}
239 }
240 
241 /* Disable global free running counter */
z_arc_connect_gfrc_disable(void)242 void z_arc_connect_gfrc_disable(void)
243 {
244 	K_SPINLOCK(&arc_connect_spinlock) {
245 		z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_DISABLE, 0);
246 	}
247 }
248 
249 /* Disable global free running counter */
z_arc_connect_gfrc_core_set(uint32_t core_mask)250 void z_arc_connect_gfrc_core_set(uint32_t core_mask)
251 {
252 	K_SPINLOCK(&arc_connect_spinlock) {
253 		z_arc_connect_cmd_data(ARC_CONNECT_CMD_GFRC_SET_CORE,
254 			0, core_mask);
255 	}
256 }
257 
258 /* Set the relevant cores to halt global free running counter */
z_arc_connect_gfrc_halt_read(void)259 uint32_t z_arc_connect_gfrc_halt_read(void)
260 {
261 	uint32_t ret = 0;
262 
263 	K_SPINLOCK(&arc_connect_spinlock) {
264 		z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_READ_HALT, 0);
265 		ret = z_arc_connect_cmd_readback();
266 	}
267 
268 	return ret;
269 }
270 
271 /* Read the internal CORE register */
z_arc_connect_gfrc_core_read(void)272 uint32_t z_arc_connect_gfrc_core_read(void)
273 {
274 	uint32_t ret = 0;
275 
276 	K_SPINLOCK(&arc_connect_spinlock) {
277 		z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_READ_CORE, 0);
278 		ret = z_arc_connect_cmd_readback();
279 	}
280 
281 	return ret;
282 }
283 
284 /* Enable interrupt distribute unit */
z_arc_connect_idu_enable(void)285 void z_arc_connect_idu_enable(void)
286 {
287 	K_SPINLOCK(&arc_connect_spinlock) {
288 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_ENABLE, 0);
289 	}
290 }
291 
292 /* Disable interrupt distribute unit */
z_arc_connect_idu_disable(void)293 void z_arc_connect_idu_disable(void)
294 {
295 	K_SPINLOCK(&arc_connect_spinlock) {
296 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_DISABLE, 0);
297 	}
298 }
299 
300 /* Read enable status of interrupt distribute unit */
z_arc_connect_idu_read_enable(void)301 uint32_t z_arc_connect_idu_read_enable(void)
302 {
303 	uint32_t ret = 0;
304 
305 	K_SPINLOCK(&arc_connect_spinlock) {
306 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_READ_ENABLE, 0);
307 		ret = z_arc_connect_cmd_readback();
308 	}
309 
310 	return ret;
311 }
312 
313 /*
314  * Set the triggering mode and distribution mode for the specified common
315  * interrupt
316  */
z_arc_connect_idu_set_mode(uint32_t irq_num,uint16_t trigger_mode,uint16_t distri_mode)317 void z_arc_connect_idu_set_mode(uint32_t irq_num,
318 	uint16_t trigger_mode, uint16_t distri_mode)
319 {
320 	K_SPINLOCK(&arc_connect_spinlock) {
321 		z_arc_connect_cmd_data(ARC_CONNECT_CMD_IDU_SET_MODE,
322 			irq_num, (distri_mode | (trigger_mode << 4)));
323 	}
324 }
325 
326 /* Read the internal MODE register of the specified common interrupt */
z_arc_connect_idu_read_mode(uint32_t irq_num)327 uint32_t z_arc_connect_idu_read_mode(uint32_t irq_num)
328 {
329 	uint32_t ret = 0;
330 
331 	K_SPINLOCK(&arc_connect_spinlock) {
332 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_READ_MODE, irq_num);
333 		ret = z_arc_connect_cmd_readback();
334 	}
335 
336 	return ret;
337 }
338 
339 /*
340  * Set the target cores to receive the specified common interrupt
341  * when it is triggered
342  */
z_arc_connect_idu_set_dest(uint32_t irq_num,uint32_t core_mask)343 void z_arc_connect_idu_set_dest(uint32_t irq_num, uint32_t core_mask)
344 {
345 	K_SPINLOCK(&arc_connect_spinlock) {
346 		z_arc_connect_cmd_data(ARC_CONNECT_CMD_IDU_SET_DEST,
347 			irq_num, core_mask);
348 	}
349 }
350 
351 /* Read the internal DEST register of the specified common interrupt */
z_arc_connect_idu_read_dest(uint32_t irq_num)352 uint32_t z_arc_connect_idu_read_dest(uint32_t irq_num)
353 {
354 	uint32_t ret = 0;
355 
356 	K_SPINLOCK(&arc_connect_spinlock) {
357 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_READ_DEST, irq_num);
358 		ret = z_arc_connect_cmd_readback();
359 	}
360 
361 	return ret;
362 }
363 
364 /* Assert the specified common interrupt */
z_arc_connect_idu_gen_cirq(uint32_t irq_num)365 void z_arc_connect_idu_gen_cirq(uint32_t irq_num)
366 {
367 	K_SPINLOCK(&arc_connect_spinlock) {
368 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_GEN_CIRQ, irq_num);
369 	}
370 }
371 
372 /* Acknowledge the specified common interrupt */
z_arc_connect_idu_ack_cirq(uint32_t irq_num)373 void z_arc_connect_idu_ack_cirq(uint32_t irq_num)
374 {
375 	K_SPINLOCK(&arc_connect_spinlock) {
376 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_ACK_CIRQ, irq_num);
377 	}
378 }
379 
380 /* Read the internal STATUS register of the specified common interrupt */
z_arc_connect_idu_check_status(uint32_t irq_num)381 uint32_t z_arc_connect_idu_check_status(uint32_t irq_num)
382 {
383 	uint32_t ret = 0;
384 
385 	K_SPINLOCK(&arc_connect_spinlock) {
386 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_CHECK_STATUS, irq_num);
387 		ret = z_arc_connect_cmd_readback();
388 	}
389 
390 	return ret;
391 }
392 
393 /* Read the internal SOURCE register of the specified common interrupt */
z_arc_connect_idu_check_source(uint32_t irq_num)394 uint32_t z_arc_connect_idu_check_source(uint32_t irq_num)
395 {
396 	uint32_t ret = 0;
397 
398 	K_SPINLOCK(&arc_connect_spinlock) {
399 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_CHECK_SOURCE, irq_num);
400 		ret = z_arc_connect_cmd_readback();
401 	}
402 
403 	return ret;
404 }
405 
406 /* Mask or unmask the specified common interrupt */
z_arc_connect_idu_set_mask(uint32_t irq_num,uint32_t mask)407 void z_arc_connect_idu_set_mask(uint32_t irq_num, uint32_t mask)
408 {
409 	K_SPINLOCK(&arc_connect_spinlock) {
410 		z_arc_connect_cmd_data(ARC_CONNECT_CMD_IDU_SET_MASK,
411 			irq_num, mask);
412 	}
413 }
414 
415 /* Read the internal MASK register of the specified common interrupt */
z_arc_connect_idu_read_mask(uint32_t irq_num)416 uint32_t z_arc_connect_idu_read_mask(uint32_t irq_num)
417 {
418 	uint32_t ret = 0;
419 
420 	K_SPINLOCK(&arc_connect_spinlock) {
421 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_READ_MASK, irq_num);
422 		ret = z_arc_connect_cmd_readback();
423 	}
424 
425 	return ret;
426 }
427 
428 /*
429  * Check if it is the first-acknowledging core to the common interrupt
430  * if IDU is programmed in the first-acknowledged mode
431  */
z_arc_connect_idu_check_first(uint32_t irq_num)432 uint32_t z_arc_connect_idu_check_first(uint32_t irq_num)
433 {
434 	uint32_t ret = 0;
435 
436 	K_SPINLOCK(&arc_connect_spinlock) {
437 		z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_CHECK_FIRST, irq_num);
438 		ret = z_arc_connect_cmd_readback();
439 	}
440 
441 	return ret;
442 
443 }
444