1 /*
2  * Copyright (c) 2017 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT snps_designware_intc
8 
9 /* This implementation supports only the regular irqs
10  * No support for priority filtering
11  * No support for vectored interrupts
12  * Firqs are also not supported
13  * This implementation works only when sw_isr_table is enabled in zephyr
14  */
15 
16 #include <device.h>
17 #include <irq_nextlevel.h>
18 #include "intc_dw.h"
19 #include <soc.h>
20 
dw_ictl_dispatch_child_isrs(uint32_t intr_status,uint32_t isr_base_offset)21 static ALWAYS_INLINE void dw_ictl_dispatch_child_isrs(uint32_t intr_status,
22 						      uint32_t isr_base_offset)
23 {
24 	uint32_t intr_bitpos, intr_offset;
25 
26 	/* Dispatch lower level ISRs depending upon the bit set */
27 	while (intr_status) {
28 		intr_bitpos = find_lsb_set(intr_status) - 1;
29 		intr_status &= ~(1 << intr_bitpos);
30 		intr_offset = isr_base_offset + intr_bitpos;
31 		_sw_isr_table[intr_offset].isr(
32 			_sw_isr_table[intr_offset].arg);
33 	}
34 }
35 
dw_ictl_initialize(const struct device * dev)36 static int dw_ictl_initialize(const struct device *dev)
37 {
38 	const struct dw_ictl_config *config = dev->config;
39 	volatile struct dw_ictl_registers * const regs =
40 			(struct dw_ictl_registers *)config->base_addr;
41 
42 	/* disable all interrupts */
43 	regs->irq_inten_l = 0U;
44 	regs->irq_inten_h = 0U;
45 
46 	return 0;
47 }
48 
dw_ictl_isr(const struct device * dev)49 static void dw_ictl_isr(const struct device *dev)
50 {
51 	const struct dw_ictl_config *config = dev->config;
52 	volatile struct dw_ictl_registers * const regs =
53 			(struct dw_ictl_registers *)config->base_addr;
54 
55 	dw_ictl_dispatch_child_isrs(regs->irq_maskstatus_l,
56 				    config->isr_table_offset);
57 
58 	if (config->numirqs > 32) {
59 		dw_ictl_dispatch_child_isrs(regs->irq_maskstatus_h,
60 					    config->isr_table_offset + 32);
61 	}
62 }
63 
dw_ictl_intr_enable(const struct device * dev,unsigned int irq)64 static inline void dw_ictl_intr_enable(const struct device *dev,
65 				       unsigned int irq)
66 {
67 	const struct dw_ictl_config *config = dev->config;
68 	volatile struct dw_ictl_registers * const regs =
69 		(struct dw_ictl_registers *)config->base_addr;
70 
71 	if (irq < 32) {
72 		regs->irq_inten_l |= (1 << irq);
73 	} else {
74 		regs->irq_inten_h |= (1 << (irq - 32));
75 	}
76 }
77 
dw_ictl_intr_disable(const struct device * dev,unsigned int irq)78 static inline void dw_ictl_intr_disable(const struct device *dev,
79 					unsigned int irq)
80 {
81 	const struct dw_ictl_config *config = dev->config;
82 	volatile struct dw_ictl_registers * const regs =
83 		(struct dw_ictl_registers *)config->base_addr;
84 
85 	if (irq < 32) {
86 		regs->irq_inten_l &= ~(1 << irq);
87 	} else {
88 		regs->irq_inten_h &= ~(1 << (irq - 32));
89 	}
90 }
91 
dw_ictl_intr_get_state(const struct device * dev)92 static inline unsigned int dw_ictl_intr_get_state(const struct device *dev)
93 {
94 	const struct dw_ictl_config *config = dev->config;
95 	volatile struct dw_ictl_registers * const regs =
96 		(struct dw_ictl_registers *)config->base_addr;
97 
98 	if (regs->irq_inten_l) {
99 		return 1;
100 	}
101 
102 	if (config->numirqs > 32) {
103 		if (regs->irq_inten_h) {
104 			return 1;
105 		}
106 	}
107 	return 0;
108 }
109 
dw_ictl_intr_get_line_state(const struct device * dev,unsigned int irq)110 static int dw_ictl_intr_get_line_state(const struct device *dev,
111 				       unsigned int irq)
112 {
113 	const struct dw_ictl_config *config = dev->config;
114 	volatile struct dw_ictl_registers * const regs =
115 		(struct dw_ictl_registers *)config->base_addr;
116 
117 	if (config->numirqs > 32) {
118 		if ((regs->irq_inten_h & BIT(irq - 32)) != 0) {
119 			return 1;
120 		}
121 	} else {
122 		if ((regs->irq_inten_l & BIT(irq)) != 0) {
123 			return 1;
124 		}
125 	}
126 
127 	return 0;
128 }
129 
130 static void dw_ictl_config_irq(const struct device *dev);
131 
132 static const struct dw_ictl_config dw_config = {
133 	.base_addr = DT_INST_REG_ADDR(0),
134 	.numirqs = DT_INST_PROP(0, num_irqs),
135 	.isr_table_offset = CONFIG_DW_ISR_TBL_OFFSET,
136 	.config_func = dw_ictl_config_irq,
137 };
138 
139 static const struct irq_next_level_api dw_ictl_apis = {
140 	.intr_enable = dw_ictl_intr_enable,
141 	.intr_disable = dw_ictl_intr_disable,
142 	.intr_get_state = dw_ictl_intr_get_state,
143 	.intr_get_line_state = dw_ictl_intr_get_line_state,
144 };
145 
146 DEVICE_DT_INST_DEFINE(0, dw_ictl_initialize, NULL,
147 		NULL, &dw_config, PRE_KERNEL_1,
148 		CONFIG_DW_ICTL_INIT_PRIORITY, &dw_ictl_apis);
149 
dw_ictl_config_irq(const struct device * port)150 static void dw_ictl_config_irq(const struct device *port)
151 {
152 	IRQ_CONNECT(DT_INST_IRQN(0),
153 		    DT_INST_IRQ(0, priority),
154 		    dw_ictl_isr,
155 		    DEVICE_DT_INST_GET(0),
156 		    DT_INST_IRQ(0, sense));
157 }
158