]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/intc/openpic.c
Include hw/qdev-properties.h less
[thirdparty/qemu.git] / hw / intc / openpic.c
CommitLineData
dbda808a
FB
1/*
2 * OpenPIC emulation
5fafdf24 3 *
dbda808a 4 * Copyright (c) 2004 Jocelyn Mayer
704c7e5d 5 * 2011 Alexander Graf
5fafdf24 6 *
dbda808a
FB
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25/*
26 *
27 * Based on OpenPic implementations:
67b55785 28 * - Intel GW80314 I/O companion chip developer's manual
dbda808a
FB
29 * - Motorola MPC8245 & MPC8540 user manuals.
30 * - Motorola MCP750 (aka Raven) programmer manual.
31 * - Motorola Harrier programmer manuel
32 *
33 * Serial interrupts, as implemented in Raven chipset are not supported yet.
5fafdf24 34 *
dbda808a 35 */
0b8fa32f 36
90191d07 37#include "qemu/osdep.h"
64552b6b 38#include "hw/irq.h"
83c9f4ca
PB
39#include "hw/ppc/mac.h"
40#include "hw/pci/pci.h"
0d09e41a 41#include "hw/ppc/openpic.h"
2b927571 42#include "hw/ppc/ppc_e500.h"
a27bd6c7 43#include "hw/qdev-properties.h"
83c9f4ca 44#include "hw/sysbus.h"
d6454270 45#include "migration/vmstate.h"
83c9f4ca 46#include "hw/pci/msi.h"
da34e65c 47#include "qapi/error.h"
e69a17f6 48#include "qemu/bitops.h"
73d963c0 49#include "qapi/qmp/qerror.h"
03dd024f 50#include "qemu/log.h"
0b8fa32f 51#include "qemu/module.h"
ddd5140b 52#include "qemu/timer.h"
df592270 53#include "qemu/error-report.h"
dbda808a 54
611493d9 55//#define DEBUG_OPENPIC
dbda808a
FB
56
57#ifdef DEBUG_OPENPIC
4c4f0e48 58static const int debug_openpic = 1;
dbda808a 59#else
4c4f0e48 60static const int debug_openpic = 0;
dbda808a 61#endif
dbda808a 62
ddd5140b 63static int get_current_cpu(void);
4c4f0e48
SW
64#define DPRINTF(fmt, ...) do { \
65 if (debug_openpic) { \
df592270 66 info_report("Core%d: " fmt, get_current_cpu(), ## __VA_ARGS__); \
4c4f0e48
SW
67 } \
68 } while (0)
69
d0b72631 70/* OpenPIC capability flags */
be7c236f 71#define OPENPIC_FLAG_IDR_CRIT (1 << 0)
e0dfe5b1 72#define OPENPIC_FLAG_ILR (2 << 0)
dbda808a 73
d0b72631 74/* OpenPIC address map */
780d16b7
AG
75#define OPENPIC_GLB_REG_START 0x0
76#define OPENPIC_GLB_REG_SIZE 0x10F0
77#define OPENPIC_TMR_REG_START 0x10F0
78#define OPENPIC_TMR_REG_SIZE 0x220
732aa6ec
AG
79#define OPENPIC_MSI_REG_START 0x1600
80#define OPENPIC_MSI_REG_SIZE 0x200
e0dfe5b1
SW
81#define OPENPIC_SUMMARY_REG_START 0x3800
82#define OPENPIC_SUMMARY_REG_SIZE 0x800
780d16b7 83#define OPENPIC_SRC_REG_START 0x10000
8935a442 84#define OPENPIC_SRC_REG_SIZE (OPENPIC_MAX_SRC * 0x20)
780d16b7
AG
85#define OPENPIC_CPU_REG_START 0x20000
86#define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
87
e0dfe5b1
SW
88static FslMpicInfo fsl_mpic_20 = {
89 .max_ext = 12,
90};
b7169916 91
e0dfe5b1
SW
92static FslMpicInfo fsl_mpic_42 = {
93 .max_ext = 12,
94};
3e772232 95
be7c236f
SW
96#define FRR_NIRQ_SHIFT 16
97#define FRR_NCPU_SHIFT 8
98#define FRR_VID_SHIFT 0
825463b3
AG
99
100#define VID_REVISION_1_2 2
d0b72631 101#define VID_REVISION_1_3 3
825463b3 102
be7c236f 103#define VIR_GENERIC 0x00000000 /* Generic Vendor ID */
58b62835 104#define VIR_MPIC2A 0x00004614 /* IBM MPIC-2A */
825463b3 105
be7c236f 106#define GCR_RESET 0x80000000
68c2dd70
AG
107#define GCR_MODE_PASS 0x00000000
108#define GCR_MODE_MIXED 0x20000000
109#define GCR_MODE_PROXY 0x60000000
71c6cacb 110
be7c236f
SW
111#define TBCR_CI 0x80000000 /* count inhibit */
112#define TCCR_TOG 0x80000000 /* toggles when decrement to zero */
825463b3 113
1945dbc1 114#define IDR_EP_SHIFT 31
def60298 115#define IDR_EP_MASK (1U << IDR_EP_SHIFT)
1945dbc1
AG
116#define IDR_CI0_SHIFT 30
117#define IDR_CI1_SHIFT 29
118#define IDR_P1_SHIFT 1
119#define IDR_P0_SHIFT 0
b7169916 120
e0dfe5b1
SW
121#define ILR_INTTGT_MASK 0x000000ff
122#define ILR_INTTGT_INT 0x00
123#define ILR_INTTGT_CINT 0x01 /* critical */
124#define ILR_INTTGT_MCP 0x02 /* machine check */
125
126/* The currently supported INTTGT values happen to be the same as QEMU's
127 * openpic output codes, but don't depend on this. The output codes
128 * could change (unlikely, but...) or support could be added for
129 * more INTTGT values.
130 */
131static const int inttgt_output[][2] = {
132 { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT },
133 { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT },
134 { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK },
135};
136
137static int inttgt_to_output(int inttgt)
138{
139 int i;
140
141 for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
142 if (inttgt_output[i][0] == inttgt) {
143 return inttgt_output[i][1];
144 }
145 }
146
df592270 147 error_report("%s: unsupported inttgt %d", __func__, inttgt);
e0dfe5b1
SW
148 return OPENPIC_OUTPUT_INT;
149}
150
151static int output_to_inttgt(int output)
152{
153 int i;
154
155 for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
156 if (inttgt_output[i][1] == output) {
157 return inttgt_output[i][0];
158 }
159 }
160
161 abort();
162}
163
732aa6ec
AG
164#define MSIIR_OFFSET 0x140
165#define MSIIR_SRS_SHIFT 29
166#define MSIIR_SRS_MASK (0x7 << MSIIR_SRS_SHIFT)
167#define MSIIR_IBS_SHIFT 24
168#define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT)
169
704c7e5d
AG
170static int get_current_cpu(void)
171{
4917cf44 172 if (!current_cpu) {
c3203fa5
SW
173 return -1;
174 }
175
4917cf44 176 return current_cpu->cpu_index;
704c7e5d
AG
177}
178
a8170e5e 179static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
704c7e5d 180 int idx);
a8170e5e 181static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
704c7e5d 182 uint32_t val, int idx);
8ebe65f3 183static void openpic_reset(DeviceState *d);
704c7e5d 184
ddd5140b
AL
185/* Convert between openpic clock ticks and nanosecs. In the hardware the clock
186 frequency is driven by board inputs to the PIC which the PIC would then
187 divide by 4 or 8. For now hard code to 25MZ.
188*/
189#define OPENPIC_TIMER_FREQ_MHZ 25
190#define OPENPIC_TIMER_NS_PER_TICK (1000 / OPENPIC_TIMER_FREQ_MHZ)
191static inline uint64_t ns_to_ticks(uint64_t ns)
192{
193 return ns / OPENPIC_TIMER_NS_PER_TICK;
194}
195static inline uint64_t ticks_to_ns(uint64_t ticks)
196{
197 return ticks * OPENPIC_TIMER_NS_PER_TICK;
198}
199
af7e9e74 200static inline void IRQ_setbit(IRQQueue *q, int n_IRQ)
dbda808a 201{
e69a17f6 202 set_bit(n_IRQ, q->queue);
dbda808a
FB
203}
204
af7e9e74 205static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ)
dbda808a 206{
e69a17f6 207 clear_bit(n_IRQ, q->queue);
dbda808a
FB
208}
209
af7e9e74 210static void IRQ_check(OpenPICState *opp, IRQQueue *q)
dbda808a 211{
4417c733
SW
212 int irq = -1;
213 int next = -1;
214 int priority = -1;
215
216 for (;;) {
217 irq = find_next_bit(q->queue, opp->max_irq, irq + 1);
218 if (irq == opp->max_irq) {
219 break;
220 }
76aec1f8 221
df592270 222 DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d",
4417c733 223 irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority);
76aec1f8 224
4417c733
SW
225 if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
226 next = irq;
227 priority = IVPR_PRIORITY(opp->src[irq].ivpr);
060fbfe1 228 }
dbda808a 229 }
76aec1f8 230
dbda808a
FB
231 q->next = next;
232 q->priority = priority;
233}
234
af7e9e74 235static int IRQ_get_next(OpenPICState *opp, IRQQueue *q)
dbda808a 236{
3c94378e
SW
237 /* XXX: optimize */
238 IRQ_check(opp, q);
dbda808a
FB
239
240 return q->next;
241}
242
9f1d4b1d
SW
243static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
244 bool active, bool was_active)
dbda808a 245{
af7e9e74
AG
246 IRQDest *dst;
247 IRQSource *src;
dbda808a
FB
248 int priority;
249
250 dst = &opp->dst[n_CPU];
251 src = &opp->src[n_IRQ];
5e22c276 252
df592270 253 DPRINTF("%s: IRQ %d active %d was %d",
9f1d4b1d
SW
254 __func__, n_IRQ, active, was_active);
255
5e22c276 256 if (src->output != OPENPIC_OUTPUT_INT) {
df592270 257 DPRINTF("%s: output %d irq %d active %d was %d count %d",
9f1d4b1d
SW
258 __func__, src->output, n_IRQ, active, was_active,
259 dst->outputs_active[src->output]);
260
5e22c276
SW
261 /* On Freescale MPIC, critical interrupts ignore priority,
262 * IACK, EOI, etc. Before MPIC v4.1 they also ignore
263 * masking.
264 */
9f1d4b1d
SW
265 if (active) {
266 if (!was_active && dst->outputs_active[src->output]++ == 0) {
df592270 267 DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d",
9f1d4b1d
SW
268 __func__, src->output, n_CPU, n_IRQ);
269 qemu_irq_raise(dst->irqs[src->output]);
270 }
271 } else {
272 if (was_active && --dst->outputs_active[src->output] == 0) {
df592270 273 DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d",
9f1d4b1d
SW
274 __func__, src->output, n_CPU, n_IRQ);
275 qemu_irq_lower(dst->irqs[src->output]);
276 }
277 }
278
060fbfe1 279 return;
dbda808a 280 }
5e22c276 281
be7c236f 282 priority = IVPR_PRIORITY(src->ivpr);
9f1d4b1d
SW
283
284 /* Even if the interrupt doesn't have enough priority,
285 * it is still raised, in case ctpr is lowered later.
286 */
287 if (active) {
288 IRQ_setbit(&dst->raised, n_IRQ);
289 } else {
290 IRQ_resetbit(&dst->raised, n_IRQ);
dbda808a 291 }
9f1d4b1d 292
3c94378e 293 IRQ_check(opp, &dst->raised);
9f1d4b1d
SW
294
295 if (active && priority <= dst->ctpr) {
df592270 296 DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d",
9f1d4b1d
SW
297 __func__, n_IRQ, priority, dst->ctpr, n_CPU);
298 active = 0;
e9df014c 299 }
9f1d4b1d
SW
300
301 if (active) {
302 if (IRQ_get_next(opp, &dst->servicing) >= 0 &&
303 priority <= dst->servicing.priority) {
df592270 304 DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d",
9f1d4b1d
SW
305 __func__, n_IRQ, dst->servicing.next, n_CPU);
306 } else {
df592270 307 DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d",
9f1d4b1d
SW
308 __func__, n_CPU, n_IRQ, dst->raised.next);
309 qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
310 }
311 } else {
312 IRQ_get_next(opp, &dst->servicing);
313 if (dst->raised.priority > dst->ctpr &&
314 dst->raised.priority > dst->servicing.priority) {
df592270 315 DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d",
9f1d4b1d
SW
316 __func__, n_IRQ, dst->raised.next, dst->raised.priority,
317 dst->ctpr, dst->servicing.priority, n_CPU);
318 /* IRQ line stays asserted */
319 } else {
df592270 320 DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d",
9f1d4b1d
SW
321 __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);
322 qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
323 }
dbda808a
FB
324 }
325}
326
611493d9 327/* update pic state because registers for n_IRQ have changed value */
6d544ee8 328static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
dbda808a 329{
af7e9e74 330 IRQSource *src;
9f1d4b1d 331 bool active, was_active;
dbda808a
FB
332 int i;
333
334 src = &opp->src[n_IRQ];
9f1d4b1d 335 active = src->pending;
611493d9 336
72c1da2c 337 if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) {
060fbfe1 338 /* Interrupt source is disabled */
df592270 339 DPRINTF("%s: IRQ %d is disabled", __func__, n_IRQ);
9f1d4b1d 340 active = false;
dbda808a 341 }
9f1d4b1d
SW
342
343 was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK);
344
345 /*
346 * We don't have a similar check for already-active because
347 * ctpr may have changed and we need to withdraw the interrupt.
348 */
349 if (!active && !was_active) {
df592270 350 DPRINTF("%s: IRQ %d is already inactive", __func__, n_IRQ);
060fbfe1 351 return;
dbda808a 352 }
9f1d4b1d
SW
353
354 if (active) {
355 src->ivpr |= IVPR_ACTIVITY_MASK;
356 } else {
357 src->ivpr &= ~IVPR_ACTIVITY_MASK;
611493d9 358 }
9f1d4b1d 359
f40c360c 360 if (src->destmask == 0) {
060fbfe1 361 /* No target */
df592270 362 DPRINTF("%s: IRQ %d has no target", __func__, n_IRQ);
060fbfe1 363 return;
dbda808a 364 }
611493d9 365
f40c360c 366 if (src->destmask == (1 << src->last_cpu)) {
e9df014c 367 /* Only one CPU is allowed to receive this IRQ */
9f1d4b1d 368 IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active);
be7c236f 369 } else if (!(src->ivpr & IVPR_MODE_MASK)) {
611493d9
FB
370 /* Directed delivery mode */
371 for (i = 0; i < opp->nb_cpus; i++) {
5e22c276 372 if (src->destmask & (1 << i)) {
9f1d4b1d 373 IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
1945dbc1 374 }
611493d9 375 }
dbda808a 376 } else {
611493d9 377 /* Distributed delivery mode */
e9df014c 378 for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
af7e9e74 379 if (i == opp->nb_cpus) {
611493d9 380 i = 0;
af7e9e74 381 }
5e22c276 382 if (src->destmask & (1 << i)) {
9f1d4b1d 383 IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
611493d9
FB
384 src->last_cpu = i;
385 break;
386 }
387 }
388 }
389}
390
d537cf6c 391static void openpic_set_irq(void *opaque, int n_IRQ, int level)
611493d9 392{
6d544ee8 393 OpenPICState *opp = opaque;
af7e9e74 394 IRQSource *src;
611493d9 395
8935a442 396 if (n_IRQ >= OPENPIC_MAX_IRQ) {
df592270 397 error_report("%s: IRQ %d out of range", __func__, n_IRQ);
65b9d0d5
SW
398 abort();
399 }
611493d9
FB
400
401 src = &opp->src[n_IRQ];
df592270 402 DPRINTF("openpic: set irq %d = %d ivpr=0x%08x",
be7c236f 403 n_IRQ, level, src->ivpr);
6c5e84c2 404 if (src->level) {
611493d9
FB
405 /* level-sensitive irq */
406 src->pending = level;
9f1d4b1d 407 openpic_update_irq(opp, n_IRQ);
611493d9
FB
408 } else {
409 /* edge-sensitive irq */
af7e9e74 410 if (level) {
611493d9 411 src->pending = 1;
9f1d4b1d
SW
412 openpic_update_irq(opp, n_IRQ);
413 }
414
415 if (src->output != OPENPIC_OUTPUT_INT) {
416 /* Edge-triggered interrupts shouldn't be used
417 * with non-INT delivery, but just in case,
418 * try to make it do something sane rather than
419 * cause an interrupt storm. This is close to
420 * what you'd probably see happen in real hardware.
421 */
422 src->pending = 0;
423 openpic_update_irq(opp, n_IRQ);
af7e9e74 424 }
dbda808a
FB
425 }
426}
427
be7c236f 428static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ)
dbda808a 429{
be7c236f 430 return opp->src[n_IRQ].idr;
8d3a8c1e 431}
dbda808a 432
e0dfe5b1
SW
433static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ)
434{
435 if (opp->flags & OPENPIC_FLAG_ILR) {
436 return output_to_inttgt(opp->src[n_IRQ].output);
437 }
438
439 return 0xffffffff;
440}
441
be7c236f 442static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ)
8d3a8c1e 443{
be7c236f 444 return opp->src[n_IRQ].ivpr;
dbda808a
FB
445}
446
be7c236f 447static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
dbda808a 448{
5e22c276
SW
449 IRQSource *src = &opp->src[n_IRQ];
450 uint32_t normal_mask = (1UL << opp->nb_cpus) - 1;
451 uint32_t crit_mask = 0;
452 uint32_t mask = normal_mask;
453 int crit_shift = IDR_EP_SHIFT - opp->nb_cpus;
454 int i;
455
456 if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
457 crit_mask = mask << crit_shift;
458 mask |= crit_mask | IDR_EP;
459 }
460
461 src->idr = val & mask;
df592270 462 DPRINTF("Set IDR %d to 0x%08x", n_IRQ, src->idr);
5e22c276
SW
463
464 if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
465 if (src->idr & crit_mask) {
466 if (src->idr & normal_mask) {
467 DPRINTF("%s: IRQ configured for multiple output types, using "
df592270 468 "critical", __func__);
5e22c276 469 }
dbda808a 470
5e22c276 471 src->output = OPENPIC_OUTPUT_CINT;
72c1da2c 472 src->nomask = true;
5e22c276
SW
473 src->destmask = 0;
474
475 for (i = 0; i < opp->nb_cpus; i++) {
476 int n_ci = IDR_CI0_SHIFT - i;
dbda808a 477
5e22c276
SW
478 if (src->idr & (1UL << n_ci)) {
479 src->destmask |= 1UL << i;
480 }
481 }
482 } else {
483 src->output = OPENPIC_OUTPUT_INT;
72c1da2c 484 src->nomask = false;
5e22c276
SW
485 src->destmask = src->idr & normal_mask;
486 }
487 } else {
488 src->destmask = src->idr;
489 }
11de8b71
AG
490}
491
e0dfe5b1
SW
492static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)
493{
494 if (opp->flags & OPENPIC_FLAG_ILR) {
495 IRQSource *src = &opp->src[n_IRQ];
496
497 src->output = inttgt_to_output(val & ILR_INTTGT_MASK);
df592270 498 DPRINTF("Set ILR %d to 0x%08x, output %d", n_IRQ, src->idr,
e0dfe5b1
SW
499 src->output);
500
501 /* TODO: on MPIC v4.0 only, set nomask for non-INT */
502 }
503}
504
be7c236f 505static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val)
11de8b71 506{
6c5e84c2
SW
507 uint32_t mask;
508
509 /* NOTE when implementing newer FSL MPIC models: starting with v4.0,
510 * the polarity bit is read-only on internal interrupts.
511 */
512 mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK |
513 IVPR_POLARITY_MASK | opp->vector_mask;
514
11de8b71 515 /* ACTIVITY bit is read-only */
6c5e84c2
SW
516 opp->src[n_IRQ].ivpr =
517 (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask);
518
519 /* For FSL internal interrupts, The sense bit is reserved and zero,
520 * and the interrupt is always level-triggered. Timers and IPIs
521 * have no sense or polarity bits, and are edge-triggered.
522 */
523 switch (opp->src[n_IRQ].type) {
524 case IRQ_TYPE_NORMAL:
525 opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK);
526 break;
527
528 case IRQ_TYPE_FSLINT:
529 opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK;
530 break;
531
532 case IRQ_TYPE_FSLSPECIAL:
533 opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK);
534 break;
535 }
536
11de8b71 537 openpic_update_irq(opp, n_IRQ);
df592270 538 DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x", n_IRQ, val,
be7c236f 539 opp->src[n_IRQ].ivpr);
dbda808a
FB
540}
541
7f11573b
AG
542static void openpic_gcr_write(OpenPICState *opp, uint64_t val)
543{
e49798b1 544 bool mpic_proxy = false;
1ac3d713 545
7f11573b 546 if (val & GCR_RESET) {
e1766344 547 openpic_reset(DEVICE(opp));
1ac3d713
AG
548 return;
549 }
7f11573b 550
1ac3d713
AG
551 opp->gcr &= ~opp->mpic_mode_mask;
552 opp->gcr |= val & opp->mpic_mode_mask;
7f11573b 553
1ac3d713
AG
554 /* Set external proxy mode */
555 if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) {
e49798b1 556 mpic_proxy = true;
7f11573b 557 }
e49798b1
AG
558
559 ppce500_set_mpic_proxy(mpic_proxy);
7f11573b
AG
560}
561
b9b2aaa3
AG
562static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
563 unsigned len)
dbda808a 564{
6d544ee8 565 OpenPICState *opp = opaque;
af7e9e74 566 IRQDest *dst;
e9df014c 567 int idx;
dbda808a 568
df592270 569 DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
4c4f0e48 570 __func__, addr, val);
af7e9e74 571 if (addr & 0xF) {
dbda808a 572 return;
af7e9e74 573 }
dbda808a 574 switch (addr) {
3e772232
BB
575 case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
576 break;
704c7e5d
AG
577 case 0x40:
578 case 0x50:
579 case 0x60:
580 case 0x70:
581 case 0x80:
582 case 0x90:
583 case 0xA0:
584 case 0xB0:
585 openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
dbda808a 586 break;
be7c236f 587 case 0x1000: /* FRR */
dbda808a 588 break;
be7c236f 589 case 0x1020: /* GCR */
7f11573b 590 openpic_gcr_write(opp, val);
060fbfe1 591 break;
be7c236f 592 case 0x1080: /* VIR */
060fbfe1 593 break;
be7c236f 594 case 0x1090: /* PIR */
e9df014c 595 for (idx = 0; idx < opp->nb_cpus; idx++) {
be7c236f 596 if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) {
df592270 597 DPRINTF("Raise OpenPIC RESET output for CPU %d", idx);
e9df014c
JM
598 dst = &opp->dst[idx];
599 qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
be7c236f 600 } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) {
df592270 601 DPRINTF("Lower OpenPIC RESET output for CPU %d", idx);
e9df014c
JM
602 dst = &opp->dst[idx];
603 qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
604 }
dbda808a 605 }
be7c236f 606 opp->pir = val;
060fbfe1 607 break;
be7c236f 608 case 0x10A0: /* IPI_IVPR */
704c7e5d
AG
609 case 0x10B0:
610 case 0x10C0:
611 case 0x10D0:
dbda808a
FB
612 {
613 int idx;
704c7e5d 614 idx = (addr - 0x10A0) >> 4;
be7c236f 615 write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val);
dbda808a
FB
616 }
617 break;
704c7e5d 618 case 0x10E0: /* SPVE */
0fe04622 619 opp->spve = val & opp->vector_mask;
dbda808a 620 break;
dbda808a
FB
621 default:
622 break;
623 }
624}
625
b9b2aaa3 626static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
dbda808a 627{
6d544ee8 628 OpenPICState *opp = opaque;
dbda808a
FB
629 uint32_t retval;
630
df592270 631 DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
dbda808a 632 retval = 0xFFFFFFFF;
af7e9e74 633 if (addr & 0xF) {
dbda808a 634 return retval;
af7e9e74 635 }
dbda808a 636 switch (addr) {
be7c236f
SW
637 case 0x1000: /* FRR */
638 retval = opp->frr;
dbda808a 639 break;
be7c236f
SW
640 case 0x1020: /* GCR */
641 retval = opp->gcr;
060fbfe1 642 break;
be7c236f
SW
643 case 0x1080: /* VIR */
644 retval = opp->vir;
060fbfe1 645 break;
be7c236f 646 case 0x1090: /* PIR */
dbda808a 647 retval = 0x00000000;
060fbfe1 648 break;
3e772232 649 case 0x00: /* Block Revision Register1 (BRR1) */
0d404683
SW
650 retval = opp->brr1;
651 break;
704c7e5d
AG
652 case 0x40:
653 case 0x50:
654 case 0x60:
655 case 0x70:
656 case 0x80:
657 case 0x90:
658 case 0xA0:
dbda808a 659 case 0xB0:
704c7e5d
AG
660 retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
661 break;
be7c236f 662 case 0x10A0: /* IPI_IVPR */
704c7e5d
AG
663 case 0x10B0:
664 case 0x10C0:
665 case 0x10D0:
dbda808a
FB
666 {
667 int idx;
704c7e5d 668 idx = (addr - 0x10A0) >> 4;
be7c236f 669 retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx);
dbda808a 670 }
060fbfe1 671 break;
704c7e5d 672 case 0x10E0: /* SPVE */
dbda808a
FB
673 retval = opp->spve;
674 break;
dbda808a
FB
675 default:
676 break;
677 }
df592270 678 DPRINTF("%s: => 0x%08x", __func__, retval);
dbda808a
FB
679
680 return retval;
681}
682
ddd5140b
AL
683static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enabled);
684
685static void qemu_timer_cb(void *opaque)
686{
687 OpenPICTimer *tmr = opaque;
688 OpenPICState *opp = tmr->opp;
689 uint32_t n_IRQ = tmr->n_IRQ;
690 uint32_t val = tmr->tbcr & ~TBCR_CI;
691 uint32_t tog = ((tmr->tccr & TCCR_TOG) ^ TCCR_TOG); /* invert toggle. */
692
df592270 693 DPRINTF("%s n_IRQ=%d", __func__, n_IRQ);
ddd5140b
AL
694 /* Reload current count from base count and setup timer. */
695 tmr->tccr = val | tog;
696 openpic_tmr_set_tmr(tmr, val, /*enabled=*/true);
697 /* Raise the interrupt. */
698 opp->src[n_IRQ].destmask = read_IRQreg_idr(opp, n_IRQ);
699 openpic_set_irq(opp, n_IRQ, 1);
700 openpic_set_irq(opp, n_IRQ, 0);
701}
702
703/* If enabled is true, arranges for an interrupt to be raised val clocks into
704 the future, if enabled is false cancels the timer. */
705static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enabled)
706{
707 uint64_t ns = ticks_to_ns(val & ~TCCR_TOG);
708 /* A count of zero causes a timer to be set to expire immediately. This
709 effectively stops the simulation since the timer is constantly expiring
710 which prevents guest code execution, so we don't honor that
711 configuration. On real hardware, this situation would generate an
712 interrupt on every clock cycle if the interrupt was unmasked. */
713 if ((ns == 0) || !enabled) {
714 tmr->qemu_timer_active = false;
715 tmr->tccr = tmr->tccr & TCCR_TOG;
716 timer_del(tmr->qemu_timer); /* set timer to never expire. */
717 } else {
718 tmr->qemu_timer_active = true;
719 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
720 tmr->origin_time = now;
721 timer_mod(tmr->qemu_timer, now + ns); /* set timer expiration. */
722 }
723}
724
725/* Returns the currrent tccr value, i.e., timer value (in clocks) with
726 appropriate TOG. */
727static uint64_t openpic_tmr_get_timer(OpenPICTimer *tmr)
728{
729 uint64_t retval;
730 if (!tmr->qemu_timer_active) {
731 retval = tmr->tccr;
732 } else {
733 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
734 uint64_t used = now - tmr->origin_time; /* nsecs */
735 uint32_t used_ticks = (uint32_t)ns_to_ticks(used);
736 uint32_t count = (tmr->tccr & ~TCCR_TOG) - used_ticks;
737 retval = (uint32_t)((tmr->tccr & TCCR_TOG) | (count & ~TCCR_TOG));
738 }
739 return retval;
740}
741
6d544ee8 742static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
a09f7443 743 unsigned len)
dbda808a 744{
6d544ee8 745 OpenPICState *opp = opaque;
dbda808a
FB
746 int idx;
747
df592270 748 DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
a09f7443 749 __func__, (addr + 0x10f0), val);
af7e9e74 750 if (addr & 0xF) {
dbda808a 751 return;
af7e9e74 752 }
c38c0b8a 753
a09f7443 754 if (addr == 0) {
be7c236f
SW
755 /* TFRR */
756 opp->tfrr = val;
c38c0b8a
AG
757 return;
758 }
a09f7443 759 addr -= 0x10; /* correct for TFRR */
03274d44 760 idx = (addr >> 6) & 0x3;
03274d44 761
c38c0b8a 762 switch (addr & 0x30) {
be7c236f 763 case 0x00: /* TCCR */
dbda808a 764 break;
be7c236f 765 case 0x10: /* TBCR */
ddd5140b
AL
766 /* Did the enable status change? */
767 if ((opp->timers[idx].tbcr & TBCR_CI) != (val & TBCR_CI)) {
768 /* Did "Count Inhibit" transition from 1 to 0? */
769 if ((val & TBCR_CI) == 0) {
770 opp->timers[idx].tccr = val & ~TCCR_TOG;
771 }
772 openpic_tmr_set_tmr(&opp->timers[idx],
773 (val & ~TBCR_CI),
774 /*enabled=*/((val & TBCR_CI) == 0));
71c6cacb 775 }
be7c236f 776 opp->timers[idx].tbcr = val;
060fbfe1 777 break;
be7c236f
SW
778 case 0x20: /* TVPR */
779 write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val);
060fbfe1 780 break;
be7c236f
SW
781 case 0x30: /* TDR */
782 write_IRQreg_idr(opp, opp->irq_tim0 + idx, val);
060fbfe1 783 break;
dbda808a
FB
784 }
785}
786
6d544ee8 787static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
dbda808a 788{
6d544ee8 789 OpenPICState *opp = opaque;
c38c0b8a 790 uint32_t retval = -1;
dbda808a
FB
791 int idx;
792
df592270 793 DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr + 0x10f0);
c38c0b8a
AG
794 if (addr & 0xF) {
795 goto out;
796 }
a09f7443 797 if (addr == 0) {
be7c236f
SW
798 /* TFRR */
799 retval = opp->tfrr;
c38c0b8a
AG
800 goto out;
801 }
a09f7443
AL
802 addr -= 0x10; /* correct for TFRR */
803 idx = (addr >> 6) & 0x3;
c38c0b8a 804 switch (addr & 0x30) {
be7c236f 805 case 0x00: /* TCCR */
ddd5140b 806 retval = openpic_tmr_get_timer(&opp->timers[idx]);
dbda808a 807 break;
be7c236f
SW
808 case 0x10: /* TBCR */
809 retval = opp->timers[idx].tbcr;
060fbfe1 810 break;
a09f7443 811 case 0x20: /* TVPR */
be7c236f 812 retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx);
060fbfe1 813 break;
a09f7443 814 case 0x30: /* TDR */
be7c236f 815 retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx);
060fbfe1 816 break;
dbda808a 817 }
c38c0b8a
AG
818
819out:
df592270 820 DPRINTF("%s: => 0x%08x", __func__, retval);
dbda808a
FB
821
822 return retval;
823}
824
b9b2aaa3
AG
825static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
826 unsigned len)
dbda808a 827{
6d544ee8 828 OpenPICState *opp = opaque;
dbda808a
FB
829 int idx;
830
df592270 831 DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64,
4c4f0e48 832 __func__, addr, val);
e0dfe5b1
SW
833
834 addr = addr & 0xffff;
dbda808a 835 idx = addr >> 5;
e0dfe5b1
SW
836
837 switch (addr & 0x1f) {
838 case 0x00:
be7c236f 839 write_IRQreg_ivpr(opp, idx, val);
e0dfe5b1
SW
840 break;
841 case 0x10:
842 write_IRQreg_idr(opp, idx, val);
843 break;
844 case 0x18:
845 write_IRQreg_ilr(opp, idx, val);
846 break;
dbda808a
FB
847 }
848}
849
b9b2aaa3 850static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
dbda808a 851{
6d544ee8 852 OpenPICState *opp = opaque;
dbda808a
FB
853 uint32_t retval;
854 int idx;
855
df592270 856 DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
dbda808a 857 retval = 0xFFFFFFFF;
e0dfe5b1
SW
858
859 addr = addr & 0xffff;
dbda808a 860 idx = addr >> 5;
e0dfe5b1
SW
861
862 switch (addr & 0x1f) {
863 case 0x00:
be7c236f 864 retval = read_IRQreg_ivpr(opp, idx);
e0dfe5b1
SW
865 break;
866 case 0x10:
867 retval = read_IRQreg_idr(opp, idx);
868 break;
869 case 0x18:
870 retval = read_IRQreg_ilr(opp, idx);
871 break;
dbda808a 872 }
dbda808a 873
df592270 874 DPRINTF("%s: => 0x%08x", __func__, retval);
dbda808a
FB
875 return retval;
876}
877
732aa6ec
AG
878static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,
879 unsigned size)
880{
881 OpenPICState *opp = opaque;
882 int idx = opp->irq_msi;
883 int srs, ibs;
884
df592270 885 DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64,
4c4f0e48 886 __func__, addr, val);
732aa6ec
AG
887 if (addr & 0xF) {
888 return;
889 }
890
891 switch (addr) {
892 case MSIIR_OFFSET:
893 srs = val >> MSIIR_SRS_SHIFT;
894 idx += srs;
895 ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT;
896 opp->msi[srs].msir |= 1 << ibs;
897 openpic_set_irq(opp, idx, 1);
898 break;
899 default:
900 /* most registers are read-only, thus ignored */
901 break;
902 }
903}
904
905static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
906{
907 OpenPICState *opp = opaque;
908 uint64_t r = 0;
909 int i, srs;
910
df592270 911 DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
732aa6ec
AG
912 if (addr & 0xF) {
913 return -1;
914 }
915
916 srs = addr >> 4;
917
918 switch (addr) {
919 case 0x00:
920 case 0x10:
921 case 0x20:
922 case 0x30:
923 case 0x40:
924 case 0x50:
925 case 0x60:
926 case 0x70: /* MSIRs */
927 r = opp->msi[srs].msir;
928 /* Clear on read */
929 opp->msi[srs].msir = 0;
e99fd8af 930 openpic_set_irq(opp, opp->irq_msi + srs, 0);
732aa6ec
AG
931 break;
932 case 0x120: /* MSISR */
933 for (i = 0; i < MAX_MSI; i++) {
934 r |= (opp->msi[i].msir ? 1 : 0) << i;
935 }
936 break;
937 }
938
939 return r;
940}
941
e0dfe5b1
SW
942static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
943{
944 uint64_t r = 0;
945
df592270 946 DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr);
e0dfe5b1
SW
947
948 /* TODO: EISR/EIMR */
949
950 return r;
951}
952
953static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val,
954 unsigned size)
955{
df592270 956 DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64,
e0dfe5b1
SW
957 __func__, addr, val);
958
959 /* TODO: EISR/EIMR */
960}
961
a8170e5e 962static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
704c7e5d 963 uint32_t val, int idx)
dbda808a 964{
6d544ee8 965 OpenPICState *opp = opaque;
af7e9e74
AG
966 IRQSource *src;
967 IRQDest *dst;
704c7e5d 968 int s_IRQ, n_IRQ;
dbda808a 969
df592270 970 DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x", __func__, idx,
704c7e5d 971 addr, val);
c3203fa5 972
04d2acbb 973 if (idx < 0 || idx >= opp->nb_cpus) {
dbda808a 974 return;
c3203fa5
SW
975 }
976
af7e9e74 977 if (addr & 0xF) {
dbda808a 978 return;
af7e9e74 979 }
dbda808a
FB
980 dst = &opp->dst[idx];
981 addr &= 0xFF0;
982 switch (addr) {
704c7e5d 983 case 0x40: /* IPIDR */
dbda808a
FB
984 case 0x50:
985 case 0x60:
986 case 0x70:
987 idx = (addr - 0x40) >> 4;
a675155e 988 /* we use IDE as mask which CPUs to deliver the IPI to still. */
f40c360c 989 opp->src[opp->irq_ipi0 + idx].destmask |= val;
b7169916
AJ
990 openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
991 openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
dbda808a 992 break;
be7c236f
SW
993 case 0x80: /* CTPR */
994 dst->ctpr = val & 0x0000000F;
9f1d4b1d 995
df592270 996 DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d",
9f1d4b1d
SW
997 __func__, idx, dst->ctpr, dst->raised.priority,
998 dst->servicing.priority);
999
1000 if (dst->raised.priority <= dst->ctpr) {
df592270 1001 DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr",
9f1d4b1d
SW
1002 __func__, idx);
1003 qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
1004 } else if (dst->raised.priority > dst->servicing.priority) {
df592270 1005 DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d",
9f1d4b1d
SW
1006 __func__, idx, dst->raised.next);
1007 qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
1008 }
1009
060fbfe1 1010 break;
dbda808a 1011 case 0x90: /* WHOAMI */
060fbfe1
AJ
1012 /* Read-only register */
1013 break;
be7c236f 1014 case 0xA0: /* IACK */
060fbfe1
AJ
1015 /* Read-only register */
1016 break;
be7c236f 1017 case 0xB0: /* EOI */
df592270 1018 DPRINTF("EOI");
060fbfe1 1019 s_IRQ = IRQ_get_next(opp, &dst->servicing);
65b9d0d5
SW
1020
1021 if (s_IRQ < 0) {
df592270 1022 DPRINTF("%s: EOI with no interrupt in service", __func__);
65b9d0d5
SW
1023 break;
1024 }
1025
060fbfe1 1026 IRQ_resetbit(&dst->servicing, s_IRQ);
060fbfe1
AJ
1027 /* Set up next servicing IRQ */
1028 s_IRQ = IRQ_get_next(opp, &dst->servicing);
e9df014c
JM
1029 /* Check queued interrupts. */
1030 n_IRQ = IRQ_get_next(opp, &dst->raised);
1031 src = &opp->src[n_IRQ];
1032 if (n_IRQ != -1 &&
1033 (s_IRQ == -1 ||
be7c236f 1034 IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
df592270 1035 DPRINTF("Raise OpenPIC INT output cpu %d irq %d",
e9df014c 1036 idx, n_IRQ);
5e22c276 1037 qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
e9df014c 1038 }
060fbfe1 1039 break;
dbda808a
FB
1040 default:
1041 break;
1042 }
1043}
1044
b9b2aaa3
AG
1045static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val,
1046 unsigned len)
704c7e5d
AG
1047{
1048 openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
1049}
1050
a898a8fc
SW
1051
1052static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
1053{
1054 IRQSource *src;
1055 int retval, irq;
1056
df592270 1057 DPRINTF("Lower OpenPIC INT output");
a898a8fc
SW
1058 qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
1059
1060 irq = IRQ_get_next(opp, &dst->raised);
df592270 1061 DPRINTF("IACK: irq=%d", irq);
a898a8fc
SW
1062
1063 if (irq == -1) {
1064 /* No more interrupt pending */
1065 return opp->spve;
1066 }
1067
1068 src = &opp->src[irq];
1069 if (!(src->ivpr & IVPR_ACTIVITY_MASK) ||
1070 !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) {
df592270 1071 error_report("%s: bad raised IRQ %d ctpr %d ivpr 0x%08x",
9f1d4b1d
SW
1072 __func__, irq, dst->ctpr, src->ivpr);
1073 openpic_update_irq(opp, irq);
a898a8fc
SW
1074 retval = opp->spve;
1075 } else {
1076 /* IRQ enter servicing state */
1077 IRQ_setbit(&dst->servicing, irq);
1078 retval = IVPR_VECTOR(opp, src->ivpr);
1079 }
9f1d4b1d 1080
a898a8fc
SW
1081 if (!src->level) {
1082 /* edge-sensitive IRQ */
1083 src->ivpr &= ~IVPR_ACTIVITY_MASK;
1084 src->pending = 0;
9f1d4b1d 1085 IRQ_resetbit(&dst->raised, irq);
a898a8fc
SW
1086 }
1087
ddd5140b
AL
1088 /* Timers and IPIs support multicast. */
1089 if (((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) ||
1090 ((irq >= opp->irq_tim0) && (irq < (opp->irq_tim0 + OPENPIC_MAX_TMR)))) {
df592270 1091 DPRINTF("irq is IPI or TMR");
f40c360c
SW
1092 src->destmask &= ~(1 << cpu);
1093 if (src->destmask && !src->level) {
a898a8fc
SW
1094 /* trigger on CPUs that didn't know about it yet */
1095 openpic_set_irq(opp, irq, 1);
1096 openpic_set_irq(opp, irq, 0);
1097 /* if all CPUs knew about it, set active bit again */
1098 src->ivpr |= IVPR_ACTIVITY_MASK;
1099 }
1100 }
1101
1102 return retval;
1103}
1104
a8170e5e 1105static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
704c7e5d 1106 int idx)
dbda808a 1107{
6d544ee8 1108 OpenPICState *opp = opaque;
af7e9e74 1109 IRQDest *dst;
dbda808a 1110 uint32_t retval;
3b46e624 1111
df592270 1112 DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx, __func__, idx, addr);
dbda808a 1113 retval = 0xFFFFFFFF;
c3203fa5 1114
04d2acbb 1115 if (idx < 0 || idx >= opp->nb_cpus) {
c3203fa5
SW
1116 return retval;
1117 }
1118
af7e9e74 1119 if (addr & 0xF) {
dbda808a 1120 return retval;
af7e9e74 1121 }
dbda808a
FB
1122 dst = &opp->dst[idx];
1123 addr &= 0xFF0;
1124 switch (addr) {
be7c236f
SW
1125 case 0x80: /* CTPR */
1126 retval = dst->ctpr;
060fbfe1 1127 break;
dbda808a 1128 case 0x90: /* WHOAMI */
060fbfe1
AJ
1129 retval = idx;
1130 break;
be7c236f 1131 case 0xA0: /* IACK */
a898a8fc 1132 retval = openpic_iack(opp, dst, idx);
060fbfe1 1133 break;
be7c236f 1134 case 0xB0: /* EOI */
060fbfe1
AJ
1135 retval = 0;
1136 break;
dbda808a
FB
1137 default:
1138 break;
1139 }
df592270 1140 DPRINTF("%s: => 0x%08x", __func__, retval);
dbda808a
FB
1141
1142 return retval;
1143}
1144
b9b2aaa3 1145static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len)
704c7e5d
AG
1146{
1147 return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
1148}
1149
35732cb4 1150static const MemoryRegionOps openpic_glb_ops_le = {
780d16b7
AG
1151 .write = openpic_gbl_write,
1152 .read = openpic_gbl_read,
1153 .endianness = DEVICE_LITTLE_ENDIAN,
1154 .impl = {
1155 .min_access_size = 4,
1156 .max_access_size = 4,
1157 },
1158};
dbda808a 1159
35732cb4
AG
1160static const MemoryRegionOps openpic_glb_ops_be = {
1161 .write = openpic_gbl_write,
1162 .read = openpic_gbl_read,
1163 .endianness = DEVICE_BIG_ENDIAN,
1164 .impl = {
1165 .min_access_size = 4,
1166 .max_access_size = 4,
1167 },
1168};
1169
1170static const MemoryRegionOps openpic_tmr_ops_le = {
6d544ee8
AG
1171 .write = openpic_tmr_write,
1172 .read = openpic_tmr_read,
780d16b7
AG
1173 .endianness = DEVICE_LITTLE_ENDIAN,
1174 .impl = {
1175 .min_access_size = 4,
1176 .max_access_size = 4,
1177 },
1178};
dbda808a 1179
35732cb4 1180static const MemoryRegionOps openpic_tmr_ops_be = {
6d544ee8
AG
1181 .write = openpic_tmr_write,
1182 .read = openpic_tmr_read,
35732cb4
AG
1183 .endianness = DEVICE_BIG_ENDIAN,
1184 .impl = {
1185 .min_access_size = 4,
1186 .max_access_size = 4,
1187 },
1188};
1189
1190static const MemoryRegionOps openpic_cpu_ops_le = {
780d16b7
AG
1191 .write = openpic_cpu_write,
1192 .read = openpic_cpu_read,
1193 .endianness = DEVICE_LITTLE_ENDIAN,
1194 .impl = {
1195 .min_access_size = 4,
1196 .max_access_size = 4,
1197 },
1198};
dbda808a 1199
35732cb4
AG
1200static const MemoryRegionOps openpic_cpu_ops_be = {
1201 .write = openpic_cpu_write,
1202 .read = openpic_cpu_read,
1203 .endianness = DEVICE_BIG_ENDIAN,
1204 .impl = {
1205 .min_access_size = 4,
1206 .max_access_size = 4,
1207 },
1208};
1209
1210static const MemoryRegionOps openpic_src_ops_le = {
780d16b7
AG
1211 .write = openpic_src_write,
1212 .read = openpic_src_read,
23c5e4ca 1213 .endianness = DEVICE_LITTLE_ENDIAN,
b9b2aaa3
AG
1214 .impl = {
1215 .min_access_size = 4,
1216 .max_access_size = 4,
1217 },
23c5e4ca
AK
1218};
1219
35732cb4
AG
1220static const MemoryRegionOps openpic_src_ops_be = {
1221 .write = openpic_src_write,
1222 .read = openpic_src_read,
1223 .endianness = DEVICE_BIG_ENDIAN,
1224 .impl = {
1225 .min_access_size = 4,
1226 .max_access_size = 4,
1227 },
1228};
1229
e0dfe5b1 1230static const MemoryRegionOps openpic_msi_ops_be = {
732aa6ec
AG
1231 .read = openpic_msi_read,
1232 .write = openpic_msi_write,
e0dfe5b1 1233 .endianness = DEVICE_BIG_ENDIAN,
732aa6ec
AG
1234 .impl = {
1235 .min_access_size = 4,
1236 .max_access_size = 4,
1237 },
1238};
1239
e0dfe5b1
SW
1240static const MemoryRegionOps openpic_summary_ops_be = {
1241 .read = openpic_summary_read,
1242 .write = openpic_summary_write,
732aa6ec
AG
1243 .endianness = DEVICE_BIG_ENDIAN,
1244 .impl = {
1245 .min_access_size = 4,
1246 .max_access_size = 4,
1247 },
1248};
1249
8ebe65f3
PJ
1250static void openpic_reset(DeviceState *d)
1251{
1252 OpenPICState *opp = OPENPIC(d);
1253 int i;
1254
1255 opp->gcr = GCR_RESET;
1256 /* Initialise controller registers */
1257 opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
1258 ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
1259 (opp->vid << FRR_VID_SHIFT);
1260
1261 opp->pir = 0;
1262 opp->spve = -1 & opp->vector_mask;
1263 opp->tfrr = opp->tfrr_reset;
1264 /* Initialise IRQ sources */
1265 for (i = 0; i < opp->max_irq; i++) {
1266 opp->src[i].ivpr = opp->ivpr_reset;
8ebe65f3
PJ
1267 switch (opp->src[i].type) {
1268 case IRQ_TYPE_NORMAL:
1269 opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK);
1270 break;
1271
1272 case IRQ_TYPE_FSLINT:
1273 opp->src[i].ivpr |= IVPR_POLARITY_MASK;
1274 break;
1275
1276 case IRQ_TYPE_FSLSPECIAL:
1277 break;
1278 }
ffd5e9fe
PJ
1279
1280 write_IRQreg_idr(opp, i, opp->idr_reset);
8ebe65f3
PJ
1281 }
1282 /* Initialise IRQ destinations */
2ada66f9 1283 for (i = 0; i < opp->nb_cpus; i++) {
8ebe65f3 1284 opp->dst[i].ctpr = 15;
8ebe65f3 1285 opp->dst[i].raised.next = -1;
2ada66f9
MCA
1286 opp->dst[i].raised.priority = 0;
1287 bitmap_clear(opp->dst[i].raised.queue, 0, IRQQUEUE_SIZE_BITS);
8ebe65f3 1288 opp->dst[i].servicing.next = -1;
2ada66f9
MCA
1289 opp->dst[i].servicing.priority = 0;
1290 bitmap_clear(opp->dst[i].servicing.queue, 0, IRQQUEUE_SIZE_BITS);
8ebe65f3
PJ
1291 }
1292 /* Initialise timers */
1293 for (i = 0; i < OPENPIC_MAX_TMR; i++) {
1294 opp->timers[i].tccr = 0;
1295 opp->timers[i].tbcr = TBCR_CI;
ddd5140b
AL
1296 if (opp->timers[i].qemu_timer_active) {
1297 timer_del(opp->timers[i].qemu_timer); /* Inhibit timer */
1298 opp->timers[i].qemu_timer_active = false;
1299 }
8ebe65f3
PJ
1300 }
1301 /* Go out of RESET state */
1302 opp->gcr = 0;
1303}
1304
af7e9e74 1305typedef struct MemReg {
d0b72631
AG
1306 const char *name;
1307 MemoryRegionOps const *ops;
1308 hwaddr start_addr;
1309 ram_addr_t size;
af7e9e74 1310} MemReg;
d0b72631 1311
e0dfe5b1
SW
1312static void fsl_common_init(OpenPICState *opp)
1313{
1314 int i;
8935a442 1315 int virq = OPENPIC_MAX_SRC;
e0dfe5b1
SW
1316
1317 opp->vid = VID_REVISION_1_2;
1318 opp->vir = VIR_GENERIC;
1319 opp->vector_mask = 0xFFFF;
1320 opp->tfrr_reset = 0;
1321 opp->ivpr_reset = IVPR_MASK_MASK;
1322 opp->idr_reset = 1 << 0;
8935a442 1323 opp->max_irq = OPENPIC_MAX_IRQ;
e0dfe5b1
SW
1324
1325 opp->irq_ipi0 = virq;
8935a442 1326 virq += OPENPIC_MAX_IPI;
e0dfe5b1 1327 opp->irq_tim0 = virq;
8935a442 1328 virq += OPENPIC_MAX_TMR;
e0dfe5b1 1329
8935a442 1330 assert(virq <= OPENPIC_MAX_IRQ);
e0dfe5b1
SW
1331
1332 opp->irq_msi = 224;
1333
226419d6 1334 msi_nonbroken = true;
e0dfe5b1
SW
1335 for (i = 0; i < opp->fsl->max_ext; i++) {
1336 opp->src[i].level = false;
1337 }
1338
1339 /* Internal interrupts, including message and MSI */
8935a442 1340 for (i = 16; i < OPENPIC_MAX_SRC; i++) {
e0dfe5b1
SW
1341 opp->src[i].type = IRQ_TYPE_FSLINT;
1342 opp->src[i].level = true;
1343 }
1344
1345 /* timers and IPIs */
8935a442 1346 for (i = OPENPIC_MAX_SRC; i < virq; i++) {
e0dfe5b1
SW
1347 opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
1348 opp->src[i].level = false;
1349 }
ddd5140b
AL
1350
1351 for (i = 0; i < OPENPIC_MAX_TMR; i++) {
1352 opp->timers[i].n_IRQ = opp->irq_tim0 + i;
1353 opp->timers[i].qemu_timer_active = false;
1354 opp->timers[i].qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
1355 &qemu_timer_cb,
1356 &opp->timers[i]);
1357 opp->timers[i].opp = opp;
1358 }
e0dfe5b1
SW
1359}
1360
1361static void map_list(OpenPICState *opp, const MemReg *list, int *count)
1362{
1363 while (list->name) {
1364 assert(*count < ARRAY_SIZE(opp->sub_io_mem));
1365
1437c94b
PB
1366 memory_region_init_io(&opp->sub_io_mem[*count], OBJECT(opp), list->ops,
1367 opp, list->name, list->size);
e0dfe5b1
SW
1368
1369 memory_region_add_subregion(&opp->mem, list->start_addr,
1370 &opp->sub_io_mem[*count]);
1371
1372 (*count)++;
1373 list++;
1374 }
1375}
1376
e5f6e732
MCA
1377static const VMStateDescription vmstate_openpic_irq_queue = {
1378 .name = "openpic_irq_queue",
1379 .version_id = 0,
1380 .minimum_version_id = 0,
1381 .fields = (VMStateField[]) {
1382 VMSTATE_BITMAP(queue, IRQQueue, 0, queue_size),
1383 VMSTATE_INT32(next, IRQQueue),
1384 VMSTATE_INT32(priority, IRQQueue),
1385 VMSTATE_END_OF_LIST()
1386 }
1387};
1388
1389static const VMStateDescription vmstate_openpic_irqdest = {
1390 .name = "openpic_irqdest",
1391 .version_id = 0,
1392 .minimum_version_id = 0,
1393 .fields = (VMStateField[]) {
1394 VMSTATE_INT32(ctpr, IRQDest),
1395 VMSTATE_STRUCT(raised, IRQDest, 0, vmstate_openpic_irq_queue,
1396 IRQQueue),
1397 VMSTATE_STRUCT(servicing, IRQDest, 0, vmstate_openpic_irq_queue,
1398 IRQQueue),
1399 VMSTATE_UINT32_ARRAY(outputs_active, IRQDest, OPENPIC_OUTPUT_NB),
1400 VMSTATE_END_OF_LIST()
1401 }
1402};
1403
1404static const VMStateDescription vmstate_openpic_irqsource = {
1405 .name = "openpic_irqsource",
1406 .version_id = 0,
1407 .minimum_version_id = 0,
1408 .fields = (VMStateField[]) {
1409 VMSTATE_UINT32(ivpr, IRQSource),
1410 VMSTATE_UINT32(idr, IRQSource),
1411 VMSTATE_UINT32(destmask, IRQSource),
1412 VMSTATE_INT32(last_cpu, IRQSource),
1413 VMSTATE_INT32(pending, IRQSource),
1414 VMSTATE_END_OF_LIST()
1415 }
1416};
1417
1418static const VMStateDescription vmstate_openpic_timer = {
1419 .name = "openpic_timer",
1420 .version_id = 0,
1421 .minimum_version_id = 0,
1422 .fields = (VMStateField[]) {
1423 VMSTATE_UINT32(tccr, OpenPICTimer),
1424 VMSTATE_UINT32(tbcr, OpenPICTimer),
1425 VMSTATE_END_OF_LIST()
1426 }
1427};
1428
1429static const VMStateDescription vmstate_openpic_msi = {
1430 .name = "openpic_msi",
1431 .version_id = 0,
1432 .minimum_version_id = 0,
1433 .fields = (VMStateField[]) {
1434 VMSTATE_UINT32(msir, OpenPICMSI),
1435 VMSTATE_END_OF_LIST()
1436 }
1437};
1438
1439static int openpic_post_load(void *opaque, int version_id)
1440{
1441 OpenPICState *opp = (OpenPICState *)opaque;
1442 int i;
1443
1444 /* Update internal ivpr and idr variables */
1445 for (i = 0; i < opp->max_irq; i++) {
1446 write_IRQreg_idr(opp, i, opp->src[i].idr);
1447 write_IRQreg_ivpr(opp, i, opp->src[i].ivpr);
1448 }
1449
1450 return 0;
1451}
1452
1453static const VMStateDescription vmstate_openpic = {
1454 .name = "openpic",
1455 .version_id = 3,
1456 .minimum_version_id = 3,
1457 .post_load = openpic_post_load,
1458 .fields = (VMStateField[]) {
1459 VMSTATE_UINT32(gcr, OpenPICState),
1460 VMSTATE_UINT32(vir, OpenPICState),
1461 VMSTATE_UINT32(pir, OpenPICState),
1462 VMSTATE_UINT32(spve, OpenPICState),
1463 VMSTATE_UINT32(tfrr, OpenPICState),
1464 VMSTATE_UINT32(max_irq, OpenPICState),
1465 VMSTATE_STRUCT_VARRAY_UINT32(src, OpenPICState, max_irq, 0,
1466 vmstate_openpic_irqsource, IRQSource),
d2164ad3 1467 VMSTATE_UINT32_EQUAL(nb_cpus, OpenPICState, NULL),
e5f6e732
MCA
1468 VMSTATE_STRUCT_VARRAY_UINT32(dst, OpenPICState, nb_cpus, 0,
1469 vmstate_openpic_irqdest, IRQDest),
1470 VMSTATE_STRUCT_ARRAY(timers, OpenPICState, OPENPIC_MAX_TMR, 0,
1471 vmstate_openpic_timer, OpenPICTimer),
1472 VMSTATE_STRUCT_ARRAY(msi, OpenPICState, MAX_MSI, 0,
1473 vmstate_openpic_msi, OpenPICMSI),
1474 VMSTATE_UINT32(irq_ipi0, OpenPICState),
1475 VMSTATE_UINT32(irq_tim0, OpenPICState),
1476 VMSTATE_UINT32(irq_msi, OpenPICState),
1477 VMSTATE_END_OF_LIST()
1478 }
1479};
1480
cbe72019 1481static void openpic_init(Object *obj)
dbda808a 1482{
cbe72019
AF
1483 OpenPICState *opp = OPENPIC(obj);
1484
1437c94b 1485 memory_region_init(&opp->mem, obj, "openpic", 0x40000);
cbe72019
AF
1486}
1487
1488static void openpic_realize(DeviceState *dev, Error **errp)
1489{
1490 SysBusDevice *d = SYS_BUS_DEVICE(dev);
e1766344 1491 OpenPICState *opp = OPENPIC(dev);
d0b72631 1492 int i, j;
e0dfe5b1
SW
1493 int list_count = 0;
1494 static const MemReg list_le[] = {
1495 {"glb", &openpic_glb_ops_le,
732aa6ec 1496 OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
e0dfe5b1 1497 {"tmr", &openpic_tmr_ops_le,
732aa6ec 1498 OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
e0dfe5b1 1499 {"src", &openpic_src_ops_le,
732aa6ec 1500 OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
e0dfe5b1 1501 {"cpu", &openpic_cpu_ops_le,
732aa6ec 1502 OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
e0dfe5b1 1503 {NULL}
780d16b7 1504 };
e0dfe5b1
SW
1505 static const MemReg list_be[] = {
1506 {"glb", &openpic_glb_ops_be,
732aa6ec 1507 OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
e0dfe5b1 1508 {"tmr", &openpic_tmr_ops_be,
732aa6ec 1509 OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
e0dfe5b1 1510 {"src", &openpic_src_ops_be,
732aa6ec 1511 OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
e0dfe5b1 1512 {"cpu", &openpic_cpu_ops_be,
732aa6ec 1513 OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
e0dfe5b1 1514 {NULL}
d0b72631 1515 };
e0dfe5b1
SW
1516 static const MemReg list_fsl[] = {
1517 {"msi", &openpic_msi_ops_be,
1518 OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
1519 {"summary", &openpic_summary_ops_be,
1520 OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE},
1521 {NULL}
1522 };
1523
73d963c0 1524 if (opp->nb_cpus > MAX_CPU) {
c6bd8c70
MA
1525 error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
1526 TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus,
1527 (uint64_t)0, (uint64_t)MAX_CPU);
73d963c0
MR
1528 return;
1529 }
1530
d0b72631
AG
1531 switch (opp->model) {
1532 case OPENPIC_MODEL_FSL_MPIC_20:
1533 default:
e0dfe5b1
SW
1534 opp->fsl = &fsl_mpic_20;
1535 opp->brr1 = 0x00400200;
be7c236f 1536 opp->flags |= OPENPIC_FLAG_IDR_CRIT;
d0b72631 1537 opp->nb_irqs = 80;
e0dfe5b1 1538 opp->mpic_mode_mask = GCR_MODE_MIXED;
68c2dd70 1539
e0dfe5b1
SW
1540 fsl_common_init(opp);
1541 map_list(opp, list_be, &list_count);
1542 map_list(opp, list_fsl, &list_count);
6c5e84c2 1543
e0dfe5b1 1544 break;
6c5e84c2 1545
e0dfe5b1
SW
1546 case OPENPIC_MODEL_FSL_MPIC_42:
1547 opp->fsl = &fsl_mpic_42;
1548 opp->brr1 = 0x00400402;
1549 opp->flags |= OPENPIC_FLAG_ILR;
1550 opp->nb_irqs = 196;
1551 opp->mpic_mode_mask = GCR_MODE_PROXY;
6c5e84c2 1552
e0dfe5b1
SW
1553 fsl_common_init(opp);
1554 map_list(opp, list_be, &list_count);
1555 map_list(opp, list_fsl, &list_count);
6c5e84c2 1556
d0b72631 1557 break;
6c5e84c2 1558
d0b72631
AG
1559 case OPENPIC_MODEL_RAVEN:
1560 opp->nb_irqs = RAVEN_MAX_EXT;
1561 opp->vid = VID_REVISION_1_3;
be7c236f 1562 opp->vir = VIR_GENERIC;
0fe04622 1563 opp->vector_mask = 0xFF;
be7c236f
SW
1564 opp->tfrr_reset = 4160000;
1565 opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK;
1566 opp->idr_reset = 0;
d0b72631
AG
1567 opp->max_irq = RAVEN_MAX_IRQ;
1568 opp->irq_ipi0 = RAVEN_IPI_IRQ;
1569 opp->irq_tim0 = RAVEN_TMR_IRQ;
dbbbfd60 1570 opp->brr1 = -1;
86e56a88 1571 opp->mpic_mode_mask = GCR_MODE_MIXED;
d0b72631 1572
d0b72631 1573 if (opp->nb_cpus != 1) {
cbe72019
AF
1574 error_setg(errp, "Only UP supported today");
1575 return;
d0b72631 1576 }
780d16b7 1577
58b62835
BH
1578 map_list(opp, list_le, &list_count);
1579 break;
1580
1581 case OPENPIC_MODEL_KEYLARGO:
1582 opp->nb_irqs = KEYLARGO_MAX_EXT;
1583 opp->vid = VID_REVISION_1_2;
1584 opp->vir = VIR_GENERIC;
1585 opp->vector_mask = 0xFF;
1586 opp->tfrr_reset = 4160000;
1587 opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK;
1588 opp->idr_reset = 0;
1589 opp->max_irq = KEYLARGO_MAX_IRQ;
1590 opp->irq_ipi0 = KEYLARGO_IPI_IRQ;
1591 opp->irq_tim0 = KEYLARGO_TMR_IRQ;
1592 opp->brr1 = -1;
1593 opp->mpic_mode_mask = GCR_MODE_MIXED;
1594
1595 if (opp->nb_cpus != 1) {
1596 error_setg(errp, "Only UP supported today");
1597 return;
1598 }
1599
e0dfe5b1
SW
1600 map_list(opp, list_le, &list_count);
1601 break;
780d16b7 1602 }
3b46e624 1603
d0b72631 1604 for (i = 0; i < opp->nb_cpus; i++) {
aa2ac1da 1605 opp->dst[i].irqs = g_new0(qemu_irq, OPENPIC_OUTPUT_NB);
d0b72631 1606 for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
cbe72019 1607 sysbus_init_irq(d, &opp->dst[i].irqs[j]);
d0b72631 1608 }
2ada66f9 1609
e5f6e732 1610 opp->dst[i].raised.queue_size = IRQQUEUE_SIZE_BITS;
2ada66f9 1611 opp->dst[i].raised.queue = bitmap_new(IRQQUEUE_SIZE_BITS);
e5f6e732 1612 opp->dst[i].servicing.queue_size = IRQQUEUE_SIZE_BITS;
2ada66f9 1613 opp->dst[i].servicing.queue = bitmap_new(IRQQUEUE_SIZE_BITS);
d0b72631
AG
1614 }
1615
cbe72019
AF
1616 sysbus_init_mmio(d, &opp->mem);
1617 qdev_init_gpio_in(dev, openpic_set_irq, opp->max_irq);
b7169916
AJ
1618}
1619
d0b72631
AG
1620static Property openpic_properties[] = {
1621 DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20),
1622 DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1),
1623 DEFINE_PROP_END_OF_LIST(),
1624};
71cf9e62 1625
cbe72019 1626static void openpic_class_init(ObjectClass *oc, void *data)
d0b72631 1627{
cbe72019 1628 DeviceClass *dc = DEVICE_CLASS(oc);
b7169916 1629
cbe72019 1630 dc->realize = openpic_realize;
d0b72631
AG
1631 dc->props = openpic_properties;
1632 dc->reset = openpic_reset;
e5f6e732 1633 dc->vmsd = &vmstate_openpic;
29f8dd66 1634 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
d0b72631 1635}
71cf9e62 1636
8c43a6f0 1637static const TypeInfo openpic_info = {
e1766344 1638 .name = TYPE_OPENPIC,
d0b72631
AG
1639 .parent = TYPE_SYS_BUS_DEVICE,
1640 .instance_size = sizeof(OpenPICState),
cbe72019 1641 .instance_init = openpic_init,
d0b72631
AG
1642 .class_init = openpic_class_init,
1643};
b7169916 1644
d0b72631
AG
1645static void openpic_register_types(void)
1646{
1647 type_register_static(&openpic_info);
dbda808a 1648}
d0b72631
AG
1649
1650type_init(openpic_register_types)