xref: /optee_os/core/kernel/interrupt.c (revision 2f4d5a0dbcc32099d7458366103f7a8f8270017b)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
27315b7b4SJens Wiklander /*
3e9f46c74SJens Wiklander  * Copyright (c) 2016-2019, Linaro Limited
47315b7b4SJens Wiklander  */
57315b7b4SJens Wiklander 
667729d8dSLudovic Barre #include <kernel/dt.h>
77315b7b4SJens Wiklander #include <kernel/interrupt.h>
8e9f46c74SJens Wiklander #include <kernel/panic.h>
967729d8dSLudovic Barre #include <libfdt.h>
10f932e355SEtienne Carriere #include <mm/core_memprot.h>
11acc5dd21SLudovic Barre #include <stdlib.h>
127315b7b4SJens Wiklander #include <trace.h>
131c832d7cSdavidwang #include <assert.h>
147315b7b4SJens Wiklander 
157315b7b4SJens Wiklander /*
167315b7b4SJens Wiklander  * NOTE!
177315b7b4SJens Wiklander  *
187315b7b4SJens Wiklander  * We're assuming that there's no concurrent use of this interface, except
197315b7b4SJens Wiklander  * delivery of interrupts in parallel. Synchronization will be needed when
207315b7b4SJens Wiklander  * we begin to modify settings after boot initialization.
217315b7b4SJens Wiklander  */
227315b7b4SJens Wiklander 
233475549bSEtienne Carriere static struct itr_chip *itr_main_chip __nex_bss;
247315b7b4SJens Wiklander 
itr_chip_is_valid(struct itr_chip * chip)25df7874b5SEtienne Carriere static bool itr_chip_is_valid(struct itr_chip *chip)
26df7874b5SEtienne Carriere {
27df7874b5SEtienne Carriere 	return chip && is_unpaged(chip) && chip->ops &&
28df7874b5SEtienne Carriere 	       is_unpaged((void *)chip->ops) &&
29df7874b5SEtienne Carriere 	       chip->ops->mask && is_unpaged(chip->ops->mask) &&
30df7874b5SEtienne Carriere 	       chip->ops->unmask && is_unpaged(chip->ops->unmask) &&
31df7874b5SEtienne Carriere 	       chip->ops->enable && chip->ops->disable;
32df7874b5SEtienne Carriere }
33df7874b5SEtienne Carriere 
__itr_chip_init(struct itr_chip * chip)34df7874b5SEtienne Carriere static void __itr_chip_init(struct itr_chip *chip)
35df7874b5SEtienne Carriere {
36df7874b5SEtienne Carriere 	SLIST_INIT(&chip->handlers);
37df7874b5SEtienne Carriere }
38df7874b5SEtienne Carriere 
itr_chip_init(struct itr_chip * chip)39f932e355SEtienne Carriere TEE_Result itr_chip_init(struct itr_chip *chip)
40f932e355SEtienne Carriere {
41df7874b5SEtienne Carriere 	/*
42df7874b5SEtienne Carriere 	 * Interrupt chips not using only the DT to configure
43df7874b5SEtienne Carriere 	 * consumers interrupts require configure handler.
44df7874b5SEtienne Carriere 	 */
45df7874b5SEtienne Carriere 	if (!itr_chip_is_valid(chip) || !chip->ops->configure)
46df7874b5SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
47df7874b5SEtienne Carriere 
48df7874b5SEtienne Carriere 	__itr_chip_init(chip);
49df7874b5SEtienne Carriere 
50df7874b5SEtienne Carriere 	return TEE_SUCCESS;
51df7874b5SEtienne Carriere }
52df7874b5SEtienne Carriere 
itr_chip_dt_only_init(struct itr_chip * chip)53df7874b5SEtienne Carriere TEE_Result itr_chip_dt_only_init(struct itr_chip *chip)
54df7874b5SEtienne Carriere {
55f932e355SEtienne Carriere 	if (!itr_chip_is_valid(chip))
56f932e355SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
57f932e355SEtienne Carriere 
58df7874b5SEtienne Carriere 	__itr_chip_init(chip);
59f932e355SEtienne Carriere 
60f932e355SEtienne Carriere 	return TEE_SUCCESS;
61f932e355SEtienne Carriere }
62f932e355SEtienne Carriere 
interrupt_main_init(struct itr_chip * chip)6301980f3fSEtienne Carriere void interrupt_main_init(struct itr_chip *chip)
647315b7b4SJens Wiklander {
655f21fda6SEtienne Carriere 	if (itr_chip_init(chip))
665f21fda6SEtienne Carriere 		panic();
675f21fda6SEtienne Carriere 
683475549bSEtienne Carriere 	itr_main_chip = chip;
697315b7b4SJens Wiklander }
707315b7b4SJens Wiklander 
interrupt_get_main_chip(void)71e050e0a7SEtienne Carriere struct itr_chip *interrupt_get_main_chip(void)
72e050e0a7SEtienne Carriere {
733475549bSEtienne Carriere 	assert(itr_main_chip);
743475549bSEtienne Carriere 	return itr_main_chip;
75e050e0a7SEtienne Carriere }
76e050e0a7SEtienne Carriere 
interrupt_get_main_chip_may_fail(void)77245a552cSJens Wiklander struct itr_chip *interrupt_get_main_chip_may_fail(void)
78245a552cSJens Wiklander {
79245a552cSJens Wiklander 	return itr_main_chip;
80245a552cSJens Wiklander }
81245a552cSJens Wiklander 
8267729d8dSLudovic Barre #ifdef CFG_DT
dt_get_irq_type_prio(const void * fdt,int node,uint32_t * type,uint32_t * prio)83702fe5a7SClément Léger int dt_get_irq_type_prio(const void *fdt, int node, uint32_t *type,
84702fe5a7SClément Léger 			 uint32_t *prio)
8567729d8dSLudovic Barre {
8667729d8dSLudovic Barre 	const uint32_t *prop = NULL;
87888bb63dSClément Léger 	int count = 0;
8867729d8dSLudovic Barre 	int it_num = DT_INFO_INVALID_INTERRUPT;
8967729d8dSLudovic Barre 
903475549bSEtienne Carriere 	if (!itr_main_chip || !itr_main_chip->dt_get_irq)
9167729d8dSLudovic Barre 		return it_num;
9267729d8dSLudovic Barre 
93888bb63dSClément Léger 	prop = fdt_getprop(fdt, node, "interrupts", &count);
9467729d8dSLudovic Barre 	if (!prop)
9567729d8dSLudovic Barre 		return it_num;
9667729d8dSLudovic Barre 
9763873401SEtienne Carriere 	return itr_main_chip->dt_get_irq(prop, count / sizeof(uint32_t), type,
9863873401SEtienne Carriere 					 prio);
9967729d8dSLudovic Barre }
10067729d8dSLudovic Barre #endif
10167729d8dSLudovic Barre 
102e9f46c74SJens Wiklander /* This function is supposed to be overridden in platform specific code */
interrupt_main_handler(void)103358bf47cSEtienne Carriere void __weak __noreturn interrupt_main_handler(void)
104e9f46c74SJens Wiklander {
105e9f46c74SJens Wiklander 	panic("Secure interrupt handler not defined");
106e9f46c74SJens Wiklander }
107f932e355SEtienne Carriere 
108f932e355SEtienne Carriere /*
109f932e355SEtienne Carriere  * Interrupt controller chip support
110f932e355SEtienne Carriere  */
interrupt_call_handlers(struct itr_chip * chip,size_t itr_num)111f932e355SEtienne Carriere void interrupt_call_handlers(struct itr_chip *chip, size_t itr_num)
112f932e355SEtienne Carriere {
113f932e355SEtienne Carriere 	struct itr_handler *h = NULL;
114f932e355SEtienne Carriere 	bool was_handled = false;
115f932e355SEtienne Carriere 
116f932e355SEtienne Carriere 	assert(chip);
117f932e355SEtienne Carriere 
118f932e355SEtienne Carriere 	SLIST_FOREACH(h, &chip->handlers, link) {
119f932e355SEtienne Carriere 		if (h->it == itr_num) {
120f932e355SEtienne Carriere 			if (h->handler(h) == ITRR_HANDLED)
121f932e355SEtienne Carriere 				was_handled = true;
122f932e355SEtienne Carriere 			else if (!(h->flags & ITRF_SHARED))
123f932e355SEtienne Carriere 				break;
124f932e355SEtienne Carriere 		}
125f932e355SEtienne Carriere 	}
126f932e355SEtienne Carriere 
127f932e355SEtienne Carriere 	if (!was_handled) {
128f932e355SEtienne Carriere 		EMSG("Mask unhandled interrupt %s:%zu", chip->name, itr_num);
129f932e355SEtienne Carriere 		interrupt_mask(chip, itr_num);
130f932e355SEtienne Carriere 	}
131f932e355SEtienne Carriere }
132f932e355SEtienne Carriere 
interrupt_configure(struct itr_chip * chip,size_t itr_num,uint32_t type,uint32_t prio)133f932e355SEtienne Carriere TEE_Result interrupt_configure(struct itr_chip *chip, size_t itr_num,
134f932e355SEtienne Carriere 			       uint32_t type, uint32_t prio)
135f932e355SEtienne Carriere {
136df7874b5SEtienne Carriere 	if (!chip->ops->configure) {
137df7874b5SEtienne Carriere 		EMSG("No configure handler in itr_chip %s", chip->name);
138df7874b5SEtienne Carriere 		return TEE_ERROR_NOT_IMPLEMENTED;
139df7874b5SEtienne Carriere 	}
140df7874b5SEtienne Carriere 
1412a50ce7dSEtienne Carriere 	chip->ops->configure(chip, itr_num, type, prio);
142f932e355SEtienne Carriere 
143f932e355SEtienne Carriere 	return TEE_SUCCESS;
144f932e355SEtienne Carriere }
145f932e355SEtienne Carriere 
add_configure_handler(struct itr_handler * hdl,uint32_t type,uint32_t prio,bool configure)146e9376d02SEtienne Carriere static TEE_Result add_configure_handler(struct itr_handler *hdl,
147e9376d02SEtienne Carriere 					uint32_t type, uint32_t prio,
148e9376d02SEtienne Carriere 					bool configure)
149f932e355SEtienne Carriere {
150df7874b5SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
151f932e355SEtienne Carriere 	struct itr_handler *h = NULL;
152f932e355SEtienne Carriere 
153f932e355SEtienne Carriere 	assert(hdl && hdl->chip->ops && is_unpaged(hdl) &&
154f932e355SEtienne Carriere 	       hdl->handler && is_unpaged(hdl->handler));
155f932e355SEtienne Carriere 
156f932e355SEtienne Carriere 	SLIST_FOREACH(h, &hdl->chip->handlers, link) {
157f932e355SEtienne Carriere 		if (h->it == hdl->it &&
158f932e355SEtienne Carriere 		    (!(hdl->flags & ITRF_SHARED) ||
159f932e355SEtienne Carriere 		     !(h->flags & ITRF_SHARED))) {
160f932e355SEtienne Carriere 			EMSG("Shared and non-shared flags on interrupt %s#%zu",
161f932e355SEtienne Carriere 			     hdl->chip->name, hdl->it);
162f932e355SEtienne Carriere 			return TEE_ERROR_GENERIC;
163f932e355SEtienne Carriere 		}
164f932e355SEtienne Carriere 	}
165f932e355SEtienne Carriere 
166df7874b5SEtienne Carriere 	if (configure) {
167df7874b5SEtienne Carriere 		res = interrupt_configure(hdl->chip, hdl->it, type, prio);
168df7874b5SEtienne Carriere 		if (res)
169df7874b5SEtienne Carriere 			return res;
170df7874b5SEtienne Carriere 	}
171f932e355SEtienne Carriere 
172f932e355SEtienne Carriere 	SLIST_INSERT_HEAD(&hdl->chip->handlers, hdl, link);
173f932e355SEtienne Carriere 
174f932e355SEtienne Carriere 	return TEE_SUCCESS;
175f932e355SEtienne Carriere }
176f932e355SEtienne Carriere 
interrupt_add_configure_handler(struct itr_handler * hdl,uint32_t type,uint32_t prio)177e9376d02SEtienne Carriere TEE_Result interrupt_add_configure_handler(struct itr_handler *hdl,
178e9376d02SEtienne Carriere 					   uint32_t type, uint32_t prio)
179e9376d02SEtienne Carriere {
180e9376d02SEtienne Carriere 	return add_configure_handler(hdl, type, prio, true /* configure */);
181e9376d02SEtienne Carriere }
182e9376d02SEtienne Carriere 
interrupt_create_handler(struct itr_chip * itr_chip,size_t itr_num,itr_handler_t callback,void * priv,uint32_t flags,struct itr_handler ** out_hdl)183e9376d02SEtienne Carriere TEE_Result interrupt_create_handler(struct itr_chip *itr_chip, size_t itr_num,
184e9376d02SEtienne Carriere 				    itr_handler_t callback, void *priv,
185e9376d02SEtienne Carriere 				    uint32_t flags,
186e9376d02SEtienne Carriere 				    struct itr_handler **out_hdl)
187e9376d02SEtienne Carriere {
188e9376d02SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
189e9376d02SEtienne Carriere 	struct itr_handler *itr_hdl = NULL;
190e9376d02SEtienne Carriere 
191e9376d02SEtienne Carriere 	itr_hdl = calloc(1, sizeof(*itr_hdl));
192e9376d02SEtienne Carriere 	if (!itr_hdl)
193e9376d02SEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
194e9376d02SEtienne Carriere 
195e9376d02SEtienne Carriere 	*itr_hdl = (struct itr_handler){
196e9376d02SEtienne Carriere 		.chip = itr_chip,
197e9376d02SEtienne Carriere 		.it = itr_num,
198e9376d02SEtienne Carriere 		.flags = flags,
199e9376d02SEtienne Carriere 		.handler = callback,
200e9376d02SEtienne Carriere 		.data = priv,
201e9376d02SEtienne Carriere 	};
202e9376d02SEtienne Carriere 
203*2f4d5a0dSEtienne Carriere 	res = add_configure_handler(itr_hdl, 0, 0, false /* !configure */);
204e9376d02SEtienne Carriere 	if (res) {
205e9376d02SEtienne Carriere 		free(itr_hdl);
206e9376d02SEtienne Carriere 		return res;
207e9376d02SEtienne Carriere 	}
208e9376d02SEtienne Carriere 
209e9376d02SEtienne Carriere 	if (out_hdl)
210e9376d02SEtienne Carriere 		*out_hdl = itr_hdl;
211e9376d02SEtienne Carriere 
212e9376d02SEtienne Carriere 	return TEE_SUCCESS;
213e9376d02SEtienne Carriere }
214e9376d02SEtienne Carriere 
interrupt_remove_handler(struct itr_handler * hdl)215f932e355SEtienne Carriere void interrupt_remove_handler(struct itr_handler *hdl)
216f932e355SEtienne Carriere {
217f932e355SEtienne Carriere 	struct itr_handler *h = NULL;
218f932e355SEtienne Carriere 	bool disable_itr = true;
219f932e355SEtienne Carriere 
220f932e355SEtienne Carriere 	if (!hdl)
221f932e355SEtienne Carriere 		return;
222f932e355SEtienne Carriere 
223f932e355SEtienne Carriere 	SLIST_FOREACH(h, &hdl->chip->handlers, link)
224f932e355SEtienne Carriere 		if (h == hdl)
225f932e355SEtienne Carriere 			break;
226f932e355SEtienne Carriere 	if (!h) {
227f932e355SEtienne Carriere 		DMSG("Invalid %s:%zu", hdl->chip->name, hdl->it);
228f932e355SEtienne Carriere 		assert(false);
229f932e355SEtienne Carriere 		return;
230f932e355SEtienne Carriere 	}
231f932e355SEtienne Carriere 
232f932e355SEtienne Carriere 	if (hdl->flags & ITRF_SHARED) {
233f932e355SEtienne Carriere 		SLIST_FOREACH(h, &hdl->chip->handlers, link) {
234f932e355SEtienne Carriere 			if (h != hdl && h->it == hdl->it) {
235f932e355SEtienne Carriere 				disable_itr = false;
236f932e355SEtienne Carriere 				break;
237f932e355SEtienne Carriere 			}
238f932e355SEtienne Carriere 		}
239f932e355SEtienne Carriere 	}
240f932e355SEtienne Carriere 
241f932e355SEtienne Carriere 	if (disable_itr)
242f932e355SEtienne Carriere 		interrupt_disable(hdl->chip, hdl->it);
243f932e355SEtienne Carriere 
244f932e355SEtienne Carriere 	SLIST_REMOVE(&hdl->chip->handlers, hdl, itr_handler, link);
245f932e355SEtienne Carriere }
246f932e355SEtienne Carriere 
interrupt_alloc_add_conf_handler(struct itr_chip * chip,size_t itr_num,itr_handler_t handler,uint32_t flags,void * data,uint32_t type,uint32_t prio,struct itr_handler ** out_hdl)2471b5c7ca4SEtienne Carriere TEE_Result interrupt_alloc_add_conf_handler(struct itr_chip *chip,
2481b5c7ca4SEtienne Carriere 					    size_t itr_num,
2491b5c7ca4SEtienne Carriere 					    itr_handler_t handler,
2501b5c7ca4SEtienne Carriere 					    uint32_t flags, void *data,
2511b5c7ca4SEtienne Carriere 					    uint32_t type, uint32_t prio,
2521b5c7ca4SEtienne Carriere 					    struct itr_handler **out_hdl)
253f932e355SEtienne Carriere {
254f932e355SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
255f932e355SEtienne Carriere 	struct itr_handler *hdl = NULL;
256f932e355SEtienne Carriere 
257f932e355SEtienne Carriere 	hdl = calloc(1, sizeof(*hdl));
258f932e355SEtienne Carriere 	if (!hdl)
259f932e355SEtienne Carriere 		return TEE_ERROR_OUT_OF_MEMORY;
260f932e355SEtienne Carriere 
261f932e355SEtienne Carriere 	*hdl = ITR_HANDLER(chip, itr_num, flags, handler, data);
262f932e355SEtienne Carriere 
2631b5c7ca4SEtienne Carriere 	res = interrupt_add_configure_handler(hdl, type, prio);
264f932e355SEtienne Carriere 	if (res) {
265f932e355SEtienne Carriere 		free(hdl);
266f932e355SEtienne Carriere 		return res;
267f932e355SEtienne Carriere 	}
268f932e355SEtienne Carriere 
269f932e355SEtienne Carriere 	if (out_hdl)
270f932e355SEtienne Carriere 		*out_hdl = hdl;
271f932e355SEtienne Carriere 
272f932e355SEtienne Carriere 	return TEE_SUCCESS;
273f932e355SEtienne Carriere }
274f932e355SEtienne Carriere 
interrupt_remove_free_handler(struct itr_handler * hdl)275f932e355SEtienne Carriere void interrupt_remove_free_handler(struct itr_handler *hdl)
276f932e355SEtienne Carriere {
277f932e355SEtienne Carriere 	if (hdl) {
278f932e355SEtienne Carriere 		interrupt_remove_handler(hdl);
279f932e355SEtienne Carriere 		free(hdl);
280f932e355SEtienne Carriere 	}
281f932e355SEtienne Carriere }
28233a0c835SEtienne Carriere 
28333a0c835SEtienne Carriere #ifdef CFG_DT
interrupt_register_provider(const void * fdt,int node,itr_dt_get_func dt_get_itr,void * data)28433a0c835SEtienne Carriere TEE_Result interrupt_register_provider(const void *fdt, int node,
28533a0c835SEtienne Carriere 				       itr_dt_get_func dt_get_itr, void *data)
28633a0c835SEtienne Carriere {
28733a0c835SEtienne Carriere 	return dt_driver_register_provider(fdt, node,
28833a0c835SEtienne Carriere 					   (get_of_device_func)dt_get_itr,
28933a0c835SEtienne Carriere 					   data, DT_DRIVER_INTERRUPT);
29033a0c835SEtienne Carriere }
29133a0c835SEtienne Carriere 
29233a0c835SEtienne Carriere /*
29333a0c835SEtienne Carriere  * Fills an itr_desc reference based on "interrupts" property bindings.
29433a0c835SEtienne Carriere  * May return TEE_ERROR_DEFER_DRIVER_INIT if parent controller is found but
29533a0c835SEtienne Carriere  * not yet initialized.
29633a0c835SEtienne Carriere  */
get_legacy_interrupt_by_index(const void * fdt,int node,unsigned int index,struct itr_desc * itr_desc)29733a0c835SEtienne Carriere static TEE_Result get_legacy_interrupt_by_index(const void *fdt, int node,
29833a0c835SEtienne Carriere 						unsigned int index,
29933a0c835SEtienne Carriere 						struct itr_desc *itr_desc)
30033a0c835SEtienne Carriere {
30133a0c835SEtienne Carriere 	const uint32_t *prop = NULL;
30233a0c835SEtienne Carriere 	uint32_t phandle = 0;
30333a0c835SEtienne Carriere 	int pnode = 0;
30433a0c835SEtienne Carriere 	int len = 0;
30533a0c835SEtienne Carriere 
30633a0c835SEtienne Carriere 	prop = fdt_getprop(fdt, node, "interrupts", &len);
30733a0c835SEtienne Carriere 	if (!prop)
30833a0c835SEtienne Carriere 		return TEE_ERROR_ITEM_NOT_FOUND;
30933a0c835SEtienne Carriere 
31033a0c835SEtienne Carriere 	/* Find "interrupt-parent" in node or its parents */
31133a0c835SEtienne Carriere 	pnode = node;
31233a0c835SEtienne Carriere 	prop = fdt_getprop(fdt, pnode, "interrupt-parent", &len);
31333a0c835SEtienne Carriere 
31433a0c835SEtienne Carriere 	while (!prop) {
31533a0c835SEtienne Carriere 		pnode = fdt_parent_offset(fdt, pnode);
31633a0c835SEtienne Carriere 		if (pnode < 0)
31733a0c835SEtienne Carriere 			break;
31833a0c835SEtienne Carriere 
31933a0c835SEtienne Carriere 		prop = fdt_getprop(fdt, pnode, "interrupt-parent", &len);
32033a0c835SEtienne Carriere 		if (!prop && len != -FDT_ERR_NOTFOUND)
32133a0c835SEtienne Carriere 			break;
32233a0c835SEtienne Carriere 	}
32333a0c835SEtienne Carriere 	if (!prop) {
32433a0c835SEtienne Carriere 		DMSG("No interrupt parent for node %s",
32533a0c835SEtienne Carriere 		     fdt_get_name(fdt, node, NULL));
32633a0c835SEtienne Carriere 		return TEE_ERROR_GENERIC;
32733a0c835SEtienne Carriere 	}
32833a0c835SEtienne Carriere 
32933a0c835SEtienne Carriere 	/* "interrupt-parent" provides interrupt controller phandle */
33033a0c835SEtienne Carriere 	phandle = fdt32_to_cpu(prop[0]);
33133a0c835SEtienne Carriere 
33233a0c835SEtienne Carriere 	/* Get interrupt chip/number from phandle and "interrupts" property */
33333a0c835SEtienne Carriere 	return dt_driver_device_from_node_idx_prop_phandle("interrupts", fdt,
33433a0c835SEtienne Carriere 							   node, index,
33533a0c835SEtienne Carriere 							   DT_DRIVER_INTERRUPT,
33633a0c835SEtienne Carriere 							   phandle,
33733a0c835SEtienne Carriere 							   itr_desc);
33833a0c835SEtienne Carriere }
33933a0c835SEtienne Carriere 
34033a0c835SEtienne Carriere /*
34133a0c835SEtienne Carriere  * Fills an itr_desc based on "interrupts-extended" property bindings.
34233a0c835SEtienne Carriere  * May return TEE_ERROR_DEFER_DRIVER_INIT if parent controller is found
34333a0c835SEtienne Carriere  * but not yet initialized.
34433a0c835SEtienne Carriere  */
get_extended_interrupt_by_index(const void * fdt,int node,unsigned int index,struct itr_desc * itr_desc)34533a0c835SEtienne Carriere static TEE_Result get_extended_interrupt_by_index(const void *fdt, int node,
34633a0c835SEtienne Carriere 						  unsigned int index,
34733a0c835SEtienne Carriere 						  struct itr_desc *itr_desc)
34833a0c835SEtienne Carriere {
34933a0c835SEtienne Carriere 	return dt_driver_device_from_node_idx_prop("interrupts-extended",
35033a0c835SEtienne Carriere 						   fdt, node, index,
35133a0c835SEtienne Carriere 						   DT_DRIVER_INTERRUPT,
35233a0c835SEtienne Carriere 						   itr_desc);
35333a0c835SEtienne Carriere }
35433a0c835SEtienne Carriere 
interrupt_dt_get_by_index(const void * fdt,int node,unsigned int index,struct itr_chip ** chip,size_t * itr_num)35533a0c835SEtienne Carriere TEE_Result interrupt_dt_get_by_index(const void *fdt, int node,
35633a0c835SEtienne Carriere 				     unsigned int index, struct itr_chip **chip,
35733a0c835SEtienne Carriere 				     size_t *itr_num)
35833a0c835SEtienne Carriere {
35933a0c835SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
36033a0c835SEtienne Carriere 	struct itr_desc desc = { };
36133a0c835SEtienne Carriere 
36233a0c835SEtienne Carriere 	assert(chip && itr_num);
36333a0c835SEtienne Carriere 
36433a0c835SEtienne Carriere 	/* "interrupts-extended" takes precedence over "interrupts" */
36533a0c835SEtienne Carriere 	if (fdt_getprop(fdt, node, "interrupts-extended", NULL))
36633a0c835SEtienne Carriere 		res = get_extended_interrupt_by_index(fdt, node, index, &desc);
36733a0c835SEtienne Carriere 	else
36833a0c835SEtienne Carriere 		res = get_legacy_interrupt_by_index(fdt, node, index, &desc);
36933a0c835SEtienne Carriere 
37033a0c835SEtienne Carriere 	if (!res) {
371941de178SEtienne Carriere 		assert(itr_chip_is_valid(desc.chip));
37233a0c835SEtienne Carriere 		*chip = desc.chip;
37333a0c835SEtienne Carriere 		*itr_num = desc.itr_num;
37433a0c835SEtienne Carriere 	}
37533a0c835SEtienne Carriere 
37633a0c835SEtienne Carriere 	return res;
37733a0c835SEtienne Carriere }
37833a0c835SEtienne Carriere 
interrupt_dt_get_by_name(const void * fdt,int node,const char * name,struct itr_chip ** chip,size_t * itr_num)37933a0c835SEtienne Carriere TEE_Result interrupt_dt_get_by_name(const void *fdt, int node, const char *name,
38033a0c835SEtienne Carriere 				    struct itr_chip **chip, size_t *itr_num)
38133a0c835SEtienne Carriere {
38233a0c835SEtienne Carriere 	int idx = 0;
38333a0c835SEtienne Carriere 
38433a0c835SEtienne Carriere 	idx = fdt_stringlist_search(fdt, node, "interrupt-names", name);
38533a0c835SEtienne Carriere 	if (idx < 0)
38633a0c835SEtienne Carriere 		return TEE_ERROR_GENERIC;
38733a0c835SEtienne Carriere 
38833a0c835SEtienne Carriere 	return interrupt_dt_get_by_index(fdt, node, idx, chip, itr_num);
38933a0c835SEtienne Carriere }
39033a0c835SEtienne Carriere #endif /*CFG_DT*/
391