Statistics
| Branch: | Revision:

root / hw / openpic.c @ dbda808a

History | View | Annotate | Download (24.7 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    16
69
#define MAX_DBL     0
70
#define MAX_MBX     0
71
#define MAX_TMR     4
72
#define VECTOR_BITS 8
73
#define MAX_IPI     4
74
#define VID         0x03 /* MPIC version ID */
75
#define VENI        0x00000000 /* Vendor ID */
76

    
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 waited_acks;
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_) (((_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
typedef struct openpic_t {
166
    PCIDevice pci_dev;
167
    /* Global registers */
168
    uint32_t frep; /* Feature reporting register */
169
    uint32_t glbc; /* Global configuration register  */
170
    uint32_t micr; /* MPIC interrupt configuration register */
171
    uint32_t veni; /* Vendor identification register */
172
    uint32_t spve; /* Spurious vector register */
173
    uint32_t tifr; /* Timer frequency reporting register */
174
    /* Source registers */
175
    IRQ_src_t src[MAX_IRQ];
176
    /* Local registers per output pin */
177
    IRQ_dst_t dst[MAX_CPU];
178
    int nb_cpus;
179
    /* Timer registers */
180
    struct {
181
        uint32_t ticc;  /* Global timer current count register */
182
        uint32_t tibc;  /* Global timer base count register */
183
    } timers[MAX_TMR];
184
#if MAX_DBL > 0
185
    /* Doorbell registers */
186
    uint32_t dar;        /* Doorbell activate register */
187
    struct {
188
        uint32_t dmr;    /* Doorbell messaging register */
189
    } doorbells[MAX_DBL];
190
#endif
191
#if MAX_MBX > 0
192
    /* Mailbox registers */
193
    struct {
194
        uint32_t mbr;    /* Mailbox register */
195
    } mailboxes[MAX_MAILBOXES];
196
#endif
197
} openpic_t;
198

    
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
            if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
224
                next = i;
225
                priority = IPVP_PRIORITY(opp->src[i].ipvp);
226
            }
227
        }
228
    }
229
    q->next = next;
230
    q->priority = priority;
231
}
232

    
233
static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
234
{
235
    if (q->next == -1) {
236
        if (q->queue == 0) {
237
            /* No more IRQ */
238
            return -1;
239
        }
240
        IRQ_check(opp, q);
241
    }
242

    
243
    return q->next;
244
}
245

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

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

    
272
void openpic_set_IRQ (openpic_t *opp, int n_IRQ, int level)
273
{
274
    IRQ_src_t *src;
275
    int i;
276

    
277
    src = &opp->src[n_IRQ];
278
    if (!test_bit(&src->ipvp, IPVP_MASK)) {
279
        /* Interrupt source is disabled */
280
        return;
281
    }
282
    if (IPVP_PRIORITY(src->ipvp) == 0) {
283
        /* Priority set to zero */
284
        return;
285
    }
286
    if (src->ide == 0x00000000) {
287
        /* No target */
288
        return;
289
    }
290
    if (level == 0) {
291
        if (test_bit(&src->ipvp, IPVP_ACTIVITY) &&
292
            test_bit(&src->ipvp, IPVP_SENSE)) {
293
            /* Inactivate a active level-sensitive IRQ */
294
            reset_bit(&src->ipvp, IPVP_ACTIVITY);
295
        }
296
    } else {
297
        if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
298
            /* Interrupt already pending */
299
            return;
300
        }
301
        if (!test_bit(&src->ipvp, IPVP_MODE) ||
302
            src->ide == (1 << src->last_cpu)) {
303
            /* Directed delivery mode */
304
            for (i = 0; i < opp->nb_cpus; i++) {
305
                if (test_bit(&src->ide, i))
306
                    IRQ_local_pipe(opp, i, n_IRQ);
307
            }
308
        } else {
309
            /* Distributed delivery mode */
310
            for (i = src->last_cpu; i < src->last_cpu; i++) {
311
                if (i == MAX_IRQ)
312
                    i = 0;
313
                if (test_bit(&src->ide, i)) {
314
                    IRQ_local_pipe(opp, i, n_IRQ);
315
                    src->last_cpu = i;
316
                    break;
317
                }
318
            }
319
        }
320
    }
321
}
322

    
323
static void openpic_reset (openpic_t *opp)
324
{
325
    int i;
326

    
327
    opp->glbc = 0x80000000;
328
    /* Initialise controler registers */
329
    opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
330
    opp->veni = VENI;
331
    opp->spve = 0x000000FF;
332
    opp->tifr = 0x003F7A00;
333
    /* ? */
334
    opp->micr = 0x00000000;
335
    /* Initialise IRQ sources */
336
    for (i = 0; i < MAX_IRQ; i++) {
337
        opp->src[i].ipvp = 0xA0000000;
338
        opp->src[i].ide  = 0x00000000;
339
    }
340
    /* Initialise IRQ destinations */
341
    for (i = 0; i < opp->nb_cpus; i++) {
342
        opp->dst[i].pctp      = 0x0000000F;
343
        opp->dst[i].pcsr      = 0x00000000;
344
        memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
345
        memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
346
    }
347
    /* Initialise timers */
348
    for (i = 0; i < MAX_TMR; i++) {
349
        opp->timers[i].ticc = 0x00000000;
350
        opp->timers[i].tibc = 0x80000000;
351
    }
352
    /* Initialise doorbells */
353
#if MAX_DBL > 0
354
    opp->dar = 0x00000000;
355
    for (i = 0; i < MAX_DBL; i++) {
356
        opp->doorbells[i].dmr  = 0x00000000;
357
    }
358
#endif
359
    /* Initialise mailboxes */
360
#if MAX_MBX > 0
361
    for (i = 0; i < MAX_MBX; i++) { /* ? */
362
        opp->mailboxes[i].mbr   = 0x00000000;
363
    }
364
#endif
365
    /* Go out of RESET state */
366
    opp->glbc = 0x00000000;
367
}
368

    
369
static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
370
{
371
    uint32_t retval;
372

    
373
    switch (reg) {
374
    case IRQ_IPVP:
375
        retval = opp->src[n_IRQ].ipvp;
376
        break;
377
    case IRQ_IDE:
378
        retval = opp->src[n_IRQ].ide;
379
        break;
380
    }
381

    
382
    return retval;
383
}
384

    
385
static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
386
                                 uint32_t reg, uint32_t val)
387
{
388
    uint32_t tmp;
389

    
390
    switch (reg) {
391
    case IRQ_IPVP:
392
        tmp = opp->src[n_IRQ].ipvp & 0x40000000;
393
        if (tmp == 0) {
394
            tmp |= val & 0x80000000;
395
            if ((opp->src[n_IRQ].type & IRQ_EXTERNAL) != 0)
396
                tmp |= val & 0x40C00000;
397
            else if ((opp->src[n_IRQ].type & IRQ_TIMER) != 0)
398
                tmp |= val & 0x00F00000;
399
        } else {
400
            tmp |= val & 0x80000000;
401
        }
402
        opp->src[n_IRQ].ipvp = tmp | (val & 0x000F00FF);
403
        DPRINTF("Set IPVP %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ipvp);
404
        break;
405
    case IRQ_IDE:
406
        tmp = val & 0xC0000000;
407
        tmp |= val & ((1 << MAX_CPU) - 1);
408
        opp->src[n_IRQ].ide = tmp;
409
        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
410
        break;
411
    }
412
}
413

    
414
#if 0 // Code provision for Intel model
415
#if MAX_DBL > 0
416
static uint32_t read_doorbell_register (openpic_t *opp,
417
                                        int n_dbl, uint32_t offset)
418
{
419
    uint32_t retval;
420

421
    switch (offset) {
422
    case DBL_IPVP_OFFSET:
423
        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
424
        break;
425
    case DBL_IDE_OFFSET:
426
        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
427
        break;
428
    case DBL_DMR_OFFSET:
429
        retval = opp->doorbells[n_dbl].dmr;
430
        break;
431
    }
432

433
    return retval;
434
}
435
     
436
static void write_doorbell_register (penpic_t *opp, int n_dbl,
437
                                     uint32_t offset, uint32_t value)
438
{
439
    switch (offset) {
440
    case DBL_IVPR_OFFSET:
441
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
442
        break;
443
    case DBL_IDE_OFFSET:
444
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
445
        break;
446
    case DBL_DMR_OFFSET:
447
        opp->doorbells[n_dbl].dmr = value;
448
        break;
449
    }
450
}
451
#endif
452

    
453
#if MAX_MBX > 0
454
static uint32_t read_mailbox_register (openpic_t *opp,
455
                                       int n_mbx, uint32_t offset)
456
{
457
    uint32_t retval;
458

    
459
    switch (offset) {
460
    case MBX_MBR_OFFSET:
461
        retval = opp->mailboxes[n_mbx].mbr;
462
        break;
463
    case MBX_IVPR_OFFSET:
464
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
465
        break;
466
    case MBX_DMR_OFFSET:
467
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
468
        break;
469
    }
470

    
471
    return retval;
472
}
473

    
474
static void write_mailbox_register (openpic_t *opp, int n_mbx,
475
                                    uint32_t address, uint32_t value)
476
{
477
    switch (offset) {
478
    case MBX_MBR_OFFSET:
479
        opp->mailboxes[n_mbx].mbr = value;
480
        break;
481
    case MBX_IVPR_OFFSET:
482
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
483
        break;
484
    case MBX_DMR_OFFSET:
485
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
486
        break;
487
    }
488
}
489
#endif
490
#endif /* 0 : Code provision for Intel model */
491

    
492
static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
493
{
494
    openpic_t *opp = opaque;
495

    
496
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
497
    if (addr & 0xF)
498
        return;
499
#if defined OPENPIC_SWAP
500
    val = bswap32(val);
501
#endif
502
    addr &= 0xFF;
503
    switch (addr) {
504
    case 0x00: /* FREP */
505
        break;
506
    case 0x20: /* GLBC */
507
        if (val & 0x80000000)
508
            openpic_reset(opp);
509
        opp->glbc = val & ~0x80000000;
510
        break;
511
    case 0x80: /* VENI */
512
        break;
513
    case 0x90: /* PINT */
514
        /* XXX: Should be able to reset any CPU */
515
        if (val & 1) {
516
            DPRINTF("Reset CPU IRQ\n");
517
            //            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET);
518
        }
519
        break;
520
#if MAX_IPI > 0
521
    case 0xA0: /* IPI_IPVP */
522
    case 0xB0:
523
    case 0xC0:
524
    case 0xD0:
525
        {
526
            int idx;
527
            idx = (addr - 0xA0) >> 4;
528
            write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
529
        }
530
        break;
531
#endif
532
    case 0xE0: /* SPVE */
533
        opp->spve = val & 0x000000FF;
534
        break;
535
    case 0xF0: /* TIFR */
536
        opp->tifr = val;
537
        break;
538
    default:
539
        break;
540
    }
541
}
542

    
543
static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
544
{
545
    openpic_t *opp = opaque;
546
    uint32_t retval;
547

    
548
    DPRINTF("%s: addr %08x\n", __func__, addr);
549
    retval = 0xFFFFFFFF;
550
    if (addr & 0xF)
551
        return retval;
552
    addr &= 0xFF;
553
    switch (addr) {
554
    case 0x00: /* FREP */
555
        retval = opp->frep;
556
        break;
557
    case 0x20: /* GLBC */
558
        retval = opp->glbc;
559
        break;
560
    case 0x80: /* VENI */
561
        retval = opp->veni;
562
        break;
563
    case 0x90: /* PINT */
564
        retval = 0x00000000;
565
        break;
566
#if MAX_IPI > 0
567
    case 0xA0: /* IPI_IPVP */
568
    case 0xB0:
569
    case 0xC0:
570
    case 0xD0:
571
        {
572
            int idx;
573
            idx = (addr - 0xA0) >> 4;
574
            retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
575
        }
576
        break;
577
#endif
578
    case 0xE0: /* SPVE */
579
        retval = opp->spve;
580
        break;
581
    case 0xF0: /* TIFR */
582
        retval = opp->tifr;
583
        break;
584
    default:
585
        break;
586
    }
587
    DPRINTF("%s: => %08x\n", __func__, retval);
588
#if defined OPENPIC_SWAP
589
    retval = bswap32(retval);
590
#endif
591

    
592
    return retval;
593
}
594

    
595
static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
596
{
597
    openpic_t *opp = opaque;
598
    int idx;
599

    
600
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
601
    if (addr & 0xF)
602
        return;
603
#if defined OPENPIC_SWAP
604
    val = bswap32(val);
605
#endif
606
    addr -= 0x1100;
607
    addr &= 0xFFFF;
608
    idx = (addr & 0xFFF0) >> 6;
609
    addr = addr & 0x30;
610
    switch (addr) {
611
    case 0x00: /* TICC */
612
        break;
613
    case 0x10: /* TIBC */
614
        if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
615
            (val & 0x800000000) == 0 &&
616
            (opp->timers[idx].tibc & 0x80000000) != 0)
617
            opp->timers[idx].ticc &= ~0x80000000;
618
        opp->timers[idx].tibc = val;
619
        break;
620
    case 0x20: /* TIVP */
621
        write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val);
622
        break;
623
    case 0x30: /* TIDE */
624
        write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val);
625
        break;
626
    }
627
}
628

    
629
static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
630
{
631
    openpic_t *opp = opaque;
632
    uint32_t retval;
633
    int idx;
634

    
635
    DPRINTF("%s: addr %08x\n", __func__, addr);
636
    retval = 0xFFFFFFFF;
637
    if (addr & 0xF)
638
        return retval;
639
    addr -= 0x1100;
640
    addr &= 0xFFFF;
641
    idx = (addr & 0xFFF0) >> 6;
642
    addr = addr & 0x30;
643
    switch (addr) {
644
    case 0x00: /* TICC */
645
        retval = opp->timers[idx].ticc;
646
        break;
647
    case 0x10: /* TIBC */
648
        retval = opp->timers[idx].tibc;
649
        break;
650
    case 0x20: /* TIPV */
651
        retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP);
652
        break;
653
    case 0x30: /* TIDE */
654
        retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE);
655
        break;
656
    }
657
    DPRINTF("%s: => %08x\n", __func__, retval);
658
#if defined OPENPIC_SWAP
659
    retval = bswap32(retval);
660
#endif
661

    
662
    return retval;
663
}
664

    
665
static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
666
{
667
    openpic_t *opp = opaque;
668
    int idx;
669

    
670
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
671
    if (addr & 0xF)
672
        return;
673
#if defined OPENPIC_SWAP
674
    val = tswap32(val);
675
#endif
676
    addr = addr & 0xFFF0;
677
    idx = addr >> 5;
678
    if (addr & 0x10) {
679
        /* EXDE / IFEDE / IEEDE */
680
        write_IRQreg(opp, idx, IRQ_IDE, val);
681
    } else {
682
        /* EXVP / IFEVP / IEEVP */
683
        write_IRQreg(opp, idx, IRQ_IPVP, val);
684
    }
685
}
686

    
687
static uint32_t openpic_src_read (void *opaque, uint32_t addr)
688
{
689
    openpic_t *opp = opaque;
690
    uint32_t retval;
691
    int idx;
692

    
693
    DPRINTF("%s: addr %08x\n", __func__, addr);
694
    retval = 0xFFFFFFFF;
695
    if (addr & 0xF)
696
        return retval;
697
    addr = addr & 0xFFF0;
698
    idx = addr >> 5;
699
    if (addr & 0x10) {
700
        /* EXDE / IFEDE / IEEDE */
701
        retval = read_IRQreg(opp, idx, IRQ_IDE);
702
    } else {
703
        /* EXVP / IFEVP / IEEVP */
704
        retval = read_IRQreg(opp, idx, IRQ_IPVP);
705
    }
706
    DPRINTF("%s: => %08x\n", __func__, retval);
707
#if defined OPENPIC_SWAP
708
    retval = tswap32(retval);
709
#endif
710

    
711
    return retval;
712
}
713

    
714
static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
715
{
716
    openpic_t *opp = opaque;
717
    IRQ_src_t *src;
718
    IRQ_dst_t *dst;
719
    int idx, n_IRQ;
720

    
721
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
722
    if (addr & 0xF)
723
        return;
724
#if defined OPENPIC_SWAP
725
    val = bswap32(val);
726
#endif
727
    addr &= 0x1FFF0;
728
    idx = addr / 0x1000;
729
    dst = &opp->dst[idx];
730
    addr &= 0xFF0;
731
    switch (addr) {
732
#if MAX_IPI > 0
733
    case 0x40: /* PIPD */
734
    case 0x50:
735
    case 0x60:
736
    case 0x70:
737
        idx = (addr - 0x40) >> 4;
738
        write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val);
739
        openpic_set_IRQ(opp, IRQ_IPI0 + idx, 1);
740
        openpic_set_IRQ(opp, IRQ_IPI0 + idx, 0);
741
        break;
742
#endif
743
    case 0x80: /* PCTP */
744
        dst->pctp = val & 0x0000000F;
745
        break;
746
    case 0x90: /* WHOAMI */
747
        /* Read-only register */
748
        break;
749
    case 0xA0: /* PIAC */
750
        /* Read-only register */
751
        break;
752
    case 0xB0: /* PEOI */
753
        DPRINTF("PEOI\n");
754
        n_IRQ = IRQ_get_next(opp, &dst->servicing);
755
        IRQ_resetbit(&dst->servicing, n_IRQ);
756
        dst->servicing.next = -1;
757
        src = &opp->src[n_IRQ];
758
        /* Set up next servicing IRQ */
759
        IRQ_get_next(opp, &dst->servicing);
760
        /* Check queued interrupts. */
761
        n_IRQ = IRQ_get_next(opp, &dst->raised);
762
        if (n_IRQ != -1) {
763
            src = &opp->src[n_IRQ];
764
            if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
765
                DPRINTF("Raise CPU IRQ\n");
766
                cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
767
            }
768
        }
769
        break;
770
    default:
771
        break;
772
    }
773
}
774

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

    
843
    return retval;
844
}
845

    
846
static void openpic_buggy_write (void *opaque,
847
                                 target_phys_addr_t addr, uint32_t val)
848
{
849
    printf("Invalid OPENPIC write access !\n");
850
}
851

    
852
static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
853
{
854
    printf("Invalid OPENPIC read access !\n");
855

    
856
    return -1;
857
}
858

    
859
static void openpic_writel (void *opaque,
860
                            target_phys_addr_t addr, uint32_t val)
861
{
862
    openpic_t *opp = opaque;
863

    
864
    addr &= 0x3FFFF;
865
    DPRINTF("%s: offset %08lx val: %08x\n", __func__, addr, val);
866
    if (addr < 0x1100) {
867
        /* Global registers */
868
        openpic_gbl_write(opp, addr, val);
869
    } else if (addr < 0x10000) {
870
        /* Timers registers */
871
        openpic_timer_write(opp, addr, val);
872
    } else if (addr < 0x20000) {
873
        /* Source registers */
874
        openpic_src_write(opp, addr, val);
875
    } else {
876
        /* CPU registers */
877
        openpic_cpu_write(opp, addr, val);
878
    }
879
}
880

    
881
static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
882
{
883
    openpic_t *opp = opaque;
884
    uint32_t retval;
885

    
886
    addr &= 0x3FFFF;
887
    DPRINTF("%s: offset %08lx\n", __func__, addr);
888
    if (addr < 0x1100) {
889
        /* Global registers */
890
        retval = openpic_gbl_read(opp, addr);
891
    } else if (addr < 0x10000) {
892
        /* Timers registers */
893
        retval = openpic_timer_read(opp, addr);
894
    } else if (addr < 0x20000) {
895
        /* Source registers */
896
        retval = openpic_src_read(opp, addr);
897
    } else {
898
        /* CPU registers */
899
        retval = openpic_cpu_read(opp, addr);
900
    }
901

    
902
    return retval;
903
}
904

    
905
static CPUWriteMemoryFunc *openpic_write[] = {
906
    &openpic_buggy_write,
907
    &openpic_buggy_write,
908
    &openpic_writel,
909
};
910

    
911
static CPUReadMemoryFunc *openpic_read[] = {
912
    &openpic_buggy_read,
913
    &openpic_buggy_read,
914
    &openpic_readl,
915
};
916

    
917
static void openpic_map(PCIDevice *pci_dev, int region_num, 
918
                        uint32_t addr, uint32_t size, int type)
919
{
920
    openpic_t *opp;
921
    int opp_io_memory;
922

    
923
    DPRINTF("Map OpenPIC\n");
924
    opp = (openpic_t *)pci_dev;
925
    /* Global registers */
926
    DPRINTF("Register OPENPIC gbl   %08x => %08x\n",
927
            addr + 0x1000, addr + 0x1000 + 0x100);
928
    /* Timer registers */
929
    DPRINTF("Register OPENPIC timer %08x => %08x\n",
930
            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
931
    /* Interrupt source registers */
932
    DPRINTF("Register OPENPIC src   %08x => %08x\n",
933
            addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2));
934
    /* Per CPU registers */
935
    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
936
            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
937
    opp_io_memory = cpu_register_io_memory(0, openpic_read,
938
                                           openpic_write, opp);
939
    cpu_register_physical_memory(addr, 0x40000, opp_io_memory);
940
#if 0 // Don't implement ISU for now
941
    opp_io_memory = cpu_register_io_memory(0, openpic_src_read,
942
                                           openpic_src_write);
943
    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
944
                                 opp_io_memory);
945
#endif
946
}
947

    
948
openpic_t *openpic_init (uint32_t isu_base, uint32_t idu_base, int nb_cpus)
949
{
950
    openpic_t *opp;
951
    uint8_t *pci_conf;
952
    int i, m;
953
    
954
    /* XXX: for now, only one CPU is supported */
955
    if (nb_cpus != 1)
956
        return NULL;
957
    opp = (openpic_t *)pci_register_device("OpenPIC", sizeof(openpic_t),
958
                                           0, -1, NULL, NULL);
959
    if (opp == NULL)
960
        return NULL;
961
    pci_conf = opp->pci_dev.config;
962
    pci_conf[0x00] = 0x14; // IBM MPIC2
963
    pci_conf[0x01] = 0x10;
964
    pci_conf[0x02] = 0xFF;
965
    pci_conf[0x03] = 0xFF;
966
    pci_conf[0x0a] = 0x80; // PIC
967
    pci_conf[0x0b] = 0x08;
968
    pci_conf[0x0e] = 0x00; // header_type
969
    pci_conf[0x3d] = 0x00; // no interrupt pin
970

    
971
    /* Register I/O spaces */
972
    pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
973
                           PCI_ADDRESS_SPACE_MEM, &openpic_map);
974

    
975
    isu_base &= 0xFFFC0000;
976
    opp->nb_cpus = nb_cpus;
977
    /* Set IRQ types */
978
    for (i = 0; i < EXT_IRQ; i++) {
979
        opp->src[i].type = IRQ_EXTERNAL;
980
    }
981
    for (; i < IRQ_TIM0; i++) {
982
        opp->src[i].type = IRQ_SPECIAL;
983
    }
984
#if MAX_IPI > 0
985
    m = IRQ_IPI0;
986
#else
987
    m = IRQ_DBL0;
988
#endif
989
    for (; i < m; i++) {
990
        opp->src[i].type = IRQ_TIMER;
991
    }
992
    for (; i < MAX_IRQ; i++) {
993
        opp->src[i].type = IRQ_INTERNAL;
994
    }
995
    openpic_reset(opp);
996

    
997
    return opp;
998
}