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