Statistics
| Branch: | Revision:

root / hw / openpic.c @ 173a543b

History | View | Annotate | Download (27.8 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 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 "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 (openpic_t *opp)
371
{
372
    int i;
373

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

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

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

    
430
    return retval;
431
}
432

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

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

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

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

478
    return retval;
479
}
480

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

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

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

    
516
    return retval;
517
}
518

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

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

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

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

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

    
646
    return retval;
647
}
648

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

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

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

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

    
716
    return retval;
717
}
718

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

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

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

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

    
765
    return retval;
766
}
767

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

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

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

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

    
902
    return retval;
903
}
904

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

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

    
915
    return -1;
916
}
917

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

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

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

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

    
961
    return retval;
962
}
963

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

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

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

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

    
1004
qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
1005
                        qemu_irq **irqs, qemu_irq irq_out)
1006
{
1007
    openpic_t *opp;
1008
    uint8_t *pci_conf;
1009
    int i, m;
1010

    
1011
    /* XXX: for now, only one CPU is supported */
1012
    if (nb_cpus != 1)
1013
        return NULL;
1014
    if (bus) {
1015
        opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
1016
                                               -1, NULL, NULL);
1017
        if (opp == NULL)
1018
            return NULL;
1019
        pci_conf = opp->pci_dev.config;
1020
        pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
1021
        pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
1022
        pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
1023
        pci_conf[0x0e] = 0x00; // header_type
1024
        pci_conf[0x3d] = 0x00; // no interrupt pin
1025

    
1026
        /* Register I/O spaces */
1027
        pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
1028
                               PCI_ADDRESS_SPACE_MEM, &openpic_map);
1029
    } else {
1030
        opp = qemu_mallocz(sizeof(openpic_t));
1031
    }
1032
    opp->mem_index = cpu_register_io_memory(0, openpic_read,
1033
                                            openpic_write, opp);
1034

    
1035
    //    isu_base &= 0xFFFC0000;
1036
    opp->nb_cpus = nb_cpus;
1037
    /* Set IRQ types */
1038
    for (i = 0; i < EXT_IRQ; i++) {
1039
        opp->src[i].type = IRQ_EXTERNAL;
1040
    }
1041
    for (; i < IRQ_TIM0; i++) {
1042
        opp->src[i].type = IRQ_SPECIAL;
1043
    }
1044
#if MAX_IPI > 0
1045
    m = IRQ_IPI0;
1046
#else
1047
    m = IRQ_DBL0;
1048
#endif
1049
    for (; i < m; i++) {
1050
        opp->src[i].type = IRQ_TIMER;
1051
    }
1052
    for (; i < MAX_IRQ; i++) {
1053
        opp->src[i].type = IRQ_INTERNAL;
1054
    }
1055
    for (i = 0; i < nb_cpus; i++)
1056
        opp->dst[i].irqs = irqs[i];
1057
    opp->irq_out = irq_out;
1058
    openpic_reset(opp);
1059
    if (pmem_index)
1060
        *pmem_index = opp->mem_index;
1061

    
1062
    return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);
1063
}