1f5fbb83fSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0
29d4fa1a1SMauro Carvalho Chehab /*
39d4fa1a1SMauro Carvalho Chehab  * Support for Intel Camera Imaging ISP subsystem.
49d4fa1a1SMauro Carvalho Chehab  * Copyright (c) 2010-2015, Intel Corporation.
59d4fa1a1SMauro Carvalho Chehab  *
69d4fa1a1SMauro Carvalho Chehab  * This program is free software; you can redistribute it and/or modify it
79d4fa1a1SMauro Carvalho Chehab  * under the terms and conditions of the GNU General Public License,
89d4fa1a1SMauro Carvalho Chehab  * version 2, as published by the Free Software Foundation.
99d4fa1a1SMauro Carvalho Chehab  *
109d4fa1a1SMauro Carvalho Chehab  * This program is distributed in the hope it will be useful, but WITHOUT
119d4fa1a1SMauro Carvalho Chehab  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
129d4fa1a1SMauro Carvalho Chehab  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
139d4fa1a1SMauro Carvalho Chehab  * more details.
149d4fa1a1SMauro Carvalho Chehab  */
159d4fa1a1SMauro Carvalho Chehab 
169d4fa1a1SMauro Carvalho Chehab #include "assert_support.h"
179d4fa1a1SMauro Carvalho Chehab #include "irq.h"
189d4fa1a1SMauro Carvalho Chehab 
199d4fa1a1SMauro Carvalho Chehab #ifndef __INLINE_GP_DEVICE__
209d4fa1a1SMauro Carvalho Chehab #define __INLINE_GP_DEVICE__
219d4fa1a1SMauro Carvalho Chehab #endif
229d4fa1a1SMauro Carvalho Chehab #include "gp_device.h"	/* _REG_GP_IRQ_REQUEST_ADDR */
239d4fa1a1SMauro Carvalho Chehab 
249d4fa1a1SMauro Carvalho Chehab static inline void irq_wait_for_write_complete(
259d4fa1a1SMauro Carvalho Chehab     const irq_ID_t		ID);
269d4fa1a1SMauro Carvalho Chehab 
279d4fa1a1SMauro Carvalho Chehab static inline bool any_irq_channel_enabled(
289d4fa1a1SMauro Carvalho Chehab     const irq_ID_t				ID);
299d4fa1a1SMauro Carvalho Chehab 
3090240017SMauro Carvalho Chehab static inline irq_ID_t virq_get_irq_id(const enum virq_id irq_ID,
319d4fa1a1SMauro Carvalho Chehab 				       unsigned int *channel_ID);
329d4fa1a1SMauro Carvalho Chehab 
339d4fa1a1SMauro Carvalho Chehab #ifndef __INLINE_IRQ__
349d4fa1a1SMauro Carvalho Chehab #include "irq_private.h"
359d4fa1a1SMauro Carvalho Chehab #endif /* __INLINE_IRQ__ */
369d4fa1a1SMauro Carvalho Chehab 
379d4fa1a1SMauro Carvalho Chehab static unsigned short IRQ_N_CHANNEL[N_IRQ_ID] = {
389d4fa1a1SMauro Carvalho Chehab 	IRQ0_ID_N_CHANNEL,
399d4fa1a1SMauro Carvalho Chehab 	IRQ1_ID_N_CHANNEL,
409d4fa1a1SMauro Carvalho Chehab 	IRQ2_ID_N_CHANNEL,
419d4fa1a1SMauro Carvalho Chehab 	IRQ3_ID_N_CHANNEL
429d4fa1a1SMauro Carvalho Chehab };
439d4fa1a1SMauro Carvalho Chehab 
449d4fa1a1SMauro Carvalho Chehab static unsigned short IRQ_N_ID_OFFSET[N_IRQ_ID + 1] = {
459d4fa1a1SMauro Carvalho Chehab 	IRQ0_ID_OFFSET,
469d4fa1a1SMauro Carvalho Chehab 	IRQ1_ID_OFFSET,
479d4fa1a1SMauro Carvalho Chehab 	IRQ2_ID_OFFSET,
489d4fa1a1SMauro Carvalho Chehab 	IRQ3_ID_OFFSET,
499d4fa1a1SMauro Carvalho Chehab 	IRQ_END_OFFSET
509d4fa1a1SMauro Carvalho Chehab };
519d4fa1a1SMauro Carvalho Chehab 
5290240017SMauro Carvalho Chehab static enum virq_id IRQ_NESTING_ID[N_IRQ_ID] = {
539d4fa1a1SMauro Carvalho Chehab 	N_virq_id,
549d4fa1a1SMauro Carvalho Chehab 	virq_ifmt,
559d4fa1a1SMauro Carvalho Chehab 	virq_isys,
569d4fa1a1SMauro Carvalho Chehab 	virq_isel
579d4fa1a1SMauro Carvalho Chehab };
589d4fa1a1SMauro Carvalho Chehab 
irq_clear_all(const irq_ID_t ID)599d4fa1a1SMauro Carvalho Chehab void irq_clear_all(
609d4fa1a1SMauro Carvalho Chehab     const irq_ID_t				ID)
619d4fa1a1SMauro Carvalho Chehab {
629d4fa1a1SMauro Carvalho Chehab 	hrt_data	mask = 0xFFFFFFFF;
639d4fa1a1SMauro Carvalho Chehab 
649d4fa1a1SMauro Carvalho Chehab 	assert(ID < N_IRQ_ID);
659d4fa1a1SMauro Carvalho Chehab 	assert(IRQ_N_CHANNEL[ID] <= HRT_DATA_WIDTH);
669d4fa1a1SMauro Carvalho Chehab 
679d4fa1a1SMauro Carvalho Chehab 	if (IRQ_N_CHANNEL[ID] < HRT_DATA_WIDTH) {
689d4fa1a1SMauro Carvalho Chehab 		mask = ~((~(hrt_data)0) >> IRQ_N_CHANNEL[ID]);
699d4fa1a1SMauro Carvalho Chehab 	}
709d4fa1a1SMauro Carvalho Chehab 
719d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
729d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, mask);
739d4fa1a1SMauro Carvalho Chehab 	return;
749d4fa1a1SMauro Carvalho Chehab }
759d4fa1a1SMauro Carvalho Chehab 
769d4fa1a1SMauro Carvalho Chehab /*
779d4fa1a1SMauro Carvalho Chehab  * Do we want the user to be able to set the signalling method ?
789d4fa1a1SMauro Carvalho Chehab  */
irq_enable_channel(const irq_ID_t ID,const unsigned int irq_id)799d4fa1a1SMauro Carvalho Chehab void irq_enable_channel(
809d4fa1a1SMauro Carvalho Chehab     const irq_ID_t				ID,
819d4fa1a1SMauro Carvalho Chehab     const unsigned int			irq_id)
829d4fa1a1SMauro Carvalho Chehab {
839d4fa1a1SMauro Carvalho Chehab 	unsigned int mask = irq_reg_load(ID,
849d4fa1a1SMauro Carvalho Chehab 					 _HRT_IRQ_CONTROLLER_MASK_REG_IDX);
859d4fa1a1SMauro Carvalho Chehab 	unsigned int enable = irq_reg_load(ID,
869d4fa1a1SMauro Carvalho Chehab 					   _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
879d4fa1a1SMauro Carvalho Chehab 	unsigned int edge_in = irq_reg_load(ID,
889d4fa1a1SMauro Carvalho Chehab 					    _HRT_IRQ_CONTROLLER_EDGE_REG_IDX);
899d4fa1a1SMauro Carvalho Chehab 	unsigned int me = 1U << irq_id;
909d4fa1a1SMauro Carvalho Chehab 
919d4fa1a1SMauro Carvalho Chehab 	assert(ID < N_IRQ_ID);
929d4fa1a1SMauro Carvalho Chehab 	assert(irq_id < IRQ_N_CHANNEL[ID]);
939d4fa1a1SMauro Carvalho Chehab 
949d4fa1a1SMauro Carvalho Chehab 	mask |= me;
959d4fa1a1SMauro Carvalho Chehab 	enable |= me;
969d4fa1a1SMauro Carvalho Chehab 	edge_in |= me;	/* rising edge */
979d4fa1a1SMauro Carvalho Chehab 
989d4fa1a1SMauro Carvalho Chehab 	/* to avoid mishaps configuration must follow the following order */
999d4fa1a1SMauro Carvalho Chehab 
1009d4fa1a1SMauro Carvalho Chehab 	/* mask this interrupt */
1019d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
1029d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_MASK_REG_IDX, mask & ~me);
1039d4fa1a1SMauro Carvalho Chehab 	/* rising edge at input */
1049d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
1059d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_EDGE_REG_IDX, edge_in);
1069d4fa1a1SMauro Carvalho Chehab 	/* enable interrupt to output */
1079d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
1089d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX, enable);
1099d4fa1a1SMauro Carvalho Chehab 	/* clear current irq only */
1109d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
1119d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, me);
1129d4fa1a1SMauro Carvalho Chehab 	/* unmask interrupt from input */
1139d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
1149d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_MASK_REG_IDX, mask);
1159d4fa1a1SMauro Carvalho Chehab 
1169d4fa1a1SMauro Carvalho Chehab 	irq_wait_for_write_complete(ID);
1179d4fa1a1SMauro Carvalho Chehab 
1189d4fa1a1SMauro Carvalho Chehab 	return;
1199d4fa1a1SMauro Carvalho Chehab }
1209d4fa1a1SMauro Carvalho Chehab 
irq_enable_pulse(const irq_ID_t ID,bool pulse)1219d4fa1a1SMauro Carvalho Chehab void irq_enable_pulse(
1229d4fa1a1SMauro Carvalho Chehab     const irq_ID_t	ID,
1239d4fa1a1SMauro Carvalho Chehab     bool			pulse)
1249d4fa1a1SMauro Carvalho Chehab {
1259d4fa1a1SMauro Carvalho Chehab 	unsigned int edge_out = 0x0;
1269d4fa1a1SMauro Carvalho Chehab 
1279d4fa1a1SMauro Carvalho Chehab 	if (pulse) {
1289d4fa1a1SMauro Carvalho Chehab 		edge_out = 0xffffffff;
1299d4fa1a1SMauro Carvalho Chehab 	}
1309d4fa1a1SMauro Carvalho Chehab 	/* output is given as edge, not pulse */
1319d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
1329d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX, edge_out);
1339d4fa1a1SMauro Carvalho Chehab 	return;
1349d4fa1a1SMauro Carvalho Chehab }
1359d4fa1a1SMauro Carvalho Chehab 
irq_disable_channel(const irq_ID_t ID,const unsigned int irq_id)1369d4fa1a1SMauro Carvalho Chehab void irq_disable_channel(
1379d4fa1a1SMauro Carvalho Chehab     const irq_ID_t				ID,
1389d4fa1a1SMauro Carvalho Chehab     const unsigned int			irq_id)
1399d4fa1a1SMauro Carvalho Chehab {
1409d4fa1a1SMauro Carvalho Chehab 	unsigned int mask = irq_reg_load(ID,
1419d4fa1a1SMauro Carvalho Chehab 					 _HRT_IRQ_CONTROLLER_MASK_REG_IDX);
1429d4fa1a1SMauro Carvalho Chehab 	unsigned int enable = irq_reg_load(ID,
1439d4fa1a1SMauro Carvalho Chehab 					   _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
1449d4fa1a1SMauro Carvalho Chehab 	unsigned int me = 1U << irq_id;
1459d4fa1a1SMauro Carvalho Chehab 
1469d4fa1a1SMauro Carvalho Chehab 	assert(ID < N_IRQ_ID);
1479d4fa1a1SMauro Carvalho Chehab 	assert(irq_id < IRQ_N_CHANNEL[ID]);
1489d4fa1a1SMauro Carvalho Chehab 
1499d4fa1a1SMauro Carvalho Chehab 	mask &= ~me;
1509d4fa1a1SMauro Carvalho Chehab 	enable &= ~me;
1519d4fa1a1SMauro Carvalho Chehab 
1529d4fa1a1SMauro Carvalho Chehab 	/* enable interrupt to output */
1539d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
1549d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX, enable);
1559d4fa1a1SMauro Carvalho Chehab 	/* unmask interrupt from input */
1569d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
1579d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_MASK_REG_IDX, mask);
1589d4fa1a1SMauro Carvalho Chehab 	/* clear current irq only */
1599d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
1609d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, me);
1619d4fa1a1SMauro Carvalho Chehab 
1629d4fa1a1SMauro Carvalho Chehab 	irq_wait_for_write_complete(ID);
1639d4fa1a1SMauro Carvalho Chehab 
1649d4fa1a1SMauro Carvalho Chehab 	return;
1659d4fa1a1SMauro Carvalho Chehab }
1669d4fa1a1SMauro Carvalho Chehab 
irq_get_channel_id(const irq_ID_t ID,unsigned int * irq_id)1679d4fa1a1SMauro Carvalho Chehab enum hrt_isp_css_irq_status irq_get_channel_id(
1689d4fa1a1SMauro Carvalho Chehab     const irq_ID_t				ID,
1699d4fa1a1SMauro Carvalho Chehab     unsigned int				*irq_id)
1709d4fa1a1SMauro Carvalho Chehab {
1719d4fa1a1SMauro Carvalho Chehab 	unsigned int irq_status = irq_reg_load(ID,
1729d4fa1a1SMauro Carvalho Chehab 					       _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
1739d4fa1a1SMauro Carvalho Chehab 	unsigned int idx;
1749d4fa1a1SMauro Carvalho Chehab 	enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_success;
1759d4fa1a1SMauro Carvalho Chehab 
1769d4fa1a1SMauro Carvalho Chehab 	assert(ID < N_IRQ_ID);
1779d4fa1a1SMauro Carvalho Chehab 	assert(irq_id);
1789d4fa1a1SMauro Carvalho Chehab 
1799d4fa1a1SMauro Carvalho Chehab 	/* find the first irq bit */
1809d4fa1a1SMauro Carvalho Chehab 	for (idx = 0; idx < IRQ_N_CHANNEL[ID]; idx++) {
1819d4fa1a1SMauro Carvalho Chehab 		if (irq_status & (1U << idx))
1829d4fa1a1SMauro Carvalho Chehab 			break;
1839d4fa1a1SMauro Carvalho Chehab 	}
1849d4fa1a1SMauro Carvalho Chehab 	if (idx == IRQ_N_CHANNEL[ID])
1859d4fa1a1SMauro Carvalho Chehab 		return hrt_isp_css_irq_status_error;
1869d4fa1a1SMauro Carvalho Chehab 
1879d4fa1a1SMauro Carvalho Chehab 	/* now check whether there are more bits set */
1889d4fa1a1SMauro Carvalho Chehab 	if (irq_status != (1U << idx))
1899d4fa1a1SMauro Carvalho Chehab 		status = hrt_isp_css_irq_status_more_irqs;
1909d4fa1a1SMauro Carvalho Chehab 
1919d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
1929d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, 1U << idx);
1939d4fa1a1SMauro Carvalho Chehab 
1949d4fa1a1SMauro Carvalho Chehab 	irq_wait_for_write_complete(ID);
1959d4fa1a1SMauro Carvalho Chehab 
1969d4fa1a1SMauro Carvalho Chehab 	if (irq_id)
1979d4fa1a1SMauro Carvalho Chehab 		*irq_id = (unsigned int)idx;
1989d4fa1a1SMauro Carvalho Chehab 
1999d4fa1a1SMauro Carvalho Chehab 	return status;
2009d4fa1a1SMauro Carvalho Chehab }
2019d4fa1a1SMauro Carvalho Chehab 
2029d4fa1a1SMauro Carvalho Chehab static const hrt_address IRQ_REQUEST_ADDR[N_IRQ_SW_CHANNEL_ID] = {
2039d4fa1a1SMauro Carvalho Chehab 	_REG_GP_IRQ_REQUEST0_ADDR,
2049d4fa1a1SMauro Carvalho Chehab 	_REG_GP_IRQ_REQUEST1_ADDR
2059d4fa1a1SMauro Carvalho Chehab };
2069d4fa1a1SMauro Carvalho Chehab 
irq_raise(const irq_ID_t ID,const irq_sw_channel_id_t irq_id)2079d4fa1a1SMauro Carvalho Chehab void irq_raise(
2089d4fa1a1SMauro Carvalho Chehab     const irq_ID_t				ID,
2099d4fa1a1SMauro Carvalho Chehab     const irq_sw_channel_id_t	irq_id)
2109d4fa1a1SMauro Carvalho Chehab {
2119d4fa1a1SMauro Carvalho Chehab 	hrt_address		addr;
2129d4fa1a1SMauro Carvalho Chehab 
2139d4fa1a1SMauro Carvalho Chehab 	OP___assert(ID == IRQ0_ID);
2149d4fa1a1SMauro Carvalho Chehab 	OP___assert(IRQ_BASE[ID] != (hrt_address)-1);
2159d4fa1a1SMauro Carvalho Chehab 	OP___assert(irq_id < N_IRQ_SW_CHANNEL_ID);
2169d4fa1a1SMauro Carvalho Chehab 
2179d4fa1a1SMauro Carvalho Chehab 	(void)ID;
2189d4fa1a1SMauro Carvalho Chehab 
2199d4fa1a1SMauro Carvalho Chehab 	addr = IRQ_REQUEST_ADDR[irq_id];
2209d4fa1a1SMauro Carvalho Chehab 	/* The SW IRQ pins are remapped to offset zero */
2219d4fa1a1SMauro Carvalho Chehab 	gp_device_reg_store(GP_DEVICE0_ID,
2229d4fa1a1SMauro Carvalho Chehab 			    (unsigned int)addr, 1);
2239d4fa1a1SMauro Carvalho Chehab 	gp_device_reg_store(GP_DEVICE0_ID,
2249d4fa1a1SMauro Carvalho Chehab 			    (unsigned int)addr, 0);
2259d4fa1a1SMauro Carvalho Chehab 	return;
2269d4fa1a1SMauro Carvalho Chehab }
2279d4fa1a1SMauro Carvalho Chehab 
irq_controller_get_state(const irq_ID_t ID,struct irq_controller_state * state)22890240017SMauro Carvalho Chehab void irq_controller_get_state(const irq_ID_t ID,
22990240017SMauro Carvalho Chehab 			      struct irq_controller_state *state)
2309d4fa1a1SMauro Carvalho Chehab {
2319d4fa1a1SMauro Carvalho Chehab 	assert(ID < N_IRQ_ID);
2329d4fa1a1SMauro Carvalho Chehab 	assert(state);
2339d4fa1a1SMauro Carvalho Chehab 
2349d4fa1a1SMauro Carvalho Chehab 	state->irq_edge = irq_reg_load(ID,
2359d4fa1a1SMauro Carvalho Chehab 				       _HRT_IRQ_CONTROLLER_EDGE_REG_IDX);
2369d4fa1a1SMauro Carvalho Chehab 	state->irq_mask = irq_reg_load(ID,
2379d4fa1a1SMauro Carvalho Chehab 				       _HRT_IRQ_CONTROLLER_MASK_REG_IDX);
2389d4fa1a1SMauro Carvalho Chehab 	state->irq_status = irq_reg_load(ID,
2399d4fa1a1SMauro Carvalho Chehab 					 _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
2409d4fa1a1SMauro Carvalho Chehab 	state->irq_enable = irq_reg_load(ID,
2419d4fa1a1SMauro Carvalho Chehab 					 _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
2429d4fa1a1SMauro Carvalho Chehab 	state->irq_level_not_pulse = irq_reg_load(ID,
2439d4fa1a1SMauro Carvalho Chehab 				     _HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX);
2449d4fa1a1SMauro Carvalho Chehab 	return;
2459d4fa1a1SMauro Carvalho Chehab }
2469d4fa1a1SMauro Carvalho Chehab 
any_virq_signal(void)2479d4fa1a1SMauro Carvalho Chehab bool any_virq_signal(void)
2489d4fa1a1SMauro Carvalho Chehab {
2499d4fa1a1SMauro Carvalho Chehab 	unsigned int irq_status = irq_reg_load(IRQ0_ID,
2509d4fa1a1SMauro Carvalho Chehab 					       _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
2519d4fa1a1SMauro Carvalho Chehab 
2529d4fa1a1SMauro Carvalho Chehab 	return (irq_status != 0);
2539d4fa1a1SMauro Carvalho Chehab }
2549d4fa1a1SMauro Carvalho Chehab 
cnd_virq_enable_channel(const enum virq_id irq_ID,const bool en)2559d4fa1a1SMauro Carvalho Chehab void cnd_virq_enable_channel(
25690240017SMauro Carvalho Chehab     const enum virq_id				irq_ID,
2579d4fa1a1SMauro Carvalho Chehab     const bool					en)
2589d4fa1a1SMauro Carvalho Chehab {
2599d4fa1a1SMauro Carvalho Chehab 	irq_ID_t		i;
2609d4fa1a1SMauro Carvalho Chehab 	unsigned int	channel_ID;
2619d4fa1a1SMauro Carvalho Chehab 	irq_ID_t		ID = virq_get_irq_id(irq_ID, &channel_ID);
2629d4fa1a1SMauro Carvalho Chehab 
2639d4fa1a1SMauro Carvalho Chehab 	assert(ID < N_IRQ_ID);
2649d4fa1a1SMauro Carvalho Chehab 
2659d4fa1a1SMauro Carvalho Chehab 	for (i = IRQ1_ID; i < N_IRQ_ID; i++) {
2669d4fa1a1SMauro Carvalho Chehab 		/* It is not allowed to enable the pin of a nested IRQ directly */
2679d4fa1a1SMauro Carvalho Chehab 		assert(irq_ID != IRQ_NESTING_ID[i]);
2689d4fa1a1SMauro Carvalho Chehab 	}
2699d4fa1a1SMauro Carvalho Chehab 
2709d4fa1a1SMauro Carvalho Chehab 	if (en) {
2719d4fa1a1SMauro Carvalho Chehab 		irq_enable_channel(ID, channel_ID);
2729d4fa1a1SMauro Carvalho Chehab 		if (IRQ_NESTING_ID[ID] != N_virq_id) {
2739d4fa1a1SMauro Carvalho Chehab 			/* Single level nesting, otherwise we'd need to recurse */
2749d4fa1a1SMauro Carvalho Chehab 			irq_enable_channel(IRQ0_ID, IRQ_NESTING_ID[ID]);
2759d4fa1a1SMauro Carvalho Chehab 		}
2769d4fa1a1SMauro Carvalho Chehab 	} else {
2779d4fa1a1SMauro Carvalho Chehab 		irq_disable_channel(ID, channel_ID);
2789d4fa1a1SMauro Carvalho Chehab 		if ((IRQ_NESTING_ID[ID] != N_virq_id) && !any_irq_channel_enabled(ID)) {
2799d4fa1a1SMauro Carvalho Chehab 			/* Only disable the top if the nested ones are empty */
2809d4fa1a1SMauro Carvalho Chehab 			irq_disable_channel(IRQ0_ID, IRQ_NESTING_ID[ID]);
2819d4fa1a1SMauro Carvalho Chehab 		}
2829d4fa1a1SMauro Carvalho Chehab 	}
2839d4fa1a1SMauro Carvalho Chehab 	return;
2849d4fa1a1SMauro Carvalho Chehab }
2859d4fa1a1SMauro Carvalho Chehab 
virq_clear_all(void)2869d4fa1a1SMauro Carvalho Chehab void virq_clear_all(void)
2879d4fa1a1SMauro Carvalho Chehab {
2889d4fa1a1SMauro Carvalho Chehab 	irq_ID_t	irq_id;
2899d4fa1a1SMauro Carvalho Chehab 
2909d4fa1a1SMauro Carvalho Chehab 	for (irq_id = (irq_ID_t)0; irq_id < N_IRQ_ID; irq_id++) {
2919d4fa1a1SMauro Carvalho Chehab 		irq_clear_all(irq_id);
2929d4fa1a1SMauro Carvalho Chehab 	}
2939d4fa1a1SMauro Carvalho Chehab 	return;
2949d4fa1a1SMauro Carvalho Chehab }
2959d4fa1a1SMauro Carvalho Chehab 
29690240017SMauro Carvalho Chehab enum hrt_isp_css_irq_status
virq_get_channel_signals(struct virq_info * irq_info)29790240017SMauro Carvalho Chehab virq_get_channel_signals(struct virq_info *irq_info)
2989d4fa1a1SMauro Carvalho Chehab {
2999d4fa1a1SMauro Carvalho Chehab 	enum hrt_isp_css_irq_status irq_status = hrt_isp_css_irq_status_error;
3009d4fa1a1SMauro Carvalho Chehab 	irq_ID_t ID;
3019d4fa1a1SMauro Carvalho Chehab 
3029d4fa1a1SMauro Carvalho Chehab 	assert(irq_info);
3039d4fa1a1SMauro Carvalho Chehab 
3049d4fa1a1SMauro Carvalho Chehab 	for (ID = (irq_ID_t)0 ; ID < N_IRQ_ID; ID++) {
3059d4fa1a1SMauro Carvalho Chehab 		if (any_irq_channel_enabled(ID)) {
3069d4fa1a1SMauro Carvalho Chehab 			hrt_data	irq_data = irq_reg_load(ID,
3079d4fa1a1SMauro Carvalho Chehab 							    _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
3089d4fa1a1SMauro Carvalho Chehab 
3099d4fa1a1SMauro Carvalho Chehab 			if (irq_data != 0) {
3109d4fa1a1SMauro Carvalho Chehab 				/* The error condition is an IRQ pulse received with no IRQ status written */
3119d4fa1a1SMauro Carvalho Chehab 				irq_status = hrt_isp_css_irq_status_success;
3129d4fa1a1SMauro Carvalho Chehab 			}
3139d4fa1a1SMauro Carvalho Chehab 
3149d4fa1a1SMauro Carvalho Chehab 			irq_info->irq_status_reg[ID] |= irq_data;
3159d4fa1a1SMauro Carvalho Chehab 
3169d4fa1a1SMauro Carvalho Chehab 			irq_reg_store(ID,
3179d4fa1a1SMauro Carvalho Chehab 				      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, irq_data);
3189d4fa1a1SMauro Carvalho Chehab 
3199d4fa1a1SMauro Carvalho Chehab 			irq_wait_for_write_complete(ID);
3209d4fa1a1SMauro Carvalho Chehab 		}
3219d4fa1a1SMauro Carvalho Chehab 	}
3229d4fa1a1SMauro Carvalho Chehab 
3239d4fa1a1SMauro Carvalho Chehab 	return irq_status;
3249d4fa1a1SMauro Carvalho Chehab }
3259d4fa1a1SMauro Carvalho Chehab 
virq_clear_info(struct virq_info * irq_info)32690240017SMauro Carvalho Chehab void virq_clear_info(struct virq_info *irq_info)
3279d4fa1a1SMauro Carvalho Chehab {
3289d4fa1a1SMauro Carvalho Chehab 	irq_ID_t ID;
3299d4fa1a1SMauro Carvalho Chehab 
3309d4fa1a1SMauro Carvalho Chehab 	assert(irq_info);
3319d4fa1a1SMauro Carvalho Chehab 
3329d4fa1a1SMauro Carvalho Chehab 	for (ID = (irq_ID_t)0 ; ID < N_IRQ_ID; ID++) {
3339d4fa1a1SMauro Carvalho Chehab 		irq_info->irq_status_reg[ID] = 0;
3349d4fa1a1SMauro Carvalho Chehab 	}
3359d4fa1a1SMauro Carvalho Chehab 	return;
3369d4fa1a1SMauro Carvalho Chehab }
3379d4fa1a1SMauro Carvalho Chehab 
virq_get_channel_id(enum virq_id * irq_id)3389d4fa1a1SMauro Carvalho Chehab enum hrt_isp_css_irq_status virq_get_channel_id(
33990240017SMauro Carvalho Chehab     enum virq_id					*irq_id)
3409d4fa1a1SMauro Carvalho Chehab {
3419d4fa1a1SMauro Carvalho Chehab 	unsigned int irq_status = irq_reg_load(IRQ0_ID,
3429d4fa1a1SMauro Carvalho Chehab 					       _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
3439d4fa1a1SMauro Carvalho Chehab 	unsigned int idx;
3449d4fa1a1SMauro Carvalho Chehab 	enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_success;
3459d4fa1a1SMauro Carvalho Chehab 	irq_ID_t ID;
3469d4fa1a1SMauro Carvalho Chehab 
3479d4fa1a1SMauro Carvalho Chehab 	assert(irq_id);
3489d4fa1a1SMauro Carvalho Chehab 
3499d4fa1a1SMauro Carvalho Chehab 	/* find the first irq bit on device 0 */
3509d4fa1a1SMauro Carvalho Chehab 	for (idx = 0; idx < IRQ_N_CHANNEL[IRQ0_ID]; idx++) {
3519d4fa1a1SMauro Carvalho Chehab 		if (irq_status & (1U << idx))
3529d4fa1a1SMauro Carvalho Chehab 			break;
3539d4fa1a1SMauro Carvalho Chehab 	}
3549d4fa1a1SMauro Carvalho Chehab 
3559d4fa1a1SMauro Carvalho Chehab 	if (idx == IRQ_N_CHANNEL[IRQ0_ID]) {
3569d4fa1a1SMauro Carvalho Chehab 		return hrt_isp_css_irq_status_error;
3579d4fa1a1SMauro Carvalho Chehab 	}
3589d4fa1a1SMauro Carvalho Chehab 
3599d4fa1a1SMauro Carvalho Chehab 	/* Check whether there are more bits set on device 0 */
3609d4fa1a1SMauro Carvalho Chehab 	if (irq_status != (1U << idx)) {
3619d4fa1a1SMauro Carvalho Chehab 		status = hrt_isp_css_irq_status_more_irqs;
3629d4fa1a1SMauro Carvalho Chehab 	}
3639d4fa1a1SMauro Carvalho Chehab 
3649d4fa1a1SMauro Carvalho Chehab 	/* Check whether we have an IRQ on one of the nested devices */
3659d4fa1a1SMauro Carvalho Chehab 	for (ID = N_IRQ_ID - 1 ; ID > (irq_ID_t)0; ID--) {
36690240017SMauro Carvalho Chehab 		if (IRQ_NESTING_ID[ID] == (enum virq_id)idx) {
3679d4fa1a1SMauro Carvalho Chehab 			break;
3689d4fa1a1SMauro Carvalho Chehab 		}
3699d4fa1a1SMauro Carvalho Chehab 	}
3709d4fa1a1SMauro Carvalho Chehab 
3719d4fa1a1SMauro Carvalho Chehab 	/* If we have a nested IRQ, load that state, discard the device 0 state */
3729d4fa1a1SMauro Carvalho Chehab 	if (ID != IRQ0_ID) {
3739d4fa1a1SMauro Carvalho Chehab 		irq_status = irq_reg_load(ID,
3749d4fa1a1SMauro Carvalho Chehab 					  _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
3759d4fa1a1SMauro Carvalho Chehab 		/* find the first irq bit on device "id" */
3769d4fa1a1SMauro Carvalho Chehab 		for (idx = 0; idx < IRQ_N_CHANNEL[ID]; idx++) {
3779d4fa1a1SMauro Carvalho Chehab 			if (irq_status & (1U << idx))
3789d4fa1a1SMauro Carvalho Chehab 				break;
3799d4fa1a1SMauro Carvalho Chehab 		}
3809d4fa1a1SMauro Carvalho Chehab 
3819d4fa1a1SMauro Carvalho Chehab 		if (idx == IRQ_N_CHANNEL[ID]) {
3829d4fa1a1SMauro Carvalho Chehab 			return hrt_isp_css_irq_status_error;
3839d4fa1a1SMauro Carvalho Chehab 		}
3849d4fa1a1SMauro Carvalho Chehab 
3859d4fa1a1SMauro Carvalho Chehab 		/* Alternatively check whether there are more bits set on this device */
3869d4fa1a1SMauro Carvalho Chehab 		if (irq_status != (1U << idx)) {
3879d4fa1a1SMauro Carvalho Chehab 			status = hrt_isp_css_irq_status_more_irqs;
3889d4fa1a1SMauro Carvalho Chehab 		} else {
3899d4fa1a1SMauro Carvalho Chehab 			/* If this device is empty, clear the state on device 0 */
3909d4fa1a1SMauro Carvalho Chehab 			irq_reg_store(IRQ0_ID,
3919d4fa1a1SMauro Carvalho Chehab 				      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, 1U << IRQ_NESTING_ID[ID]);
3929d4fa1a1SMauro Carvalho Chehab 		}
3939d4fa1a1SMauro Carvalho Chehab 	} /* if (ID != IRQ0_ID) */
3949d4fa1a1SMauro Carvalho Chehab 
3959d4fa1a1SMauro Carvalho Chehab 	/* Here we proceed to clear the IRQ on detected device, if no nested IRQ, this is device 0 */
3969d4fa1a1SMauro Carvalho Chehab 	irq_reg_store(ID,
3979d4fa1a1SMauro Carvalho Chehab 		      _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, 1U << idx);
3989d4fa1a1SMauro Carvalho Chehab 
3999d4fa1a1SMauro Carvalho Chehab 	irq_wait_for_write_complete(ID);
4009d4fa1a1SMauro Carvalho Chehab 
4019d4fa1a1SMauro Carvalho Chehab 	idx += IRQ_N_ID_OFFSET[ID];
4029d4fa1a1SMauro Carvalho Chehab 	if (irq_id)
40390240017SMauro Carvalho Chehab 		*irq_id = (enum virq_id)idx;
4049d4fa1a1SMauro Carvalho Chehab 
4059d4fa1a1SMauro Carvalho Chehab 	return status;
4069d4fa1a1SMauro Carvalho Chehab }
4079d4fa1a1SMauro Carvalho Chehab 
irq_wait_for_write_complete(const irq_ID_t ID)4089d4fa1a1SMauro Carvalho Chehab static inline void irq_wait_for_write_complete(
4099d4fa1a1SMauro Carvalho Chehab     const irq_ID_t		ID)
4109d4fa1a1SMauro Carvalho Chehab {
4119d4fa1a1SMauro Carvalho Chehab 	assert(ID < N_IRQ_ID);
4129d4fa1a1SMauro Carvalho Chehab 	assert(IRQ_BASE[ID] != (hrt_address)-1);
4139d4fa1a1SMauro Carvalho Chehab 	(void)ia_css_device_load_uint32(IRQ_BASE[ID] +
4149d4fa1a1SMauro Carvalho Chehab 					_HRT_IRQ_CONTROLLER_ENABLE_REG_IDX * sizeof(hrt_data));
4159d4fa1a1SMauro Carvalho Chehab }
4169d4fa1a1SMauro Carvalho Chehab 
any_irq_channel_enabled(const irq_ID_t ID)4179d4fa1a1SMauro Carvalho Chehab static inline bool any_irq_channel_enabled(
4189d4fa1a1SMauro Carvalho Chehab     const irq_ID_t				ID)
4199d4fa1a1SMauro Carvalho Chehab {
4209d4fa1a1SMauro Carvalho Chehab 	hrt_data	en_reg;
4219d4fa1a1SMauro Carvalho Chehab 
4229d4fa1a1SMauro Carvalho Chehab 	assert(ID < N_IRQ_ID);
4239d4fa1a1SMauro Carvalho Chehab 
4249d4fa1a1SMauro Carvalho Chehab 	en_reg = irq_reg_load(ID,
4259d4fa1a1SMauro Carvalho Chehab 			      _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
4269d4fa1a1SMauro Carvalho Chehab 
4279d4fa1a1SMauro Carvalho Chehab 	return (en_reg != 0);
4289d4fa1a1SMauro Carvalho Chehab }
4299d4fa1a1SMauro Carvalho Chehab 
virq_get_irq_id(const enum virq_id irq_ID,unsigned int * channel_ID)4309d4fa1a1SMauro Carvalho Chehab static inline irq_ID_t virq_get_irq_id(
43190240017SMauro Carvalho Chehab     const enum virq_id		irq_ID,
4329d4fa1a1SMauro Carvalho Chehab     unsigned int		*channel_ID)
4339d4fa1a1SMauro Carvalho Chehab {
4349d4fa1a1SMauro Carvalho Chehab 	irq_ID_t ID;
4359d4fa1a1SMauro Carvalho Chehab 
4369d4fa1a1SMauro Carvalho Chehab 	assert(channel_ID);
4379d4fa1a1SMauro Carvalho Chehab 
4389d4fa1a1SMauro Carvalho Chehab 	for (ID = (irq_ID_t)0 ; ID < N_IRQ_ID; ID++) {
4399d4fa1a1SMauro Carvalho Chehab 		if (irq_ID < IRQ_N_ID_OFFSET[ID + 1]) {
4409d4fa1a1SMauro Carvalho Chehab 			break;
4419d4fa1a1SMauro Carvalho Chehab 		}
4429d4fa1a1SMauro Carvalho Chehab 	}
4439d4fa1a1SMauro Carvalho Chehab 
4449d4fa1a1SMauro Carvalho Chehab 	*channel_ID = (unsigned int)irq_ID - IRQ_N_ID_OFFSET[ID];
4459d4fa1a1SMauro Carvalho Chehab 
4469d4fa1a1SMauro Carvalho Chehab 	return ID;
4479d4fa1a1SMauro Carvalho Chehab }
448