Statistics
| Branch: | Revision:

root / hw / openpic.c @ 9a40611c

History | View | Annotate | Download (31.2 kB)

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 companion chip developer'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 "hw.h"
36
#include "ppc_mac.h"
37
#include "pci.h"
38

    
39
//#define DEBUG_OPENPIC
40

    
41
#ifdef DEBUG_OPENPIC
42
#define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
43
#else
44
#define DPRINTF(fmt, args...) do { } while (0)
45
#endif
46
#define ERROR(fmr, args...) do { printf("ERROR: " fmr , ##args); } while (0)
47

    
48
#define USE_MPCxxx /* Intel model is broken, for now */
49

    
50
#if defined (USE_INTEL_GW80314)
51
/* Intel GW80314 I/O Companion chip */
52

    
53
#define MAX_CPU     4
54
#define MAX_IRQ    32
55
#define MAX_DBL     4
56
#define MAX_MBX     4
57
#define MAX_TMR     4
58
#define VECTOR_BITS 8
59
#define MAX_IPI     0
60

    
61
#define VID (0x00000000)
62

    
63
#define OPENPIC_LITTLE_ENDIAN 1
64
#define OPENPIC_BIG_ENDIAN    0
65

    
66
#elif defined(USE_MPCxxx)
67

    
68
#define MAX_CPU     2
69
#define MAX_IRQ    64
70
#define EXT_IRQ    48
71
#define MAX_DBL     0
72
#define MAX_MBX     0
73
#define MAX_TMR     4
74
#define VECTOR_BITS 8
75
#define MAX_IPI     4
76
#define VID         0x03 /* MPIC version ID */
77
#define VENI        0x00000000 /* Vendor ID */
78

    
79
enum {
80
    IRQ_IPVP = 0,
81
    IRQ_IDE,
82
};
83

    
84
#define OPENPIC_LITTLE_ENDIAN 1
85
#define OPENPIC_BIG_ENDIAN    0
86

    
87
#else
88
#error "Please select which OpenPic implementation is to be emulated"
89
#endif
90

    
91
#if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \
92
    (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN)
93
#define OPENPIC_SWAP
94
#endif
95

    
96
/* Interrupt definitions */
97
#define IRQ_FE     (EXT_IRQ)     /* Internal functional IRQ */
98
#define IRQ_ERR    (EXT_IRQ + 1) /* Error IRQ */
99
#define IRQ_TIM0   (EXT_IRQ + 2) /* First timer IRQ */
100
#if MAX_IPI > 0
101
#define IRQ_IPI0   (IRQ_TIM0 + MAX_TMR) /* First IPI IRQ */
102
#define IRQ_DBL0   (IRQ_IPI0 + (MAX_CPU * MAX_IPI)) /* First doorbell IRQ */
103
#else
104
#define IRQ_DBL0   (IRQ_TIM0 + MAX_TMR) /* First doorbell IRQ */
105
#define IRQ_MBX0   (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */
106
#endif
107

    
108
#define BF_WIDTH(_bits_) \
109
(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
110

    
111
static inline void set_bit (uint32_t *field, int bit)
112
{
113
    field[bit >> 5] |= 1 << (bit & 0x1F);
114
}
115

    
116
static inline void reset_bit (uint32_t *field, int bit)
117
{
118
    field[bit >> 5] &= ~(1 << (bit & 0x1F));
119
}
120

    
121
static inline int test_bit (uint32_t *field, int bit)
122
{
123
    return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
124
}
125

    
126
enum {
127
    IRQ_EXTERNAL = 0x01,
128
    IRQ_INTERNAL = 0x02,
129
    IRQ_TIMER    = 0x04,
130
    IRQ_SPECIAL  = 0x08,
131
};
132

    
133
typedef struct IRQ_queue_t {
134
    uint32_t queue[BF_WIDTH(MAX_IRQ)];
135
    int next;
136
    int priority;
137
} IRQ_queue_t;
138

    
139
typedef struct IRQ_src_t {
140
    uint32_t ipvp;  /* IRQ vector/priority register */
141
    uint32_t ide;   /* IRQ destination register */
142
    int type;
143
    int last_cpu;
144
    int pending;    /* TRUE if IRQ is pending */
145
} IRQ_src_t;
146

    
147
enum IPVP_bits {
148
    IPVP_MASK     = 31,
149
    IPVP_ACTIVITY = 30,
150
    IPVP_MODE     = 29,
151
    IPVP_POLARITY = 23,
152
    IPVP_SENSE    = 22,
153
};
154
#define IPVP_PRIORITY_MASK     (0x1F << 16)
155
#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
156
#define IPVP_VECTOR_MASK       ((1 << VECTOR_BITS) - 1)
157
#define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)
158

    
159
typedef struct IRQ_dst_t {
160
    uint32_t pctp; /* CPU current task priority */
161
    uint32_t pcsr; /* CPU sensitivity register */
162
    IRQ_queue_t raised;
163
    IRQ_queue_t servicing;
164
    qemu_irq *irqs;
165
} IRQ_dst_t;
166

    
167
typedef struct openpic_t {
168
    PCIDevice pci_dev;
169
    int mem_index;
170
    /* Global registers */
171
    uint32_t frep; /* Feature reporting register */
172
    uint32_t glbc; /* Global configuration register  */
173
    uint32_t micr; /* MPIC interrupt configuration register */
174
    uint32_t veni; /* Vendor identification register */
175
    uint32_t pint; /* Processor initialization register */
176
    uint32_t spve; /* Spurious vector register */
177
    uint32_t tifr; /* Timer frequency reporting register */
178
    /* Source registers */
179
    IRQ_src_t src[MAX_IRQ];
180
    /* Local registers per output pin */
181
    IRQ_dst_t dst[MAX_CPU];
182
    int nb_cpus;
183
    /* Timer registers */
184
    struct {
185
        uint32_t ticc;  /* Global timer current count register */
186
        uint32_t tibc;  /* Global timer base count register */
187
    } timers[MAX_TMR];
188
#if MAX_DBL > 0
189
    /* Doorbell registers */
190
    uint32_t dar;        /* Doorbell activate register */
191
    struct {
192
        uint32_t dmr;    /* Doorbell messaging register */
193
    } doorbells[MAX_DBL];
194
#endif
195
#if MAX_MBX > 0
196
    /* Mailbox registers */
197
    struct {
198
        uint32_t mbr;    /* Mailbox register */
199
    } mailboxes[MAX_MAILBOXES];
200
#endif
201
    /* IRQ out is used when in bypass mode (not implemented) */
202
    qemu_irq irq_out;
203
} openpic_t;
204

    
205
static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
206
{
207
    set_bit(q->queue, n_IRQ);
208
}
209

    
210
static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
211
{
212
    reset_bit(q->queue, n_IRQ);
213
}
214

    
215
static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
216
{
217
    return test_bit(q->queue, n_IRQ);
218
}
219

    
220
static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
221
{
222
    int next, i;
223
    int priority;
224

    
225
    next = -1;
226
    priority = -1;
227
    for (i = 0; i < MAX_IRQ; i++) {
228
        if (IRQ_testbit(q, i)) {
229
            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
230
                    i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
231
            if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
232
                next = i;
233
                priority = IPVP_PRIORITY(opp->src[i].ipvp);
234
            }
235
        }
236
    }
237
    q->next = next;
238
    q->priority = priority;
239
}
240

    
241
static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
242
{
243
    if (q->next == -1) {
244
        /* XXX: optimize */
245
        IRQ_check(opp, q);
246
    }
247

    
248
    return q->next;
249
}
250

    
251
static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
252
{
253
    IRQ_dst_t *dst;
254
    IRQ_src_t *src;
255
    int priority;
256

    
257
    dst = &opp->dst[n_CPU];
258
    src = &opp->src[n_IRQ];
259
    priority = IPVP_PRIORITY(src->ipvp);
260
    if (priority <= dst->pctp) {
261
        /* Too low priority */
262
        DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
263
                __func__, n_IRQ, n_CPU);
264
        return;
265
    }
266
    if (IRQ_testbit(&dst->raised, n_IRQ)) {
267
        /* Interrupt miss */
268
        DPRINTF("%s: IRQ %d was missed on CPU %d\n",
269
                __func__, n_IRQ, n_CPU);
270
        return;
271
    }
272
    set_bit(&src->ipvp, IPVP_ACTIVITY);
273
    IRQ_setbit(&dst->raised, n_IRQ);
274
    if (priority < dst->raised.priority) {
275
        /* An higher priority IRQ is already raised */
276
        DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
277
                __func__, n_IRQ, dst->raised.next, n_CPU);
278
        return;
279
    }
280
    IRQ_get_next(opp, &dst->raised);
281
    if (IRQ_get_next(opp, &dst->servicing) != -1 &&
282
        priority <= dst->servicing.priority) {
283
        DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
284
                __func__, n_IRQ, dst->servicing.next, n_CPU);
285
        /* Already servicing a higher priority IRQ */
286
        return;
287
    }
288
    DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
289
    qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
290
}
291

    
292
/* update pic state because registers for n_IRQ have changed value */
293
static void openpic_update_irq(openpic_t *opp, int n_IRQ)
294
{
295
    IRQ_src_t *src;
296
    int i;
297

    
298
    src = &opp->src[n_IRQ];
299

    
300
    if (!src->pending) {
301
        /* no irq pending */
302
        DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
303
        return;
304
    }
305
    if (test_bit(&src->ipvp, IPVP_MASK)) {
306
        /* Interrupt source is disabled */
307
        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
308
        return;
309
    }
310
    if (IPVP_PRIORITY(src->ipvp) == 0) {
311
        /* Priority set to zero */
312
        DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
313
        return;
314
    }
315
    if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
316
        /* IRQ already active */
317
        DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
318
        return;
319
    }
320
    if (src->ide == 0x00000000) {
321
        /* No target */
322
        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
323
        return;
324
    }
325

    
326
    if (src->ide == (1 << src->last_cpu)) {
327
        /* Only one CPU is allowed to receive this IRQ */
328
        IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
329
    } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
330
        /* Directed delivery mode */
331
        for (i = 0; i < opp->nb_cpus; i++) {
332
            if (test_bit(&src->ide, i))
333
                IRQ_local_pipe(opp, i, n_IRQ);
334
        }
335
    } else {
336
        /* Distributed delivery mode */
337
        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
338
            if (i == opp->nb_cpus)
339
                i = 0;
340
            if (test_bit(&src->ide, i)) {
341
                IRQ_local_pipe(opp, i, n_IRQ);
342
                src->last_cpu = i;
343
                break;
344
            }
345
        }
346
    }
347
}
348

    
349
static void openpic_set_irq(void *opaque, int n_IRQ, int level)
350
{
351
    openpic_t *opp = opaque;
352
    IRQ_src_t *src;
353

    
354
    src = &opp->src[n_IRQ];
355
    DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
356
            n_IRQ, level, src->ipvp);
357
    if (test_bit(&src->ipvp, IPVP_SENSE)) {
358
        /* level-sensitive irq */
359
        src->pending = level;
360
        if (!level)
361
            reset_bit(&src->ipvp, IPVP_ACTIVITY);
362
    } else {
363
        /* edge-sensitive irq */
364
        if (level)
365
            src->pending = 1;
366
    }
367
    openpic_update_irq(opp, n_IRQ);
368
}
369

    
370
static void openpic_reset (void *opaque)
371
{
372
    openpic_t *opp = (openpic_t *)opaque;
373
    int i;
374

    
375
    opp->glbc = 0x80000000;
376
    /* Initialise controller registers */
377
    opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
378
    opp->veni = VENI;
379
    opp->pint = 0x00000000;
380
    opp->spve = 0x000000FF;
381
    opp->tifr = 0x003F7A00;
382
    /* ? */
383
    opp->micr = 0x00000000;
384
    /* Initialise IRQ sources */
385
    for (i = 0; i < MAX_IRQ; i++) {
386
        opp->src[i].ipvp = 0xA0000000;
387
        opp->src[i].ide  = 0x00000000;
388
    }
389
    /* Initialise IRQ destinations */
390
    for (i = 0; i < MAX_CPU; i++) {
391
        opp->dst[i].pctp      = 0x0000000F;
392
        opp->dst[i].pcsr      = 0x00000000;
393
        memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
394
        memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
395
    }
396
    /* Initialise timers */
397
    for (i = 0; i < MAX_TMR; i++) {
398
        opp->timers[i].ticc = 0x00000000;
399
        opp->timers[i].tibc = 0x80000000;
400
    }
401
    /* Initialise doorbells */
402
#if MAX_DBL > 0
403
    opp->dar = 0x00000000;
404
    for (i = 0; i < MAX_DBL; i++) {
405
        opp->doorbells[i].dmr  = 0x00000000;
406
    }
407
#endif
408
    /* Initialise mailboxes */
409
#if MAX_MBX > 0
410
    for (i = 0; i < MAX_MBX; i++) { /* ? */
411
        opp->mailboxes[i].mbr   = 0x00000000;
412
    }
413
#endif
414
    /* Go out of RESET state */
415
    opp->glbc = 0x00000000;
416
}
417

    
418
static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
419
{
420
    uint32_t retval;
421

    
422
    switch (reg) {
423
    case IRQ_IPVP:
424
        retval = opp->src[n_IRQ].ipvp;
425
        break;
426
    case IRQ_IDE:
427
        retval = opp->src[n_IRQ].ide;
428
        break;
429
    }
430

    
431
    return retval;
432
}
433

    
434
static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
435
                                 uint32_t reg, uint32_t val)
436
{
437
    uint32_t tmp;
438

    
439
    switch (reg) {
440
    case IRQ_IPVP:
441
        /* NOTE: not fully accurate for special IRQs, but simple and
442
           sufficient */
443
        /* ACTIVITY bit is read-only */
444
        opp->src[n_IRQ].ipvp =
445
            (opp->src[n_IRQ].ipvp & 0x40000000) |
446
            (val & 0x800F00FF);
447
        openpic_update_irq(opp, n_IRQ);
448
        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
449
                n_IRQ, val, opp->src[n_IRQ].ipvp);
450
        break;
451
    case IRQ_IDE:
452
        tmp = val & 0xC0000000;
453
        tmp |= val & ((1 << MAX_CPU) - 1);
454
        opp->src[n_IRQ].ide = tmp;
455
        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
456
        break;
457
    }
458
}
459

    
460
#if 0 // Code provision for Intel model
461
#if MAX_DBL > 0
462
static uint32_t read_doorbell_register (openpic_t *opp,
463
                                        int n_dbl, uint32_t offset)
464
{
465
    uint32_t retval;
466

467
    switch (offset) {
468
    case DBL_IPVP_OFFSET:
469
        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
470
        break;
471
    case DBL_IDE_OFFSET:
472
        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
473
        break;
474
    case DBL_DMR_OFFSET:
475
        retval = opp->doorbells[n_dbl].dmr;
476
        break;
477
    }
478

479
    return retval;
480
}
481

482
static void write_doorbell_register (penpic_t *opp, int n_dbl,
483
                                     uint32_t offset, uint32_t value)
484
{
485
    switch (offset) {
486
    case DBL_IVPR_OFFSET:
487
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
488
        break;
489
    case DBL_IDE_OFFSET:
490
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
491
        break;
492
    case DBL_DMR_OFFSET:
493
        opp->doorbells[n_dbl].dmr = value;
494
        break;
495
    }
496
}
497
#endif
498

    
499
#if MAX_MBX > 0
500
static uint32_t read_mailbox_register (openpic_t *opp,
501
                                       int n_mbx, uint32_t offset)
502
{
503
    uint32_t retval;
504

    
505
    switch (offset) {
506
    case MBX_MBR_OFFSET:
507
        retval = opp->mailboxes[n_mbx].mbr;
508
        break;
509
    case MBX_IVPR_OFFSET:
510
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
511
        break;
512
    case MBX_DMR_OFFSET:
513
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
514
        break;
515
    }
516

    
517
    return retval;
518
}
519

    
520
static void write_mailbox_register (openpic_t *opp, int n_mbx,
521
                                    uint32_t address, uint32_t value)
522
{
523
    switch (offset) {
524
    case MBX_MBR_OFFSET:
525
        opp->mailboxes[n_mbx].mbr = value;
526
        break;
527
    case MBX_IVPR_OFFSET:
528
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
529
        break;
530
    case MBX_DMR_OFFSET:
531
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
532
        break;
533
    }
534
}
535
#endif
536
#endif /* 0 : Code provision for Intel model */
537

    
538
static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
539
{
540
    openpic_t *opp = opaque;
541
    IRQ_dst_t *dst;
542
    int idx;
543

    
544
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
545
    if (addr & 0xF)
546
        return;
547
#if defined OPENPIC_SWAP
548
    val = bswap32(val);
549
#endif
550
    addr &= 0xFF;
551
    switch (addr) {
552
    case 0x00: /* FREP */
553
        break;
554
    case 0x20: /* GLBC */
555
        if (val & 0x80000000)
556
            openpic_reset(opp);
557
        opp->glbc = val & ~0x80000000;
558
        break;
559
    case 0x80: /* VENI */
560
        break;
561
    case 0x90: /* PINT */
562
        for (idx = 0; idx < opp->nb_cpus; idx++) {
563
            if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
564
                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
565
                dst = &opp->dst[idx];
566
                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
567
            } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
568
                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
569
                dst = &opp->dst[idx];
570
                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
571
            }
572
        }
573
        opp->pint = val;
574
        break;
575
#if MAX_IPI > 0
576
    case 0xA0: /* IPI_IPVP */
577
    case 0xB0:
578
    case 0xC0:
579
    case 0xD0:
580
        {
581
            int idx;
582
            idx = (addr - 0xA0) >> 4;
583
            write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
584
        }
585
        break;
586
#endif
587
    case 0xE0: /* SPVE */
588
        opp->spve = val & 0x000000FF;
589
        break;
590
    case 0xF0: /* TIFR */
591
        opp->tifr = val;
592
        break;
593
    default:
594
        break;
595
    }
596
}
597

    
598
static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
599
{
600
    openpic_t *opp = opaque;
601
    uint32_t retval;
602

    
603
    DPRINTF("%s: addr %08x\n", __func__, addr);
604
    retval = 0xFFFFFFFF;
605
    if (addr & 0xF)
606
        return retval;
607
    addr &= 0xFF;
608
    switch (addr) {
609
    case 0x00: /* FREP */
610
        retval = opp->frep;
611
        break;
612
    case 0x20: /* GLBC */
613
        retval = opp->glbc;
614
        break;
615
    case 0x80: /* VENI */
616
        retval = opp->veni;
617
        break;
618
    case 0x90: /* PINT */
619
        retval = 0x00000000;
620
        break;
621
#if MAX_IPI > 0
622
    case 0xA0: /* IPI_IPVP */
623
    case 0xB0:
624
    case 0xC0:
625
    case 0xD0:
626
        {
627
            int idx;
628
            idx = (addr - 0xA0) >> 4;
629
            retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
630
        }
631
        break;
632
#endif
633
    case 0xE0: /* SPVE */
634
        retval = opp->spve;
635
        break;
636
    case 0xF0: /* TIFR */
637
        retval = opp->tifr;
638
        break;
639
    default:
640
        break;
641
    }
642
    DPRINTF("%s: => %08x\n", __func__, retval);
643
#if defined OPENPIC_SWAP
644
    retval = bswap32(retval);
645
#endif
646

    
647
    return retval;
648
}
649

    
650
static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
651
{
652
    openpic_t *opp = opaque;
653
    int idx;
654

    
655
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
656
    if (addr & 0xF)
657
        return;
658
#if defined OPENPIC_SWAP
659
    val = bswap32(val);
660
#endif
661
    addr -= 0x1100;
662
    addr &= 0xFFFF;
663
    idx = (addr & 0xFFF0) >> 6;
664
    addr = addr & 0x30;
665
    switch (addr) {
666
    case 0x00: /* TICC */
667
        break;
668
    case 0x10: /* TIBC */
669
        if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
670
            (val & 0x80000000) == 0 &&
671
            (opp->timers[idx].tibc & 0x80000000) != 0)
672
            opp->timers[idx].ticc &= ~0x80000000;
673
        opp->timers[idx].tibc = val;
674
        break;
675
    case 0x20: /* TIVP */
676
        write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val);
677
        break;
678
    case 0x30: /* TIDE */
679
        write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val);
680
        break;
681
    }
682
}
683

    
684
static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
685
{
686
    openpic_t *opp = opaque;
687
    uint32_t retval;
688
    int idx;
689

    
690
    DPRINTF("%s: addr %08x\n", __func__, addr);
691
    retval = 0xFFFFFFFF;
692
    if (addr & 0xF)
693
        return retval;
694
    addr -= 0x1100;
695
    addr &= 0xFFFF;
696
    idx = (addr & 0xFFF0) >> 6;
697
    addr = addr & 0x30;
698
    switch (addr) {
699
    case 0x00: /* TICC */
700
        retval = opp->timers[idx].ticc;
701
        break;
702
    case 0x10: /* TIBC */
703
        retval = opp->timers[idx].tibc;
704
        break;
705
    case 0x20: /* TIPV */
706
        retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP);
707
        break;
708
    case 0x30: /* TIDE */
709
        retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE);
710
        break;
711
    }
712
    DPRINTF("%s: => %08x\n", __func__, retval);
713
#if defined OPENPIC_SWAP
714
    retval = bswap32(retval);
715
#endif
716

    
717
    return retval;
718
}
719

    
720
static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
721
{
722
    openpic_t *opp = opaque;
723
    int idx;
724

    
725
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
726
    if (addr & 0xF)
727
        return;
728
#if defined OPENPIC_SWAP
729
    val = tswap32(val);
730
#endif
731
    addr = addr & 0xFFF0;
732
    idx = addr >> 5;
733
    if (addr & 0x10) {
734
        /* EXDE / IFEDE / IEEDE */
735
        write_IRQreg(opp, idx, IRQ_IDE, val);
736
    } else {
737
        /* EXVP / IFEVP / IEEVP */
738
        write_IRQreg(opp, idx, IRQ_IPVP, val);
739
    }
740
}
741

    
742
static uint32_t openpic_src_read (void *opaque, uint32_t addr)
743
{
744
    openpic_t *opp = opaque;
745
    uint32_t retval;
746
    int idx;
747

    
748
    DPRINTF("%s: addr %08x\n", __func__, addr);
749
    retval = 0xFFFFFFFF;
750
    if (addr & 0xF)
751
        return retval;
752
    addr = addr & 0xFFF0;
753
    idx = addr >> 5;
754
    if (addr & 0x10) {
755
        /* EXDE / IFEDE / IEEDE */
756
        retval = read_IRQreg(opp, idx, IRQ_IDE);
757
    } else {
758
        /* EXVP / IFEVP / IEEVP */
759
        retval = read_IRQreg(opp, idx, IRQ_IPVP);
760
    }
761
    DPRINTF("%s: => %08x\n", __func__, retval);
762
#if defined OPENPIC_SWAP
763
    retval = tswap32(retval);
764
#endif
765

    
766
    return retval;
767
}
768

    
769
static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
770
{
771
    openpic_t *opp = opaque;
772
    IRQ_src_t *src;
773
    IRQ_dst_t *dst;
774
    int idx, s_IRQ, n_IRQ;
775

    
776
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
777
    if (addr & 0xF)
778
        return;
779
#if defined OPENPIC_SWAP
780
    val = bswap32(val);
781
#endif
782
    addr &= 0x1FFF0;
783
    idx = addr / 0x1000;
784
    dst = &opp->dst[idx];
785
    addr &= 0xFF0;
786
    switch (addr) {
787
#if MAX_IPI > 0
788
    case 0x40: /* PIPD */
789
    case 0x50:
790
    case 0x60:
791
    case 0x70:
792
        idx = (addr - 0x40) >> 4;
793
        write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val);
794
        openpic_set_irq(opp, IRQ_IPI0 + idx, 1);
795
        openpic_set_irq(opp, IRQ_IPI0 + idx, 0);
796
        break;
797
#endif
798
    case 0x80: /* PCTP */
799
        dst->pctp = val & 0x0000000F;
800
        break;
801
    case 0x90: /* WHOAMI */
802
        /* Read-only register */
803
        break;
804
    case 0xA0: /* PIAC */
805
        /* Read-only register */
806
        break;
807
    case 0xB0: /* PEOI */
808
        DPRINTF("PEOI\n");
809
        s_IRQ = IRQ_get_next(opp, &dst->servicing);
810
        IRQ_resetbit(&dst->servicing, s_IRQ);
811
        dst->servicing.next = -1;
812
        /* Set up next servicing IRQ */
813
        s_IRQ = IRQ_get_next(opp, &dst->servicing);
814
        /* Check queued interrupts. */
815
        n_IRQ = IRQ_get_next(opp, &dst->raised);
816
        src = &opp->src[n_IRQ];
817
        if (n_IRQ != -1 &&
818
            (s_IRQ == -1 ||
819
             IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
820
            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
821
                    idx, n_IRQ);
822
            qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
823
        }
824
        break;
825
    default:
826
        break;
827
    }
828
}
829

    
830
static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
831
{
832
    openpic_t *opp = opaque;
833
    IRQ_src_t *src;
834
    IRQ_dst_t *dst;
835
    uint32_t retval;
836
    int idx, n_IRQ;
837

    
838
    DPRINTF("%s: addr %08x\n", __func__, addr);
839
    retval = 0xFFFFFFFF;
840
    if (addr & 0xF)
841
        return retval;
842
    addr &= 0x1FFF0;
843
    idx = addr / 0x1000;
844
    dst = &opp->dst[idx];
845
    addr &= 0xFF0;
846
    switch (addr) {
847
    case 0x80: /* PCTP */
848
        retval = dst->pctp;
849
        break;
850
    case 0x90: /* WHOAMI */
851
        retval = idx;
852
        break;
853
    case 0xA0: /* PIAC */
854
        DPRINTF("Lower OpenPIC INT output\n");
855
        qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
856
        n_IRQ = IRQ_get_next(opp, &dst->raised);
857
        DPRINTF("PIAC: irq=%d\n", n_IRQ);
858
        if (n_IRQ == -1) {
859
            /* No more interrupt pending */
860
            retval = IPVP_VECTOR(opp->spve);
861
        } else {
862
            src = &opp->src[n_IRQ];
863
            if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
864
                !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
865
                /* - Spurious level-sensitive IRQ
866
                 * - Priorities has been changed
867
                 *   and the pending IRQ isn't allowed anymore
868
                 */
869
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
870
                retval = IPVP_VECTOR(opp->spve);
871
            } else {
872
                /* IRQ enter servicing state */
873
                IRQ_setbit(&dst->servicing, n_IRQ);
874
                retval = IPVP_VECTOR(src->ipvp);
875
            }
876
            IRQ_resetbit(&dst->raised, n_IRQ);
877
            dst->raised.next = -1;
878
            if (!test_bit(&src->ipvp, IPVP_SENSE)) {
879
                /* edge-sensitive IRQ */
880
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
881
                src->pending = 0;
882
            }
883
        }
884
        break;
885
    case 0xB0: /* PEOI */
886
        retval = 0;
887
        break;
888
#if MAX_IPI > 0
889
    case 0x40: /* IDE */
890
    case 0x50:
891
        idx = (addr - 0x40) >> 4;
892
        retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE);
893
        break;
894
#endif
895
    default:
896
        break;
897
    }
898
    DPRINTF("%s: => %08x\n", __func__, retval);
899
#if defined OPENPIC_SWAP
900
    retval= bswap32(retval);
901
#endif
902

    
903
    return retval;
904
}
905

    
906
static void openpic_buggy_write (void *opaque,
907
                                 target_phys_addr_t addr, uint32_t val)
908
{
909
    printf("Invalid OPENPIC write access !\n");
910
}
911

    
912
static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
913
{
914
    printf("Invalid OPENPIC read access !\n");
915

    
916
    return -1;
917
}
918

    
919
static void openpic_writel (void *opaque,
920
                            target_phys_addr_t addr, uint32_t val)
921
{
922
    openpic_t *opp = opaque;
923

    
924
    addr &= 0x3FFFF;
925
    DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
926
    if (addr < 0x1100) {
927
        /* Global registers */
928
        openpic_gbl_write(opp, addr, val);
929
    } else if (addr < 0x10000) {
930
        /* Timers registers */
931
        openpic_timer_write(opp, addr, val);
932
    } else if (addr < 0x20000) {
933
        /* Source registers */
934
        openpic_src_write(opp, addr, val);
935
    } else {
936
        /* CPU registers */
937
        openpic_cpu_write(opp, addr, val);
938
    }
939
}
940

    
941
static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
942
{
943
    openpic_t *opp = opaque;
944
    uint32_t retval;
945

    
946
    addr &= 0x3FFFF;
947
    DPRINTF("%s: offset %08x\n", __func__, (int)addr);
948
    if (addr < 0x1100) {
949
        /* Global registers */
950
        retval = openpic_gbl_read(opp, addr);
951
    } else if (addr < 0x10000) {
952
        /* Timers registers */
953
        retval = openpic_timer_read(opp, addr);
954
    } else if (addr < 0x20000) {
955
        /* Source registers */
956
        retval = openpic_src_read(opp, addr);
957
    } else {
958
        /* CPU registers */
959
        retval = openpic_cpu_read(opp, addr);
960
    }
961

    
962
    return retval;
963
}
964

    
965
static CPUWriteMemoryFunc *openpic_write[] = {
966
    &openpic_buggy_write,
967
    &openpic_buggy_write,
968
    &openpic_writel,
969
};
970

    
971
static CPUReadMemoryFunc *openpic_read[] = {
972
    &openpic_buggy_read,
973
    &openpic_buggy_read,
974
    &openpic_readl,
975
};
976

    
977
static void openpic_map(PCIDevice *pci_dev, int region_num,
978
                        uint32_t addr, uint32_t size, int type)
979
{
980
    openpic_t *opp;
981

    
982
    DPRINTF("Map OpenPIC\n");
983
    opp = (openpic_t *)pci_dev;
984
    /* Global registers */
985
    DPRINTF("Register OPENPIC gbl   %08x => %08x\n",
986
            addr + 0x1000, addr + 0x1000 + 0x100);
987
    /* Timer registers */
988
    DPRINTF("Register OPENPIC timer %08x => %08x\n",
989
            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
990
    /* Interrupt source registers */
991
    DPRINTF("Register OPENPIC src   %08x => %08x\n",
992
            addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2));
993
    /* Per CPU registers */
994
    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
995
            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
996
    cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
997
#if 0 // Don't implement ISU for now
998
    opp_io_memory = cpu_register_io_memory(0, openpic_src_read,
999
                                           openpic_src_write);
1000
    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
1001
                                 opp_io_memory);
1002
#endif
1003
}
1004

    
1005
static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
1006
{
1007
    unsigned int i;
1008

    
1009
    for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
1010
        qemu_put_be32s(f, &q->queue[i]);
1011

    
1012
    qemu_put_sbe32s(f, &q->next);
1013
    qemu_put_sbe32s(f, &q->priority);
1014
}
1015

    
1016
static void openpic_save(QEMUFile* f, void *opaque)
1017
{
1018
    openpic_t *opp = (openpic_t *)opaque;
1019
    unsigned int i;
1020

    
1021
    qemu_put_be32s(f, &opp->frep);
1022
    qemu_put_be32s(f, &opp->glbc);
1023
    qemu_put_be32s(f, &opp->micr);
1024
    qemu_put_be32s(f, &opp->veni);
1025
    qemu_put_be32s(f, &opp->pint);
1026
    qemu_put_be32s(f, &opp->spve);
1027
    qemu_put_be32s(f, &opp->tifr);
1028

    
1029
    for (i = 0; i < MAX_IRQ; i++) {
1030
        qemu_put_be32s(f, &opp->src[i].ipvp);
1031
        qemu_put_be32s(f, &opp->src[i].ide);
1032
        qemu_put_sbe32s(f, &opp->src[i].type);
1033
        qemu_put_sbe32s(f, &opp->src[i].last_cpu);
1034
        qemu_put_sbe32s(f, &opp->src[i].pending);
1035
    }
1036

    
1037
    for (i = 0; i < MAX_IRQ; i++) {
1038
        qemu_put_be32s(f, &opp->dst[i].pctp);
1039
        qemu_put_be32s(f, &opp->dst[i].pcsr);
1040
        openpic_save_IRQ_queue(f, &opp->dst[i].raised);
1041
        openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
1042
    }
1043

    
1044
    qemu_put_sbe32s(f, &opp->nb_cpus);
1045

    
1046
    for (i = 0; i < MAX_TMR; i++) {
1047
        qemu_put_be32s(f, &opp->timers[i].ticc);
1048
        qemu_put_be32s(f, &opp->timers[i].tibc);
1049
    }
1050

    
1051
#if MAX_DBL > 0
1052
    qemu_put_be32s(f, &opp->dar);
1053

    
1054
    for (i = 0; i < MAX_DBL; i++) {
1055
        qemu_put_be32s(f, &opp->doorbells[i].dmr);
1056
    }
1057
#endif
1058

    
1059
#if MAX_MBX > 0
1060
    for (i = 0; i < MAX_MAILBOXES; i++) {
1061
        qemu_put_be32s(f, &opp->mailboxes[i].mbr);
1062
    }
1063
#endif
1064

    
1065
    pci_device_save(&opp->pci_dev, f);
1066
}
1067

    
1068
static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
1069
{
1070
    unsigned int i;
1071

    
1072
    for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
1073
        qemu_get_be32s(f, &q->queue[i]);
1074

    
1075
    qemu_get_sbe32s(f, &q->next);
1076
    qemu_get_sbe32s(f, &q->priority);
1077
}
1078

    
1079
static int openpic_load(QEMUFile* f, void *opaque, int version_id)
1080
{
1081
    openpic_t *opp = (openpic_t *)opaque;
1082
    unsigned int i;
1083

    
1084
    if (version_id != 1)
1085
        return -EINVAL;
1086

    
1087
    qemu_get_be32s(f, &opp->frep);
1088
    qemu_get_be32s(f, &opp->glbc);
1089
    qemu_get_be32s(f, &opp->micr);
1090
    qemu_get_be32s(f, &opp->veni);
1091
    qemu_get_be32s(f, &opp->pint);
1092
    qemu_get_be32s(f, &opp->spve);
1093
    qemu_get_be32s(f, &opp->tifr);
1094

    
1095
    for (i = 0; i < MAX_IRQ; i++) {
1096
        qemu_get_be32s(f, &opp->src[i].ipvp);
1097
        qemu_get_be32s(f, &opp->src[i].ide);
1098
        qemu_get_sbe32s(f, &opp->src[i].type);
1099
        qemu_get_sbe32s(f, &opp->src[i].last_cpu);
1100
        qemu_get_sbe32s(f, &opp->src[i].pending);
1101
    }
1102

    
1103
    for (i = 0; i < MAX_IRQ; i++) {
1104
        qemu_get_be32s(f, &opp->dst[i].pctp);
1105
        qemu_get_be32s(f, &opp->dst[i].pcsr);
1106
        openpic_load_IRQ_queue(f, &opp->dst[i].raised);
1107
        openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
1108
    }
1109

    
1110
    qemu_get_sbe32s(f, &opp->nb_cpus);
1111

    
1112
    for (i = 0; i < MAX_TMR; i++) {
1113
        qemu_get_be32s(f, &opp->timers[i].ticc);
1114
        qemu_get_be32s(f, &opp->timers[i].tibc);
1115
    }
1116

    
1117
#if MAX_DBL > 0
1118
    qemu_get_be32s(f, &opp->dar);
1119

    
1120
    for (i = 0; i < MAX_DBL; i++) {
1121
        qemu_get_be32s(f, &opp->doorbells[i].dmr);
1122
    }
1123
#endif
1124

    
1125
#if MAX_MBX > 0
1126
    for (i = 0; i < MAX_MAILBOXES; i++) {
1127
        qemu_get_be32s(f, &opp->mailboxes[i].mbr);
1128
    }
1129
#endif
1130

    
1131
    return pci_device_load(&opp->pci_dev, f);
1132
}
1133

    
1134
qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
1135
                        qemu_irq **irqs, qemu_irq irq_out)
1136
{
1137
    openpic_t *opp;
1138
    uint8_t *pci_conf;
1139
    int i, m;
1140

    
1141
    /* XXX: for now, only one CPU is supported */
1142
    if (nb_cpus != 1)
1143
        return NULL;
1144
    if (bus) {
1145
        opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
1146
                                               -1, NULL, NULL);
1147
        if (opp == NULL)
1148
            return NULL;
1149
        pci_conf = opp->pci_dev.config;
1150
        pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
1151
        pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
1152
        pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
1153
        pci_conf[0x0e] = 0x00; // header_type
1154
        pci_conf[0x3d] = 0x00; // no interrupt pin
1155

    
1156
        /* Register I/O spaces */
1157
        pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
1158
                               PCI_ADDRESS_SPACE_MEM, &openpic_map);
1159
    } else {
1160
        opp = qemu_mallocz(sizeof(openpic_t));
1161
    }
1162
    opp->mem_index = cpu_register_io_memory(0, openpic_read,
1163
                                            openpic_write, opp);
1164

    
1165
    //    isu_base &= 0xFFFC0000;
1166
    opp->nb_cpus = nb_cpus;
1167
    /* Set IRQ types */
1168
    for (i = 0; i < EXT_IRQ; i++) {
1169
        opp->src[i].type = IRQ_EXTERNAL;
1170
    }
1171
    for (; i < IRQ_TIM0; i++) {
1172
        opp->src[i].type = IRQ_SPECIAL;
1173
    }
1174
#if MAX_IPI > 0
1175
    m = IRQ_IPI0;
1176
#else
1177
    m = IRQ_DBL0;
1178
#endif
1179
    for (; i < m; i++) {
1180
        opp->src[i].type = IRQ_TIMER;
1181
    }
1182
    for (; i < MAX_IRQ; i++) {
1183
        opp->src[i].type = IRQ_INTERNAL;
1184
    }
1185
    for (i = 0; i < nb_cpus; i++)
1186
        opp->dst[i].irqs = irqs[i];
1187
    opp->irq_out = irq_out;
1188

    
1189
    register_savevm("openpic", 0, 1, openpic_save, openpic_load, opp);
1190
    qemu_register_reset(openpic_reset, opp);
1191
    openpic_reset(opp);
1192
    if (pmem_index)
1193
        *pmem_index = opp->mem_index;
1194

    
1195
    return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);
1196
}