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