1 /*
2  * Copyright (c) 2023 TOKITTA Hiroshi <tokita.hiroshi@fujitsu.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT renesas_ra_interrupt_controller_unit
8 
9 #include <zephyr/device.h>
10 #include <zephyr/irq.h>
11 #include <soc.h>
12 #include <zephyr/drivers/interrupt_controller/intc_ra_icu.h>
13 #include <zephyr/sw_isr_table.h>
14 #include <errno.h>
15 
16 #define IELSRn_REG(n) (DT_INST_REG_ADDR(0) + IELSRn_OFFSET + (n * 4))
17 #define IRQCRi_REG(i) (DT_INST_REG_ADDR(0) + IRQCRi_OFFSET + (i))
18 
19 #define IRQCRi_IRQMD_POS  0
20 #define IRQCRi_IRQMD_MASK BIT_MASK(2)
21 #define IELSRn_IR_POS     16
22 #define IELSRn_IR_MASK    BIT_MASK(1)
23 
24 enum {
25 	IRQCRi_OFFSET = 0x0,
26 	IELSRn_OFFSET = 0x300,
27 };
28 
ra_icu_query_exists_irq(uint32_t event)29 int ra_icu_query_exists_irq(uint32_t event)
30 {
31 	for (uint32_t i = 0; i < CONFIG_NUM_IRQS; i++) {
32 		uint32_t els = sys_read32(IELSRn_REG(i)) & UINT8_MAX;
33 
34 		if (event == els) {
35 			return i;
36 		}
37 	}
38 
39 	return -EINVAL;
40 }
41 
ra_icu_query_available_irq(uint32_t event)42 int ra_icu_query_available_irq(uint32_t event)
43 {
44 	int irq = -EINVAL;
45 
46 	if (ra_icu_query_exists_irq(event) > 0) {
47 		return -EINVAL;
48 	}
49 
50 	for (uint32_t i = 0; i < CONFIG_NUM_IRQS; i++) {
51 		if (_sw_isr_table[i].isr == z_irq_spurious) {
52 			irq = i;
53 			break;
54 		}
55 	}
56 
57 	return irq;
58 }
59 
ra_icu_clear_int_flag(unsigned int irqn)60 void ra_icu_clear_int_flag(unsigned int irqn)
61 {
62 	uint32_t cfg = sys_read32(IELSRn_REG(irqn));
63 
64 	sys_write32(cfg & ~BIT(IELSRn_IR_POS), IELSRn_REG(irqn));
65 }
66 
ra_icu_query_irq_config(unsigned int irq,uint32_t * intcfg,ra_isr_handler * cb,const void ** cbarg)67 void ra_icu_query_irq_config(unsigned int irq, uint32_t *intcfg, ra_isr_handler *cb,
68 			     const void **cbarg)
69 {
70 	*intcfg = sys_read32(IELSRn_REG(irq));
71 	*cb = _sw_isr_table[irq].isr;
72 	*cbarg = (void *)_sw_isr_table[irq].arg;
73 }
74 
ra_icu_irq_configure(unsigned int irqn,uint32_t intcfg)75 static void ra_icu_irq_configure(unsigned int irqn, uint32_t intcfg)
76 {
77 	uint8_t reg = sys_read8(IRQCRi_REG(irqn)) & ~(IRQCRi_IRQMD_MASK);
78 
79 	sys_write8(reg | (intcfg & IRQCRi_IRQMD_MASK), IRQCRi_REG(irqn));
80 }
81 
ra_icu_irq_connect_dynamic(unsigned int irq,unsigned int priority,void (* routine)(const void * parameter),const void * parameter,uint32_t flags)82 int ra_icu_irq_connect_dynamic(unsigned int irq, unsigned int priority,
83 			       void (*routine)(const void *parameter), const void *parameter,
84 			       uint32_t flags)
85 {
86 	uint32_t event = ((flags & RA_ICU_FLAG_EVENT_MASK) >> RA_ICU_FLAG_EVENT_OFFSET);
87 	uint32_t intcfg = ((flags & RA_ICU_FLAG_INTCFG_MASK) >> RA_ICU_FLAG_INTCFG_OFFSET);
88 	int irqn = irq;
89 
90 	if (irq == RA_ICU_IRQ_UNSPECIFIED) {
91 		irqn = ra_icu_query_available_irq(event);
92 		if (irqn < 0) {
93 			return irqn;
94 		}
95 	}
96 
97 	irq_disable(irqn);
98 	sys_write32(event, IELSRn_REG(irqn));
99 	z_isr_install(irqn, routine, parameter);
100 	z_arm_irq_priority_set(irqn, priority, flags);
101 	ra_icu_irq_configure(event, intcfg);
102 
103 	return irqn;
104 }
105 
ra_icu_irq_disconnect_dynamic(unsigned int irq,unsigned int priority,void (* routine)(const void * parameter),const void * parameter,uint32_t flags)106 int ra_icu_irq_disconnect_dynamic(unsigned int irq, unsigned int priority,
107 				  void (*routine)(const void *parameter), const void *parameter,
108 				  uint32_t flags)
109 {
110 	int irqn = irq;
111 
112 	if (irq == RA_ICU_IRQ_UNSPECIFIED) {
113 		return -EINVAL;
114 	}
115 
116 	irq_disable(irqn);
117 	sys_write32(0, IELSRn_REG(irqn));
118 	z_isr_install(irqn, z_irq_spurious, NULL);
119 	z_arm_irq_priority_set(irqn, 0, 0);
120 
121 	return 0;
122 }
123 
124 DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL);
125