]> git.proxmox.com Git - qemu.git/blame - hw/openpic.c
memory mapped NVRAM (Jocelyn Mayer)
[qemu.git] / hw / openpic.c
CommitLineData
dbda808a
FB
1/*
2 * OpenPIC emulation
3 *
4 * Copyright (c) 2004 Jocelyn Mayer
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24/*
25 *
26 * Based on OpenPic implementations:
27 * - Intel GW80314 I/O compagnion chip developper's manual
28 * - Motorola MPC8245 & MPC8540 user manuals.
29 * - Motorola MCP750 (aka Raven) programmer manual.
30 * - Motorola Harrier programmer manuel
31 *
32 * Serial interrupts, as implemented in Raven chipset are not supported yet.
33 *
34 */
35#include "vl.h"
36
37#define DEBUG_OPENPIC
38
39#ifdef DEBUG_OPENPIC
40#define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
41#else
42#define DPRINTF(fmt, args...) do { } while (0)
43#endif
44#define ERROR(fmr, args...) do { printf("ERROR: " fmr , ##args); } while (0)
45
46#define USE_MPCxxx /* Intel model is broken, for now */
47
48#if defined (USE_INTEL_GW80314)
49/* Intel GW80314 I/O Companion chip */
50
51#define MAX_CPU 4
52#define MAX_IRQ 32
53#define MAX_DBL 4
54#define MAX_MBX 4
55#define MAX_TMR 4
56#define VECTOR_BITS 8
57#define MAX_IPI 0
58
59#define VID (0x00000000)
60
61#define OPENPIC_LITTLE_ENDIAN 1
62#define OPENPIC_BIG_ENDIAN 0
63
64#elif defined(USE_MPCxxx)
65
66#define MAX_CPU 2
67#define MAX_IRQ 64
68#define EXT_IRQ 16
69#define MAX_DBL 0
70#define MAX_MBX 0
71#define MAX_TMR 4
72#define VECTOR_BITS 8
73#define MAX_IPI 4
74#define VID 0x03 /* MPIC version ID */
75#define VENI 0x00000000 /* Vendor ID */
76
77enum {
78 IRQ_IPVP = 0,
79 IRQ_IDE,
80};
81
82#define OPENPIC_LITTLE_ENDIAN 1
83#define OPENPIC_BIG_ENDIAN 0
84
85#else
86#error "Please select which OpenPic implementation is to be emulated"
87#endif
88
89#if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \
90 (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN)
91#define OPENPIC_SWAP
92#endif
93
94/* Interrupt definitions */
95#define IRQ_FE (EXT_IRQ) /* Internal functional IRQ */
96#define IRQ_ERR (EXT_IRQ + 1) /* Error IRQ */
97#define IRQ_TIM0 (EXT_IRQ + 2) /* First timer IRQ */
98#if MAX_IPI > 0
99#define IRQ_IPI0 (IRQ_TIM0 + MAX_TMR) /* First IPI IRQ */
100#define IRQ_DBL0 (IRQ_IPI0 + (MAX_CPU * MAX_IPI)) /* First doorbell IRQ */
101#else
102#define IRQ_DBL0 (IRQ_TIM0 + MAX_TMR) /* First doorbell IRQ */
103#define IRQ_MBX0 (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */
104#endif
105
106#define BF_WIDTH(_bits_) \
107(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
108
109static inline void set_bit (uint32_t *field, int bit)
110{
111 field[bit >> 5] |= 1 << (bit & 0x1F);
112}
113
114static inline void reset_bit (uint32_t *field, int bit)
115{
116 field[bit >> 5] &= ~(1 << (bit & 0x1F));
117}
118
119static inline int test_bit (uint32_t *field, int bit)
120{
121 return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
122}
123
124enum {
125 IRQ_EXTERNAL = 0x01,
126 IRQ_INTERNAL = 0x02,
127 IRQ_TIMER = 0x04,
128 IRQ_SPECIAL = 0x08,
129} IRQ_src_type;
130
131typedef struct IRQ_queue_t {
132 uint32_t queue[BF_WIDTH(MAX_IRQ)];
133 int next;
134 int priority;
135} IRQ_queue_t;
136
137typedef struct IRQ_src_t {
138 uint32_t ipvp; /* IRQ vector/priority register */
139 uint32_t ide; /* IRQ destination register */
140 int type;
141 int last_cpu;
142 int waited_acks;
143} IRQ_src_t;
144
145enum IPVP_bits {
146 IPVP_MASK = 31,
147 IPVP_ACTIVITY = 30,
148 IPVP_MODE = 29,
149 IPVP_POLARITY = 23,
150 IPVP_SENSE = 22,
151};
152#define IPVP_PRIORITY_MASK (0x1F << 16)
153#define IPVP_PRIORITY(_ipvpr_) (((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)
154#define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1)
155#define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK)
156
157typedef struct IRQ_dst_t {
158 uint32_t pctp; /* CPU current task priority */
159 uint32_t pcsr; /* CPU sensitivity register */
160 IRQ_queue_t raised;
161 IRQ_queue_t servicing;
162 CPUState *env; /* Needed if we did SMP */
163} IRQ_dst_t;
164
165typedef struct openpic_t {
166 PCIDevice pci_dev;
167 /* Global registers */
168 uint32_t frep; /* Feature reporting register */
169 uint32_t glbc; /* Global configuration register */
170 uint32_t micr; /* MPIC interrupt configuration register */
171 uint32_t veni; /* Vendor identification register */
172 uint32_t spve; /* Spurious vector register */
173 uint32_t tifr; /* Timer frequency reporting register */
174 /* Source registers */
175 IRQ_src_t src[MAX_IRQ];
176 /* Local registers per output pin */
177 IRQ_dst_t dst[MAX_CPU];
178 int nb_cpus;
179 /* Timer registers */
180 struct {
181 uint32_t ticc; /* Global timer current count register */
182 uint32_t tibc; /* Global timer base count register */
183 } timers[MAX_TMR];
184#if MAX_DBL > 0
185 /* Doorbell registers */
186 uint32_t dar; /* Doorbell activate register */
187 struct {
188 uint32_t dmr; /* Doorbell messaging register */
189 } doorbells[MAX_DBL];
190#endif
191#if MAX_MBX > 0
192 /* Mailbox registers */
193 struct {
194 uint32_t mbr; /* Mailbox register */
195 } mailboxes[MAX_MAILBOXES];
196#endif
197} openpic_t;
198
199static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
200{
201 set_bit(q->queue, n_IRQ);
202}
203
204static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
205{
206 reset_bit(q->queue, n_IRQ);
207}
208
209static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
210{
211 return test_bit(q->queue, n_IRQ);
212}
213
214static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
215{
216 int next, i;
217 int priority;
218
219 next = -1;
220 priority = -1;
221 for (i = 0; i < MAX_IRQ; i++) {
222 if (IRQ_testbit(q, i)) {
223 if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
224 next = i;
225 priority = IPVP_PRIORITY(opp->src[i].ipvp);
226 }
227 }
228 }
229 q->next = next;
230 q->priority = priority;
231}
232
233static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
234{
235 if (q->next == -1) {
236 if (q->queue == 0) {
237 /* No more IRQ */
238 return -1;
239 }
240 IRQ_check(opp, q);
241 }
242
243 return q->next;
244}
245
246static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
247{
248 IRQ_dst_t *dst;
249 IRQ_src_t *src;
250 int priority;
251
252 dst = &opp->dst[n_CPU];
253 src = &opp->src[n_IRQ];
254 priority = IPVP_PRIORITY(src->ipvp);
255 if (priority <= dst->pctp) {
256 /* Too low priority */
257 return;
258 }
259 if (IRQ_testbit(&dst->raised, n_IRQ)) {
260 /* Interrupt miss */
261 return;
262 }
263 set_bit(&src->ipvp, IPVP_ACTIVITY);
264 IRQ_setbit(&dst->raised, n_IRQ);
265 if (priority > dst->raised.priority) {
266 IRQ_get_next(opp, &dst->raised);
267 DPRINTF("Raise CPU IRQ\n");
268 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
269 }
270}
271
272void openpic_set_IRQ (openpic_t *opp, int n_IRQ, int level)
273{
274 IRQ_src_t *src;
275 int i;
276
277 src = &opp->src[n_IRQ];
278 if (!test_bit(&src->ipvp, IPVP_MASK)) {
279 /* Interrupt source is disabled */
280 return;
281 }
282 if (IPVP_PRIORITY(src->ipvp) == 0) {
283 /* Priority set to zero */
284 return;
285 }
286 if (src->ide == 0x00000000) {
287 /* No target */
288 return;
289 }
290 if (level == 0) {
291 if (test_bit(&src->ipvp, IPVP_ACTIVITY) &&
292 test_bit(&src->ipvp, IPVP_SENSE)) {
293 /* Inactivate a active level-sensitive IRQ */
294 reset_bit(&src->ipvp, IPVP_ACTIVITY);
295 }
296 } else {
297 if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
298 /* Interrupt already pending */
299 return;
300 }
301 if (!test_bit(&src->ipvp, IPVP_MODE) ||
302 src->ide == (1 << src->last_cpu)) {
303 /* Directed delivery mode */
304 for (i = 0; i < opp->nb_cpus; i++) {
305 if (test_bit(&src->ide, i))
306 IRQ_local_pipe(opp, i, n_IRQ);
307 }
308 } else {
309 /* Distributed delivery mode */
310 for (i = src->last_cpu; i < src->last_cpu; i++) {
311 if (i == MAX_IRQ)
312 i = 0;
313 if (test_bit(&src->ide, i)) {
314 IRQ_local_pipe(opp, i, n_IRQ);
315 src->last_cpu = i;
316 break;
317 }
318 }
319 }
320 }
321}
322
323static void openpic_reset (openpic_t *opp)
324{
325 int i;
326
327 opp->glbc = 0x80000000;
328 /* Initialise controler registers */
329 opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
330 opp->veni = VENI;
331 opp->spve = 0x000000FF;
332 opp->tifr = 0x003F7A00;
333 /* ? */
334 opp->micr = 0x00000000;
335 /* Initialise IRQ sources */
336 for (i = 0; i < MAX_IRQ; i++) {
337 opp->src[i].ipvp = 0xA0000000;
338 opp->src[i].ide = 0x00000000;
339 }
340 /* Initialise IRQ destinations */
341 for (i = 0; i < opp->nb_cpus; i++) {
342 opp->dst[i].pctp = 0x0000000F;
343 opp->dst[i].pcsr = 0x00000000;
344 memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
345 memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
346 }
347 /* Initialise timers */
348 for (i = 0; i < MAX_TMR; i++) {
349 opp->timers[i].ticc = 0x00000000;
350 opp->timers[i].tibc = 0x80000000;
351 }
352 /* Initialise doorbells */
353#if MAX_DBL > 0
354 opp->dar = 0x00000000;
355 for (i = 0; i < MAX_DBL; i++) {
356 opp->doorbells[i].dmr = 0x00000000;
357 }
358#endif
359 /* Initialise mailboxes */
360#if MAX_MBX > 0
361 for (i = 0; i < MAX_MBX; i++) { /* ? */
362 opp->mailboxes[i].mbr = 0x00000000;
363 }
364#endif
365 /* Go out of RESET state */
366 opp->glbc = 0x00000000;
367}
368
369static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
370{
371 uint32_t retval;
372
373 switch (reg) {
374 case IRQ_IPVP:
375 retval = opp->src[n_IRQ].ipvp;
376 break;
377 case IRQ_IDE:
378 retval = opp->src[n_IRQ].ide;
379 break;
380 }
381
382 return retval;
383}
384
385static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
386 uint32_t reg, uint32_t val)
387{
388 uint32_t tmp;
389
390 switch (reg) {
391 case IRQ_IPVP:
392 tmp = opp->src[n_IRQ].ipvp & 0x40000000;
393 if (tmp == 0) {
394 tmp |= val & 0x80000000;
395 if ((opp->src[n_IRQ].type & IRQ_EXTERNAL) != 0)
396 tmp |= val & 0x40C00000;
397 else if ((opp->src[n_IRQ].type & IRQ_TIMER) != 0)
398 tmp |= val & 0x00F00000;
399 } else {
400 tmp |= val & 0x80000000;
401 }
402 opp->src[n_IRQ].ipvp = tmp | (val & 0x000F00FF);
403 DPRINTF("Set IPVP %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ipvp);
404 break;
405 case IRQ_IDE:
406 tmp = val & 0xC0000000;
407 tmp |= val & ((1 << MAX_CPU) - 1);
408 opp->src[n_IRQ].ide = tmp;
409 DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
410 break;
411 }
412}
413
414#if 0 // Code provision for Intel model
415#if MAX_DBL > 0
416static uint32_t read_doorbell_register (openpic_t *opp,
417 int n_dbl, uint32_t offset)
418{
419 uint32_t retval;
420
421 switch (offset) {
422 case DBL_IPVP_OFFSET:
423 retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
424 break;
425 case DBL_IDE_OFFSET:
426 retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
427 break;
428 case DBL_DMR_OFFSET:
429 retval = opp->doorbells[n_dbl].dmr;
430 break;
431 }
432
433 return retval;
434}
435
436static void write_doorbell_register (penpic_t *opp, int n_dbl,
437 uint32_t offset, uint32_t value)
438{
439 switch (offset) {
440 case DBL_IVPR_OFFSET:
441 write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
442 break;
443 case DBL_IDE_OFFSET:
444 write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
445 break;
446 case DBL_DMR_OFFSET:
447 opp->doorbells[n_dbl].dmr = value;
448 break;
449 }
450}
451#endif
452
453#if MAX_MBX > 0
454static uint32_t read_mailbox_register (openpic_t *opp,
455 int n_mbx, uint32_t offset)
456{
457 uint32_t retval;
458
459 switch (offset) {
460 case MBX_MBR_OFFSET:
461 retval = opp->mailboxes[n_mbx].mbr;
462 break;
463 case MBX_IVPR_OFFSET:
464 retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
465 break;
466 case MBX_DMR_OFFSET:
467 retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
468 break;
469 }
470
471 return retval;
472}
473
474static void write_mailbox_register (openpic_t *opp, int n_mbx,
475 uint32_t address, uint32_t value)
476{
477 switch (offset) {
478 case MBX_MBR_OFFSET:
479 opp->mailboxes[n_mbx].mbr = value;
480 break;
481 case MBX_IVPR_OFFSET:
482 write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
483 break;
484 case MBX_DMR_OFFSET:
485 write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
486 break;
487 }
488}
489#endif
490#endif /* 0 : Code provision for Intel model */
491
492static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
493{
494 openpic_t *opp = opaque;
495
496 DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
497 if (addr & 0xF)
498 return;
499#if defined OPENPIC_SWAP
500 val = bswap32(val);
501#endif
502 addr &= 0xFF;
503 switch (addr) {
504 case 0x00: /* FREP */
505 break;
506 case 0x20: /* GLBC */
507 if (val & 0x80000000)
508 openpic_reset(opp);
509 opp->glbc = val & ~0x80000000;
510 break;
511 case 0x80: /* VENI */
512 break;
513 case 0x90: /* PINT */
514 /* XXX: Should be able to reset any CPU */
515 if (val & 1) {
516 DPRINTF("Reset CPU IRQ\n");
517 // cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET);
518 }
519 break;
520#if MAX_IPI > 0
521 case 0xA0: /* IPI_IPVP */
522 case 0xB0:
523 case 0xC0:
524 case 0xD0:
525 {
526 int idx;
527 idx = (addr - 0xA0) >> 4;
528 write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
529 }
530 break;
531#endif
532 case 0xE0: /* SPVE */
533 opp->spve = val & 0x000000FF;
534 break;
535 case 0xF0: /* TIFR */
536 opp->tifr = val;
537 break;
538 default:
539 break;
540 }
541}
542
543static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
544{
545 openpic_t *opp = opaque;
546 uint32_t retval;
547
548 DPRINTF("%s: addr %08x\n", __func__, addr);
549 retval = 0xFFFFFFFF;
550 if (addr & 0xF)
551 return retval;
552 addr &= 0xFF;
553 switch (addr) {
554 case 0x00: /* FREP */
555 retval = opp->frep;
556 break;
557 case 0x20: /* GLBC */
558 retval = opp->glbc;
559 break;
560 case 0x80: /* VENI */
561 retval = opp->veni;
562 break;
563 case 0x90: /* PINT */
564 retval = 0x00000000;
565 break;
566#if MAX_IPI > 0
567 case 0xA0: /* IPI_IPVP */
568 case 0xB0:
569 case 0xC0:
570 case 0xD0:
571 {
572 int idx;
573 idx = (addr - 0xA0) >> 4;
574 retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
575 }
576 break;
577#endif
578 case 0xE0: /* SPVE */
579 retval = opp->spve;
580 break;
581 case 0xF0: /* TIFR */
582 retval = opp->tifr;
583 break;
584 default:
585 break;
586 }
587 DPRINTF("%s: => %08x\n", __func__, retval);
588#if defined OPENPIC_SWAP
589 retval = bswap32(retval);
590#endif
591
592 return retval;
593}
594
595static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
596{
597 openpic_t *opp = opaque;
598 int idx;
599
600 DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
601 if (addr & 0xF)
602 return;
603#if defined OPENPIC_SWAP
604 val = bswap32(val);
605#endif
606 addr -= 0x1100;
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 */
614 if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
615 (val & 0x800000000) == 0 &&
616 (opp->timers[idx].tibc & 0x80000000) != 0)
617 opp->timers[idx].ticc &= ~0x80000000;
618 opp->timers[idx].tibc = val;
619 break;
620 case 0x20: /* TIVP */
621 write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val);
622 break;
623 case 0x30: /* TIDE */
624 write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val);
625 break;
626 }
627}
628
629static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
630{
631 openpic_t *opp = opaque;
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;
639 addr -= 0x1100;
640 addr &= 0xFFFF;
641 idx = (addr & 0xFFF0) >> 6;
642 addr = addr & 0x30;
643 switch (addr) {
644 case 0x00: /* TICC */
645 retval = opp->timers[idx].ticc;
646 break;
647 case 0x10: /* TIBC */
648 retval = opp->timers[idx].tibc;
649 break;
650 case 0x20: /* TIPV */
651 retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP);
652 break;
653 case 0x30: /* TIDE */
654 retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE);
655 break;
656 }
657 DPRINTF("%s: => %08x\n", __func__, retval);
658#if defined OPENPIC_SWAP
659 retval = bswap32(retval);
660#endif
661
662 return retval;
663}
664
665static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
666{
667 openpic_t *opp = opaque;
668 int idx;
669
670 DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
671 if (addr & 0xF)
672 return;
673#if defined OPENPIC_SWAP
674 val = tswap32(val);
675#endif
676 addr = addr & 0xFFF0;
677 idx = addr >> 5;
678 if (addr & 0x10) {
679 /* EXDE / IFEDE / IEEDE */
680 write_IRQreg(opp, idx, IRQ_IDE, val);
681 } else {
682 /* EXVP / IFEVP / IEEVP */
683 write_IRQreg(opp, idx, IRQ_IPVP, val);
684 }
685}
686
687static uint32_t openpic_src_read (void *opaque, uint32_t addr)
688{
689 openpic_t *opp = opaque;
690 uint32_t retval;
691 int idx;
692
693 DPRINTF("%s: addr %08x\n", __func__, addr);
694 retval = 0xFFFFFFFF;
695 if (addr & 0xF)
696 return retval;
697 addr = addr & 0xFFF0;
698 idx = addr >> 5;
699 if (addr & 0x10) {
700 /* EXDE / IFEDE / IEEDE */
701 retval = read_IRQreg(opp, idx, IRQ_IDE);
702 } else {
703 /* EXVP / IFEVP / IEEVP */
704 retval = read_IRQreg(opp, idx, IRQ_IPVP);
705 }
706 DPRINTF("%s: => %08x\n", __func__, retval);
707#if defined OPENPIC_SWAP
708 retval = tswap32(retval);
709#endif
710
711 return retval;
712}
713
714static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
715{
716 openpic_t *opp = opaque;
717 IRQ_src_t *src;
718 IRQ_dst_t *dst;
719 int idx, n_IRQ;
720
721 DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
722 if (addr & 0xF)
723 return;
724#if defined OPENPIC_SWAP
725 val = bswap32(val);
726#endif
727 addr &= 0x1FFF0;
728 idx = addr / 0x1000;
729 dst = &opp->dst[idx];
730 addr &= 0xFF0;
731 switch (addr) {
732#if MAX_IPI > 0
733 case 0x40: /* PIPD */
734 case 0x50:
735 case 0x60:
736 case 0x70:
737 idx = (addr - 0x40) >> 4;
738 write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val);
739 openpic_set_IRQ(opp, IRQ_IPI0 + idx, 1);
740 openpic_set_IRQ(opp, IRQ_IPI0 + idx, 0);
741 break;
742#endif
743 case 0x80: /* PCTP */
744 dst->pctp = val & 0x0000000F;
745 break;
746 case 0x90: /* WHOAMI */
747 /* Read-only register */
748 break;
749 case 0xA0: /* PIAC */
750 /* Read-only register */
751 break;
752 case 0xB0: /* PEOI */
753 DPRINTF("PEOI\n");
754 n_IRQ = IRQ_get_next(opp, &dst->servicing);
755 IRQ_resetbit(&dst->servicing, n_IRQ);
756 dst->servicing.next = -1;
757 src = &opp->src[n_IRQ];
758 /* Set up next servicing IRQ */
759 IRQ_get_next(opp, &dst->servicing);
760 /* Check queued interrupts. */
761 n_IRQ = IRQ_get_next(opp, &dst->raised);
762 if (n_IRQ != -1) {
763 src = &opp->src[n_IRQ];
764 if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
765 DPRINTF("Raise CPU IRQ\n");
766 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
767 }
768 }
769 break;
770 default:
771 break;
772 }
773}
774
775static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
776{
777 openpic_t *opp = opaque;
778 IRQ_src_t *src;
779 IRQ_dst_t *dst;
780 uint32_t retval;
781 int idx, n_IRQ;
782
783 DPRINTF("%s: addr %08x\n", __func__, addr);
784 retval = 0xFFFFFFFF;
785 if (addr & 0xF)
786 return retval;
787 addr &= 0x1FFF0;
788 idx = addr / 0x1000;
789 dst = &opp->dst[idx];
790 addr &= 0xFF0;
791 switch (addr) {
792 case 0x80: /* PCTP */
793 retval = dst->pctp;
794 break;
795 case 0x90: /* WHOAMI */
796 retval = idx;
797 break;
798 case 0xA0: /* PIAC */
799 n_IRQ = IRQ_get_next(opp, &dst->raised);
800 DPRINTF("PIAC: irq=%d\n", n_IRQ);
801 if (n_IRQ == -1) {
802 /* No more interrupt pending */
803 retval = opp->spve;
804 } else {
805 src = &opp->src[n_IRQ];
806 if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
807 !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
808 /* - Spurious level-sensitive IRQ
809 * - Priorities has been changed
810 * and the pending IRQ isn't allowed anymore
811 */
812 reset_bit(&src->ipvp, IPVP_ACTIVITY);
813 retval = IPVP_VECTOR(opp->spve);
814 } else {
815 /* IRQ enter servicing state */
816 IRQ_setbit(&dst->servicing, n_IRQ);
817 retval = IPVP_VECTOR(src->ipvp);
818 }
819 IRQ_resetbit(&dst->raised, n_IRQ);
820 dst->raised.next = -1;
821 if (!test_bit(&src->ipvp, IPVP_SENSE))
822 reset_bit(&src->ipvp, IPVP_ACTIVITY);
823 }
824 break;
825 case 0xB0: /* PEOI */
826 retval = 0;
827 break;
828#if MAX_IPI > 0
829 case 0x40: /* IDE */
830 case 0x50:
831 idx = (addr - 0x40) >> 4;
832 retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE);
833 break;
834#endif
835 default:
836 break;
837 }
838 DPRINTF("%s: => %08x\n", __func__, retval);
839#if defined OPENPIC_SWAP
840 retval= bswap32(retval);
841#endif
842
843 return retval;
844}
845
846static void openpic_buggy_write (void *opaque,
847 target_phys_addr_t addr, uint32_t val)
848{
849 printf("Invalid OPENPIC write access !\n");
850}
851
852static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
853{
854 printf("Invalid OPENPIC read access !\n");
855
856 return -1;
857}
858
859static void openpic_writel (void *opaque,
860 target_phys_addr_t addr, uint32_t val)
861{
862 openpic_t *opp = opaque;
863
864 addr &= 0x3FFFF;
865 DPRINTF("%s: offset %08lx val: %08x\n", __func__, addr, val);
866 if (addr < 0x1100) {
867 /* Global registers */
868 openpic_gbl_write(opp, addr, val);
869 } else if (addr < 0x10000) {
870 /* Timers registers */
871 openpic_timer_write(opp, addr, val);
872 } else if (addr < 0x20000) {
873 /* Source registers */
874 openpic_src_write(opp, addr, val);
875 } else {
876 /* CPU registers */
877 openpic_cpu_write(opp, addr, val);
878 }
879}
880
881static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
882{
883 openpic_t *opp = opaque;
884 uint32_t retval;
885
886 addr &= 0x3FFFF;
887 DPRINTF("%s: offset %08lx\n", __func__, addr);
888 if (addr < 0x1100) {
889 /* Global registers */
890 retval = openpic_gbl_read(opp, addr);
891 } else if (addr < 0x10000) {
892 /* Timers registers */
893 retval = openpic_timer_read(opp, addr);
894 } else if (addr < 0x20000) {
895 /* Source registers */
896 retval = openpic_src_read(opp, addr);
897 } else {
898 /* CPU registers */
899 retval = openpic_cpu_read(opp, addr);
900 }
901
902 return retval;
903}
904
905static CPUWriteMemoryFunc *openpic_write[] = {
906 &openpic_buggy_write,
907 &openpic_buggy_write,
908 &openpic_writel,
909};
910
911static CPUReadMemoryFunc *openpic_read[] = {
912 &openpic_buggy_read,
913 &openpic_buggy_read,
914 &openpic_readl,
915};
916
917static void openpic_map(PCIDevice *pci_dev, int region_num,
918 uint32_t addr, uint32_t size, int type)
919{
920 openpic_t *opp;
921 int opp_io_memory;
922
923 DPRINTF("Map OpenPIC\n");
924 opp = (openpic_t *)pci_dev;
925 /* Global registers */
926 DPRINTF("Register OPENPIC gbl %08x => %08x\n",
927 addr + 0x1000, addr + 0x1000 + 0x100);
928 /* Timer registers */
929 DPRINTF("Register OPENPIC timer %08x => %08x\n",
930 addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
931 /* Interrupt source registers */
932 DPRINTF("Register OPENPIC src %08x => %08x\n",
933 addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2));
934 /* Per CPU registers */
935 DPRINTF("Register OPENPIC dst %08x => %08x\n",
936 addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
937 opp_io_memory = cpu_register_io_memory(0, openpic_read,
938 openpic_write, opp);
939 cpu_register_physical_memory(addr, 0x40000, opp_io_memory);
940#if 0 // Don't implement ISU for now
941 opp_io_memory = cpu_register_io_memory(0, openpic_src_read,
942 openpic_src_write);
943 cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
944 opp_io_memory);
945#endif
946}
947
948openpic_t *openpic_init (uint32_t isu_base, uint32_t idu_base, int nb_cpus)
949{
950 openpic_t *opp;
951 uint8_t *pci_conf;
952 int i, m;
953
954 /* XXX: for now, only one CPU is supported */
955 if (nb_cpus != 1)
956 return NULL;
957 opp = (openpic_t *)pci_register_device("OpenPIC", sizeof(openpic_t),
958 0, -1, NULL, NULL);
959 if (opp == NULL)
960 return NULL;
961 pci_conf = opp->pci_dev.config;
962 pci_conf[0x00] = 0x14; // IBM MPIC2
963 pci_conf[0x01] = 0x10;
964 pci_conf[0x02] = 0xFF;
965 pci_conf[0x03] = 0xFF;
966 pci_conf[0x0a] = 0x80; // PIC
967 pci_conf[0x0b] = 0x08;
968 pci_conf[0x0e] = 0x00; // header_type
969 pci_conf[0x3d] = 0x00; // no interrupt pin
970
971 /* Register I/O spaces */
972 pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
973 PCI_ADDRESS_SPACE_MEM, &openpic_map);
974
975 isu_base &= 0xFFFC0000;
976 opp->nb_cpus = nb_cpus;
977 /* Set IRQ types */
978 for (i = 0; i < EXT_IRQ; i++) {
979 opp->src[i].type = IRQ_EXTERNAL;
980 }
981 for (; i < IRQ_TIM0; i++) {
982 opp->src[i].type = IRQ_SPECIAL;
983 }
984#if MAX_IPI > 0
985 m = IRQ_IPI0;
986#else
987 m = IRQ_DBL0;
988#endif
989 for (; i < m; i++) {
990 opp->src[i].type = IRQ_TIMER;
991 }
992 for (; i < MAX_IRQ; i++) {
993 opp->src[i].type = IRQ_INTERNAL;
994 }
995 openpic_reset(opp);
996
997 return opp;
998}