Statistics
| Branch: | Revision:

root / hw / exynos4210_combiner.c @ 37952117

History | View | Annotate | Download (15.1 kB)

1 8e03cf1e Evgeny Voevodin
/*
2 8e03cf1e Evgeny Voevodin
 * Samsung exynos4210 Interrupt Combiner
3 8e03cf1e Evgeny Voevodin
 *
4 8e03cf1e Evgeny Voevodin
 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
5 8e03cf1e Evgeny Voevodin
 * All rights reserved.
6 8e03cf1e Evgeny Voevodin
 *
7 8e03cf1e Evgeny Voevodin
 * Evgeny Voevodin <e.voevodin@samsung.com>
8 8e03cf1e Evgeny Voevodin
 *
9 8e03cf1e Evgeny Voevodin
 * This program is free software; you can redistribute it and/or modify it
10 8e03cf1e Evgeny Voevodin
 * under the terms of the GNU General Public License as published by the
11 8e03cf1e Evgeny Voevodin
 * Free Software Foundation; either version 2 of the License, or (at your
12 8e03cf1e Evgeny Voevodin
 * option) any later version.
13 8e03cf1e Evgeny Voevodin
 *
14 8e03cf1e Evgeny Voevodin
 * This program is distributed in the hope that it will be useful,
15 8e03cf1e Evgeny Voevodin
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 8e03cf1e Evgeny Voevodin
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 8e03cf1e Evgeny Voevodin
 * See the GNU General Public License for more details.
18 8e03cf1e Evgeny Voevodin
 *
19 8e03cf1e Evgeny Voevodin
 * You should have received a copy of the GNU General Public License along
20 8e03cf1e Evgeny Voevodin
 * with this program; if not, see <http://www.gnu.org/licenses/>.
21 8e03cf1e Evgeny Voevodin
 */
22 8e03cf1e Evgeny Voevodin
23 8e03cf1e Evgeny Voevodin
/*
24 8e03cf1e Evgeny Voevodin
 * Exynos4210 Combiner represents an OR gate for SOC's IRQ lines. It combines
25 8e03cf1e Evgeny Voevodin
 * IRQ sources into groups and provides signal output to GIC from each group. It
26 8e03cf1e Evgeny Voevodin
 * is driven by common mask and enable/disable logic. Take a note that not all
27 8e03cf1e Evgeny Voevodin
 * IRQs are passed to GIC through Combiner.
28 8e03cf1e Evgeny Voevodin
 */
29 8e03cf1e Evgeny Voevodin
30 8e03cf1e Evgeny Voevodin
#include "sysbus.h"
31 8e03cf1e Evgeny Voevodin
32 8e03cf1e Evgeny Voevodin
#include "exynos4210.h"
33 8e03cf1e Evgeny Voevodin
34 8e03cf1e Evgeny Voevodin
//#define DEBUG_COMBINER
35 8e03cf1e Evgeny Voevodin
36 8e03cf1e Evgeny Voevodin
#ifdef DEBUG_COMBINER
37 8e03cf1e Evgeny Voevodin
#define DPRINTF(fmt, ...) \
38 8e03cf1e Evgeny Voevodin
        do { fprintf(stdout, "COMBINER: [%s:%d] " fmt, __func__ , __LINE__, \
39 8e03cf1e Evgeny Voevodin
                ## __VA_ARGS__); } while (0)
40 8e03cf1e Evgeny Voevodin
#else
41 8e03cf1e Evgeny Voevodin
#define DPRINTF(fmt, ...) do {} while (0)
42 8e03cf1e Evgeny Voevodin
#endif
43 8e03cf1e Evgeny Voevodin
44 8e03cf1e Evgeny Voevodin
#define    IIC_NGRP        64            /* Internal Interrupt Combiner
45 8e03cf1e Evgeny Voevodin
                                            Groups number */
46 8e03cf1e Evgeny Voevodin
#define    IIC_NIRQ        (IIC_NGRP * 8)/* Internal Interrupt Combiner
47 8e03cf1e Evgeny Voevodin
                                            Interrupts number */
48 8e03cf1e Evgeny Voevodin
#define IIC_REGION_SIZE    0x108         /* Size of memory mapped region */
49 8e03cf1e Evgeny Voevodin
#define IIC_REGSET_SIZE    0x41
50 8e03cf1e Evgeny Voevodin
51 8e03cf1e Evgeny Voevodin
/*
52 8e03cf1e Evgeny Voevodin
 * State for each output signal of internal combiner
53 8e03cf1e Evgeny Voevodin
 */
54 8e03cf1e Evgeny Voevodin
typedef struct CombinerGroupState {
55 8e03cf1e Evgeny Voevodin
    uint8_t src_mask;            /* 1 - source enabled, 0 - disabled */
56 8e03cf1e Evgeny Voevodin
    uint8_t src_pending;        /* Pending source interrupts before masking */
57 8e03cf1e Evgeny Voevodin
} CombinerGroupState;
58 8e03cf1e Evgeny Voevodin
59 8e03cf1e Evgeny Voevodin
typedef struct Exynos4210CombinerState {
60 8e03cf1e Evgeny Voevodin
    SysBusDevice busdev;
61 8e03cf1e Evgeny Voevodin
    MemoryRegion iomem;
62 8e03cf1e Evgeny Voevodin
63 8e03cf1e Evgeny Voevodin
    struct CombinerGroupState group[IIC_NGRP];
64 8e03cf1e Evgeny Voevodin
    uint32_t reg_set[IIC_REGSET_SIZE];
65 8e03cf1e Evgeny Voevodin
    uint32_t icipsr[2];
66 8e03cf1e Evgeny Voevodin
    uint32_t external;          /* 1 means that this combiner is external */
67 8e03cf1e Evgeny Voevodin
68 8e03cf1e Evgeny Voevodin
    qemu_irq output_irq[IIC_NGRP];
69 8e03cf1e Evgeny Voevodin
} Exynos4210CombinerState;
70 8e03cf1e Evgeny Voevodin
71 8e03cf1e Evgeny Voevodin
static const VMStateDescription vmstate_exynos4210_combiner_group_state = {
72 8e03cf1e Evgeny Voevodin
    .name = "exynos4210.combiner.groupstate",
73 8e03cf1e Evgeny Voevodin
    .version_id = 1,
74 8e03cf1e Evgeny Voevodin
    .minimum_version_id = 1,
75 8e03cf1e Evgeny Voevodin
    .minimum_version_id_old = 1,
76 8e03cf1e Evgeny Voevodin
    .fields = (VMStateField[]) {
77 8e03cf1e Evgeny Voevodin
        VMSTATE_UINT8(src_mask, CombinerGroupState),
78 8e03cf1e Evgeny Voevodin
        VMSTATE_UINT8(src_pending, CombinerGroupState),
79 8e03cf1e Evgeny Voevodin
        VMSTATE_END_OF_LIST()
80 8e03cf1e Evgeny Voevodin
    }
81 8e03cf1e Evgeny Voevodin
};
82 8e03cf1e Evgeny Voevodin
83 8e03cf1e Evgeny Voevodin
static const VMStateDescription vmstate_exynos4210_combiner = {
84 8e03cf1e Evgeny Voevodin
    .name = "exynos4210.combiner",
85 8e03cf1e Evgeny Voevodin
    .version_id = 1,
86 8e03cf1e Evgeny Voevodin
    .minimum_version_id = 1,
87 8e03cf1e Evgeny Voevodin
    .minimum_version_id_old = 1,
88 8e03cf1e Evgeny Voevodin
    .fields = (VMStateField[]) {
89 8e03cf1e Evgeny Voevodin
        VMSTATE_STRUCT_ARRAY(group, Exynos4210CombinerState, IIC_NGRP, 0,
90 8e03cf1e Evgeny Voevodin
                vmstate_exynos4210_combiner_group_state, CombinerGroupState),
91 8e03cf1e Evgeny Voevodin
        VMSTATE_UINT32_ARRAY(reg_set, Exynos4210CombinerState,
92 8e03cf1e Evgeny Voevodin
                IIC_REGSET_SIZE),
93 8e03cf1e Evgeny Voevodin
        VMSTATE_UINT32_ARRAY(icipsr, Exynos4210CombinerState, 2),
94 8e03cf1e Evgeny Voevodin
        VMSTATE_UINT32(external, Exynos4210CombinerState),
95 8e03cf1e Evgeny Voevodin
        VMSTATE_END_OF_LIST()
96 8e03cf1e Evgeny Voevodin
    }
97 8e03cf1e Evgeny Voevodin
};
98 8e03cf1e Evgeny Voevodin
99 8e03cf1e Evgeny Voevodin
/*
100 8e03cf1e Evgeny Voevodin
 * Get Combiner input GPIO into irqs structure
101 8e03cf1e Evgeny Voevodin
 */
102 8e03cf1e Evgeny Voevodin
void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev,
103 8e03cf1e Evgeny Voevodin
        int ext)
104 8e03cf1e Evgeny Voevodin
{
105 8e03cf1e Evgeny Voevodin
    int n;
106 8e03cf1e Evgeny Voevodin
    int bit;
107 8e03cf1e Evgeny Voevodin
    int max;
108 8e03cf1e Evgeny Voevodin
    qemu_irq *irq;
109 8e03cf1e Evgeny Voevodin
110 8e03cf1e Evgeny Voevodin
    max = ext ? EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ :
111 8e03cf1e Evgeny Voevodin
        EXYNOS4210_MAX_INT_COMBINER_IN_IRQ;
112 8e03cf1e Evgeny Voevodin
    irq = ext ? irqs->ext_combiner_irq : irqs->int_combiner_irq;
113 8e03cf1e Evgeny Voevodin
114 8e03cf1e Evgeny Voevodin
    /*
115 8e03cf1e Evgeny Voevodin
     * Some IRQs of Int/External Combiner are going to two Combiners groups,
116 8e03cf1e Evgeny Voevodin
     * so let split them.
117 8e03cf1e Evgeny Voevodin
     */
118 8e03cf1e Evgeny Voevodin
    for (n = 0; n < max; n++) {
119 8e03cf1e Evgeny Voevodin
120 8e03cf1e Evgeny Voevodin
        bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
121 8e03cf1e Evgeny Voevodin
122 8e03cf1e Evgeny Voevodin
        switch (n) {
123 8e03cf1e Evgeny Voevodin
        /* MDNIE_LCD1 INTG1 */
124 8e03cf1e Evgeny Voevodin
        case EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 0) ...
125 8e03cf1e Evgeny Voevodin
             EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 3):
126 8e03cf1e Evgeny Voevodin
            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
127 8e03cf1e Evgeny Voevodin
                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(0, bit + 4)]);
128 8e03cf1e Evgeny Voevodin
            continue;
129 8e03cf1e Evgeny Voevodin
130 8e03cf1e Evgeny Voevodin
        /* TMU INTG3 */
131 8e03cf1e Evgeny Voevodin
        case EXYNOS4210_COMBINER_GET_IRQ_NUM(3, 4):
132 8e03cf1e Evgeny Voevodin
            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
133 8e03cf1e Evgeny Voevodin
                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(2, bit)]);
134 8e03cf1e Evgeny Voevodin
            continue;
135 8e03cf1e Evgeny Voevodin
136 8e03cf1e Evgeny Voevodin
        /* LCD1 INTG12 */
137 8e03cf1e Evgeny Voevodin
        case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 0) ...
138 8e03cf1e Evgeny Voevodin
             EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 3):
139 8e03cf1e Evgeny Voevodin
            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
140 8e03cf1e Evgeny Voevodin
                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(11, bit + 4)]);
141 8e03cf1e Evgeny Voevodin
            continue;
142 8e03cf1e Evgeny Voevodin
143 8e03cf1e Evgeny Voevodin
        /* Multi-Core Timer INTG12 */
144 8e03cf1e Evgeny Voevodin
        case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4) ...
145 8e03cf1e Evgeny Voevodin
             EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 8):
146 8e03cf1e Evgeny Voevodin
               irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
147 8e03cf1e Evgeny Voevodin
                       irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
148 8e03cf1e Evgeny Voevodin
            continue;
149 8e03cf1e Evgeny Voevodin
150 8e03cf1e Evgeny Voevodin
        /* Multi-Core Timer INTG35 */
151 8e03cf1e Evgeny Voevodin
        case EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 4) ...
152 8e03cf1e Evgeny Voevodin
             EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 8):
153 8e03cf1e Evgeny Voevodin
            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
154 8e03cf1e Evgeny Voevodin
                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
155 8e03cf1e Evgeny Voevodin
            continue;
156 8e03cf1e Evgeny Voevodin
157 8e03cf1e Evgeny Voevodin
        /* Multi-Core Timer INTG51 */
158 8e03cf1e Evgeny Voevodin
        case EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 4) ...
159 8e03cf1e Evgeny Voevodin
             EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 8):
160 8e03cf1e Evgeny Voevodin
            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
161 8e03cf1e Evgeny Voevodin
                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
162 8e03cf1e Evgeny Voevodin
            continue;
163 8e03cf1e Evgeny Voevodin
164 8e03cf1e Evgeny Voevodin
        /* Multi-Core Timer INTG53 */
165 8e03cf1e Evgeny Voevodin
        case EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 4) ...
166 8e03cf1e Evgeny Voevodin
             EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 8):
167 8e03cf1e Evgeny Voevodin
            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
168 8e03cf1e Evgeny Voevodin
                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
169 8e03cf1e Evgeny Voevodin
            continue;
170 8e03cf1e Evgeny Voevodin
        }
171 8e03cf1e Evgeny Voevodin
172 8e03cf1e Evgeny Voevodin
        irq[n] = qdev_get_gpio_in(dev, n);
173 8e03cf1e Evgeny Voevodin
    }
174 8e03cf1e Evgeny Voevodin
}
175 8e03cf1e Evgeny Voevodin
176 8e03cf1e Evgeny Voevodin
static uint64_t
177 8e03cf1e Evgeny Voevodin
exynos4210_combiner_read(void *opaque, target_phys_addr_t offset, unsigned size)
178 8e03cf1e Evgeny Voevodin
{
179 8e03cf1e Evgeny Voevodin
    struct Exynos4210CombinerState *s =
180 8e03cf1e Evgeny Voevodin
            (struct Exynos4210CombinerState *)opaque;
181 8e03cf1e Evgeny Voevodin
    uint32_t req_quad_base_n;    /* Base of registers quad. Multiply it by 4 and
182 8e03cf1e Evgeny Voevodin
                                   get a start of corresponding group quad */
183 8e03cf1e Evgeny Voevodin
    uint32_t grp_quad_base_n;    /* Base of group quad */
184 8e03cf1e Evgeny Voevodin
    uint32_t reg_n;              /* Register number inside the quad */
185 8e03cf1e Evgeny Voevodin
    uint32_t val;
186 8e03cf1e Evgeny Voevodin
187 8e03cf1e Evgeny Voevodin
    req_quad_base_n = offset >> 4;
188 8e03cf1e Evgeny Voevodin
    grp_quad_base_n = req_quad_base_n << 2;
189 8e03cf1e Evgeny Voevodin
    reg_n = (offset - (req_quad_base_n << 4)) >> 2;
190 8e03cf1e Evgeny Voevodin
191 8e03cf1e Evgeny Voevodin
    if (req_quad_base_n >= IIC_NGRP) {
192 8e03cf1e Evgeny Voevodin
        /* Read of ICIPSR register */
193 8e03cf1e Evgeny Voevodin
        return s->icipsr[reg_n];
194 8e03cf1e Evgeny Voevodin
    }
195 8e03cf1e Evgeny Voevodin
196 8e03cf1e Evgeny Voevodin
    val = 0;
197 8e03cf1e Evgeny Voevodin
198 8e03cf1e Evgeny Voevodin
    switch (reg_n) {
199 8e03cf1e Evgeny Voevodin
    /* IISTR */
200 8e03cf1e Evgeny Voevodin
    case 2:
201 8e03cf1e Evgeny Voevodin
        val |= s->group[grp_quad_base_n].src_pending;
202 8e03cf1e Evgeny Voevodin
        val |= s->group[grp_quad_base_n + 1].src_pending << 8;
203 8e03cf1e Evgeny Voevodin
        val |= s->group[grp_quad_base_n + 2].src_pending << 16;
204 8e03cf1e Evgeny Voevodin
        val |= s->group[grp_quad_base_n + 3].src_pending << 24;
205 8e03cf1e Evgeny Voevodin
        break;
206 8e03cf1e Evgeny Voevodin
    /* IIMSR */
207 8e03cf1e Evgeny Voevodin
    case 3:
208 8e03cf1e Evgeny Voevodin
        val |= s->group[grp_quad_base_n].src_mask &
209 8e03cf1e Evgeny Voevodin
        s->group[grp_quad_base_n].src_pending;
210 8e03cf1e Evgeny Voevodin
        val |= (s->group[grp_quad_base_n + 1].src_mask &
211 8e03cf1e Evgeny Voevodin
                s->group[grp_quad_base_n + 1].src_pending) << 8;
212 8e03cf1e Evgeny Voevodin
        val |= (s->group[grp_quad_base_n + 2].src_mask &
213 8e03cf1e Evgeny Voevodin
                s->group[grp_quad_base_n + 2].src_pending) << 16;
214 8e03cf1e Evgeny Voevodin
        val |= (s->group[grp_quad_base_n + 3].src_mask &
215 8e03cf1e Evgeny Voevodin
                s->group[grp_quad_base_n + 3].src_pending) << 24;
216 8e03cf1e Evgeny Voevodin
        break;
217 8e03cf1e Evgeny Voevodin
    default:
218 8e03cf1e Evgeny Voevodin
        if (offset >> 2 >= IIC_REGSET_SIZE) {
219 8e03cf1e Evgeny Voevodin
            hw_error("exynos4210.combiner: overflow of reg_set by 0x"
220 8e03cf1e Evgeny Voevodin
                    TARGET_FMT_plx "offset\n", offset);
221 8e03cf1e Evgeny Voevodin
        }
222 8e03cf1e Evgeny Voevodin
        val = s->reg_set[offset >> 2];
223 8e03cf1e Evgeny Voevodin
        return 0;
224 8e03cf1e Evgeny Voevodin
    }
225 8e03cf1e Evgeny Voevodin
    return val;
226 8e03cf1e Evgeny Voevodin
}
227 8e03cf1e Evgeny Voevodin
228 8e03cf1e Evgeny Voevodin
static void exynos4210_combiner_update(void *opaque, uint8_t group_n)
229 8e03cf1e Evgeny Voevodin
{
230 8e03cf1e Evgeny Voevodin
    struct Exynos4210CombinerState *s =
231 8e03cf1e Evgeny Voevodin
            (struct Exynos4210CombinerState *)opaque;
232 8e03cf1e Evgeny Voevodin
233 8e03cf1e Evgeny Voevodin
    /* Send interrupt if needed */
234 8e03cf1e Evgeny Voevodin
    if (s->group[group_n].src_mask & s->group[group_n].src_pending) {
235 8e03cf1e Evgeny Voevodin
#ifdef DEBUG_COMBINER
236 8e03cf1e Evgeny Voevodin
        if (group_n != 26) {
237 8e03cf1e Evgeny Voevodin
            /* skip uart */
238 8e03cf1e Evgeny Voevodin
            DPRINTF("%s raise IRQ[%d]\n", s->external ? "EXT" : "INT", group_n);
239 8e03cf1e Evgeny Voevodin
        }
240 8e03cf1e Evgeny Voevodin
#endif
241 8e03cf1e Evgeny Voevodin
242 8e03cf1e Evgeny Voevodin
        /* Set Combiner interrupt pending status after masking */
243 8e03cf1e Evgeny Voevodin
        if (group_n >= 32) {
244 8e03cf1e Evgeny Voevodin
            s->icipsr[1] |= 1 << (group_n - 32);
245 8e03cf1e Evgeny Voevodin
        } else {
246 8e03cf1e Evgeny Voevodin
            s->icipsr[0] |= 1 << group_n;
247 8e03cf1e Evgeny Voevodin
        }
248 8e03cf1e Evgeny Voevodin
249 8e03cf1e Evgeny Voevodin
        qemu_irq_raise(s->output_irq[group_n]);
250 8e03cf1e Evgeny Voevodin
    } else {
251 8e03cf1e Evgeny Voevodin
#ifdef DEBUG_COMBINER
252 8e03cf1e Evgeny Voevodin
        if (group_n != 26) {
253 8e03cf1e Evgeny Voevodin
            /* skip uart */
254 8e03cf1e Evgeny Voevodin
            DPRINTF("%s lower IRQ[%d]\n", s->external ? "EXT" : "INT", group_n);
255 8e03cf1e Evgeny Voevodin
        }
256 8e03cf1e Evgeny Voevodin
#endif
257 8e03cf1e Evgeny Voevodin
258 8e03cf1e Evgeny Voevodin
        /* Set Combiner interrupt pending status after masking */
259 8e03cf1e Evgeny Voevodin
        if (group_n >= 32) {
260 8e03cf1e Evgeny Voevodin
            s->icipsr[1] &= ~(1 << (group_n - 32));
261 8e03cf1e Evgeny Voevodin
        } else {
262 8e03cf1e Evgeny Voevodin
            s->icipsr[0] &= ~(1 << group_n);
263 8e03cf1e Evgeny Voevodin
        }
264 8e03cf1e Evgeny Voevodin
265 8e03cf1e Evgeny Voevodin
        qemu_irq_lower(s->output_irq[group_n]);
266 8e03cf1e Evgeny Voevodin
    }
267 8e03cf1e Evgeny Voevodin
}
268 8e03cf1e Evgeny Voevodin
269 8e03cf1e Evgeny Voevodin
static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset,
270 8e03cf1e Evgeny Voevodin
        uint64_t val, unsigned size)
271 8e03cf1e Evgeny Voevodin
{
272 8e03cf1e Evgeny Voevodin
    struct Exynos4210CombinerState *s =
273 8e03cf1e Evgeny Voevodin
            (struct Exynos4210CombinerState *)opaque;
274 8e03cf1e Evgeny Voevodin
    uint32_t req_quad_base_n;    /* Base of registers quad. Multiply it by 4 and
275 8e03cf1e Evgeny Voevodin
                                   get a start of corresponding group quad */
276 8e03cf1e Evgeny Voevodin
    uint32_t grp_quad_base_n;    /* Base of group quad */
277 8e03cf1e Evgeny Voevodin
    uint32_t reg_n;              /* Register number inside the quad */
278 8e03cf1e Evgeny Voevodin
279 8e03cf1e Evgeny Voevodin
    req_quad_base_n = offset >> 4;
280 8e03cf1e Evgeny Voevodin
    grp_quad_base_n = req_quad_base_n << 2;
281 8e03cf1e Evgeny Voevodin
    reg_n = (offset - (req_quad_base_n << 4)) >> 2;
282 8e03cf1e Evgeny Voevodin
283 8e03cf1e Evgeny Voevodin
    if (req_quad_base_n >= IIC_NGRP) {
284 8e03cf1e Evgeny Voevodin
        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
285 8e03cf1e Evgeny Voevodin
                TARGET_FMT_plx "\n", offset);
286 8e03cf1e Evgeny Voevodin
        return;
287 8e03cf1e Evgeny Voevodin
    }
288 8e03cf1e Evgeny Voevodin
289 8e03cf1e Evgeny Voevodin
    if (reg_n > 1) {
290 8e03cf1e Evgeny Voevodin
        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
291 8e03cf1e Evgeny Voevodin
                TARGET_FMT_plx "\n", offset);
292 8e03cf1e Evgeny Voevodin
        return;
293 8e03cf1e Evgeny Voevodin
    }
294 8e03cf1e Evgeny Voevodin
295 8e03cf1e Evgeny Voevodin
    if (offset >> 2 >= IIC_REGSET_SIZE) {
296 8e03cf1e Evgeny Voevodin
        hw_error("exynos4210.combiner: overflow of reg_set by 0x"
297 8e03cf1e Evgeny Voevodin
                TARGET_FMT_plx "offset\n", offset);
298 8e03cf1e Evgeny Voevodin
    }
299 8e03cf1e Evgeny Voevodin
    s->reg_set[offset >> 2] = val;
300 8e03cf1e Evgeny Voevodin
301 8e03cf1e Evgeny Voevodin
    switch (reg_n) {
302 8e03cf1e Evgeny Voevodin
    /* IIESR */
303 8e03cf1e Evgeny Voevodin
    case 0:
304 8e03cf1e Evgeny Voevodin
        /* FIXME: what if irq is pending, allowed by mask, and we allow it
305 8e03cf1e Evgeny Voevodin
         * again. Interrupt will rise again! */
306 8e03cf1e Evgeny Voevodin
307 8e03cf1e Evgeny Voevodin
        DPRINTF("%s enable IRQ for groups %d, %d, %d, %d\n",
308 8e03cf1e Evgeny Voevodin
                s->external ? "EXT" : "INT",
309 8e03cf1e Evgeny Voevodin
                grp_quad_base_n,
310 8e03cf1e Evgeny Voevodin
                grp_quad_base_n + 1,
311 8e03cf1e Evgeny Voevodin
                grp_quad_base_n + 2,
312 8e03cf1e Evgeny Voevodin
                grp_quad_base_n + 3);
313 8e03cf1e Evgeny Voevodin
314 8e03cf1e Evgeny Voevodin
        /* Enable interrupt sources */
315 8e03cf1e Evgeny Voevodin
        s->group[grp_quad_base_n].src_mask |= val & 0xFF;
316 8e03cf1e Evgeny Voevodin
        s->group[grp_quad_base_n + 1].src_mask |= (val & 0xFF00) >> 8;
317 8e03cf1e Evgeny Voevodin
        s->group[grp_quad_base_n + 2].src_mask |= (val & 0xFF0000) >> 16;
318 8e03cf1e Evgeny Voevodin
        s->group[grp_quad_base_n + 3].src_mask |= (val & 0xFF000000) >> 24;
319 8e03cf1e Evgeny Voevodin
320 8e03cf1e Evgeny Voevodin
        exynos4210_combiner_update(s, grp_quad_base_n);
321 8e03cf1e Evgeny Voevodin
        exynos4210_combiner_update(s, grp_quad_base_n + 1);
322 8e03cf1e Evgeny Voevodin
        exynos4210_combiner_update(s, grp_quad_base_n + 2);
323 8e03cf1e Evgeny Voevodin
        exynos4210_combiner_update(s, grp_quad_base_n + 3);
324 8e03cf1e Evgeny Voevodin
        break;
325 8e03cf1e Evgeny Voevodin
        /* IIECR */
326 8e03cf1e Evgeny Voevodin
    case 1:
327 8e03cf1e Evgeny Voevodin
        DPRINTF("%s disable IRQ for groups %d, %d, %d, %d\n",
328 8e03cf1e Evgeny Voevodin
                s->external ? "EXT" : "INT",
329 8e03cf1e Evgeny Voevodin
                grp_quad_base_n,
330 8e03cf1e Evgeny Voevodin
                grp_quad_base_n + 1,
331 8e03cf1e Evgeny Voevodin
                grp_quad_base_n + 2,
332 8e03cf1e Evgeny Voevodin
                grp_quad_base_n + 3);
333 8e03cf1e Evgeny Voevodin
334 8e03cf1e Evgeny Voevodin
        /* Disable interrupt sources */
335 8e03cf1e Evgeny Voevodin
        s->group[grp_quad_base_n].src_mask &= ~(val & 0xFF);
336 8e03cf1e Evgeny Voevodin
        s->group[grp_quad_base_n + 1].src_mask &= ~((val & 0xFF00) >> 8);
337 8e03cf1e Evgeny Voevodin
        s->group[grp_quad_base_n + 2].src_mask &= ~((val & 0xFF0000) >> 16);
338 8e03cf1e Evgeny Voevodin
        s->group[grp_quad_base_n + 3].src_mask &= ~((val & 0xFF000000) >> 24);
339 8e03cf1e Evgeny Voevodin
340 8e03cf1e Evgeny Voevodin
        exynos4210_combiner_update(s, grp_quad_base_n);
341 8e03cf1e Evgeny Voevodin
        exynos4210_combiner_update(s, grp_quad_base_n + 1);
342 8e03cf1e Evgeny Voevodin
        exynos4210_combiner_update(s, grp_quad_base_n + 2);
343 8e03cf1e Evgeny Voevodin
        exynos4210_combiner_update(s, grp_quad_base_n + 3);
344 8e03cf1e Evgeny Voevodin
        break;
345 8e03cf1e Evgeny Voevodin
    default:
346 8e03cf1e Evgeny Voevodin
        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
347 8e03cf1e Evgeny Voevodin
                TARGET_FMT_plx "\n", offset);
348 8e03cf1e Evgeny Voevodin
        break;
349 8e03cf1e Evgeny Voevodin
    }
350 8e03cf1e Evgeny Voevodin
351 8e03cf1e Evgeny Voevodin
    return;
352 8e03cf1e Evgeny Voevodin
}
353 8e03cf1e Evgeny Voevodin
354 8e03cf1e Evgeny Voevodin
/* Get combiner group and bit from irq number */
355 8e03cf1e Evgeny Voevodin
static uint8_t get_combiner_group_and_bit(int irq, uint8_t *bit)
356 8e03cf1e Evgeny Voevodin
{
357 8e03cf1e Evgeny Voevodin
    *bit = irq - ((irq >> 3) << 3);
358 8e03cf1e Evgeny Voevodin
    return irq >> 3;
359 8e03cf1e Evgeny Voevodin
}
360 8e03cf1e Evgeny Voevodin
361 8e03cf1e Evgeny Voevodin
/* Process a change in an external IRQ input.  */
362 8e03cf1e Evgeny Voevodin
static void exynos4210_combiner_handler(void *opaque, int irq, int level)
363 8e03cf1e Evgeny Voevodin
{
364 8e03cf1e Evgeny Voevodin
    struct Exynos4210CombinerState *s =
365 8e03cf1e Evgeny Voevodin
            (struct Exynos4210CombinerState *)opaque;
366 8e03cf1e Evgeny Voevodin
    uint8_t bit_n, group_n;
367 8e03cf1e Evgeny Voevodin
368 8e03cf1e Evgeny Voevodin
    group_n = get_combiner_group_and_bit(irq, &bit_n);
369 8e03cf1e Evgeny Voevodin
370 8e03cf1e Evgeny Voevodin
    if (s->external && group_n >= EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ) {
371 8e03cf1e Evgeny Voevodin
        DPRINTF("%s unallowed IRQ group 0x%x\n", s->external ? "EXT" : "INT"
372 8e03cf1e Evgeny Voevodin
                , group_n);
373 8e03cf1e Evgeny Voevodin
        return;
374 8e03cf1e Evgeny Voevodin
    }
375 8e03cf1e Evgeny Voevodin
376 8e03cf1e Evgeny Voevodin
    if (level) {
377 8e03cf1e Evgeny Voevodin
        s->group[group_n].src_pending |= 1 << bit_n;
378 8e03cf1e Evgeny Voevodin
    } else {
379 8e03cf1e Evgeny Voevodin
        s->group[group_n].src_pending &= ~(1 << bit_n);
380 8e03cf1e Evgeny Voevodin
    }
381 8e03cf1e Evgeny Voevodin
382 8e03cf1e Evgeny Voevodin
    exynos4210_combiner_update(s, group_n);
383 8e03cf1e Evgeny Voevodin
384 8e03cf1e Evgeny Voevodin
    return;
385 8e03cf1e Evgeny Voevodin
}
386 8e03cf1e Evgeny Voevodin
387 8e03cf1e Evgeny Voevodin
static void exynos4210_combiner_reset(DeviceState *d)
388 8e03cf1e Evgeny Voevodin
{
389 8e03cf1e Evgeny Voevodin
    struct Exynos4210CombinerState *s = (struct Exynos4210CombinerState *)d;
390 8e03cf1e Evgeny Voevodin
391 8e03cf1e Evgeny Voevodin
    memset(&s->group, 0, sizeof(s->group));
392 8e03cf1e Evgeny Voevodin
    memset(&s->reg_set, 0, sizeof(s->reg_set));
393 8e03cf1e Evgeny Voevodin
394 8e03cf1e Evgeny Voevodin
    s->reg_set[0xC0 >> 2] = 0x01010101;
395 8e03cf1e Evgeny Voevodin
    s->reg_set[0xC4 >> 2] = 0x01010101;
396 8e03cf1e Evgeny Voevodin
    s->reg_set[0xD0 >> 2] = 0x01010101;
397 8e03cf1e Evgeny Voevodin
    s->reg_set[0xD4 >> 2] = 0x01010101;
398 8e03cf1e Evgeny Voevodin
}
399 8e03cf1e Evgeny Voevodin
400 8e03cf1e Evgeny Voevodin
static const MemoryRegionOps exynos4210_combiner_ops = {
401 8e03cf1e Evgeny Voevodin
    .read = exynos4210_combiner_read,
402 8e03cf1e Evgeny Voevodin
    .write = exynos4210_combiner_write,
403 8e03cf1e Evgeny Voevodin
    .endianness = DEVICE_NATIVE_ENDIAN,
404 8e03cf1e Evgeny Voevodin
};
405 8e03cf1e Evgeny Voevodin
406 8e03cf1e Evgeny Voevodin
/*
407 8e03cf1e Evgeny Voevodin
 * Internal Combiner initialization.
408 8e03cf1e Evgeny Voevodin
 */
409 8e03cf1e Evgeny Voevodin
static int exynos4210_combiner_init(SysBusDevice *dev)
410 8e03cf1e Evgeny Voevodin
{
411 8e03cf1e Evgeny Voevodin
    unsigned int i;
412 8e03cf1e Evgeny Voevodin
    struct Exynos4210CombinerState *s =
413 8e03cf1e Evgeny Voevodin
            FROM_SYSBUS(struct Exynos4210CombinerState, dev);
414 8e03cf1e Evgeny Voevodin
415 8e03cf1e Evgeny Voevodin
    /* Allocate general purpose input signals and connect a handler to each of
416 8e03cf1e Evgeny Voevodin
     * them */
417 8e03cf1e Evgeny Voevodin
    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_combiner_handler, IIC_NIRQ);
418 8e03cf1e Evgeny Voevodin
419 8e03cf1e Evgeny Voevodin
    /* Connect SysBusDev irqs to device specific irqs */
420 8e03cf1e Evgeny Voevodin
    for (i = 0; i < IIC_NIRQ; i++) {
421 8e03cf1e Evgeny Voevodin
        sysbus_init_irq(dev, &s->output_irq[i]);
422 8e03cf1e Evgeny Voevodin
    }
423 8e03cf1e Evgeny Voevodin
424 8e03cf1e Evgeny Voevodin
    memory_region_init_io(&s->iomem, &exynos4210_combiner_ops, s,
425 8e03cf1e Evgeny Voevodin
            "exynos4210-combiner", IIC_REGION_SIZE);
426 8e03cf1e Evgeny Voevodin
    sysbus_init_mmio(dev, &s->iomem);
427 8e03cf1e Evgeny Voevodin
428 8e03cf1e Evgeny Voevodin
    return 0;
429 8e03cf1e Evgeny Voevodin
}
430 8e03cf1e Evgeny Voevodin
431 8e03cf1e Evgeny Voevodin
static Property exynos4210_combiner_properties[] = {
432 8e03cf1e Evgeny Voevodin
    DEFINE_PROP_UINT32("external", Exynos4210CombinerState, external, 0),
433 8e03cf1e Evgeny Voevodin
    DEFINE_PROP_END_OF_LIST(),
434 8e03cf1e Evgeny Voevodin
};
435 8e03cf1e Evgeny Voevodin
436 8e03cf1e Evgeny Voevodin
static void exynos4210_combiner_class_init(ObjectClass *klass, void *data)
437 8e03cf1e Evgeny Voevodin
{
438 8e03cf1e Evgeny Voevodin
    DeviceClass *dc = DEVICE_CLASS(klass);
439 8e03cf1e Evgeny Voevodin
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
440 8e03cf1e Evgeny Voevodin
441 8e03cf1e Evgeny Voevodin
    k->init = exynos4210_combiner_init;
442 8e03cf1e Evgeny Voevodin
    dc->reset = exynos4210_combiner_reset;
443 8e03cf1e Evgeny Voevodin
    dc->props = exynos4210_combiner_properties;
444 8e03cf1e Evgeny Voevodin
    dc->vmsd = &vmstate_exynos4210_combiner;
445 8e03cf1e Evgeny Voevodin
}
446 8e03cf1e Evgeny Voevodin
447 8e03cf1e Evgeny Voevodin
static TypeInfo exynos4210_combiner_info = {
448 8e03cf1e Evgeny Voevodin
    .name          = "exynos4210.combiner",
449 8e03cf1e Evgeny Voevodin
    .parent        = TYPE_SYS_BUS_DEVICE,
450 8e03cf1e Evgeny Voevodin
    .instance_size = sizeof(Exynos4210CombinerState),
451 8e03cf1e Evgeny Voevodin
    .class_init    = exynos4210_combiner_class_init,
452 8e03cf1e Evgeny Voevodin
};
453 8e03cf1e Evgeny Voevodin
454 8e03cf1e Evgeny Voevodin
static void exynos4210_combiner_register_types(void)
455 8e03cf1e Evgeny Voevodin
{
456 8e03cf1e Evgeny Voevodin
    type_register_static(&exynos4210_combiner_info);
457 8e03cf1e Evgeny Voevodin
}
458 8e03cf1e Evgeny Voevodin
459 8e03cf1e Evgeny Voevodin
type_init(exynos4210_combiner_register_types)