1 /*
2 * Renesas SCP/MCP Software
3 * Copyright (c) 2020-2022, Renesas Electronics Corporation. All rights
4 * reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include <mmio.h>
10 #include <rcar_irq.h>
11
12 #include <fwk_arch.h>
13 #include <fwk_interrupt.h>
14 #include <fwk_macros.h>
15 #include <fwk_mm.h>
16 #include <fwk_status.h>
17
18 #include <arch_gic.h>
19
20 #define C_INT_ID (INT_ID(c_interrupt))
21 #ifndef RCAR_SCMI_LIB
22 # define RCAR_MFIS_MIN U(256)
23 # define RCAR_MFIS_NO U(8)
24 # define RCAR_MFIS_MAX (RCAR_MFIS_MIN + RCAR_MFIS_NO)
25 # define IS_SUPPORT_INT(n) ((n >= RCAR_MFIS_MIN) && (n < RCAR_MFIS_MAX))
26 # define EFECTIVE_NO(n) (n - RCAR_MFIS_MIN)
27 #else
28 # define IS_SUPPORT_INT(n) ((n >= SMCMH_IRQ_START) && (n < SMCMH_IRQ_END))
29 # define EFECTIVE_NO(n) (n & 0xff)
30 #endif /* RCAR_SCMI_LIB */
31 #define CHECK_BIT(d, b) ((d >> b) & 1)
32 #define IID_LEN (10)
33
34 /*
35 * For interrupts with parameters, their entry in the vector table points to a
36 * global handler that calls a registered function in the callback table with a
37 * corresponding parameter. Entries in the vector table for interrupts without
38 * parameters point directly to the handler functions.
39 */
40 struct callback {
41 union {
42 void (*func)(uintptr_t param);
43 void (*funcn)(void);
44 };
45 uintptr_t param;
46 };
47
48 struct r_node {
49 int valid;
50 struct r_node *left;
51 struct r_node *right;
52 struct callback *entry;
53 };
54
55 struct r_tree {
56 struct r_node *root;
57 int _allocated;
58 };
59
60 static unsigned int c_interrupt;
61 static struct r_tree *radix;
62
init_entry(struct r_tree * rt)63 struct r_tree *init_entry(struct r_tree *rt)
64 {
65 if (NULL == rt) {
66 rt = fwk_mm_calloc(1, sizeof(struct r_tree));
67 if (NULL == rt) {
68 return NULL;
69 }
70 rt->_allocated = 1;
71 } else {
72 rt->_allocated = 0;
73 }
74 rt->root = NULL;
75
76 return rt;
77 }
78
_lookup(struct r_node * cur,struct r_node * cand,uint32_t iid,int bitno)79 static void *_lookup(
80 struct r_node *cur,
81 struct r_node *cand,
82 uint32_t iid,
83 int bitno)
84 {
85 if (NULL == cur) {
86 return NULL != cand ? cand->entry : NULL;
87 }
88
89 if (cur->valid) {
90 cand = cur;
91 }
92
93 if (CHECK_BIT(iid, bitno)) {
94 return _lookup(cur->right, cand, iid, bitno + 1);
95 } else {
96 return _lookup(cur->left, cand, iid, bitno + 1);
97 }
98 }
99
lookup_entry(struct r_tree * rt,uint32_t iid)100 static void *lookup_entry(struct r_tree *rt, uint32_t iid)
101 {
102 return _lookup(rt->root, NULL, iid, 0);
103 }
104
_add(struct r_node ** cur,uint32_t iid,void * entry,int bitsize,int bitno)105 static int _add(
106 struct r_node **cur,
107 uint32_t iid,
108 void *entry,
109 int bitsize,
110 int bitno)
111 {
112 struct r_node *new;
113
114 if (NULL == *cur) {
115 new = fwk_mm_calloc(1, sizeof(struct r_node));
116 if (NULL == new) {
117 return -1;
118 }
119 memset(new, 0, sizeof(struct r_node));
120 *cur = new;
121 }
122
123 if (bitsize == bitno) {
124 if ((*cur)->valid) {
125 return -1;
126 }
127 (*cur)->valid = 1;
128 (*cur)->entry = entry;
129 return 0;
130 } else {
131 if (CHECK_BIT(iid, bitno)) {
132 return _add(&(*cur)->right, iid, entry, bitsize, bitno + 1);
133 } else {
134 return _add(&(*cur)->left, iid, entry, bitsize, bitno + 1);
135 }
136 }
137 }
138
add_entry(struct r_tree * rt,uint32_t iid,void * entry,int len)139 static int add_entry(struct r_tree *rt, uint32_t iid, void *entry, int len)
140 {
141 return _add(&rt->root, iid, entry, len, 0);
142 }
143
irq_global(uint32_t iid)144 void irq_global(uint32_t iid)
145 {
146 struct callback *entry;
147
148 c_interrupt = iid;
149
150 entry = (struct callback *)lookup_entry(radix, iid);
151 if (entry != NULL) {
152 if (entry->func) {
153 /* Available callback Function */
154 if (entry->param) {
155 entry->func(entry->param);
156 } else {
157 entry->funcn();
158 }
159 }
160 } else {
161 /* No interrupt entry */
162 }
163 c_interrupt = 0;
164 }
165
166 #ifndef RCAR_SCMI_LIB
167
168 /*******************************************************************************
169 * GIC Distributor interface accessors for reading entire registers
170 ******************************************************************************/
171 /*
172 * Accessor to read the GIC Distributor ISENABLER corresponding to the
173 * interrupt `id`, 32 interrupt ids at a time.
174 */
gicd_read_isenabler(uintptr_t base,unsigned int id)175 static unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id)
176 {
177 unsigned int n = id >> ISENABLER_SHIFT;
178
179 return mmio_read_32(base + GICD_ISENABLER + (n << 2));
180 }
181
182 /*
183 * Accessor to read the GIC Distributor ISPENDR corresponding to the
184 * interrupt `id`, 32 interrupt IDs at a time.
185 */
gicd_read_ispendr(uintptr_t base,unsigned int id)186 static unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id)
187 {
188 unsigned int n = id >> ISPENDR_SHIFT;
189
190 return mmio_read_32(base + GICD_ISPENDR + (n << 2));
191 }
192
193 /*******************************************************************************
194 * GIC Distributor interface accessors for writing entire registers
195 ******************************************************************************/
196 /*
197 * Accessor to write the GIC Distributor ISENABLER corresponding to the
198 * interrupt `id`, 32 interrupt IDs at a time.
199 */
gicd_write_isenabler(uintptr_t base,unsigned int id,unsigned int val)200 static void gicd_write_isenabler(
201 uintptr_t base,
202 unsigned int id,
203 unsigned int val)
204 {
205 unsigned int n = id >> ISENABLER_SHIFT;
206
207 mmio_write_32(base + GICD_ISENABLER + (n << 2), val);
208 }
209
210 /*
211 * Accessor to write the GIC Distributor ICENABLER corresponding to the
212 * interrupt `id`, 32 interrupt IDs at a time.
213 */
gicd_write_icenabler(uintptr_t base,unsigned int id,unsigned int val)214 static void gicd_write_icenabler(
215 uintptr_t base,
216 unsigned int id,
217 unsigned int val)
218 {
219 unsigned int n = id >> ICENABLER_SHIFT;
220
221 mmio_write_32(base + GICD_ICENABLER + (n << 2), val);
222 }
223
224 /*
225 * Accessor to write the GIC Distributor ISPENDR corresponding to the
226 * interrupt `id`, 32 interrupt IDs at a time.
227 */
gicd_write_ispendr(uintptr_t base,unsigned int id,unsigned int val)228 static void gicd_write_ispendr(
229 uintptr_t base,
230 unsigned int id,
231 unsigned int val)
232 {
233 unsigned int n = id >> ISPENDR_SHIFT;
234
235 mmio_write_32(base + GICD_ISPENDR + (n << 2), val);
236 }
237
238 /*
239 * Accessor to write the GIC Distributor ICPENDR corresponding to the
240 * interrupt `id`, 32 interrupt IDs at a time.
241 */
gicd_write_icpendr(uintptr_t base,unsigned int id,unsigned int val)242 static void gicd_write_icpendr(
243 uintptr_t base,
244 unsigned int id,
245 unsigned int val)
246 {
247 unsigned int n = id >> ICPENDR_SHIFT;
248
249 mmio_write_32(base + GICD_ICPENDR + (n << 2), val);
250 }
251
252 /*******************************************************************************
253 * GIC Distributor functions for accessing the GIC registers
254 * corresponding to a single interrupt ID. These functions use bitwise
255 * operations or appropriate register accesses to modify or return
256 * the bit-field corresponding the single interrupt ID.
257 ******************************************************************************/
gicd_set_isenabler(uintptr_t base,unsigned int id)258 static void gicd_set_isenabler(uintptr_t base, unsigned int id)
259 {
260 unsigned int bit_num = id & ((1U << ISENABLER_SHIFT) - 1U);
261
262 gicd_write_isenabler(base, id, (1U << bit_num));
263 }
264
gicd_set_icenabler(uintptr_t base,unsigned int id)265 static void gicd_set_icenabler(uintptr_t base, unsigned int id)
266 {
267 unsigned int bit_num = id & ((1U << ICENABLER_SHIFT) - 1U);
268
269 gicd_write_icenabler(base, id, (1U << bit_num));
270 }
271
gicd_set_ipriorityr(uintptr_t base,unsigned int id,unsigned int pri)272 static void gicd_set_ipriorityr(
273 uintptr_t base,
274 unsigned int id,
275 unsigned int pri)
276 {
277 uint8_t val = (uint8_t)(pri & GIC_PRI_MASK);
278
279 mmio_write_8(base + GICD_IPRIORITYR + id, val);
280 }
281
gicd_get_isenabler(uintptr_t base,unsigned int id)282 static unsigned int gicd_get_isenabler(uintptr_t base, unsigned int id)
283 {
284 unsigned int bit_num = id & ((1U << ISENABLER_SHIFT) - 1U);
285
286 return ((gicd_read_isenabler(base, id) >> bit_num) & 1U);
287 }
288
289 /*******************************************************************************
290 * GIC CPU interface accessors for writing entire registers
291 ******************************************************************************/
gicc_read_ctlr(uintptr_t base)292 static inline unsigned int gicc_read_ctlr(uintptr_t base)
293 {
294 return mmio_read_32(base + GICC_CTLR);
295 }
296
gicc_write_ctlr(uintptr_t base,unsigned int val)297 static void gicc_write_ctlr(uintptr_t base, unsigned int val)
298 {
299 mmio_write_32(base + GICC_CTLR, val);
300 }
301
gicc_write_pmr(uintptr_t base,unsigned int val)302 static void gicc_write_pmr(uintptr_t base, unsigned int val)
303 {
304 mmio_write_32(base + GICC_PMR, val);
305 }
306
307 /*******************************************************************************
308 * Enable secure interrupts and use FIQs to route them. Disable legacy bypass
309 * and set the priority mask register to allow all interrupts to trickle in.
310 ******************************************************************************/
gic_cpuif_enable(void)311 void gic_cpuif_enable(void)
312 {
313 unsigned int val;
314
315 /*
316 * Enable the Group 0 interrupts, FIQEn and disable Group 0/1
317 * bypass.
318 */
319 val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0;
320 val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
321
322 /* Program the idle priority in the PMR */
323 gicc_write_pmr(RCAR_GICC_BASE, GIC_PRI_MASK);
324 gicc_write_ctlr(RCAR_GICC_BASE, val);
325 }
326
327 /*******************************************************************************
328 * Place the cpu interface in a state where it can never make a cpu exit wfi as
329 * as result of an asserted interrupt. This is critical for powering down a cpu
330 ******************************************************************************/
gic_cpuif_disable(void)331 void gic_cpuif_disable(void)
332 {
333 unsigned int val;
334
335 /* Disable secure, non-secure interrupts and disable their bypass */
336 val = gicc_read_ctlr(RCAR_GICC_BASE);
337 val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT);
338 val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0;
339 val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1;
340 gicc_write_ctlr(RCAR_GICC_BASE, val);
341 }
342
gic_init(void)343 void gic_init(void)
344 {
345 gicd_set_ipriorityr(
346 RCAR_GICD_BASE,
347 (unsigned int)VIRTUAL_TIMER_IRQ,
348 GIC_HIGHEST_SEC_PRIORITY);
349 gicd_set_isenabler(RCAR_GICD_BASE, (unsigned int)VIRTUAL_TIMER_IRQ);
350 gicd_set_ipriorityr(
351 RCAR_GICD_BASE,
352 (unsigned int)NS_PHYSICAL_TIMER_IRQ,
353 GIC_HIGHEST_SEC_PRIORITY);
354 gicd_set_isenabler(RCAR_GICD_BASE, (unsigned int)NS_PHYSICAL_TIMER_IRQ);
355 gic_cpuif_enable();
356 }
357
358 /* --------------------------------------------------- */
359
global_enable(void)360 static int global_enable(void)
361 {
362 __asm__ volatile("msr DAIFClr, #1"); /* FIQ */
363 return FWK_SUCCESS;
364 }
365
global_disable(void)366 static int global_disable(void)
367 {
368 __asm__ volatile("msr DAIFSet, #1"); /* FIQ */
369 return FWK_SUCCESS;
370 }
371
is_enabled(unsigned int interrupt,bool * enabled)372 static int is_enabled(unsigned int interrupt, bool *enabled)
373 {
374 if (!IS_SUPPORT_INT(interrupt))
375 return FWK_E_PARAM;
376
377 *enabled = (bool)gicd_get_isenabler(RCAR_GICD_BASE, interrupt);
378
379 return FWK_SUCCESS;
380 }
381
enable(unsigned int interrupt)382 static int enable(unsigned int interrupt)
383 {
384 if (!IS_SUPPORT_INT(interrupt))
385 return FWK_E_PARAM;
386
387 gicd_set_isenabler(RCAR_GICD_BASE, interrupt);
388
389 return FWK_SUCCESS;
390 }
391
disable(unsigned int interrupt)392 static int disable(unsigned int interrupt)
393 {
394 if (!IS_SUPPORT_INT(interrupt))
395 return FWK_E_PARAM;
396
397 gicd_set_icenabler(RCAR_GICD_BASE, interrupt);
398
399 return FWK_SUCCESS;
400 }
401
is_pending(unsigned int interrupt,bool * pending)402 static int is_pending(unsigned int interrupt, bool *pending)
403 {
404 unsigned int bit;
405
406 if (!IS_SUPPORT_INT(interrupt))
407 return FWK_E_PARAM;
408
409 bit = interrupt % 32;
410 *pending =
411 ((gicd_read_ispendr(RCAR_GICD_BASE, interrupt) & (1 << bit)) ? true :
412 false);
413
414 return FWK_SUCCESS;
415 }
416
set_pending(unsigned int interrupt)417 static int set_pending(unsigned int interrupt)
418 {
419 unsigned int bit;
420
421 if (!IS_SUPPORT_INT(interrupt))
422 return FWK_E_PARAM;
423
424 bit = interrupt % 32;
425 gicd_write_ispendr(RCAR_GICD_BASE, interrupt, 1U << bit);
426
427 return FWK_SUCCESS;
428 }
429
clear_pending(unsigned int interrupt)430 static int clear_pending(unsigned int interrupt)
431 {
432 unsigned int bit;
433
434 if (!IS_SUPPORT_INT(interrupt))
435 return FWK_E_PARAM;
436
437 bit = interrupt % 32;
438 gicd_write_icpendr(RCAR_GICD_BASE, interrupt, 1U << bit);
439
440 return FWK_SUCCESS;
441 }
442
443 #else
444
global_enable(void)445 static int global_enable(void)
446 {
447 return FWK_SUCCESS;
448 }
449
global_disable(void)450 static int global_disable(void)
451 {
452 return FWK_SUCCESS;
453 }
454
is_enabled(unsigned int interrupt,bool * enabled)455 static int is_enabled(unsigned int interrupt, bool *enabled)
456 {
457 return FWK_SUCCESS;
458 }
459
enable(unsigned int interrupt)460 static int enable(unsigned int interrupt)
461 {
462 return FWK_SUCCESS;
463 }
464
disable(unsigned int interrupt)465 static int disable(unsigned int interrupt)
466 {
467 return FWK_SUCCESS;
468 }
469
is_pending(unsigned int interrupt,bool * pending)470 static int is_pending(unsigned int interrupt, bool *pending)
471 {
472 return FWK_SUCCESS;
473 }
474
set_pending(unsigned int interrupt)475 static int set_pending(unsigned int interrupt)
476 {
477 return FWK_SUCCESS;
478 }
479
clear_pending(unsigned int interrupt)480 static int clear_pending(unsigned int interrupt)
481 {
482 return FWK_SUCCESS;
483 }
484
485 #endif /* RCAR_SCMI_LIB */
486
set_isr_irq(unsigned int interrupt,void (* isr)(void))487 static int set_isr_irq(unsigned int interrupt, void (*isr)(void))
488 {
489 struct callback *entry;
490 int ret;
491
492 if ((MIN_IRQ > interrupt) || (MAX_IRQ <= interrupt))
493 return FWK_E_PARAM;
494
495 entry = fwk_mm_calloc(1, sizeof(struct callback));
496 if (NULL == entry)
497 return FWK_E_PANIC;
498
499 entry->funcn = isr;
500 entry->param = (uintptr_t)NULL;
501 ret = add_entry(radix, interrupt, (void *)entry, IID_LEN);
502 if (ret)
503 return FWK_E_PANIC;
504
505 return FWK_SUCCESS;
506 }
507
set_isr_irq_param(unsigned int interrupt,void (* isr)(uintptr_t param),uintptr_t parameter)508 static int set_isr_irq_param(
509 unsigned int interrupt,
510 void (*isr)(uintptr_t param),
511 uintptr_t parameter)
512 {
513 struct callback *entry;
514 int ret;
515
516 if ((MIN_IRQ > interrupt) || (MAX_IRQ <= interrupt))
517 return FWK_E_PANIC;
518
519 entry = fwk_mm_calloc(1, sizeof(struct callback));
520 if (NULL == entry)
521 return FWK_E_PANIC;
522
523 entry->func = isr;
524 entry->param = parameter;
525 ret = add_entry(radix, interrupt, (void *)entry, IID_LEN);
526 if (ret)
527 return FWK_E_PARAM;
528
529 return FWK_SUCCESS;
530 }
531
set_isr_dummy(void (* isr)(void))532 static int set_isr_dummy(void (*isr)(void))
533 {
534 return FWK_SUCCESS;
535 }
536
set_isr_dummy_param(void (* isr)(uintptr_t param),uintptr_t parameter)537 static int set_isr_dummy_param(
538 void (*isr)(uintptr_t param),
539 uintptr_t parameter)
540 {
541 return FWK_SUCCESS;
542 }
543
get_current(unsigned int * interrupt)544 static int get_current(unsigned int *interrupt)
545 {
546 *interrupt = c_interrupt;
547
548 /* Not an interrupt */
549 if (0 == *interrupt)
550 return FWK_E_STATE;
551
552 return FWK_SUCCESS;
553 }
554
is_interrupt_context(void)555 static bool is_interrupt_context(void)
556 {
557 /* Not an interrupt */
558 if (c_interrupt == 0) {
559 return false;
560 }
561
562 return true;
563 }
564
565 static const struct fwk_arch_interrupt_driver arm_gic_driver = {
566 .global_enable = global_enable,
567 .global_disable = global_disable,
568 .is_enabled = is_enabled,
569 .enable = enable,
570 .disable = disable,
571 .is_pending = is_pending,
572 .set_pending = set_pending,
573 .clear_pending = clear_pending,
574 .set_isr_irq = set_isr_irq,
575 .set_isr_irq_param = set_isr_irq_param,
576 .set_isr_nmi = set_isr_dummy,
577 .set_isr_nmi_param = set_isr_dummy_param,
578 .set_isr_fault = set_isr_dummy,
579 .get_current = get_current,
580 .is_interrupt_context = is_interrupt_context,
581 };
582
arm_gic_init(const struct fwk_arch_interrupt_driver ** driver)583 int arm_gic_init(const struct fwk_arch_interrupt_driver **driver)
584 {
585 /*
586 * Allocate and initialize a table for the callback functions and their
587 * corresponding parameters.
588 */
589 radix = init_entry(NULL);
590 if (radix == NULL)
591 return FWK_E_NOMEM;
592
593 gic_init();
594
595 /*
596 * Initialize all exception entries to point to the arm_exception_invalid()
597 * handler.
598 *
599 * Note: Initialization starts from entry 1 since entry 0 is not an
600 * exception pointer but the default stack pointer.
601 */
602
603 *driver = &arm_gic_driver;
604
605 return FWK_SUCCESS;
606 }
607