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