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#include <utils/util.h>
14#include <platsupport/irq_combiner.h>
15#include "../../services.h"
16
17
18#define NGROUPS 32
19
20struct combiner_gmap {
21    uint32_t enable_set;
22    uint32_t enable_clr;
23    uint32_t status;
24    uint32_t masked_status;
25};
26
27struct irq_combiner_map {
28    struct combiner_gmap g[NGROUPS / 4];
29    uint32_t res[32];
30    uint32_t pending;
31};
32
33volatile struct irq_combiner_map *_combiner_regs = NULL;
34
35#define GROUP_INDEX(cirq) (COMBINER_IRQ_GET_GROUP(cirq) >> 2)
36#define GROUP_SHIFT(cirq) ((COMBINER_IRQ_GET_GROUP(cirq) & 0x3) * 8)
37#define IRQ_SHIFT(cirq)   (COMBINER_IRQ_GET_INDEX(cirq))
38#define GROUP_INDEX_MASK  0xff
39
40static volatile struct irq_combiner_map*
41irq_combiner_get_regs(irq_combiner_t* combiner) {
42    assert(combiner);
43    assert(combiner->priv);
44    return (volatile struct irq_combiner_map*)combiner->priv;
45}
46
47static int
48exynos_irq_combiner_is_pending(irq_combiner_t* combiner, combiner_irq_t cirq)
49{
50    volatile struct irq_combiner_map* regs;
51    int gidx, shift;
52    regs = irq_combiner_get_regs(combiner);
53    gidx = GROUP_INDEX(cirq);
54    shift = GROUP_SHIFT(cirq) + IRQ_SHIFT(cirq);
55    return !!(regs->g[gidx].masked_status & BIT(shift));
56}
57
58static int
59exynos_irq_combiner_is_enabled(irq_combiner_t* combiner, combiner_irq_t cirq)
60{
61    volatile struct irq_combiner_map* regs;
62    int gidx, shift;
63    regs = irq_combiner_get_regs(combiner);
64    gidx = GROUP_INDEX(cirq);
65    shift = GROUP_SHIFT(cirq) + IRQ_SHIFT(cirq);
66    return !!(regs->g[gidx].enable_set & BIT(shift));
67}
68
69static int
70exynos_irq_combiner_set_enabled(irq_combiner_t* combiner, combiner_irq_t cirq, int v)
71{
72    volatile struct irq_combiner_map* regs;
73    int gidx, shift;
74    regs = irq_combiner_get_regs(combiner);
75    gidx = GROUP_INDEX(cirq);
76    shift = GROUP_SHIFT(cirq) + IRQ_SHIFT(cirq);
77    if (v) {
78        regs->g[gidx].enable_set = BIT(shift);
79    } else {
80        regs->g[gidx].enable_clr = BIT(shift);
81    }
82    return 0;
83}
84
85static uint32_t
86exynos_irq_combiner_grp_pending(irq_combiner_t* combiner, int group)
87{
88    volatile struct irq_combiner_map* regs;
89    combiner_irq_t cirq;
90    int gidx, shift;
91    uint32_t v;
92    regs = irq_combiner_get_regs(combiner);
93    cirq = COMBINER_IRQ(group, 0);
94    gidx = GROUP_INDEX(cirq);
95    shift = GROUP_SHIFT(cirq);
96    v = regs->g[gidx].masked_status;
97    return (v >> shift) & GROUP_INDEX_MASK;
98}
99
100static int
101irq_combiner_init_common(irq_combiner_t* combiner)
102{
103    if (_combiner_regs == NULL) {
104        return -1;
105    } else {
106        /* Initialise the structure */
107        combiner->priv = (void*)_combiner_regs;
108        combiner->is_pending  = &exynos_irq_combiner_is_pending;
109        combiner->is_enabled  = &exynos_irq_combiner_is_enabled;
110        combiner->set_enabled = &exynos_irq_combiner_set_enabled;
111        combiner->grp_pending = &exynos_irq_combiner_grp_pending;
112        return 0;
113    }
114}
115
116int
117exynos_irq_combiner_init(void* base, irq_combiner_t* combiner)
118{
119    if (base) {
120        _combiner_regs = (volatile struct irq_combiner_map *)base;
121    }
122    return irq_combiner_init_common(combiner);
123}
124
125int
126irq_combiner_init(enum irq_combiner_id id, ps_io_ops_t* io_ops, irq_combiner_t* combiner)
127{
128    /* Map memory */
129    ZF_LOGD("Mapping device ID %d\n", id);
130    switch (id) {
131    case IRQ_COMBINER0:
132        MAP_IF_NULL(io_ops, EXYNOS_IRQ_COMBINER, _combiner_regs);
133        break;
134    default:
135        return -1;
136    }
137
138    return irq_combiner_init_common(combiner);
139}
140
141int
142irq_combiner_nirqs(enum irq_combiner_id id)
143{
144    switch (id) {
145    case IRQ_COMBINER0:
146        return 32;
147    default:
148        return -1;
149    }
150}
151
152int irq_combiner_irq(enum irq_combiner_id id, int group)
153{
154    switch (id) {
155    case IRQ_COMBINER0:
156        return group + 32;
157    default:
158        return -1;
159    }
160}
161