Statistics
| Branch: | Revision:

root / hw / openpic.c @ 9277bc72

History | View | Annotate | Download (27.8 kB)

1 dbda808a bellard
/*
2 dbda808a bellard
 * OpenPIC emulation
3 5fafdf24 ths
 *
4 dbda808a bellard
 * Copyright (c) 2004 Jocelyn Mayer
5 5fafdf24 ths
 *
6 dbda808a bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 dbda808a bellard
 * of this software and associated documentation files (the "Software"), to deal
8 dbda808a bellard
 * in the Software without restriction, including without limitation the rights
9 dbda808a bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 dbda808a bellard
 * copies of the Software, and to permit persons to whom the Software is
11 dbda808a bellard
 * furnished to do so, subject to the following conditions:
12 dbda808a bellard
 *
13 dbda808a bellard
 * The above copyright notice and this permission notice shall be included in
14 dbda808a bellard
 * all copies or substantial portions of the Software.
15 dbda808a bellard
 *
16 dbda808a bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 dbda808a bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 dbda808a bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 dbda808a bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 dbda808a bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 dbda808a bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 dbda808a bellard
 * THE SOFTWARE.
23 dbda808a bellard
 */
24 dbda808a bellard
/*
25 dbda808a bellard
 *
26 dbda808a bellard
 * Based on OpenPic implementations:
27 dbda808a bellard
 * - Intel GW80314 I/O compagnion chip developper's manual
28 dbda808a bellard
 * - Motorola MPC8245 & MPC8540 user manuals.
29 dbda808a bellard
 * - Motorola MCP750 (aka Raven) programmer manual.
30 dbda808a bellard
 * - Motorola Harrier programmer manuel
31 dbda808a bellard
 *
32 dbda808a bellard
 * Serial interrupts, as implemented in Raven chipset are not supported yet.
33 5fafdf24 ths
 *
34 dbda808a bellard
 */
35 87ecb68b pbrook
#include "hw.h"
36 87ecb68b pbrook
#include "ppc_mac.h"
37 87ecb68b pbrook
#include "pci.h"
38 dbda808a bellard
39 611493d9 bellard
//#define DEBUG_OPENPIC
40 dbda808a bellard
41 dbda808a bellard
#ifdef DEBUG_OPENPIC
42 dbda808a bellard
#define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
43 dbda808a bellard
#else
44 dbda808a bellard
#define DPRINTF(fmt, args...) do { } while (0)
45 dbda808a bellard
#endif
46 dbda808a bellard
#define ERROR(fmr, args...) do { printf("ERROR: " fmr , ##args); } while (0)
47 dbda808a bellard
48 dbda808a bellard
#define USE_MPCxxx /* Intel model is broken, for now */
49 dbda808a bellard
50 dbda808a bellard
#if defined (USE_INTEL_GW80314)
51 dbda808a bellard
/* Intel GW80314 I/O Companion chip */
52 dbda808a bellard
53 dbda808a bellard
#define MAX_CPU     4
54 dbda808a bellard
#define MAX_IRQ    32
55 dbda808a bellard
#define MAX_DBL     4
56 dbda808a bellard
#define MAX_MBX     4
57 dbda808a bellard
#define MAX_TMR     4
58 dbda808a bellard
#define VECTOR_BITS 8
59 dbda808a bellard
#define MAX_IPI     0
60 dbda808a bellard
61 dbda808a bellard
#define VID (0x00000000)
62 dbda808a bellard
63 dbda808a bellard
#define OPENPIC_LITTLE_ENDIAN 1
64 dbda808a bellard
#define OPENPIC_BIG_ENDIAN    0
65 dbda808a bellard
66 dbda808a bellard
#elif defined(USE_MPCxxx)
67 dbda808a bellard
68 dbda808a bellard
#define MAX_CPU     2
69 dbda808a bellard
#define MAX_IRQ    64
70 611493d9 bellard
#define EXT_IRQ    48
71 dbda808a bellard
#define MAX_DBL     0
72 dbda808a bellard
#define MAX_MBX     0
73 dbda808a bellard
#define MAX_TMR     4
74 dbda808a bellard
#define VECTOR_BITS 8
75 dbda808a bellard
#define MAX_IPI     4
76 dbda808a bellard
#define VID         0x03 /* MPIC version ID */
77 dbda808a bellard
#define VENI        0x00000000 /* Vendor ID */
78 dbda808a bellard
79 dbda808a bellard
enum {
80 dbda808a bellard
    IRQ_IPVP = 0,
81 dbda808a bellard
    IRQ_IDE,
82 dbda808a bellard
};
83 dbda808a bellard
84 dbda808a bellard
#define OPENPIC_LITTLE_ENDIAN 1
85 dbda808a bellard
#define OPENPIC_BIG_ENDIAN    0
86 dbda808a bellard
87 dbda808a bellard
#else
88 dbda808a bellard
#error "Please select which OpenPic implementation is to be emulated"
89 dbda808a bellard
#endif
90 dbda808a bellard
91 dbda808a bellard
#if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \
92 dbda808a bellard
    (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN)
93 dbda808a bellard
#define OPENPIC_SWAP
94 dbda808a bellard
#endif
95 dbda808a bellard
96 dbda808a bellard
/* Interrupt definitions */
97 dbda808a bellard
#define IRQ_FE     (EXT_IRQ)     /* Internal functional IRQ */
98 dbda808a bellard
#define IRQ_ERR    (EXT_IRQ + 1) /* Error IRQ */
99 dbda808a bellard
#define IRQ_TIM0   (EXT_IRQ + 2) /* First timer IRQ */
100 dbda808a bellard
#if MAX_IPI > 0
101 dbda808a bellard
#define IRQ_IPI0   (IRQ_TIM0 + MAX_TMR) /* First IPI IRQ */
102 dbda808a bellard
#define IRQ_DBL0   (IRQ_IPI0 + (MAX_CPU * MAX_IPI)) /* First doorbell IRQ */
103 dbda808a bellard
#else
104 dbda808a bellard
#define IRQ_DBL0   (IRQ_TIM0 + MAX_TMR) /* First doorbell IRQ */
105 dbda808a bellard
#define IRQ_MBX0   (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */
106 dbda808a bellard
#endif
107 dbda808a bellard
108 dbda808a bellard
#define BF_WIDTH(_bits_) \
109 dbda808a bellard
(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
110 dbda808a bellard
111 dbda808a bellard
static inline void set_bit (uint32_t *field, int bit)
112 dbda808a bellard
{
113 dbda808a bellard
    field[bit >> 5] |= 1 << (bit & 0x1F);
114 dbda808a bellard
}
115 dbda808a bellard
116 dbda808a bellard
static inline void reset_bit (uint32_t *field, int bit)
117 dbda808a bellard
{
118 dbda808a bellard
    field[bit >> 5] &= ~(1 << (bit & 0x1F));
119 dbda808a bellard
}
120 dbda808a bellard
121 dbda808a bellard
static inline int test_bit (uint32_t *field, int bit)
122 dbda808a bellard
{
123 dbda808a bellard
    return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
124 dbda808a bellard
}
125 dbda808a bellard
126 dbda808a bellard
enum {
127 dbda808a bellard
    IRQ_EXTERNAL = 0x01,
128 dbda808a bellard
    IRQ_INTERNAL = 0x02,
129 dbda808a bellard
    IRQ_TIMER    = 0x04,
130 dbda808a bellard
    IRQ_SPECIAL  = 0x08,
131 dbda808a bellard
} IRQ_src_type;
132 dbda808a bellard
133 dbda808a bellard
typedef struct IRQ_queue_t {
134 dbda808a bellard
    uint32_t queue[BF_WIDTH(MAX_IRQ)];
135 dbda808a bellard
    int next;
136 dbda808a bellard
    int priority;
137 dbda808a bellard
} IRQ_queue_t;
138 dbda808a bellard
139 dbda808a bellard
typedef struct IRQ_src_t {
140 dbda808a bellard
    uint32_t ipvp;  /* IRQ vector/priority register */
141 dbda808a bellard
    uint32_t ide;   /* IRQ destination register */
142 dbda808a bellard
    int type;
143 dbda808a bellard
    int last_cpu;
144 611493d9 bellard
    int pending;    /* TRUE if IRQ is pending */
145 dbda808a bellard
} IRQ_src_t;
146 dbda808a bellard
147 dbda808a bellard
enum IPVP_bits {
148 dbda808a bellard
    IPVP_MASK     = 31,
149 dbda808a bellard
    IPVP_ACTIVITY = 30,
150 dbda808a bellard
    IPVP_MODE     = 29,
151 dbda808a bellard
    IPVP_POLARITY = 23,
152 dbda808a bellard
    IPVP_SENSE    = 22,
153 dbda808a bellard
};
154 dbda808a bellard
#define IPVP_PRIORITY_MASK     (0x1F << 16)
155 611493d9 bellard
#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
156 dbda808a bellard
#define IPVP_VECTOR_MASK       ((1 << VECTOR_BITS) - 1)
157 dbda808a bellard
#define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)
158 dbda808a bellard
159 dbda808a bellard
typedef struct IRQ_dst_t {
160 dbda808a bellard
    uint32_t pctp; /* CPU current task priority */
161 dbda808a bellard
    uint32_t pcsr; /* CPU sensitivity register */
162 dbda808a bellard
    IRQ_queue_t raised;
163 dbda808a bellard
    IRQ_queue_t servicing;
164 e9df014c j_mayer
    qemu_irq *irqs;
165 dbda808a bellard
} IRQ_dst_t;
166 dbda808a bellard
167 d537cf6c pbrook
typedef struct openpic_t {
168 dbda808a bellard
    PCIDevice pci_dev;
169 91d848eb bellard
    int mem_index;
170 dbda808a bellard
    /* Global registers */
171 dbda808a bellard
    uint32_t frep; /* Feature reporting register */
172 dbda808a bellard
    uint32_t glbc; /* Global configuration register  */
173 dbda808a bellard
    uint32_t micr; /* MPIC interrupt configuration register */
174 dbda808a bellard
    uint32_t veni; /* Vendor identification register */
175 e9df014c j_mayer
    uint32_t pint; /* Processor initialization register */
176 dbda808a bellard
    uint32_t spve; /* Spurious vector register */
177 dbda808a bellard
    uint32_t tifr; /* Timer frequency reporting register */
178 dbda808a bellard
    /* Source registers */
179 dbda808a bellard
    IRQ_src_t src[MAX_IRQ];
180 dbda808a bellard
    /* Local registers per output pin */
181 dbda808a bellard
    IRQ_dst_t dst[MAX_CPU];
182 dbda808a bellard
    int nb_cpus;
183 dbda808a bellard
    /* Timer registers */
184 dbda808a bellard
    struct {
185 dbda808a bellard
        uint32_t ticc;  /* Global timer current count register */
186 dbda808a bellard
        uint32_t tibc;  /* Global timer base count register */
187 dbda808a bellard
    } timers[MAX_TMR];
188 dbda808a bellard
#if MAX_DBL > 0
189 dbda808a bellard
    /* Doorbell registers */
190 dbda808a bellard
    uint32_t dar;        /* Doorbell activate register */
191 dbda808a bellard
    struct {
192 dbda808a bellard
        uint32_t dmr;    /* Doorbell messaging register */
193 dbda808a bellard
    } doorbells[MAX_DBL];
194 dbda808a bellard
#endif
195 dbda808a bellard
#if MAX_MBX > 0
196 dbda808a bellard
    /* Mailbox registers */
197 dbda808a bellard
    struct {
198 dbda808a bellard
        uint32_t mbr;    /* Mailbox register */
199 dbda808a bellard
    } mailboxes[MAX_MAILBOXES];
200 dbda808a bellard
#endif
201 e9df014c j_mayer
    /* IRQ out is used when in bypass mode (not implemented) */
202 e9df014c j_mayer
    qemu_irq irq_out;
203 d537cf6c pbrook
} openpic_t;
204 dbda808a bellard
205 dbda808a bellard
static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
206 dbda808a bellard
{
207 dbda808a bellard
    set_bit(q->queue, n_IRQ);
208 dbda808a bellard
}
209 dbda808a bellard
210 dbda808a bellard
static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
211 dbda808a bellard
{
212 dbda808a bellard
    reset_bit(q->queue, n_IRQ);
213 dbda808a bellard
}
214 dbda808a bellard
215 dbda808a bellard
static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
216 dbda808a bellard
{
217 dbda808a bellard
    return test_bit(q->queue, n_IRQ);
218 dbda808a bellard
}
219 dbda808a bellard
220 dbda808a bellard
static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
221 dbda808a bellard
{
222 dbda808a bellard
    int next, i;
223 dbda808a bellard
    int priority;
224 dbda808a bellard
225 dbda808a bellard
    next = -1;
226 dbda808a bellard
    priority = -1;
227 dbda808a bellard
    for (i = 0; i < MAX_IRQ; i++) {
228 dbda808a bellard
        if (IRQ_testbit(q, i)) {
229 5fafdf24 ths
            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
230 611493d9 bellard
                    i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
231 dbda808a bellard
            if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
232 dbda808a bellard
                next = i;
233 dbda808a bellard
                priority = IPVP_PRIORITY(opp->src[i].ipvp);
234 dbda808a bellard
            }
235 dbda808a bellard
        }
236 dbda808a bellard
    }
237 dbda808a bellard
    q->next = next;
238 dbda808a bellard
    q->priority = priority;
239 dbda808a bellard
}
240 dbda808a bellard
241 dbda808a bellard
static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
242 dbda808a bellard
{
243 dbda808a bellard
    if (q->next == -1) {
244 611493d9 bellard
        /* XXX: optimize */
245 dbda808a bellard
        IRQ_check(opp, q);
246 dbda808a bellard
    }
247 dbda808a bellard
248 dbda808a bellard
    return q->next;
249 dbda808a bellard
}
250 dbda808a bellard
251 dbda808a bellard
static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
252 dbda808a bellard
{
253 dbda808a bellard
    IRQ_dst_t *dst;
254 dbda808a bellard
    IRQ_src_t *src;
255 dbda808a bellard
    int priority;
256 dbda808a bellard
257 dbda808a bellard
    dst = &opp->dst[n_CPU];
258 dbda808a bellard
    src = &opp->src[n_IRQ];
259 dbda808a bellard
    priority = IPVP_PRIORITY(src->ipvp);
260 dbda808a bellard
    if (priority <= dst->pctp) {
261 dbda808a bellard
        /* Too low priority */
262 e9df014c j_mayer
        DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
263 e9df014c j_mayer
                __func__, n_IRQ, n_CPU);
264 dbda808a bellard
        return;
265 dbda808a bellard
    }
266 dbda808a bellard
    if (IRQ_testbit(&dst->raised, n_IRQ)) {
267 dbda808a bellard
        /* Interrupt miss */
268 e9df014c j_mayer
        DPRINTF("%s: IRQ %d was missed on CPU %d\n",
269 e9df014c j_mayer
                __func__, n_IRQ, n_CPU);
270 dbda808a bellard
        return;
271 dbda808a bellard
    }
272 dbda808a bellard
    set_bit(&src->ipvp, IPVP_ACTIVITY);
273 dbda808a bellard
    IRQ_setbit(&dst->raised, n_IRQ);
274 e9df014c j_mayer
    if (priority < dst->raised.priority) {
275 e9df014c j_mayer
        /* An higher priority IRQ is already raised */
276 e9df014c j_mayer
        DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
277 e9df014c j_mayer
                __func__, n_IRQ, dst->raised.next, n_CPU);
278 e9df014c j_mayer
        return;
279 e9df014c j_mayer
    }
280 e9df014c j_mayer
    IRQ_get_next(opp, &dst->raised);
281 e9df014c j_mayer
    if (IRQ_get_next(opp, &dst->servicing) != -1 &&
282 e9df014c j_mayer
        priority < dst->servicing.priority) {
283 e9df014c j_mayer
        DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
284 e9df014c j_mayer
                __func__, n_IRQ, dst->servicing.next, n_CPU);
285 e9df014c j_mayer
        /* Already servicing a higher priority IRQ */
286 e9df014c j_mayer
        return;
287 dbda808a bellard
    }
288 e9df014c j_mayer
    DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
289 e9df014c j_mayer
    qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
290 dbda808a bellard
}
291 dbda808a bellard
292 611493d9 bellard
/* update pic state because registers for n_IRQ have changed value */
293 611493d9 bellard
static void openpic_update_irq(openpic_t *opp, int n_IRQ)
294 dbda808a bellard
{
295 dbda808a bellard
    IRQ_src_t *src;
296 dbda808a bellard
    int i;
297 dbda808a bellard
298 dbda808a bellard
    src = &opp->src[n_IRQ];
299 611493d9 bellard
300 611493d9 bellard
    if (!src->pending) {
301 611493d9 bellard
        /* no irq pending */
302 e9df014c j_mayer
        DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
303 611493d9 bellard
        return;
304 611493d9 bellard
    }
305 611493d9 bellard
    if (test_bit(&src->ipvp, IPVP_MASK)) {
306 dbda808a bellard
        /* Interrupt source is disabled */
307 e9df014c j_mayer
        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
308 dbda808a bellard
        return;
309 dbda808a bellard
    }
310 dbda808a bellard
    if (IPVP_PRIORITY(src->ipvp) == 0) {
311 dbda808a bellard
        /* Priority set to zero */
312 e9df014c j_mayer
        DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
313 dbda808a bellard
        return;
314 dbda808a bellard
    }
315 611493d9 bellard
    if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
316 611493d9 bellard
        /* IRQ already active */
317 e9df014c j_mayer
        DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
318 611493d9 bellard
        return;
319 611493d9 bellard
    }
320 dbda808a bellard
    if (src->ide == 0x00000000) {
321 dbda808a bellard
        /* No target */
322 e9df014c j_mayer
        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
323 dbda808a bellard
        return;
324 dbda808a bellard
    }
325 611493d9 bellard
326 e9df014c j_mayer
    if (src->ide == (1 << src->last_cpu)) {
327 e9df014c j_mayer
        /* Only one CPU is allowed to receive this IRQ */
328 e9df014c j_mayer
        IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
329 e9df014c j_mayer
    } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
330 611493d9 bellard
        /* Directed delivery mode */
331 611493d9 bellard
        for (i = 0; i < opp->nb_cpus; i++) {
332 611493d9 bellard
            if (test_bit(&src->ide, i))
333 611493d9 bellard
                IRQ_local_pipe(opp, i, n_IRQ);
334 611493d9 bellard
        }
335 dbda808a bellard
    } else {
336 611493d9 bellard
        /* Distributed delivery mode */
337 e9df014c j_mayer
        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
338 e9df014c j_mayer
            if (i == opp->nb_cpus)
339 611493d9 bellard
                i = 0;
340 611493d9 bellard
            if (test_bit(&src->ide, i)) {
341 611493d9 bellard
                IRQ_local_pipe(opp, i, n_IRQ);
342 611493d9 bellard
                src->last_cpu = i;
343 611493d9 bellard
                break;
344 611493d9 bellard
            }
345 611493d9 bellard
        }
346 611493d9 bellard
    }
347 611493d9 bellard
}
348 611493d9 bellard
349 d537cf6c pbrook
static void openpic_set_irq(void *opaque, int n_IRQ, int level)
350 611493d9 bellard
{
351 54fa5af5 bellard
    openpic_t *opp = opaque;
352 611493d9 bellard
    IRQ_src_t *src;
353 611493d9 bellard
354 611493d9 bellard
    src = &opp->src[n_IRQ];
355 5fafdf24 ths
    DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
356 611493d9 bellard
            n_IRQ, level, src->ipvp);
357 611493d9 bellard
    if (test_bit(&src->ipvp, IPVP_SENSE)) {
358 611493d9 bellard
        /* level-sensitive irq */
359 611493d9 bellard
        src->pending = level;
360 611493d9 bellard
        if (!level)
361 611493d9 bellard
            reset_bit(&src->ipvp, IPVP_ACTIVITY);
362 611493d9 bellard
    } else {
363 611493d9 bellard
        /* edge-sensitive irq */
364 611493d9 bellard
        if (level)
365 611493d9 bellard
            src->pending = 1;
366 dbda808a bellard
    }
367 611493d9 bellard
    openpic_update_irq(opp, n_IRQ);
368 dbda808a bellard
}
369 dbda808a bellard
370 dbda808a bellard
static void openpic_reset (openpic_t *opp)
371 dbda808a bellard
{
372 dbda808a bellard
    int i;
373 dbda808a bellard
374 dbda808a bellard
    opp->glbc = 0x80000000;
375 f8407028 bellard
    /* Initialise controller registers */
376 dbda808a bellard
    opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
377 dbda808a bellard
    opp->veni = VENI;
378 e9df014c j_mayer
    opp->pint = 0x00000000;
379 dbda808a bellard
    opp->spve = 0x000000FF;
380 dbda808a bellard
    opp->tifr = 0x003F7A00;
381 dbda808a bellard
    /* ? */
382 dbda808a bellard
    opp->micr = 0x00000000;
383 dbda808a bellard
    /* Initialise IRQ sources */
384 dbda808a bellard
    for (i = 0; i < MAX_IRQ; i++) {
385 dbda808a bellard
        opp->src[i].ipvp = 0xA0000000;
386 dbda808a bellard
        opp->src[i].ide  = 0x00000000;
387 dbda808a bellard
    }
388 dbda808a bellard
    /* Initialise IRQ destinations */
389 e9df014c j_mayer
    for (i = 0; i < MAX_CPU; i++) {
390 dbda808a bellard
        opp->dst[i].pctp      = 0x0000000F;
391 dbda808a bellard
        opp->dst[i].pcsr      = 0x00000000;
392 dbda808a bellard
        memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
393 dbda808a bellard
        memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
394 dbda808a bellard
    }
395 dbda808a bellard
    /* Initialise timers */
396 dbda808a bellard
    for (i = 0; i < MAX_TMR; i++) {
397 dbda808a bellard
        opp->timers[i].ticc = 0x00000000;
398 dbda808a bellard
        opp->timers[i].tibc = 0x80000000;
399 dbda808a bellard
    }
400 dbda808a bellard
    /* Initialise doorbells */
401 dbda808a bellard
#if MAX_DBL > 0
402 dbda808a bellard
    opp->dar = 0x00000000;
403 dbda808a bellard
    for (i = 0; i < MAX_DBL; i++) {
404 dbda808a bellard
        opp->doorbells[i].dmr  = 0x00000000;
405 dbda808a bellard
    }
406 dbda808a bellard
#endif
407 dbda808a bellard
    /* Initialise mailboxes */
408 dbda808a bellard
#if MAX_MBX > 0
409 dbda808a bellard
    for (i = 0; i < MAX_MBX; i++) { /* ? */
410 dbda808a bellard
        opp->mailboxes[i].mbr   = 0x00000000;
411 dbda808a bellard
    }
412 dbda808a bellard
#endif
413 dbda808a bellard
    /* Go out of RESET state */
414 dbda808a bellard
    opp->glbc = 0x00000000;
415 dbda808a bellard
}
416 dbda808a bellard
417 dbda808a bellard
static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
418 dbda808a bellard
{
419 dbda808a bellard
    uint32_t retval;
420 dbda808a bellard
421 dbda808a bellard
    switch (reg) {
422 dbda808a bellard
    case IRQ_IPVP:
423 dbda808a bellard
        retval = opp->src[n_IRQ].ipvp;
424 dbda808a bellard
        break;
425 dbda808a bellard
    case IRQ_IDE:
426 dbda808a bellard
        retval = opp->src[n_IRQ].ide;
427 dbda808a bellard
        break;
428 dbda808a bellard
    }
429 dbda808a bellard
430 dbda808a bellard
    return retval;
431 dbda808a bellard
}
432 dbda808a bellard
433 dbda808a bellard
static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
434 dbda808a bellard
                                 uint32_t reg, uint32_t val)
435 dbda808a bellard
{
436 dbda808a bellard
    uint32_t tmp;
437 dbda808a bellard
438 dbda808a bellard
    switch (reg) {
439 dbda808a bellard
    case IRQ_IPVP:
440 611493d9 bellard
        /* NOTE: not fully accurate for special IRQs, but simple and
441 611493d9 bellard
           sufficient */
442 611493d9 bellard
        /* ACTIVITY bit is read-only */
443 5fafdf24 ths
        opp->src[n_IRQ].ipvp =
444 611493d9 bellard
            (opp->src[n_IRQ].ipvp & 0x40000000) |
445 611493d9 bellard
            (val & 0x800F00FF);
446 611493d9 bellard
        openpic_update_irq(opp, n_IRQ);
447 5fafdf24 ths
        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
448 611493d9 bellard
                n_IRQ, val, opp->src[n_IRQ].ipvp);
449 dbda808a bellard
        break;
450 dbda808a bellard
    case IRQ_IDE:
451 dbda808a bellard
        tmp = val & 0xC0000000;
452 dbda808a bellard
        tmp |= val & ((1 << MAX_CPU) - 1);
453 dbda808a bellard
        opp->src[n_IRQ].ide = tmp;
454 dbda808a bellard
        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
455 dbda808a bellard
        break;
456 dbda808a bellard
    }
457 dbda808a bellard
}
458 dbda808a bellard
459 dbda808a bellard
#if 0 // Code provision for Intel model
460 dbda808a bellard
#if MAX_DBL > 0
461 dbda808a bellard
static uint32_t read_doorbell_register (openpic_t *opp,
462 dbda808a bellard
                                        int n_dbl, uint32_t offset)
463 dbda808a bellard
{
464 dbda808a bellard
    uint32_t retval;
465 dbda808a bellard

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

478 dbda808a bellard
    return retval;
479 dbda808a bellard
}
480 3b46e624 ths

481 dbda808a bellard
static void write_doorbell_register (penpic_t *opp, int n_dbl,
482 dbda808a bellard
                                     uint32_t offset, uint32_t value)
483 dbda808a bellard
{
484 dbda808a bellard
    switch (offset) {
485 dbda808a bellard
    case DBL_IVPR_OFFSET:
486 dbda808a bellard
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
487 dbda808a bellard
        break;
488 dbda808a bellard
    case DBL_IDE_OFFSET:
489 dbda808a bellard
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
490 dbda808a bellard
        break;
491 dbda808a bellard
    case DBL_DMR_OFFSET:
492 dbda808a bellard
        opp->doorbells[n_dbl].dmr = value;
493 dbda808a bellard
        break;
494 dbda808a bellard
    }
495 dbda808a bellard
}
496 dbda808a bellard
#endif
497 dbda808a bellard
498 dbda808a bellard
#if MAX_MBX > 0
499 dbda808a bellard
static uint32_t read_mailbox_register (openpic_t *opp,
500 dbda808a bellard
                                       int n_mbx, uint32_t offset)
501 dbda808a bellard
{
502 dbda808a bellard
    uint32_t retval;
503 dbda808a bellard
504 dbda808a bellard
    switch (offset) {
505 dbda808a bellard
    case MBX_MBR_OFFSET:
506 dbda808a bellard
        retval = opp->mailboxes[n_mbx].mbr;
507 dbda808a bellard
        break;
508 dbda808a bellard
    case MBX_IVPR_OFFSET:
509 dbda808a bellard
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
510 dbda808a bellard
        break;
511 dbda808a bellard
    case MBX_DMR_OFFSET:
512 dbda808a bellard
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
513 dbda808a bellard
        break;
514 dbda808a bellard
    }
515 dbda808a bellard
516 dbda808a bellard
    return retval;
517 dbda808a bellard
}
518 dbda808a bellard
519 dbda808a bellard
static void write_mailbox_register (openpic_t *opp, int n_mbx,
520 dbda808a bellard
                                    uint32_t address, uint32_t value)
521 dbda808a bellard
{
522 dbda808a bellard
    switch (offset) {
523 dbda808a bellard
    case MBX_MBR_OFFSET:
524 dbda808a bellard
        opp->mailboxes[n_mbx].mbr = value;
525 dbda808a bellard
        break;
526 dbda808a bellard
    case MBX_IVPR_OFFSET:
527 dbda808a bellard
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
528 dbda808a bellard
        break;
529 dbda808a bellard
    case MBX_DMR_OFFSET:
530 dbda808a bellard
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
531 dbda808a bellard
        break;
532 dbda808a bellard
    }
533 dbda808a bellard
}
534 dbda808a bellard
#endif
535 dbda808a bellard
#endif /* 0 : Code provision for Intel model */
536 dbda808a bellard
537 dbda808a bellard
static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
538 dbda808a bellard
{
539 dbda808a bellard
    openpic_t *opp = opaque;
540 e9df014c j_mayer
    IRQ_dst_t *dst;
541 e9df014c j_mayer
    int idx;
542 dbda808a bellard
543 dbda808a bellard
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
544 dbda808a bellard
    if (addr & 0xF)
545 dbda808a bellard
        return;
546 dbda808a bellard
#if defined OPENPIC_SWAP
547 dbda808a bellard
    val = bswap32(val);
548 dbda808a bellard
#endif
549 dbda808a bellard
    addr &= 0xFF;
550 dbda808a bellard
    switch (addr) {
551 dbda808a bellard
    case 0x00: /* FREP */
552 dbda808a bellard
        break;
553 dbda808a bellard
    case 0x20: /* GLBC */
554 dbda808a bellard
        if (val & 0x80000000)
555 dbda808a bellard
            openpic_reset(opp);
556 dbda808a bellard
        opp->glbc = val & ~0x80000000;
557 dbda808a bellard
        break;
558 dbda808a bellard
    case 0x80: /* VENI */
559 dbda808a bellard
        break;
560 dbda808a bellard
    case 0x90: /* PINT */
561 e9df014c j_mayer
        for (idx = 0; idx < opp->nb_cpus; idx++) {
562 e9df014c j_mayer
            if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
563 e9df014c j_mayer
                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
564 e9df014c j_mayer
                dst = &opp->dst[idx];
565 e9df014c j_mayer
                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
566 e9df014c j_mayer
            } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
567 e9df014c j_mayer
                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
568 e9df014c j_mayer
                dst = &opp->dst[idx];
569 e9df014c j_mayer
                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
570 e9df014c j_mayer
            }
571 dbda808a bellard
        }
572 e9df014c j_mayer
        opp->pint = val;
573 dbda808a bellard
        break;
574 dbda808a bellard
#if MAX_IPI > 0
575 dbda808a bellard
    case 0xA0: /* IPI_IPVP */
576 dbda808a bellard
    case 0xB0:
577 dbda808a bellard
    case 0xC0:
578 dbda808a bellard
    case 0xD0:
579 dbda808a bellard
        {
580 dbda808a bellard
            int idx;
581 dbda808a bellard
            idx = (addr - 0xA0) >> 4;
582 dbda808a bellard
            write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
583 dbda808a bellard
        }
584 dbda808a bellard
        break;
585 dbda808a bellard
#endif
586 dbda808a bellard
    case 0xE0: /* SPVE */
587 dbda808a bellard
        opp->spve = val & 0x000000FF;
588 dbda808a bellard
        break;
589 dbda808a bellard
    case 0xF0: /* TIFR */
590 dbda808a bellard
        opp->tifr = val;
591 dbda808a bellard
        break;
592 dbda808a bellard
    default:
593 dbda808a bellard
        break;
594 dbda808a bellard
    }
595 dbda808a bellard
}
596 dbda808a bellard
597 dbda808a bellard
static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
598 dbda808a bellard
{
599 dbda808a bellard
    openpic_t *opp = opaque;
600 dbda808a bellard
    uint32_t retval;
601 dbda808a bellard
602 dbda808a bellard
    DPRINTF("%s: addr %08x\n", __func__, addr);
603 dbda808a bellard
    retval = 0xFFFFFFFF;
604 dbda808a bellard
    if (addr & 0xF)
605 dbda808a bellard
        return retval;
606 dbda808a bellard
    addr &= 0xFF;
607 dbda808a bellard
    switch (addr) {
608 dbda808a bellard
    case 0x00: /* FREP */
609 dbda808a bellard
        retval = opp->frep;
610 dbda808a bellard
        break;
611 dbda808a bellard
    case 0x20: /* GLBC */
612 dbda808a bellard
        retval = opp->glbc;
613 dbda808a bellard
        break;
614 dbda808a bellard
    case 0x80: /* VENI */
615 dbda808a bellard
        retval = opp->veni;
616 dbda808a bellard
        break;
617 dbda808a bellard
    case 0x90: /* PINT */
618 dbda808a bellard
        retval = 0x00000000;
619 dbda808a bellard
        break;
620 dbda808a bellard
#if MAX_IPI > 0
621 dbda808a bellard
    case 0xA0: /* IPI_IPVP */
622 dbda808a bellard
    case 0xB0:
623 dbda808a bellard
    case 0xC0:
624 dbda808a bellard
    case 0xD0:
625 dbda808a bellard
        {
626 dbda808a bellard
            int idx;
627 dbda808a bellard
            idx = (addr - 0xA0) >> 4;
628 dbda808a bellard
            retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
629 dbda808a bellard
        }
630 dbda808a bellard
        break;
631 dbda808a bellard
#endif
632 dbda808a bellard
    case 0xE0: /* SPVE */
633 dbda808a bellard
        retval = opp->spve;
634 dbda808a bellard
        break;
635 dbda808a bellard
    case 0xF0: /* TIFR */
636 dbda808a bellard
        retval = opp->tifr;
637 dbda808a bellard
        break;
638 dbda808a bellard
    default:
639 dbda808a bellard
        break;
640 dbda808a bellard
    }
641 dbda808a bellard
    DPRINTF("%s: => %08x\n", __func__, retval);
642 dbda808a bellard
#if defined OPENPIC_SWAP
643 dbda808a bellard
    retval = bswap32(retval);
644 dbda808a bellard
#endif
645 dbda808a bellard
646 dbda808a bellard
    return retval;
647 dbda808a bellard
}
648 dbda808a bellard
649 dbda808a bellard
static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
650 dbda808a bellard
{
651 dbda808a bellard
    openpic_t *opp = opaque;
652 dbda808a bellard
    int idx;
653 dbda808a bellard
654 dbda808a bellard
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
655 dbda808a bellard
    if (addr & 0xF)
656 dbda808a bellard
        return;
657 dbda808a bellard
#if defined OPENPIC_SWAP
658 dbda808a bellard
    val = bswap32(val);
659 dbda808a bellard
#endif
660 dbda808a bellard
    addr -= 0x1100;
661 dbda808a bellard
    addr &= 0xFFFF;
662 dbda808a bellard
    idx = (addr & 0xFFF0) >> 6;
663 dbda808a bellard
    addr = addr & 0x30;
664 dbda808a bellard
    switch (addr) {
665 dbda808a bellard
    case 0x00: /* TICC */
666 dbda808a bellard
        break;
667 dbda808a bellard
    case 0x10: /* TIBC */
668 dbda808a bellard
        if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
669 8adbc566 bellard
            (val & 0x80000000) == 0 &&
670 dbda808a bellard
            (opp->timers[idx].tibc & 0x80000000) != 0)
671 dbda808a bellard
            opp->timers[idx].ticc &= ~0x80000000;
672 dbda808a bellard
        opp->timers[idx].tibc = val;
673 dbda808a bellard
        break;
674 dbda808a bellard
    case 0x20: /* TIVP */
675 dbda808a bellard
        write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val);
676 dbda808a bellard
        break;
677 dbda808a bellard
    case 0x30: /* TIDE */
678 dbda808a bellard
        write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val);
679 dbda808a bellard
        break;
680 dbda808a bellard
    }
681 dbda808a bellard
}
682 dbda808a bellard
683 dbda808a bellard
static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
684 dbda808a bellard
{
685 dbda808a bellard
    openpic_t *opp = opaque;
686 dbda808a bellard
    uint32_t retval;
687 dbda808a bellard
    int idx;
688 dbda808a bellard
689 dbda808a bellard
    DPRINTF("%s: addr %08x\n", __func__, addr);
690 dbda808a bellard
    retval = 0xFFFFFFFF;
691 dbda808a bellard
    if (addr & 0xF)
692 dbda808a bellard
        return retval;
693 dbda808a bellard
    addr -= 0x1100;
694 dbda808a bellard
    addr &= 0xFFFF;
695 dbda808a bellard
    idx = (addr & 0xFFF0) >> 6;
696 dbda808a bellard
    addr = addr & 0x30;
697 dbda808a bellard
    switch (addr) {
698 dbda808a bellard
    case 0x00: /* TICC */
699 dbda808a bellard
        retval = opp->timers[idx].ticc;
700 dbda808a bellard
        break;
701 dbda808a bellard
    case 0x10: /* TIBC */
702 dbda808a bellard
        retval = opp->timers[idx].tibc;
703 dbda808a bellard
        break;
704 dbda808a bellard
    case 0x20: /* TIPV */
705 dbda808a bellard
        retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP);
706 dbda808a bellard
        break;
707 dbda808a bellard
    case 0x30: /* TIDE */
708 dbda808a bellard
        retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE);
709 dbda808a bellard
        break;
710 dbda808a bellard
    }
711 dbda808a bellard
    DPRINTF("%s: => %08x\n", __func__, retval);
712 dbda808a bellard
#if defined OPENPIC_SWAP
713 dbda808a bellard
    retval = bswap32(retval);
714 dbda808a bellard
#endif
715 dbda808a bellard
716 dbda808a bellard
    return retval;
717 dbda808a bellard
}
718 dbda808a bellard
719 dbda808a bellard
static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
720 dbda808a bellard
{
721 dbda808a bellard
    openpic_t *opp = opaque;
722 dbda808a bellard
    int idx;
723 dbda808a bellard
724 dbda808a bellard
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
725 dbda808a bellard
    if (addr & 0xF)
726 dbda808a bellard
        return;
727 dbda808a bellard
#if defined OPENPIC_SWAP
728 dbda808a bellard
    val = tswap32(val);
729 dbda808a bellard
#endif
730 dbda808a bellard
    addr = addr & 0xFFF0;
731 dbda808a bellard
    idx = addr >> 5;
732 dbda808a bellard
    if (addr & 0x10) {
733 dbda808a bellard
        /* EXDE / IFEDE / IEEDE */
734 dbda808a bellard
        write_IRQreg(opp, idx, IRQ_IDE, val);
735 dbda808a bellard
    } else {
736 dbda808a bellard
        /* EXVP / IFEVP / IEEVP */
737 dbda808a bellard
        write_IRQreg(opp, idx, IRQ_IPVP, val);
738 dbda808a bellard
    }
739 dbda808a bellard
}
740 dbda808a bellard
741 dbda808a bellard
static uint32_t openpic_src_read (void *opaque, uint32_t addr)
742 dbda808a bellard
{
743 dbda808a bellard
    openpic_t *opp = opaque;
744 dbda808a bellard
    uint32_t retval;
745 dbda808a bellard
    int idx;
746 dbda808a bellard
747 dbda808a bellard
    DPRINTF("%s: addr %08x\n", __func__, addr);
748 dbda808a bellard
    retval = 0xFFFFFFFF;
749 dbda808a bellard
    if (addr & 0xF)
750 dbda808a bellard
        return retval;
751 dbda808a bellard
    addr = addr & 0xFFF0;
752 dbda808a bellard
    idx = addr >> 5;
753 dbda808a bellard
    if (addr & 0x10) {
754 dbda808a bellard
        /* EXDE / IFEDE / IEEDE */
755 dbda808a bellard
        retval = read_IRQreg(opp, idx, IRQ_IDE);
756 dbda808a bellard
    } else {
757 dbda808a bellard
        /* EXVP / IFEVP / IEEVP */
758 dbda808a bellard
        retval = read_IRQreg(opp, idx, IRQ_IPVP);
759 dbda808a bellard
    }
760 dbda808a bellard
    DPRINTF("%s: => %08x\n", __func__, retval);
761 dbda808a bellard
#if defined OPENPIC_SWAP
762 dbda808a bellard
    retval = tswap32(retval);
763 dbda808a bellard
#endif
764 dbda808a bellard
765 dbda808a bellard
    return retval;
766 dbda808a bellard
}
767 dbda808a bellard
768 dbda808a bellard
static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
769 dbda808a bellard
{
770 dbda808a bellard
    openpic_t *opp = opaque;
771 dbda808a bellard
    IRQ_src_t *src;
772 dbda808a bellard
    IRQ_dst_t *dst;
773 e9df014c j_mayer
    int idx, s_IRQ, n_IRQ;
774 dbda808a bellard
775 dbda808a bellard
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
776 dbda808a bellard
    if (addr & 0xF)
777 dbda808a bellard
        return;
778 dbda808a bellard
#if defined OPENPIC_SWAP
779 dbda808a bellard
    val = bswap32(val);
780 dbda808a bellard
#endif
781 dbda808a bellard
    addr &= 0x1FFF0;
782 dbda808a bellard
    idx = addr / 0x1000;
783 dbda808a bellard
    dst = &opp->dst[idx];
784 dbda808a bellard
    addr &= 0xFF0;
785 dbda808a bellard
    switch (addr) {
786 dbda808a bellard
#if MAX_IPI > 0
787 dbda808a bellard
    case 0x40: /* PIPD */
788 dbda808a bellard
    case 0x50:
789 dbda808a bellard
    case 0x60:
790 dbda808a bellard
    case 0x70:
791 dbda808a bellard
        idx = (addr - 0x40) >> 4;
792 dbda808a bellard
        write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val);
793 611493d9 bellard
        openpic_set_irq(opp, IRQ_IPI0 + idx, 1);
794 611493d9 bellard
        openpic_set_irq(opp, IRQ_IPI0 + idx, 0);
795 dbda808a bellard
        break;
796 dbda808a bellard
#endif
797 dbda808a bellard
    case 0x80: /* PCTP */
798 dbda808a bellard
        dst->pctp = val & 0x0000000F;
799 dbda808a bellard
        break;
800 dbda808a bellard
    case 0x90: /* WHOAMI */
801 dbda808a bellard
        /* Read-only register */
802 dbda808a bellard
        break;
803 dbda808a bellard
    case 0xA0: /* PIAC */
804 dbda808a bellard
        /* Read-only register */
805 dbda808a bellard
        break;
806 dbda808a bellard
    case 0xB0: /* PEOI */
807 dbda808a bellard
        DPRINTF("PEOI\n");
808 e9df014c j_mayer
        s_IRQ = IRQ_get_next(opp, &dst->servicing);
809 e9df014c j_mayer
        IRQ_resetbit(&dst->servicing, s_IRQ);
810 dbda808a bellard
        dst->servicing.next = -1;
811 dbda808a bellard
        /* Set up next servicing IRQ */
812 e9df014c j_mayer
        s_IRQ = IRQ_get_next(opp, &dst->servicing);
813 e9df014c j_mayer
        /* Check queued interrupts. */
814 e9df014c j_mayer
        n_IRQ = IRQ_get_next(opp, &dst->raised);
815 e9df014c j_mayer
        src = &opp->src[n_IRQ];
816 e9df014c j_mayer
        if (n_IRQ != -1 &&
817 e9df014c j_mayer
            (s_IRQ == -1 ||
818 e9df014c j_mayer
             IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
819 e9df014c j_mayer
            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
820 e9df014c j_mayer
                    idx, n_IRQ);
821 e9df014c j_mayer
            qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
822 e9df014c j_mayer
        }
823 dbda808a bellard
        break;
824 dbda808a bellard
    default:
825 dbda808a bellard
        break;
826 dbda808a bellard
    }
827 dbda808a bellard
}
828 dbda808a bellard
829 dbda808a bellard
static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
830 dbda808a bellard
{
831 dbda808a bellard
    openpic_t *opp = opaque;
832 dbda808a bellard
    IRQ_src_t *src;
833 dbda808a bellard
    IRQ_dst_t *dst;
834 dbda808a bellard
    uint32_t retval;
835 dbda808a bellard
    int idx, n_IRQ;
836 3b46e624 ths
837 dbda808a bellard
    DPRINTF("%s: addr %08x\n", __func__, addr);
838 dbda808a bellard
    retval = 0xFFFFFFFF;
839 dbda808a bellard
    if (addr & 0xF)
840 dbda808a bellard
        return retval;
841 dbda808a bellard
    addr &= 0x1FFF0;
842 dbda808a bellard
    idx = addr / 0x1000;
843 dbda808a bellard
    dst = &opp->dst[idx];
844 dbda808a bellard
    addr &= 0xFF0;
845 dbda808a bellard
    switch (addr) {
846 dbda808a bellard
    case 0x80: /* PCTP */
847 dbda808a bellard
        retval = dst->pctp;
848 dbda808a bellard
        break;
849 dbda808a bellard
    case 0x90: /* WHOAMI */
850 dbda808a bellard
        retval = idx;
851 dbda808a bellard
        break;
852 dbda808a bellard
    case 0xA0: /* PIAC */
853 e9df014c j_mayer
        DPRINTF("Lower OpenPIC INT output\n");
854 e9df014c j_mayer
        qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
855 dbda808a bellard
        n_IRQ = IRQ_get_next(opp, &dst->raised);
856 dbda808a bellard
        DPRINTF("PIAC: irq=%d\n", n_IRQ);
857 dbda808a bellard
        if (n_IRQ == -1) {
858 dbda808a bellard
            /* No more interrupt pending */
859 e9df014c j_mayer
            retval = IPVP_VECTOR(opp->spve);
860 dbda808a bellard
        } else {
861 dbda808a bellard
            src = &opp->src[n_IRQ];
862 dbda808a bellard
            if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
863 dbda808a bellard
                !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
864 dbda808a bellard
                /* - Spurious level-sensitive IRQ
865 dbda808a bellard
                 * - Priorities has been changed
866 dbda808a bellard
                 *   and the pending IRQ isn't allowed anymore
867 dbda808a bellard
                 */
868 dbda808a bellard
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
869 dbda808a bellard
                retval = IPVP_VECTOR(opp->spve);
870 dbda808a bellard
            } else {
871 dbda808a bellard
                /* IRQ enter servicing state */
872 dbda808a bellard
                IRQ_setbit(&dst->servicing, n_IRQ);
873 dbda808a bellard
                retval = IPVP_VECTOR(src->ipvp);
874 dbda808a bellard
            }
875 dbda808a bellard
            IRQ_resetbit(&dst->raised, n_IRQ);
876 dbda808a bellard
            dst->raised.next = -1;
877 611493d9 bellard
            if (!test_bit(&src->ipvp, IPVP_SENSE)) {
878 611493d9 bellard
                /* edge-sensitive IRQ */
879 dbda808a bellard
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
880 611493d9 bellard
                src->pending = 0;
881 611493d9 bellard
            }
882 dbda808a bellard
        }
883 dbda808a bellard
        break;
884 dbda808a bellard
    case 0xB0: /* PEOI */
885 dbda808a bellard
        retval = 0;
886 dbda808a bellard
        break;
887 dbda808a bellard
#if MAX_IPI > 0
888 dbda808a bellard
    case 0x40: /* IDE */
889 dbda808a bellard
    case 0x50:
890 dbda808a bellard
        idx = (addr - 0x40) >> 4;
891 dbda808a bellard
        retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE);
892 dbda808a bellard
        break;
893 dbda808a bellard
#endif
894 dbda808a bellard
    default:
895 dbda808a bellard
        break;
896 dbda808a bellard
    }
897 dbda808a bellard
    DPRINTF("%s: => %08x\n", __func__, retval);
898 dbda808a bellard
#if defined OPENPIC_SWAP
899 dbda808a bellard
    retval= bswap32(retval);
900 dbda808a bellard
#endif
901 dbda808a bellard
902 dbda808a bellard
    return retval;
903 dbda808a bellard
}
904 dbda808a bellard
905 dbda808a bellard
static void openpic_buggy_write (void *opaque,
906 dbda808a bellard
                                 target_phys_addr_t addr, uint32_t val)
907 dbda808a bellard
{
908 dbda808a bellard
    printf("Invalid OPENPIC write access !\n");
909 dbda808a bellard
}
910 dbda808a bellard
911 dbda808a bellard
static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
912 dbda808a bellard
{
913 dbda808a bellard
    printf("Invalid OPENPIC read access !\n");
914 dbda808a bellard
915 dbda808a bellard
    return -1;
916 dbda808a bellard
}
917 dbda808a bellard
918 dbda808a bellard
static void openpic_writel (void *opaque,
919 dbda808a bellard
                            target_phys_addr_t addr, uint32_t val)
920 dbda808a bellard
{
921 dbda808a bellard
    openpic_t *opp = opaque;
922 dbda808a bellard
923 dbda808a bellard
    addr &= 0x3FFFF;
924 611493d9 bellard
    DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
925 dbda808a bellard
    if (addr < 0x1100) {
926 dbda808a bellard
        /* Global registers */
927 dbda808a bellard
        openpic_gbl_write(opp, addr, val);
928 dbda808a bellard
    } else if (addr < 0x10000) {
929 dbda808a bellard
        /* Timers registers */
930 dbda808a bellard
        openpic_timer_write(opp, addr, val);
931 dbda808a bellard
    } else if (addr < 0x20000) {
932 dbda808a bellard
        /* Source registers */
933 dbda808a bellard
        openpic_src_write(opp, addr, val);
934 dbda808a bellard
    } else {
935 dbda808a bellard
        /* CPU registers */
936 dbda808a bellard
        openpic_cpu_write(opp, addr, val);
937 dbda808a bellard
    }
938 dbda808a bellard
}
939 dbda808a bellard
940 dbda808a bellard
static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
941 dbda808a bellard
{
942 dbda808a bellard
    openpic_t *opp = opaque;
943 dbda808a bellard
    uint32_t retval;
944 dbda808a bellard
945 dbda808a bellard
    addr &= 0x3FFFF;
946 611493d9 bellard
    DPRINTF("%s: offset %08x\n", __func__, (int)addr);
947 dbda808a bellard
    if (addr < 0x1100) {
948 dbda808a bellard
        /* Global registers */
949 dbda808a bellard
        retval = openpic_gbl_read(opp, addr);
950 dbda808a bellard
    } else if (addr < 0x10000) {
951 dbda808a bellard
        /* Timers registers */
952 dbda808a bellard
        retval = openpic_timer_read(opp, addr);
953 dbda808a bellard
    } else if (addr < 0x20000) {
954 dbda808a bellard
        /* Source registers */
955 dbda808a bellard
        retval = openpic_src_read(opp, addr);
956 dbda808a bellard
    } else {
957 dbda808a bellard
        /* CPU registers */
958 dbda808a bellard
        retval = openpic_cpu_read(opp, addr);
959 dbda808a bellard
    }
960 dbda808a bellard
961 dbda808a bellard
    return retval;
962 dbda808a bellard
}
963 dbda808a bellard
964 dbda808a bellard
static CPUWriteMemoryFunc *openpic_write[] = {
965 dbda808a bellard
    &openpic_buggy_write,
966 dbda808a bellard
    &openpic_buggy_write,
967 dbda808a bellard
    &openpic_writel,
968 dbda808a bellard
};
969 dbda808a bellard
970 dbda808a bellard
static CPUReadMemoryFunc *openpic_read[] = {
971 dbda808a bellard
    &openpic_buggy_read,
972 dbda808a bellard
    &openpic_buggy_read,
973 dbda808a bellard
    &openpic_readl,
974 dbda808a bellard
};
975 dbda808a bellard
976 5fafdf24 ths
static void openpic_map(PCIDevice *pci_dev, int region_num,
977 dbda808a bellard
                        uint32_t addr, uint32_t size, int type)
978 dbda808a bellard
{
979 dbda808a bellard
    openpic_t *opp;
980 dbda808a bellard
981 dbda808a bellard
    DPRINTF("Map OpenPIC\n");
982 dbda808a bellard
    opp = (openpic_t *)pci_dev;
983 dbda808a bellard
    /* Global registers */
984 dbda808a bellard
    DPRINTF("Register OPENPIC gbl   %08x => %08x\n",
985 dbda808a bellard
            addr + 0x1000, addr + 0x1000 + 0x100);
986 dbda808a bellard
    /* Timer registers */
987 dbda808a bellard
    DPRINTF("Register OPENPIC timer %08x => %08x\n",
988 dbda808a bellard
            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
989 dbda808a bellard
    /* Interrupt source registers */
990 dbda808a bellard
    DPRINTF("Register OPENPIC src   %08x => %08x\n",
991 dbda808a bellard
            addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2));
992 dbda808a bellard
    /* Per CPU registers */
993 dbda808a bellard
    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
994 dbda808a bellard
            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
995 91d848eb bellard
    cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
996 dbda808a bellard
#if 0 // Don't implement ISU for now
997 dbda808a bellard
    opp_io_memory = cpu_register_io_memory(0, openpic_src_read,
998 dbda808a bellard
                                           openpic_src_write);
999 dbda808a bellard
    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
1000 dbda808a bellard
                                 opp_io_memory);
1001 dbda808a bellard
#endif
1002 dbda808a bellard
}
1003 dbda808a bellard
1004 e9df014c j_mayer
qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
1005 e9df014c j_mayer
                        qemu_irq **irqs, qemu_irq irq_out)
1006 dbda808a bellard
{
1007 dbda808a bellard
    openpic_t *opp;
1008 dbda808a bellard
    uint8_t *pci_conf;
1009 dbda808a bellard
    int i, m;
1010 3b46e624 ths
1011 dbda808a bellard
    /* XXX: for now, only one CPU is supported */
1012 dbda808a bellard
    if (nb_cpus != 1)
1013 dbda808a bellard
        return NULL;
1014 91d848eb bellard
    if (bus) {
1015 91d848eb bellard
        opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
1016 91d848eb bellard
                                               -1, NULL, NULL);
1017 91d848eb bellard
        if (opp == NULL)
1018 91d848eb bellard
            return NULL;
1019 91d848eb bellard
        pci_conf = opp->pci_dev.config;
1020 91d848eb bellard
        pci_conf[0x00] = 0x14; // IBM MPIC2
1021 91d848eb bellard
        pci_conf[0x01] = 0x10;
1022 91d848eb bellard
        pci_conf[0x02] = 0xFF;
1023 91d848eb bellard
        pci_conf[0x03] = 0xFF;
1024 91d848eb bellard
        pci_conf[0x0a] = 0x80; // PIC
1025 91d848eb bellard
        pci_conf[0x0b] = 0x08;
1026 91d848eb bellard
        pci_conf[0x0e] = 0x00; // header_type
1027 91d848eb bellard
        pci_conf[0x3d] = 0x00; // no interrupt pin
1028 3b46e624 ths
1029 91d848eb bellard
        /* Register I/O spaces */
1030 91d848eb bellard
        pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
1031 91d848eb bellard
                               PCI_ADDRESS_SPACE_MEM, &openpic_map);
1032 91d848eb bellard
    } else {
1033 91d848eb bellard
        opp = qemu_mallocz(sizeof(openpic_t));
1034 91d848eb bellard
    }
1035 91d848eb bellard
    opp->mem_index = cpu_register_io_memory(0, openpic_read,
1036 91d848eb bellard
                                            openpic_write, opp);
1037 3b46e624 ths
1038 91d848eb bellard
    //    isu_base &= 0xFFFC0000;
1039 dbda808a bellard
    opp->nb_cpus = nb_cpus;
1040 dbda808a bellard
    /* Set IRQ types */
1041 dbda808a bellard
    for (i = 0; i < EXT_IRQ; i++) {
1042 dbda808a bellard
        opp->src[i].type = IRQ_EXTERNAL;
1043 dbda808a bellard
    }
1044 dbda808a bellard
    for (; i < IRQ_TIM0; i++) {
1045 dbda808a bellard
        opp->src[i].type = IRQ_SPECIAL;
1046 dbda808a bellard
    }
1047 dbda808a bellard
#if MAX_IPI > 0
1048 dbda808a bellard
    m = IRQ_IPI0;
1049 dbda808a bellard
#else
1050 dbda808a bellard
    m = IRQ_DBL0;
1051 dbda808a bellard
#endif
1052 dbda808a bellard
    for (; i < m; i++) {
1053 dbda808a bellard
        opp->src[i].type = IRQ_TIMER;
1054 dbda808a bellard
    }
1055 dbda808a bellard
    for (; i < MAX_IRQ; i++) {
1056 dbda808a bellard
        opp->src[i].type = IRQ_INTERNAL;
1057 dbda808a bellard
    }
1058 7668a27f bellard
    for (i = 0; i < nb_cpus; i++)
1059 e9df014c j_mayer
        opp->dst[i].irqs = irqs[i];
1060 e9df014c j_mayer
    opp->irq_out = irq_out;
1061 dbda808a bellard
    openpic_reset(opp);
1062 91d848eb bellard
    if (pmem_index)
1063 91d848eb bellard
        *pmem_index = opp->mem_index;
1064 e9df014c j_mayer
1065 d537cf6c pbrook
    return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);
1066 dbda808a bellard
}