1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#pragma once
14
15#include <platsupport/io.h>
16
17typedef struct irq_combiner irq_combiner_t;
18typedef int combiner_irq_t;
19
20struct irq_combiner {
21    int (*is_pending)(irq_combiner_t* combiner, combiner_irq_t cirq);
22    int (*is_enabled)(irq_combiner_t* combiner, combiner_irq_t cirq);
23    int (*set_enabled)(irq_combiner_t* combiner, combiner_irq_t cirq, int v);
24    uint32_t (*grp_pending)(irq_combiner_t* combiner, int group);
25    void* priv;
26};
27
28#include <platsupport/plat/irq_combiner.h>
29
30#define COMBINER_IRQ_FLAG         0x8000
31#define IS_COMBINER_IRQ(x)        !!((x) & COMBINER_IRQ_FLAG)
32#define COMBINER_IRQ(grp, idx)    (((grp) << 8) | (idx) | COMBINER_IRQ_FLAG)
33#define COMBINER_IRQ_GET_GROUP(x) (((x) & ~COMBINER_IRQ_FLAG) >> 8)
34#define COMBINER_IRQ_GET_INDEX(x) (((x) & ~COMBINER_IRQ_FLAG) & 0xff)
35
36/**
37 * Initialise the IRQ combiner
38 * @param[in]  id       The combiner device ID
39 * @param[in]  io_ops   IO operations for accessing this device
40 * @param[out] combiner An IRQ combiner structure to populate
41 * @return              0 on success.
42 */
43int irq_combiner_init(enum irq_combiner_id id, ps_io_ops_t* io_ops, irq_combiner_t* combiner);
44
45/**
46 * Find the number of IRQ groups managed by the combiner. This will typically
47 * be the number of IRQ groups.
48 * @param[in] id        The combiner device ID
49 * @return              The number of IRQ lines that this combiner manages.
50 *                      -1 if the combiner id is invalid
51 */
52int irq_combiner_nirqs(enum irq_combiner_id id);
53
54/**
55 * Find the IRQ mapped to the requested group
56 * @param[in] id        The combiner device ID
57 * @param[in] group     The Combiner group number to query
58 * @return              The IRQ number for the provided IRQ group
59 *                      -1 if the combiner id is invalid
60 */
61int irq_combiner_irq(enum irq_combiner_id id, int group);
62
63/**
64 * Determine if a combiner IRQ is pending
65 * @param[in] combiner A handle to an IRQ combiner
66 * @param[in] cirq     A combiner IRQ id as constructed from COMBINER_IRQ(grp, idx)
67 * @return             0 if the IRQ is not pending, 1 if the IRQ is pending, or
68 *                     -1 on error.
69 */
70static inline int irq_combiner_is_pending(irq_combiner_t* combiner, combiner_irq_t cirq)
71{
72    assert(combiner);
73    assert(combiner->is_pending);
74    return combiner->is_pending(combiner, cirq);
75}
76
77/**
78 * Determine if a combiner IRQ is enabled
79 * @param[in] combiner A handle to an IRQ combiner
80 * @param[in] cirq     A combiner IRQ id as constructed from COMBINER_IRQ(grp, idx)
81 * @return             0 if the IRQ is not enabled, 1 if the IRQ is enabled, or
82 *                     -1 on error.
83 */
84static inline int irq_combiner_is_enabled(irq_combiner_t* combiner, combiner_irq_t cirq)
85{
86    assert(combiner);
87    assert(combiner->is_pending);
88    return combiner->is_enabled(combiner, cirq);
89}
90
91/**
92 * Enable a combiner IRQ index within a group. Does not enable the entire group
93 * at the primary interrupt controller.
94 * @param[in] combiner A handle to an IRQ combiner
95 * @param[in] cirq     A combiner IRQ id as constructed from COMBINER_IRQ(grp, idx)
96 * @return             0 on success.
97 */
98static inline int irq_combiner_enable_irq(irq_combiner_t* combiner, combiner_irq_t cirq)
99{
100    assert(combiner);
101    assert(combiner->is_pending);
102    return combiner->set_enabled(combiner, cirq, 1);
103}
104
105/**
106 * Disable a combiner IRQ within a group. Does not disable the entire group
107 * at the primary interrupt controller.
108 * @param[in] combiner A handle to an IRQ combiner
109 * @param[in] cirq     A combiner IRQ id as constructed from COMBINER_IRQ(grp, idx)
110 * @return             0 on success.
111 */
112static inline int irq_combiner_disable_irq(irq_combiner_t* combiner, combiner_irq_t cirq)
113{
114    assert(combiner);
115    assert(combiner->is_pending);
116    return combiner->set_enabled(combiner, cirq, 0);
117}
118
119/**
120 * Determine which IRQs in a Combiner group are pending
121 * @param[in] combiner A handle to an IRQ combiner
122 * @param[in] group    The Combiner group number to query
123 * @return             A bitfield of pending IRQs for this group.
124 */
125static inline uint32_t irq_combiner_group_pending(irq_combiner_t* combiner, int group)
126{
127    assert(combiner);
128    assert(combiner->is_pending);
129    return combiner->grp_pending(combiner, group);
130}
131
132