]> git.proxmox.com Git - qemu.git/blame - hw/openpic.c
openpic: Convert subregions to memory api
[qemu.git] / hw / 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 */
87ecb68b
PB
36#include "hw.h"
37#include "ppc_mac.h"
38#include "pci.h"
b7169916 39#include "openpic.h"
dbda808a 40
611493d9 41//#define DEBUG_OPENPIC
dbda808a
FB
42
43#ifdef DEBUG_OPENPIC
001faf32 44#define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
dbda808a 45#else
001faf32 46#define DPRINTF(fmt, ...) do { } while (0)
dbda808a 47#endif
dbda808a 48
cdbb912a
AG
49#define MAX_CPU 15
50#define MAX_SRC 256
dbda808a
FB
51#define MAX_TMR 4
52#define VECTOR_BITS 8
53#define MAX_IPI 4
cdbb912a 54#define MAX_IRQ (MAX_SRC + MAX_IPI + MAX_TMR)
dbda808a
FB
55#define VID 0x03 /* MPIC version ID */
56#define VENI 0x00000000 /* Vendor ID */
57
58enum {
59 IRQ_IPVP = 0,
60 IRQ_IDE,
61};
62
b7169916
AJ
63/* OpenPIC */
64#define OPENPIC_MAX_CPU 2
65#define OPENPIC_MAX_IRQ 64
66#define OPENPIC_EXT_IRQ 48
67#define OPENPIC_MAX_TMR MAX_TMR
68#define OPENPIC_MAX_IPI MAX_IPI
dbda808a 69
b7169916
AJ
70/* Interrupt definitions */
71#define OPENPIC_IRQ_FE (OPENPIC_EXT_IRQ) /* Internal functional IRQ */
72#define OPENPIC_IRQ_ERR (OPENPIC_EXT_IRQ + 1) /* Error IRQ */
73#define OPENPIC_IRQ_TIM0 (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */
74#if OPENPIC_MAX_IPI > 0
75#define OPENPIC_IRQ_IPI0 (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */
76#define OPENPIC_IRQ_DBL0 (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */
dbda808a 77#else
b7169916
AJ
78#define OPENPIC_IRQ_DBL0 (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */
79#define OPENPIC_IRQ_MBX0 (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */
dbda808a
FB
80#endif
81
780d16b7
AG
82#define OPENPIC_GLB_REG_START 0x0
83#define OPENPIC_GLB_REG_SIZE 0x10F0
84#define OPENPIC_TMR_REG_START 0x10F0
85#define OPENPIC_TMR_REG_SIZE 0x220
86#define OPENPIC_SRC_REG_START 0x10000
87#define OPENPIC_SRC_REG_SIZE (MAX_SRC * 0x20)
88#define OPENPIC_CPU_REG_START 0x20000
89#define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
90
b7169916
AJ
91/* MPIC */
92#define MPIC_MAX_CPU 1
93#define MPIC_MAX_EXT 12
94#define MPIC_MAX_INT 64
cdbb912a 95#define MPIC_MAX_IRQ MAX_IRQ
dbda808a
FB
96
97/* Interrupt definitions */
cdbb912a
AG
98/* IRQs, accessible through the IRQ region */
99#define MPIC_EXT_IRQ 0x00
100#define MPIC_INT_IRQ 0x10
101#define MPIC_MSG_IRQ 0xb0
102#define MPIC_MSI_IRQ 0xe0
103/* These are available through separate regions, but
104 for simplicity's sake mapped into the same number space */
105#define MPIC_TMR_IRQ 0x100
106#define MPIC_IPI_IRQ 0x104
b7169916
AJ
107
108#define MPIC_GLB_REG_START 0x0
109#define MPIC_GLB_REG_SIZE 0x10F0
110#define MPIC_TMR_REG_START 0x10F0
111#define MPIC_TMR_REG_SIZE 0x220
a285f1ca
AG
112#define MPIC_SRC_REG_START 0x10000
113#define MPIC_SRC_REG_SIZE (MAX_SRC * 0x20)
b7169916 114#define MPIC_CPU_REG_START 0x20000
bc59d9c9 115#define MPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
b7169916 116
3e772232
BB
117/*
118 * Block Revision Register1 (BRR1): QEMU does not fully emulate
119 * any version on MPIC. So to start with, set the IP version to 0.
120 *
121 * NOTE: This is Freescale MPIC specific register. Keep it here till
122 * this code is refactored for different variants of OPENPIC and MPIC.
123 */
124#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */
125#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */
126#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */
127
b7169916 128enum mpic_ide_bits {
0d33defb
AG
129 IDR_EP = 31,
130 IDR_CI0 = 30,
131 IDR_CI1 = 29,
132 IDR_P1 = 1,
133 IDR_P0 = 0,
b7169916
AJ
134};
135
dbda808a
FB
136#define BF_WIDTH(_bits_) \
137(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
138
139static inline void set_bit (uint32_t *field, int bit)
140{
141 field[bit >> 5] |= 1 << (bit & 0x1F);
142}
143
144static inline void reset_bit (uint32_t *field, int bit)
145{
146 field[bit >> 5] &= ~(1 << (bit & 0x1F));
147}
148
149static inline int test_bit (uint32_t *field, int bit)
150{
151 return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
152}
153
704c7e5d
AG
154static int get_current_cpu(void)
155{
156 return cpu_single_env->cpu_index;
157}
158
a8170e5e 159static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
704c7e5d 160 int idx);
a8170e5e 161static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
704c7e5d
AG
162 uint32_t val, int idx);
163
dbda808a
FB
164enum {
165 IRQ_EXTERNAL = 0x01,
166 IRQ_INTERNAL = 0x02,
167 IRQ_TIMER = 0x04,
168 IRQ_SPECIAL = 0x08,
b1d8e52e 169};
dbda808a 170
c227f099 171typedef struct IRQ_queue_t {
dbda808a
FB
172 uint32_t queue[BF_WIDTH(MAX_IRQ)];
173 int next;
174 int priority;
c227f099 175} IRQ_queue_t;
dbda808a 176
c227f099 177typedef struct IRQ_src_t {
dbda808a
FB
178 uint32_t ipvp; /* IRQ vector/priority register */
179 uint32_t ide; /* IRQ destination register */
180 int type;
181 int last_cpu;
611493d9 182 int pending; /* TRUE if IRQ is pending */
c227f099 183} IRQ_src_t;
dbda808a
FB
184
185enum IPVP_bits {
186 IPVP_MASK = 31,
187 IPVP_ACTIVITY = 30,
188 IPVP_MODE = 29,
189 IPVP_POLARITY = 23,
190 IPVP_SENSE = 22,
191};
192#define IPVP_PRIORITY_MASK (0x1F << 16)
611493d9 193#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
dbda808a
FB
194#define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1)
195#define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK)
196
c227f099 197typedef struct IRQ_dst_t {
b7169916 198 uint32_t tfrr;
dbda808a
FB
199 uint32_t pctp; /* CPU current task priority */
200 uint32_t pcsr; /* CPU sensitivity register */
c227f099
AL
201 IRQ_queue_t raised;
202 IRQ_queue_t servicing;
e9df014c 203 qemu_irq *irqs;
c227f099 204} IRQ_dst_t;
dbda808a 205
c227f099 206typedef struct openpic_t {
dbda808a 207 PCIDevice pci_dev;
23c5e4ca 208 MemoryRegion mem;
71cf9e62
FC
209
210 /* Sub-regions */
211 MemoryRegion sub_io_mem[7];
212
dbda808a
FB
213 /* Global registers */
214 uint32_t frep; /* Feature reporting register */
215 uint32_t glbc; /* Global configuration register */
216 uint32_t micr; /* MPIC interrupt configuration register */
217 uint32_t veni; /* Vendor identification register */
e9df014c 218 uint32_t pint; /* Processor initialization register */
dbda808a
FB
219 uint32_t spve; /* Spurious vector register */
220 uint32_t tifr; /* Timer frequency reporting register */
221 /* Source registers */
c227f099 222 IRQ_src_t src[MAX_IRQ];
dbda808a 223 /* Local registers per output pin */
c227f099 224 IRQ_dst_t dst[MAX_CPU];
dbda808a
FB
225 int nb_cpus;
226 /* Timer registers */
227 struct {
060fbfe1
AJ
228 uint32_t ticc; /* Global timer current count register */
229 uint32_t tibc; /* Global timer base count register */
dbda808a 230 } timers[MAX_TMR];
e9df014c
JM
231 /* IRQ out is used when in bypass mode (not implemented) */
232 qemu_irq irq_out;
b7169916
AJ
233 int max_irq;
234 int irq_ipi0;
235 int irq_tim0;
b7169916 236 void (*reset) (void *);
c227f099
AL
237 void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *);
238} openpic_t;
dbda808a 239
c227f099 240static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
dbda808a
FB
241{
242 set_bit(q->queue, n_IRQ);
243}
244
c227f099 245static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
dbda808a
FB
246{
247 reset_bit(q->queue, n_IRQ);
248}
249
c227f099 250static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
dbda808a
FB
251{
252 return test_bit(q->queue, n_IRQ);
253}
254
c227f099 255static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
dbda808a
FB
256{
257 int next, i;
258 int priority;
259
260 next = -1;
261 priority = -1;
b7169916 262 for (i = 0; i < opp->max_irq; i++) {
060fbfe1 263 if (IRQ_testbit(q, i)) {
5fafdf24 264 DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
611493d9 265 i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
060fbfe1
AJ
266 if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
267 next = i;
268 priority = IPVP_PRIORITY(opp->src[i].ipvp);
269 }
270 }
dbda808a
FB
271 }
272 q->next = next;
273 q->priority = priority;
274}
275
c227f099 276static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
dbda808a
FB
277{
278 if (q->next == -1) {
611493d9 279 /* XXX: optimize */
060fbfe1 280 IRQ_check(opp, q);
dbda808a
FB
281 }
282
283 return q->next;
284}
285
c227f099 286static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
dbda808a 287{
c227f099
AL
288 IRQ_dst_t *dst;
289 IRQ_src_t *src;
dbda808a
FB
290 int priority;
291
292 dst = &opp->dst[n_CPU];
293 src = &opp->src[n_IRQ];
294 priority = IPVP_PRIORITY(src->ipvp);
295 if (priority <= dst->pctp) {
060fbfe1 296 /* Too low priority */
e9df014c
JM
297 DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
298 __func__, n_IRQ, n_CPU);
060fbfe1 299 return;
dbda808a
FB
300 }
301 if (IRQ_testbit(&dst->raised, n_IRQ)) {
060fbfe1 302 /* Interrupt miss */
e9df014c
JM
303 DPRINTF("%s: IRQ %d was missed on CPU %d\n",
304 __func__, n_IRQ, n_CPU);
060fbfe1 305 return;
dbda808a
FB
306 }
307 set_bit(&src->ipvp, IPVP_ACTIVITY);
308 IRQ_setbit(&dst->raised, n_IRQ);
e9df014c
JM
309 if (priority < dst->raised.priority) {
310 /* An higher priority IRQ is already raised */
311 DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
312 __func__, n_IRQ, dst->raised.next, n_CPU);
313 return;
314 }
315 IRQ_get_next(opp, &dst->raised);
316 if (IRQ_get_next(opp, &dst->servicing) != -1 &&
24865167 317 priority <= dst->servicing.priority) {
e9df014c
JM
318 DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
319 __func__, n_IRQ, dst->servicing.next, n_CPU);
320 /* Already servicing a higher priority IRQ */
321 return;
dbda808a 322 }
e9df014c 323 DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
b7169916 324 opp->irq_raise(opp, n_CPU, src);
dbda808a
FB
325}
326
611493d9 327/* update pic state because registers for n_IRQ have changed value */
c227f099 328static void openpic_update_irq(openpic_t *opp, int n_IRQ)
dbda808a 329{
c227f099 330 IRQ_src_t *src;
dbda808a
FB
331 int i;
332
333 src = &opp->src[n_IRQ];
611493d9
FB
334
335 if (!src->pending) {
336 /* no irq pending */
e9df014c 337 DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
611493d9
FB
338 return;
339 }
340 if (test_bit(&src->ipvp, IPVP_MASK)) {
060fbfe1 341 /* Interrupt source is disabled */
e9df014c 342 DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
060fbfe1 343 return;
dbda808a
FB
344 }
345 if (IPVP_PRIORITY(src->ipvp) == 0) {
060fbfe1 346 /* Priority set to zero */
e9df014c 347 DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
060fbfe1 348 return;
dbda808a 349 }
611493d9
FB
350 if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
351 /* IRQ already active */
e9df014c 352 DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
611493d9
FB
353 return;
354 }
dbda808a 355 if (src->ide == 0x00000000) {
060fbfe1 356 /* No target */
e9df014c 357 DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
060fbfe1 358 return;
dbda808a 359 }
611493d9 360
e9df014c
JM
361 if (src->ide == (1 << src->last_cpu)) {
362 /* Only one CPU is allowed to receive this IRQ */
363 IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
364 } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
611493d9
FB
365 /* Directed delivery mode */
366 for (i = 0; i < opp->nb_cpus; i++) {
367 if (test_bit(&src->ide, i))
368 IRQ_local_pipe(opp, i, n_IRQ);
369 }
dbda808a 370 } else {
611493d9 371 /* Distributed delivery mode */
e9df014c
JM
372 for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
373 if (i == opp->nb_cpus)
611493d9
FB
374 i = 0;
375 if (test_bit(&src->ide, i)) {
376 IRQ_local_pipe(opp, i, n_IRQ);
377 src->last_cpu = i;
378 break;
379 }
380 }
381 }
382}
383
d537cf6c 384static void openpic_set_irq(void *opaque, int n_IRQ, int level)
611493d9 385{
c227f099
AL
386 openpic_t *opp = opaque;
387 IRQ_src_t *src;
611493d9
FB
388
389 src = &opp->src[n_IRQ];
5fafdf24 390 DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
611493d9
FB
391 n_IRQ, level, src->ipvp);
392 if (test_bit(&src->ipvp, IPVP_SENSE)) {
393 /* level-sensitive irq */
394 src->pending = level;
395 if (!level)
396 reset_bit(&src->ipvp, IPVP_ACTIVITY);
397 } else {
398 /* edge-sensitive irq */
399 if (level)
400 src->pending = 1;
dbda808a 401 }
611493d9 402 openpic_update_irq(opp, n_IRQ);
dbda808a
FB
403}
404
67b55785 405static void openpic_reset (void *opaque)
dbda808a 406{
c227f099 407 openpic_t *opp = (openpic_t *)opaque;
dbda808a
FB
408 int i;
409
410 opp->glbc = 0x80000000;
f8407028 411 /* Initialise controller registers */
b7169916 412 opp->frep = ((OPENPIC_EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
dbda808a 413 opp->veni = VENI;
e9df014c 414 opp->pint = 0x00000000;
dbda808a
FB
415 opp->spve = 0x000000FF;
416 opp->tifr = 0x003F7A00;
417 /* ? */
418 opp->micr = 0x00000000;
419 /* Initialise IRQ sources */
b7169916 420 for (i = 0; i < opp->max_irq; i++) {
060fbfe1
AJ
421 opp->src[i].ipvp = 0xA0000000;
422 opp->src[i].ide = 0x00000000;
dbda808a
FB
423 }
424 /* Initialise IRQ destinations */
e9df014c 425 for (i = 0; i < MAX_CPU; i++) {
060fbfe1
AJ
426 opp->dst[i].pctp = 0x0000000F;
427 opp->dst[i].pcsr = 0x00000000;
428 memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
d14ed254 429 opp->dst[i].raised.next = -1;
060fbfe1 430 memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
d14ed254 431 opp->dst[i].servicing.next = -1;
dbda808a
FB
432 }
433 /* Initialise timers */
434 for (i = 0; i < MAX_TMR; i++) {
060fbfe1
AJ
435 opp->timers[i].ticc = 0x00000000;
436 opp->timers[i].tibc = 0x80000000;
dbda808a 437 }
dbda808a
FB
438 /* Go out of RESET state */
439 opp->glbc = 0x00000000;
440}
441
8d3a8c1e 442static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ)
dbda808a 443{
8d3a8c1e
AG
444 return opp->src[n_IRQ].ide;
445}
dbda808a 446
8d3a8c1e
AG
447static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ)
448{
449 return opp->src[n_IRQ].ipvp;
dbda808a
FB
450}
451
11de8b71 452static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val)
dbda808a
FB
453{
454 uint32_t tmp;
455
11de8b71
AG
456 tmp = val & 0xC0000000;
457 tmp |= val & ((1ULL << MAX_CPU) - 1);
458 opp->src[n_IRQ].ide = tmp;
459 DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
460}
461
462static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val)
463{
464 /* NOTE: not fully accurate for special IRQs, but simple and sufficient */
465 /* ACTIVITY bit is read-only */
466 opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000)
467 | (val & 0x800F00FF);
468 openpic_update_irq(opp, n_IRQ);
469 DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
470 opp->src[n_IRQ].ipvp);
dbda808a
FB
471}
472
b9b2aaa3
AG
473static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
474 unsigned len)
dbda808a 475{
c227f099
AL
476 openpic_t *opp = opaque;
477 IRQ_dst_t *dst;
e9df014c 478 int idx;
dbda808a 479
0bf9e31a 480 DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
dbda808a
FB
481 if (addr & 0xF)
482 return;
dbda808a 483 switch (addr) {
3e772232
BB
484 case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
485 break;
704c7e5d
AG
486 case 0x40:
487 case 0x50:
488 case 0x60:
489 case 0x70:
490 case 0x80:
491 case 0x90:
492 case 0xA0:
493 case 0xB0:
494 openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
dbda808a 495 break;
704c7e5d 496 case 0x1000: /* FREP */
dbda808a 497 break;
704c7e5d 498 case 0x1020: /* GLBC */
b7169916
AJ
499 if (val & 0x80000000 && opp->reset)
500 opp->reset(opp);
dbda808a 501 opp->glbc = val & ~0x80000000;
060fbfe1 502 break;
704c7e5d 503 case 0x1080: /* VENI */
060fbfe1 504 break;
704c7e5d 505 case 0x1090: /* PINT */
e9df014c
JM
506 for (idx = 0; idx < opp->nb_cpus; idx++) {
507 if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
508 DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
509 dst = &opp->dst[idx];
510 qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
511 } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
512 DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
513 dst = &opp->dst[idx];
514 qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
515 }
dbda808a 516 }
e9df014c 517 opp->pint = val;
060fbfe1 518 break;
704c7e5d
AG
519 case 0x10A0: /* IPI_IPVP */
520 case 0x10B0:
521 case 0x10C0:
522 case 0x10D0:
dbda808a
FB
523 {
524 int idx;
704c7e5d 525 idx = (addr - 0x10A0) >> 4;
11de8b71 526 write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val);
dbda808a
FB
527 }
528 break;
704c7e5d 529 case 0x10E0: /* SPVE */
dbda808a
FB
530 opp->spve = val & 0x000000FF;
531 break;
704c7e5d 532 case 0x10F0: /* TIFR */
dbda808a 533 opp->tifr = val;
060fbfe1 534 break;
dbda808a
FB
535 default:
536 break;
537 }
538}
539
b9b2aaa3 540static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
dbda808a 541{
c227f099 542 openpic_t *opp = opaque;
dbda808a
FB
543 uint32_t retval;
544
0bf9e31a 545 DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
dbda808a
FB
546 retval = 0xFFFFFFFF;
547 if (addr & 0xF)
548 return retval;
dbda808a 549 switch (addr) {
704c7e5d 550 case 0x1000: /* FREP */
dbda808a
FB
551 retval = opp->frep;
552 break;
704c7e5d 553 case 0x1020: /* GLBC */
dbda808a 554 retval = opp->glbc;
060fbfe1 555 break;
704c7e5d 556 case 0x1080: /* VENI */
dbda808a 557 retval = opp->veni;
060fbfe1 558 break;
704c7e5d 559 case 0x1090: /* PINT */
dbda808a 560 retval = 0x00000000;
060fbfe1 561 break;
3e772232 562 case 0x00: /* Block Revision Register1 (BRR1) */
704c7e5d
AG
563 case 0x40:
564 case 0x50:
565 case 0x60:
566 case 0x70:
567 case 0x80:
568 case 0x90:
569 case 0xA0:
dbda808a 570 case 0xB0:
704c7e5d
AG
571 retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
572 break;
573 case 0x10A0: /* IPI_IPVP */
574 case 0x10B0:
575 case 0x10C0:
576 case 0x10D0:
dbda808a
FB
577 {
578 int idx;
704c7e5d 579 idx = (addr - 0x10A0) >> 4;
8d3a8c1e 580 retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx);
dbda808a 581 }
060fbfe1 582 break;
704c7e5d 583 case 0x10E0: /* SPVE */
dbda808a
FB
584 retval = opp->spve;
585 break;
704c7e5d 586 case 0x10F0: /* TIFR */
dbda808a 587 retval = opp->tifr;
060fbfe1 588 break;
dbda808a
FB
589 default:
590 break;
591 }
592 DPRINTF("%s: => %08x\n", __func__, retval);
dbda808a
FB
593
594 return retval;
595}
596
b9b2aaa3
AG
597static void openpic_timer_write(void *opaque, hwaddr addr, uint64_t val,
598 unsigned len)
dbda808a 599{
c227f099 600 openpic_t *opp = opaque;
dbda808a
FB
601 int idx;
602
603 DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
604 if (addr & 0xF)
605 return;
38ae51a8 606 addr -= 0x10;
dbda808a
FB
607 addr &= 0xFFFF;
608 idx = (addr & 0xFFF0) >> 6;
609 addr = addr & 0x30;
610 switch (addr) {
611 case 0x00: /* TICC */
612 break;
613 case 0x10: /* TIBC */
060fbfe1
AJ
614 if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
615 (val & 0x80000000) == 0 &&
dbda808a 616 (opp->timers[idx].tibc & 0x80000000) != 0)
060fbfe1
AJ
617 opp->timers[idx].ticc &= ~0x80000000;
618 opp->timers[idx].tibc = val;
619 break;
dbda808a 620 case 0x20: /* TIVP */
11de8b71 621 write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val);
060fbfe1 622 break;
dbda808a 623 case 0x30: /* TIDE */
11de8b71 624 write_IRQreg_ide(opp, opp->irq_tim0 + idx, val);
060fbfe1 625 break;
dbda808a
FB
626 }
627}
628
b9b2aaa3 629static uint64_t openpic_timer_read(void *opaque, hwaddr addr, unsigned len)
dbda808a 630{
c227f099 631 openpic_t *opp = opaque;
dbda808a
FB
632 uint32_t retval;
633 int idx;
634
635 DPRINTF("%s: addr %08x\n", __func__, addr);
636 retval = 0xFFFFFFFF;
637 if (addr & 0xF)
638 return retval;
38ae51a8 639 addr -= 0x10;
dbda808a
FB
640 addr &= 0xFFFF;
641 idx = (addr & 0xFFF0) >> 6;
642 addr = addr & 0x30;
643 switch (addr) {
644 case 0x00: /* TICC */
060fbfe1 645 retval = opp->timers[idx].ticc;
dbda808a
FB
646 break;
647 case 0x10: /* TIBC */
060fbfe1
AJ
648 retval = opp->timers[idx].tibc;
649 break;
dbda808a 650 case 0x20: /* TIPV */
8d3a8c1e 651 retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx);
060fbfe1 652 break;
dbda808a 653 case 0x30: /* TIDE */
8d3a8c1e 654 retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx);
060fbfe1 655 break;
dbda808a
FB
656 }
657 DPRINTF("%s: => %08x\n", __func__, retval);
dbda808a
FB
658
659 return retval;
660}
661
b9b2aaa3
AG
662static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
663 unsigned len)
dbda808a 664{
c227f099 665 openpic_t *opp = opaque;
dbda808a
FB
666 int idx;
667
668 DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
669 if (addr & 0xF)
670 return;
dbda808a
FB
671 addr = addr & 0xFFF0;
672 idx = addr >> 5;
673 if (addr & 0x10) {
674 /* EXDE / IFEDE / IEEDE */
11de8b71 675 write_IRQreg_ide(opp, idx, val);
dbda808a
FB
676 } else {
677 /* EXVP / IFEVP / IEEVP */
11de8b71 678 write_IRQreg_ipvp(opp, idx, val);
dbda808a
FB
679 }
680}
681
b9b2aaa3 682static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
dbda808a 683{
c227f099 684 openpic_t *opp = opaque;
dbda808a
FB
685 uint32_t retval;
686 int idx;
687
688 DPRINTF("%s: addr %08x\n", __func__, addr);
689 retval = 0xFFFFFFFF;
690 if (addr & 0xF)
691 return retval;
692 addr = addr & 0xFFF0;
693 idx = addr >> 5;
694 if (addr & 0x10) {
695 /* EXDE / IFEDE / IEEDE */
8d3a8c1e 696 retval = read_IRQreg_ide(opp, idx);
dbda808a
FB
697 } else {
698 /* EXVP / IFEVP / IEEVP */
8d3a8c1e 699 retval = read_IRQreg_ipvp(opp, idx);
dbda808a
FB
700 }
701 DPRINTF("%s: => %08x\n", __func__, retval);
dbda808a
FB
702
703 return retval;
704}
705
a8170e5e 706static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
704c7e5d 707 uint32_t val, int idx)
dbda808a 708{
c227f099
AL
709 openpic_t *opp = opaque;
710 IRQ_src_t *src;
711 IRQ_dst_t *dst;
704c7e5d 712 int s_IRQ, n_IRQ;
dbda808a 713
704c7e5d
AG
714 DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx,
715 addr, val);
dbda808a
FB
716 if (addr & 0xF)
717 return;
dbda808a
FB
718 dst = &opp->dst[idx];
719 addr &= 0xFF0;
720 switch (addr) {
704c7e5d 721 case 0x40: /* IPIDR */
dbda808a
FB
722 case 0x50:
723 case 0x60:
724 case 0x70:
725 idx = (addr - 0x40) >> 4;
a675155e 726 /* we use IDE as mask which CPUs to deliver the IPI to still. */
11de8b71
AG
727 write_IRQreg_ide(opp, opp->irq_ipi0 + idx,
728 opp->src[opp->irq_ipi0 + idx].ide | val);
b7169916
AJ
729 openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
730 openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
dbda808a 731 break;
dbda808a 732 case 0x80: /* PCTP */
060fbfe1
AJ
733 dst->pctp = val & 0x0000000F;
734 break;
dbda808a 735 case 0x90: /* WHOAMI */
060fbfe1
AJ
736 /* Read-only register */
737 break;
dbda808a 738 case 0xA0: /* PIAC */
060fbfe1
AJ
739 /* Read-only register */
740 break;
dbda808a
FB
741 case 0xB0: /* PEOI */
742 DPRINTF("PEOI\n");
060fbfe1
AJ
743 s_IRQ = IRQ_get_next(opp, &dst->servicing);
744 IRQ_resetbit(&dst->servicing, s_IRQ);
745 dst->servicing.next = -1;
746 /* Set up next servicing IRQ */
747 s_IRQ = IRQ_get_next(opp, &dst->servicing);
e9df014c
JM
748 /* Check queued interrupts. */
749 n_IRQ = IRQ_get_next(opp, &dst->raised);
750 src = &opp->src[n_IRQ];
751 if (n_IRQ != -1 &&
752 (s_IRQ == -1 ||
753 IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
754 DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
755 idx, n_IRQ);
b7169916 756 opp->irq_raise(opp, idx, src);
e9df014c 757 }
060fbfe1 758 break;
dbda808a
FB
759 default:
760 break;
761 }
762}
763
b9b2aaa3
AG
764static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val,
765 unsigned len)
704c7e5d
AG
766{
767 openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
768}
769
a8170e5e 770static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
704c7e5d 771 int idx)
dbda808a 772{
c227f099
AL
773 openpic_t *opp = opaque;
774 IRQ_src_t *src;
775 IRQ_dst_t *dst;
dbda808a 776 uint32_t retval;
704c7e5d 777 int n_IRQ;
3b46e624 778
704c7e5d 779 DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr);
dbda808a
FB
780 retval = 0xFFFFFFFF;
781 if (addr & 0xF)
782 return retval;
dbda808a
FB
783 dst = &opp->dst[idx];
784 addr &= 0xFF0;
785 switch (addr) {
3e772232
BB
786 case 0x00: /* Block Revision Register1 (BRR1) */
787 retval = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN;
788 break;
dbda808a 789 case 0x80: /* PCTP */
060fbfe1
AJ
790 retval = dst->pctp;
791 break;
dbda808a 792 case 0x90: /* WHOAMI */
060fbfe1
AJ
793 retval = idx;
794 break;
dbda808a 795 case 0xA0: /* PIAC */
e9df014c
JM
796 DPRINTF("Lower OpenPIC INT output\n");
797 qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
060fbfe1 798 n_IRQ = IRQ_get_next(opp, &dst->raised);
dbda808a 799 DPRINTF("PIAC: irq=%d\n", n_IRQ);
060fbfe1
AJ
800 if (n_IRQ == -1) {
801 /* No more interrupt pending */
e9df014c 802 retval = IPVP_VECTOR(opp->spve);
060fbfe1
AJ
803 } else {
804 src = &opp->src[n_IRQ];
805 if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
806 !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
807 /* - Spurious level-sensitive IRQ
808 * - Priorities has been changed
809 * and the pending IRQ isn't allowed anymore
810 */
811 reset_bit(&src->ipvp, IPVP_ACTIVITY);
812 retval = IPVP_VECTOR(opp->spve);
813 } else {
814 /* IRQ enter servicing state */
815 IRQ_setbit(&dst->servicing, n_IRQ);
816 retval = IPVP_VECTOR(src->ipvp);
817 }
818 IRQ_resetbit(&dst->raised, n_IRQ);
819 dst->raised.next = -1;
820 if (!test_bit(&src->ipvp, IPVP_SENSE)) {
611493d9 821 /* edge-sensitive IRQ */
060fbfe1 822 reset_bit(&src->ipvp, IPVP_ACTIVITY);
611493d9
FB
823 src->pending = 0;
824 }
a675155e
AG
825
826 if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) {
827 src->ide &= ~(1 << idx);
828 if (src->ide && !test_bit(&src->ipvp, IPVP_SENSE)) {
829 /* trigger on CPUs that didn't know about it yet */
830 openpic_set_irq(opp, n_IRQ, 1);
831 openpic_set_irq(opp, n_IRQ, 0);
832 /* if all CPUs knew about it, set active bit again */
833 set_bit(&src->ipvp, IPVP_ACTIVITY);
834 }
835 }
060fbfe1
AJ
836 }
837 break;
dbda808a 838 case 0xB0: /* PEOI */
060fbfe1
AJ
839 retval = 0;
840 break;
dbda808a
FB
841 default:
842 break;
843 }
844 DPRINTF("%s: => %08x\n", __func__, retval);
dbda808a
FB
845
846 return retval;
847}
848
b9b2aaa3 849static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len)
704c7e5d
AG
850{
851 return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
852}
853
780d16b7
AG
854static const MemoryRegionOps openpic_glb_ops = {
855 .write = openpic_gbl_write,
856 .read = openpic_gbl_read,
857 .endianness = DEVICE_LITTLE_ENDIAN,
858 .impl = {
859 .min_access_size = 4,
860 .max_access_size = 4,
861 },
862};
dbda808a 863
780d16b7
AG
864static const MemoryRegionOps openpic_tmr_ops = {
865 .write = openpic_timer_write,
866 .read = openpic_timer_read,
867 .endianness = DEVICE_LITTLE_ENDIAN,
868 .impl = {
869 .min_access_size = 4,
870 .max_access_size = 4,
871 },
872};
dbda808a 873
780d16b7
AG
874static const MemoryRegionOps openpic_cpu_ops = {
875 .write = openpic_cpu_write,
876 .read = openpic_cpu_read,
877 .endianness = DEVICE_LITTLE_ENDIAN,
878 .impl = {
879 .min_access_size = 4,
880 .max_access_size = 4,
881 },
882};
dbda808a 883
780d16b7
AG
884static const MemoryRegionOps openpic_src_ops = {
885 .write = openpic_src_write,
886 .read = openpic_src_read,
23c5e4ca 887 .endianness = DEVICE_LITTLE_ENDIAN,
b9b2aaa3
AG
888 .impl = {
889 .min_access_size = 4,
890 .max_access_size = 4,
891 },
23c5e4ca
AK
892};
893
c227f099 894static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
67b55785
BS
895{
896 unsigned int i;
897
898 for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
899 qemu_put_be32s(f, &q->queue[i]);
900
901 qemu_put_sbe32s(f, &q->next);
902 qemu_put_sbe32s(f, &q->priority);
903}
904
905static void openpic_save(QEMUFile* f, void *opaque)
906{
c227f099 907 openpic_t *opp = (openpic_t *)opaque;
67b55785
BS
908 unsigned int i;
909
910 qemu_put_be32s(f, &opp->frep);
911 qemu_put_be32s(f, &opp->glbc);
912 qemu_put_be32s(f, &opp->micr);
913 qemu_put_be32s(f, &opp->veni);
914 qemu_put_be32s(f, &opp->pint);
915 qemu_put_be32s(f, &opp->spve);
916 qemu_put_be32s(f, &opp->tifr);
917
b7169916 918 for (i = 0; i < opp->max_irq; i++) {
67b55785
BS
919 qemu_put_be32s(f, &opp->src[i].ipvp);
920 qemu_put_be32s(f, &opp->src[i].ide);
921 qemu_put_sbe32s(f, &opp->src[i].type);
922 qemu_put_sbe32s(f, &opp->src[i].last_cpu);
923 qemu_put_sbe32s(f, &opp->src[i].pending);
924 }
925
b7169916
AJ
926 qemu_put_sbe32s(f, &opp->nb_cpus);
927
928 for (i = 0; i < opp->nb_cpus; i++) {
929 qemu_put_be32s(f, &opp->dst[i].tfrr);
67b55785
BS
930 qemu_put_be32s(f, &opp->dst[i].pctp);
931 qemu_put_be32s(f, &opp->dst[i].pcsr);
932 openpic_save_IRQ_queue(f, &opp->dst[i].raised);
933 openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
934 }
935
67b55785
BS
936 for (i = 0; i < MAX_TMR; i++) {
937 qemu_put_be32s(f, &opp->timers[i].ticc);
938 qemu_put_be32s(f, &opp->timers[i].tibc);
939 }
940
67b55785
BS
941 pci_device_save(&opp->pci_dev, f);
942}
943
c227f099 944static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
67b55785
BS
945{
946 unsigned int i;
947
948 for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
949 qemu_get_be32s(f, &q->queue[i]);
950
951 qemu_get_sbe32s(f, &q->next);
952 qemu_get_sbe32s(f, &q->priority);
953}
954
955static int openpic_load(QEMUFile* f, void *opaque, int version_id)
956{
c227f099 957 openpic_t *opp = (openpic_t *)opaque;
67b55785
BS
958 unsigned int i;
959
960 if (version_id != 1)
961 return -EINVAL;
962
963 qemu_get_be32s(f, &opp->frep);
964 qemu_get_be32s(f, &opp->glbc);
965 qemu_get_be32s(f, &opp->micr);
966 qemu_get_be32s(f, &opp->veni);
967 qemu_get_be32s(f, &opp->pint);
968 qemu_get_be32s(f, &opp->spve);
969 qemu_get_be32s(f, &opp->tifr);
970
b7169916 971 for (i = 0; i < opp->max_irq; i++) {
67b55785
BS
972 qemu_get_be32s(f, &opp->src[i].ipvp);
973 qemu_get_be32s(f, &opp->src[i].ide);
974 qemu_get_sbe32s(f, &opp->src[i].type);
975 qemu_get_sbe32s(f, &opp->src[i].last_cpu);
976 qemu_get_sbe32s(f, &opp->src[i].pending);
977 }
978
b7169916
AJ
979 qemu_get_sbe32s(f, &opp->nb_cpus);
980
981 for (i = 0; i < opp->nb_cpus; i++) {
982 qemu_get_be32s(f, &opp->dst[i].tfrr);
67b55785
BS
983 qemu_get_be32s(f, &opp->dst[i].pctp);
984 qemu_get_be32s(f, &opp->dst[i].pcsr);
985 openpic_load_IRQ_queue(f, &opp->dst[i].raised);
986 openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
987 }
988
67b55785
BS
989 for (i = 0; i < MAX_TMR; i++) {
990 qemu_get_be32s(f, &opp->timers[i].ticc);
991 qemu_get_be32s(f, &opp->timers[i].tibc);
992 }
993
67b55785
BS
994 return pci_device_load(&opp->pci_dev, f);
995}
996
c227f099 997static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
b7169916
AJ
998{
999 qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1000}
1001
8a5faa1d 1002qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
e9df014c 1003 qemu_irq **irqs, qemu_irq irq_out)
dbda808a 1004{
c227f099 1005 openpic_t *opp;
dbda808a 1006 int i, m;
780d16b7
AG
1007 struct {
1008 const char *name;
1009 MemoryRegionOps const *ops;
1010 hwaddr start_addr;
1011 ram_addr_t size;
1012 } const list[] = {
1013 {"glb", &openpic_glb_ops, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
1014 {"tmr", &openpic_tmr_ops, OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
1015 {"src", &openpic_src_ops, OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
1016 {"cpu", &openpic_cpu_ops, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
1017 };
3b46e624 1018
dbda808a
FB
1019 /* XXX: for now, only one CPU is supported */
1020 if (nb_cpus != 1)
1021 return NULL;
8a5faa1d 1022 opp = g_malloc0(sizeof(openpic_t));
780d16b7
AG
1023
1024 memory_region_init(&opp->mem, "openpic", 0x40000);
1025
1026 for (i = 0; i < ARRAY_SIZE(list); i++) {
1027
1028 memory_region_init_io(&opp->sub_io_mem[i], list[i].ops, opp,
1029 list[i].name, list[i].size);
1030
1031 memory_region_add_subregion(&opp->mem, list[i].start_addr,
1032 &opp->sub_io_mem[i]);
1033 }
3b46e624 1034
91d848eb 1035 // isu_base &= 0xFFFC0000;
dbda808a 1036 opp->nb_cpus = nb_cpus;
b7169916
AJ
1037 opp->max_irq = OPENPIC_MAX_IRQ;
1038 opp->irq_ipi0 = OPENPIC_IRQ_IPI0;
1039 opp->irq_tim0 = OPENPIC_IRQ_TIM0;
dbda808a 1040 /* Set IRQ types */
b7169916 1041 for (i = 0; i < OPENPIC_EXT_IRQ; i++) {
dbda808a
FB
1042 opp->src[i].type = IRQ_EXTERNAL;
1043 }
b7169916 1044 for (; i < OPENPIC_IRQ_TIM0; i++) {
dbda808a
FB
1045 opp->src[i].type = IRQ_SPECIAL;
1046 }
b7169916 1047 m = OPENPIC_IRQ_IPI0;
dbda808a
FB
1048 for (; i < m; i++) {
1049 opp->src[i].type = IRQ_TIMER;
1050 }
b7169916 1051 for (; i < OPENPIC_MAX_IRQ; i++) {
dbda808a
FB
1052 opp->src[i].type = IRQ_INTERNAL;
1053 }
7668a27f 1054 for (i = 0; i < nb_cpus; i++)
e9df014c
JM
1055 opp->dst[i].irqs = irqs[i];
1056 opp->irq_out = irq_out;
67b55785 1057
0be71e32
AW
1058 register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2,
1059 openpic_save, openpic_load, opp);
a08d4367 1060 qemu_register_reset(openpic_reset, opp);
b7169916
AJ
1061
1062 opp->irq_raise = openpic_irq_raise;
1063 opp->reset = openpic_reset;
1064
23c5e4ca
AK
1065 if (pmem)
1066 *pmem = &opp->mem;
e9df014c 1067
b7169916
AJ
1068 return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
1069}
1070
c227f099 1071static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src)
b7169916
AJ
1072{
1073 int n_ci = IDR_CI0 - n_CPU;
0bf9e31a 1074
b7169916
AJ
1075 if(test_bit(&src->ide, n_ci)) {
1076 qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]);
1077 }
1078 else {
1079 qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1080 }
1081}
1082
1083static void mpic_reset (void *opaque)
1084{
c227f099 1085 openpic_t *mpp = (openpic_t *)opaque;
b7169916
AJ
1086 int i;
1087
1088 mpp->glbc = 0x80000000;
1089 /* Initialise controller registers */
bbc58422 1090 mpp->frep = 0x004f0002 | ((mpp->nb_cpus - 1) << 8);
b7169916
AJ
1091 mpp->veni = VENI;
1092 mpp->pint = 0x00000000;
1093 mpp->spve = 0x0000FFFF;
1094 /* Initialise IRQ sources */
1095 for (i = 0; i < mpp->max_irq; i++) {
1096 mpp->src[i].ipvp = 0x80800000;
1097 mpp->src[i].ide = 0x00000001;
1098 }
9250fd24
AG
1099 /* Set IDE for IPIs to 0 so we don't get spurious interrupts */
1100 for (i = mpp->irq_ipi0; i < (mpp->irq_ipi0 + MAX_IPI); i++) {
1101 mpp->src[i].ide = 0;
1102 }
b7169916
AJ
1103 /* Initialise IRQ destinations */
1104 for (i = 0; i < MAX_CPU; i++) {
1105 mpp->dst[i].pctp = 0x0000000F;
1106 mpp->dst[i].tfrr = 0x00000000;
c227f099 1107 memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t));
b7169916 1108 mpp->dst[i].raised.next = -1;
c227f099 1109 memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
b7169916
AJ
1110 mpp->dst[i].servicing.next = -1;
1111 }
1112 /* Initialise timers */
1113 for (i = 0; i < MAX_TMR; i++) {
1114 mpp->timers[i].ticc = 0x00000000;
1115 mpp->timers[i].tibc = 0x80000000;
1116 }
1117 /* Go out of RESET state */
1118 mpp->glbc = 0x00000000;
1119}
1120
b9b2aaa3
AG
1121static void mpic_timer_write(void *opaque, hwaddr addr, uint64_t val,
1122 unsigned len)
b7169916 1123{
c227f099 1124 openpic_t *mpp = opaque;
b7169916
AJ
1125 int idx, cpu;
1126
0bf9e31a 1127 DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
b7169916
AJ
1128 if (addr & 0xF)
1129 return;
b7169916
AJ
1130 cpu = addr >> 12;
1131 idx = (addr >> 6) & 0x3;
1132 switch (addr & 0x30) {
1133 case 0x00: /* gtccr */
1134 break;
1135 case 0x10: /* gtbcr */
1136 if ((mpp->timers[idx].ticc & 0x80000000) != 0 &&
1137 (val & 0x80000000) == 0 &&
1138 (mpp->timers[idx].tibc & 0x80000000) != 0)
1139 mpp->timers[idx].ticc &= ~0x80000000;
1140 mpp->timers[idx].tibc = val;
1141 break;
1142 case 0x20: /* GTIVPR */
11de8b71 1143 write_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx, val);
b7169916
AJ
1144 break;
1145 case 0x30: /* GTIDR & TFRR */
1146 if ((addr & 0xF0) == 0xF0)
1147 mpp->dst[cpu].tfrr = val;
1148 else
11de8b71 1149 write_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx, val);
b7169916
AJ
1150 break;
1151 }
1152}
1153
b9b2aaa3 1154static uint64_t mpic_timer_read(void *opaque, hwaddr addr, unsigned len)
b7169916 1155{
c227f099 1156 openpic_t *mpp = opaque;
b7169916
AJ
1157 uint32_t retval;
1158 int idx, cpu;
1159
0bf9e31a 1160 DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
b7169916
AJ
1161 retval = 0xFFFFFFFF;
1162 if (addr & 0xF)
1163 return retval;
b7169916
AJ
1164 cpu = addr >> 12;
1165 idx = (addr >> 6) & 0x3;
1166 switch (addr & 0x30) {
1167 case 0x00: /* gtccr */
1168 retval = mpp->timers[idx].ticc;
1169 break;
1170 case 0x10: /* gtbcr */
1171 retval = mpp->timers[idx].tibc;
1172 break;
1173 case 0x20: /* TIPV */
8d3a8c1e 1174 retval = read_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx);
b7169916
AJ
1175 break;
1176 case 0x30: /* TIDR */
1177 if ((addr &0xF0) == 0XF0)
1178 retval = mpp->dst[cpu].tfrr;
1179 else
8d3a8c1e 1180 retval = read_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx);
b7169916
AJ
1181 break;
1182 }
1183 DPRINTF("%s: => %08x\n", __func__, retval);
1184
1185 return retval;
1186}
1187
71cf9e62 1188static const MemoryRegionOps mpic_glb_ops = {
b9b2aaa3
AG
1189 .write = openpic_gbl_write,
1190 .read = openpic_gbl_read,
71cf9e62 1191 .endianness = DEVICE_BIG_ENDIAN,
b9b2aaa3
AG
1192 .impl = {
1193 .min_access_size = 4,
1194 .max_access_size = 4,
1195 },
b7169916
AJ
1196};
1197
71cf9e62 1198static const MemoryRegionOps mpic_tmr_ops = {
b9b2aaa3
AG
1199 .write = mpic_timer_write,
1200 .read = mpic_timer_read,
71cf9e62 1201 .endianness = DEVICE_BIG_ENDIAN,
b9b2aaa3
AG
1202 .impl = {
1203 .min_access_size = 4,
1204 .max_access_size = 4,
1205 },
b7169916
AJ
1206};
1207
71cf9e62 1208static const MemoryRegionOps mpic_cpu_ops = {
b9b2aaa3
AG
1209 .write = openpic_cpu_write,
1210 .read = openpic_cpu_read,
71cf9e62 1211 .endianness = DEVICE_BIG_ENDIAN,
b9b2aaa3
AG
1212 .impl = {
1213 .min_access_size = 4,
1214 .max_access_size = 4,
1215 },
b7169916
AJ
1216};
1217
cdbb912a 1218static const MemoryRegionOps mpic_irq_ops = {
a285f1ca
AG
1219 .write = openpic_src_write,
1220 .read = openpic_src_read,
71cf9e62 1221 .endianness = DEVICE_BIG_ENDIAN,
cdbb912a
AG
1222 .impl = {
1223 .min_access_size = 4,
1224 .max_access_size = 4,
71cf9e62 1225 },
b7169916
AJ
1226};
1227
a8170e5e 1228qemu_irq *mpic_init (MemoryRegion *address_space, hwaddr base,
71cf9e62 1229 int nb_cpus, qemu_irq **irqs, qemu_irq irq_out)
b7169916 1230{
71cf9e62
FC
1231 openpic_t *mpp;
1232 int i;
b7169916 1233 struct {
71cf9e62
FC
1234 const char *name;
1235 MemoryRegionOps const *ops;
a8170e5e 1236 hwaddr start_addr;
71cf9e62 1237 ram_addr_t size;
dfebf62b 1238 } const list[] = {
71cf9e62
FC
1239 {"glb", &mpic_glb_ops, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
1240 {"tmr", &mpic_tmr_ops, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
a285f1ca 1241 {"src", &mpic_irq_ops, MPIC_SRC_REG_START, MPIC_SRC_REG_SIZE},
71cf9e62 1242 {"cpu", &mpic_cpu_ops, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
b7169916
AJ
1243 };
1244
7267c094 1245 mpp = g_malloc0(sizeof(openpic_t));
b7169916 1246
71cf9e62
FC
1247 memory_region_init(&mpp->mem, "mpic", 0x40000);
1248 memory_region_add_subregion(address_space, base, &mpp->mem);
1249
b7169916 1250 for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
b7169916 1251
71cf9e62
FC
1252 memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp,
1253 list[i].name, list[i].size);
1254
1255 memory_region_add_subregion(&mpp->mem, list[i].start_addr,
1256 &mpp->sub_io_mem[i]);
b7169916
AJ
1257 }
1258
1259 mpp->nb_cpus = nb_cpus;
1260 mpp->max_irq = MPIC_MAX_IRQ;
1261 mpp->irq_ipi0 = MPIC_IPI_IRQ;
1262 mpp->irq_tim0 = MPIC_TMR_IRQ;
1263
1264 for (i = 0; i < nb_cpus; i++)
1265 mpp->dst[i].irqs = irqs[i];
1266 mpp->irq_out = irq_out;
b7169916
AJ
1267
1268 mpp->irq_raise = mpic_irq_raise;
1269 mpp->reset = mpic_reset;
1270
0be71e32 1271 register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp);
a08d4367 1272 qemu_register_reset(mpic_reset, mpp);
b7169916
AJ
1273
1274 return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
dbda808a 1275}