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