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