xref: /qemu/hw/alpha/typhoon.c (revision 8063396bf3459a810d24e3efd6110b8480f0de5b)
180bb2ff7SRichard Henderson /*
280bb2ff7SRichard Henderson  * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
380bb2ff7SRichard Henderson  *
480bb2ff7SRichard Henderson  * Written by Richard Henderson.
580bb2ff7SRichard Henderson  *
680bb2ff7SRichard Henderson  * This work is licensed under the GNU GPL license version 2 or later.
780bb2ff7SRichard Henderson  */
880bb2ff7SRichard Henderson 
9e2e5e114SPeter Maydell #include "qemu/osdep.h"
100b8fa32fSMarkus Armbruster #include "qemu/module.h"
112b41742aSPhilippe Mathieu-Daudé #include "qemu/units.h"
12da34e65cSMarkus Armbruster #include "qapi/error.h"
1380bb2ff7SRichard Henderson #include "cpu.h"
1412e9493dSMarkus Armbruster #include "hw/boards.h"
1564552b6bSMarkus Armbruster #include "hw/irq.h"
1647b43a1fSPaolo Bonzini #include "alpha_sys.h"
17022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
18db1015e9SEduardo Habkost #include "qom/object.h"
1980bb2ff7SRichard Henderson 
2080bb2ff7SRichard Henderson 
2194dd91d6SAndreas Färber #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
221221a474SAlexey Kardashevskiy #define TYPE_TYPHOON_IOMMU_MEMORY_REGION "typhoon-iommu-memory-region"
2394dd91d6SAndreas Färber 
2480bb2ff7SRichard Henderson typedef struct TyphoonCchip {
2580bb2ff7SRichard Henderson     MemoryRegion region;
2680bb2ff7SRichard Henderson     uint64_t misc;
2780bb2ff7SRichard Henderson     uint64_t drir;
2880bb2ff7SRichard Henderson     uint64_t dim[4];
2980bb2ff7SRichard Henderson     uint32_t iic[4];
30ad601177SAndreas Färber     AlphaCPU *cpu[4];
3180bb2ff7SRichard Henderson } TyphoonCchip;
3280bb2ff7SRichard Henderson 
3380bb2ff7SRichard Henderson typedef struct TyphoonWindow {
34b83c4db8SRichard Henderson     uint64_t wba;
35b83c4db8SRichard Henderson     uint64_t wsm;
36b83c4db8SRichard Henderson     uint64_t tba;
3780bb2ff7SRichard Henderson } TyphoonWindow;
3880bb2ff7SRichard Henderson 
3980bb2ff7SRichard Henderson typedef struct TyphoonPchip {
4080bb2ff7SRichard Henderson     MemoryRegion region;
4180bb2ff7SRichard Henderson     MemoryRegion reg_iack;
4280bb2ff7SRichard Henderson     MemoryRegion reg_mem;
4380bb2ff7SRichard Henderson     MemoryRegion reg_io;
4480bb2ff7SRichard Henderson     MemoryRegion reg_conf;
45b83c4db8SRichard Henderson 
46b83c4db8SRichard Henderson     AddressSpace iommu_as;
473df9d748SAlexey Kardashevskiy     IOMMUMemoryRegion iommu;
48b83c4db8SRichard Henderson 
4980bb2ff7SRichard Henderson     uint64_t ctl;
5080bb2ff7SRichard Henderson     TyphoonWindow win[4];
5180bb2ff7SRichard Henderson } TyphoonPchip;
5280bb2ff7SRichard Henderson 
53*8063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(TyphoonState, TYPHOON_PCI_HOST_BRIDGE)
5494dd91d6SAndreas Färber 
55db1015e9SEduardo Habkost struct TyphoonState {
5667c332fdSAndreas Färber     PCIHostState parent_obj;
5794dd91d6SAndreas Färber 
5880bb2ff7SRichard Henderson     TyphoonCchip cchip;
5980bb2ff7SRichard Henderson     TyphoonPchip pchip;
6080bb2ff7SRichard Henderson     MemoryRegion dchip_region;
61db1015e9SEduardo Habkost };
6280bb2ff7SRichard Henderson 
6380bb2ff7SRichard Henderson /* Called when one of DRIR or DIM changes.  */
64ad601177SAndreas Färber static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
6580bb2ff7SRichard Henderson {
6680bb2ff7SRichard Henderson     /* If there are any non-masked interrupts, tell the cpu.  */
67ad601177SAndreas Färber     if (cpu != NULL) {
68d8ed887bSAndreas Färber         CPUState *cs = CPU(cpu);
6980bb2ff7SRichard Henderson         if (req) {
70c3affe56SAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
7180bb2ff7SRichard Henderson         } else {
72d8ed887bSAndreas Färber             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
7380bb2ff7SRichard Henderson         }
7480bb2ff7SRichard Henderson     }
7580bb2ff7SRichard Henderson }
7680bb2ff7SRichard Henderson 
77b7ed683aSPeter Maydell static MemTxResult cchip_read(void *opaque, hwaddr addr,
78b7ed683aSPeter Maydell                               uint64_t *data, unsigned size,
79b7ed683aSPeter Maydell                               MemTxAttrs attrs)
8080bb2ff7SRichard Henderson {
814917cf44SAndreas Färber     CPUState *cpu = current_cpu;
8280bb2ff7SRichard Henderson     TyphoonState *s = opaque;
8380bb2ff7SRichard Henderson     uint64_t ret = 0;
8480bb2ff7SRichard Henderson 
8580bb2ff7SRichard Henderson     switch (addr) {
8680bb2ff7SRichard Henderson     case 0x0000:
8780bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
8880bb2ff7SRichard Henderson         /* All sorts of data here; probably the only thing relevant is
8980bb2ff7SRichard Henderson            PIP<14> Pchip 1 Present = 0.  */
9080bb2ff7SRichard Henderson         break;
9180bb2ff7SRichard Henderson 
9280bb2ff7SRichard Henderson     case 0x0040:
9380bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
9480bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
9580bb2ff7SRichard Henderson         break;
9680bb2ff7SRichard Henderson 
9780bb2ff7SRichard Henderson     case 0x0080:
9880bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
9955e5c285SAndreas Färber         ret = s->cchip.misc | (cpu->cpu_index & 3);
10080bb2ff7SRichard Henderson         break;
10180bb2ff7SRichard Henderson 
10280bb2ff7SRichard Henderson     case 0x00c0:
10380bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
10480bb2ff7SRichard Henderson         break;
10580bb2ff7SRichard Henderson 
10680bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
10780bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
10880bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
10980bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
11080bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
11180bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
11280bb2ff7SRichard Henderson         break;
11380bb2ff7SRichard Henderson 
11480bb2ff7SRichard Henderson     case 0x0200:
11580bb2ff7SRichard Henderson         /* DIM0: Device Interrupt Mask Register, CPU0.  */
11680bb2ff7SRichard Henderson         ret = s->cchip.dim[0];
11780bb2ff7SRichard Henderson         break;
11880bb2ff7SRichard Henderson     case 0x0240:
11980bb2ff7SRichard Henderson         /* DIM1: Device Interrupt Mask Register, CPU1.  */
12080bb2ff7SRichard Henderson         ret = s->cchip.dim[1];
12180bb2ff7SRichard Henderson         break;
12280bb2ff7SRichard Henderson     case 0x0280:
12380bb2ff7SRichard Henderson         /* DIR0: Device Interrupt Request Register, CPU0.  */
12480bb2ff7SRichard Henderson         ret = s->cchip.dim[0] & s->cchip.drir;
12580bb2ff7SRichard Henderson         break;
12680bb2ff7SRichard Henderson     case 0x02c0:
12780bb2ff7SRichard Henderson         /* DIR1: Device Interrupt Request Register, CPU1.  */
12880bb2ff7SRichard Henderson         ret = s->cchip.dim[1] & s->cchip.drir;
12980bb2ff7SRichard Henderson         break;
13080bb2ff7SRichard Henderson     case 0x0300:
13180bb2ff7SRichard Henderson         /* DRIR: Device Raw Interrupt Request Register.  */
13280bb2ff7SRichard Henderson         ret = s->cchip.drir;
13380bb2ff7SRichard Henderson         break;
13480bb2ff7SRichard Henderson 
13580bb2ff7SRichard Henderson     case 0x0340:
13680bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
13780bb2ff7SRichard Henderson         break;
13880bb2ff7SRichard Henderson 
13980bb2ff7SRichard Henderson     case 0x0380:
14080bb2ff7SRichard Henderson         /* IIC0: Interval Ignore Count Register, CPU0.  */
14180bb2ff7SRichard Henderson         ret = s->cchip.iic[0];
14280bb2ff7SRichard Henderson         break;
14380bb2ff7SRichard Henderson     case 0x03c0:
14480bb2ff7SRichard Henderson         /* IIC1: Interval Ignore Count Register, CPU1.  */
14580bb2ff7SRichard Henderson         ret = s->cchip.iic[1];
14680bb2ff7SRichard Henderson         break;
14780bb2ff7SRichard Henderson 
14880bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
14980bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
15080bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
15180bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
15280bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
15380bb2ff7SRichard Henderson         break;
15480bb2ff7SRichard Henderson 
15580bb2ff7SRichard Henderson     case 0x0580:
15680bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
15780bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
15880bb2ff7SRichard Henderson         break;
15980bb2ff7SRichard Henderson     case 0x05c0:
16080bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
16180bb2ff7SRichard Henderson         break;
16280bb2ff7SRichard Henderson 
16380bb2ff7SRichard Henderson     case 0x0600:
16480bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
16580bb2ff7SRichard Henderson         ret = s->cchip.dim[2];
16680bb2ff7SRichard Henderson         break;
16780bb2ff7SRichard Henderson     case 0x0640:
16880bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
16980bb2ff7SRichard Henderson         ret = s->cchip.dim[3];
17080bb2ff7SRichard Henderson         break;
17180bb2ff7SRichard Henderson     case 0x0680:
17280bb2ff7SRichard Henderson         /* DIR2: Device Interrupt Request Register, CPU2.  */
17380bb2ff7SRichard Henderson         ret = s->cchip.dim[2] & s->cchip.drir;
17480bb2ff7SRichard Henderson         break;
17580bb2ff7SRichard Henderson     case 0x06c0:
17680bb2ff7SRichard Henderson         /* DIR3: Device Interrupt Request Register, CPU3.  */
17780bb2ff7SRichard Henderson         ret = s->cchip.dim[3] & s->cchip.drir;
17880bb2ff7SRichard Henderson         break;
17980bb2ff7SRichard Henderson 
18080bb2ff7SRichard Henderson     case 0x0700:
18180bb2ff7SRichard Henderson         /* IIC2: Interval Ignore Count Register, CPU2.  */
18280bb2ff7SRichard Henderson         ret = s->cchip.iic[2];
18380bb2ff7SRichard Henderson         break;
18480bb2ff7SRichard Henderson     case 0x0740:
18580bb2ff7SRichard Henderson         /* IIC3: Interval Ignore Count Register, CPU3.  */
18680bb2ff7SRichard Henderson         ret = s->cchip.iic[3];
18780bb2ff7SRichard Henderson         break;
18880bb2ff7SRichard Henderson 
18980bb2ff7SRichard Henderson     case 0x0780:
19080bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
19180bb2ff7SRichard Henderson         break;
19280bb2ff7SRichard Henderson 
19380bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
19480bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
19580bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
19680bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
19780bb2ff7SRichard Henderson         break;
19880bb2ff7SRichard Henderson 
19980bb2ff7SRichard Henderson     default:
200b7ed683aSPeter Maydell         return MEMTX_ERROR;
20180bb2ff7SRichard Henderson     }
20280bb2ff7SRichard Henderson 
203b7ed683aSPeter Maydell     *data = ret;
204b7ed683aSPeter Maydell     return MEMTX_OK;
20580bb2ff7SRichard Henderson }
20680bb2ff7SRichard Henderson 
207a8170e5eSAvi Kivity static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
20880bb2ff7SRichard Henderson {
20980bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
21080bb2ff7SRichard Henderson     return 0;
21180bb2ff7SRichard Henderson }
21280bb2ff7SRichard Henderson 
213b7ed683aSPeter Maydell static MemTxResult pchip_read(void *opaque, hwaddr addr, uint64_t *data,
214b7ed683aSPeter Maydell                               unsigned size, MemTxAttrs attrs)
21580bb2ff7SRichard Henderson {
21680bb2ff7SRichard Henderson     TyphoonState *s = opaque;
21780bb2ff7SRichard Henderson     uint64_t ret = 0;
21880bb2ff7SRichard Henderson 
21980bb2ff7SRichard Henderson     switch (addr) {
22080bb2ff7SRichard Henderson     case 0x0000:
22180bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
222b83c4db8SRichard Henderson         ret = s->pchip.win[0].wba;
22380bb2ff7SRichard Henderson         break;
22480bb2ff7SRichard Henderson     case 0x0040:
22580bb2ff7SRichard Henderson         /* WSBA1 */
226b83c4db8SRichard Henderson         ret = s->pchip.win[1].wba;
22780bb2ff7SRichard Henderson         break;
22880bb2ff7SRichard Henderson     case 0x0080:
22980bb2ff7SRichard Henderson         /* WSBA2 */
230b83c4db8SRichard Henderson         ret = s->pchip.win[2].wba;
23180bb2ff7SRichard Henderson         break;
23280bb2ff7SRichard Henderson     case 0x00c0:
23380bb2ff7SRichard Henderson         /* WSBA3 */
234b83c4db8SRichard Henderson         ret = s->pchip.win[3].wba;
23580bb2ff7SRichard Henderson         break;
23680bb2ff7SRichard Henderson 
23780bb2ff7SRichard Henderson     case 0x0100:
23880bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
239b83c4db8SRichard Henderson         ret = s->pchip.win[0].wsm;
24080bb2ff7SRichard Henderson         break;
24180bb2ff7SRichard Henderson     case 0x0140:
24280bb2ff7SRichard Henderson         /* WSM1 */
243b83c4db8SRichard Henderson         ret = s->pchip.win[1].wsm;
24480bb2ff7SRichard Henderson         break;
24580bb2ff7SRichard Henderson     case 0x0180:
24680bb2ff7SRichard Henderson         /* WSM2 */
247b83c4db8SRichard Henderson         ret = s->pchip.win[2].wsm;
24880bb2ff7SRichard Henderson         break;
24980bb2ff7SRichard Henderson     case 0x01c0:
25080bb2ff7SRichard Henderson         /* WSM3 */
251b83c4db8SRichard Henderson         ret = s->pchip.win[3].wsm;
25280bb2ff7SRichard Henderson         break;
25380bb2ff7SRichard Henderson 
25480bb2ff7SRichard Henderson     case 0x0200:
25580bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
256b83c4db8SRichard Henderson         ret = s->pchip.win[0].tba;
25780bb2ff7SRichard Henderson         break;
25880bb2ff7SRichard Henderson     case 0x0240:
25980bb2ff7SRichard Henderson         /* TBA1 */
260b83c4db8SRichard Henderson         ret = s->pchip.win[1].tba;
26180bb2ff7SRichard Henderson         break;
26280bb2ff7SRichard Henderson     case 0x0280:
26380bb2ff7SRichard Henderson         /* TBA2 */
264b83c4db8SRichard Henderson         ret = s->pchip.win[2].tba;
26580bb2ff7SRichard Henderson         break;
26680bb2ff7SRichard Henderson     case 0x02c0:
26780bb2ff7SRichard Henderson         /* TBA3 */
268b83c4db8SRichard Henderson         ret = s->pchip.win[3].tba;
26980bb2ff7SRichard Henderson         break;
27080bb2ff7SRichard Henderson 
27180bb2ff7SRichard Henderson     case 0x0300:
27280bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
27380bb2ff7SRichard Henderson         ret = s->pchip.ctl;
27480bb2ff7SRichard Henderson         break;
27580bb2ff7SRichard Henderson     case 0x0340:
27680bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
27780bb2ff7SRichard Henderson         break;
27880bb2ff7SRichard Henderson     case 0x03c0:
27980bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
28080bb2ff7SRichard Henderson         break;
28180bb2ff7SRichard Henderson     case 0x0400:
28280bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
28380bb2ff7SRichard Henderson         break;
28480bb2ff7SRichard Henderson     case 0x0440:
28580bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
28680bb2ff7SRichard Henderson         break;
28780bb2ff7SRichard Henderson     case 0x0480:
28880bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
28980bb2ff7SRichard Henderson         break;
29080bb2ff7SRichard Henderson     case 0x04c0:
29180bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
29280bb2ff7SRichard Henderson         break;
29380bb2ff7SRichard Henderson     case 0x0500: /* PMONCTL */
29480bb2ff7SRichard Henderson     case 0x0540: /* PMONCNT */
29580bb2ff7SRichard Henderson     case 0x0800: /* SPRST */
29680bb2ff7SRichard Henderson         break;
29780bb2ff7SRichard Henderson 
29880bb2ff7SRichard Henderson     default:
299b7ed683aSPeter Maydell         return MEMTX_ERROR;
30080bb2ff7SRichard Henderson     }
30180bb2ff7SRichard Henderson 
302b7ed683aSPeter Maydell     *data = ret;
303b7ed683aSPeter Maydell     return MEMTX_OK;
30480bb2ff7SRichard Henderson }
30580bb2ff7SRichard Henderson 
306b7ed683aSPeter Maydell static MemTxResult cchip_write(void *opaque, hwaddr addr,
307b7ed683aSPeter Maydell                                uint64_t val, unsigned size,
308b7ed683aSPeter Maydell                                MemTxAttrs attrs)
30980bb2ff7SRichard Henderson {
31080bb2ff7SRichard Henderson     TyphoonState *s = opaque;
31167842165SRichard Henderson     uint64_t oldval, newval;
31280bb2ff7SRichard Henderson 
31380bb2ff7SRichard Henderson     switch (addr) {
31480bb2ff7SRichard Henderson     case 0x0000:
31580bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
31680bb2ff7SRichard Henderson         /* All sorts of data here; nothing relevant RW.  */
31780bb2ff7SRichard Henderson         break;
31880bb2ff7SRichard Henderson 
31980bb2ff7SRichard Henderson     case 0x0040:
32080bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
32180bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
32280bb2ff7SRichard Henderson         break;
32380bb2ff7SRichard Henderson 
32480bb2ff7SRichard Henderson     case 0x0080:
32580bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
32680bb2ff7SRichard Henderson         newval = oldval = s->cchip.misc;
32780bb2ff7SRichard Henderson         newval &= ~(val & 0x10000ff0);     /* W1C fields */
32880bb2ff7SRichard Henderson         if (val & 0x100000) {
32980bb2ff7SRichard Henderson             newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
33080bb2ff7SRichard Henderson         } else {
33180bb2ff7SRichard Henderson             newval |= val & 0x00f00000;    /* ABT field is W1S */
33280bb2ff7SRichard Henderson             if ((newval & 0xf0000) == 0) {
33380bb2ff7SRichard Henderson                 newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
33480bb2ff7SRichard Henderson             }
33580bb2ff7SRichard Henderson         }
33680bb2ff7SRichard Henderson         newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
33780bb2ff7SRichard Henderson 
33880bb2ff7SRichard Henderson         newval &= ~0xf0000000000ull;       /* WO and RW fields */
33980bb2ff7SRichard Henderson         newval |= val & 0xf0000000000ull;
34080bb2ff7SRichard Henderson         s->cchip.misc = newval;
34180bb2ff7SRichard Henderson 
34280bb2ff7SRichard Henderson         /* Pass on changes to IPI and ITI state.  */
34380bb2ff7SRichard Henderson         if ((newval ^ oldval) & 0xff0) {
34480bb2ff7SRichard Henderson             int i;
34580bb2ff7SRichard Henderson             for (i = 0; i < 4; ++i) {
346ad601177SAndreas Färber                 AlphaCPU *cpu = s->cchip.cpu[i];
347ad601177SAndreas Färber                 if (cpu != NULL) {
348d8ed887bSAndreas Färber                     CPUState *cs = CPU(cpu);
34980bb2ff7SRichard Henderson                     /* IPI can be either cleared or set by the write.  */
35080bb2ff7SRichard Henderson                     if (newval & (1 << (i + 8))) {
351c3affe56SAndreas Färber                         cpu_interrupt(cs, CPU_INTERRUPT_SMP);
35280bb2ff7SRichard Henderson                     } else {
353d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
35480bb2ff7SRichard Henderson                     }
35580bb2ff7SRichard Henderson 
35680bb2ff7SRichard Henderson                     /* ITI can only be cleared by the write.  */
35780bb2ff7SRichard Henderson                     if ((newval & (1 << (i + 4))) == 0) {
358d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
35980bb2ff7SRichard Henderson                     }
36080bb2ff7SRichard Henderson                 }
36180bb2ff7SRichard Henderson             }
36280bb2ff7SRichard Henderson         }
36380bb2ff7SRichard Henderson         break;
36480bb2ff7SRichard Henderson 
36580bb2ff7SRichard Henderson     case 0x00c0:
36680bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
36780bb2ff7SRichard Henderson         break;
36880bb2ff7SRichard Henderson 
36980bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
37080bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
37180bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
37280bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
37380bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
37480bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
37580bb2ff7SRichard Henderson         break;
37680bb2ff7SRichard Henderson 
37780bb2ff7SRichard Henderson     case 0x0200: /* DIM0 */
37880bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU0.  */
37980bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
38080bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
38180bb2ff7SRichard Henderson         break;
38280bb2ff7SRichard Henderson     case 0x0240: /* DIM1 */
38380bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU1.  */
384424ad838SRichard Henderson         s->cchip.dim[1] = val;
38580bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
38680bb2ff7SRichard Henderson         break;
38780bb2ff7SRichard Henderson 
38880bb2ff7SRichard Henderson     case 0x0280: /* DIR0 (RO) */
38980bb2ff7SRichard Henderson     case 0x02c0: /* DIR1 (RO) */
39080bb2ff7SRichard Henderson     case 0x0300: /* DRIR (RO) */
39180bb2ff7SRichard Henderson         break;
39280bb2ff7SRichard Henderson 
39380bb2ff7SRichard Henderson     case 0x0340:
39480bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
39580bb2ff7SRichard Henderson         break;
39680bb2ff7SRichard Henderson 
39780bb2ff7SRichard Henderson     case 0x0380: /* IIC0 */
39880bb2ff7SRichard Henderson         s->cchip.iic[0] = val & 0xffffff;
39980bb2ff7SRichard Henderson         break;
40080bb2ff7SRichard Henderson     case 0x03c0: /* IIC1 */
40180bb2ff7SRichard Henderson         s->cchip.iic[1] = val & 0xffffff;
40280bb2ff7SRichard Henderson         break;
40380bb2ff7SRichard Henderson 
40480bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
40580bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
40680bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
40780bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
40880bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
40980bb2ff7SRichard Henderson         break;
41080bb2ff7SRichard Henderson 
41180bb2ff7SRichard Henderson     case 0x0580:
41280bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
41380bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
41480bb2ff7SRichard Henderson         break;
41580bb2ff7SRichard Henderson     case 0x05c0:
41680bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
41780bb2ff7SRichard Henderson         break;
41880bb2ff7SRichard Henderson 
41980bb2ff7SRichard Henderson     case 0x0600:
42080bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
42180bb2ff7SRichard Henderson         s->cchip.dim[2] = val;
42280bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
42380bb2ff7SRichard Henderson         break;
42480bb2ff7SRichard Henderson     case 0x0640:
42580bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
42680bb2ff7SRichard Henderson         s->cchip.dim[3] = val;
42780bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
42880bb2ff7SRichard Henderson         break;
42980bb2ff7SRichard Henderson 
43080bb2ff7SRichard Henderson     case 0x0680: /* DIR2 (RO) */
43180bb2ff7SRichard Henderson     case 0x06c0: /* DIR3 (RO) */
43280bb2ff7SRichard Henderson         break;
43380bb2ff7SRichard Henderson 
43480bb2ff7SRichard Henderson     case 0x0700: /* IIC2 */
43580bb2ff7SRichard Henderson         s->cchip.iic[2] = val & 0xffffff;
43680bb2ff7SRichard Henderson         break;
43780bb2ff7SRichard Henderson     case 0x0740: /* IIC3 */
43880bb2ff7SRichard Henderson         s->cchip.iic[3] = val & 0xffffff;
43980bb2ff7SRichard Henderson         break;
44080bb2ff7SRichard Henderson 
44180bb2ff7SRichard Henderson     case 0x0780:
44280bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
44380bb2ff7SRichard Henderson         break;
44480bb2ff7SRichard Henderson 
44580bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
44680bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
44780bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
44880bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
44980bb2ff7SRichard Henderson         break;
45080bb2ff7SRichard Henderson 
45180bb2ff7SRichard Henderson     default:
452b7ed683aSPeter Maydell         return MEMTX_ERROR;
45380bb2ff7SRichard Henderson     }
454b7ed683aSPeter Maydell 
455b7ed683aSPeter Maydell     return MEMTX_OK;
45680bb2ff7SRichard Henderson }
45780bb2ff7SRichard Henderson 
458a8170e5eSAvi Kivity static void dchip_write(void *opaque, hwaddr addr,
45980bb2ff7SRichard Henderson                         uint64_t val, unsigned size)
46080bb2ff7SRichard Henderson {
46180bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
46280bb2ff7SRichard Henderson }
46380bb2ff7SRichard Henderson 
464b7ed683aSPeter Maydell static MemTxResult pchip_write(void *opaque, hwaddr addr,
465b7ed683aSPeter Maydell                                uint64_t val, unsigned size,
466b7ed683aSPeter Maydell                                MemTxAttrs attrs)
46780bb2ff7SRichard Henderson {
46880bb2ff7SRichard Henderson     TyphoonState *s = opaque;
46967842165SRichard Henderson     uint64_t oldval;
47080bb2ff7SRichard Henderson 
47180bb2ff7SRichard Henderson     switch (addr) {
47280bb2ff7SRichard Henderson     case 0x0000:
47380bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
474b83c4db8SRichard Henderson         s->pchip.win[0].wba = val & 0xfff00003u;
47580bb2ff7SRichard Henderson         break;
47680bb2ff7SRichard Henderson     case 0x0040:
47780bb2ff7SRichard Henderson         /* WSBA1 */
478b83c4db8SRichard Henderson         s->pchip.win[1].wba = val & 0xfff00003u;
47980bb2ff7SRichard Henderson         break;
48080bb2ff7SRichard Henderson     case 0x0080:
48180bb2ff7SRichard Henderson         /* WSBA2 */
482b83c4db8SRichard Henderson         s->pchip.win[2].wba = val & 0xfff00003u;
48380bb2ff7SRichard Henderson         break;
48480bb2ff7SRichard Henderson     case 0x00c0:
48580bb2ff7SRichard Henderson         /* WSBA3 */
486b83c4db8SRichard Henderson         s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
48780bb2ff7SRichard Henderson         break;
48880bb2ff7SRichard Henderson 
48980bb2ff7SRichard Henderson     case 0x0100:
49080bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
491b83c4db8SRichard Henderson         s->pchip.win[0].wsm = val & 0xfff00000u;
49280bb2ff7SRichard Henderson         break;
49380bb2ff7SRichard Henderson     case 0x0140:
49480bb2ff7SRichard Henderson         /* WSM1 */
495b83c4db8SRichard Henderson         s->pchip.win[1].wsm = val & 0xfff00000u;
49680bb2ff7SRichard Henderson         break;
49780bb2ff7SRichard Henderson     case 0x0180:
49880bb2ff7SRichard Henderson         /* WSM2 */
499b83c4db8SRichard Henderson         s->pchip.win[2].wsm = val & 0xfff00000u;
50080bb2ff7SRichard Henderson         break;
50180bb2ff7SRichard Henderson     case 0x01c0:
50280bb2ff7SRichard Henderson         /* WSM3 */
503b83c4db8SRichard Henderson         s->pchip.win[3].wsm = val & 0xfff00000u;
50480bb2ff7SRichard Henderson         break;
50580bb2ff7SRichard Henderson 
50680bb2ff7SRichard Henderson     case 0x0200:
50780bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
508b83c4db8SRichard Henderson         s->pchip.win[0].tba = val & 0x7fffffc00ull;
50980bb2ff7SRichard Henderson         break;
51080bb2ff7SRichard Henderson     case 0x0240:
51180bb2ff7SRichard Henderson         /* TBA1 */
512b83c4db8SRichard Henderson         s->pchip.win[1].tba = val & 0x7fffffc00ull;
51380bb2ff7SRichard Henderson         break;
51480bb2ff7SRichard Henderson     case 0x0280:
51580bb2ff7SRichard Henderson         /* TBA2 */
516b83c4db8SRichard Henderson         s->pchip.win[2].tba = val & 0x7fffffc00ull;
51780bb2ff7SRichard Henderson         break;
51880bb2ff7SRichard Henderson     case 0x02c0:
51980bb2ff7SRichard Henderson         /* TBA3 */
520b83c4db8SRichard Henderson         s->pchip.win[3].tba = val & 0x7fffffc00ull;
52180bb2ff7SRichard Henderson         break;
52280bb2ff7SRichard Henderson 
52380bb2ff7SRichard Henderson     case 0x0300:
52480bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
52580bb2ff7SRichard Henderson         oldval = s->pchip.ctl;
52680bb2ff7SRichard Henderson         oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
52780bb2ff7SRichard Henderson         oldval |= val & 0x00001cff0fc7ffull;
52880bb2ff7SRichard Henderson         s->pchip.ctl = oldval;
52980bb2ff7SRichard Henderson         break;
53080bb2ff7SRichard Henderson 
53180bb2ff7SRichard Henderson     case 0x0340:
53280bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
53380bb2ff7SRichard Henderson         break;
53480bb2ff7SRichard Henderson     case 0x03c0:
53580bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
53680bb2ff7SRichard Henderson         break;
53780bb2ff7SRichard Henderson     case 0x0400:
53880bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
53980bb2ff7SRichard Henderson         break;
54080bb2ff7SRichard Henderson     case 0x0440:
54180bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
54280bb2ff7SRichard Henderson         break;
54380bb2ff7SRichard Henderson 
54480bb2ff7SRichard Henderson     case 0x0480:
54580bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
54680bb2ff7SRichard Henderson         break;
54780bb2ff7SRichard Henderson 
54880bb2ff7SRichard Henderson     case 0x04c0:
54980bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
55080bb2ff7SRichard Henderson         break;
55180bb2ff7SRichard Henderson 
55280bb2ff7SRichard Henderson     case 0x0500:
55380bb2ff7SRichard Henderson         /* PMONCTL */
55480bb2ff7SRichard Henderson     case 0x0540:
55580bb2ff7SRichard Henderson         /* PMONCNT */
55680bb2ff7SRichard Henderson     case 0x0800:
55780bb2ff7SRichard Henderson         /* SPRST */
55880bb2ff7SRichard Henderson         break;
55980bb2ff7SRichard Henderson 
56080bb2ff7SRichard Henderson     default:
561b7ed683aSPeter Maydell         return MEMTX_ERROR;
56280bb2ff7SRichard Henderson     }
563b7ed683aSPeter Maydell 
564b7ed683aSPeter Maydell     return MEMTX_OK;
56580bb2ff7SRichard Henderson }
56680bb2ff7SRichard Henderson 
56780bb2ff7SRichard Henderson static const MemoryRegionOps cchip_ops = {
568b7ed683aSPeter Maydell     .read_with_attrs = cchip_read,
569b7ed683aSPeter Maydell     .write_with_attrs = cchip_write,
57080bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
57180bb2ff7SRichard Henderson     .valid = {
57267842165SRichard Henderson         .min_access_size = 8,
57380bb2ff7SRichard Henderson         .max_access_size = 8,
57480bb2ff7SRichard Henderson     },
57580bb2ff7SRichard Henderson     .impl = {
57667842165SRichard Henderson         .min_access_size = 8,
57767842165SRichard Henderson         .max_access_size = 8,
57880bb2ff7SRichard Henderson     },
57980bb2ff7SRichard Henderson };
58080bb2ff7SRichard Henderson 
58180bb2ff7SRichard Henderson static const MemoryRegionOps dchip_ops = {
58280bb2ff7SRichard Henderson     .read = dchip_read,
58380bb2ff7SRichard Henderson     .write = dchip_write,
58480bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
58580bb2ff7SRichard Henderson     .valid = {
58667842165SRichard Henderson         .min_access_size = 8,
58780bb2ff7SRichard Henderson         .max_access_size = 8,
58880bb2ff7SRichard Henderson     },
58980bb2ff7SRichard Henderson     .impl = {
59067842165SRichard Henderson         .min_access_size = 8,
59180bb2ff7SRichard Henderson         .max_access_size = 8,
59280bb2ff7SRichard Henderson     },
59380bb2ff7SRichard Henderson };
59480bb2ff7SRichard Henderson 
59580bb2ff7SRichard Henderson static const MemoryRegionOps pchip_ops = {
596b7ed683aSPeter Maydell     .read_with_attrs = pchip_read,
597b7ed683aSPeter Maydell     .write_with_attrs = pchip_write,
59880bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
59980bb2ff7SRichard Henderson     .valid = {
60067842165SRichard Henderson         .min_access_size = 8,
60180bb2ff7SRichard Henderson         .max_access_size = 8,
60280bb2ff7SRichard Henderson     },
60380bb2ff7SRichard Henderson     .impl = {
60467842165SRichard Henderson         .min_access_size = 8,
60567842165SRichard Henderson         .max_access_size = 8,
60680bb2ff7SRichard Henderson     },
60780bb2ff7SRichard Henderson };
60880bb2ff7SRichard Henderson 
609b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
610b83c4db8SRichard Henderson    using the given translated address and mask.  */
611b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
612b83c4db8SRichard Henderson {
613b83c4db8SRichard Henderson     *ret = (IOMMUTLBEntry) {
614b83c4db8SRichard Henderson         .target_as = &address_space_memory,
615b83c4db8SRichard Henderson         .translated_addr = taddr,
616b83c4db8SRichard Henderson         .addr_mask = mask,
617b83c4db8SRichard Henderson         .perm = IOMMU_RW,
618b83c4db8SRichard Henderson     };
619b83c4db8SRichard Henderson     return true;
620b83c4db8SRichard Henderson }
621b83c4db8SRichard Henderson 
622b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather
623b83c4db8SRichard Henderson    translation, given the address of the PTE.  */
624b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
625b83c4db8SRichard Henderson {
62642874d3aSPeter Maydell     uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
62742874d3aSPeter Maydell                                      MEMTXATTRS_UNSPECIFIED, NULL);
628b83c4db8SRichard Henderson 
629b83c4db8SRichard Henderson     /* Check valid bit.  */
630b83c4db8SRichard Henderson     if ((pte & 1) == 0) {
631b83c4db8SRichard Henderson         return false;
632b83c4db8SRichard Henderson     }
633b83c4db8SRichard Henderson 
634b83c4db8SRichard Henderson     return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
635b83c4db8SRichard Henderson }
636b83c4db8SRichard Henderson 
637b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the
638b83c4db8SRichard Henderson    four single-address-cycle translation windows.  */
639b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr,
640b83c4db8SRichard Henderson                              IOMMUTLBEntry *ret)
641b83c4db8SRichard Henderson {
642b83c4db8SRichard Henderson     uint32_t wba = win->wba;
643b83c4db8SRichard Henderson     uint64_t wsm = win->wsm;
644b83c4db8SRichard Henderson     uint64_t tba = win->tba;
645b83c4db8SRichard Henderson     uint64_t wsm_ext = wsm | 0xfffff;
646b83c4db8SRichard Henderson 
647b83c4db8SRichard Henderson     /* Check for window disabled.  */
648b83c4db8SRichard Henderson     if ((wba & 1) == 0) {
649b83c4db8SRichard Henderson         return false;
650b83c4db8SRichard Henderson     }
651b83c4db8SRichard Henderson 
652b83c4db8SRichard Henderson     /* Check for window hit.  */
653b83c4db8SRichard Henderson     if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
654b83c4db8SRichard Henderson         return false;
655b83c4db8SRichard Henderson     }
656b83c4db8SRichard Henderson 
657b83c4db8SRichard Henderson     if (wba & 2) {
658b83c4db8SRichard Henderson         /* Scatter-gather translation.  */
659b83c4db8SRichard Henderson         hwaddr pte_addr;
660b83c4db8SRichard Henderson 
661b83c4db8SRichard Henderson         /* See table 10-6, Generating PTE address for PCI DMA Address.  */
662b83c4db8SRichard Henderson         pte_addr  = tba & ~(wsm >> 10);
663b83c4db8SRichard Henderson         pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
664b83c4db8SRichard Henderson         return pte_translate(pte_addr, ret);
665b83c4db8SRichard Henderson     } else {
666b83c4db8SRichard Henderson         /* Direct-mapped translation.  */
667b83c4db8SRichard Henderson         return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
668b83c4db8SRichard Henderson     }
669b83c4db8SRichard Henderson }
670b83c4db8SRichard Henderson 
671b83c4db8SRichard Henderson /* Handle PCI-to-system address translation.  */
672b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the
673b83c4db8SRichard Henderson    Pchip and generate a machine check interrupt.  */
6743df9d748SAlexey Kardashevskiy static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
6753df9d748SAlexey Kardashevskiy                                              hwaddr addr,
6762c91bcf2SPeter Maydell                                              IOMMUAccessFlags flag,
6772c91bcf2SPeter Maydell                                              int iommu_idx)
678b83c4db8SRichard Henderson {
679b83c4db8SRichard Henderson     TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
680b83c4db8SRichard Henderson     IOMMUTLBEntry ret;
681b83c4db8SRichard Henderson     int i;
682b83c4db8SRichard Henderson 
683b83c4db8SRichard Henderson     if (addr <= 0xffffffffu) {
684b83c4db8SRichard Henderson         /* Single-address cycle.  */
685b83c4db8SRichard Henderson 
686b83c4db8SRichard Henderson         /* Check for the Window Hole, inhibiting matching.  */
687b83c4db8SRichard Henderson         if ((pchip->ctl & 0x20)
688b83c4db8SRichard Henderson             && addr >= 0x80000
689b83c4db8SRichard Henderson             && addr <= 0xfffff) {
690b83c4db8SRichard Henderson             goto failure;
691b83c4db8SRichard Henderson         }
692b83c4db8SRichard Henderson 
693b83c4db8SRichard Henderson         /* Check the first three windows.  */
694b83c4db8SRichard Henderson         for (i = 0; i < 3; ++i) {
695b83c4db8SRichard Henderson             if (window_translate(&pchip->win[i], addr, &ret)) {
696b83c4db8SRichard Henderson                 goto success;
697b83c4db8SRichard Henderson             }
698b83c4db8SRichard Henderson         }
699b83c4db8SRichard Henderson 
700b83c4db8SRichard Henderson         /* Check the fourth window for DAC disable.  */
701b83c4db8SRichard Henderson         if ((pchip->win[3].wba & 0x80000000000ull) == 0
702b83c4db8SRichard Henderson             && window_translate(&pchip->win[3], addr, &ret)) {
703b83c4db8SRichard Henderson             goto success;
704b83c4db8SRichard Henderson         }
705b83c4db8SRichard Henderson     } else {
706b83c4db8SRichard Henderson         /* Double-address cycle.  */
707b83c4db8SRichard Henderson 
708b83c4db8SRichard Henderson         if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
709b83c4db8SRichard Henderson             /* Check for the DMA monster window.  */
710b83c4db8SRichard Henderson             if (pchip->ctl & 0x40) {
711b83c4db8SRichard Henderson                 /* See 10.1.4.4; in particular <39:35> is ignored.  */
712b83c4db8SRichard Henderson                 make_iommu_tlbe(0, 0x007ffffffffull, &ret);
713b83c4db8SRichard Henderson                 goto success;
714b83c4db8SRichard Henderson             }
715b83c4db8SRichard Henderson         }
716b83c4db8SRichard Henderson 
7179b2caaf4SStefan Weil         if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) {
718b83c4db8SRichard Henderson             /* Check the fourth window for DAC enable and window enable.  */
719b83c4db8SRichard Henderson             if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
720b83c4db8SRichard Henderson                 uint64_t pte_addr;
721b83c4db8SRichard Henderson 
722b83c4db8SRichard Henderson                 pte_addr  = pchip->win[3].tba & 0x7ffc00000ull;
723b83c4db8SRichard Henderson                 pte_addr |= (addr & 0xffffe000u) >> 10;
724b83c4db8SRichard Henderson                 if (pte_translate(pte_addr, &ret)) {
725b83c4db8SRichard Henderson                         goto success;
726b83c4db8SRichard Henderson                 }
727b83c4db8SRichard Henderson             }
728b83c4db8SRichard Henderson         }
729b83c4db8SRichard Henderson     }
730b83c4db8SRichard Henderson 
731b83c4db8SRichard Henderson  failure:
732b83c4db8SRichard Henderson     ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
733b83c4db8SRichard Henderson  success:
734b83c4db8SRichard Henderson     return ret;
735b83c4db8SRichard Henderson }
736b83c4db8SRichard Henderson 
737b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
738b83c4db8SRichard Henderson {
739b83c4db8SRichard Henderson     TyphoonState *s = opaque;
740b83c4db8SRichard Henderson     return &s->pchip.iommu_as;
741b83c4db8SRichard Henderson }
742b83c4db8SRichard Henderson 
74380bb2ff7SRichard Henderson static void typhoon_set_irq(void *opaque, int irq, int level)
74480bb2ff7SRichard Henderson {
74580bb2ff7SRichard Henderson     TyphoonState *s = opaque;
74680bb2ff7SRichard Henderson     uint64_t drir;
74780bb2ff7SRichard Henderson     int i;
74880bb2ff7SRichard Henderson 
74980bb2ff7SRichard Henderson     /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
75080bb2ff7SRichard Henderson     drir = s->cchip.drir;
75180bb2ff7SRichard Henderson     if (level) {
75280bb2ff7SRichard Henderson         drir |= 1ull << irq;
75380bb2ff7SRichard Henderson     } else {
75480bb2ff7SRichard Henderson         drir &= ~(1ull << irq);
75580bb2ff7SRichard Henderson     }
75680bb2ff7SRichard Henderson     s->cchip.drir = drir;
75780bb2ff7SRichard Henderson 
75880bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
75980bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
76080bb2ff7SRichard Henderson     }
76180bb2ff7SRichard Henderson }
76280bb2ff7SRichard Henderson 
76380bb2ff7SRichard Henderson static void typhoon_set_isa_irq(void *opaque, int irq, int level)
76480bb2ff7SRichard Henderson {
76580bb2ff7SRichard Henderson     typhoon_set_irq(opaque, 55, level);
76680bb2ff7SRichard Henderson }
76780bb2ff7SRichard Henderson 
76880bb2ff7SRichard Henderson static void typhoon_set_timer_irq(void *opaque, int irq, int level)
76980bb2ff7SRichard Henderson {
77080bb2ff7SRichard Henderson     TyphoonState *s = opaque;
77180bb2ff7SRichard Henderson     int i;
77280bb2ff7SRichard Henderson 
77380bb2ff7SRichard Henderson     /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
77480bb2ff7SRichard Henderson        and so we don't have to worry about missing interrupts just
77580bb2ff7SRichard Henderson        because we never actually ACK the interrupt.  Just ignore any
77680bb2ff7SRichard Henderson        case of the interrupt level going low.  */
77780bb2ff7SRichard Henderson     if (level == 0) {
77880bb2ff7SRichard Henderson         return;
77980bb2ff7SRichard Henderson     }
78080bb2ff7SRichard Henderson 
78180bb2ff7SRichard Henderson     /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
78280bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
783ad601177SAndreas Färber         AlphaCPU *cpu = s->cchip.cpu[i];
784ad601177SAndreas Färber         if (cpu != NULL) {
78580bb2ff7SRichard Henderson             uint32_t iic = s->cchip.iic[i];
78680bb2ff7SRichard Henderson 
78780bb2ff7SRichard Henderson             /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
78880bb2ff7SRichard Henderson                Bit 24 is the OverFlow bit, RO, and set when the count
78980bb2ff7SRichard Henderson                decrements past 0.  When is OF cleared?  My guess is that
79080bb2ff7SRichard Henderson                OF is actually cleared when the IIC is written, and that
79180bb2ff7SRichard Henderson                the ICNT field always decrements.  At least, that's an
79280bb2ff7SRichard Henderson                interpretation that makes sense, and "allows the CPU to
79380bb2ff7SRichard Henderson                determine exactly how mant interval timer ticks were
79480bb2ff7SRichard Henderson                skipped".  At least within the next 4M ticks...  */
79580bb2ff7SRichard Henderson 
79680bb2ff7SRichard Henderson             iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
79780bb2ff7SRichard Henderson             s->cchip.iic[i] = iic;
79880bb2ff7SRichard Henderson 
79980bb2ff7SRichard Henderson             if (iic & 0x1000000) {
80080bb2ff7SRichard Henderson                 /* Set the ITI bit for this cpu.  */
80180bb2ff7SRichard Henderson                 s->cchip.misc |= 1 << (i + 4);
80280bb2ff7SRichard Henderson                 /* And signal the interrupt.  */
803c3affe56SAndreas Färber                 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
80480bb2ff7SRichard Henderson             }
80580bb2ff7SRichard Henderson         }
80680bb2ff7SRichard Henderson     }
80780bb2ff7SRichard Henderson }
80880bb2ff7SRichard Henderson 
809c781cf96SRichard Henderson static void typhoon_alarm_timer(void *opaque)
810c781cf96SRichard Henderson {
811c781cf96SRichard Henderson     TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
812c781cf96SRichard Henderson     int cpu = (uintptr_t)opaque & 3;
813c781cf96SRichard Henderson 
814c781cf96SRichard Henderson     /* Set the ITI bit for this cpu.  */
815c781cf96SRichard Henderson     s->cchip.misc |= 1 << (cpu + 4);
816c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
817c781cf96SRichard Henderson }
818c781cf96SRichard Henderson 
819b844d822SIgor Mammedov PCIBus *typhoon_init(MemoryRegion *ram, ISABus **isa_bus, qemu_irq *p_rtc_irq,
820ad601177SAndreas Färber                      AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq)
82180bb2ff7SRichard Henderson {
82280bb2ff7SRichard Henderson     MemoryRegion *addr_space = get_system_memory();
82380bb2ff7SRichard Henderson     DeviceState *dev;
82480bb2ff7SRichard Henderson     TyphoonState *s;
82594dd91d6SAndreas Färber     PCIHostState *phb;
82680bb2ff7SRichard Henderson     PCIBus *b;
827c781cf96SRichard Henderson     int i;
82880bb2ff7SRichard Henderson 
8293e80f690SMarkus Armbruster     dev = qdev_new(TYPE_TYPHOON_PCI_HOST_BRIDGE);
83080bb2ff7SRichard Henderson 
83194dd91d6SAndreas Färber     s = TYPHOON_PCI_HOST_BRIDGE(dev);
8328558d942SAndreas Färber     phb = PCI_HOST_BRIDGE(dev);
83380bb2ff7SRichard Henderson 
834b83c4db8SRichard Henderson     s->cchip.misc = 0x800000000ull; /* Revision: Typhoon.  */
835b83c4db8SRichard Henderson     s->pchip.win[3].wba = 2;        /* Window 3 SG always enabled. */
836b83c4db8SRichard Henderson 
83780bb2ff7SRichard Henderson     /* Remember the CPUs so that we can deliver interrupts to them.  */
838c781cf96SRichard Henderson     for (i = 0; i < 4; i++) {
839ad601177SAndreas Färber         AlphaCPU *cpu = cpus[i];
840ad601177SAndreas Färber         s->cchip.cpu[i] = cpu;
841ad601177SAndreas Färber         if (cpu != NULL) {
842bc72ad67SAlex Bligh             cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
843c781cf96SRichard Henderson                                                  typhoon_alarm_timer,
844c781cf96SRichard Henderson                                                  (void *)((uintptr_t)s + i));
845c781cf96SRichard Henderson         }
846c781cf96SRichard Henderson     }
84780bb2ff7SRichard Henderson 
84854292736SShannon Zhao     *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
84980bb2ff7SRichard Henderson 
85080bb2ff7SRichard Henderson     /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
85180bb2ff7SRichard Henderson        but the address space hole reserved at this point is 8TB.  */
852b844d822SIgor Mammedov     memory_region_add_subregion(addr_space, 0, ram);
85380bb2ff7SRichard Henderson 
85480bb2ff7SRichard Henderson     /* TIGbus, 0x801.0000.0000, 1GB.  */
85580bb2ff7SRichard Henderson     /* ??? The TIGbus is used for delivering interrupts, and access to
85680bb2ff7SRichard Henderson        the flash ROM.  I'm not sure that we need to implement it at all.  */
85780bb2ff7SRichard Henderson 
85880bb2ff7SRichard Henderson     /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
85964bde0f3SPaolo Bonzini     memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
8602b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
86102d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80180000000ULL,
86202d6516cSStefan Weil                                 &s->pchip.region);
86380bb2ff7SRichard Henderson 
86480bb2ff7SRichard Henderson     /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
86564bde0f3SPaolo Bonzini     memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
8662b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
86702d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801a0000000ULL,
86802d6516cSStefan Weil                                 &s->cchip.region);
86980bb2ff7SRichard Henderson 
87080bb2ff7SRichard Henderson     /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
87164bde0f3SPaolo Bonzini     memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
8722b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
87302d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801b0000000ULL,
87402d6516cSStefan Weil                                 &s->dchip_region);
87580bb2ff7SRichard Henderson 
87680bb2ff7SRichard Henderson     /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
8772b41742aSPhilippe Mathieu-Daudé     memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4 * GiB);
87802d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80000000000ULL,
87902d6516cSStefan Weil                                 &s->pchip.reg_mem);
88080bb2ff7SRichard Henderson 
88180bb2ff7SRichard Henderson     /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
8823661049fSRichard Henderson     memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops,
8832b41742aSPhilippe Mathieu-Daudé                           NULL, "pci0-io", 32 * MiB);
88402d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fc000000ULL,
88502d6516cSStefan Weil                                 &s->pchip.reg_io);
88680bb2ff7SRichard Henderson 
8871115ff6dSDavid Gibson     b = pci_register_root_bus(dev, "pci",
88880bb2ff7SRichard Henderson                               typhoon_set_irq, sys_map_irq, s,
889056e6baeSRichard Henderson                               &s->pchip.reg_mem, &s->pchip.reg_io,
890056e6baeSRichard Henderson                               0, 64, TYPE_PCI_BUS);
89194dd91d6SAndreas Färber     phb->bus = b;
8923c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
89380bb2ff7SRichard Henderson 
894b83c4db8SRichard Henderson     /* Host memory as seen from the PCI side, via the IOMMU.  */
8951221a474SAlexey Kardashevskiy     memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu),
8961221a474SAlexey Kardashevskiy                              TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s),
897b83c4db8SRichard Henderson                              "iommu-typhoon", UINT64_MAX);
8983df9d748SAlexey Kardashevskiy     address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
8993df9d748SAlexey Kardashevskiy                        "pchip0-pci");
900b83c4db8SRichard Henderson     pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
901b83c4db8SRichard Henderson 
90280bb2ff7SRichard Henderson     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
903056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
9042b41742aSPhilippe Mathieu-Daudé                           b, "pci0-iack", 64 * MiB);
90502d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801f8000000ULL,
90602d6516cSStefan Weil                                 &s->pchip.reg_iack);
90780bb2ff7SRichard Henderson 
90880bb2ff7SRichard Henderson     /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
909056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
9102b41742aSPhilippe Mathieu-Daudé                           b, "pci0-conf", 16 * MiB);
91102d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fe000000ULL,
91202d6516cSStefan Weil                                 &s->pchip.reg_conf);
91380bb2ff7SRichard Henderson 
91480bb2ff7SRichard Henderson     /* For the record, these are the mappings for the second PCI bus.
91580bb2ff7SRichard Henderson        We can get away with not implementing them because we indicate
91680bb2ff7SRichard Henderson        via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
91780bb2ff7SRichard Henderson     /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
91880bb2ff7SRichard Henderson     /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
91980bb2ff7SRichard Henderson     /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
92080bb2ff7SRichard Henderson     /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
92180bb2ff7SRichard Henderson     /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
92280bb2ff7SRichard Henderson 
92380bb2ff7SRichard Henderson     /* Init the ISA bus.  */
92480bb2ff7SRichard Henderson     /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
92580bb2ff7SRichard Henderson     {
92654292736SShannon Zhao         qemu_irq *isa_irqs;
92780bb2ff7SRichard Henderson 
928d10e5432SMarkus Armbruster         *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io,
929d10e5432SMarkus Armbruster                                &error_abort);
93054292736SShannon Zhao         isa_irqs = i8259_init(*isa_bus,
93154292736SShannon Zhao                               qemu_allocate_irq(typhoon_set_isa_irq, s, 0));
93271baa303SHervé Poussineau         isa_bus_irqs(*isa_bus, isa_irqs);
93380bb2ff7SRichard Henderson     }
93480bb2ff7SRichard Henderson 
93580bb2ff7SRichard Henderson     return b;
93680bb2ff7SRichard Henderson }
93780bb2ff7SRichard Henderson 
9384240abffSAndreas Färber static const TypeInfo typhoon_pcihost_info = {
93994dd91d6SAndreas Färber     .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
9408558d942SAndreas Färber     .parent        = TYPE_PCI_HOST_BRIDGE,
94139bffca2SAnthony Liguori     .instance_size = sizeof(TyphoonState),
94280bb2ff7SRichard Henderson };
94380bb2ff7SRichard Henderson 
9441221a474SAlexey Kardashevskiy static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
9451221a474SAlexey Kardashevskiy                                                    void *data)
9461221a474SAlexey Kardashevskiy {
9471221a474SAlexey Kardashevskiy     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
9481221a474SAlexey Kardashevskiy 
9491221a474SAlexey Kardashevskiy     imrc->translate = typhoon_translate_iommu;
9501221a474SAlexey Kardashevskiy }
9511221a474SAlexey Kardashevskiy 
9521221a474SAlexey Kardashevskiy static const TypeInfo typhoon_iommu_memory_region_info = {
9531221a474SAlexey Kardashevskiy     .parent = TYPE_IOMMU_MEMORY_REGION,
9541221a474SAlexey Kardashevskiy     .name = TYPE_TYPHOON_IOMMU_MEMORY_REGION,
9551221a474SAlexey Kardashevskiy     .class_init = typhoon_iommu_memory_region_class_init,
9561221a474SAlexey Kardashevskiy };
9571221a474SAlexey Kardashevskiy 
95883f7d43aSAndreas Färber static void typhoon_register_types(void)
95980bb2ff7SRichard Henderson {
96039bffca2SAnthony Liguori     type_register_static(&typhoon_pcihost_info);
9611221a474SAlexey Kardashevskiy     type_register_static(&typhoon_iommu_memory_region_info);
96280bb2ff7SRichard Henderson }
96383f7d43aSAndreas Färber 
96483f7d43aSAndreas Färber type_init(typhoon_register_types)
965