Revision dbda808a

b/hw/openpic.c
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
}

Also available in: Unified diff