root / hw / alpha / typhoon.c @ 056e6bae
History | View | Annotate | Download (23.2 kB)
1 |
/*
|
---|---|
2 |
* DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
|
3 |
*
|
4 |
* Written by Richard Henderson.
|
5 |
*
|
6 |
* This work is licensed under the GNU GPL license version 2 or later.
|
7 |
*/
|
8 |
|
9 |
#include "cpu.h" |
10 |
#include "hw/hw.h" |
11 |
#include "hw/devices.h" |
12 |
#include "sysemu/sysemu.h" |
13 |
#include "alpha_sys.h" |
14 |
#include "exec/address-spaces.h" |
15 |
|
16 |
|
17 |
#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost" |
18 |
|
19 |
typedef struct TyphoonCchip { |
20 |
MemoryRegion region; |
21 |
uint64_t misc; |
22 |
uint64_t drir; |
23 |
uint64_t dim[4];
|
24 |
uint32_t iic[4];
|
25 |
AlphaCPU *cpu[4];
|
26 |
} TyphoonCchip; |
27 |
|
28 |
typedef struct TyphoonWindow { |
29 |
uint32_t base_addr; |
30 |
uint32_t mask; |
31 |
uint32_t translated_base_pfn; |
32 |
} TyphoonWindow; |
33 |
|
34 |
typedef struct TyphoonPchip { |
35 |
MemoryRegion region; |
36 |
MemoryRegion reg_iack; |
37 |
MemoryRegion reg_mem; |
38 |
MemoryRegion reg_io; |
39 |
MemoryRegion reg_conf; |
40 |
uint64_t ctl; |
41 |
TyphoonWindow win[4];
|
42 |
} TyphoonPchip; |
43 |
|
44 |
#define TYPHOON_PCI_HOST_BRIDGE(obj) \
|
45 |
OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE) |
46 |
|
47 |
typedef struct TyphoonState { |
48 |
PCIHostState parent_obj; |
49 |
|
50 |
TyphoonCchip cchip; |
51 |
TyphoonPchip pchip; |
52 |
MemoryRegion dchip_region; |
53 |
MemoryRegion ram_region; |
54 |
|
55 |
/* QEMU emulation state. */
|
56 |
uint32_t latch_tmp; |
57 |
} TyphoonState; |
58 |
|
59 |
/* Called when one of DRIR or DIM changes. */
|
60 |
static void cpu_irq_change(AlphaCPU *cpu, uint64_t req) |
61 |
{ |
62 |
/* If there are any non-masked interrupts, tell the cpu. */
|
63 |
if (cpu != NULL) { |
64 |
CPUState *cs = CPU(cpu); |
65 |
if (req) {
|
66 |
cpu_interrupt(cs, CPU_INTERRUPT_HARD); |
67 |
} else {
|
68 |
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); |
69 |
} |
70 |
} |
71 |
} |
72 |
|
73 |
static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) |
74 |
{ |
75 |
CPUState *cpu = current_cpu; |
76 |
TyphoonState *s = opaque; |
77 |
uint64_t ret = 0;
|
78 |
|
79 |
if (addr & 4) { |
80 |
return s->latch_tmp;
|
81 |
} |
82 |
|
83 |
switch (addr) {
|
84 |
case 0x0000: |
85 |
/* CSC: Cchip System Configuration Register. */
|
86 |
/* All sorts of data here; probably the only thing relevant is
|
87 |
PIP<14> Pchip 1 Present = 0. */
|
88 |
break;
|
89 |
|
90 |
case 0x0040: |
91 |
/* MTR: Memory Timing Register. */
|
92 |
/* All sorts of stuff related to real DRAM. */
|
93 |
break;
|
94 |
|
95 |
case 0x0080: |
96 |
/* MISC: Miscellaneous Register. */
|
97 |
ret = s->cchip.misc | (cpu->cpu_index & 3);
|
98 |
break;
|
99 |
|
100 |
case 0x00c0: |
101 |
/* MPD: Memory Presence Detect Register. */
|
102 |
break;
|
103 |
|
104 |
case 0x0100: /* AAR0 */ |
105 |
case 0x0140: /* AAR1 */ |
106 |
case 0x0180: /* AAR2 */ |
107 |
case 0x01c0: /* AAR3 */ |
108 |
/* AAR: Array Address Register. */
|
109 |
/* All sorts of information about DRAM. */
|
110 |
break;
|
111 |
|
112 |
case 0x0200: |
113 |
/* DIM0: Device Interrupt Mask Register, CPU0. */
|
114 |
ret = s->cchip.dim[0];
|
115 |
break;
|
116 |
case 0x0240: |
117 |
/* DIM1: Device Interrupt Mask Register, CPU1. */
|
118 |
ret = s->cchip.dim[1];
|
119 |
break;
|
120 |
case 0x0280: |
121 |
/* DIR0: Device Interrupt Request Register, CPU0. */
|
122 |
ret = s->cchip.dim[0] & s->cchip.drir;
|
123 |
break;
|
124 |
case 0x02c0: |
125 |
/* DIR1: Device Interrupt Request Register, CPU1. */
|
126 |
ret = s->cchip.dim[1] & s->cchip.drir;
|
127 |
break;
|
128 |
case 0x0300: |
129 |
/* DRIR: Device Raw Interrupt Request Register. */
|
130 |
ret = s->cchip.drir; |
131 |
break;
|
132 |
|
133 |
case 0x0340: |
134 |
/* PRBEN: Probe Enable Register. */
|
135 |
break;
|
136 |
|
137 |
case 0x0380: |
138 |
/* IIC0: Interval Ignore Count Register, CPU0. */
|
139 |
ret = s->cchip.iic[0];
|
140 |
break;
|
141 |
case 0x03c0: |
142 |
/* IIC1: Interval Ignore Count Register, CPU1. */
|
143 |
ret = s->cchip.iic[1];
|
144 |
break;
|
145 |
|
146 |
case 0x0400: /* MPR0 */ |
147 |
case 0x0440: /* MPR1 */ |
148 |
case 0x0480: /* MPR2 */ |
149 |
case 0x04c0: /* MPR3 */ |
150 |
/* MPR: Memory Programming Register. */
|
151 |
break;
|
152 |
|
153 |
case 0x0580: |
154 |
/* TTR: TIGbus Timing Register. */
|
155 |
/* All sorts of stuff related to interrupt delivery timings. */
|
156 |
break;
|
157 |
case 0x05c0: |
158 |
/* TDR: TIGbug Device Timing Register. */
|
159 |
break;
|
160 |
|
161 |
case 0x0600: |
162 |
/* DIM2: Device Interrupt Mask Register, CPU2. */
|
163 |
ret = s->cchip.dim[2];
|
164 |
break;
|
165 |
case 0x0640: |
166 |
/* DIM3: Device Interrupt Mask Register, CPU3. */
|
167 |
ret = s->cchip.dim[3];
|
168 |
break;
|
169 |
case 0x0680: |
170 |
/* DIR2: Device Interrupt Request Register, CPU2. */
|
171 |
ret = s->cchip.dim[2] & s->cchip.drir;
|
172 |
break;
|
173 |
case 0x06c0: |
174 |
/* DIR3: Device Interrupt Request Register, CPU3. */
|
175 |
ret = s->cchip.dim[3] & s->cchip.drir;
|
176 |
break;
|
177 |
|
178 |
case 0x0700: |
179 |
/* IIC2: Interval Ignore Count Register, CPU2. */
|
180 |
ret = s->cchip.iic[2];
|
181 |
break;
|
182 |
case 0x0740: |
183 |
/* IIC3: Interval Ignore Count Register, CPU3. */
|
184 |
ret = s->cchip.iic[3];
|
185 |
break;
|
186 |
|
187 |
case 0x0780: |
188 |
/* PWR: Power Management Control. */
|
189 |
break;
|
190 |
|
191 |
case 0x0c00: /* CMONCTLA */ |
192 |
case 0x0c40: /* CMONCTLB */ |
193 |
case 0x0c80: /* CMONCNT01 */ |
194 |
case 0x0cc0: /* CMONCNT23 */ |
195 |
break;
|
196 |
|
197 |
default:
|
198 |
cpu_unassigned_access(cpu, addr, false, false, 0, size); |
199 |
return -1; |
200 |
} |
201 |
|
202 |
s->latch_tmp = ret >> 32;
|
203 |
return ret;
|
204 |
} |
205 |
|
206 |
static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size) |
207 |
{ |
208 |
/* Skip this. It's all related to DRAM timing and setup. */
|
209 |
return 0; |
210 |
} |
211 |
|
212 |
static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size) |
213 |
{ |
214 |
TyphoonState *s = opaque; |
215 |
uint64_t ret = 0;
|
216 |
|
217 |
if (addr & 4) { |
218 |
return s->latch_tmp;
|
219 |
} |
220 |
|
221 |
switch (addr) {
|
222 |
case 0x0000: |
223 |
/* WSBA0: Window Space Base Address Register. */
|
224 |
ret = s->pchip.win[0].base_addr;
|
225 |
break;
|
226 |
case 0x0040: |
227 |
/* WSBA1 */
|
228 |
ret = s->pchip.win[1].base_addr;
|
229 |
break;
|
230 |
case 0x0080: |
231 |
/* WSBA2 */
|
232 |
ret = s->pchip.win[2].base_addr;
|
233 |
break;
|
234 |
case 0x00c0: |
235 |
/* WSBA3 */
|
236 |
ret = s->pchip.win[3].base_addr;
|
237 |
break;
|
238 |
|
239 |
case 0x0100: |
240 |
/* WSM0: Window Space Mask Register. */
|
241 |
ret = s->pchip.win[0].mask;
|
242 |
break;
|
243 |
case 0x0140: |
244 |
/* WSM1 */
|
245 |
ret = s->pchip.win[1].mask;
|
246 |
break;
|
247 |
case 0x0180: |
248 |
/* WSM2 */
|
249 |
ret = s->pchip.win[2].mask;
|
250 |
break;
|
251 |
case 0x01c0: |
252 |
/* WSM3 */
|
253 |
ret = s->pchip.win[3].mask;
|
254 |
break;
|
255 |
|
256 |
case 0x0200: |
257 |
/* TBA0: Translated Base Address Register. */
|
258 |
ret = (uint64_t)s->pchip.win[0].translated_base_pfn << 10; |
259 |
break;
|
260 |
case 0x0240: |
261 |
/* TBA1 */
|
262 |
ret = (uint64_t)s->pchip.win[1].translated_base_pfn << 10; |
263 |
break;
|
264 |
case 0x0280: |
265 |
/* TBA2 */
|
266 |
ret = (uint64_t)s->pchip.win[2].translated_base_pfn << 10; |
267 |
break;
|
268 |
case 0x02c0: |
269 |
/* TBA3 */
|
270 |
ret = (uint64_t)s->pchip.win[3].translated_base_pfn << 10; |
271 |
break;
|
272 |
|
273 |
case 0x0300: |
274 |
/* PCTL: Pchip Control Register. */
|
275 |
ret = s->pchip.ctl; |
276 |
break;
|
277 |
case 0x0340: |
278 |
/* PLAT: Pchip Master Latency Register. */
|
279 |
break;
|
280 |
case 0x03c0: |
281 |
/* PERROR: Pchip Error Register. */
|
282 |
break;
|
283 |
case 0x0400: |
284 |
/* PERRMASK: Pchip Error Mask Register. */
|
285 |
break;
|
286 |
case 0x0440: |
287 |
/* PERRSET: Pchip Error Set Register. */
|
288 |
break;
|
289 |
case 0x0480: |
290 |
/* TLBIV: Translation Buffer Invalidate Virtual Register (WO). */
|
291 |
break;
|
292 |
case 0x04c0: |
293 |
/* TLBIA: Translation Buffer Invalidate All Register (WO). */
|
294 |
break;
|
295 |
case 0x0500: /* PMONCTL */ |
296 |
case 0x0540: /* PMONCNT */ |
297 |
case 0x0800: /* SPRST */ |
298 |
break;
|
299 |
|
300 |
default:
|
301 |
cpu_unassigned_access(current_cpu, addr, false, false, 0, size); |
302 |
return -1; |
303 |
} |
304 |
|
305 |
s->latch_tmp = ret >> 32;
|
306 |
return ret;
|
307 |
} |
308 |
|
309 |
static void cchip_write(void *opaque, hwaddr addr, |
310 |
uint64_t v32, unsigned size)
|
311 |
{ |
312 |
TyphoonState *s = opaque; |
313 |
uint64_t val, oldval, newval; |
314 |
|
315 |
if (addr & 4) { |
316 |
val = v32 << 32 | s->latch_tmp;
|
317 |
addr ^= 4;
|
318 |
} else {
|
319 |
s->latch_tmp = v32; |
320 |
return;
|
321 |
} |
322 |
|
323 |
switch (addr) {
|
324 |
case 0x0000: |
325 |
/* CSC: Cchip System Configuration Register. */
|
326 |
/* All sorts of data here; nothing relevant RW. */
|
327 |
break;
|
328 |
|
329 |
case 0x0040: |
330 |
/* MTR: Memory Timing Register. */
|
331 |
/* All sorts of stuff related to real DRAM. */
|
332 |
break;
|
333 |
|
334 |
case 0x0080: |
335 |
/* MISC: Miscellaneous Register. */
|
336 |
newval = oldval = s->cchip.misc; |
337 |
newval &= ~(val & 0x10000ff0); /* W1C fields */ |
338 |
if (val & 0x100000) { |
339 |
newval &= ~0xff0000ull; /* ACL clears ABT and ABW */ |
340 |
} else {
|
341 |
newval |= val & 0x00f00000; /* ABT field is W1S */ |
342 |
if ((newval & 0xf0000) == 0) { |
343 |
newval |= val & 0xf0000; /* ABW field is W1S iff zero */ |
344 |
} |
345 |
} |
346 |
newval |= (val & 0xf000) >> 4; /* IPREQ field sets IPINTR. */ |
347 |
|
348 |
newval &= ~0xf0000000000ull; /* WO and RW fields */ |
349 |
newval |= val & 0xf0000000000ull;
|
350 |
s->cchip.misc = newval; |
351 |
|
352 |
/* Pass on changes to IPI and ITI state. */
|
353 |
if ((newval ^ oldval) & 0xff0) { |
354 |
int i;
|
355 |
for (i = 0; i < 4; ++i) { |
356 |
AlphaCPU *cpu = s->cchip.cpu[i]; |
357 |
if (cpu != NULL) { |
358 |
CPUState *cs = CPU(cpu); |
359 |
/* IPI can be either cleared or set by the write. */
|
360 |
if (newval & (1 << (i + 8))) { |
361 |
cpu_interrupt(cs, CPU_INTERRUPT_SMP); |
362 |
} else {
|
363 |
cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP); |
364 |
} |
365 |
|
366 |
/* ITI can only be cleared by the write. */
|
367 |
if ((newval & (1 << (i + 4))) == 0) { |
368 |
cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER); |
369 |
} |
370 |
} |
371 |
} |
372 |
} |
373 |
break;
|
374 |
|
375 |
case 0x00c0: |
376 |
/* MPD: Memory Presence Detect Register. */
|
377 |
break;
|
378 |
|
379 |
case 0x0100: /* AAR0 */ |
380 |
case 0x0140: /* AAR1 */ |
381 |
case 0x0180: /* AAR2 */ |
382 |
case 0x01c0: /* AAR3 */ |
383 |
/* AAR: Array Address Register. */
|
384 |
/* All sorts of information about DRAM. */
|
385 |
break;
|
386 |
|
387 |
case 0x0200: /* DIM0 */ |
388 |
/* DIM: Device Interrupt Mask Register, CPU0. */
|
389 |
s->cchip.dim[0] = val;
|
390 |
cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
|
391 |
break;
|
392 |
case 0x0240: /* DIM1 */ |
393 |
/* DIM: Device Interrupt Mask Register, CPU1. */
|
394 |
s->cchip.dim[0] = val;
|
395 |
cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
|
396 |
break;
|
397 |
|
398 |
case 0x0280: /* DIR0 (RO) */ |
399 |
case 0x02c0: /* DIR1 (RO) */ |
400 |
case 0x0300: /* DRIR (RO) */ |
401 |
break;
|
402 |
|
403 |
case 0x0340: |
404 |
/* PRBEN: Probe Enable Register. */
|
405 |
break;
|
406 |
|
407 |
case 0x0380: /* IIC0 */ |
408 |
s->cchip.iic[0] = val & 0xffffff; |
409 |
break;
|
410 |
case 0x03c0: /* IIC1 */ |
411 |
s->cchip.iic[1] = val & 0xffffff; |
412 |
break;
|
413 |
|
414 |
case 0x0400: /* MPR0 */ |
415 |
case 0x0440: /* MPR1 */ |
416 |
case 0x0480: /* MPR2 */ |
417 |
case 0x04c0: /* MPR3 */ |
418 |
/* MPR: Memory Programming Register. */
|
419 |
break;
|
420 |
|
421 |
case 0x0580: |
422 |
/* TTR: TIGbus Timing Register. */
|
423 |
/* All sorts of stuff related to interrupt delivery timings. */
|
424 |
break;
|
425 |
case 0x05c0: |
426 |
/* TDR: TIGbug Device Timing Register. */
|
427 |
break;
|
428 |
|
429 |
case 0x0600: |
430 |
/* DIM2: Device Interrupt Mask Register, CPU2. */
|
431 |
s->cchip.dim[2] = val;
|
432 |
cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
|
433 |
break;
|
434 |
case 0x0640: |
435 |
/* DIM3: Device Interrupt Mask Register, CPU3. */
|
436 |
s->cchip.dim[3] = val;
|
437 |
cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
|
438 |
break;
|
439 |
|
440 |
case 0x0680: /* DIR2 (RO) */ |
441 |
case 0x06c0: /* DIR3 (RO) */ |
442 |
break;
|
443 |
|
444 |
case 0x0700: /* IIC2 */ |
445 |
s->cchip.iic[2] = val & 0xffffff; |
446 |
break;
|
447 |
case 0x0740: /* IIC3 */ |
448 |
s->cchip.iic[3] = val & 0xffffff; |
449 |
break;
|
450 |
|
451 |
case 0x0780: |
452 |
/* PWR: Power Management Control. */
|
453 |
break;
|
454 |
|
455 |
case 0x0c00: /* CMONCTLA */ |
456 |
case 0x0c40: /* CMONCTLB */ |
457 |
case 0x0c80: /* CMONCNT01 */ |
458 |
case 0x0cc0: /* CMONCNT23 */ |
459 |
break;
|
460 |
|
461 |
default:
|
462 |
cpu_unassigned_access(current_cpu, addr, true, false, 0, size); |
463 |
return;
|
464 |
} |
465 |
} |
466 |
|
467 |
static void dchip_write(void *opaque, hwaddr addr, |
468 |
uint64_t val, unsigned size)
|
469 |
{ |
470 |
/* Skip this. It's all related to DRAM timing and setup. */
|
471 |
} |
472 |
|
473 |
static void pchip_write(void *opaque, hwaddr addr, |
474 |
uint64_t v32, unsigned size)
|
475 |
{ |
476 |
TyphoonState *s = opaque; |
477 |
uint64_t val, oldval; |
478 |
|
479 |
if (addr & 4) { |
480 |
val = v32 << 32 | s->latch_tmp;
|
481 |
addr ^= 4;
|
482 |
} else {
|
483 |
s->latch_tmp = v32; |
484 |
return;
|
485 |
} |
486 |
|
487 |
switch (addr) {
|
488 |
case 0x0000: |
489 |
/* WSBA0: Window Space Base Address Register. */
|
490 |
s->pchip.win[0].base_addr = val;
|
491 |
break;
|
492 |
case 0x0040: |
493 |
/* WSBA1 */
|
494 |
s->pchip.win[1].base_addr = val;
|
495 |
break;
|
496 |
case 0x0080: |
497 |
/* WSBA2 */
|
498 |
s->pchip.win[2].base_addr = val;
|
499 |
break;
|
500 |
case 0x00c0: |
501 |
/* WSBA3 */
|
502 |
s->pchip.win[3].base_addr = val;
|
503 |
break;
|
504 |
|
505 |
case 0x0100: |
506 |
/* WSM0: Window Space Mask Register. */
|
507 |
s->pchip.win[0].mask = val;
|
508 |
break;
|
509 |
case 0x0140: |
510 |
/* WSM1 */
|
511 |
s->pchip.win[1].mask = val;
|
512 |
break;
|
513 |
case 0x0180: |
514 |
/* WSM2 */
|
515 |
s->pchip.win[2].mask = val;
|
516 |
break;
|
517 |
case 0x01c0: |
518 |
/* WSM3 */
|
519 |
s->pchip.win[3].mask = val;
|
520 |
break;
|
521 |
|
522 |
case 0x0200: |
523 |
/* TBA0: Translated Base Address Register. */
|
524 |
s->pchip.win[0].translated_base_pfn = val >> 10; |
525 |
break;
|
526 |
case 0x0240: |
527 |
/* TBA1 */
|
528 |
s->pchip.win[1].translated_base_pfn = val >> 10; |
529 |
break;
|
530 |
case 0x0280: |
531 |
/* TBA2 */
|
532 |
s->pchip.win[2].translated_base_pfn = val >> 10; |
533 |
break;
|
534 |
case 0x02c0: |
535 |
/* TBA3 */
|
536 |
s->pchip.win[3].translated_base_pfn = val >> 10; |
537 |
break;
|
538 |
|
539 |
case 0x0300: |
540 |
/* PCTL: Pchip Control Register. */
|
541 |
oldval = s->pchip.ctl; |
542 |
oldval &= ~0x00001cff0fc7ffull; /* RW fields */ |
543 |
oldval |= val & 0x00001cff0fc7ffull;
|
544 |
|
545 |
s->pchip.ctl = oldval; |
546 |
break;
|
547 |
|
548 |
case 0x0340: |
549 |
/* PLAT: Pchip Master Latency Register. */
|
550 |
break;
|
551 |
case 0x03c0: |
552 |
/* PERROR: Pchip Error Register. */
|
553 |
break;
|
554 |
case 0x0400: |
555 |
/* PERRMASK: Pchip Error Mask Register. */
|
556 |
break;
|
557 |
case 0x0440: |
558 |
/* PERRSET: Pchip Error Set Register. */
|
559 |
break;
|
560 |
|
561 |
case 0x0480: |
562 |
/* TLBIV: Translation Buffer Invalidate Virtual Register. */
|
563 |
break;
|
564 |
|
565 |
case 0x04c0: |
566 |
/* TLBIA: Translation Buffer Invalidate All Register (WO). */
|
567 |
break;
|
568 |
|
569 |
case 0x0500: |
570 |
/* PMONCTL */
|
571 |
case 0x0540: |
572 |
/* PMONCNT */
|
573 |
case 0x0800: |
574 |
/* SPRST */
|
575 |
break;
|
576 |
|
577 |
default:
|
578 |
cpu_unassigned_access(current_cpu, addr, true, false, 0, size); |
579 |
return;
|
580 |
} |
581 |
} |
582 |
|
583 |
static const MemoryRegionOps cchip_ops = { |
584 |
.read = cchip_read, |
585 |
.write = cchip_write, |
586 |
.endianness = DEVICE_LITTLE_ENDIAN, |
587 |
.valid = { |
588 |
.min_access_size = 4, /* ??? Should be 8. */ |
589 |
.max_access_size = 8,
|
590 |
}, |
591 |
.impl = { |
592 |
.min_access_size = 4,
|
593 |
.max_access_size = 4,
|
594 |
}, |
595 |
}; |
596 |
|
597 |
static const MemoryRegionOps dchip_ops = { |
598 |
.read = dchip_read, |
599 |
.write = dchip_write, |
600 |
.endianness = DEVICE_LITTLE_ENDIAN, |
601 |
.valid = { |
602 |
.min_access_size = 4, /* ??? Should be 8. */ |
603 |
.max_access_size = 8,
|
604 |
}, |
605 |
.impl = { |
606 |
.min_access_size = 4,
|
607 |
.max_access_size = 8,
|
608 |
}, |
609 |
}; |
610 |
|
611 |
static const MemoryRegionOps pchip_ops = { |
612 |
.read = pchip_read, |
613 |
.write = pchip_write, |
614 |
.endianness = DEVICE_LITTLE_ENDIAN, |
615 |
.valid = { |
616 |
.min_access_size = 4, /* ??? Should be 8. */ |
617 |
.max_access_size = 8,
|
618 |
}, |
619 |
.impl = { |
620 |
.min_access_size = 4,
|
621 |
.max_access_size = 4,
|
622 |
}, |
623 |
}; |
624 |
|
625 |
static void typhoon_set_irq(void *opaque, int irq, int level) |
626 |
{ |
627 |
TyphoonState *s = opaque; |
628 |
uint64_t drir; |
629 |
int i;
|
630 |
|
631 |
/* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL. */
|
632 |
drir = s->cchip.drir; |
633 |
if (level) {
|
634 |
drir |= 1ull << irq;
|
635 |
} else {
|
636 |
drir &= ~(1ull << irq);
|
637 |
} |
638 |
s->cchip.drir = drir; |
639 |
|
640 |
for (i = 0; i < 4; ++i) { |
641 |
cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir); |
642 |
} |
643 |
} |
644 |
|
645 |
static void typhoon_set_isa_irq(void *opaque, int irq, int level) |
646 |
{ |
647 |
typhoon_set_irq(opaque, 55, level);
|
648 |
} |
649 |
|
650 |
static void typhoon_set_timer_irq(void *opaque, int irq, int level) |
651 |
{ |
652 |
TyphoonState *s = opaque; |
653 |
int i;
|
654 |
|
655 |
/* Thankfully, the mc146818rtc code doesn't track the IRQ state,
|
656 |
and so we don't have to worry about missing interrupts just
|
657 |
because we never actually ACK the interrupt. Just ignore any
|
658 |
case of the interrupt level going low. */
|
659 |
if (level == 0) { |
660 |
return;
|
661 |
} |
662 |
|
663 |
/* Deliver the interrupt to each CPU, considering each CPU's IIC. */
|
664 |
for (i = 0; i < 4; ++i) { |
665 |
AlphaCPU *cpu = s->cchip.cpu[i]; |
666 |
if (cpu != NULL) { |
667 |
uint32_t iic = s->cchip.iic[i]; |
668 |
|
669 |
/* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
|
670 |
Bit 24 is the OverFlow bit, RO, and set when the count
|
671 |
decrements past 0. When is OF cleared? My guess is that
|
672 |
OF is actually cleared when the IIC is written, and that
|
673 |
the ICNT field always decrements. At least, that's an
|
674 |
interpretation that makes sense, and "allows the CPU to
|
675 |
determine exactly how mant interval timer ticks were
|
676 |
skipped". At least within the next 4M ticks... */
|
677 |
|
678 |
iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000); |
679 |
s->cchip.iic[i] = iic; |
680 |
|
681 |
if (iic & 0x1000000) { |
682 |
/* Set the ITI bit for this cpu. */
|
683 |
s->cchip.misc |= 1 << (i + 4); |
684 |
/* And signal the interrupt. */
|
685 |
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER); |
686 |
} |
687 |
} |
688 |
} |
689 |
} |
690 |
|
691 |
static void typhoon_alarm_timer(void *opaque) |
692 |
{ |
693 |
TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
|
694 |
int cpu = (uintptr_t)opaque & 3; |
695 |
|
696 |
/* Set the ITI bit for this cpu. */
|
697 |
s->cchip.misc |= 1 << (cpu + 4); |
698 |
cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER); |
699 |
} |
700 |
|
701 |
PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, |
702 |
qemu_irq *p_rtc_irq, |
703 |
AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq)
|
704 |
{ |
705 |
const uint64_t MB = 1024 * 1024; |
706 |
const uint64_t GB = 1024 * MB; |
707 |
MemoryRegion *addr_space = get_system_memory(); |
708 |
DeviceState *dev; |
709 |
TyphoonState *s; |
710 |
PCIHostState *phb; |
711 |
PCIBus *b; |
712 |
int i;
|
713 |
|
714 |
dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
|
715 |
qdev_init_nofail(dev); |
716 |
|
717 |
s = TYPHOON_PCI_HOST_BRIDGE(dev); |
718 |
phb = PCI_HOST_BRIDGE(dev); |
719 |
|
720 |
/* Remember the CPUs so that we can deliver interrupts to them. */
|
721 |
for (i = 0; i < 4; i++) { |
722 |
AlphaCPU *cpu = cpus[i]; |
723 |
s->cchip.cpu[i] = cpu; |
724 |
if (cpu != NULL) { |
725 |
cpu->alarm_timer = qemu_new_timer_ns(rtc_clock, |
726 |
typhoon_alarm_timer, |
727 |
(void *)((uintptr_t)s + i));
|
728 |
} |
729 |
} |
730 |
|
731 |
*p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
|
732 |
|
733 |
/* Main memory region, 0x00.0000.0000. Real hardware supports 32GB,
|
734 |
but the address space hole reserved at this point is 8TB. */
|
735 |
memory_region_init_ram(&s->ram_region, OBJECT(s), "ram", ram_size);
|
736 |
vmstate_register_ram_global(&s->ram_region); |
737 |
memory_region_add_subregion(addr_space, 0, &s->ram_region);
|
738 |
|
739 |
/* TIGbus, 0x801.0000.0000, 1GB. */
|
740 |
/* ??? The TIGbus is used for delivering interrupts, and access to
|
741 |
the flash ROM. I'm not sure that we need to implement it at all. */
|
742 |
|
743 |
/* Pchip0 CSRs, 0x801.8000.0000, 256MB. */
|
744 |
memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
|
745 |
256*MB);
|
746 |
memory_region_add_subregion(addr_space, 0x80180000000ULL,
|
747 |
&s->pchip.region); |
748 |
|
749 |
/* Cchip CSRs, 0x801.A000.0000, 256MB. */
|
750 |
memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
|
751 |
256*MB);
|
752 |
memory_region_add_subregion(addr_space, 0x801a0000000ULL,
|
753 |
&s->cchip.region); |
754 |
|
755 |
/* Dchip CSRs, 0x801.B000.0000, 256MB. */
|
756 |
memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
|
757 |
256*MB);
|
758 |
memory_region_add_subregion(addr_space, 0x801b0000000ULL,
|
759 |
&s->dchip_region); |
760 |
|
761 |
/* Pchip0 PCI memory, 0x800.0000.0000, 4GB. */
|
762 |
memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4*GB); |
763 |
memory_region_add_subregion(addr_space, 0x80000000000ULL,
|
764 |
&s->pchip.reg_mem); |
765 |
|
766 |
/* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB. */
|
767 |
memory_region_init(&s->pchip.reg_io, OBJECT(s), "pci0-io", 32*MB); |
768 |
memory_region_add_subregion(addr_space, 0x801fc000000ULL,
|
769 |
&s->pchip.reg_io); |
770 |
|
771 |
b = pci_register_bus(dev, "pci",
|
772 |
typhoon_set_irq, sys_map_irq, s, |
773 |
&s->pchip.reg_mem, &s->pchip.reg_io, |
774 |
0, 64, TYPE_PCI_BUS); |
775 |
phb->bus = b; |
776 |
|
777 |
/* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */
|
778 |
memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops, |
779 |
b, "pci0-iack", 64*MB); |
780 |
memory_region_add_subregion(addr_space, 0x801f8000000ULL,
|
781 |
&s->pchip.reg_iack); |
782 |
|
783 |
/* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB. */
|
784 |
memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops, |
785 |
b, "pci0-conf", 16*MB); |
786 |
memory_region_add_subregion(addr_space, 0x801fe000000ULL,
|
787 |
&s->pchip.reg_conf); |
788 |
|
789 |
/* For the record, these are the mappings for the second PCI bus.
|
790 |
We can get away with not implementing them because we indicate
|
791 |
via the Cchip.CSC<PIP> bit that Pchip1 is not present. */
|
792 |
/* Pchip1 PCI memory, 0x802.0000.0000, 4GB. */
|
793 |
/* Pchip1 CSRs, 0x802.8000.0000, 256MB. */
|
794 |
/* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB. */
|
795 |
/* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB. */
|
796 |
/* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB. */
|
797 |
|
798 |
/* Init the ISA bus. */
|
799 |
/* ??? Technically there should be a cy82c693ub pci-isa bridge. */
|
800 |
{ |
801 |
qemu_irq isa_pci_irq, *isa_irqs; |
802 |
|
803 |
*isa_bus = isa_bus_new(NULL, &s->pchip.reg_io);
|
804 |
isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1);
|
805 |
isa_irqs = i8259_init(*isa_bus, isa_pci_irq); |
806 |
isa_bus_irqs(*isa_bus, isa_irqs); |
807 |
} |
808 |
|
809 |
return b;
|
810 |
} |
811 |
|
812 |
static int typhoon_pcihost_init(SysBusDevice *dev) |
813 |
{ |
814 |
return 0; |
815 |
} |
816 |
|
817 |
static void typhoon_pcihost_class_init(ObjectClass *klass, void *data) |
818 |
{ |
819 |
DeviceClass *dc = DEVICE_CLASS(klass); |
820 |
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
821 |
|
822 |
k->init = typhoon_pcihost_init; |
823 |
dc->no_user = 1;
|
824 |
} |
825 |
|
826 |
static const TypeInfo typhoon_pcihost_info = { |
827 |
.name = TYPE_TYPHOON_PCI_HOST_BRIDGE, |
828 |
.parent = TYPE_PCI_HOST_BRIDGE, |
829 |
.instance_size = sizeof(TyphoonState),
|
830 |
.class_init = typhoon_pcihost_class_init, |
831 |
}; |
832 |
|
833 |
static void typhoon_register_types(void) |
834 |
{ |
835 |
type_register_static(&typhoon_pcihost_info); |
836 |
} |
837 |
|
838 |
type_init(typhoon_register_types) |