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"
28 #include "hw/qdev-properties.h"
29 #include "migration/vmstate.h"
47 # define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
49 # define LOG_UIC(...) do { } while (0)
52 static void ppcuic_trigger_irq(PPCUIC
*uic
)
55 int start
, end
, inc
, i
;
57 /* Trigger interrupt if any is pending */
58 ir
= uic
->uicsr
& uic
->uicer
& (~uic
->uiccr
);
59 cr
= uic
->uicsr
& uic
->uicer
& uic
->uiccr
;
60 LOG_UIC("%s: uicsr %08" PRIx32
" uicer %08" PRIx32
61 " uiccr %08" PRIx32
"\n"
62 " %08" PRIx32
" ir %08" PRIx32
" cr %08" PRIx32
"\n",
63 __func__
, uic
->uicsr
, uic
->uicer
, uic
->uiccr
,
64 uic
->uicsr
& uic
->uicer
, ir
, cr
);
65 if (ir
!= 0x0000000) {
66 LOG_UIC("Raise UIC interrupt\n");
67 qemu_irq_raise(uic
->output_int
);
69 LOG_UIC("Lower UIC interrupt\n");
70 qemu_irq_lower(uic
->output_int
);
72 /* Trigger critical interrupt if any is pending and update vector */
73 if (cr
!= 0x0000000) {
74 qemu_irq_raise(uic
->output_cint
);
75 if (uic
->use_vectors
) {
76 /* Compute critical IRQ vector */
77 if (uic
->uicvcr
& 1) {
86 uic
->uicvr
= uic
->uicvcr
& 0xFFFFFFFC;
87 for (i
= start
; i
<= end
; i
+= inc
) {
89 uic
->uicvr
+= (i
- start
) * 512 * inc
;
94 LOG_UIC("Raise UIC critical interrupt - "
95 "vector %08" PRIx32
"\n", uic
->uicvr
);
97 LOG_UIC("Lower UIC critical interrupt\n");
98 qemu_irq_lower(uic
->output_cint
);
99 uic
->uicvr
= 0x00000000;
103 static void ppcuic_set_irq(void *opaque
, int irq_num
, int level
)
105 PPCUIC
*uic
= opaque
;
108 mask
= 1U << (31 - irq_num
);
109 LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
110 " mask %08" PRIx32
" => %08" PRIx32
" %08" PRIx32
"\n",
111 __func__
, irq_num
, level
,
112 uic
->uicsr
, mask
, uic
->uicsr
& mask
, level
<< irq_num
);
113 if (irq_num
< 0 || irq_num
> 31) {
118 /* Update status register */
119 if (uic
->uictr
& mask
) {
120 /* Edge sensitive interrupt */
125 /* Level sensitive interrupt */
134 LOG_UIC("%s: irq %d level %d sr %" PRIx32
" => "
135 "%08" PRIx32
"\n", __func__
, irq_num
, level
, uic
->uicsr
, sr
);
136 if (sr
!= uic
->uicsr
) {
137 ppcuic_trigger_irq(uic
);
141 static uint32_t dcr_read_uic(void *opaque
, int dcrn
)
143 PPCUIC
*uic
= opaque
;
146 dcrn
-= uic
->dcr_base
;
165 ret
= uic
->uicsr
& uic
->uicer
;
168 if (!uic
->use_vectors
) {
174 if (!uic
->use_vectors
) {
188 static void dcr_write_uic(void *opaque
, int dcrn
, uint32_t val
)
190 PPCUIC
*uic
= opaque
;
192 dcrn
-= uic
->dcr_base
;
193 LOG_UIC("%s: dcr %d val 0x%x\n", __func__
, dcrn
, val
);
197 uic
->uicsr
|= uic
->level
;
198 ppcuic_trigger_irq(uic
);
202 ppcuic_trigger_irq(uic
);
206 ppcuic_trigger_irq(uic
);
210 ppcuic_trigger_irq(uic
);
217 ppcuic_trigger_irq(uic
);
224 uic
->uicvcr
= val
& 0xFFFFFFFD;
225 ppcuic_trigger_irq(uic
);
230 static void ppc_uic_reset(DeviceState
*dev
)
232 PPCUIC
*uic
= PPC_UIC(dev
);
234 uic
->uiccr
= 0x00000000;
235 uic
->uicer
= 0x00000000;
236 uic
->uicpr
= 0x00000000;
237 uic
->uicsr
= 0x00000000;
238 uic
->uictr
= 0x00000000;
239 if (uic
->use_vectors
) {
240 uic
->uicvcr
= 0x00000000;
241 uic
->uicvr
= 0x0000000;
245 static void ppc_uic_realize(DeviceState
*dev
, Error
**errp
)
247 PPCUIC
*uic
= PPC_UIC(dev
);
248 Ppc4xxDcrDeviceState
*dcr
= PPC4xx_DCR_DEVICE(dev
);
249 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
252 for (i
= 0; i
< DCR_UICMAX
; i
++) {
253 ppc4xx_dcr_register(dcr
, uic
->dcr_base
+ i
, uic
,
254 &dcr_read_uic
, &dcr_write_uic
);
257 sysbus_init_irq(sbd
, &uic
->output_int
);
258 sysbus_init_irq(sbd
, &uic
->output_cint
);
259 qdev_init_gpio_in(dev
, ppcuic_set_irq
, UIC_MAX_IRQ
);
262 static Property ppc_uic_properties
[] = {
263 DEFINE_PROP_UINT32("dcr-base", PPCUIC
, dcr_base
, 0xc0),
264 DEFINE_PROP_BOOL("use-vectors", PPCUIC
, use_vectors
, true),
265 DEFINE_PROP_END_OF_LIST()
268 static const VMStateDescription ppc_uic_vmstate
= {
271 .minimum_version_id
= 1,
272 .fields
= (VMStateField
[]) {
273 VMSTATE_UINT32(level
, PPCUIC
),
274 VMSTATE_UINT32(uicsr
, PPCUIC
),
275 VMSTATE_UINT32(uicer
, PPCUIC
),
276 VMSTATE_UINT32(uiccr
, PPCUIC
),
277 VMSTATE_UINT32(uicpr
, PPCUIC
),
278 VMSTATE_UINT32(uictr
, PPCUIC
),
279 VMSTATE_UINT32(uicvcr
, PPCUIC
),
280 VMSTATE_UINT32(uicvr
, PPCUIC
),
281 VMSTATE_END_OF_LIST()
285 static void ppc_uic_class_init(ObjectClass
*klass
, void *data
)
287 DeviceClass
*dc
= DEVICE_CLASS(klass
);
289 dc
->reset
= ppc_uic_reset
;
290 dc
->realize
= ppc_uic_realize
;
291 dc
->vmsd
= &ppc_uic_vmstate
;
292 device_class_set_props(dc
, ppc_uic_properties
);
295 static const TypeInfo ppc_uic_info
= {
296 .name
= TYPE_PPC_UIC
,
297 .parent
= TYPE_PPC4xx_DCR_DEVICE
,
298 .instance_size
= sizeof(PPCUIC
),
299 .class_init
= ppc_uic_class_init
,
302 static void ppc_uic_register_types(void)
304 type_register_static(&ppc_uic_info
);
307 type_init(ppc_uic_register_types
);