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