Statistics
| Branch: | Revision:

root / hw / openpic.c @ 611493d9

History | View | Annotate | Download (25.5 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 "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    48
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

    
77
enum {
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

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

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

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

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

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

    
137
typedef 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 pending;    /* TRUE if IRQ is pending */
143
} IRQ_src_t;
144

    
145
enum 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_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
154
#define IPVP_VECTOR_MASK       ((1 << VECTOR_BITS) - 1)
155
#define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)
156

    
157
typedef 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

    
165
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
};
198

    
199
static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
200
{
201
    set_bit(q->queue, n_IRQ);
202
}
203

    
204
static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
205
{
206
    reset_bit(q->queue, n_IRQ);
207
}
208

    
209
static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
210
{
211
    return test_bit(q->queue, n_IRQ);
212
}
213

    
214
static 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
            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", 
224
                    i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
225
            if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
226
                next = i;
227
                priority = IPVP_PRIORITY(opp->src[i].ipvp);
228
            }
229
        }
230
    }
231
    q->next = next;
232
    q->priority = priority;
233
}
234

    
235
static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
236
{
237
    if (q->next == -1) {
238
        /* XXX: optimize */
239
        IRQ_check(opp, q);
240
    }
241

    
242
    return q->next;
243
}
244

    
245
static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
246
{
247
    IRQ_dst_t *dst;
248
    IRQ_src_t *src;
249
    int priority;
250

    
251
    dst = &opp->dst[n_CPU];
252
    src = &opp->src[n_IRQ];
253
    priority = IPVP_PRIORITY(src->ipvp);
254
    if (priority <= dst->pctp) {
255
        /* Too low priority */
256
        return;
257
    }
258
    if (IRQ_testbit(&dst->raised, n_IRQ)) {
259
        /* Interrupt miss */
260
        return;
261
    }
262
    set_bit(&src->ipvp, IPVP_ACTIVITY);
263
    IRQ_setbit(&dst->raised, n_IRQ);
264
    if (priority > dst->raised.priority) {
265
        IRQ_get_next(opp, &dst->raised);
266
        DPRINTF("Raise CPU IRQ\n");
267
        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
268
    }
269
}
270

    
271
/* update pic state because registers for n_IRQ have changed value */
272
static void openpic_update_irq(openpic_t *opp, int n_IRQ)
273
{
274
    IRQ_src_t *src;
275
    int i;
276

    
277
    src = &opp->src[n_IRQ];
278

    
279
    if (!src->pending) {
280
        /* no irq pending */
281
        return;
282
    }
283
    if (test_bit(&src->ipvp, IPVP_MASK)) {
284
        /* Interrupt source is disabled */
285
        return;
286
    }
287
    if (IPVP_PRIORITY(src->ipvp) == 0) {
288
        /* Priority set to zero */
289
        return;
290
    }
291
    if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
292
        /* IRQ already active */
293
        return;
294
    }
295
    if (src->ide == 0x00000000) {
296
        /* No target */
297
        return;
298
    }
299

    
300
    if (!test_bit(&src->ipvp, IPVP_MODE) ||
301
        src->ide == (1 << src->last_cpu)) {
302
        /* Directed delivery mode */
303
        for (i = 0; i < opp->nb_cpus; i++) {
304
            if (test_bit(&src->ide, i))
305
                IRQ_local_pipe(opp, i, n_IRQ);
306
        }
307
    } else {
308
        /* Distributed delivery mode */
309
        /* XXX: incorrect code */
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
void openpic_set_irq(openpic_t *opp, int n_IRQ, int level)
323
{
324
    IRQ_src_t *src;
325

    
326
    src = &opp->src[n_IRQ];
327
    DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", 
328
            n_IRQ, level, src->ipvp);
329
    if (test_bit(&src->ipvp, IPVP_SENSE)) {
330
        /* level-sensitive irq */
331
        src->pending = level;
332
        if (!level)
333
            reset_bit(&src->ipvp, IPVP_ACTIVITY);
334
    } else {
335
        /* edge-sensitive irq */
336
        if (level)
337
            src->pending = 1;
338
    }
339
    openpic_update_irq(opp, n_IRQ);
340
}
341

    
342
static void openpic_reset (openpic_t *opp)
343
{
344
    int i;
345

    
346
    opp->glbc = 0x80000000;
347
    /* Initialise controler registers */
348
    opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
349
    opp->veni = VENI;
350
    opp->spve = 0x000000FF;
351
    opp->tifr = 0x003F7A00;
352
    /* ? */
353
    opp->micr = 0x00000000;
354
    /* Initialise IRQ sources */
355
    for (i = 0; i < MAX_IRQ; i++) {
356
        opp->src[i].ipvp = 0xA0000000;
357
        opp->src[i].ide  = 0x00000000;
358
    }
359
    /* Initialise IRQ destinations */
360
    for (i = 0; i < opp->nb_cpus; i++) {
361
        opp->dst[i].pctp      = 0x0000000F;
362
        opp->dst[i].pcsr      = 0x00000000;
363
        memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
364
        memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
365
    }
366
    /* Initialise timers */
367
    for (i = 0; i < MAX_TMR; i++) {
368
        opp->timers[i].ticc = 0x00000000;
369
        opp->timers[i].tibc = 0x80000000;
370
    }
371
    /* Initialise doorbells */
372
#if MAX_DBL > 0
373
    opp->dar = 0x00000000;
374
    for (i = 0; i < MAX_DBL; i++) {
375
        opp->doorbells[i].dmr  = 0x00000000;
376
    }
377
#endif
378
    /* Initialise mailboxes */
379
#if MAX_MBX > 0
380
    for (i = 0; i < MAX_MBX; i++) { /* ? */
381
        opp->mailboxes[i].mbr   = 0x00000000;
382
    }
383
#endif
384
    /* Go out of RESET state */
385
    opp->glbc = 0x00000000;
386
}
387

    
388
static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
389
{
390
    uint32_t retval;
391

    
392
    switch (reg) {
393
    case IRQ_IPVP:
394
        retval = opp->src[n_IRQ].ipvp;
395
        break;
396
    case IRQ_IDE:
397
        retval = opp->src[n_IRQ].ide;
398
        break;
399
    }
400

    
401
    return retval;
402
}
403

    
404
static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
405
                                 uint32_t reg, uint32_t val)
406
{
407
    uint32_t tmp;
408

    
409
    switch (reg) {
410
    case IRQ_IPVP:
411
        /* NOTE: not fully accurate for special IRQs, but simple and
412
           sufficient */
413
        /* ACTIVITY bit is read-only */
414
        opp->src[n_IRQ].ipvp = 
415
            (opp->src[n_IRQ].ipvp & 0x40000000) |
416
            (val & 0x800F00FF);
417
        openpic_update_irq(opp, n_IRQ);
418
        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", 
419
                n_IRQ, val, opp->src[n_IRQ].ipvp);
420
        break;
421
    case IRQ_IDE:
422
        tmp = val & 0xC0000000;
423
        tmp |= val & ((1 << MAX_CPU) - 1);
424
        opp->src[n_IRQ].ide = tmp;
425
        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
426
        break;
427
    }
428
}
429

    
430
#if 0 // Code provision for Intel model
431
#if MAX_DBL > 0
432
static uint32_t read_doorbell_register (openpic_t *opp,
433
                                        int n_dbl, uint32_t offset)
434
{
435
    uint32_t retval;
436

437
    switch (offset) {
438
    case DBL_IPVP_OFFSET:
439
        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
440
        break;
441
    case DBL_IDE_OFFSET:
442
        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
443
        break;
444
    case DBL_DMR_OFFSET:
445
        retval = opp->doorbells[n_dbl].dmr;
446
        break;
447
    }
448

449
    return retval;
450
}
451
     
452
static void write_doorbell_register (penpic_t *opp, int n_dbl,
453
                                     uint32_t offset, uint32_t value)
454
{
455
    switch (offset) {
456
    case DBL_IVPR_OFFSET:
457
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
458
        break;
459
    case DBL_IDE_OFFSET:
460
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
461
        break;
462
    case DBL_DMR_OFFSET:
463
        opp->doorbells[n_dbl].dmr = value;
464
        break;
465
    }
466
}
467
#endif
468

    
469
#if MAX_MBX > 0
470
static uint32_t read_mailbox_register (openpic_t *opp,
471
                                       int n_mbx, uint32_t offset)
472
{
473
    uint32_t retval;
474

    
475
    switch (offset) {
476
    case MBX_MBR_OFFSET:
477
        retval = opp->mailboxes[n_mbx].mbr;
478
        break;
479
    case MBX_IVPR_OFFSET:
480
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
481
        break;
482
    case MBX_DMR_OFFSET:
483
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
484
        break;
485
    }
486

    
487
    return retval;
488
}
489

    
490
static void write_mailbox_register (openpic_t *opp, int n_mbx,
491
                                    uint32_t address, uint32_t value)
492
{
493
    switch (offset) {
494
    case MBX_MBR_OFFSET:
495
        opp->mailboxes[n_mbx].mbr = value;
496
        break;
497
    case MBX_IVPR_OFFSET:
498
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
499
        break;
500
    case MBX_DMR_OFFSET:
501
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
502
        break;
503
    }
504
}
505
#endif
506
#endif /* 0 : Code provision for Intel model */
507

    
508
static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
509
{
510
    openpic_t *opp = opaque;
511

    
512
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
513
    if (addr & 0xF)
514
        return;
515
#if defined OPENPIC_SWAP
516
    val = bswap32(val);
517
#endif
518
    addr &= 0xFF;
519
    switch (addr) {
520
    case 0x00: /* FREP */
521
        break;
522
    case 0x20: /* GLBC */
523
        if (val & 0x80000000)
524
            openpic_reset(opp);
525
        opp->glbc = val & ~0x80000000;
526
        break;
527
    case 0x80: /* VENI */
528
        break;
529
    case 0x90: /* PINT */
530
        /* XXX: Should be able to reset any CPU */
531
        if (val & 1) {
532
            DPRINTF("Reset CPU IRQ\n");
533
            //            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET);
534
        }
535
        break;
536
#if MAX_IPI > 0
537
    case 0xA0: /* IPI_IPVP */
538
    case 0xB0:
539
    case 0xC0:
540
    case 0xD0:
541
        {
542
            int idx;
543
            idx = (addr - 0xA0) >> 4;
544
            write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
545
        }
546
        break;
547
#endif
548
    case 0xE0: /* SPVE */
549
        opp->spve = val & 0x000000FF;
550
        break;
551
    case 0xF0: /* TIFR */
552
        opp->tifr = val;
553
        break;
554
    default:
555
        break;
556
    }
557
}
558

    
559
static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
560
{
561
    openpic_t *opp = opaque;
562
    uint32_t retval;
563

    
564
    DPRINTF("%s: addr %08x\n", __func__, addr);
565
    retval = 0xFFFFFFFF;
566
    if (addr & 0xF)
567
        return retval;
568
    addr &= 0xFF;
569
    switch (addr) {
570
    case 0x00: /* FREP */
571
        retval = opp->frep;
572
        break;
573
    case 0x20: /* GLBC */
574
        retval = opp->glbc;
575
        break;
576
    case 0x80: /* VENI */
577
        retval = opp->veni;
578
        break;
579
    case 0x90: /* PINT */
580
        retval = 0x00000000;
581
        break;
582
#if MAX_IPI > 0
583
    case 0xA0: /* IPI_IPVP */
584
    case 0xB0:
585
    case 0xC0:
586
    case 0xD0:
587
        {
588
            int idx;
589
            idx = (addr - 0xA0) >> 4;
590
            retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
591
        }
592
        break;
593
#endif
594
    case 0xE0: /* SPVE */
595
        retval = opp->spve;
596
        break;
597
    case 0xF0: /* TIFR */
598
        retval = opp->tifr;
599
        break;
600
    default:
601
        break;
602
    }
603
    DPRINTF("%s: => %08x\n", __func__, retval);
604
#if defined OPENPIC_SWAP
605
    retval = bswap32(retval);
606
#endif
607

    
608
    return retval;
609
}
610

    
611
static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
612
{
613
    openpic_t *opp = opaque;
614
    int idx;
615

    
616
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
617
    if (addr & 0xF)
618
        return;
619
#if defined OPENPIC_SWAP
620
    val = bswap32(val);
621
#endif
622
    addr -= 0x1100;
623
    addr &= 0xFFFF;
624
    idx = (addr & 0xFFF0) >> 6;
625
    addr = addr & 0x30;
626
    switch (addr) {
627
    case 0x00: /* TICC */
628
        break;
629
    case 0x10: /* TIBC */
630
        if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
631
            (val & 0x800000000) == 0 &&
632
            (opp->timers[idx].tibc & 0x80000000) != 0)
633
            opp->timers[idx].ticc &= ~0x80000000;
634
        opp->timers[idx].tibc = val;
635
        break;
636
    case 0x20: /* TIVP */
637
        write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val);
638
        break;
639
    case 0x30: /* TIDE */
640
        write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val);
641
        break;
642
    }
643
}
644

    
645
static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
646
{
647
    openpic_t *opp = opaque;
648
    uint32_t retval;
649
    int idx;
650

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

    
678
    return retval;
679
}
680

    
681
static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
682
{
683
    openpic_t *opp = opaque;
684
    int idx;
685

    
686
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
687
    if (addr & 0xF)
688
        return;
689
#if defined OPENPIC_SWAP
690
    val = tswap32(val);
691
#endif
692
    addr = addr & 0xFFF0;
693
    idx = addr >> 5;
694
    if (addr & 0x10) {
695
        /* EXDE / IFEDE / IEEDE */
696
        write_IRQreg(opp, idx, IRQ_IDE, val);
697
    } else {
698
        /* EXVP / IFEVP / IEEVP */
699
        write_IRQreg(opp, idx, IRQ_IPVP, val);
700
    }
701
}
702

    
703
static uint32_t openpic_src_read (void *opaque, uint32_t addr)
704
{
705
    openpic_t *opp = opaque;
706
    uint32_t retval;
707
    int idx;
708

    
709
    DPRINTF("%s: addr %08x\n", __func__, addr);
710
    retval = 0xFFFFFFFF;
711
    if (addr & 0xF)
712
        return retval;
713
    addr = addr & 0xFFF0;
714
    idx = addr >> 5;
715
    if (addr & 0x10) {
716
        /* EXDE / IFEDE / IEEDE */
717
        retval = read_IRQreg(opp, idx, IRQ_IDE);
718
    } else {
719
        /* EXVP / IFEVP / IEEVP */
720
        retval = read_IRQreg(opp, idx, IRQ_IPVP);
721
    }
722
    DPRINTF("%s: => %08x\n", __func__, retval);
723
#if defined OPENPIC_SWAP
724
    retval = tswap32(retval);
725
#endif
726

    
727
    return retval;
728
}
729

    
730
static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
731
{
732
    openpic_t *opp = opaque;
733
    IRQ_src_t *src;
734
    IRQ_dst_t *dst;
735
    int idx, n_IRQ;
736

    
737
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
738
    if (addr & 0xF)
739
        return;
740
#if defined OPENPIC_SWAP
741
    val = bswap32(val);
742
#endif
743
    addr &= 0x1FFF0;
744
    idx = addr / 0x1000;
745
    dst = &opp->dst[idx];
746
    addr &= 0xFF0;
747
    switch (addr) {
748
#if MAX_IPI > 0
749
    case 0x40: /* PIPD */
750
    case 0x50:
751
    case 0x60:
752
    case 0x70:
753
        idx = (addr - 0x40) >> 4;
754
        write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val);
755
        openpic_set_irq(opp, IRQ_IPI0 + idx, 1);
756
        openpic_set_irq(opp, IRQ_IPI0 + idx, 0);
757
        break;
758
#endif
759
    case 0x80: /* PCTP */
760
        dst->pctp = val & 0x0000000F;
761
        break;
762
    case 0x90: /* WHOAMI */
763
        /* Read-only register */
764
        break;
765
    case 0xA0: /* PIAC */
766
        /* Read-only register */
767
        break;
768
    case 0xB0: /* PEOI */
769
        DPRINTF("PEOI\n");
770
        n_IRQ = IRQ_get_next(opp, &dst->servicing);
771
        IRQ_resetbit(&dst->servicing, n_IRQ);
772
        dst->servicing.next = -1;
773
        src = &opp->src[n_IRQ];
774
        /* Set up next servicing IRQ */
775
        IRQ_get_next(opp, &dst->servicing);
776
        /* Check queued interrupts. */
777
        n_IRQ = IRQ_get_next(opp, &dst->raised);
778
        if (n_IRQ != -1) {
779
            src = &opp->src[n_IRQ];
780
            if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
781
                DPRINTF("Raise CPU IRQ\n");
782
                cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
783
            }
784
        }
785
        break;
786
    default:
787
        break;
788
    }
789
}
790

    
791
static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
792
{
793
    openpic_t *opp = opaque;
794
    IRQ_src_t *src;
795
    IRQ_dst_t *dst;
796
    uint32_t retval;
797
    int idx, n_IRQ;
798
    
799
    DPRINTF("%s: addr %08x\n", __func__, addr);
800
    retval = 0xFFFFFFFF;
801
    if (addr & 0xF)
802
        return retval;
803
    addr &= 0x1FFF0;
804
    idx = addr / 0x1000;
805
    dst = &opp->dst[idx];
806
    addr &= 0xFF0;
807
    switch (addr) {
808
    case 0x80: /* PCTP */
809
        retval = dst->pctp;
810
        break;
811
    case 0x90: /* WHOAMI */
812
        retval = idx;
813
        break;
814
    case 0xA0: /* PIAC */
815
        n_IRQ = IRQ_get_next(opp, &dst->raised);
816
        DPRINTF("PIAC: irq=%d\n", n_IRQ);
817
        if (n_IRQ == -1) {
818
            /* No more interrupt pending */
819
            retval = opp->spve;
820
        } else {
821
            src = &opp->src[n_IRQ];
822
            if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
823
                !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
824
                /* - Spurious level-sensitive IRQ
825
                 * - Priorities has been changed
826
                 *   and the pending IRQ isn't allowed anymore
827
                 */
828
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
829
                retval = IPVP_VECTOR(opp->spve);
830
            } else {
831
                /* IRQ enter servicing state */
832
                IRQ_setbit(&dst->servicing, n_IRQ);
833
                retval = IPVP_VECTOR(src->ipvp);
834
            }
835
            IRQ_resetbit(&dst->raised, n_IRQ);
836
            dst->raised.next = -1;
837
            if (!test_bit(&src->ipvp, IPVP_SENSE)) {
838
                /* edge-sensitive IRQ */
839
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
840
                src->pending = 0;
841
            }
842
        }
843
        break;
844
    case 0xB0: /* PEOI */
845
        retval = 0;
846
        break;
847
#if MAX_IPI > 0
848
    case 0x40: /* IDE */
849
    case 0x50:
850
        idx = (addr - 0x40) >> 4;
851
        retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE);
852
        break;
853
#endif
854
    default:
855
        break;
856
    }
857
    DPRINTF("%s: => %08x\n", __func__, retval);
858
#if defined OPENPIC_SWAP
859
    retval= bswap32(retval);
860
#endif
861

    
862
    return retval;
863
}
864

    
865
static void openpic_buggy_write (void *opaque,
866
                                 target_phys_addr_t addr, uint32_t val)
867
{
868
    printf("Invalid OPENPIC write access !\n");
869
}
870

    
871
static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
872
{
873
    printf("Invalid OPENPIC read access !\n");
874

    
875
    return -1;
876
}
877

    
878
static void openpic_writel (void *opaque,
879
                            target_phys_addr_t addr, uint32_t val)
880
{
881
    openpic_t *opp = opaque;
882

    
883
    addr &= 0x3FFFF;
884
    DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
885
    if (addr < 0x1100) {
886
        /* Global registers */
887
        openpic_gbl_write(opp, addr, val);
888
    } else if (addr < 0x10000) {
889
        /* Timers registers */
890
        openpic_timer_write(opp, addr, val);
891
    } else if (addr < 0x20000) {
892
        /* Source registers */
893
        openpic_src_write(opp, addr, val);
894
    } else {
895
        /* CPU registers */
896
        openpic_cpu_write(opp, addr, val);
897
    }
898
}
899

    
900
static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
901
{
902
    openpic_t *opp = opaque;
903
    uint32_t retval;
904

    
905
    addr &= 0x3FFFF;
906
    DPRINTF("%s: offset %08x\n", __func__, (int)addr);
907
    if (addr < 0x1100) {
908
        /* Global registers */
909
        retval = openpic_gbl_read(opp, addr);
910
    } else if (addr < 0x10000) {
911
        /* Timers registers */
912
        retval = openpic_timer_read(opp, addr);
913
    } else if (addr < 0x20000) {
914
        /* Source registers */
915
        retval = openpic_src_read(opp, addr);
916
    } else {
917
        /* CPU registers */
918
        retval = openpic_cpu_read(opp, addr);
919
    }
920

    
921
    return retval;
922
}
923

    
924
static CPUWriteMemoryFunc *openpic_write[] = {
925
    &openpic_buggy_write,
926
    &openpic_buggy_write,
927
    &openpic_writel,
928
};
929

    
930
static CPUReadMemoryFunc *openpic_read[] = {
931
    &openpic_buggy_read,
932
    &openpic_buggy_read,
933
    &openpic_readl,
934
};
935

    
936
static void openpic_map(PCIDevice *pci_dev, int region_num, 
937
                        uint32_t addr, uint32_t size, int type)
938
{
939
    openpic_t *opp;
940
    int opp_io_memory;
941

    
942
    DPRINTF("Map OpenPIC\n");
943
    opp = (openpic_t *)pci_dev;
944
    /* Global registers */
945
    DPRINTF("Register OPENPIC gbl   %08x => %08x\n",
946
            addr + 0x1000, addr + 0x1000 + 0x100);
947
    /* Timer registers */
948
    DPRINTF("Register OPENPIC timer %08x => %08x\n",
949
            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
950
    /* Interrupt source registers */
951
    DPRINTF("Register OPENPIC src   %08x => %08x\n",
952
            addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2));
953
    /* Per CPU registers */
954
    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
955
            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
956
    opp_io_memory = cpu_register_io_memory(0, openpic_read,
957
                                           openpic_write, opp);
958
    cpu_register_physical_memory(addr, 0x40000, opp_io_memory);
959
#if 0 // Don't implement ISU for now
960
    opp_io_memory = cpu_register_io_memory(0, openpic_src_read,
961
                                           openpic_src_write);
962
    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
963
                                 opp_io_memory);
964
#endif
965
}
966

    
967
openpic_t *openpic_init (uint32_t isu_base, uint32_t idu_base, int nb_cpus)
968
{
969
    openpic_t *opp;
970
    uint8_t *pci_conf;
971
    int i, m;
972
    
973
    /* XXX: for now, only one CPU is supported */
974
    if (nb_cpus != 1)
975
        return NULL;
976
    opp = (openpic_t *)pci_register_device("OpenPIC", sizeof(openpic_t),
977
                                           0, -1, NULL, NULL);
978
    if (opp == NULL)
979
        return NULL;
980
    pci_conf = opp->pci_dev.config;
981
    pci_conf[0x00] = 0x14; // IBM MPIC2
982
    pci_conf[0x01] = 0x10;
983
    pci_conf[0x02] = 0xFF;
984
    pci_conf[0x03] = 0xFF;
985
    pci_conf[0x0a] = 0x80; // PIC
986
    pci_conf[0x0b] = 0x08;
987
    pci_conf[0x0e] = 0x00; // header_type
988
    pci_conf[0x3d] = 0x00; // no interrupt pin
989

    
990
    /* Register I/O spaces */
991
    pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
992
                           PCI_ADDRESS_SPACE_MEM, &openpic_map);
993

    
994
    isu_base &= 0xFFFC0000;
995
    opp->nb_cpus = nb_cpus;
996
    /* Set IRQ types */
997
    for (i = 0; i < EXT_IRQ; i++) {
998
        opp->src[i].type = IRQ_EXTERNAL;
999
    }
1000
    for (; i < IRQ_TIM0; i++) {
1001
        opp->src[i].type = IRQ_SPECIAL;
1002
    }
1003
#if MAX_IPI > 0
1004
    m = IRQ_IPI0;
1005
#else
1006
    m = IRQ_DBL0;
1007
#endif
1008
    for (; i < m; i++) {
1009
        opp->src[i].type = IRQ_TIMER;
1010
    }
1011
    for (; i < MAX_IRQ; i++) {
1012
        opp->src[i].type = IRQ_INTERNAL;
1013
    }
1014
    openpic_reset(opp);
1015

    
1016
    return opp;
1017
}