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