Statistics
| Branch: | Revision:

root / hw / openpic.c @ bc927e48

History | View | Annotate | Download (47 kB)

1
/*
2
 * OpenPIC emulation
3
 *
4
 * Copyright (c) 2004 Jocelyn Mayer
5
 *               2011 Alexander Graf
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 */
25
/*
26
 *
27
 * Based on OpenPic implementations:
28
 * - Intel GW80314 I/O companion chip developer's manual
29
 * - Motorola MPC8245 & MPC8540 user manuals.
30
 * - Motorola MCP750 (aka Raven) programmer manual.
31
 * - Motorola Harrier programmer manuel
32
 *
33
 * Serial interrupts, as implemented in Raven chipset are not supported yet.
34
 *
35
 */
36
#include "hw.h"
37
#include "ppc_mac.h"
38
#include "pci.h"
39
#include "openpic.h"
40

    
41
//#define DEBUG_OPENPIC
42

    
43
#ifdef DEBUG_OPENPIC
44
#define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
45
#else
46
#define DPRINTF(fmt, ...) do { } while (0)
47
#endif
48

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

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

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

    
62
#define VID (0x00000000)
63

    
64
#elif defined(USE_MPCxxx)
65

    
66
#define MAX_CPU    15
67
#define MAX_IRQ   128
68
#define MAX_DBL     0
69
#define MAX_MBX     0
70
#define MAX_TMR     4
71
#define VECTOR_BITS 8
72
#define MAX_IPI     4
73
#define VID         0x03 /* MPIC version ID */
74
#define VENI        0x00000000 /* Vendor ID */
75

    
76
enum {
77
    IRQ_IPVP = 0,
78
    IRQ_IDE,
79
};
80

    
81
/* OpenPIC */
82
#define OPENPIC_MAX_CPU      2
83
#define OPENPIC_MAX_IRQ     64
84
#define OPENPIC_EXT_IRQ     48
85
#define OPENPIC_MAX_TMR      MAX_TMR
86
#define OPENPIC_MAX_IPI      MAX_IPI
87

    
88
/* Interrupt definitions */
89
#define OPENPIC_IRQ_FE     (OPENPIC_EXT_IRQ)     /* Internal functional IRQ */
90
#define OPENPIC_IRQ_ERR    (OPENPIC_EXT_IRQ + 1) /* Error IRQ */
91
#define OPENPIC_IRQ_TIM0   (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */
92
#if OPENPIC_MAX_IPI > 0
93
#define OPENPIC_IRQ_IPI0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */
94
#define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */
95
#else
96
#define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */
97
#define OPENPIC_IRQ_MBX0   (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */
98
#endif
99

    
100
/* MPIC */
101
#define MPIC_MAX_CPU      1
102
#define MPIC_MAX_EXT     12
103
#define MPIC_MAX_INT     64
104
#define MPIC_MAX_MSG      4
105
#define MPIC_MAX_MSI      8
106
#define MPIC_MAX_TMR      MAX_TMR
107
#define MPIC_MAX_IPI      MAX_IPI
108
#define MPIC_MAX_IRQ     (MPIC_MAX_EXT + MPIC_MAX_INT + MPIC_MAX_TMR + MPIC_MAX_MSG + MPIC_MAX_MSI + (MPIC_MAX_IPI * MPIC_MAX_CPU))
109

    
110
/* Interrupt definitions */
111
#define MPIC_EXT_IRQ      0
112
#define MPIC_INT_IRQ      (MPIC_EXT_IRQ + MPIC_MAX_EXT)
113
#define MPIC_TMR_IRQ      (MPIC_INT_IRQ + MPIC_MAX_INT)
114
#define MPIC_MSG_IRQ      (MPIC_TMR_IRQ + MPIC_MAX_TMR)
115
#define MPIC_MSI_IRQ      (MPIC_MSG_IRQ + MPIC_MAX_MSG)
116
#define MPIC_IPI_IRQ      (MPIC_MSI_IRQ + MPIC_MAX_MSI)
117

    
118
#define MPIC_GLB_REG_START        0x0
119
#define MPIC_GLB_REG_SIZE         0x10F0
120
#define MPIC_TMR_REG_START        0x10F0
121
#define MPIC_TMR_REG_SIZE         0x220
122
#define MPIC_EXT_REG_START        0x10000
123
#define MPIC_EXT_REG_SIZE         0x180
124
#define MPIC_INT_REG_START        0x10200
125
#define MPIC_INT_REG_SIZE         0x800
126
#define MPIC_MSG_REG_START        0x11600
127
#define MPIC_MSG_REG_SIZE         0x100
128
#define MPIC_MSI_REG_START        0x11C00
129
#define MPIC_MSI_REG_SIZE         0x100
130
#define MPIC_CPU_REG_START        0x20000
131
#define MPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
132

    
133
/*
134
 * Block Revision Register1 (BRR1): QEMU does not fully emulate
135
 * any version on MPIC. So to start with, set the IP version to 0.
136
 *
137
 * NOTE: This is Freescale MPIC specific register. Keep it here till
138
 * this code is refactored for different variants of OPENPIC and MPIC.
139
 */
140
#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */
141
#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */
142
#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */
143

    
144
enum mpic_ide_bits {
145
    IDR_EP     = 31,
146
    IDR_CI0     = 30,
147
    IDR_CI1     = 29,
148
    IDR_P1     = 1,
149
    IDR_P0     = 0,
150
};
151

    
152
#else
153
#error "Please select which OpenPic implementation is to be emulated"
154
#endif
155

    
156
#define OPENPIC_PAGE_SIZE 4096
157

    
158
#define BF_WIDTH(_bits_) \
159
(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
160

    
161
static inline void set_bit (uint32_t *field, int bit)
162
{
163
    field[bit >> 5] |= 1 << (bit & 0x1F);
164
}
165

    
166
static inline void reset_bit (uint32_t *field, int bit)
167
{
168
    field[bit >> 5] &= ~(1 << (bit & 0x1F));
169
}
170

    
171
static inline int test_bit (uint32_t *field, int bit)
172
{
173
    return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
174
}
175

    
176
static int get_current_cpu(void)
177
{
178
  return cpu_single_env->cpu_index;
179
}
180

    
181
static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
182
                                          int idx);
183
static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
184
                                       uint32_t val, int idx);
185

    
186
enum {
187
    IRQ_EXTERNAL = 0x01,
188
    IRQ_INTERNAL = 0x02,
189
    IRQ_TIMER    = 0x04,
190
    IRQ_SPECIAL  = 0x08,
191
};
192

    
193
typedef struct IRQ_queue_t {
194
    uint32_t queue[BF_WIDTH(MAX_IRQ)];
195
    int next;
196
    int priority;
197
} IRQ_queue_t;
198

    
199
typedef struct IRQ_src_t {
200
    uint32_t ipvp;  /* IRQ vector/priority register */
201
    uint32_t ide;   /* IRQ destination register */
202
    int type;
203
    int last_cpu;
204
    int pending;    /* TRUE if IRQ is pending */
205
} IRQ_src_t;
206

    
207
enum IPVP_bits {
208
    IPVP_MASK     = 31,
209
    IPVP_ACTIVITY = 30,
210
    IPVP_MODE     = 29,
211
    IPVP_POLARITY = 23,
212
    IPVP_SENSE    = 22,
213
};
214
#define IPVP_PRIORITY_MASK     (0x1F << 16)
215
#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
216
#define IPVP_VECTOR_MASK       ((1 << VECTOR_BITS) - 1)
217
#define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)
218

    
219
typedef struct IRQ_dst_t {
220
    uint32_t tfrr;
221
    uint32_t pctp; /* CPU current task priority */
222
    uint32_t pcsr; /* CPU sensitivity register */
223
    IRQ_queue_t raised;
224
    IRQ_queue_t servicing;
225
    qemu_irq *irqs;
226
} IRQ_dst_t;
227

    
228
typedef struct openpic_t {
229
    PCIDevice pci_dev;
230
    MemoryRegion mem;
231

    
232
    /* Sub-regions */
233
    MemoryRegion sub_io_mem[7];
234

    
235
    /* Global registers */
236
    uint32_t frep; /* Feature reporting register */
237
    uint32_t glbc; /* Global configuration register  */
238
    uint32_t micr; /* MPIC interrupt configuration register */
239
    uint32_t veni; /* Vendor identification register */
240
    uint32_t pint; /* Processor initialization register */
241
    uint32_t spve; /* Spurious vector register */
242
    uint32_t tifr; /* Timer frequency reporting register */
243
    /* Source registers */
244
    IRQ_src_t src[MAX_IRQ];
245
    /* Local registers per output pin */
246
    IRQ_dst_t dst[MAX_CPU];
247
    int nb_cpus;
248
    /* Timer registers */
249
    struct {
250
        uint32_t ticc;  /* Global timer current count register */
251
        uint32_t tibc;  /* Global timer base count register */
252
    } timers[MAX_TMR];
253
#if MAX_DBL > 0
254
    /* Doorbell registers */
255
    uint32_t dar;        /* Doorbell activate register */
256
    struct {
257
        uint32_t dmr;    /* Doorbell messaging register */
258
    } doorbells[MAX_DBL];
259
#endif
260
#if MAX_MBX > 0
261
    /* Mailbox registers */
262
    struct {
263
        uint32_t mbr;    /* Mailbox register */
264
    } mailboxes[MAX_MAILBOXES];
265
#endif
266
    /* IRQ out is used when in bypass mode (not implemented) */
267
    qemu_irq irq_out;
268
    int max_irq;
269
    int irq_ipi0;
270
    int irq_tim0;
271
    void (*reset) (void *);
272
    void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *);
273
} openpic_t;
274

    
275
static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
276
{
277
    set_bit(q->queue, n_IRQ);
278
}
279

    
280
static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
281
{
282
    reset_bit(q->queue, n_IRQ);
283
}
284

    
285
static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
286
{
287
    return test_bit(q->queue, n_IRQ);
288
}
289

    
290
static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
291
{
292
    int next, i;
293
    int priority;
294

    
295
    next = -1;
296
    priority = -1;
297
    for (i = 0; i < opp->max_irq; i++) {
298
        if (IRQ_testbit(q, i)) {
299
            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
300
                    i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
301
            if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
302
                next = i;
303
                priority = IPVP_PRIORITY(opp->src[i].ipvp);
304
            }
305
        }
306
    }
307
    q->next = next;
308
    q->priority = priority;
309
}
310

    
311
static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
312
{
313
    if (q->next == -1) {
314
        /* XXX: optimize */
315
        IRQ_check(opp, q);
316
    }
317

    
318
    return q->next;
319
}
320

    
321
static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
322
{
323
    IRQ_dst_t *dst;
324
    IRQ_src_t *src;
325
    int priority;
326

    
327
    dst = &opp->dst[n_CPU];
328
    src = &opp->src[n_IRQ];
329
    priority = IPVP_PRIORITY(src->ipvp);
330
    if (priority <= dst->pctp) {
331
        /* Too low priority */
332
        DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
333
                __func__, n_IRQ, n_CPU);
334
        return;
335
    }
336
    if (IRQ_testbit(&dst->raised, n_IRQ)) {
337
        /* Interrupt miss */
338
        DPRINTF("%s: IRQ %d was missed on CPU %d\n",
339
                __func__, n_IRQ, n_CPU);
340
        return;
341
    }
342
    set_bit(&src->ipvp, IPVP_ACTIVITY);
343
    IRQ_setbit(&dst->raised, n_IRQ);
344
    if (priority < dst->raised.priority) {
345
        /* An higher priority IRQ is already raised */
346
        DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
347
                __func__, n_IRQ, dst->raised.next, n_CPU);
348
        return;
349
    }
350
    IRQ_get_next(opp, &dst->raised);
351
    if (IRQ_get_next(opp, &dst->servicing) != -1 &&
352
        priority <= dst->servicing.priority) {
353
        DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
354
                __func__, n_IRQ, dst->servicing.next, n_CPU);
355
        /* Already servicing a higher priority IRQ */
356
        return;
357
    }
358
    DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
359
    opp->irq_raise(opp, n_CPU, src);
360
}
361

    
362
/* update pic state because registers for n_IRQ have changed value */
363
static void openpic_update_irq(openpic_t *opp, int n_IRQ)
364
{
365
    IRQ_src_t *src;
366
    int i;
367

    
368
    src = &opp->src[n_IRQ];
369

    
370
    if (!src->pending) {
371
        /* no irq pending */
372
        DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
373
        return;
374
    }
375
    if (test_bit(&src->ipvp, IPVP_MASK)) {
376
        /* Interrupt source is disabled */
377
        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
378
        return;
379
    }
380
    if (IPVP_PRIORITY(src->ipvp) == 0) {
381
        /* Priority set to zero */
382
        DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
383
        return;
384
    }
385
    if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
386
        /* IRQ already active */
387
        DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
388
        return;
389
    }
390
    if (src->ide == 0x00000000) {
391
        /* No target */
392
        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
393
        return;
394
    }
395

    
396
    if (src->ide == (1 << src->last_cpu)) {
397
        /* Only one CPU is allowed to receive this IRQ */
398
        IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
399
    } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
400
        /* Directed delivery mode */
401
        for (i = 0; i < opp->nb_cpus; i++) {
402
            if (test_bit(&src->ide, i))
403
                IRQ_local_pipe(opp, i, n_IRQ);
404
        }
405
    } else {
406
        /* Distributed delivery mode */
407
        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
408
            if (i == opp->nb_cpus)
409
                i = 0;
410
            if (test_bit(&src->ide, i)) {
411
                IRQ_local_pipe(opp, i, n_IRQ);
412
                src->last_cpu = i;
413
                break;
414
            }
415
        }
416
    }
417
}
418

    
419
static void openpic_set_irq(void *opaque, int n_IRQ, int level)
420
{
421
    openpic_t *opp = opaque;
422
    IRQ_src_t *src;
423

    
424
    src = &opp->src[n_IRQ];
425
    DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
426
            n_IRQ, level, src->ipvp);
427
    if (test_bit(&src->ipvp, IPVP_SENSE)) {
428
        /* level-sensitive irq */
429
        src->pending = level;
430
        if (!level)
431
            reset_bit(&src->ipvp, IPVP_ACTIVITY);
432
    } else {
433
        /* edge-sensitive irq */
434
        if (level)
435
            src->pending = 1;
436
    }
437
    openpic_update_irq(opp, n_IRQ);
438
}
439

    
440
static void openpic_reset (void *opaque)
441
{
442
    openpic_t *opp = (openpic_t *)opaque;
443
    int i;
444

    
445
    opp->glbc = 0x80000000;
446
    /* Initialise controller registers */
447
    opp->frep = ((OPENPIC_EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
448
    opp->veni = VENI;
449
    opp->pint = 0x00000000;
450
    opp->spve = 0x000000FF;
451
    opp->tifr = 0x003F7A00;
452
    /* ? */
453
    opp->micr = 0x00000000;
454
    /* Initialise IRQ sources */
455
    for (i = 0; i < opp->max_irq; i++) {
456
        opp->src[i].ipvp = 0xA0000000;
457
        opp->src[i].ide  = 0x00000000;
458
    }
459
    /* Initialise IRQ destinations */
460
    for (i = 0; i < MAX_CPU; i++) {
461
        opp->dst[i].pctp      = 0x0000000F;
462
        opp->dst[i].pcsr      = 0x00000000;
463
        memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
464
        opp->dst[i].raised.next = -1;
465
        memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
466
        opp->dst[i].servicing.next = -1;
467
    }
468
    /* Initialise timers */
469
    for (i = 0; i < MAX_TMR; i++) {
470
        opp->timers[i].ticc = 0x00000000;
471
        opp->timers[i].tibc = 0x80000000;
472
    }
473
    /* Initialise doorbells */
474
#if MAX_DBL > 0
475
    opp->dar = 0x00000000;
476
    for (i = 0; i < MAX_DBL; i++) {
477
        opp->doorbells[i].dmr  = 0x00000000;
478
    }
479
#endif
480
    /* Initialise mailboxes */
481
#if MAX_MBX > 0
482
    for (i = 0; i < MAX_MBX; i++) { /* ? */
483
        opp->mailboxes[i].mbr   = 0x00000000;
484
    }
485
#endif
486
    /* Go out of RESET state */
487
    opp->glbc = 0x00000000;
488
}
489

    
490
static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ)
491
{
492
    return opp->src[n_IRQ].ide;
493
}
494

    
495
static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ)
496
{
497
    return opp->src[n_IRQ].ipvp;
498
}
499

    
500
static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val)
501
{
502
    uint32_t tmp;
503

    
504
    tmp = val & 0xC0000000;
505
    tmp |= val & ((1ULL << MAX_CPU) - 1);
506
    opp->src[n_IRQ].ide = tmp;
507
    DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
508
}
509

    
510
static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val)
511
{
512
    /* NOTE: not fully accurate for special IRQs, but simple and sufficient */
513
    /* ACTIVITY bit is read-only */
514
    opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000)
515
                         | (val & 0x800F00FF);
516
    openpic_update_irq(opp, n_IRQ);
517
    DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
518
            opp->src[n_IRQ].ipvp);
519
}
520

    
521
#if 0 // Code provision for Intel model
522
#if MAX_DBL > 0
523
static uint32_t read_doorbell_register (openpic_t *opp,
524
                                        int n_dbl, uint32_t offset)
525
{
526
    uint32_t retval;
527

528
    switch (offset) {
529
    case DBL_IPVP_OFFSET:
530
        retval = read_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl);
531
        break;
532
    case DBL_IDE_OFFSET:
533
        retval = read_IRQreg_ide(opp, IRQ_DBL0 + n_dbl);
534
        break;
535
    case DBL_DMR_OFFSET:
536
        retval = opp->doorbells[n_dbl].dmr;
537
        break;
538
    }
539

540
    return retval;
541
}
542

543
static void write_doorbell_register (penpic_t *opp, int n_dbl,
544
                                     uint32_t offset, uint32_t value)
545
{
546
    switch (offset) {
547
    case DBL_IVPR_OFFSET:
548
        write_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl, value);
549
        break;
550
    case DBL_IDE_OFFSET:
551
        write_IRQreg_ide(opp, IRQ_DBL0 + n_dbl, value);
552
        break;
553
    case DBL_DMR_OFFSET:
554
        opp->doorbells[n_dbl].dmr = value;
555
        break;
556
    }
557
}
558
#endif
559

    
560
#if MAX_MBX > 0
561
static uint32_t read_mailbox_register (openpic_t *opp,
562
                                       int n_mbx, uint32_t offset)
563
{
564
    uint32_t retval;
565

    
566
    switch (offset) {
567
    case MBX_MBR_OFFSET:
568
        retval = opp->mailboxes[n_mbx].mbr;
569
        break;
570
    case MBX_IVPR_OFFSET:
571
        retval = read_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx);
572
        break;
573
    case MBX_DMR_OFFSET:
574
        retval = read_IRQreg_ide(opp, IRQ_MBX0 + n_mbx);
575
        break;
576
    }
577

    
578
    return retval;
579
}
580

    
581
static void write_mailbox_register (openpic_t *opp, int n_mbx,
582
                                    uint32_t address, uint32_t value)
583
{
584
    switch (offset) {
585
    case MBX_MBR_OFFSET:
586
        opp->mailboxes[n_mbx].mbr = value;
587
        break;
588
    case MBX_IVPR_OFFSET:
589
        write_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx, value);
590
        break;
591
    case MBX_DMR_OFFSET:
592
        write_IRQreg_ide(opp, IRQ_MBX0 + n_mbx, value);
593
        break;
594
    }
595
}
596
#endif
597
#endif /* 0 : Code provision for Intel model */
598

    
599
static void openpic_gbl_write (void *opaque, hwaddr addr, uint32_t val)
600
{
601
    openpic_t *opp = opaque;
602
    IRQ_dst_t *dst;
603
    int idx;
604

    
605
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
606
    if (addr & 0xF)
607
        return;
608
    switch (addr) {
609
    case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
610
        break;
611
    case 0x40:
612
    case 0x50:
613
    case 0x60:
614
    case 0x70:
615
    case 0x80:
616
    case 0x90:
617
    case 0xA0:
618
    case 0xB0:
619
        openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
620
        break;
621
    case 0x1000: /* FREP */
622
        break;
623
    case 0x1020: /* GLBC */
624
        if (val & 0x80000000 && opp->reset)
625
            opp->reset(opp);
626
        opp->glbc = val & ~0x80000000;
627
        break;
628
    case 0x1080: /* VENI */
629
        break;
630
    case 0x1090: /* PINT */
631
        for (idx = 0; idx < opp->nb_cpus; idx++) {
632
            if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
633
                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
634
                dst = &opp->dst[idx];
635
                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
636
            } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
637
                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
638
                dst = &opp->dst[idx];
639
                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
640
            }
641
        }
642
        opp->pint = val;
643
        break;
644
    case 0x10A0: /* IPI_IPVP */
645
    case 0x10B0:
646
    case 0x10C0:
647
    case 0x10D0:
648
        {
649
            int idx;
650
            idx = (addr - 0x10A0) >> 4;
651
            write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val);
652
        }
653
        break;
654
    case 0x10E0: /* SPVE */
655
        opp->spve = val & 0x000000FF;
656
        break;
657
    case 0x10F0: /* TIFR */
658
        opp->tifr = val;
659
        break;
660
    default:
661
        break;
662
    }
663
}
664

    
665
static uint32_t openpic_gbl_read (void *opaque, hwaddr addr)
666
{
667
    openpic_t *opp = opaque;
668
    uint32_t retval;
669

    
670
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
671
    retval = 0xFFFFFFFF;
672
    if (addr & 0xF)
673
        return retval;
674
    switch (addr) {
675
    case 0x1000: /* FREP */
676
        retval = opp->frep;
677
        break;
678
    case 0x1020: /* GLBC */
679
        retval = opp->glbc;
680
        break;
681
    case 0x1080: /* VENI */
682
        retval = opp->veni;
683
        break;
684
    case 0x1090: /* PINT */
685
        retval = 0x00000000;
686
        break;
687
    case 0x00: /* Block Revision Register1 (BRR1) */
688
    case 0x40:
689
    case 0x50:
690
    case 0x60:
691
    case 0x70:
692
    case 0x80:
693
    case 0x90:
694
    case 0xA0:
695
    case 0xB0:
696
        retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
697
        break;
698
    case 0x10A0: /* IPI_IPVP */
699
    case 0x10B0:
700
    case 0x10C0:
701
    case 0x10D0:
702
        {
703
            int idx;
704
            idx = (addr - 0x10A0) >> 4;
705
            retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx);
706
        }
707
        break;
708
    case 0x10E0: /* SPVE */
709
        retval = opp->spve;
710
        break;
711
    case 0x10F0: /* TIFR */
712
        retval = opp->tifr;
713
        break;
714
    default:
715
        break;
716
    }
717
    DPRINTF("%s: => %08x\n", __func__, retval);
718

    
719
    return retval;
720
}
721

    
722
static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
723
{
724
    openpic_t *opp = opaque;
725
    int idx;
726

    
727
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
728
    if (addr & 0xF)
729
        return;
730
    addr -= 0x10;
731
    addr &= 0xFFFF;
732
    idx = (addr & 0xFFF0) >> 6;
733
    addr = addr & 0x30;
734
    switch (addr) {
735
    case 0x00: /* TICC */
736
        break;
737
    case 0x10: /* TIBC */
738
        if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
739
            (val & 0x80000000) == 0 &&
740
            (opp->timers[idx].tibc & 0x80000000) != 0)
741
            opp->timers[idx].ticc &= ~0x80000000;
742
        opp->timers[idx].tibc = val;
743
        break;
744
    case 0x20: /* TIVP */
745
        write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val);
746
        break;
747
    case 0x30: /* TIDE */
748
        write_IRQreg_ide(opp, opp->irq_tim0 + idx, val);
749
        break;
750
    }
751
}
752

    
753
static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
754
{
755
    openpic_t *opp = opaque;
756
    uint32_t retval;
757
    int idx;
758

    
759
    DPRINTF("%s: addr %08x\n", __func__, addr);
760
    retval = 0xFFFFFFFF;
761
    if (addr & 0xF)
762
        return retval;
763
    addr -= 0x10;
764
    addr &= 0xFFFF;
765
    idx = (addr & 0xFFF0) >> 6;
766
    addr = addr & 0x30;
767
    switch (addr) {
768
    case 0x00: /* TICC */
769
        retval = opp->timers[idx].ticc;
770
        break;
771
    case 0x10: /* TIBC */
772
        retval = opp->timers[idx].tibc;
773
        break;
774
    case 0x20: /* TIPV */
775
        retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx);
776
        break;
777
    case 0x30: /* TIDE */
778
        retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx);
779
        break;
780
    }
781
    DPRINTF("%s: => %08x\n", __func__, retval);
782

    
783
    return retval;
784
}
785

    
786
static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
787
{
788
    openpic_t *opp = opaque;
789
    int idx;
790

    
791
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
792
    if (addr & 0xF)
793
        return;
794
    addr = addr & 0xFFF0;
795
    idx = addr >> 5;
796
    if (addr & 0x10) {
797
        /* EXDE / IFEDE / IEEDE */
798
        write_IRQreg_ide(opp, idx, val);
799
    } else {
800
        /* EXVP / IFEVP / IEEVP */
801
        write_IRQreg_ipvp(opp, idx, val);
802
    }
803
}
804

    
805
static uint32_t openpic_src_read (void *opaque, uint32_t addr)
806
{
807
    openpic_t *opp = opaque;
808
    uint32_t retval;
809
    int idx;
810

    
811
    DPRINTF("%s: addr %08x\n", __func__, addr);
812
    retval = 0xFFFFFFFF;
813
    if (addr & 0xF)
814
        return retval;
815
    addr = addr & 0xFFF0;
816
    idx = addr >> 5;
817
    if (addr & 0x10) {
818
        /* EXDE / IFEDE / IEEDE */
819
        retval = read_IRQreg_ide(opp, idx);
820
    } else {
821
        /* EXVP / IFEVP / IEEVP */
822
        retval = read_IRQreg_ipvp(opp, idx);
823
    }
824
    DPRINTF("%s: => %08x\n", __func__, retval);
825

    
826
    return retval;
827
}
828

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

    
837
    DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx,
838
            addr, val);
839
    if (addr & 0xF)
840
        return;
841
    dst = &opp->dst[idx];
842
    addr &= 0xFF0;
843
    switch (addr) {
844
#if MAX_IPI > 0
845
    case 0x40: /* IPIDR */
846
    case 0x50:
847
    case 0x60:
848
    case 0x70:
849
        idx = (addr - 0x40) >> 4;
850
        /* we use IDE as mask which CPUs to deliver the IPI to still. */
851
        write_IRQreg_ide(opp, opp->irq_ipi0 + idx,
852
                         opp->src[opp->irq_ipi0 + idx].ide | val);
853
        openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
854
        openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
855
        break;
856
#endif
857
    case 0x80: /* PCTP */
858
        dst->pctp = val & 0x0000000F;
859
        break;
860
    case 0x90: /* WHOAMI */
861
        /* Read-only register */
862
        break;
863
    case 0xA0: /* PIAC */
864
        /* Read-only register */
865
        break;
866
    case 0xB0: /* PEOI */
867
        DPRINTF("PEOI\n");
868
        s_IRQ = IRQ_get_next(opp, &dst->servicing);
869
        IRQ_resetbit(&dst->servicing, s_IRQ);
870
        dst->servicing.next = -1;
871
        /* Set up next servicing IRQ */
872
        s_IRQ = IRQ_get_next(opp, &dst->servicing);
873
        /* Check queued interrupts. */
874
        n_IRQ = IRQ_get_next(opp, &dst->raised);
875
        src = &opp->src[n_IRQ];
876
        if (n_IRQ != -1 &&
877
            (s_IRQ == -1 ||
878
             IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
879
            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
880
                    idx, n_IRQ);
881
            opp->irq_raise(opp, idx, src);
882
        }
883
        break;
884
    default:
885
        break;
886
    }
887
}
888

    
889
static void openpic_cpu_write(void *opaque, hwaddr addr, uint32_t val)
890
{
891
    openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
892
}
893

    
894
static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
895
                                          int idx)
896
{
897
    openpic_t *opp = opaque;
898
    IRQ_src_t *src;
899
    IRQ_dst_t *dst;
900
    uint32_t retval;
901
    int n_IRQ;
902

    
903
    DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr);
904
    retval = 0xFFFFFFFF;
905
    if (addr & 0xF)
906
        return retval;
907
    dst = &opp->dst[idx];
908
    addr &= 0xFF0;
909
    switch (addr) {
910
    case 0x00: /* Block Revision Register1 (BRR1) */
911
        retval = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN;
912
        break;
913
    case 0x80: /* PCTP */
914
        retval = dst->pctp;
915
        break;
916
    case 0x90: /* WHOAMI */
917
        retval = idx;
918
        break;
919
    case 0xA0: /* PIAC */
920
        DPRINTF("Lower OpenPIC INT output\n");
921
        qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
922
        n_IRQ = IRQ_get_next(opp, &dst->raised);
923
        DPRINTF("PIAC: irq=%d\n", n_IRQ);
924
        if (n_IRQ == -1) {
925
            /* No more interrupt pending */
926
            retval = IPVP_VECTOR(opp->spve);
927
        } else {
928
            src = &opp->src[n_IRQ];
929
            if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
930
                !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
931
                /* - Spurious level-sensitive IRQ
932
                 * - Priorities has been changed
933
                 *   and the pending IRQ isn't allowed anymore
934
                 */
935
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
936
                retval = IPVP_VECTOR(opp->spve);
937
            } else {
938
                /* IRQ enter servicing state */
939
                IRQ_setbit(&dst->servicing, n_IRQ);
940
                retval = IPVP_VECTOR(src->ipvp);
941
            }
942
            IRQ_resetbit(&dst->raised, n_IRQ);
943
            dst->raised.next = -1;
944
            if (!test_bit(&src->ipvp, IPVP_SENSE)) {
945
                /* edge-sensitive IRQ */
946
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
947
                src->pending = 0;
948
            }
949

    
950
            if ((n_IRQ >= opp->irq_ipi0) &&  (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) {
951
                src->ide &= ~(1 << idx);
952
                if (src->ide && !test_bit(&src->ipvp, IPVP_SENSE)) {
953
                    /* trigger on CPUs that didn't know about it yet */
954
                    openpic_set_irq(opp, n_IRQ, 1);
955
                    openpic_set_irq(opp, n_IRQ, 0);
956
                    /* if all CPUs knew about it, set active bit again */
957
                    set_bit(&src->ipvp, IPVP_ACTIVITY);
958
                }
959
            }
960
        }
961
        break;
962
    case 0xB0: /* PEOI */
963
        retval = 0;
964
        break;
965
    default:
966
        break;
967
    }
968
    DPRINTF("%s: => %08x\n", __func__, retval);
969

    
970
    return retval;
971
}
972

    
973
static uint32_t openpic_cpu_read(void *opaque, hwaddr addr)
974
{
975
    return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
976
}
977

    
978
static void openpic_buggy_write (void *opaque,
979
                                 hwaddr addr, uint32_t val)
980
{
981
    printf("Invalid OPENPIC write access !\n");
982
}
983

    
984
static uint32_t openpic_buggy_read (void *opaque, hwaddr addr)
985
{
986
    printf("Invalid OPENPIC read access !\n");
987

    
988
    return -1;
989
}
990

    
991
static void openpic_writel (void *opaque,
992
                            hwaddr addr, uint32_t val)
993
{
994
    openpic_t *opp = opaque;
995

    
996
    addr &= 0x3FFFF;
997
    DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
998
    if (addr < 0x1100) {
999
        /* Global registers */
1000
        openpic_gbl_write(opp, addr, val);
1001
    } else if (addr < 0x10000) {
1002
        /* Timers registers */
1003
        openpic_timer_write(opp, addr, val);
1004
    } else if (addr < 0x20000) {
1005
        /* Source registers */
1006
        openpic_src_write(opp, addr, val);
1007
    } else {
1008
        /* CPU registers */
1009
        openpic_cpu_write(opp, addr, val);
1010
    }
1011
}
1012

    
1013
static uint32_t openpic_readl (void *opaque,hwaddr addr)
1014
{
1015
    openpic_t *opp = opaque;
1016
    uint32_t retval;
1017

    
1018
    addr &= 0x3FFFF;
1019
    DPRINTF("%s: offset %08x\n", __func__, (int)addr);
1020
    if (addr < 0x1100) {
1021
        /* Global registers */
1022
        retval = openpic_gbl_read(opp, addr);
1023
    } else if (addr < 0x10000) {
1024
        /* Timers registers */
1025
        retval = openpic_timer_read(opp, addr);
1026
    } else if (addr < 0x20000) {
1027
        /* Source registers */
1028
        retval = openpic_src_read(opp, addr);
1029
    } else {
1030
        /* CPU registers */
1031
        retval = openpic_cpu_read(opp, addr);
1032
    }
1033

    
1034
    return retval;
1035
}
1036

    
1037
static uint64_t openpic_read(void *opaque, hwaddr addr,
1038
                             unsigned size)
1039
{
1040
    openpic_t *opp = opaque;
1041

    
1042
    switch (size) {
1043
    case 4: return openpic_readl(opp, addr);
1044
    default: return openpic_buggy_read(opp, addr);
1045
    }
1046
}
1047

    
1048
static void openpic_write(void *opaque, hwaddr addr,
1049
                          uint64_t data, unsigned size)
1050
{
1051
    openpic_t *opp = opaque;
1052

    
1053
    switch (size) {
1054
    case 4: return openpic_writel(opp, addr, data);
1055
    default: return openpic_buggy_write(opp, addr, data);
1056
    }
1057
}
1058

    
1059
static const MemoryRegionOps openpic_ops = {
1060
    .read = openpic_read,
1061
    .write = openpic_write,
1062
    .endianness = DEVICE_LITTLE_ENDIAN,
1063
};
1064

    
1065
static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
1066
{
1067
    unsigned int i;
1068

    
1069
    for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
1070
        qemu_put_be32s(f, &q->queue[i]);
1071

    
1072
    qemu_put_sbe32s(f, &q->next);
1073
    qemu_put_sbe32s(f, &q->priority);
1074
}
1075

    
1076
static void openpic_save(QEMUFile* f, void *opaque)
1077
{
1078
    openpic_t *opp = (openpic_t *)opaque;
1079
    unsigned int i;
1080

    
1081
    qemu_put_be32s(f, &opp->frep);
1082
    qemu_put_be32s(f, &opp->glbc);
1083
    qemu_put_be32s(f, &opp->micr);
1084
    qemu_put_be32s(f, &opp->veni);
1085
    qemu_put_be32s(f, &opp->pint);
1086
    qemu_put_be32s(f, &opp->spve);
1087
    qemu_put_be32s(f, &opp->tifr);
1088

    
1089
    for (i = 0; i < opp->max_irq; i++) {
1090
        qemu_put_be32s(f, &opp->src[i].ipvp);
1091
        qemu_put_be32s(f, &opp->src[i].ide);
1092
        qemu_put_sbe32s(f, &opp->src[i].type);
1093
        qemu_put_sbe32s(f, &opp->src[i].last_cpu);
1094
        qemu_put_sbe32s(f, &opp->src[i].pending);
1095
    }
1096

    
1097
    qemu_put_sbe32s(f, &opp->nb_cpus);
1098

    
1099
    for (i = 0; i < opp->nb_cpus; i++) {
1100
        qemu_put_be32s(f, &opp->dst[i].tfrr);
1101
        qemu_put_be32s(f, &opp->dst[i].pctp);
1102
        qemu_put_be32s(f, &opp->dst[i].pcsr);
1103
        openpic_save_IRQ_queue(f, &opp->dst[i].raised);
1104
        openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
1105
    }
1106

    
1107
    for (i = 0; i < MAX_TMR; i++) {
1108
        qemu_put_be32s(f, &opp->timers[i].ticc);
1109
        qemu_put_be32s(f, &opp->timers[i].tibc);
1110
    }
1111

    
1112
#if MAX_DBL > 0
1113
    qemu_put_be32s(f, &opp->dar);
1114

    
1115
    for (i = 0; i < MAX_DBL; i++) {
1116
        qemu_put_be32s(f, &opp->doorbells[i].dmr);
1117
    }
1118
#endif
1119

    
1120
#if MAX_MBX > 0
1121
    for (i = 0; i < MAX_MAILBOXES; i++) {
1122
        qemu_put_be32s(f, &opp->mailboxes[i].mbr);
1123
    }
1124
#endif
1125

    
1126
    pci_device_save(&opp->pci_dev, f);
1127
}
1128

    
1129
static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
1130
{
1131
    unsigned int i;
1132

    
1133
    for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
1134
        qemu_get_be32s(f, &q->queue[i]);
1135

    
1136
    qemu_get_sbe32s(f, &q->next);
1137
    qemu_get_sbe32s(f, &q->priority);
1138
}
1139

    
1140
static int openpic_load(QEMUFile* f, void *opaque, int version_id)
1141
{
1142
    openpic_t *opp = (openpic_t *)opaque;
1143
    unsigned int i;
1144

    
1145
    if (version_id != 1)
1146
        return -EINVAL;
1147

    
1148
    qemu_get_be32s(f, &opp->frep);
1149
    qemu_get_be32s(f, &opp->glbc);
1150
    qemu_get_be32s(f, &opp->micr);
1151
    qemu_get_be32s(f, &opp->veni);
1152
    qemu_get_be32s(f, &opp->pint);
1153
    qemu_get_be32s(f, &opp->spve);
1154
    qemu_get_be32s(f, &opp->tifr);
1155

    
1156
    for (i = 0; i < opp->max_irq; i++) {
1157
        qemu_get_be32s(f, &opp->src[i].ipvp);
1158
        qemu_get_be32s(f, &opp->src[i].ide);
1159
        qemu_get_sbe32s(f, &opp->src[i].type);
1160
        qemu_get_sbe32s(f, &opp->src[i].last_cpu);
1161
        qemu_get_sbe32s(f, &opp->src[i].pending);
1162
    }
1163

    
1164
    qemu_get_sbe32s(f, &opp->nb_cpus);
1165

    
1166
    for (i = 0; i < opp->nb_cpus; i++) {
1167
        qemu_get_be32s(f, &opp->dst[i].tfrr);
1168
        qemu_get_be32s(f, &opp->dst[i].pctp);
1169
        qemu_get_be32s(f, &opp->dst[i].pcsr);
1170
        openpic_load_IRQ_queue(f, &opp->dst[i].raised);
1171
        openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
1172
    }
1173

    
1174
    for (i = 0; i < MAX_TMR; i++) {
1175
        qemu_get_be32s(f, &opp->timers[i].ticc);
1176
        qemu_get_be32s(f, &opp->timers[i].tibc);
1177
    }
1178

    
1179
#if MAX_DBL > 0
1180
    qemu_get_be32s(f, &opp->dar);
1181

    
1182
    for (i = 0; i < MAX_DBL; i++) {
1183
        qemu_get_be32s(f, &opp->doorbells[i].dmr);
1184
    }
1185
#endif
1186

    
1187
#if MAX_MBX > 0
1188
    for (i = 0; i < MAX_MAILBOXES; i++) {
1189
        qemu_get_be32s(f, &opp->mailboxes[i].mbr);
1190
    }
1191
#endif
1192

    
1193
    return pci_device_load(&opp->pci_dev, f);
1194
}
1195

    
1196
static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
1197
{
1198
    qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1199
}
1200

    
1201
qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
1202
                        qemu_irq **irqs, qemu_irq irq_out)
1203
{
1204
    openpic_t *opp;
1205
    int i, m;
1206

    
1207
    /* XXX: for now, only one CPU is supported */
1208
    if (nb_cpus != 1)
1209
        return NULL;
1210
    opp = g_malloc0(sizeof(openpic_t));
1211
    memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
1212

    
1213
    //    isu_base &= 0xFFFC0000;
1214
    opp->nb_cpus = nb_cpus;
1215
    opp->max_irq = OPENPIC_MAX_IRQ;
1216
    opp->irq_ipi0 = OPENPIC_IRQ_IPI0;
1217
    opp->irq_tim0 = OPENPIC_IRQ_TIM0;
1218
    /* Set IRQ types */
1219
    for (i = 0; i < OPENPIC_EXT_IRQ; i++) {
1220
        opp->src[i].type = IRQ_EXTERNAL;
1221
    }
1222
    for (; i < OPENPIC_IRQ_TIM0; i++) {
1223
        opp->src[i].type = IRQ_SPECIAL;
1224
    }
1225
#if MAX_IPI > 0
1226
    m = OPENPIC_IRQ_IPI0;
1227
#else
1228
    m = OPENPIC_IRQ_DBL0;
1229
#endif
1230
    for (; i < m; i++) {
1231
        opp->src[i].type = IRQ_TIMER;
1232
    }
1233
    for (; i < OPENPIC_MAX_IRQ; i++) {
1234
        opp->src[i].type = IRQ_INTERNAL;
1235
    }
1236
    for (i = 0; i < nb_cpus; i++)
1237
        opp->dst[i].irqs = irqs[i];
1238
    opp->irq_out = irq_out;
1239

    
1240
    register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2,
1241
                    openpic_save, openpic_load, opp);
1242
    qemu_register_reset(openpic_reset, opp);
1243

    
1244
    opp->irq_raise = openpic_irq_raise;
1245
    opp->reset = openpic_reset;
1246

    
1247
    if (pmem)
1248
        *pmem = &opp->mem;
1249

    
1250
    return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
1251
}
1252

    
1253
static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src)
1254
{
1255
    int n_ci = IDR_CI0 - n_CPU;
1256

    
1257
    if(test_bit(&src->ide, n_ci)) {
1258
        qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]);
1259
    }
1260
    else {
1261
        qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1262
    }
1263
}
1264

    
1265
static void mpic_reset (void *opaque)
1266
{
1267
    openpic_t *mpp = (openpic_t *)opaque;
1268
    int i;
1269

    
1270
    mpp->glbc = 0x80000000;
1271
    /* Initialise controller registers */
1272
    mpp->frep = 0x004f0002 | ((mpp->nb_cpus - 1) << 8);
1273
    mpp->veni = VENI;
1274
    mpp->pint = 0x00000000;
1275
    mpp->spve = 0x0000FFFF;
1276
    /* Initialise IRQ sources */
1277
    for (i = 0; i < mpp->max_irq; i++) {
1278
        mpp->src[i].ipvp = 0x80800000;
1279
        mpp->src[i].ide  = 0x00000001;
1280
    }
1281
    /* Set IDE for IPIs to 0 so we don't get spurious interrupts */
1282
    for (i = mpp->irq_ipi0; i < (mpp->irq_ipi0 + MAX_IPI); i++) {
1283
        mpp->src[i].ide = 0;
1284
    }
1285
    /* Initialise IRQ destinations */
1286
    for (i = 0; i < MAX_CPU; i++) {
1287
        mpp->dst[i].pctp      = 0x0000000F;
1288
        mpp->dst[i].tfrr      = 0x00000000;
1289
        memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t));
1290
        mpp->dst[i].raised.next = -1;
1291
        memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
1292
        mpp->dst[i].servicing.next = -1;
1293
    }
1294
    /* Initialise timers */
1295
    for (i = 0; i < MAX_TMR; i++) {
1296
        mpp->timers[i].ticc = 0x00000000;
1297
        mpp->timers[i].tibc = 0x80000000;
1298
    }
1299
    /* Go out of RESET state */
1300
    mpp->glbc = 0x00000000;
1301
}
1302

    
1303
static void mpic_timer_write (void *opaque, hwaddr addr, uint32_t val)
1304
{
1305
    openpic_t *mpp = opaque;
1306
    int idx, cpu;
1307

    
1308
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1309
    if (addr & 0xF)
1310
        return;
1311
    addr &= 0xFFFF;
1312
    cpu = addr >> 12;
1313
    idx = (addr >> 6) & 0x3;
1314
    switch (addr & 0x30) {
1315
    case 0x00: /* gtccr */
1316
        break;
1317
    case 0x10: /* gtbcr */
1318
        if ((mpp->timers[idx].ticc & 0x80000000) != 0 &&
1319
            (val & 0x80000000) == 0 &&
1320
            (mpp->timers[idx].tibc & 0x80000000) != 0)
1321
            mpp->timers[idx].ticc &= ~0x80000000;
1322
        mpp->timers[idx].tibc = val;
1323
        break;
1324
    case 0x20: /* GTIVPR */
1325
        write_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx, val);
1326
        break;
1327
    case 0x30: /* GTIDR & TFRR */
1328
        if ((addr & 0xF0) == 0xF0)
1329
            mpp->dst[cpu].tfrr = val;
1330
        else
1331
            write_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx, val);
1332
        break;
1333
    }
1334
}
1335

    
1336
static uint32_t mpic_timer_read (void *opaque, hwaddr addr)
1337
{
1338
    openpic_t *mpp = opaque;
1339
    uint32_t retval;
1340
    int idx, cpu;
1341

    
1342
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1343
    retval = 0xFFFFFFFF;
1344
    if (addr & 0xF)
1345
        return retval;
1346
    addr &= 0xFFFF;
1347
    cpu = addr >> 12;
1348
    idx = (addr >> 6) & 0x3;
1349
    switch (addr & 0x30) {
1350
    case 0x00: /* gtccr */
1351
        retval = mpp->timers[idx].ticc;
1352
        break;
1353
    case 0x10: /* gtbcr */
1354
        retval = mpp->timers[idx].tibc;
1355
        break;
1356
    case 0x20: /* TIPV */
1357
        retval = read_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx);
1358
        break;
1359
    case 0x30: /* TIDR */
1360
        if ((addr &0xF0) == 0XF0)
1361
            retval = mpp->dst[cpu].tfrr;
1362
        else
1363
            retval = read_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx);
1364
        break;
1365
    }
1366
    DPRINTF("%s: => %08x\n", __func__, retval);
1367

    
1368
    return retval;
1369
}
1370

    
1371
static void mpic_src_ext_write (void *opaque, hwaddr addr,
1372
                                uint32_t val)
1373
{
1374
    openpic_t *mpp = opaque;
1375
    int idx = MPIC_EXT_IRQ;
1376

    
1377
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1378
    if (addr & 0xF)
1379
        return;
1380

    
1381
    if (addr < MPIC_EXT_REG_SIZE) {
1382
        idx += (addr & 0xFFF0) >> 5;
1383
        if (addr & 0x10) {
1384
            /* EXDE / IFEDE / IEEDE */
1385
            write_IRQreg_ide(mpp, idx, val);
1386
        } else {
1387
            /* EXVP / IFEVP / IEEVP */
1388
            write_IRQreg_ipvp(mpp, idx, val);
1389
        }
1390
    }
1391
}
1392

    
1393
static uint32_t mpic_src_ext_read (void *opaque, hwaddr addr)
1394
{
1395
    openpic_t *mpp = opaque;
1396
    uint32_t retval;
1397
    int idx = MPIC_EXT_IRQ;
1398

    
1399
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1400
    retval = 0xFFFFFFFF;
1401
    if (addr & 0xF)
1402
        return retval;
1403

    
1404
    if (addr < MPIC_EXT_REG_SIZE) {
1405
        idx += (addr & 0xFFF0) >> 5;
1406
        if (addr & 0x10) {
1407
            /* EXDE / IFEDE / IEEDE */
1408
            retval = read_IRQreg_ide(mpp, idx);
1409
        } else {
1410
            /* EXVP / IFEVP / IEEVP */
1411
            retval = read_IRQreg_ipvp(mpp, idx);
1412
        }
1413
        DPRINTF("%s: => %08x\n", __func__, retval);
1414
    }
1415

    
1416
    return retval;
1417
}
1418

    
1419
static void mpic_src_int_write (void *opaque, hwaddr addr,
1420
                                uint32_t val)
1421
{
1422
    openpic_t *mpp = opaque;
1423
    int idx = MPIC_INT_IRQ;
1424

    
1425
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1426
    if (addr & 0xF)
1427
        return;
1428

    
1429
    if (addr < MPIC_INT_REG_SIZE) {
1430
        idx += (addr & 0xFFF0) >> 5;
1431
        if (addr & 0x10) {
1432
            /* EXDE / IFEDE / IEEDE */
1433
            write_IRQreg_ide(mpp, idx, val);
1434
        } else {
1435
            /* EXVP / IFEVP / IEEVP */
1436
            write_IRQreg_ipvp(mpp, idx, val);
1437
        }
1438
    }
1439
}
1440

    
1441
static uint32_t mpic_src_int_read (void *opaque, hwaddr addr)
1442
{
1443
    openpic_t *mpp = opaque;
1444
    uint32_t retval;
1445
    int idx = MPIC_INT_IRQ;
1446

    
1447
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1448
    retval = 0xFFFFFFFF;
1449
    if (addr & 0xF)
1450
        return retval;
1451

    
1452
    if (addr < MPIC_INT_REG_SIZE) {
1453
        idx += (addr & 0xFFF0) >> 5;
1454
        if (addr & 0x10) {
1455
            /* EXDE / IFEDE / IEEDE */
1456
            retval = read_IRQreg_ide(mpp, idx);
1457
        } else {
1458
            /* EXVP / IFEVP / IEEVP */
1459
            retval = read_IRQreg_ipvp(mpp, idx);
1460
        }
1461
        DPRINTF("%s: => %08x\n", __func__, retval);
1462
    }
1463

    
1464
    return retval;
1465
}
1466

    
1467
static void mpic_src_msg_write (void *opaque, hwaddr addr,
1468
                                uint32_t val)
1469
{
1470
    openpic_t *mpp = opaque;
1471
    int idx = MPIC_MSG_IRQ;
1472

    
1473
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1474
    if (addr & 0xF)
1475
        return;
1476

    
1477
    if (addr < MPIC_MSG_REG_SIZE) {
1478
        idx += (addr & 0xFFF0) >> 5;
1479
        if (addr & 0x10) {
1480
            /* EXDE / IFEDE / IEEDE */
1481
            write_IRQreg_ide(mpp, idx, val);
1482
        } else {
1483
            /* EXVP / IFEVP / IEEVP */
1484
            write_IRQreg_ipvp(mpp, idx, val);
1485
        }
1486
    }
1487
}
1488

    
1489
static uint32_t mpic_src_msg_read (void *opaque, hwaddr addr)
1490
{
1491
    openpic_t *mpp = opaque;
1492
    uint32_t retval;
1493
    int idx = MPIC_MSG_IRQ;
1494

    
1495
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1496
    retval = 0xFFFFFFFF;
1497
    if (addr & 0xF)
1498
        return retval;
1499

    
1500
    if (addr < MPIC_MSG_REG_SIZE) {
1501
        idx += (addr & 0xFFF0) >> 5;
1502
        if (addr & 0x10) {
1503
            /* EXDE / IFEDE / IEEDE */
1504
            retval = read_IRQreg_ide(mpp, idx);
1505
        } else {
1506
            /* EXVP / IFEVP / IEEVP */
1507
            retval = read_IRQreg_ipvp(mpp, idx);
1508
        }
1509
        DPRINTF("%s: => %08x\n", __func__, retval);
1510
    }
1511

    
1512
    return retval;
1513
}
1514

    
1515
static void mpic_src_msi_write (void *opaque, hwaddr addr,
1516
                                uint32_t val)
1517
{
1518
    openpic_t *mpp = opaque;
1519
    int idx = MPIC_MSI_IRQ;
1520

    
1521
    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1522
    if (addr & 0xF)
1523
        return;
1524

    
1525
    if (addr < MPIC_MSI_REG_SIZE) {
1526
        idx += (addr & 0xFFF0) >> 5;
1527
        if (addr & 0x10) {
1528
            /* EXDE / IFEDE / IEEDE */
1529
            write_IRQreg_ide(mpp, idx, val);
1530
        } else {
1531
            /* EXVP / IFEVP / IEEVP */
1532
            write_IRQreg_ipvp(mpp, idx, val);
1533
        }
1534
    }
1535
}
1536
static uint32_t mpic_src_msi_read (void *opaque, hwaddr addr)
1537
{
1538
    openpic_t *mpp = opaque;
1539
    uint32_t retval;
1540
    int idx = MPIC_MSI_IRQ;
1541

    
1542
    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1543
    retval = 0xFFFFFFFF;
1544
    if (addr & 0xF)
1545
        return retval;
1546

    
1547
    if (addr < MPIC_MSI_REG_SIZE) {
1548
        idx += (addr & 0xFFF0) >> 5;
1549
        if (addr & 0x10) {
1550
            /* EXDE / IFEDE / IEEDE */
1551
            retval = read_IRQreg_ide(mpp, idx);
1552
        } else {
1553
            /* EXVP / IFEVP / IEEVP */
1554
            retval = read_IRQreg_ipvp(mpp, idx);
1555
        }
1556
        DPRINTF("%s: => %08x\n", __func__, retval);
1557
    }
1558

    
1559
    return retval;
1560
}
1561

    
1562
static const MemoryRegionOps mpic_glb_ops = {
1563
    .old_mmio = {
1564
        .write = { openpic_buggy_write,
1565
                   openpic_buggy_write,
1566
                   openpic_gbl_write,
1567
        },
1568
        .read  = { openpic_buggy_read,
1569
                   openpic_buggy_read,
1570
                   openpic_gbl_read,
1571
        },
1572
    },
1573
    .endianness = DEVICE_BIG_ENDIAN,
1574
};
1575

    
1576
static const MemoryRegionOps mpic_tmr_ops = {
1577
    .old_mmio = {
1578
        .write = { openpic_buggy_write,
1579
                   openpic_buggy_write,
1580
                   mpic_timer_write,
1581
        },
1582
        .read  = { openpic_buggy_read,
1583
                   openpic_buggy_read,
1584
                   mpic_timer_read,
1585
        },
1586
    },
1587
    .endianness = DEVICE_BIG_ENDIAN,
1588
};
1589

    
1590
static const MemoryRegionOps mpic_cpu_ops = {
1591
    .old_mmio = {
1592
        .write = { openpic_buggy_write,
1593
                   openpic_buggy_write,
1594
                   openpic_cpu_write,
1595
        },
1596
        .read  = { openpic_buggy_read,
1597
                   openpic_buggy_read,
1598
                   openpic_cpu_read,
1599
        },
1600
    },
1601
    .endianness = DEVICE_BIG_ENDIAN,
1602
};
1603

    
1604
static const MemoryRegionOps mpic_ext_ops = {
1605
    .old_mmio = {
1606
        .write = { openpic_buggy_write,
1607
                   openpic_buggy_write,
1608
                   mpic_src_ext_write,
1609
        },
1610
        .read  = { openpic_buggy_read,
1611
                   openpic_buggy_read,
1612
                   mpic_src_ext_read,
1613
        },
1614
    },
1615
    .endianness = DEVICE_BIG_ENDIAN,
1616
};
1617

    
1618
static const MemoryRegionOps mpic_int_ops = {
1619
    .old_mmio = {
1620
        .write = { openpic_buggy_write,
1621
                   openpic_buggy_write,
1622
                   mpic_src_int_write,
1623
        },
1624
        .read  = { openpic_buggy_read,
1625
                   openpic_buggy_read,
1626
                   mpic_src_int_read,
1627
        },
1628
    },
1629
    .endianness = DEVICE_BIG_ENDIAN,
1630
};
1631

    
1632
static const MemoryRegionOps mpic_msg_ops = {
1633
    .old_mmio = {
1634
        .write = { openpic_buggy_write,
1635
                   openpic_buggy_write,
1636
                   mpic_src_msg_write,
1637
        },
1638
        .read  = { openpic_buggy_read,
1639
                   openpic_buggy_read,
1640
                   mpic_src_msg_read,
1641
        },
1642
    },
1643
    .endianness = DEVICE_BIG_ENDIAN,
1644
};
1645

    
1646
static const MemoryRegionOps mpic_msi_ops = {
1647
    .old_mmio = {
1648
        .write = { openpic_buggy_write,
1649
                   openpic_buggy_write,
1650
                   mpic_src_msi_write,
1651
        },
1652
        .read  = { openpic_buggy_read,
1653
                   openpic_buggy_read,
1654
                   mpic_src_msi_read,
1655
        },
1656
    },
1657
    .endianness = DEVICE_BIG_ENDIAN,
1658
};
1659

    
1660
qemu_irq *mpic_init (MemoryRegion *address_space, hwaddr base,
1661
                     int nb_cpus, qemu_irq **irqs, qemu_irq irq_out)
1662
{
1663
    openpic_t    *mpp;
1664
    int           i;
1665
    struct {
1666
        const char             *name;
1667
        MemoryRegionOps const  *ops;
1668
        hwaddr      start_addr;
1669
        ram_addr_t              size;
1670
    } const list[] = {
1671
        {"glb", &mpic_glb_ops, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
1672
        {"tmr", &mpic_tmr_ops, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
1673
        {"ext", &mpic_ext_ops, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
1674
        {"int", &mpic_int_ops, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
1675
        {"msg", &mpic_msg_ops, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
1676
        {"msi", &mpic_msi_ops, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
1677
        {"cpu", &mpic_cpu_ops, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
1678
    };
1679

    
1680
    mpp = g_malloc0(sizeof(openpic_t));
1681

    
1682
    memory_region_init(&mpp->mem, "mpic", 0x40000);
1683
    memory_region_add_subregion(address_space, base, &mpp->mem);
1684

    
1685
    for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
1686

    
1687
        memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp,
1688
                              list[i].name, list[i].size);
1689

    
1690
        memory_region_add_subregion(&mpp->mem, list[i].start_addr,
1691
                                    &mpp->sub_io_mem[i]);
1692
    }
1693

    
1694
    mpp->nb_cpus = nb_cpus;
1695
    mpp->max_irq = MPIC_MAX_IRQ;
1696
    mpp->irq_ipi0 = MPIC_IPI_IRQ;
1697
    mpp->irq_tim0 = MPIC_TMR_IRQ;
1698

    
1699
    for (i = 0; i < nb_cpus; i++)
1700
        mpp->dst[i].irqs = irqs[i];
1701
    mpp->irq_out = irq_out;
1702

    
1703
    mpp->irq_raise = mpic_irq_raise;
1704
    mpp->reset = mpic_reset;
1705

    
1706
    register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp);
1707
    qemu_register_reset(mpic_reset, mpp);
1708

    
1709
    return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
1710
}