1 /* Copyright (c) 2021 Intel Corporation
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 
5 #include <zephyr/device.h>
6 #include <xtensa/xtruntime.h>
7 #include <zephyr/irq_nextlevel.h>
8 #include <xtensa/hal.h>
9 #include <zephyr/init.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/irq.h>
12 
13 #include <adsp_shim.h>
14 #include <cavs-idc.h>
15 #include <adsp_interrupt.h>
16 #include "soc.h"
17 
18 #ifdef CONFIG_DYNAMIC_INTERRUPTS
19 #include <zephyr/sw_isr_table.h>
20 #endif
21 
22 LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
23 
24 #define CAVS_INTC_NODE(n) DT_INST(n, intel_cavs_intc)
25 
z_soc_irq_enable(uint32_t irq)26 void z_soc_irq_enable(uint32_t irq)
27 {
28 	const struct device *dev_cavs;
29 
30 	switch (XTENSA_IRQ_NUMBER(irq)) {
31 	case DT_IRQN(CAVS_INTC_NODE(0)):
32 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(0));
33 		break;
34 	case DT_IRQN(CAVS_INTC_NODE(1)):
35 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(1));
36 		break;
37 	case DT_IRQN(CAVS_INTC_NODE(2)):
38 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(2));
39 		break;
40 	case DT_IRQN(CAVS_INTC_NODE(3)):
41 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(3));
42 		break;
43 	default:
44 		/* regular interrupt */
45 		xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq));
46 		return;
47 	}
48 
49 	if (!device_is_ready(dev_cavs)) {
50 		LOG_DBG("board: CAVS device is not ready");
51 		return;
52 	}
53 
54 	/*
55 	 * The specified interrupt is in CAVS interrupt controller.
56 	 * So enable core interrupt first.
57 	 */
58 	xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq));
59 
60 	/* Then enable the interrupt in CAVS interrupt controller */
61 	irq_enable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
62 }
63 
z_soc_irq_disable(uint32_t irq)64 void z_soc_irq_disable(uint32_t irq)
65 {
66 	const struct device *dev_cavs;
67 
68 	switch (XTENSA_IRQ_NUMBER(irq)) {
69 	case DT_IRQN(CAVS_INTC_NODE(0)):
70 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(0));
71 		break;
72 	case DT_IRQN(CAVS_INTC_NODE(1)):
73 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(1));
74 		break;
75 	case DT_IRQN(CAVS_INTC_NODE(2)):
76 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(2));
77 		break;
78 	case DT_IRQN(CAVS_INTC_NODE(3)):
79 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(3));
80 		break;
81 	default:
82 		/* regular interrupt */
83 		xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
84 		return;
85 	}
86 
87 	if (!device_is_ready(dev_cavs)) {
88 		LOG_DBG("board: CAVS device is not ready");
89 		return;
90 	}
91 
92 	/*
93 	 * The specified interrupt is in CAVS interrupt controller.
94 	 * So disable the interrupt in CAVS interrupt controller.
95 	 */
96 	irq_disable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
97 
98 	/* Then disable the parent IRQ if all children are disabled */
99 	if (!irq_is_enabled_next_level(dev_cavs)) {
100 		xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
101 	}
102 }
103 
z_soc_irq_is_enabled(unsigned int irq)104 int z_soc_irq_is_enabled(unsigned int irq)
105 {
106 	const struct device *dev_cavs;
107 	int ret = 0;
108 
109 	switch (XTENSA_IRQ_NUMBER(irq)) {
110 	case DT_IRQN(CAVS_INTC_NODE(0)):
111 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(0));
112 		break;
113 	case DT_IRQN(CAVS_INTC_NODE(1)):
114 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(1));
115 		break;
116 	case DT_IRQN(CAVS_INTC_NODE(2)):
117 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(2));
118 		break;
119 	case DT_IRQN(CAVS_INTC_NODE(3)):
120 		dev_cavs = DEVICE_DT_GET(CAVS_INTC_NODE(3));
121 		break;
122 	default:
123 		/* regular interrupt */
124 		ret = xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq));
125 		goto out;
126 	}
127 
128 	if (!device_is_ready(dev_cavs)) {
129 		LOG_DBG("board: CAVS device is not ready");
130 		ret = -ENODEV;
131 		goto out;
132 	}
133 
134 	/* Then check the interrupt in CAVS interrupt controller */
135 	ret = irq_line_is_enabled_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
136 
137 out:
138 	return ret;
139 }
140 
141 #ifdef CONFIG_DYNAMIC_INTERRUPTS
z_soc_irq_connect_dynamic(unsigned int irq,unsigned int priority,void (* routine)(const void * parameter),const void * parameter,uint32_t flags)142 int z_soc_irq_connect_dynamic(unsigned int irq, unsigned int priority,
143 			      void (*routine)(const void *parameter),
144 			      const void *parameter, uint32_t flags)
145 {
146 	uint32_t table_idx;
147 	uint32_t cavs_irq, cavs_idx;
148 	int ret;
149 
150 	ARG_UNUSED(flags);
151 	ARG_UNUSED(priority);
152 
153 	/* extract 2nd level interrupt number */
154 	cavs_irq = CAVS_IRQ_NUMBER(irq);
155 	ret = irq;
156 
157 	if (cavs_irq == 0) {
158 		/* Not affecting 2nd level interrupts */
159 		z_isr_install(irq, routine, parameter);
160 		goto irq_connect_out;
161 	}
162 
163 	/* Figure out the base index. */
164 	switch (XTENSA_IRQ_NUMBER(irq)) {
165 	case DT_IRQN(CAVS_INTC_NODE(0)):
166 		cavs_idx = 0;
167 		break;
168 	case DT_IRQN(CAVS_INTC_NODE(1)):
169 		cavs_idx = 1;
170 		break;
171 	case DT_IRQN(CAVS_INTC_NODE(2)):
172 		cavs_idx = 2;
173 		break;
174 	case DT_IRQN(CAVS_INTC_NODE(3)):
175 		cavs_idx = 3;
176 		break;
177 	default:
178 		ret = -EINVAL;
179 		goto irq_connect_out;
180 	}
181 
182 	table_idx = CONFIG_CAVS_ISR_TBL_OFFSET +
183 		CONFIG_MAX_IRQ_PER_AGGREGATOR * cavs_idx;
184 	table_idx += cavs_irq;
185 
186 	_sw_isr_table[table_idx].arg = parameter;
187 	_sw_isr_table[table_idx].isr = routine;
188 
189 irq_connect_out:
190 	return ret;
191 }
192 #endif
193