2 * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
4 * Copyright (c) 2007 Jocelyn Mayer
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include "qemu/osdep.h"
26 #include "hw/intc/ppc-uic.h"
29 #include "hw/ppc/ppc.h"
30 #include "hw/qdev-properties.h"
31 #include "migration/vmstate.h"
32 #include "qapi/error.h"
50 # define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
52 # define LOG_UIC(...) do { } while (0)
55 static void ppcuic_trigger_irq(PPCUIC
*uic
)
58 int start
, end
, inc
, i
;
60 /* Trigger interrupt if any is pending */
61 ir
= uic
->uicsr
& uic
->uicer
& (~uic
->uiccr
);
62 cr
= uic
->uicsr
& uic
->uicer
& uic
->uiccr
;
63 LOG_UIC("%s: uicsr %08" PRIx32
" uicer %08" PRIx32
64 " uiccr %08" PRIx32
"\n"
65 " %08" PRIx32
" ir %08" PRIx32
" cr %08" PRIx32
"\n",
66 __func__
, uic
->uicsr
, uic
->uicer
, uic
->uiccr
,
67 uic
->uicsr
& uic
->uicer
, ir
, cr
);
68 if (ir
!= 0x0000000) {
69 LOG_UIC("Raise UIC interrupt\n");
70 qemu_irq_raise(uic
->output_int
);
72 LOG_UIC("Lower UIC interrupt\n");
73 qemu_irq_lower(uic
->output_int
);
75 /* Trigger critical interrupt if any is pending and update vector */
76 if (cr
!= 0x0000000) {
77 qemu_irq_raise(uic
->output_cint
);
78 if (uic
->use_vectors
) {
79 /* Compute critical IRQ vector */
80 if (uic
->uicvcr
& 1) {
89 uic
->uicvr
= uic
->uicvcr
& 0xFFFFFFFC;
90 for (i
= start
; i
<= end
; i
+= inc
) {
92 uic
->uicvr
+= (i
- start
) * 512 * inc
;
97 LOG_UIC("Raise UIC critical interrupt - "
98 "vector %08" PRIx32
"\n", uic
->uicvr
);
100 LOG_UIC("Lower UIC critical interrupt\n");
101 qemu_irq_lower(uic
->output_cint
);
102 uic
->uicvr
= 0x00000000;
106 static void ppcuic_set_irq(void *opaque
, int irq_num
, int level
)
112 mask
= 1U << (31 - irq_num
);
113 LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
114 " mask %08" PRIx32
" => %08" PRIx32
" %08" PRIx32
"\n",
115 __func__
, irq_num
, level
,
116 uic
->uicsr
, mask
, uic
->uicsr
& mask
, level
<< irq_num
);
117 if (irq_num
< 0 || irq_num
> 31) {
122 /* Update status register */
123 if (uic
->uictr
& mask
) {
124 /* Edge sensitive interrupt */
129 /* Level sensitive interrupt */
138 LOG_UIC("%s: irq %d level %d sr %" PRIx32
" => "
139 "%08" PRIx32
"\n", __func__
, irq_num
, level
, uic
->uicsr
, sr
);
140 if (sr
!= uic
->uicsr
) {
141 ppcuic_trigger_irq(uic
);
145 static uint32_t dcr_read_uic(void *opaque
, int dcrn
)
151 dcrn
-= uic
->dcr_base
;
170 ret
= uic
->uicsr
& uic
->uicer
;
173 if (!uic
->use_vectors
) {
179 if (!uic
->use_vectors
) {
193 static void dcr_write_uic(void *opaque
, int dcrn
, uint32_t val
)
198 dcrn
-= uic
->dcr_base
;
199 LOG_UIC("%s: dcr %d val 0x%x\n", __func__
, dcrn
, val
);
203 uic
->uicsr
|= uic
->level
;
204 ppcuic_trigger_irq(uic
);
208 ppcuic_trigger_irq(uic
);
212 ppcuic_trigger_irq(uic
);
216 ppcuic_trigger_irq(uic
);
223 ppcuic_trigger_irq(uic
);
230 uic
->uicvcr
= val
& 0xFFFFFFFD;
231 ppcuic_trigger_irq(uic
);
236 static void ppc_uic_reset(DeviceState
*dev
)
238 PPCUIC
*uic
= PPC_UIC(dev
);
240 uic
->uiccr
= 0x00000000;
241 uic
->uicer
= 0x00000000;
242 uic
->uicpr
= 0x00000000;
243 uic
->uicsr
= 0x00000000;
244 uic
->uictr
= 0x00000000;
245 if (uic
->use_vectors
) {
246 uic
->uicvcr
= 0x00000000;
247 uic
->uicvr
= 0x0000000;
251 static void ppc_uic_realize(DeviceState
*dev
, Error
**errp
)
253 PPCUIC
*uic
= PPC_UIC(dev
);
254 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
259 /* This is a programming error in the code using this device */
260 error_setg(errp
, "ppc-uic 'cpu' link property was not set");
264 cpu
= POWERPC_CPU(uic
->cpu
);
265 for (i
= 0; i
< DCR_UICMAX
; i
++) {
266 ppc_dcr_register(&cpu
->env
, uic
->dcr_base
+ i
, uic
,
267 &dcr_read_uic
, &dcr_write_uic
);
270 sysbus_init_irq(sbd
, &uic
->output_int
);
271 sysbus_init_irq(sbd
, &uic
->output_cint
);
272 qdev_init_gpio_in(dev
, ppcuic_set_irq
, UIC_MAX_IRQ
);
275 static Property ppc_uic_properties
[] = {
276 DEFINE_PROP_LINK("cpu", PPCUIC
, cpu
, TYPE_CPU
, CPUState
*),
277 DEFINE_PROP_UINT32("dcr-base", PPCUIC
, dcr_base
, 0xc0),
278 DEFINE_PROP_BOOL("use-vectors", PPCUIC
, use_vectors
, true),
279 DEFINE_PROP_END_OF_LIST()
282 static const VMStateDescription ppc_uic_vmstate
= {
285 .minimum_version_id
= 1,
286 .fields
= (VMStateField
[]) {
287 VMSTATE_UINT32(level
, PPCUIC
),
288 VMSTATE_UINT32(uicsr
, PPCUIC
),
289 VMSTATE_UINT32(uicer
, PPCUIC
),
290 VMSTATE_UINT32(uiccr
, PPCUIC
),
291 VMSTATE_UINT32(uicpr
, PPCUIC
),
292 VMSTATE_UINT32(uictr
, PPCUIC
),
293 VMSTATE_UINT32(uicvcr
, PPCUIC
),
294 VMSTATE_UINT32(uicvr
, PPCUIC
),
295 VMSTATE_END_OF_LIST()
299 static void ppc_uic_class_init(ObjectClass
*klass
, void *data
)
301 DeviceClass
*dc
= DEVICE_CLASS(klass
);
303 dc
->reset
= ppc_uic_reset
;
304 dc
->realize
= ppc_uic_realize
;
305 dc
->vmsd
= &ppc_uic_vmstate
;
306 device_class_set_props(dc
, ppc_uic_properties
);
309 static const TypeInfo ppc_uic_info
= {
310 .name
= TYPE_PPC_UIC
,
311 .parent
= TYPE_SYS_BUS_DEVICE
,
312 .instance_size
= sizeof(PPCUIC
),
313 .class_init
= ppc_uic_class_init
,
316 static void ppc_uic_register_types(void)
318 type_register_static(&ppc_uic_info
);
321 type_init(ppc_uic_register_types
);