xref: /qemu/hw/alpha/typhoon.c (revision db1015e92e04835c9eb50c29625fe566d1202dbd)
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"
18*db1015e9SEduardo 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*db1015e9SEduardo Habkost typedef struct TyphoonState TyphoonState;
5494dd91d6SAndreas Färber #define TYPHOON_PCI_HOST_BRIDGE(obj) \
5594dd91d6SAndreas Färber     OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE)
5694dd91d6SAndreas Färber 
57*db1015e9SEduardo Habkost struct TyphoonState {
5867c332fdSAndreas Färber     PCIHostState parent_obj;
5994dd91d6SAndreas Färber 
6080bb2ff7SRichard Henderson     TyphoonCchip cchip;
6180bb2ff7SRichard Henderson     TyphoonPchip pchip;
6280bb2ff7SRichard Henderson     MemoryRegion dchip_region;
63*db1015e9SEduardo Habkost };
6480bb2ff7SRichard Henderson 
6580bb2ff7SRichard Henderson /* Called when one of DRIR or DIM changes.  */
66ad601177SAndreas Färber static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
6780bb2ff7SRichard Henderson {
6880bb2ff7SRichard Henderson     /* If there are any non-masked interrupts, tell the cpu.  */
69ad601177SAndreas Färber     if (cpu != NULL) {
70d8ed887bSAndreas Färber         CPUState *cs = CPU(cpu);
7180bb2ff7SRichard Henderson         if (req) {
72c3affe56SAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
7380bb2ff7SRichard Henderson         } else {
74d8ed887bSAndreas Färber             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
7580bb2ff7SRichard Henderson         }
7680bb2ff7SRichard Henderson     }
7780bb2ff7SRichard Henderson }
7880bb2ff7SRichard Henderson 
79b7ed683aSPeter Maydell static MemTxResult cchip_read(void *opaque, hwaddr addr,
80b7ed683aSPeter Maydell                               uint64_t *data, unsigned size,
81b7ed683aSPeter Maydell                               MemTxAttrs attrs)
8280bb2ff7SRichard Henderson {
834917cf44SAndreas Färber     CPUState *cpu = current_cpu;
8480bb2ff7SRichard Henderson     TyphoonState *s = opaque;
8580bb2ff7SRichard Henderson     uint64_t ret = 0;
8680bb2ff7SRichard Henderson 
8780bb2ff7SRichard Henderson     switch (addr) {
8880bb2ff7SRichard Henderson     case 0x0000:
8980bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
9080bb2ff7SRichard Henderson         /* All sorts of data here; probably the only thing relevant is
9180bb2ff7SRichard Henderson            PIP<14> Pchip 1 Present = 0.  */
9280bb2ff7SRichard Henderson         break;
9380bb2ff7SRichard Henderson 
9480bb2ff7SRichard Henderson     case 0x0040:
9580bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
9680bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
9780bb2ff7SRichard Henderson         break;
9880bb2ff7SRichard Henderson 
9980bb2ff7SRichard Henderson     case 0x0080:
10080bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
10155e5c285SAndreas Färber         ret = s->cchip.misc | (cpu->cpu_index & 3);
10280bb2ff7SRichard Henderson         break;
10380bb2ff7SRichard Henderson 
10480bb2ff7SRichard Henderson     case 0x00c0:
10580bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
10680bb2ff7SRichard Henderson         break;
10780bb2ff7SRichard Henderson 
10880bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
10980bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
11080bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
11180bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
11280bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
11380bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
11480bb2ff7SRichard Henderson         break;
11580bb2ff7SRichard Henderson 
11680bb2ff7SRichard Henderson     case 0x0200:
11780bb2ff7SRichard Henderson         /* DIM0: Device Interrupt Mask Register, CPU0.  */
11880bb2ff7SRichard Henderson         ret = s->cchip.dim[0];
11980bb2ff7SRichard Henderson         break;
12080bb2ff7SRichard Henderson     case 0x0240:
12180bb2ff7SRichard Henderson         /* DIM1: Device Interrupt Mask Register, CPU1.  */
12280bb2ff7SRichard Henderson         ret = s->cchip.dim[1];
12380bb2ff7SRichard Henderson         break;
12480bb2ff7SRichard Henderson     case 0x0280:
12580bb2ff7SRichard Henderson         /* DIR0: Device Interrupt Request Register, CPU0.  */
12680bb2ff7SRichard Henderson         ret = s->cchip.dim[0] & s->cchip.drir;
12780bb2ff7SRichard Henderson         break;
12880bb2ff7SRichard Henderson     case 0x02c0:
12980bb2ff7SRichard Henderson         /* DIR1: Device Interrupt Request Register, CPU1.  */
13080bb2ff7SRichard Henderson         ret = s->cchip.dim[1] & s->cchip.drir;
13180bb2ff7SRichard Henderson         break;
13280bb2ff7SRichard Henderson     case 0x0300:
13380bb2ff7SRichard Henderson         /* DRIR: Device Raw Interrupt Request Register.  */
13480bb2ff7SRichard Henderson         ret = s->cchip.drir;
13580bb2ff7SRichard Henderson         break;
13680bb2ff7SRichard Henderson 
13780bb2ff7SRichard Henderson     case 0x0340:
13880bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
13980bb2ff7SRichard Henderson         break;
14080bb2ff7SRichard Henderson 
14180bb2ff7SRichard Henderson     case 0x0380:
14280bb2ff7SRichard Henderson         /* IIC0: Interval Ignore Count Register, CPU0.  */
14380bb2ff7SRichard Henderson         ret = s->cchip.iic[0];
14480bb2ff7SRichard Henderson         break;
14580bb2ff7SRichard Henderson     case 0x03c0:
14680bb2ff7SRichard Henderson         /* IIC1: Interval Ignore Count Register, CPU1.  */
14780bb2ff7SRichard Henderson         ret = s->cchip.iic[1];
14880bb2ff7SRichard Henderson         break;
14980bb2ff7SRichard Henderson 
15080bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
15180bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
15280bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
15380bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
15480bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
15580bb2ff7SRichard Henderson         break;
15680bb2ff7SRichard Henderson 
15780bb2ff7SRichard Henderson     case 0x0580:
15880bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
15980bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
16080bb2ff7SRichard Henderson         break;
16180bb2ff7SRichard Henderson     case 0x05c0:
16280bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
16380bb2ff7SRichard Henderson         break;
16480bb2ff7SRichard Henderson 
16580bb2ff7SRichard Henderson     case 0x0600:
16680bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
16780bb2ff7SRichard Henderson         ret = s->cchip.dim[2];
16880bb2ff7SRichard Henderson         break;
16980bb2ff7SRichard Henderson     case 0x0640:
17080bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
17180bb2ff7SRichard Henderson         ret = s->cchip.dim[3];
17280bb2ff7SRichard Henderson         break;
17380bb2ff7SRichard Henderson     case 0x0680:
17480bb2ff7SRichard Henderson         /* DIR2: Device Interrupt Request Register, CPU2.  */
17580bb2ff7SRichard Henderson         ret = s->cchip.dim[2] & s->cchip.drir;
17680bb2ff7SRichard Henderson         break;
17780bb2ff7SRichard Henderson     case 0x06c0:
17880bb2ff7SRichard Henderson         /* DIR3: Device Interrupt Request Register, CPU3.  */
17980bb2ff7SRichard Henderson         ret = s->cchip.dim[3] & s->cchip.drir;
18080bb2ff7SRichard Henderson         break;
18180bb2ff7SRichard Henderson 
18280bb2ff7SRichard Henderson     case 0x0700:
18380bb2ff7SRichard Henderson         /* IIC2: Interval Ignore Count Register, CPU2.  */
18480bb2ff7SRichard Henderson         ret = s->cchip.iic[2];
18580bb2ff7SRichard Henderson         break;
18680bb2ff7SRichard Henderson     case 0x0740:
18780bb2ff7SRichard Henderson         /* IIC3: Interval Ignore Count Register, CPU3.  */
18880bb2ff7SRichard Henderson         ret = s->cchip.iic[3];
18980bb2ff7SRichard Henderson         break;
19080bb2ff7SRichard Henderson 
19180bb2ff7SRichard Henderson     case 0x0780:
19280bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
19380bb2ff7SRichard Henderson         break;
19480bb2ff7SRichard Henderson 
19580bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
19680bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
19780bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
19880bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
19980bb2ff7SRichard Henderson         break;
20080bb2ff7SRichard Henderson 
20180bb2ff7SRichard Henderson     default:
202b7ed683aSPeter Maydell         return MEMTX_ERROR;
20380bb2ff7SRichard Henderson     }
20480bb2ff7SRichard Henderson 
205b7ed683aSPeter Maydell     *data = ret;
206b7ed683aSPeter Maydell     return MEMTX_OK;
20780bb2ff7SRichard Henderson }
20880bb2ff7SRichard Henderson 
209a8170e5eSAvi Kivity static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
21080bb2ff7SRichard Henderson {
21180bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
21280bb2ff7SRichard Henderson     return 0;
21380bb2ff7SRichard Henderson }
21480bb2ff7SRichard Henderson 
215b7ed683aSPeter Maydell static MemTxResult pchip_read(void *opaque, hwaddr addr, uint64_t *data,
216b7ed683aSPeter Maydell                               unsigned size, MemTxAttrs attrs)
21780bb2ff7SRichard Henderson {
21880bb2ff7SRichard Henderson     TyphoonState *s = opaque;
21980bb2ff7SRichard Henderson     uint64_t ret = 0;
22080bb2ff7SRichard Henderson 
22180bb2ff7SRichard Henderson     switch (addr) {
22280bb2ff7SRichard Henderson     case 0x0000:
22380bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
224b83c4db8SRichard Henderson         ret = s->pchip.win[0].wba;
22580bb2ff7SRichard Henderson         break;
22680bb2ff7SRichard Henderson     case 0x0040:
22780bb2ff7SRichard Henderson         /* WSBA1 */
228b83c4db8SRichard Henderson         ret = s->pchip.win[1].wba;
22980bb2ff7SRichard Henderson         break;
23080bb2ff7SRichard Henderson     case 0x0080:
23180bb2ff7SRichard Henderson         /* WSBA2 */
232b83c4db8SRichard Henderson         ret = s->pchip.win[2].wba;
23380bb2ff7SRichard Henderson         break;
23480bb2ff7SRichard Henderson     case 0x00c0:
23580bb2ff7SRichard Henderson         /* WSBA3 */
236b83c4db8SRichard Henderson         ret = s->pchip.win[3].wba;
23780bb2ff7SRichard Henderson         break;
23880bb2ff7SRichard Henderson 
23980bb2ff7SRichard Henderson     case 0x0100:
24080bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
241b83c4db8SRichard Henderson         ret = s->pchip.win[0].wsm;
24280bb2ff7SRichard Henderson         break;
24380bb2ff7SRichard Henderson     case 0x0140:
24480bb2ff7SRichard Henderson         /* WSM1 */
245b83c4db8SRichard Henderson         ret = s->pchip.win[1].wsm;
24680bb2ff7SRichard Henderson         break;
24780bb2ff7SRichard Henderson     case 0x0180:
24880bb2ff7SRichard Henderson         /* WSM2 */
249b83c4db8SRichard Henderson         ret = s->pchip.win[2].wsm;
25080bb2ff7SRichard Henderson         break;
25180bb2ff7SRichard Henderson     case 0x01c0:
25280bb2ff7SRichard Henderson         /* WSM3 */
253b83c4db8SRichard Henderson         ret = s->pchip.win[3].wsm;
25480bb2ff7SRichard Henderson         break;
25580bb2ff7SRichard Henderson 
25680bb2ff7SRichard Henderson     case 0x0200:
25780bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
258b83c4db8SRichard Henderson         ret = s->pchip.win[0].tba;
25980bb2ff7SRichard Henderson         break;
26080bb2ff7SRichard Henderson     case 0x0240:
26180bb2ff7SRichard Henderson         /* TBA1 */
262b83c4db8SRichard Henderson         ret = s->pchip.win[1].tba;
26380bb2ff7SRichard Henderson         break;
26480bb2ff7SRichard Henderson     case 0x0280:
26580bb2ff7SRichard Henderson         /* TBA2 */
266b83c4db8SRichard Henderson         ret = s->pchip.win[2].tba;
26780bb2ff7SRichard Henderson         break;
26880bb2ff7SRichard Henderson     case 0x02c0:
26980bb2ff7SRichard Henderson         /* TBA3 */
270b83c4db8SRichard Henderson         ret = s->pchip.win[3].tba;
27180bb2ff7SRichard Henderson         break;
27280bb2ff7SRichard Henderson 
27380bb2ff7SRichard Henderson     case 0x0300:
27480bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
27580bb2ff7SRichard Henderson         ret = s->pchip.ctl;
27680bb2ff7SRichard Henderson         break;
27780bb2ff7SRichard Henderson     case 0x0340:
27880bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
27980bb2ff7SRichard Henderson         break;
28080bb2ff7SRichard Henderson     case 0x03c0:
28180bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
28280bb2ff7SRichard Henderson         break;
28380bb2ff7SRichard Henderson     case 0x0400:
28480bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
28580bb2ff7SRichard Henderson         break;
28680bb2ff7SRichard Henderson     case 0x0440:
28780bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
28880bb2ff7SRichard Henderson         break;
28980bb2ff7SRichard Henderson     case 0x0480:
29080bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
29180bb2ff7SRichard Henderson         break;
29280bb2ff7SRichard Henderson     case 0x04c0:
29380bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
29480bb2ff7SRichard Henderson         break;
29580bb2ff7SRichard Henderson     case 0x0500: /* PMONCTL */
29680bb2ff7SRichard Henderson     case 0x0540: /* PMONCNT */
29780bb2ff7SRichard Henderson     case 0x0800: /* SPRST */
29880bb2ff7SRichard Henderson         break;
29980bb2ff7SRichard Henderson 
30080bb2ff7SRichard Henderson     default:
301b7ed683aSPeter Maydell         return MEMTX_ERROR;
30280bb2ff7SRichard Henderson     }
30380bb2ff7SRichard Henderson 
304b7ed683aSPeter Maydell     *data = ret;
305b7ed683aSPeter Maydell     return MEMTX_OK;
30680bb2ff7SRichard Henderson }
30780bb2ff7SRichard Henderson 
308b7ed683aSPeter Maydell static MemTxResult cchip_write(void *opaque, hwaddr addr,
309b7ed683aSPeter Maydell                                uint64_t val, unsigned size,
310b7ed683aSPeter Maydell                                MemTxAttrs attrs)
31180bb2ff7SRichard Henderson {
31280bb2ff7SRichard Henderson     TyphoonState *s = opaque;
31367842165SRichard Henderson     uint64_t oldval, newval;
31480bb2ff7SRichard Henderson 
31580bb2ff7SRichard Henderson     switch (addr) {
31680bb2ff7SRichard Henderson     case 0x0000:
31780bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
31880bb2ff7SRichard Henderson         /* All sorts of data here; nothing relevant RW.  */
31980bb2ff7SRichard Henderson         break;
32080bb2ff7SRichard Henderson 
32180bb2ff7SRichard Henderson     case 0x0040:
32280bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
32380bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
32480bb2ff7SRichard Henderson         break;
32580bb2ff7SRichard Henderson 
32680bb2ff7SRichard Henderson     case 0x0080:
32780bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
32880bb2ff7SRichard Henderson         newval = oldval = s->cchip.misc;
32980bb2ff7SRichard Henderson         newval &= ~(val & 0x10000ff0);     /* W1C fields */
33080bb2ff7SRichard Henderson         if (val & 0x100000) {
33180bb2ff7SRichard Henderson             newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
33280bb2ff7SRichard Henderson         } else {
33380bb2ff7SRichard Henderson             newval |= val & 0x00f00000;    /* ABT field is W1S */
33480bb2ff7SRichard Henderson             if ((newval & 0xf0000) == 0) {
33580bb2ff7SRichard Henderson                 newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
33680bb2ff7SRichard Henderson             }
33780bb2ff7SRichard Henderson         }
33880bb2ff7SRichard Henderson         newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
33980bb2ff7SRichard Henderson 
34080bb2ff7SRichard Henderson         newval &= ~0xf0000000000ull;       /* WO and RW fields */
34180bb2ff7SRichard Henderson         newval |= val & 0xf0000000000ull;
34280bb2ff7SRichard Henderson         s->cchip.misc = newval;
34380bb2ff7SRichard Henderson 
34480bb2ff7SRichard Henderson         /* Pass on changes to IPI and ITI state.  */
34580bb2ff7SRichard Henderson         if ((newval ^ oldval) & 0xff0) {
34680bb2ff7SRichard Henderson             int i;
34780bb2ff7SRichard Henderson             for (i = 0; i < 4; ++i) {
348ad601177SAndreas Färber                 AlphaCPU *cpu = s->cchip.cpu[i];
349ad601177SAndreas Färber                 if (cpu != NULL) {
350d8ed887bSAndreas Färber                     CPUState *cs = CPU(cpu);
35180bb2ff7SRichard Henderson                     /* IPI can be either cleared or set by the write.  */
35280bb2ff7SRichard Henderson                     if (newval & (1 << (i + 8))) {
353c3affe56SAndreas Färber                         cpu_interrupt(cs, CPU_INTERRUPT_SMP);
35480bb2ff7SRichard Henderson                     } else {
355d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
35680bb2ff7SRichard Henderson                     }
35780bb2ff7SRichard Henderson 
35880bb2ff7SRichard Henderson                     /* ITI can only be cleared by the write.  */
35980bb2ff7SRichard Henderson                     if ((newval & (1 << (i + 4))) == 0) {
360d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
36180bb2ff7SRichard Henderson                     }
36280bb2ff7SRichard Henderson                 }
36380bb2ff7SRichard Henderson             }
36480bb2ff7SRichard Henderson         }
36580bb2ff7SRichard Henderson         break;
36680bb2ff7SRichard Henderson 
36780bb2ff7SRichard Henderson     case 0x00c0:
36880bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
36980bb2ff7SRichard Henderson         break;
37080bb2ff7SRichard Henderson 
37180bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
37280bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
37380bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
37480bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
37580bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
37680bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
37780bb2ff7SRichard Henderson         break;
37880bb2ff7SRichard Henderson 
37980bb2ff7SRichard Henderson     case 0x0200: /* DIM0 */
38080bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU0.  */
38180bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
38280bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
38380bb2ff7SRichard Henderson         break;
38480bb2ff7SRichard Henderson     case 0x0240: /* DIM1 */
38580bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU1.  */
386424ad838SRichard Henderson         s->cchip.dim[1] = val;
38780bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
38880bb2ff7SRichard Henderson         break;
38980bb2ff7SRichard Henderson 
39080bb2ff7SRichard Henderson     case 0x0280: /* DIR0 (RO) */
39180bb2ff7SRichard Henderson     case 0x02c0: /* DIR1 (RO) */
39280bb2ff7SRichard Henderson     case 0x0300: /* DRIR (RO) */
39380bb2ff7SRichard Henderson         break;
39480bb2ff7SRichard Henderson 
39580bb2ff7SRichard Henderson     case 0x0340:
39680bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
39780bb2ff7SRichard Henderson         break;
39880bb2ff7SRichard Henderson 
39980bb2ff7SRichard Henderson     case 0x0380: /* IIC0 */
40080bb2ff7SRichard Henderson         s->cchip.iic[0] = val & 0xffffff;
40180bb2ff7SRichard Henderson         break;
40280bb2ff7SRichard Henderson     case 0x03c0: /* IIC1 */
40380bb2ff7SRichard Henderson         s->cchip.iic[1] = val & 0xffffff;
40480bb2ff7SRichard Henderson         break;
40580bb2ff7SRichard Henderson 
40680bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
40780bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
40880bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
40980bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
41080bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
41180bb2ff7SRichard Henderson         break;
41280bb2ff7SRichard Henderson 
41380bb2ff7SRichard Henderson     case 0x0580:
41480bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
41580bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
41680bb2ff7SRichard Henderson         break;
41780bb2ff7SRichard Henderson     case 0x05c0:
41880bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
41980bb2ff7SRichard Henderson         break;
42080bb2ff7SRichard Henderson 
42180bb2ff7SRichard Henderson     case 0x0600:
42280bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
42380bb2ff7SRichard Henderson         s->cchip.dim[2] = val;
42480bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
42580bb2ff7SRichard Henderson         break;
42680bb2ff7SRichard Henderson     case 0x0640:
42780bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
42880bb2ff7SRichard Henderson         s->cchip.dim[3] = val;
42980bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
43080bb2ff7SRichard Henderson         break;
43180bb2ff7SRichard Henderson 
43280bb2ff7SRichard Henderson     case 0x0680: /* DIR2 (RO) */
43380bb2ff7SRichard Henderson     case 0x06c0: /* DIR3 (RO) */
43480bb2ff7SRichard Henderson         break;
43580bb2ff7SRichard Henderson 
43680bb2ff7SRichard Henderson     case 0x0700: /* IIC2 */
43780bb2ff7SRichard Henderson         s->cchip.iic[2] = val & 0xffffff;
43880bb2ff7SRichard Henderson         break;
43980bb2ff7SRichard Henderson     case 0x0740: /* IIC3 */
44080bb2ff7SRichard Henderson         s->cchip.iic[3] = val & 0xffffff;
44180bb2ff7SRichard Henderson         break;
44280bb2ff7SRichard Henderson 
44380bb2ff7SRichard Henderson     case 0x0780:
44480bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
44580bb2ff7SRichard Henderson         break;
44680bb2ff7SRichard Henderson 
44780bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
44880bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
44980bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
45080bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
45180bb2ff7SRichard Henderson         break;
45280bb2ff7SRichard Henderson 
45380bb2ff7SRichard Henderson     default:
454b7ed683aSPeter Maydell         return MEMTX_ERROR;
45580bb2ff7SRichard Henderson     }
456b7ed683aSPeter Maydell 
457b7ed683aSPeter Maydell     return MEMTX_OK;
45880bb2ff7SRichard Henderson }
45980bb2ff7SRichard Henderson 
460a8170e5eSAvi Kivity static void dchip_write(void *opaque, hwaddr addr,
46180bb2ff7SRichard Henderson                         uint64_t val, unsigned size)
46280bb2ff7SRichard Henderson {
46380bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
46480bb2ff7SRichard Henderson }
46580bb2ff7SRichard Henderson 
466b7ed683aSPeter Maydell static MemTxResult pchip_write(void *opaque, hwaddr addr,
467b7ed683aSPeter Maydell                                uint64_t val, unsigned size,
468b7ed683aSPeter Maydell                                MemTxAttrs attrs)
46980bb2ff7SRichard Henderson {
47080bb2ff7SRichard Henderson     TyphoonState *s = opaque;
47167842165SRichard Henderson     uint64_t oldval;
47280bb2ff7SRichard Henderson 
47380bb2ff7SRichard Henderson     switch (addr) {
47480bb2ff7SRichard Henderson     case 0x0000:
47580bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
476b83c4db8SRichard Henderson         s->pchip.win[0].wba = val & 0xfff00003u;
47780bb2ff7SRichard Henderson         break;
47880bb2ff7SRichard Henderson     case 0x0040:
47980bb2ff7SRichard Henderson         /* WSBA1 */
480b83c4db8SRichard Henderson         s->pchip.win[1].wba = val & 0xfff00003u;
48180bb2ff7SRichard Henderson         break;
48280bb2ff7SRichard Henderson     case 0x0080:
48380bb2ff7SRichard Henderson         /* WSBA2 */
484b83c4db8SRichard Henderson         s->pchip.win[2].wba = val & 0xfff00003u;
48580bb2ff7SRichard Henderson         break;
48680bb2ff7SRichard Henderson     case 0x00c0:
48780bb2ff7SRichard Henderson         /* WSBA3 */
488b83c4db8SRichard Henderson         s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
48980bb2ff7SRichard Henderson         break;
49080bb2ff7SRichard Henderson 
49180bb2ff7SRichard Henderson     case 0x0100:
49280bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
493b83c4db8SRichard Henderson         s->pchip.win[0].wsm = val & 0xfff00000u;
49480bb2ff7SRichard Henderson         break;
49580bb2ff7SRichard Henderson     case 0x0140:
49680bb2ff7SRichard Henderson         /* WSM1 */
497b83c4db8SRichard Henderson         s->pchip.win[1].wsm = val & 0xfff00000u;
49880bb2ff7SRichard Henderson         break;
49980bb2ff7SRichard Henderson     case 0x0180:
50080bb2ff7SRichard Henderson         /* WSM2 */
501b83c4db8SRichard Henderson         s->pchip.win[2].wsm = val & 0xfff00000u;
50280bb2ff7SRichard Henderson         break;
50380bb2ff7SRichard Henderson     case 0x01c0:
50480bb2ff7SRichard Henderson         /* WSM3 */
505b83c4db8SRichard Henderson         s->pchip.win[3].wsm = val & 0xfff00000u;
50680bb2ff7SRichard Henderson         break;
50780bb2ff7SRichard Henderson 
50880bb2ff7SRichard Henderson     case 0x0200:
50980bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
510b83c4db8SRichard Henderson         s->pchip.win[0].tba = val & 0x7fffffc00ull;
51180bb2ff7SRichard Henderson         break;
51280bb2ff7SRichard Henderson     case 0x0240:
51380bb2ff7SRichard Henderson         /* TBA1 */
514b83c4db8SRichard Henderson         s->pchip.win[1].tba = val & 0x7fffffc00ull;
51580bb2ff7SRichard Henderson         break;
51680bb2ff7SRichard Henderson     case 0x0280:
51780bb2ff7SRichard Henderson         /* TBA2 */
518b83c4db8SRichard Henderson         s->pchip.win[2].tba = val & 0x7fffffc00ull;
51980bb2ff7SRichard Henderson         break;
52080bb2ff7SRichard Henderson     case 0x02c0:
52180bb2ff7SRichard Henderson         /* TBA3 */
522b83c4db8SRichard Henderson         s->pchip.win[3].tba = val & 0x7fffffc00ull;
52380bb2ff7SRichard Henderson         break;
52480bb2ff7SRichard Henderson 
52580bb2ff7SRichard Henderson     case 0x0300:
52680bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
52780bb2ff7SRichard Henderson         oldval = s->pchip.ctl;
52880bb2ff7SRichard Henderson         oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
52980bb2ff7SRichard Henderson         oldval |= val & 0x00001cff0fc7ffull;
53080bb2ff7SRichard Henderson         s->pchip.ctl = oldval;
53180bb2ff7SRichard Henderson         break;
53280bb2ff7SRichard Henderson 
53380bb2ff7SRichard Henderson     case 0x0340:
53480bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
53580bb2ff7SRichard Henderson         break;
53680bb2ff7SRichard Henderson     case 0x03c0:
53780bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
53880bb2ff7SRichard Henderson         break;
53980bb2ff7SRichard Henderson     case 0x0400:
54080bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
54180bb2ff7SRichard Henderson         break;
54280bb2ff7SRichard Henderson     case 0x0440:
54380bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
54480bb2ff7SRichard Henderson         break;
54580bb2ff7SRichard Henderson 
54680bb2ff7SRichard Henderson     case 0x0480:
54780bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
54880bb2ff7SRichard Henderson         break;
54980bb2ff7SRichard Henderson 
55080bb2ff7SRichard Henderson     case 0x04c0:
55180bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
55280bb2ff7SRichard Henderson         break;
55380bb2ff7SRichard Henderson 
55480bb2ff7SRichard Henderson     case 0x0500:
55580bb2ff7SRichard Henderson         /* PMONCTL */
55680bb2ff7SRichard Henderson     case 0x0540:
55780bb2ff7SRichard Henderson         /* PMONCNT */
55880bb2ff7SRichard Henderson     case 0x0800:
55980bb2ff7SRichard Henderson         /* SPRST */
56080bb2ff7SRichard Henderson         break;
56180bb2ff7SRichard Henderson 
56280bb2ff7SRichard Henderson     default:
563b7ed683aSPeter Maydell         return MEMTX_ERROR;
56480bb2ff7SRichard Henderson     }
565b7ed683aSPeter Maydell 
566b7ed683aSPeter Maydell     return MEMTX_OK;
56780bb2ff7SRichard Henderson }
56880bb2ff7SRichard Henderson 
56980bb2ff7SRichard Henderson static const MemoryRegionOps cchip_ops = {
570b7ed683aSPeter Maydell     .read_with_attrs = cchip_read,
571b7ed683aSPeter Maydell     .write_with_attrs = cchip_write,
57280bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
57380bb2ff7SRichard Henderson     .valid = {
57467842165SRichard Henderson         .min_access_size = 8,
57580bb2ff7SRichard Henderson         .max_access_size = 8,
57680bb2ff7SRichard Henderson     },
57780bb2ff7SRichard Henderson     .impl = {
57867842165SRichard Henderson         .min_access_size = 8,
57967842165SRichard Henderson         .max_access_size = 8,
58080bb2ff7SRichard Henderson     },
58180bb2ff7SRichard Henderson };
58280bb2ff7SRichard Henderson 
58380bb2ff7SRichard Henderson static const MemoryRegionOps dchip_ops = {
58480bb2ff7SRichard Henderson     .read = dchip_read,
58580bb2ff7SRichard Henderson     .write = dchip_write,
58680bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
58780bb2ff7SRichard Henderson     .valid = {
58867842165SRichard Henderson         .min_access_size = 8,
58980bb2ff7SRichard Henderson         .max_access_size = 8,
59080bb2ff7SRichard Henderson     },
59180bb2ff7SRichard Henderson     .impl = {
59267842165SRichard Henderson         .min_access_size = 8,
59380bb2ff7SRichard Henderson         .max_access_size = 8,
59480bb2ff7SRichard Henderson     },
59580bb2ff7SRichard Henderson };
59680bb2ff7SRichard Henderson 
59780bb2ff7SRichard Henderson static const MemoryRegionOps pchip_ops = {
598b7ed683aSPeter Maydell     .read_with_attrs = pchip_read,
599b7ed683aSPeter Maydell     .write_with_attrs = pchip_write,
60080bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
60180bb2ff7SRichard Henderson     .valid = {
60267842165SRichard Henderson         .min_access_size = 8,
60380bb2ff7SRichard Henderson         .max_access_size = 8,
60480bb2ff7SRichard Henderson     },
60580bb2ff7SRichard Henderson     .impl = {
60667842165SRichard Henderson         .min_access_size = 8,
60767842165SRichard Henderson         .max_access_size = 8,
60880bb2ff7SRichard Henderson     },
60980bb2ff7SRichard Henderson };
61080bb2ff7SRichard Henderson 
611b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
612b83c4db8SRichard Henderson    using the given translated address and mask.  */
613b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
614b83c4db8SRichard Henderson {
615b83c4db8SRichard Henderson     *ret = (IOMMUTLBEntry) {
616b83c4db8SRichard Henderson         .target_as = &address_space_memory,
617b83c4db8SRichard Henderson         .translated_addr = taddr,
618b83c4db8SRichard Henderson         .addr_mask = mask,
619b83c4db8SRichard Henderson         .perm = IOMMU_RW,
620b83c4db8SRichard Henderson     };
621b83c4db8SRichard Henderson     return true;
622b83c4db8SRichard Henderson }
623b83c4db8SRichard Henderson 
624b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather
625b83c4db8SRichard Henderson    translation, given the address of the PTE.  */
626b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
627b83c4db8SRichard Henderson {
62842874d3aSPeter Maydell     uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
62942874d3aSPeter Maydell                                      MEMTXATTRS_UNSPECIFIED, NULL);
630b83c4db8SRichard Henderson 
631b83c4db8SRichard Henderson     /* Check valid bit.  */
632b83c4db8SRichard Henderson     if ((pte & 1) == 0) {
633b83c4db8SRichard Henderson         return false;
634b83c4db8SRichard Henderson     }
635b83c4db8SRichard Henderson 
636b83c4db8SRichard Henderson     return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
637b83c4db8SRichard Henderson }
638b83c4db8SRichard Henderson 
639b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the
640b83c4db8SRichard Henderson    four single-address-cycle translation windows.  */
641b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr,
642b83c4db8SRichard Henderson                              IOMMUTLBEntry *ret)
643b83c4db8SRichard Henderson {
644b83c4db8SRichard Henderson     uint32_t wba = win->wba;
645b83c4db8SRichard Henderson     uint64_t wsm = win->wsm;
646b83c4db8SRichard Henderson     uint64_t tba = win->tba;
647b83c4db8SRichard Henderson     uint64_t wsm_ext = wsm | 0xfffff;
648b83c4db8SRichard Henderson 
649b83c4db8SRichard Henderson     /* Check for window disabled.  */
650b83c4db8SRichard Henderson     if ((wba & 1) == 0) {
651b83c4db8SRichard Henderson         return false;
652b83c4db8SRichard Henderson     }
653b83c4db8SRichard Henderson 
654b83c4db8SRichard Henderson     /* Check for window hit.  */
655b83c4db8SRichard Henderson     if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
656b83c4db8SRichard Henderson         return false;
657b83c4db8SRichard Henderson     }
658b83c4db8SRichard Henderson 
659b83c4db8SRichard Henderson     if (wba & 2) {
660b83c4db8SRichard Henderson         /* Scatter-gather translation.  */
661b83c4db8SRichard Henderson         hwaddr pte_addr;
662b83c4db8SRichard Henderson 
663b83c4db8SRichard Henderson         /* See table 10-6, Generating PTE address for PCI DMA Address.  */
664b83c4db8SRichard Henderson         pte_addr  = tba & ~(wsm >> 10);
665b83c4db8SRichard Henderson         pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
666b83c4db8SRichard Henderson         return pte_translate(pte_addr, ret);
667b83c4db8SRichard Henderson     } else {
668b83c4db8SRichard Henderson         /* Direct-mapped translation.  */
669b83c4db8SRichard Henderson         return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
670b83c4db8SRichard Henderson     }
671b83c4db8SRichard Henderson }
672b83c4db8SRichard Henderson 
673b83c4db8SRichard Henderson /* Handle PCI-to-system address translation.  */
674b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the
675b83c4db8SRichard Henderson    Pchip and generate a machine check interrupt.  */
6763df9d748SAlexey Kardashevskiy static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
6773df9d748SAlexey Kardashevskiy                                              hwaddr addr,
6782c91bcf2SPeter Maydell                                              IOMMUAccessFlags flag,
6792c91bcf2SPeter Maydell                                              int iommu_idx)
680b83c4db8SRichard Henderson {
681b83c4db8SRichard Henderson     TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
682b83c4db8SRichard Henderson     IOMMUTLBEntry ret;
683b83c4db8SRichard Henderson     int i;
684b83c4db8SRichard Henderson 
685b83c4db8SRichard Henderson     if (addr <= 0xffffffffu) {
686b83c4db8SRichard Henderson         /* Single-address cycle.  */
687b83c4db8SRichard Henderson 
688b83c4db8SRichard Henderson         /* Check for the Window Hole, inhibiting matching.  */
689b83c4db8SRichard Henderson         if ((pchip->ctl & 0x20)
690b83c4db8SRichard Henderson             && addr >= 0x80000
691b83c4db8SRichard Henderson             && addr <= 0xfffff) {
692b83c4db8SRichard Henderson             goto failure;
693b83c4db8SRichard Henderson         }
694b83c4db8SRichard Henderson 
695b83c4db8SRichard Henderson         /* Check the first three windows.  */
696b83c4db8SRichard Henderson         for (i = 0; i < 3; ++i) {
697b83c4db8SRichard Henderson             if (window_translate(&pchip->win[i], addr, &ret)) {
698b83c4db8SRichard Henderson                 goto success;
699b83c4db8SRichard Henderson             }
700b83c4db8SRichard Henderson         }
701b83c4db8SRichard Henderson 
702b83c4db8SRichard Henderson         /* Check the fourth window for DAC disable.  */
703b83c4db8SRichard Henderson         if ((pchip->win[3].wba & 0x80000000000ull) == 0
704b83c4db8SRichard Henderson             && window_translate(&pchip->win[3], addr, &ret)) {
705b83c4db8SRichard Henderson             goto success;
706b83c4db8SRichard Henderson         }
707b83c4db8SRichard Henderson     } else {
708b83c4db8SRichard Henderson         /* Double-address cycle.  */
709b83c4db8SRichard Henderson 
710b83c4db8SRichard Henderson         if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
711b83c4db8SRichard Henderson             /* Check for the DMA monster window.  */
712b83c4db8SRichard Henderson             if (pchip->ctl & 0x40) {
713b83c4db8SRichard Henderson                 /* See 10.1.4.4; in particular <39:35> is ignored.  */
714b83c4db8SRichard Henderson                 make_iommu_tlbe(0, 0x007ffffffffull, &ret);
715b83c4db8SRichard Henderson                 goto success;
716b83c4db8SRichard Henderson             }
717b83c4db8SRichard Henderson         }
718b83c4db8SRichard Henderson 
7199b2caaf4SStefan Weil         if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) {
720b83c4db8SRichard Henderson             /* Check the fourth window for DAC enable and window enable.  */
721b83c4db8SRichard Henderson             if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
722b83c4db8SRichard Henderson                 uint64_t pte_addr;
723b83c4db8SRichard Henderson 
724b83c4db8SRichard Henderson                 pte_addr  = pchip->win[3].tba & 0x7ffc00000ull;
725b83c4db8SRichard Henderson                 pte_addr |= (addr & 0xffffe000u) >> 10;
726b83c4db8SRichard Henderson                 if (pte_translate(pte_addr, &ret)) {
727b83c4db8SRichard Henderson                         goto success;
728b83c4db8SRichard Henderson                 }
729b83c4db8SRichard Henderson             }
730b83c4db8SRichard Henderson         }
731b83c4db8SRichard Henderson     }
732b83c4db8SRichard Henderson 
733b83c4db8SRichard Henderson  failure:
734b83c4db8SRichard Henderson     ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
735b83c4db8SRichard Henderson  success:
736b83c4db8SRichard Henderson     return ret;
737b83c4db8SRichard Henderson }
738b83c4db8SRichard Henderson 
739b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
740b83c4db8SRichard Henderson {
741b83c4db8SRichard Henderson     TyphoonState *s = opaque;
742b83c4db8SRichard Henderson     return &s->pchip.iommu_as;
743b83c4db8SRichard Henderson }
744b83c4db8SRichard Henderson 
74580bb2ff7SRichard Henderson static void typhoon_set_irq(void *opaque, int irq, int level)
74680bb2ff7SRichard Henderson {
74780bb2ff7SRichard Henderson     TyphoonState *s = opaque;
74880bb2ff7SRichard Henderson     uint64_t drir;
74980bb2ff7SRichard Henderson     int i;
75080bb2ff7SRichard Henderson 
75180bb2ff7SRichard Henderson     /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
75280bb2ff7SRichard Henderson     drir = s->cchip.drir;
75380bb2ff7SRichard Henderson     if (level) {
75480bb2ff7SRichard Henderson         drir |= 1ull << irq;
75580bb2ff7SRichard Henderson     } else {
75680bb2ff7SRichard Henderson         drir &= ~(1ull << irq);
75780bb2ff7SRichard Henderson     }
75880bb2ff7SRichard Henderson     s->cchip.drir = drir;
75980bb2ff7SRichard Henderson 
76080bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
76180bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
76280bb2ff7SRichard Henderson     }
76380bb2ff7SRichard Henderson }
76480bb2ff7SRichard Henderson 
76580bb2ff7SRichard Henderson static void typhoon_set_isa_irq(void *opaque, int irq, int level)
76680bb2ff7SRichard Henderson {
76780bb2ff7SRichard Henderson     typhoon_set_irq(opaque, 55, level);
76880bb2ff7SRichard Henderson }
76980bb2ff7SRichard Henderson 
77080bb2ff7SRichard Henderson static void typhoon_set_timer_irq(void *opaque, int irq, int level)
77180bb2ff7SRichard Henderson {
77280bb2ff7SRichard Henderson     TyphoonState *s = opaque;
77380bb2ff7SRichard Henderson     int i;
77480bb2ff7SRichard Henderson 
77580bb2ff7SRichard Henderson     /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
77680bb2ff7SRichard Henderson        and so we don't have to worry about missing interrupts just
77780bb2ff7SRichard Henderson        because we never actually ACK the interrupt.  Just ignore any
77880bb2ff7SRichard Henderson        case of the interrupt level going low.  */
77980bb2ff7SRichard Henderson     if (level == 0) {
78080bb2ff7SRichard Henderson         return;
78180bb2ff7SRichard Henderson     }
78280bb2ff7SRichard Henderson 
78380bb2ff7SRichard Henderson     /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
78480bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
785ad601177SAndreas Färber         AlphaCPU *cpu = s->cchip.cpu[i];
786ad601177SAndreas Färber         if (cpu != NULL) {
78780bb2ff7SRichard Henderson             uint32_t iic = s->cchip.iic[i];
78880bb2ff7SRichard Henderson 
78980bb2ff7SRichard Henderson             /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
79080bb2ff7SRichard Henderson                Bit 24 is the OverFlow bit, RO, and set when the count
79180bb2ff7SRichard Henderson                decrements past 0.  When is OF cleared?  My guess is that
79280bb2ff7SRichard Henderson                OF is actually cleared when the IIC is written, and that
79380bb2ff7SRichard Henderson                the ICNT field always decrements.  At least, that's an
79480bb2ff7SRichard Henderson                interpretation that makes sense, and "allows the CPU to
79580bb2ff7SRichard Henderson                determine exactly how mant interval timer ticks were
79680bb2ff7SRichard Henderson                skipped".  At least within the next 4M ticks...  */
79780bb2ff7SRichard Henderson 
79880bb2ff7SRichard Henderson             iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
79980bb2ff7SRichard Henderson             s->cchip.iic[i] = iic;
80080bb2ff7SRichard Henderson 
80180bb2ff7SRichard Henderson             if (iic & 0x1000000) {
80280bb2ff7SRichard Henderson                 /* Set the ITI bit for this cpu.  */
80380bb2ff7SRichard Henderson                 s->cchip.misc |= 1 << (i + 4);
80480bb2ff7SRichard Henderson                 /* And signal the interrupt.  */
805c3affe56SAndreas Färber                 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
80680bb2ff7SRichard Henderson             }
80780bb2ff7SRichard Henderson         }
80880bb2ff7SRichard Henderson     }
80980bb2ff7SRichard Henderson }
81080bb2ff7SRichard Henderson 
811c781cf96SRichard Henderson static void typhoon_alarm_timer(void *opaque)
812c781cf96SRichard Henderson {
813c781cf96SRichard Henderson     TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
814c781cf96SRichard Henderson     int cpu = (uintptr_t)opaque & 3;
815c781cf96SRichard Henderson 
816c781cf96SRichard Henderson     /* Set the ITI bit for this cpu.  */
817c781cf96SRichard Henderson     s->cchip.misc |= 1 << (cpu + 4);
818c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
819c781cf96SRichard Henderson }
820c781cf96SRichard Henderson 
821b844d822SIgor Mammedov PCIBus *typhoon_init(MemoryRegion *ram, ISABus **isa_bus, qemu_irq *p_rtc_irq,
822ad601177SAndreas Färber                      AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq)
82380bb2ff7SRichard Henderson {
82480bb2ff7SRichard Henderson     MemoryRegion *addr_space = get_system_memory();
82580bb2ff7SRichard Henderson     DeviceState *dev;
82680bb2ff7SRichard Henderson     TyphoonState *s;
82794dd91d6SAndreas Färber     PCIHostState *phb;
82880bb2ff7SRichard Henderson     PCIBus *b;
829c781cf96SRichard Henderson     int i;
83080bb2ff7SRichard Henderson 
8313e80f690SMarkus Armbruster     dev = qdev_new(TYPE_TYPHOON_PCI_HOST_BRIDGE);
83280bb2ff7SRichard Henderson 
83394dd91d6SAndreas Färber     s = TYPHOON_PCI_HOST_BRIDGE(dev);
8348558d942SAndreas Färber     phb = PCI_HOST_BRIDGE(dev);
83580bb2ff7SRichard Henderson 
836b83c4db8SRichard Henderson     s->cchip.misc = 0x800000000ull; /* Revision: Typhoon.  */
837b83c4db8SRichard Henderson     s->pchip.win[3].wba = 2;        /* Window 3 SG always enabled. */
838b83c4db8SRichard Henderson 
83980bb2ff7SRichard Henderson     /* Remember the CPUs so that we can deliver interrupts to them.  */
840c781cf96SRichard Henderson     for (i = 0; i < 4; i++) {
841ad601177SAndreas Färber         AlphaCPU *cpu = cpus[i];
842ad601177SAndreas Färber         s->cchip.cpu[i] = cpu;
843ad601177SAndreas Färber         if (cpu != NULL) {
844bc72ad67SAlex Bligh             cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
845c781cf96SRichard Henderson                                                  typhoon_alarm_timer,
846c781cf96SRichard Henderson                                                  (void *)((uintptr_t)s + i));
847c781cf96SRichard Henderson         }
848c781cf96SRichard Henderson     }
84980bb2ff7SRichard Henderson 
85054292736SShannon Zhao     *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
85180bb2ff7SRichard Henderson 
85280bb2ff7SRichard Henderson     /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
85380bb2ff7SRichard Henderson        but the address space hole reserved at this point is 8TB.  */
854b844d822SIgor Mammedov     memory_region_add_subregion(addr_space, 0, ram);
85580bb2ff7SRichard Henderson 
85680bb2ff7SRichard Henderson     /* TIGbus, 0x801.0000.0000, 1GB.  */
85780bb2ff7SRichard Henderson     /* ??? The TIGbus is used for delivering interrupts, and access to
85880bb2ff7SRichard Henderson        the flash ROM.  I'm not sure that we need to implement it at all.  */
85980bb2ff7SRichard Henderson 
86080bb2ff7SRichard Henderson     /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
86164bde0f3SPaolo Bonzini     memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
8622b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
86302d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80180000000ULL,
86402d6516cSStefan Weil                                 &s->pchip.region);
86580bb2ff7SRichard Henderson 
86680bb2ff7SRichard Henderson     /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
86764bde0f3SPaolo Bonzini     memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
8682b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
86902d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801a0000000ULL,
87002d6516cSStefan Weil                                 &s->cchip.region);
87180bb2ff7SRichard Henderson 
87280bb2ff7SRichard Henderson     /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
87364bde0f3SPaolo Bonzini     memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
8742b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
87502d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801b0000000ULL,
87602d6516cSStefan Weil                                 &s->dchip_region);
87780bb2ff7SRichard Henderson 
87880bb2ff7SRichard Henderson     /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
8792b41742aSPhilippe Mathieu-Daudé     memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4 * GiB);
88002d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80000000000ULL,
88102d6516cSStefan Weil                                 &s->pchip.reg_mem);
88280bb2ff7SRichard Henderson 
88380bb2ff7SRichard Henderson     /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
8843661049fSRichard Henderson     memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops,
8852b41742aSPhilippe Mathieu-Daudé                           NULL, "pci0-io", 32 * MiB);
88602d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fc000000ULL,
88702d6516cSStefan Weil                                 &s->pchip.reg_io);
88880bb2ff7SRichard Henderson 
8891115ff6dSDavid Gibson     b = pci_register_root_bus(dev, "pci",
89080bb2ff7SRichard Henderson                               typhoon_set_irq, sys_map_irq, s,
891056e6baeSRichard Henderson                               &s->pchip.reg_mem, &s->pchip.reg_io,
892056e6baeSRichard Henderson                               0, 64, TYPE_PCI_BUS);
89394dd91d6SAndreas Färber     phb->bus = b;
8943c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
89580bb2ff7SRichard Henderson 
896b83c4db8SRichard Henderson     /* Host memory as seen from the PCI side, via the IOMMU.  */
8971221a474SAlexey Kardashevskiy     memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu),
8981221a474SAlexey Kardashevskiy                              TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s),
899b83c4db8SRichard Henderson                              "iommu-typhoon", UINT64_MAX);
9003df9d748SAlexey Kardashevskiy     address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
9013df9d748SAlexey Kardashevskiy                        "pchip0-pci");
902b83c4db8SRichard Henderson     pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
903b83c4db8SRichard Henderson 
90480bb2ff7SRichard Henderson     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
905056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
9062b41742aSPhilippe Mathieu-Daudé                           b, "pci0-iack", 64 * MiB);
90702d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801f8000000ULL,
90802d6516cSStefan Weil                                 &s->pchip.reg_iack);
90980bb2ff7SRichard Henderson 
91080bb2ff7SRichard Henderson     /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
911056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
9122b41742aSPhilippe Mathieu-Daudé                           b, "pci0-conf", 16 * MiB);
91302d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fe000000ULL,
91402d6516cSStefan Weil                                 &s->pchip.reg_conf);
91580bb2ff7SRichard Henderson 
91680bb2ff7SRichard Henderson     /* For the record, these are the mappings for the second PCI bus.
91780bb2ff7SRichard Henderson        We can get away with not implementing them because we indicate
91880bb2ff7SRichard Henderson        via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
91980bb2ff7SRichard Henderson     /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
92080bb2ff7SRichard Henderson     /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
92180bb2ff7SRichard Henderson     /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
92280bb2ff7SRichard Henderson     /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
92380bb2ff7SRichard Henderson     /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
92480bb2ff7SRichard Henderson 
92580bb2ff7SRichard Henderson     /* Init the ISA bus.  */
92680bb2ff7SRichard Henderson     /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
92780bb2ff7SRichard Henderson     {
92854292736SShannon Zhao         qemu_irq *isa_irqs;
92980bb2ff7SRichard Henderson 
930d10e5432SMarkus Armbruster         *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io,
931d10e5432SMarkus Armbruster                                &error_abort);
93254292736SShannon Zhao         isa_irqs = i8259_init(*isa_bus,
93354292736SShannon Zhao                               qemu_allocate_irq(typhoon_set_isa_irq, s, 0));
93471baa303SHervé Poussineau         isa_bus_irqs(*isa_bus, isa_irqs);
93580bb2ff7SRichard Henderson     }
93680bb2ff7SRichard Henderson 
93780bb2ff7SRichard Henderson     return b;
93880bb2ff7SRichard Henderson }
93980bb2ff7SRichard Henderson 
9404240abffSAndreas Färber static const TypeInfo typhoon_pcihost_info = {
94194dd91d6SAndreas Färber     .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
9428558d942SAndreas Färber     .parent        = TYPE_PCI_HOST_BRIDGE,
94339bffca2SAnthony Liguori     .instance_size = sizeof(TyphoonState),
94480bb2ff7SRichard Henderson };
94580bb2ff7SRichard Henderson 
9461221a474SAlexey Kardashevskiy static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
9471221a474SAlexey Kardashevskiy                                                    void *data)
9481221a474SAlexey Kardashevskiy {
9491221a474SAlexey Kardashevskiy     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
9501221a474SAlexey Kardashevskiy 
9511221a474SAlexey Kardashevskiy     imrc->translate = typhoon_translate_iommu;
9521221a474SAlexey Kardashevskiy }
9531221a474SAlexey Kardashevskiy 
9541221a474SAlexey Kardashevskiy static const TypeInfo typhoon_iommu_memory_region_info = {
9551221a474SAlexey Kardashevskiy     .parent = TYPE_IOMMU_MEMORY_REGION,
9561221a474SAlexey Kardashevskiy     .name = TYPE_TYPHOON_IOMMU_MEMORY_REGION,
9571221a474SAlexey Kardashevskiy     .class_init = typhoon_iommu_memory_region_class_init,
9581221a474SAlexey Kardashevskiy };
9591221a474SAlexey Kardashevskiy 
96083f7d43aSAndreas Färber static void typhoon_register_types(void)
96180bb2ff7SRichard Henderson {
96239bffca2SAnthony Liguori     type_register_static(&typhoon_pcihost_info);
9631221a474SAlexey Kardashevskiy     type_register_static(&typhoon_iommu_memory_region_info);
96480bb2ff7SRichard Henderson }
96583f7d43aSAndreas Färber 
96683f7d43aSAndreas Färber type_init(typhoon_register_types)
967