root / hw / openpic.c @ 0d09e41a
History | View | Annotate | Download (45.3 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/hw.h" |
37 |
#include "hw/ppc/mac.h" |
38 |
#include "hw/pci/pci.h" |
39 |
#include "hw/ppc/openpic.h" |
40 |
#include "hw/sysbus.h" |
41 |
#include "hw/pci/msi.h" |
42 |
#include "qemu/bitops.h" |
43 |
#include "hw/ppc/ppc.h" |
44 |
|
45 |
//#define DEBUG_OPENPIC
|
46 |
|
47 |
#ifdef DEBUG_OPENPIC
|
48 |
static const int debug_openpic = 1; |
49 |
#else
|
50 |
static const int debug_openpic = 0; |
51 |
#endif
|
52 |
|
53 |
#define DPRINTF(fmt, ...) do { \ |
54 |
if (debug_openpic) { \
|
55 |
printf(fmt , ## __VA_ARGS__); \ |
56 |
} \ |
57 |
} while (0) |
58 |
|
59 |
#define MAX_CPU 32 |
60 |
#define MAX_SRC 256 |
61 |
#define MAX_TMR 4 |
62 |
#define MAX_IPI 4 |
63 |
#define MAX_MSI 8 |
64 |
#define MAX_IRQ (MAX_SRC + MAX_IPI + MAX_TMR)
|
65 |
#define VID 0x03 /* MPIC version ID */ |
66 |
|
67 |
/* OpenPIC capability flags */
|
68 |
#define OPENPIC_FLAG_IDR_CRIT (1 << 0) |
69 |
#define OPENPIC_FLAG_ILR (2 << 0) |
70 |
|
71 |
/* OpenPIC address map */
|
72 |
#define OPENPIC_GLB_REG_START 0x0 |
73 |
#define OPENPIC_GLB_REG_SIZE 0x10F0 |
74 |
#define OPENPIC_TMR_REG_START 0x10F0 |
75 |
#define OPENPIC_TMR_REG_SIZE 0x220 |
76 |
#define OPENPIC_MSI_REG_START 0x1600 |
77 |
#define OPENPIC_MSI_REG_SIZE 0x200 |
78 |
#define OPENPIC_SUMMARY_REG_START 0x3800 |
79 |
#define OPENPIC_SUMMARY_REG_SIZE 0x800 |
80 |
#define OPENPIC_SRC_REG_START 0x10000 |
81 |
#define OPENPIC_SRC_REG_SIZE (MAX_SRC * 0x20) |
82 |
#define OPENPIC_CPU_REG_START 0x20000 |
83 |
#define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000) |
84 |
|
85 |
/* Raven */
|
86 |
#define RAVEN_MAX_CPU 2 |
87 |
#define RAVEN_MAX_EXT 48 |
88 |
#define RAVEN_MAX_IRQ 64 |
89 |
#define RAVEN_MAX_TMR MAX_TMR
|
90 |
#define RAVEN_MAX_IPI MAX_IPI
|
91 |
|
92 |
/* Interrupt definitions */
|
93 |
#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */ |
94 |
#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */ |
95 |
#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */ |
96 |
#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */ |
97 |
/* First doorbell IRQ */
|
98 |
#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
|
99 |
|
100 |
typedef struct FslMpicInfo { |
101 |
int max_ext;
|
102 |
} FslMpicInfo; |
103 |
|
104 |
static FslMpicInfo fsl_mpic_20 = {
|
105 |
.max_ext = 12,
|
106 |
}; |
107 |
|
108 |
static FslMpicInfo fsl_mpic_42 = {
|
109 |
.max_ext = 12,
|
110 |
}; |
111 |
|
112 |
#define FRR_NIRQ_SHIFT 16 |
113 |
#define FRR_NCPU_SHIFT 8 |
114 |
#define FRR_VID_SHIFT 0 |
115 |
|
116 |
#define VID_REVISION_1_2 2 |
117 |
#define VID_REVISION_1_3 3 |
118 |
|
119 |
#define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ |
120 |
|
121 |
#define GCR_RESET 0x80000000 |
122 |
#define GCR_MODE_PASS 0x00000000 |
123 |
#define GCR_MODE_MIXED 0x20000000 |
124 |
#define GCR_MODE_PROXY 0x60000000 |
125 |
|
126 |
#define TBCR_CI 0x80000000 /* count inhibit */ |
127 |
#define TCCR_TOG 0x80000000 /* toggles when decrement to zero */ |
128 |
|
129 |
#define IDR_EP_SHIFT 31 |
130 |
#define IDR_EP_MASK (1 << IDR_EP_SHIFT) |
131 |
#define IDR_CI0_SHIFT 30 |
132 |
#define IDR_CI1_SHIFT 29 |
133 |
#define IDR_P1_SHIFT 1 |
134 |
#define IDR_P0_SHIFT 0 |
135 |
|
136 |
#define ILR_INTTGT_MASK 0x000000ff |
137 |
#define ILR_INTTGT_INT 0x00 |
138 |
#define ILR_INTTGT_CINT 0x01 /* critical */ |
139 |
#define ILR_INTTGT_MCP 0x02 /* machine check */ |
140 |
|
141 |
/* The currently supported INTTGT values happen to be the same as QEMU's
|
142 |
* openpic output codes, but don't depend on this. The output codes
|
143 |
* could change (unlikely, but...) or support could be added for
|
144 |
* more INTTGT values.
|
145 |
*/
|
146 |
static const int inttgt_output[][2] = { |
147 |
{ ILR_INTTGT_INT, OPENPIC_OUTPUT_INT }, |
148 |
{ ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT }, |
149 |
{ ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK }, |
150 |
}; |
151 |
|
152 |
static int inttgt_to_output(int inttgt) |
153 |
{ |
154 |
int i;
|
155 |
|
156 |
for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) { |
157 |
if (inttgt_output[i][0] == inttgt) { |
158 |
return inttgt_output[i][1]; |
159 |
} |
160 |
} |
161 |
|
162 |
fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
|
163 |
return OPENPIC_OUTPUT_INT;
|
164 |
} |
165 |
|
166 |
static int output_to_inttgt(int output) |
167 |
{ |
168 |
int i;
|
169 |
|
170 |
for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) { |
171 |
if (inttgt_output[i][1] == output) { |
172 |
return inttgt_output[i][0]; |
173 |
} |
174 |
} |
175 |
|
176 |
abort(); |
177 |
} |
178 |
|
179 |
#define MSIIR_OFFSET 0x140 |
180 |
#define MSIIR_SRS_SHIFT 29 |
181 |
#define MSIIR_SRS_MASK (0x7 << MSIIR_SRS_SHIFT) |
182 |
#define MSIIR_IBS_SHIFT 24 |
183 |
#define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT) |
184 |
|
185 |
static int get_current_cpu(void) |
186 |
{ |
187 |
CPUState *cpu_single_cpu; |
188 |
|
189 |
if (!cpu_single_env) {
|
190 |
return -1; |
191 |
} |
192 |
|
193 |
cpu_single_cpu = ENV_GET_CPU(cpu_single_env); |
194 |
return cpu_single_cpu->cpu_index;
|
195 |
} |
196 |
|
197 |
static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, |
198 |
int idx);
|
199 |
static void openpic_cpu_write_internal(void *opaque, hwaddr addr, |
200 |
uint32_t val, int idx);
|
201 |
|
202 |
typedef enum IRQType { |
203 |
IRQ_TYPE_NORMAL = 0,
|
204 |
IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */
|
205 |
IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
|
206 |
} IRQType; |
207 |
|
208 |
typedef struct IRQQueue { |
209 |
/* Round up to the nearest 64 IRQs so that the queue length
|
210 |
* won't change when moving between 32 and 64 bit hosts.
|
211 |
*/
|
212 |
unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)]; |
213 |
int next;
|
214 |
int priority;
|
215 |
} IRQQueue; |
216 |
|
217 |
typedef struct IRQSource { |
218 |
uint32_t ivpr; /* IRQ vector/priority register */
|
219 |
uint32_t idr; /* IRQ destination register */
|
220 |
uint32_t destmask; /* bitmap of CPU destinations */
|
221 |
int last_cpu;
|
222 |
int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ |
223 |
int pending; /* TRUE if IRQ is pending */ |
224 |
IRQType type; |
225 |
bool level:1; /* level-triggered */ |
226 |
bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ |
227 |
} IRQSource; |
228 |
|
229 |
#define IVPR_MASK_SHIFT 31 |
230 |
#define IVPR_MASK_MASK (1 << IVPR_MASK_SHIFT) |
231 |
#define IVPR_ACTIVITY_SHIFT 30 |
232 |
#define IVPR_ACTIVITY_MASK (1 << IVPR_ACTIVITY_SHIFT) |
233 |
#define IVPR_MODE_SHIFT 29 |
234 |
#define IVPR_MODE_MASK (1 << IVPR_MODE_SHIFT) |
235 |
#define IVPR_POLARITY_SHIFT 23 |
236 |
#define IVPR_POLARITY_MASK (1 << IVPR_POLARITY_SHIFT) |
237 |
#define IVPR_SENSE_SHIFT 22 |
238 |
#define IVPR_SENSE_MASK (1 << IVPR_SENSE_SHIFT) |
239 |
|
240 |
#define IVPR_PRIORITY_MASK (0xF << 16) |
241 |
#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16)) |
242 |
#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
|
243 |
|
244 |
/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
|
245 |
#define IDR_EP 0x80000000 /* external pin */ |
246 |
#define IDR_CI 0x40000000 /* critical interrupt */ |
247 |
|
248 |
typedef struct IRQDest { |
249 |
int32_t ctpr; /* CPU current task priority */
|
250 |
IRQQueue raised; |
251 |
IRQQueue servicing; |
252 |
qemu_irq *irqs; |
253 |
|
254 |
/* Count of IRQ sources asserting on non-INT outputs */
|
255 |
uint32_t outputs_active[OPENPIC_OUTPUT_NB]; |
256 |
} IRQDest; |
257 |
|
258 |
typedef struct OpenPICState { |
259 |
SysBusDevice busdev; |
260 |
MemoryRegion mem; |
261 |
|
262 |
/* Behavior control */
|
263 |
FslMpicInfo *fsl; |
264 |
uint32_t model; |
265 |
uint32_t flags; |
266 |
uint32_t nb_irqs; |
267 |
uint32_t vid; |
268 |
uint32_t vir; /* Vendor identification register */
|
269 |
uint32_t vector_mask; |
270 |
uint32_t tfrr_reset; |
271 |
uint32_t ivpr_reset; |
272 |
uint32_t idr_reset; |
273 |
uint32_t brr1; |
274 |
uint32_t mpic_mode_mask; |
275 |
|
276 |
/* Sub-regions */
|
277 |
MemoryRegion sub_io_mem[6];
|
278 |
|
279 |
/* Global registers */
|
280 |
uint32_t frr; /* Feature reporting register */
|
281 |
uint32_t gcr; /* Global configuration register */
|
282 |
uint32_t pir; /* Processor initialization register */
|
283 |
uint32_t spve; /* Spurious vector register */
|
284 |
uint32_t tfrr; /* Timer frequency reporting register */
|
285 |
/* Source registers */
|
286 |
IRQSource src[MAX_IRQ]; |
287 |
/* Local registers per output pin */
|
288 |
IRQDest dst[MAX_CPU]; |
289 |
uint32_t nb_cpus; |
290 |
/* Timer registers */
|
291 |
struct {
|
292 |
uint32_t tccr; /* Global timer current count register */
|
293 |
uint32_t tbcr; /* Global timer base count register */
|
294 |
} timers[MAX_TMR]; |
295 |
/* Shared MSI registers */
|
296 |
struct {
|
297 |
uint32_t msir; /* Shared Message Signaled Interrupt Register */
|
298 |
} msi[MAX_MSI]; |
299 |
uint32_t max_irq; |
300 |
uint32_t irq_ipi0; |
301 |
uint32_t irq_tim0; |
302 |
uint32_t irq_msi; |
303 |
} OpenPICState; |
304 |
|
305 |
static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) |
306 |
{ |
307 |
set_bit(n_IRQ, q->queue); |
308 |
} |
309 |
|
310 |
static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) |
311 |
{ |
312 |
clear_bit(n_IRQ, q->queue); |
313 |
} |
314 |
|
315 |
static inline int IRQ_testbit(IRQQueue *q, int n_IRQ) |
316 |
{ |
317 |
return test_bit(n_IRQ, q->queue);
|
318 |
} |
319 |
|
320 |
static void IRQ_check(OpenPICState *opp, IRQQueue *q) |
321 |
{ |
322 |
int irq = -1; |
323 |
int next = -1; |
324 |
int priority = -1; |
325 |
|
326 |
for (;;) {
|
327 |
irq = find_next_bit(q->queue, opp->max_irq, irq + 1);
|
328 |
if (irq == opp->max_irq) {
|
329 |
break;
|
330 |
} |
331 |
|
332 |
DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n",
|
333 |
irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority); |
334 |
|
335 |
if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
|
336 |
next = irq; |
337 |
priority = IVPR_PRIORITY(opp->src[irq].ivpr); |
338 |
} |
339 |
} |
340 |
|
341 |
q->next = next; |
342 |
q->priority = priority; |
343 |
} |
344 |
|
345 |
static int IRQ_get_next(OpenPICState *opp, IRQQueue *q) |
346 |
{ |
347 |
/* XXX: optimize */
|
348 |
IRQ_check(opp, q); |
349 |
|
350 |
return q->next;
|
351 |
} |
352 |
|
353 |
static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, |
354 |
bool active, bool was_active) |
355 |
{ |
356 |
IRQDest *dst; |
357 |
IRQSource *src; |
358 |
int priority;
|
359 |
|
360 |
dst = &opp->dst[n_CPU]; |
361 |
src = &opp->src[n_IRQ]; |
362 |
|
363 |
DPRINTF("%s: IRQ %d active %d was %d\n",
|
364 |
__func__, n_IRQ, active, was_active); |
365 |
|
366 |
if (src->output != OPENPIC_OUTPUT_INT) {
|
367 |
DPRINTF("%s: output %d irq %d active %d was %d count %d\n",
|
368 |
__func__, src->output, n_IRQ, active, was_active, |
369 |
dst->outputs_active[src->output]); |
370 |
|
371 |
/* On Freescale MPIC, critical interrupts ignore priority,
|
372 |
* IACK, EOI, etc. Before MPIC v4.1 they also ignore
|
373 |
* masking.
|
374 |
*/
|
375 |
if (active) {
|
376 |
if (!was_active && dst->outputs_active[src->output]++ == 0) { |
377 |
DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n",
|
378 |
__func__, src->output, n_CPU, n_IRQ); |
379 |
qemu_irq_raise(dst->irqs[src->output]); |
380 |
} |
381 |
} else {
|
382 |
if (was_active && --dst->outputs_active[src->output] == 0) { |
383 |
DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n",
|
384 |
__func__, src->output, n_CPU, n_IRQ); |
385 |
qemu_irq_lower(dst->irqs[src->output]); |
386 |
} |
387 |
} |
388 |
|
389 |
return;
|
390 |
} |
391 |
|
392 |
priority = IVPR_PRIORITY(src->ivpr); |
393 |
|
394 |
/* Even if the interrupt doesn't have enough priority,
|
395 |
* it is still raised, in case ctpr is lowered later.
|
396 |
*/
|
397 |
if (active) {
|
398 |
IRQ_setbit(&dst->raised, n_IRQ); |
399 |
} else {
|
400 |
IRQ_resetbit(&dst->raised, n_IRQ); |
401 |
} |
402 |
|
403 |
IRQ_check(opp, &dst->raised); |
404 |
|
405 |
if (active && priority <= dst->ctpr) {
|
406 |
DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n",
|
407 |
__func__, n_IRQ, priority, dst->ctpr, n_CPU); |
408 |
active = 0;
|
409 |
} |
410 |
|
411 |
if (active) {
|
412 |
if (IRQ_get_next(opp, &dst->servicing) >= 0 && |
413 |
priority <= dst->servicing.priority) { |
414 |
DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
|
415 |
__func__, n_IRQ, dst->servicing.next, n_CPU); |
416 |
} else {
|
417 |
DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n",
|
418 |
__func__, n_CPU, n_IRQ, dst->raised.next); |
419 |
qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); |
420 |
} |
421 |
} else {
|
422 |
IRQ_get_next(opp, &dst->servicing); |
423 |
if (dst->raised.priority > dst->ctpr &&
|
424 |
dst->raised.priority > dst->servicing.priority) { |
425 |
DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n",
|
426 |
__func__, n_IRQ, dst->raised.next, dst->raised.priority, |
427 |
dst->ctpr, dst->servicing.priority, n_CPU); |
428 |
/* IRQ line stays asserted */
|
429 |
} else {
|
430 |
DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n",
|
431 |
__func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU); |
432 |
qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); |
433 |
} |
434 |
} |
435 |
} |
436 |
|
437 |
/* update pic state because registers for n_IRQ have changed value */
|
438 |
static void openpic_update_irq(OpenPICState *opp, int n_IRQ) |
439 |
{ |
440 |
IRQSource *src; |
441 |
bool active, was_active;
|
442 |
int i;
|
443 |
|
444 |
src = &opp->src[n_IRQ]; |
445 |
active = src->pending; |
446 |
|
447 |
if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) {
|
448 |
/* Interrupt source is disabled */
|
449 |
DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
|
450 |
active = false;
|
451 |
} |
452 |
|
453 |
was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK); |
454 |
|
455 |
/*
|
456 |
* We don't have a similar check for already-active because
|
457 |
* ctpr may have changed and we need to withdraw the interrupt.
|
458 |
*/
|
459 |
if (!active && !was_active) {
|
460 |
DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ);
|
461 |
return;
|
462 |
} |
463 |
|
464 |
if (active) {
|
465 |
src->ivpr |= IVPR_ACTIVITY_MASK; |
466 |
} else {
|
467 |
src->ivpr &= ~IVPR_ACTIVITY_MASK; |
468 |
} |
469 |
|
470 |
if (src->destmask == 0) { |
471 |
/* No target */
|
472 |
DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
|
473 |
return;
|
474 |
} |
475 |
|
476 |
if (src->destmask == (1 << src->last_cpu)) { |
477 |
/* Only one CPU is allowed to receive this IRQ */
|
478 |
IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); |
479 |
} else if (!(src->ivpr & IVPR_MODE_MASK)) { |
480 |
/* Directed delivery mode */
|
481 |
for (i = 0; i < opp->nb_cpus; i++) { |
482 |
if (src->destmask & (1 << i)) { |
483 |
IRQ_local_pipe(opp, i, n_IRQ, active, was_active); |
484 |
} |
485 |
} |
486 |
} else {
|
487 |
/* Distributed delivery mode */
|
488 |
for (i = src->last_cpu + 1; i != src->last_cpu; i++) { |
489 |
if (i == opp->nb_cpus) {
|
490 |
i = 0;
|
491 |
} |
492 |
if (src->destmask & (1 << i)) { |
493 |
IRQ_local_pipe(opp, i, n_IRQ, active, was_active); |
494 |
src->last_cpu = i; |
495 |
break;
|
496 |
} |
497 |
} |
498 |
} |
499 |
} |
500 |
|
501 |
static void openpic_set_irq(void *opaque, int n_IRQ, int level) |
502 |
{ |
503 |
OpenPICState *opp = opaque; |
504 |
IRQSource *src; |
505 |
|
506 |
if (n_IRQ >= MAX_IRQ) {
|
507 |
fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ);
|
508 |
abort(); |
509 |
} |
510 |
|
511 |
src = &opp->src[n_IRQ]; |
512 |
DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n",
|
513 |
n_IRQ, level, src->ivpr); |
514 |
if (src->level) {
|
515 |
/* level-sensitive irq */
|
516 |
src->pending = level; |
517 |
openpic_update_irq(opp, n_IRQ); |
518 |
} else {
|
519 |
/* edge-sensitive irq */
|
520 |
if (level) {
|
521 |
src->pending = 1;
|
522 |
openpic_update_irq(opp, n_IRQ); |
523 |
} |
524 |
|
525 |
if (src->output != OPENPIC_OUTPUT_INT) {
|
526 |
/* Edge-triggered interrupts shouldn't be used
|
527 |
* with non-INT delivery, but just in case,
|
528 |
* try to make it do something sane rather than
|
529 |
* cause an interrupt storm. This is close to
|
530 |
* what you'd probably see happen in real hardware.
|
531 |
*/
|
532 |
src->pending = 0;
|
533 |
openpic_update_irq(opp, n_IRQ); |
534 |
} |
535 |
} |
536 |
} |
537 |
|
538 |
static void openpic_reset(DeviceState *d) |
539 |
{ |
540 |
OpenPICState *opp = FROM_SYSBUS(typeof(*opp), SYS_BUS_DEVICE(d)); |
541 |
int i;
|
542 |
|
543 |
opp->gcr = GCR_RESET; |
544 |
/* Initialise controller registers */
|
545 |
opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
|
546 |
((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
|
547 |
(opp->vid << FRR_VID_SHIFT); |
548 |
|
549 |
opp->pir = 0;
|
550 |
opp->spve = -1 & opp->vector_mask;
|
551 |
opp->tfrr = opp->tfrr_reset; |
552 |
/* Initialise IRQ sources */
|
553 |
for (i = 0; i < opp->max_irq; i++) { |
554 |
opp->src[i].ivpr = opp->ivpr_reset; |
555 |
opp->src[i].idr = opp->idr_reset; |
556 |
|
557 |
switch (opp->src[i].type) {
|
558 |
case IRQ_TYPE_NORMAL:
|
559 |
opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK); |
560 |
break;
|
561 |
|
562 |
case IRQ_TYPE_FSLINT:
|
563 |
opp->src[i].ivpr |= IVPR_POLARITY_MASK; |
564 |
break;
|
565 |
|
566 |
case IRQ_TYPE_FSLSPECIAL:
|
567 |
break;
|
568 |
} |
569 |
} |
570 |
/* Initialise IRQ destinations */
|
571 |
for (i = 0; i < MAX_CPU; i++) { |
572 |
opp->dst[i].ctpr = 15;
|
573 |
memset(&opp->dst[i].raised, 0, sizeof(IRQQueue)); |
574 |
opp->dst[i].raised.next = -1;
|
575 |
memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue)); |
576 |
opp->dst[i].servicing.next = -1;
|
577 |
} |
578 |
/* Initialise timers */
|
579 |
for (i = 0; i < MAX_TMR; i++) { |
580 |
opp->timers[i].tccr = 0;
|
581 |
opp->timers[i].tbcr = TBCR_CI; |
582 |
} |
583 |
/* Go out of RESET state */
|
584 |
opp->gcr = 0;
|
585 |
} |
586 |
|
587 |
static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ) |
588 |
{ |
589 |
return opp->src[n_IRQ].idr;
|
590 |
} |
591 |
|
592 |
static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ) |
593 |
{ |
594 |
if (opp->flags & OPENPIC_FLAG_ILR) {
|
595 |
return output_to_inttgt(opp->src[n_IRQ].output);
|
596 |
} |
597 |
|
598 |
return 0xffffffff; |
599 |
} |
600 |
|
601 |
static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ) |
602 |
{ |
603 |
return opp->src[n_IRQ].ivpr;
|
604 |
} |
605 |
|
606 |
static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) |
607 |
{ |
608 |
IRQSource *src = &opp->src[n_IRQ]; |
609 |
uint32_t normal_mask = (1UL << opp->nb_cpus) - 1; |
610 |
uint32_t crit_mask = 0;
|
611 |
uint32_t mask = normal_mask; |
612 |
int crit_shift = IDR_EP_SHIFT - opp->nb_cpus;
|
613 |
int i;
|
614 |
|
615 |
if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
|
616 |
crit_mask = mask << crit_shift; |
617 |
mask |= crit_mask | IDR_EP; |
618 |
} |
619 |
|
620 |
src->idr = val & mask; |
621 |
DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr);
|
622 |
|
623 |
if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
|
624 |
if (src->idr & crit_mask) {
|
625 |
if (src->idr & normal_mask) {
|
626 |
DPRINTF("%s: IRQ configured for multiple output types, using "
|
627 |
"critical\n", __func__);
|
628 |
} |
629 |
|
630 |
src->output = OPENPIC_OUTPUT_CINT; |
631 |
src->nomask = true;
|
632 |
src->destmask = 0;
|
633 |
|
634 |
for (i = 0; i < opp->nb_cpus; i++) { |
635 |
int n_ci = IDR_CI0_SHIFT - i;
|
636 |
|
637 |
if (src->idr & (1UL << n_ci)) { |
638 |
src->destmask |= 1UL << i;
|
639 |
} |
640 |
} |
641 |
} else {
|
642 |
src->output = OPENPIC_OUTPUT_INT; |
643 |
src->nomask = false;
|
644 |
src->destmask = src->idr & normal_mask; |
645 |
} |
646 |
} else {
|
647 |
src->destmask = src->idr; |
648 |
} |
649 |
} |
650 |
|
651 |
static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val) |
652 |
{ |
653 |
if (opp->flags & OPENPIC_FLAG_ILR) {
|
654 |
IRQSource *src = &opp->src[n_IRQ]; |
655 |
|
656 |
src->output = inttgt_to_output(val & ILR_INTTGT_MASK); |
657 |
DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr,
|
658 |
src->output); |
659 |
|
660 |
/* TODO: on MPIC v4.0 only, set nomask for non-INT */
|
661 |
} |
662 |
} |
663 |
|
664 |
static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) |
665 |
{ |
666 |
uint32_t mask; |
667 |
|
668 |
/* NOTE when implementing newer FSL MPIC models: starting with v4.0,
|
669 |
* the polarity bit is read-only on internal interrupts.
|
670 |
*/
|
671 |
mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK | |
672 |
IVPR_POLARITY_MASK | opp->vector_mask; |
673 |
|
674 |
/* ACTIVITY bit is read-only */
|
675 |
opp->src[n_IRQ].ivpr = |
676 |
(opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask); |
677 |
|
678 |
/* For FSL internal interrupts, The sense bit is reserved and zero,
|
679 |
* and the interrupt is always level-triggered. Timers and IPIs
|
680 |
* have no sense or polarity bits, and are edge-triggered.
|
681 |
*/
|
682 |
switch (opp->src[n_IRQ].type) {
|
683 |
case IRQ_TYPE_NORMAL:
|
684 |
opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK); |
685 |
break;
|
686 |
|
687 |
case IRQ_TYPE_FSLINT:
|
688 |
opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK; |
689 |
break;
|
690 |
|
691 |
case IRQ_TYPE_FSLSPECIAL:
|
692 |
opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK); |
693 |
break;
|
694 |
} |
695 |
|
696 |
openpic_update_irq(opp, n_IRQ); |
697 |
DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
|
698 |
opp->src[n_IRQ].ivpr); |
699 |
} |
700 |
|
701 |
static void openpic_gcr_write(OpenPICState *opp, uint64_t val) |
702 |
{ |
703 |
bool mpic_proxy = false; |
704 |
|
705 |
if (val & GCR_RESET) {
|
706 |
openpic_reset(&opp->busdev.qdev); |
707 |
return;
|
708 |
} |
709 |
|
710 |
opp->gcr &= ~opp->mpic_mode_mask; |
711 |
opp->gcr |= val & opp->mpic_mode_mask; |
712 |
|
713 |
/* Set external proxy mode */
|
714 |
if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) {
|
715 |
mpic_proxy = true;
|
716 |
} |
717 |
|
718 |
ppce500_set_mpic_proxy(mpic_proxy); |
719 |
} |
720 |
|
721 |
static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, |
722 |
unsigned len)
|
723 |
{ |
724 |
OpenPICState *opp = opaque; |
725 |
IRQDest *dst; |
726 |
int idx;
|
727 |
|
728 |
DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", |
729 |
__func__, addr, val); |
730 |
if (addr & 0xF) { |
731 |
return;
|
732 |
} |
733 |
switch (addr) {
|
734 |
case 0x00: /* Block Revision Register1 (BRR1) is Readonly */ |
735 |
break;
|
736 |
case 0x40: |
737 |
case 0x50: |
738 |
case 0x60: |
739 |
case 0x70: |
740 |
case 0x80: |
741 |
case 0x90: |
742 |
case 0xA0: |
743 |
case 0xB0: |
744 |
openpic_cpu_write_internal(opp, addr, val, get_current_cpu()); |
745 |
break;
|
746 |
case 0x1000: /* FRR */ |
747 |
break;
|
748 |
case 0x1020: /* GCR */ |
749 |
openpic_gcr_write(opp, val); |
750 |
break;
|
751 |
case 0x1080: /* VIR */ |
752 |
break;
|
753 |
case 0x1090: /* PIR */ |
754 |
for (idx = 0; idx < opp->nb_cpus; idx++) { |
755 |
if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) { |
756 |
DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
|
757 |
dst = &opp->dst[idx]; |
758 |
qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]); |
759 |
} else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) { |
760 |
DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
|
761 |
dst = &opp->dst[idx]; |
762 |
qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]); |
763 |
} |
764 |
} |
765 |
opp->pir = val; |
766 |
break;
|
767 |
case 0x10A0: /* IPI_IVPR */ |
768 |
case 0x10B0: |
769 |
case 0x10C0: |
770 |
case 0x10D0: |
771 |
{ |
772 |
int idx;
|
773 |
idx = (addr - 0x10A0) >> 4; |
774 |
write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val); |
775 |
} |
776 |
break;
|
777 |
case 0x10E0: /* SPVE */ |
778 |
opp->spve = val & opp->vector_mask; |
779 |
break;
|
780 |
default:
|
781 |
break;
|
782 |
} |
783 |
} |
784 |
|
785 |
static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) |
786 |
{ |
787 |
OpenPICState *opp = opaque; |
788 |
uint32_t retval; |
789 |
|
790 |
DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); |
791 |
retval = 0xFFFFFFFF;
|
792 |
if (addr & 0xF) { |
793 |
return retval;
|
794 |
} |
795 |
switch (addr) {
|
796 |
case 0x1000: /* FRR */ |
797 |
retval = opp->frr; |
798 |
break;
|
799 |
case 0x1020: /* GCR */ |
800 |
retval = opp->gcr; |
801 |
break;
|
802 |
case 0x1080: /* VIR */ |
803 |
retval = opp->vir; |
804 |
break;
|
805 |
case 0x1090: /* PIR */ |
806 |
retval = 0x00000000;
|
807 |
break;
|
808 |
case 0x00: /* Block Revision Register1 (BRR1) */ |
809 |
retval = opp->brr1; |
810 |
break;
|
811 |
case 0x40: |
812 |
case 0x50: |
813 |
case 0x60: |
814 |
case 0x70: |
815 |
case 0x80: |
816 |
case 0x90: |
817 |
case 0xA0: |
818 |
case 0xB0: |
819 |
retval = openpic_cpu_read_internal(opp, addr, get_current_cpu()); |
820 |
break;
|
821 |
case 0x10A0: /* IPI_IVPR */ |
822 |
case 0x10B0: |
823 |
case 0x10C0: |
824 |
case 0x10D0: |
825 |
{ |
826 |
int idx;
|
827 |
idx = (addr - 0x10A0) >> 4; |
828 |
retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx); |
829 |
} |
830 |
break;
|
831 |
case 0x10E0: /* SPVE */ |
832 |
retval = opp->spve; |
833 |
break;
|
834 |
default:
|
835 |
break;
|
836 |
} |
837 |
DPRINTF("%s: => 0x%08x\n", __func__, retval);
|
838 |
|
839 |
return retval;
|
840 |
} |
841 |
|
842 |
static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, |
843 |
unsigned len)
|
844 |
{ |
845 |
OpenPICState *opp = opaque; |
846 |
int idx;
|
847 |
|
848 |
addr += 0x10f0;
|
849 |
|
850 |
DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", |
851 |
__func__, addr, val); |
852 |
if (addr & 0xF) { |
853 |
return;
|
854 |
} |
855 |
|
856 |
if (addr == 0x10f0) { |
857 |
/* TFRR */
|
858 |
opp->tfrr = val; |
859 |
return;
|
860 |
} |
861 |
|
862 |
idx = (addr >> 6) & 0x3; |
863 |
addr = addr & 0x30;
|
864 |
|
865 |
switch (addr & 0x30) { |
866 |
case 0x00: /* TCCR */ |
867 |
break;
|
868 |
case 0x10: /* TBCR */ |
869 |
if ((opp->timers[idx].tccr & TCCR_TOG) != 0 && |
870 |
(val & TBCR_CI) == 0 &&
|
871 |
(opp->timers[idx].tbcr & TBCR_CI) != 0) {
|
872 |
opp->timers[idx].tccr &= ~TCCR_TOG; |
873 |
} |
874 |
opp->timers[idx].tbcr = val; |
875 |
break;
|
876 |
case 0x20: /* TVPR */ |
877 |
write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val); |
878 |
break;
|
879 |
case 0x30: /* TDR */ |
880 |
write_IRQreg_idr(opp, opp->irq_tim0 + idx, val); |
881 |
break;
|
882 |
} |
883 |
} |
884 |
|
885 |
static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) |
886 |
{ |
887 |
OpenPICState *opp = opaque; |
888 |
uint32_t retval = -1;
|
889 |
int idx;
|
890 |
|
891 |
DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); |
892 |
if (addr & 0xF) { |
893 |
goto out;
|
894 |
} |
895 |
idx = (addr >> 6) & 0x3; |
896 |
if (addr == 0x0) { |
897 |
/* TFRR */
|
898 |
retval = opp->tfrr; |
899 |
goto out;
|
900 |
} |
901 |
switch (addr & 0x30) { |
902 |
case 0x00: /* TCCR */ |
903 |
retval = opp->timers[idx].tccr; |
904 |
break;
|
905 |
case 0x10: /* TBCR */ |
906 |
retval = opp->timers[idx].tbcr; |
907 |
break;
|
908 |
case 0x20: /* TIPV */ |
909 |
retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx); |
910 |
break;
|
911 |
case 0x30: /* TIDE (TIDR) */ |
912 |
retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx); |
913 |
break;
|
914 |
} |
915 |
|
916 |
out:
|
917 |
DPRINTF("%s: => 0x%08x\n", __func__, retval);
|
918 |
|
919 |
return retval;
|
920 |
} |
921 |
|
922 |
static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, |
923 |
unsigned len)
|
924 |
{ |
925 |
OpenPICState *opp = opaque; |
926 |
int idx;
|
927 |
|
928 |
DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", |
929 |
__func__, addr, val); |
930 |
|
931 |
addr = addr & 0xffff;
|
932 |
idx = addr >> 5;
|
933 |
|
934 |
switch (addr & 0x1f) { |
935 |
case 0x00: |
936 |
write_IRQreg_ivpr(opp, idx, val); |
937 |
break;
|
938 |
case 0x10: |
939 |
write_IRQreg_idr(opp, idx, val); |
940 |
break;
|
941 |
case 0x18: |
942 |
write_IRQreg_ilr(opp, idx, val); |
943 |
break;
|
944 |
} |
945 |
} |
946 |
|
947 |
static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) |
948 |
{ |
949 |
OpenPICState *opp = opaque; |
950 |
uint32_t retval; |
951 |
int idx;
|
952 |
|
953 |
DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); |
954 |
retval = 0xFFFFFFFF;
|
955 |
|
956 |
addr = addr & 0xffff;
|
957 |
idx = addr >> 5;
|
958 |
|
959 |
switch (addr & 0x1f) { |
960 |
case 0x00: |
961 |
retval = read_IRQreg_ivpr(opp, idx); |
962 |
break;
|
963 |
case 0x10: |
964 |
retval = read_IRQreg_idr(opp, idx); |
965 |
break;
|
966 |
case 0x18: |
967 |
retval = read_IRQreg_ilr(opp, idx); |
968 |
break;
|
969 |
} |
970 |
|
971 |
DPRINTF("%s: => 0x%08x\n", __func__, retval);
|
972 |
return retval;
|
973 |
} |
974 |
|
975 |
static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val, |
976 |
unsigned size)
|
977 |
{ |
978 |
OpenPICState *opp = opaque; |
979 |
int idx = opp->irq_msi;
|
980 |
int srs, ibs;
|
981 |
|
982 |
DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", |
983 |
__func__, addr, val); |
984 |
if (addr & 0xF) { |
985 |
return;
|
986 |
} |
987 |
|
988 |
switch (addr) {
|
989 |
case MSIIR_OFFSET:
|
990 |
srs = val >> MSIIR_SRS_SHIFT; |
991 |
idx += srs; |
992 |
ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT; |
993 |
opp->msi[srs].msir |= 1 << ibs;
|
994 |
openpic_set_irq(opp, idx, 1);
|
995 |
break;
|
996 |
default:
|
997 |
/* most registers are read-only, thus ignored */
|
998 |
break;
|
999 |
} |
1000 |
} |
1001 |
|
1002 |
static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) |
1003 |
{ |
1004 |
OpenPICState *opp = opaque; |
1005 |
uint64_t r = 0;
|
1006 |
int i, srs;
|
1007 |
|
1008 |
DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); |
1009 |
if (addr & 0xF) { |
1010 |
return -1; |
1011 |
} |
1012 |
|
1013 |
srs = addr >> 4;
|
1014 |
|
1015 |
switch (addr) {
|
1016 |
case 0x00: |
1017 |
case 0x10: |
1018 |
case 0x20: |
1019 |
case 0x30: |
1020 |
case 0x40: |
1021 |
case 0x50: |
1022 |
case 0x60: |
1023 |
case 0x70: /* MSIRs */ |
1024 |
r = opp->msi[srs].msir; |
1025 |
/* Clear on read */
|
1026 |
opp->msi[srs].msir = 0;
|
1027 |
openpic_set_irq(opp, opp->irq_msi + srs, 0);
|
1028 |
break;
|
1029 |
case 0x120: /* MSISR */ |
1030 |
for (i = 0; i < MAX_MSI; i++) { |
1031 |
r |= (opp->msi[i].msir ? 1 : 0) << i; |
1032 |
} |
1033 |
break;
|
1034 |
} |
1035 |
|
1036 |
return r;
|
1037 |
} |
1038 |
|
1039 |
static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size) |
1040 |
{ |
1041 |
uint64_t r = 0;
|
1042 |
|
1043 |
DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); |
1044 |
|
1045 |
/* TODO: EISR/EIMR */
|
1046 |
|
1047 |
return r;
|
1048 |
} |
1049 |
|
1050 |
static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val, |
1051 |
unsigned size)
|
1052 |
{ |
1053 |
DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", |
1054 |
__func__, addr, val); |
1055 |
|
1056 |
/* TODO: EISR/EIMR */
|
1057 |
} |
1058 |
|
1059 |
static void openpic_cpu_write_internal(void *opaque, hwaddr addr, |
1060 |
uint32_t val, int idx)
|
1061 |
{ |
1062 |
OpenPICState *opp = opaque; |
1063 |
IRQSource *src; |
1064 |
IRQDest *dst; |
1065 |
int s_IRQ, n_IRQ;
|
1066 |
|
1067 |
DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx, |
1068 |
addr, val); |
1069 |
|
1070 |
if (idx < 0) { |
1071 |
return;
|
1072 |
} |
1073 |
|
1074 |
if (addr & 0xF) { |
1075 |
return;
|
1076 |
} |
1077 |
dst = &opp->dst[idx]; |
1078 |
addr &= 0xFF0;
|
1079 |
switch (addr) {
|
1080 |
case 0x40: /* IPIDR */ |
1081 |
case 0x50: |
1082 |
case 0x60: |
1083 |
case 0x70: |
1084 |
idx = (addr - 0x40) >> 4; |
1085 |
/* we use IDE as mask which CPUs to deliver the IPI to still. */
|
1086 |
opp->src[opp->irq_ipi0 + idx].destmask |= val; |
1087 |
openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
|
1088 |
openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
|
1089 |
break;
|
1090 |
case 0x80: /* CTPR */ |
1091 |
dst->ctpr = val & 0x0000000F;
|
1092 |
|
1093 |
DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n",
|
1094 |
__func__, idx, dst->ctpr, dst->raised.priority, |
1095 |
dst->servicing.priority); |
1096 |
|
1097 |
if (dst->raised.priority <= dst->ctpr) {
|
1098 |
DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n",
|
1099 |
__func__, idx); |
1100 |
qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); |
1101 |
} else if (dst->raised.priority > dst->servicing.priority) { |
1102 |
DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n",
|
1103 |
__func__, idx, dst->raised.next); |
1104 |
qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); |
1105 |
} |
1106 |
|
1107 |
break;
|
1108 |
case 0x90: /* WHOAMI */ |
1109 |
/* Read-only register */
|
1110 |
break;
|
1111 |
case 0xA0: /* IACK */ |
1112 |
/* Read-only register */
|
1113 |
break;
|
1114 |
case 0xB0: /* EOI */ |
1115 |
DPRINTF("EOI\n");
|
1116 |
s_IRQ = IRQ_get_next(opp, &dst->servicing); |
1117 |
|
1118 |
if (s_IRQ < 0) { |
1119 |
DPRINTF("%s: EOI with no interrupt in service\n", __func__);
|
1120 |
break;
|
1121 |
} |
1122 |
|
1123 |
IRQ_resetbit(&dst->servicing, s_IRQ); |
1124 |
/* Set up next servicing IRQ */
|
1125 |
s_IRQ = IRQ_get_next(opp, &dst->servicing); |
1126 |
/* Check queued interrupts. */
|
1127 |
n_IRQ = IRQ_get_next(opp, &dst->raised); |
1128 |
src = &opp->src[n_IRQ]; |
1129 |
if (n_IRQ != -1 && |
1130 |
(s_IRQ == -1 ||
|
1131 |
IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { |
1132 |
DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
|
1133 |
idx, n_IRQ); |
1134 |
qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]); |
1135 |
} |
1136 |
break;
|
1137 |
default:
|
1138 |
break;
|
1139 |
} |
1140 |
} |
1141 |
|
1142 |
static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val, |
1143 |
unsigned len)
|
1144 |
{ |
1145 |
openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12); |
1146 |
} |
1147 |
|
1148 |
|
1149 |
static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) |
1150 |
{ |
1151 |
IRQSource *src; |
1152 |
int retval, irq;
|
1153 |
|
1154 |
DPRINTF("Lower OpenPIC INT output\n");
|
1155 |
qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); |
1156 |
|
1157 |
irq = IRQ_get_next(opp, &dst->raised); |
1158 |
DPRINTF("IACK: irq=%d\n", irq);
|
1159 |
|
1160 |
if (irq == -1) { |
1161 |
/* No more interrupt pending */
|
1162 |
return opp->spve;
|
1163 |
} |
1164 |
|
1165 |
src = &opp->src[irq]; |
1166 |
if (!(src->ivpr & IVPR_ACTIVITY_MASK) ||
|
1167 |
!(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { |
1168 |
fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n",
|
1169 |
__func__, irq, dst->ctpr, src->ivpr); |
1170 |
openpic_update_irq(opp, irq); |
1171 |
retval = opp->spve; |
1172 |
} else {
|
1173 |
/* IRQ enter servicing state */
|
1174 |
IRQ_setbit(&dst->servicing, irq); |
1175 |
retval = IVPR_VECTOR(opp, src->ivpr); |
1176 |
} |
1177 |
|
1178 |
if (!src->level) {
|
1179 |
/* edge-sensitive IRQ */
|
1180 |
src->ivpr &= ~IVPR_ACTIVITY_MASK; |
1181 |
src->pending = 0;
|
1182 |
IRQ_resetbit(&dst->raised, irq); |
1183 |
} |
1184 |
|
1185 |
if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) {
|
1186 |
src->destmask &= ~(1 << cpu);
|
1187 |
if (src->destmask && !src->level) {
|
1188 |
/* trigger on CPUs that didn't know about it yet */
|
1189 |
openpic_set_irq(opp, irq, 1);
|
1190 |
openpic_set_irq(opp, irq, 0);
|
1191 |
/* if all CPUs knew about it, set active bit again */
|
1192 |
src->ivpr |= IVPR_ACTIVITY_MASK; |
1193 |
} |
1194 |
} |
1195 |
|
1196 |
return retval;
|
1197 |
} |
1198 |
|
1199 |
static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, |
1200 |
int idx)
|
1201 |
{ |
1202 |
OpenPICState *opp = opaque; |
1203 |
IRQDest *dst; |
1204 |
uint32_t retval; |
1205 |
|
1206 |
DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr); |
1207 |
retval = 0xFFFFFFFF;
|
1208 |
|
1209 |
if (idx < 0) { |
1210 |
return retval;
|
1211 |
} |
1212 |
|
1213 |
if (addr & 0xF) { |
1214 |
return retval;
|
1215 |
} |
1216 |
dst = &opp->dst[idx]; |
1217 |
addr &= 0xFF0;
|
1218 |
switch (addr) {
|
1219 |
case 0x80: /* CTPR */ |
1220 |
retval = dst->ctpr; |
1221 |
break;
|
1222 |
case 0x90: /* WHOAMI */ |
1223 |
retval = idx; |
1224 |
break;
|
1225 |
case 0xA0: /* IACK */ |
1226 |
retval = openpic_iack(opp, dst, idx); |
1227 |
break;
|
1228 |
case 0xB0: /* EOI */ |
1229 |
retval = 0;
|
1230 |
break;
|
1231 |
default:
|
1232 |
break;
|
1233 |
} |
1234 |
DPRINTF("%s: => 0x%08x\n", __func__, retval);
|
1235 |
|
1236 |
return retval;
|
1237 |
} |
1238 |
|
1239 |
static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len) |
1240 |
{ |
1241 |
return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12); |
1242 |
} |
1243 |
|
1244 |
static const MemoryRegionOps openpic_glb_ops_le = { |
1245 |
.write = openpic_gbl_write, |
1246 |
.read = openpic_gbl_read, |
1247 |
.endianness = DEVICE_LITTLE_ENDIAN, |
1248 |
.impl = { |
1249 |
.min_access_size = 4,
|
1250 |
.max_access_size = 4,
|
1251 |
}, |
1252 |
}; |
1253 |
|
1254 |
static const MemoryRegionOps openpic_glb_ops_be = { |
1255 |
.write = openpic_gbl_write, |
1256 |
.read = openpic_gbl_read, |
1257 |
.endianness = DEVICE_BIG_ENDIAN, |
1258 |
.impl = { |
1259 |
.min_access_size = 4,
|
1260 |
.max_access_size = 4,
|
1261 |
}, |
1262 |
}; |
1263 |
|
1264 |
static const MemoryRegionOps openpic_tmr_ops_le = { |
1265 |
.write = openpic_tmr_write, |
1266 |
.read = openpic_tmr_read, |
1267 |
.endianness = DEVICE_LITTLE_ENDIAN, |
1268 |
.impl = { |
1269 |
.min_access_size = 4,
|
1270 |
.max_access_size = 4,
|
1271 |
}, |
1272 |
}; |
1273 |
|
1274 |
static const MemoryRegionOps openpic_tmr_ops_be = { |
1275 |
.write = openpic_tmr_write, |
1276 |
.read = openpic_tmr_read, |
1277 |
.endianness = DEVICE_BIG_ENDIAN, |
1278 |
.impl = { |
1279 |
.min_access_size = 4,
|
1280 |
.max_access_size = 4,
|
1281 |
}, |
1282 |
}; |
1283 |
|
1284 |
static const MemoryRegionOps openpic_cpu_ops_le = { |
1285 |
.write = openpic_cpu_write, |
1286 |
.read = openpic_cpu_read, |
1287 |
.endianness = DEVICE_LITTLE_ENDIAN, |
1288 |
.impl = { |
1289 |
.min_access_size = 4,
|
1290 |
.max_access_size = 4,
|
1291 |
}, |
1292 |
}; |
1293 |
|
1294 |
static const MemoryRegionOps openpic_cpu_ops_be = { |
1295 |
.write = openpic_cpu_write, |
1296 |
.read = openpic_cpu_read, |
1297 |
.endianness = DEVICE_BIG_ENDIAN, |
1298 |
.impl = { |
1299 |
.min_access_size = 4,
|
1300 |
.max_access_size = 4,
|
1301 |
}, |
1302 |
}; |
1303 |
|
1304 |
static const MemoryRegionOps openpic_src_ops_le = { |
1305 |
.write = openpic_src_write, |
1306 |
.read = openpic_src_read, |
1307 |
.endianness = DEVICE_LITTLE_ENDIAN, |
1308 |
.impl = { |
1309 |
.min_access_size = 4,
|
1310 |
.max_access_size = 4,
|
1311 |
}, |
1312 |
}; |
1313 |
|
1314 |
static const MemoryRegionOps openpic_src_ops_be = { |
1315 |
.write = openpic_src_write, |
1316 |
.read = openpic_src_read, |
1317 |
.endianness = DEVICE_BIG_ENDIAN, |
1318 |
.impl = { |
1319 |
.min_access_size = 4,
|
1320 |
.max_access_size = 4,
|
1321 |
}, |
1322 |
}; |
1323 |
|
1324 |
static const MemoryRegionOps openpic_msi_ops_be = { |
1325 |
.read = openpic_msi_read, |
1326 |
.write = openpic_msi_write, |
1327 |
.endianness = DEVICE_BIG_ENDIAN, |
1328 |
.impl = { |
1329 |
.min_access_size = 4,
|
1330 |
.max_access_size = 4,
|
1331 |
}, |
1332 |
}; |
1333 |
|
1334 |
static const MemoryRegionOps openpic_summary_ops_be = { |
1335 |
.read = openpic_summary_read, |
1336 |
.write = openpic_summary_write, |
1337 |
.endianness = DEVICE_BIG_ENDIAN, |
1338 |
.impl = { |
1339 |
.min_access_size = 4,
|
1340 |
.max_access_size = 4,
|
1341 |
}, |
1342 |
}; |
1343 |
|
1344 |
static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q) |
1345 |
{ |
1346 |
unsigned int i; |
1347 |
|
1348 |
for (i = 0; i < ARRAY_SIZE(q->queue); i++) { |
1349 |
/* Always put the lower half of a 64-bit long first, in case we
|
1350 |
* restore on a 32-bit host. The least significant bits correspond
|
1351 |
* to lower IRQ numbers in the bitmap.
|
1352 |
*/
|
1353 |
qemu_put_be32(f, (uint32_t)q->queue[i]); |
1354 |
#if LONG_MAX > 0x7FFFFFFF |
1355 |
qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32));
|
1356 |
#endif
|
1357 |
} |
1358 |
|
1359 |
qemu_put_sbe32s(f, &q->next); |
1360 |
qemu_put_sbe32s(f, &q->priority); |
1361 |
} |
1362 |
|
1363 |
static void openpic_save(QEMUFile* f, void *opaque) |
1364 |
{ |
1365 |
OpenPICState *opp = (OpenPICState *)opaque; |
1366 |
unsigned int i; |
1367 |
|
1368 |
qemu_put_be32s(f, &opp->gcr); |
1369 |
qemu_put_be32s(f, &opp->vir); |
1370 |
qemu_put_be32s(f, &opp->pir); |
1371 |
qemu_put_be32s(f, &opp->spve); |
1372 |
qemu_put_be32s(f, &opp->tfrr); |
1373 |
|
1374 |
qemu_put_be32s(f, &opp->nb_cpus); |
1375 |
|
1376 |
for (i = 0; i < opp->nb_cpus; i++) { |
1377 |
qemu_put_sbe32s(f, &opp->dst[i].ctpr); |
1378 |
openpic_save_IRQ_queue(f, &opp->dst[i].raised); |
1379 |
openpic_save_IRQ_queue(f, &opp->dst[i].servicing); |
1380 |
qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active, |
1381 |
sizeof(opp->dst[i].outputs_active));
|
1382 |
} |
1383 |
|
1384 |
for (i = 0; i < MAX_TMR; i++) { |
1385 |
qemu_put_be32s(f, &opp->timers[i].tccr); |
1386 |
qemu_put_be32s(f, &opp->timers[i].tbcr); |
1387 |
} |
1388 |
|
1389 |
for (i = 0; i < opp->max_irq; i++) { |
1390 |
qemu_put_be32s(f, &opp->src[i].ivpr); |
1391 |
qemu_put_be32s(f, &opp->src[i].idr); |
1392 |
qemu_get_be32s(f, &opp->src[i].destmask); |
1393 |
qemu_put_sbe32s(f, &opp->src[i].last_cpu); |
1394 |
qemu_put_sbe32s(f, &opp->src[i].pending); |
1395 |
} |
1396 |
} |
1397 |
|
1398 |
static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) |
1399 |
{ |
1400 |
unsigned int i; |
1401 |
|
1402 |
for (i = 0; i < ARRAY_SIZE(q->queue); i++) { |
1403 |
unsigned long val; |
1404 |
|
1405 |
val = qemu_get_be32(f); |
1406 |
#if LONG_MAX > 0x7FFFFFFF |
1407 |
val <<= 32;
|
1408 |
val |= qemu_get_be32(f); |
1409 |
#endif
|
1410 |
|
1411 |
q->queue[i] = val; |
1412 |
} |
1413 |
|
1414 |
qemu_get_sbe32s(f, &q->next); |
1415 |
qemu_get_sbe32s(f, &q->priority); |
1416 |
} |
1417 |
|
1418 |
static int openpic_load(QEMUFile* f, void *opaque, int version_id) |
1419 |
{ |
1420 |
OpenPICState *opp = (OpenPICState *)opaque; |
1421 |
unsigned int i; |
1422 |
|
1423 |
if (version_id != 1) { |
1424 |
return -EINVAL;
|
1425 |
} |
1426 |
|
1427 |
qemu_get_be32s(f, &opp->gcr); |
1428 |
qemu_get_be32s(f, &opp->vir); |
1429 |
qemu_get_be32s(f, &opp->pir); |
1430 |
qemu_get_be32s(f, &opp->spve); |
1431 |
qemu_get_be32s(f, &opp->tfrr); |
1432 |
|
1433 |
qemu_get_be32s(f, &opp->nb_cpus); |
1434 |
|
1435 |
for (i = 0; i < opp->nb_cpus; i++) { |
1436 |
qemu_get_sbe32s(f, &opp->dst[i].ctpr); |
1437 |
openpic_load_IRQ_queue(f, &opp->dst[i].raised); |
1438 |
openpic_load_IRQ_queue(f, &opp->dst[i].servicing); |
1439 |
qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active, |
1440 |
sizeof(opp->dst[i].outputs_active));
|
1441 |
} |
1442 |
|
1443 |
for (i = 0; i < MAX_TMR; i++) { |
1444 |
qemu_get_be32s(f, &opp->timers[i].tccr); |
1445 |
qemu_get_be32s(f, &opp->timers[i].tbcr); |
1446 |
} |
1447 |
|
1448 |
for (i = 0; i < opp->max_irq; i++) { |
1449 |
uint32_t val; |
1450 |
|
1451 |
val = qemu_get_be32(f); |
1452 |
write_IRQreg_idr(opp, i, val); |
1453 |
val = qemu_get_be32(f); |
1454 |
write_IRQreg_ivpr(opp, i, val); |
1455 |
|
1456 |
qemu_get_be32s(f, &opp->src[i].ivpr); |
1457 |
qemu_get_be32s(f, &opp->src[i].idr); |
1458 |
qemu_get_be32s(f, &opp->src[i].destmask); |
1459 |
qemu_get_sbe32s(f, &opp->src[i].last_cpu); |
1460 |
qemu_get_sbe32s(f, &opp->src[i].pending); |
1461 |
} |
1462 |
|
1463 |
return 0; |
1464 |
} |
1465 |
|
1466 |
typedef struct MemReg { |
1467 |
const char *name; |
1468 |
MemoryRegionOps const *ops;
|
1469 |
hwaddr start_addr; |
1470 |
ram_addr_t size; |
1471 |
} MemReg; |
1472 |
|
1473 |
static void fsl_common_init(OpenPICState *opp) |
1474 |
{ |
1475 |
int i;
|
1476 |
int virq = MAX_SRC;
|
1477 |
|
1478 |
opp->vid = VID_REVISION_1_2; |
1479 |
opp->vir = VIR_GENERIC; |
1480 |
opp->vector_mask = 0xFFFF;
|
1481 |
opp->tfrr_reset = 0;
|
1482 |
opp->ivpr_reset = IVPR_MASK_MASK; |
1483 |
opp->idr_reset = 1 << 0; |
1484 |
opp->max_irq = MAX_IRQ; |
1485 |
|
1486 |
opp->irq_ipi0 = virq; |
1487 |
virq += MAX_IPI; |
1488 |
opp->irq_tim0 = virq; |
1489 |
virq += MAX_TMR; |
1490 |
|
1491 |
assert(virq <= MAX_IRQ); |
1492 |
|
1493 |
opp->irq_msi = 224;
|
1494 |
|
1495 |
msi_supported = true;
|
1496 |
for (i = 0; i < opp->fsl->max_ext; i++) { |
1497 |
opp->src[i].level = false;
|
1498 |
} |
1499 |
|
1500 |
/* Internal interrupts, including message and MSI */
|
1501 |
for (i = 16; i < MAX_SRC; i++) { |
1502 |
opp->src[i].type = IRQ_TYPE_FSLINT; |
1503 |
opp->src[i].level = true;
|
1504 |
} |
1505 |
|
1506 |
/* timers and IPIs */
|
1507 |
for (i = MAX_SRC; i < virq; i++) {
|
1508 |
opp->src[i].type = IRQ_TYPE_FSLSPECIAL; |
1509 |
opp->src[i].level = false;
|
1510 |
} |
1511 |
} |
1512 |
|
1513 |
static void map_list(OpenPICState *opp, const MemReg *list, int *count) |
1514 |
{ |
1515 |
while (list->name) {
|
1516 |
assert(*count < ARRAY_SIZE(opp->sub_io_mem)); |
1517 |
|
1518 |
memory_region_init_io(&opp->sub_io_mem[*count], list->ops, opp, |
1519 |
list->name, list->size); |
1520 |
|
1521 |
memory_region_add_subregion(&opp->mem, list->start_addr, |
1522 |
&opp->sub_io_mem[*count]); |
1523 |
|
1524 |
(*count)++; |
1525 |
list++; |
1526 |
} |
1527 |
} |
1528 |
|
1529 |
static int openpic_init(SysBusDevice *dev) |
1530 |
{ |
1531 |
OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev); |
1532 |
int i, j;
|
1533 |
int list_count = 0; |
1534 |
static const MemReg list_le[] = { |
1535 |
{"glb", &openpic_glb_ops_le,
|
1536 |
OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, |
1537 |
{"tmr", &openpic_tmr_ops_le,
|
1538 |
OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, |
1539 |
{"src", &openpic_src_ops_le,
|
1540 |
OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, |
1541 |
{"cpu", &openpic_cpu_ops_le,
|
1542 |
OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, |
1543 |
{NULL}
|
1544 |
}; |
1545 |
static const MemReg list_be[] = { |
1546 |
{"glb", &openpic_glb_ops_be,
|
1547 |
OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, |
1548 |
{"tmr", &openpic_tmr_ops_be,
|
1549 |
OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, |
1550 |
{"src", &openpic_src_ops_be,
|
1551 |
OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, |
1552 |
{"cpu", &openpic_cpu_ops_be,
|
1553 |
OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, |
1554 |
{NULL}
|
1555 |
}; |
1556 |
static const MemReg list_fsl[] = { |
1557 |
{"msi", &openpic_msi_ops_be,
|
1558 |
OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, |
1559 |
{"summary", &openpic_summary_ops_be,
|
1560 |
OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE}, |
1561 |
{NULL}
|
1562 |
}; |
1563 |
|
1564 |
memory_region_init(&opp->mem, "openpic", 0x40000); |
1565 |
|
1566 |
switch (opp->model) {
|
1567 |
case OPENPIC_MODEL_FSL_MPIC_20:
|
1568 |
default:
|
1569 |
opp->fsl = &fsl_mpic_20; |
1570 |
opp->brr1 = 0x00400200;
|
1571 |
opp->flags |= OPENPIC_FLAG_IDR_CRIT; |
1572 |
opp->nb_irqs = 80;
|
1573 |
opp->mpic_mode_mask = GCR_MODE_MIXED; |
1574 |
|
1575 |
fsl_common_init(opp); |
1576 |
map_list(opp, list_be, &list_count); |
1577 |
map_list(opp, list_fsl, &list_count); |
1578 |
|
1579 |
break;
|
1580 |
|
1581 |
case OPENPIC_MODEL_FSL_MPIC_42:
|
1582 |
opp->fsl = &fsl_mpic_42; |
1583 |
opp->brr1 = 0x00400402;
|
1584 |
opp->flags |= OPENPIC_FLAG_ILR; |
1585 |
opp->nb_irqs = 196;
|
1586 |
opp->mpic_mode_mask = GCR_MODE_PROXY; |
1587 |
|
1588 |
fsl_common_init(opp); |
1589 |
map_list(opp, list_be, &list_count); |
1590 |
map_list(opp, list_fsl, &list_count); |
1591 |
|
1592 |
break;
|
1593 |
|
1594 |
case OPENPIC_MODEL_RAVEN:
|
1595 |
opp->nb_irqs = RAVEN_MAX_EXT; |
1596 |
opp->vid = VID_REVISION_1_3; |
1597 |
opp->vir = VIR_GENERIC; |
1598 |
opp->vector_mask = 0xFF;
|
1599 |
opp->tfrr_reset = 4160000;
|
1600 |
opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK; |
1601 |
opp->idr_reset = 0;
|
1602 |
opp->max_irq = RAVEN_MAX_IRQ; |
1603 |
opp->irq_ipi0 = RAVEN_IPI_IRQ; |
1604 |
opp->irq_tim0 = RAVEN_TMR_IRQ; |
1605 |
opp->brr1 = -1;
|
1606 |
opp->mpic_mode_mask = GCR_MODE_MIXED; |
1607 |
|
1608 |
/* Only UP supported today */
|
1609 |
if (opp->nb_cpus != 1) { |
1610 |
return -EINVAL;
|
1611 |
} |
1612 |
|
1613 |
map_list(opp, list_le, &list_count); |
1614 |
break;
|
1615 |
} |
1616 |
|
1617 |
for (i = 0; i < opp->nb_cpus; i++) { |
1618 |
opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB); |
1619 |
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { |
1620 |
sysbus_init_irq(dev, &opp->dst[i].irqs[j]); |
1621 |
} |
1622 |
} |
1623 |
|
1624 |
register_savevm(&opp->busdev.qdev, "openpic", 0, 2, |
1625 |
openpic_save, openpic_load, opp); |
1626 |
|
1627 |
sysbus_init_mmio(dev, &opp->mem); |
1628 |
qdev_init_gpio_in(&dev->qdev, openpic_set_irq, opp->max_irq); |
1629 |
|
1630 |
return 0; |
1631 |
} |
1632 |
|
1633 |
static Property openpic_properties[] = {
|
1634 |
DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20),
|
1635 |
DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1), |
1636 |
DEFINE_PROP_END_OF_LIST(), |
1637 |
}; |
1638 |
|
1639 |
static void openpic_class_init(ObjectClass *klass, void *data) |
1640 |
{ |
1641 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1642 |
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
1643 |
|
1644 |
k->init = openpic_init; |
1645 |
dc->props = openpic_properties; |
1646 |
dc->reset = openpic_reset; |
1647 |
} |
1648 |
|
1649 |
static const TypeInfo openpic_info = { |
1650 |
.name = "openpic",
|
1651 |
.parent = TYPE_SYS_BUS_DEVICE, |
1652 |
.instance_size = sizeof(OpenPICState),
|
1653 |
.class_init = openpic_class_init, |
1654 |
}; |
1655 |
|
1656 |
static void openpic_register_types(void) |
1657 |
{ |
1658 |
type_register_static(&openpic_info); |
1659 |
} |
1660 |
|
1661 |
type_init(openpic_register_types) |