xref: /qemu/hw/alpha/typhoon.c (revision 0b8fa32f551e863bb548a11394239239270dd3dc)
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"
10*0b8fa32fSMarkus Armbruster #include "qemu/module.h"
112b41742aSPhilippe Mathieu-Daudé #include "qemu/units.h"
12da34e65cSMarkus Armbruster #include "qapi/error.h"
1380bb2ff7SRichard Henderson #include "cpu.h"
1483c9f4caSPaolo Bonzini #include "hw/hw.h"
159c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
1647b43a1fSPaolo Bonzini #include "alpha_sys.h"
17022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
1880bb2ff7SRichard Henderson 
1980bb2ff7SRichard Henderson 
2094dd91d6SAndreas Färber #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
211221a474SAlexey Kardashevskiy #define TYPE_TYPHOON_IOMMU_MEMORY_REGION "typhoon-iommu-memory-region"
2294dd91d6SAndreas Färber 
2380bb2ff7SRichard Henderson typedef struct TyphoonCchip {
2480bb2ff7SRichard Henderson     MemoryRegion region;
2580bb2ff7SRichard Henderson     uint64_t misc;
2680bb2ff7SRichard Henderson     uint64_t drir;
2780bb2ff7SRichard Henderson     uint64_t dim[4];
2880bb2ff7SRichard Henderson     uint32_t iic[4];
29ad601177SAndreas Färber     AlphaCPU *cpu[4];
3080bb2ff7SRichard Henderson } TyphoonCchip;
3180bb2ff7SRichard Henderson 
3280bb2ff7SRichard Henderson typedef struct TyphoonWindow {
33b83c4db8SRichard Henderson     uint64_t wba;
34b83c4db8SRichard Henderson     uint64_t wsm;
35b83c4db8SRichard Henderson     uint64_t tba;
3680bb2ff7SRichard Henderson } TyphoonWindow;
3780bb2ff7SRichard Henderson 
3880bb2ff7SRichard Henderson typedef struct TyphoonPchip {
3980bb2ff7SRichard Henderson     MemoryRegion region;
4080bb2ff7SRichard Henderson     MemoryRegion reg_iack;
4180bb2ff7SRichard Henderson     MemoryRegion reg_mem;
4280bb2ff7SRichard Henderson     MemoryRegion reg_io;
4380bb2ff7SRichard Henderson     MemoryRegion reg_conf;
44b83c4db8SRichard Henderson 
45b83c4db8SRichard Henderson     AddressSpace iommu_as;
463df9d748SAlexey Kardashevskiy     IOMMUMemoryRegion iommu;
47b83c4db8SRichard Henderson 
4880bb2ff7SRichard Henderson     uint64_t ctl;
4980bb2ff7SRichard Henderson     TyphoonWindow win[4];
5080bb2ff7SRichard Henderson } TyphoonPchip;
5180bb2ff7SRichard Henderson 
5294dd91d6SAndreas Färber #define TYPHOON_PCI_HOST_BRIDGE(obj) \
5394dd91d6SAndreas Färber     OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE)
5494dd91d6SAndreas Färber 
5580bb2ff7SRichard Henderson typedef struct TyphoonState {
5667c332fdSAndreas Färber     PCIHostState parent_obj;
5794dd91d6SAndreas Färber 
5880bb2ff7SRichard Henderson     TyphoonCchip cchip;
5980bb2ff7SRichard Henderson     TyphoonPchip pchip;
6080bb2ff7SRichard Henderson     MemoryRegion dchip_region;
6180bb2ff7SRichard Henderson     MemoryRegion ram_region;
6280bb2ff7SRichard Henderson } TyphoonState;
6380bb2ff7SRichard Henderson 
6480bb2ff7SRichard Henderson /* Called when one of DRIR or DIM changes.  */
65ad601177SAndreas Färber static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
6680bb2ff7SRichard Henderson {
6780bb2ff7SRichard Henderson     /* If there are any non-masked interrupts, tell the cpu.  */
68ad601177SAndreas Färber     if (cpu != NULL) {
69d8ed887bSAndreas Färber         CPUState *cs = CPU(cpu);
7080bb2ff7SRichard Henderson         if (req) {
71c3affe56SAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
7280bb2ff7SRichard Henderson         } else {
73d8ed887bSAndreas Färber             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
7480bb2ff7SRichard Henderson         }
7580bb2ff7SRichard Henderson     }
7680bb2ff7SRichard Henderson }
7780bb2ff7SRichard Henderson 
78b7ed683aSPeter Maydell static MemTxResult cchip_read(void *opaque, hwaddr addr,
79b7ed683aSPeter Maydell                               uint64_t *data, unsigned size,
80b7ed683aSPeter Maydell                               MemTxAttrs attrs)
8180bb2ff7SRichard Henderson {
824917cf44SAndreas Färber     CPUState *cpu = current_cpu;
8380bb2ff7SRichard Henderson     TyphoonState *s = opaque;
8480bb2ff7SRichard Henderson     uint64_t ret = 0;
8580bb2ff7SRichard Henderson 
8680bb2ff7SRichard Henderson     switch (addr) {
8780bb2ff7SRichard Henderson     case 0x0000:
8880bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
8980bb2ff7SRichard Henderson         /* All sorts of data here; probably the only thing relevant is
9080bb2ff7SRichard Henderson            PIP<14> Pchip 1 Present = 0.  */
9180bb2ff7SRichard Henderson         break;
9280bb2ff7SRichard Henderson 
9380bb2ff7SRichard Henderson     case 0x0040:
9480bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
9580bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
9680bb2ff7SRichard Henderson         break;
9780bb2ff7SRichard Henderson 
9880bb2ff7SRichard Henderson     case 0x0080:
9980bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
10055e5c285SAndreas Färber         ret = s->cchip.misc | (cpu->cpu_index & 3);
10180bb2ff7SRichard Henderson         break;
10280bb2ff7SRichard Henderson 
10380bb2ff7SRichard Henderson     case 0x00c0:
10480bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
10580bb2ff7SRichard Henderson         break;
10680bb2ff7SRichard Henderson 
10780bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
10880bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
10980bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
11080bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
11180bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
11280bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
11380bb2ff7SRichard Henderson         break;
11480bb2ff7SRichard Henderson 
11580bb2ff7SRichard Henderson     case 0x0200:
11680bb2ff7SRichard Henderson         /* DIM0: Device Interrupt Mask Register, CPU0.  */
11780bb2ff7SRichard Henderson         ret = s->cchip.dim[0];
11880bb2ff7SRichard Henderson         break;
11980bb2ff7SRichard Henderson     case 0x0240:
12080bb2ff7SRichard Henderson         /* DIM1: Device Interrupt Mask Register, CPU1.  */
12180bb2ff7SRichard Henderson         ret = s->cchip.dim[1];
12280bb2ff7SRichard Henderson         break;
12380bb2ff7SRichard Henderson     case 0x0280:
12480bb2ff7SRichard Henderson         /* DIR0: Device Interrupt Request Register, CPU0.  */
12580bb2ff7SRichard Henderson         ret = s->cchip.dim[0] & s->cchip.drir;
12680bb2ff7SRichard Henderson         break;
12780bb2ff7SRichard Henderson     case 0x02c0:
12880bb2ff7SRichard Henderson         /* DIR1: Device Interrupt Request Register, CPU1.  */
12980bb2ff7SRichard Henderson         ret = s->cchip.dim[1] & s->cchip.drir;
13080bb2ff7SRichard Henderson         break;
13180bb2ff7SRichard Henderson     case 0x0300:
13280bb2ff7SRichard Henderson         /* DRIR: Device Raw Interrupt Request Register.  */
13380bb2ff7SRichard Henderson         ret = s->cchip.drir;
13480bb2ff7SRichard Henderson         break;
13580bb2ff7SRichard Henderson 
13680bb2ff7SRichard Henderson     case 0x0340:
13780bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
13880bb2ff7SRichard Henderson         break;
13980bb2ff7SRichard Henderson 
14080bb2ff7SRichard Henderson     case 0x0380:
14180bb2ff7SRichard Henderson         /* IIC0: Interval Ignore Count Register, CPU0.  */
14280bb2ff7SRichard Henderson         ret = s->cchip.iic[0];
14380bb2ff7SRichard Henderson         break;
14480bb2ff7SRichard Henderson     case 0x03c0:
14580bb2ff7SRichard Henderson         /* IIC1: Interval Ignore Count Register, CPU1.  */
14680bb2ff7SRichard Henderson         ret = s->cchip.iic[1];
14780bb2ff7SRichard Henderson         break;
14880bb2ff7SRichard Henderson 
14980bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
15080bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
15180bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
15280bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
15380bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
15480bb2ff7SRichard Henderson         break;
15580bb2ff7SRichard Henderson 
15680bb2ff7SRichard Henderson     case 0x0580:
15780bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
15880bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
15980bb2ff7SRichard Henderson         break;
16080bb2ff7SRichard Henderson     case 0x05c0:
16180bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
16280bb2ff7SRichard Henderson         break;
16380bb2ff7SRichard Henderson 
16480bb2ff7SRichard Henderson     case 0x0600:
16580bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
16680bb2ff7SRichard Henderson         ret = s->cchip.dim[2];
16780bb2ff7SRichard Henderson         break;
16880bb2ff7SRichard Henderson     case 0x0640:
16980bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
17080bb2ff7SRichard Henderson         ret = s->cchip.dim[3];
17180bb2ff7SRichard Henderson         break;
17280bb2ff7SRichard Henderson     case 0x0680:
17380bb2ff7SRichard Henderson         /* DIR2: Device Interrupt Request Register, CPU2.  */
17480bb2ff7SRichard Henderson         ret = s->cchip.dim[2] & s->cchip.drir;
17580bb2ff7SRichard Henderson         break;
17680bb2ff7SRichard Henderson     case 0x06c0:
17780bb2ff7SRichard Henderson         /* DIR3: Device Interrupt Request Register, CPU3.  */
17880bb2ff7SRichard Henderson         ret = s->cchip.dim[3] & s->cchip.drir;
17980bb2ff7SRichard Henderson         break;
18080bb2ff7SRichard Henderson 
18180bb2ff7SRichard Henderson     case 0x0700:
18280bb2ff7SRichard Henderson         /* IIC2: Interval Ignore Count Register, CPU2.  */
18380bb2ff7SRichard Henderson         ret = s->cchip.iic[2];
18480bb2ff7SRichard Henderson         break;
18580bb2ff7SRichard Henderson     case 0x0740:
18680bb2ff7SRichard Henderson         /* IIC3: Interval Ignore Count Register, CPU3.  */
18780bb2ff7SRichard Henderson         ret = s->cchip.iic[3];
18880bb2ff7SRichard Henderson         break;
18980bb2ff7SRichard Henderson 
19080bb2ff7SRichard Henderson     case 0x0780:
19180bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
19280bb2ff7SRichard Henderson         break;
19380bb2ff7SRichard Henderson 
19480bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
19580bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
19680bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
19780bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
19880bb2ff7SRichard Henderson         break;
19980bb2ff7SRichard Henderson 
20080bb2ff7SRichard Henderson     default:
201b7ed683aSPeter Maydell         return MEMTX_ERROR;
20280bb2ff7SRichard Henderson     }
20380bb2ff7SRichard Henderson 
204b7ed683aSPeter Maydell     *data = ret;
205b7ed683aSPeter Maydell     return MEMTX_OK;
20680bb2ff7SRichard Henderson }
20780bb2ff7SRichard Henderson 
208a8170e5eSAvi Kivity static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
20980bb2ff7SRichard Henderson {
21080bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
21180bb2ff7SRichard Henderson     return 0;
21280bb2ff7SRichard Henderson }
21380bb2ff7SRichard Henderson 
214b7ed683aSPeter Maydell static MemTxResult pchip_read(void *opaque, hwaddr addr, uint64_t *data,
215b7ed683aSPeter Maydell                               unsigned size, MemTxAttrs attrs)
21680bb2ff7SRichard Henderson {
21780bb2ff7SRichard Henderson     TyphoonState *s = opaque;
21880bb2ff7SRichard Henderson     uint64_t ret = 0;
21980bb2ff7SRichard Henderson 
22080bb2ff7SRichard Henderson     switch (addr) {
22180bb2ff7SRichard Henderson     case 0x0000:
22280bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
223b83c4db8SRichard Henderson         ret = s->pchip.win[0].wba;
22480bb2ff7SRichard Henderson         break;
22580bb2ff7SRichard Henderson     case 0x0040:
22680bb2ff7SRichard Henderson         /* WSBA1 */
227b83c4db8SRichard Henderson         ret = s->pchip.win[1].wba;
22880bb2ff7SRichard Henderson         break;
22980bb2ff7SRichard Henderson     case 0x0080:
23080bb2ff7SRichard Henderson         /* WSBA2 */
231b83c4db8SRichard Henderson         ret = s->pchip.win[2].wba;
23280bb2ff7SRichard Henderson         break;
23380bb2ff7SRichard Henderson     case 0x00c0:
23480bb2ff7SRichard Henderson         /* WSBA3 */
235b83c4db8SRichard Henderson         ret = s->pchip.win[3].wba;
23680bb2ff7SRichard Henderson         break;
23780bb2ff7SRichard Henderson 
23880bb2ff7SRichard Henderson     case 0x0100:
23980bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
240b83c4db8SRichard Henderson         ret = s->pchip.win[0].wsm;
24180bb2ff7SRichard Henderson         break;
24280bb2ff7SRichard Henderson     case 0x0140:
24380bb2ff7SRichard Henderson         /* WSM1 */
244b83c4db8SRichard Henderson         ret = s->pchip.win[1].wsm;
24580bb2ff7SRichard Henderson         break;
24680bb2ff7SRichard Henderson     case 0x0180:
24780bb2ff7SRichard Henderson         /* WSM2 */
248b83c4db8SRichard Henderson         ret = s->pchip.win[2].wsm;
24980bb2ff7SRichard Henderson         break;
25080bb2ff7SRichard Henderson     case 0x01c0:
25180bb2ff7SRichard Henderson         /* WSM3 */
252b83c4db8SRichard Henderson         ret = s->pchip.win[3].wsm;
25380bb2ff7SRichard Henderson         break;
25480bb2ff7SRichard Henderson 
25580bb2ff7SRichard Henderson     case 0x0200:
25680bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
257b83c4db8SRichard Henderson         ret = s->pchip.win[0].tba;
25880bb2ff7SRichard Henderson         break;
25980bb2ff7SRichard Henderson     case 0x0240:
26080bb2ff7SRichard Henderson         /* TBA1 */
261b83c4db8SRichard Henderson         ret = s->pchip.win[1].tba;
26280bb2ff7SRichard Henderson         break;
26380bb2ff7SRichard Henderson     case 0x0280:
26480bb2ff7SRichard Henderson         /* TBA2 */
265b83c4db8SRichard Henderson         ret = s->pchip.win[2].tba;
26680bb2ff7SRichard Henderson         break;
26780bb2ff7SRichard Henderson     case 0x02c0:
26880bb2ff7SRichard Henderson         /* TBA3 */
269b83c4db8SRichard Henderson         ret = s->pchip.win[3].tba;
27080bb2ff7SRichard Henderson         break;
27180bb2ff7SRichard Henderson 
27280bb2ff7SRichard Henderson     case 0x0300:
27380bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
27480bb2ff7SRichard Henderson         ret = s->pchip.ctl;
27580bb2ff7SRichard Henderson         break;
27680bb2ff7SRichard Henderson     case 0x0340:
27780bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
27880bb2ff7SRichard Henderson         break;
27980bb2ff7SRichard Henderson     case 0x03c0:
28080bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
28180bb2ff7SRichard Henderson         break;
28280bb2ff7SRichard Henderson     case 0x0400:
28380bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
28480bb2ff7SRichard Henderson         break;
28580bb2ff7SRichard Henderson     case 0x0440:
28680bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
28780bb2ff7SRichard Henderson         break;
28880bb2ff7SRichard Henderson     case 0x0480:
28980bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
29080bb2ff7SRichard Henderson         break;
29180bb2ff7SRichard Henderson     case 0x04c0:
29280bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
29380bb2ff7SRichard Henderson         break;
29480bb2ff7SRichard Henderson     case 0x0500: /* PMONCTL */
29580bb2ff7SRichard Henderson     case 0x0540: /* PMONCNT */
29680bb2ff7SRichard Henderson     case 0x0800: /* SPRST */
29780bb2ff7SRichard Henderson         break;
29880bb2ff7SRichard Henderson 
29980bb2ff7SRichard Henderson     default:
300b7ed683aSPeter Maydell         return MEMTX_ERROR;
30180bb2ff7SRichard Henderson     }
30280bb2ff7SRichard Henderson 
303b7ed683aSPeter Maydell     *data = ret;
304b7ed683aSPeter Maydell     return MEMTX_OK;
30580bb2ff7SRichard Henderson }
30680bb2ff7SRichard Henderson 
307b7ed683aSPeter Maydell static MemTxResult cchip_write(void *opaque, hwaddr addr,
308b7ed683aSPeter Maydell                                uint64_t val, unsigned size,
309b7ed683aSPeter Maydell                                MemTxAttrs attrs)
31080bb2ff7SRichard Henderson {
31180bb2ff7SRichard Henderson     TyphoonState *s = opaque;
31267842165SRichard Henderson     uint64_t oldval, newval;
31380bb2ff7SRichard Henderson 
31480bb2ff7SRichard Henderson     switch (addr) {
31580bb2ff7SRichard Henderson     case 0x0000:
31680bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
31780bb2ff7SRichard Henderson         /* All sorts of data here; nothing relevant RW.  */
31880bb2ff7SRichard Henderson         break;
31980bb2ff7SRichard Henderson 
32080bb2ff7SRichard Henderson     case 0x0040:
32180bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
32280bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
32380bb2ff7SRichard Henderson         break;
32480bb2ff7SRichard Henderson 
32580bb2ff7SRichard Henderson     case 0x0080:
32680bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
32780bb2ff7SRichard Henderson         newval = oldval = s->cchip.misc;
32880bb2ff7SRichard Henderson         newval &= ~(val & 0x10000ff0);     /* W1C fields */
32980bb2ff7SRichard Henderson         if (val & 0x100000) {
33080bb2ff7SRichard Henderson             newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
33180bb2ff7SRichard Henderson         } else {
33280bb2ff7SRichard Henderson             newval |= val & 0x00f00000;    /* ABT field is W1S */
33380bb2ff7SRichard Henderson             if ((newval & 0xf0000) == 0) {
33480bb2ff7SRichard Henderson                 newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
33580bb2ff7SRichard Henderson             }
33680bb2ff7SRichard Henderson         }
33780bb2ff7SRichard Henderson         newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
33880bb2ff7SRichard Henderson 
33980bb2ff7SRichard Henderson         newval &= ~0xf0000000000ull;       /* WO and RW fields */
34080bb2ff7SRichard Henderson         newval |= val & 0xf0000000000ull;
34180bb2ff7SRichard Henderson         s->cchip.misc = newval;
34280bb2ff7SRichard Henderson 
34380bb2ff7SRichard Henderson         /* Pass on changes to IPI and ITI state.  */
34480bb2ff7SRichard Henderson         if ((newval ^ oldval) & 0xff0) {
34580bb2ff7SRichard Henderson             int i;
34680bb2ff7SRichard Henderson             for (i = 0; i < 4; ++i) {
347ad601177SAndreas Färber                 AlphaCPU *cpu = s->cchip.cpu[i];
348ad601177SAndreas Färber                 if (cpu != NULL) {
349d8ed887bSAndreas Färber                     CPUState *cs = CPU(cpu);
35080bb2ff7SRichard Henderson                     /* IPI can be either cleared or set by the write.  */
35180bb2ff7SRichard Henderson                     if (newval & (1 << (i + 8))) {
352c3affe56SAndreas Färber                         cpu_interrupt(cs, CPU_INTERRUPT_SMP);
35380bb2ff7SRichard Henderson                     } else {
354d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
35580bb2ff7SRichard Henderson                     }
35680bb2ff7SRichard Henderson 
35780bb2ff7SRichard Henderson                     /* ITI can only be cleared by the write.  */
35880bb2ff7SRichard Henderson                     if ((newval & (1 << (i + 4))) == 0) {
359d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
36080bb2ff7SRichard Henderson                     }
36180bb2ff7SRichard Henderson                 }
36280bb2ff7SRichard Henderson             }
36380bb2ff7SRichard Henderson         }
36480bb2ff7SRichard Henderson         break;
36580bb2ff7SRichard Henderson 
36680bb2ff7SRichard Henderson     case 0x00c0:
36780bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
36880bb2ff7SRichard Henderson         break;
36980bb2ff7SRichard Henderson 
37080bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
37180bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
37280bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
37380bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
37480bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
37580bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
37680bb2ff7SRichard Henderson         break;
37780bb2ff7SRichard Henderson 
37880bb2ff7SRichard Henderson     case 0x0200: /* DIM0 */
37980bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU0.  */
38080bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
38180bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
38280bb2ff7SRichard Henderson         break;
38380bb2ff7SRichard Henderson     case 0x0240: /* DIM1 */
38480bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU1.  */
385424ad838SRichard Henderson         s->cchip.dim[1] = val;
38680bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
38780bb2ff7SRichard Henderson         break;
38880bb2ff7SRichard Henderson 
38980bb2ff7SRichard Henderson     case 0x0280: /* DIR0 (RO) */
39080bb2ff7SRichard Henderson     case 0x02c0: /* DIR1 (RO) */
39180bb2ff7SRichard Henderson     case 0x0300: /* DRIR (RO) */
39280bb2ff7SRichard Henderson         break;
39380bb2ff7SRichard Henderson 
39480bb2ff7SRichard Henderson     case 0x0340:
39580bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
39680bb2ff7SRichard Henderson         break;
39780bb2ff7SRichard Henderson 
39880bb2ff7SRichard Henderson     case 0x0380: /* IIC0 */
39980bb2ff7SRichard Henderson         s->cchip.iic[0] = val & 0xffffff;
40080bb2ff7SRichard Henderson         break;
40180bb2ff7SRichard Henderson     case 0x03c0: /* IIC1 */
40280bb2ff7SRichard Henderson         s->cchip.iic[1] = val & 0xffffff;
40380bb2ff7SRichard Henderson         break;
40480bb2ff7SRichard Henderson 
40580bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
40680bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
40780bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
40880bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
40980bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
41080bb2ff7SRichard Henderson         break;
41180bb2ff7SRichard Henderson 
41280bb2ff7SRichard Henderson     case 0x0580:
41380bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
41480bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
41580bb2ff7SRichard Henderson         break;
41680bb2ff7SRichard Henderson     case 0x05c0:
41780bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
41880bb2ff7SRichard Henderson         break;
41980bb2ff7SRichard Henderson 
42080bb2ff7SRichard Henderson     case 0x0600:
42180bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
42280bb2ff7SRichard Henderson         s->cchip.dim[2] = val;
42380bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
42480bb2ff7SRichard Henderson         break;
42580bb2ff7SRichard Henderson     case 0x0640:
42680bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
42780bb2ff7SRichard Henderson         s->cchip.dim[3] = val;
42880bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
42980bb2ff7SRichard Henderson         break;
43080bb2ff7SRichard Henderson 
43180bb2ff7SRichard Henderson     case 0x0680: /* DIR2 (RO) */
43280bb2ff7SRichard Henderson     case 0x06c0: /* DIR3 (RO) */
43380bb2ff7SRichard Henderson         break;
43480bb2ff7SRichard Henderson 
43580bb2ff7SRichard Henderson     case 0x0700: /* IIC2 */
43680bb2ff7SRichard Henderson         s->cchip.iic[2] = val & 0xffffff;
43780bb2ff7SRichard Henderson         break;
43880bb2ff7SRichard Henderson     case 0x0740: /* IIC3 */
43980bb2ff7SRichard Henderson         s->cchip.iic[3] = val & 0xffffff;
44080bb2ff7SRichard Henderson         break;
44180bb2ff7SRichard Henderson 
44280bb2ff7SRichard Henderson     case 0x0780:
44380bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
44480bb2ff7SRichard Henderson         break;
44580bb2ff7SRichard Henderson 
44680bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
44780bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
44880bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
44980bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
45080bb2ff7SRichard Henderson         break;
45180bb2ff7SRichard Henderson 
45280bb2ff7SRichard Henderson     default:
453b7ed683aSPeter Maydell         return MEMTX_ERROR;
45480bb2ff7SRichard Henderson     }
455b7ed683aSPeter Maydell 
456b7ed683aSPeter Maydell     return MEMTX_OK;
45780bb2ff7SRichard Henderson }
45880bb2ff7SRichard Henderson 
459a8170e5eSAvi Kivity static void dchip_write(void *opaque, hwaddr addr,
46080bb2ff7SRichard Henderson                         uint64_t val, unsigned size)
46180bb2ff7SRichard Henderson {
46280bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
46380bb2ff7SRichard Henderson }
46480bb2ff7SRichard Henderson 
465b7ed683aSPeter Maydell static MemTxResult pchip_write(void *opaque, hwaddr addr,
466b7ed683aSPeter Maydell                                uint64_t val, unsigned size,
467b7ed683aSPeter Maydell                                MemTxAttrs attrs)
46880bb2ff7SRichard Henderson {
46980bb2ff7SRichard Henderson     TyphoonState *s = opaque;
47067842165SRichard Henderson     uint64_t oldval;
47180bb2ff7SRichard Henderson 
47280bb2ff7SRichard Henderson     switch (addr) {
47380bb2ff7SRichard Henderson     case 0x0000:
47480bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
475b83c4db8SRichard Henderson         s->pchip.win[0].wba = val & 0xfff00003u;
47680bb2ff7SRichard Henderson         break;
47780bb2ff7SRichard Henderson     case 0x0040:
47880bb2ff7SRichard Henderson         /* WSBA1 */
479b83c4db8SRichard Henderson         s->pchip.win[1].wba = val & 0xfff00003u;
48080bb2ff7SRichard Henderson         break;
48180bb2ff7SRichard Henderson     case 0x0080:
48280bb2ff7SRichard Henderson         /* WSBA2 */
483b83c4db8SRichard Henderson         s->pchip.win[2].wba = val & 0xfff00003u;
48480bb2ff7SRichard Henderson         break;
48580bb2ff7SRichard Henderson     case 0x00c0:
48680bb2ff7SRichard Henderson         /* WSBA3 */
487b83c4db8SRichard Henderson         s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
48880bb2ff7SRichard Henderson         break;
48980bb2ff7SRichard Henderson 
49080bb2ff7SRichard Henderson     case 0x0100:
49180bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
492b83c4db8SRichard Henderson         s->pchip.win[0].wsm = val & 0xfff00000u;
49380bb2ff7SRichard Henderson         break;
49480bb2ff7SRichard Henderson     case 0x0140:
49580bb2ff7SRichard Henderson         /* WSM1 */
496b83c4db8SRichard Henderson         s->pchip.win[1].wsm = val & 0xfff00000u;
49780bb2ff7SRichard Henderson         break;
49880bb2ff7SRichard Henderson     case 0x0180:
49980bb2ff7SRichard Henderson         /* WSM2 */
500b83c4db8SRichard Henderson         s->pchip.win[2].wsm = val & 0xfff00000u;
50180bb2ff7SRichard Henderson         break;
50280bb2ff7SRichard Henderson     case 0x01c0:
50380bb2ff7SRichard Henderson         /* WSM3 */
504b83c4db8SRichard Henderson         s->pchip.win[3].wsm = val & 0xfff00000u;
50580bb2ff7SRichard Henderson         break;
50680bb2ff7SRichard Henderson 
50780bb2ff7SRichard Henderson     case 0x0200:
50880bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
509b83c4db8SRichard Henderson         s->pchip.win[0].tba = val & 0x7fffffc00ull;
51080bb2ff7SRichard Henderson         break;
51180bb2ff7SRichard Henderson     case 0x0240:
51280bb2ff7SRichard Henderson         /* TBA1 */
513b83c4db8SRichard Henderson         s->pchip.win[1].tba = val & 0x7fffffc00ull;
51480bb2ff7SRichard Henderson         break;
51580bb2ff7SRichard Henderson     case 0x0280:
51680bb2ff7SRichard Henderson         /* TBA2 */
517b83c4db8SRichard Henderson         s->pchip.win[2].tba = val & 0x7fffffc00ull;
51880bb2ff7SRichard Henderson         break;
51980bb2ff7SRichard Henderson     case 0x02c0:
52080bb2ff7SRichard Henderson         /* TBA3 */
521b83c4db8SRichard Henderson         s->pchip.win[3].tba = val & 0x7fffffc00ull;
52280bb2ff7SRichard Henderson         break;
52380bb2ff7SRichard Henderson 
52480bb2ff7SRichard Henderson     case 0x0300:
52580bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
52680bb2ff7SRichard Henderson         oldval = s->pchip.ctl;
52780bb2ff7SRichard Henderson         oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
52880bb2ff7SRichard Henderson         oldval |= val & 0x00001cff0fc7ffull;
52980bb2ff7SRichard Henderson         s->pchip.ctl = oldval;
53080bb2ff7SRichard Henderson         break;
53180bb2ff7SRichard Henderson 
53280bb2ff7SRichard Henderson     case 0x0340:
53380bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
53480bb2ff7SRichard Henderson         break;
53580bb2ff7SRichard Henderson     case 0x03c0:
53680bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
53780bb2ff7SRichard Henderson         break;
53880bb2ff7SRichard Henderson     case 0x0400:
53980bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
54080bb2ff7SRichard Henderson         break;
54180bb2ff7SRichard Henderson     case 0x0440:
54280bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
54380bb2ff7SRichard Henderson         break;
54480bb2ff7SRichard Henderson 
54580bb2ff7SRichard Henderson     case 0x0480:
54680bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
54780bb2ff7SRichard Henderson         break;
54880bb2ff7SRichard Henderson 
54980bb2ff7SRichard Henderson     case 0x04c0:
55080bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
55180bb2ff7SRichard Henderson         break;
55280bb2ff7SRichard Henderson 
55380bb2ff7SRichard Henderson     case 0x0500:
55480bb2ff7SRichard Henderson         /* PMONCTL */
55580bb2ff7SRichard Henderson     case 0x0540:
55680bb2ff7SRichard Henderson         /* PMONCNT */
55780bb2ff7SRichard Henderson     case 0x0800:
55880bb2ff7SRichard Henderson         /* SPRST */
55980bb2ff7SRichard Henderson         break;
56080bb2ff7SRichard Henderson 
56180bb2ff7SRichard Henderson     default:
562b7ed683aSPeter Maydell         return MEMTX_ERROR;
56380bb2ff7SRichard Henderson     }
564b7ed683aSPeter Maydell 
565b7ed683aSPeter Maydell     return MEMTX_OK;
56680bb2ff7SRichard Henderson }
56780bb2ff7SRichard Henderson 
56880bb2ff7SRichard Henderson static const MemoryRegionOps cchip_ops = {
569b7ed683aSPeter Maydell     .read_with_attrs = cchip_read,
570b7ed683aSPeter Maydell     .write_with_attrs = cchip_write,
57180bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
57280bb2ff7SRichard Henderson     .valid = {
57367842165SRichard Henderson         .min_access_size = 8,
57480bb2ff7SRichard Henderson         .max_access_size = 8,
57580bb2ff7SRichard Henderson     },
57680bb2ff7SRichard Henderson     .impl = {
57767842165SRichard Henderson         .min_access_size = 8,
57867842165SRichard Henderson         .max_access_size = 8,
57980bb2ff7SRichard Henderson     },
58080bb2ff7SRichard Henderson };
58180bb2ff7SRichard Henderson 
58280bb2ff7SRichard Henderson static const MemoryRegionOps dchip_ops = {
58380bb2ff7SRichard Henderson     .read = dchip_read,
58480bb2ff7SRichard Henderson     .write = dchip_write,
58580bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
58680bb2ff7SRichard Henderson     .valid = {
58767842165SRichard Henderson         .min_access_size = 8,
58880bb2ff7SRichard Henderson         .max_access_size = 8,
58980bb2ff7SRichard Henderson     },
59080bb2ff7SRichard Henderson     .impl = {
59167842165SRichard Henderson         .min_access_size = 8,
59280bb2ff7SRichard Henderson         .max_access_size = 8,
59380bb2ff7SRichard Henderson     },
59480bb2ff7SRichard Henderson };
59580bb2ff7SRichard Henderson 
59680bb2ff7SRichard Henderson static const MemoryRegionOps pchip_ops = {
597b7ed683aSPeter Maydell     .read_with_attrs = pchip_read,
598b7ed683aSPeter Maydell     .write_with_attrs = pchip_write,
59980bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
60080bb2ff7SRichard Henderson     .valid = {
60167842165SRichard Henderson         .min_access_size = 8,
60280bb2ff7SRichard Henderson         .max_access_size = 8,
60380bb2ff7SRichard Henderson     },
60480bb2ff7SRichard Henderson     .impl = {
60567842165SRichard Henderson         .min_access_size = 8,
60667842165SRichard Henderson         .max_access_size = 8,
60780bb2ff7SRichard Henderson     },
60880bb2ff7SRichard Henderson };
60980bb2ff7SRichard Henderson 
610b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
611b83c4db8SRichard Henderson    using the given translated address and mask.  */
612b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
613b83c4db8SRichard Henderson {
614b83c4db8SRichard Henderson     *ret = (IOMMUTLBEntry) {
615b83c4db8SRichard Henderson         .target_as = &address_space_memory,
616b83c4db8SRichard Henderson         .translated_addr = taddr,
617b83c4db8SRichard Henderson         .addr_mask = mask,
618b83c4db8SRichard Henderson         .perm = IOMMU_RW,
619b83c4db8SRichard Henderson     };
620b83c4db8SRichard Henderson     return true;
621b83c4db8SRichard Henderson }
622b83c4db8SRichard Henderson 
623b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather
624b83c4db8SRichard Henderson    translation, given the address of the PTE.  */
625b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
626b83c4db8SRichard Henderson {
62742874d3aSPeter Maydell     uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
62842874d3aSPeter Maydell                                      MEMTXATTRS_UNSPECIFIED, NULL);
629b83c4db8SRichard Henderson 
630b83c4db8SRichard Henderson     /* Check valid bit.  */
631b83c4db8SRichard Henderson     if ((pte & 1) == 0) {
632b83c4db8SRichard Henderson         return false;
633b83c4db8SRichard Henderson     }
634b83c4db8SRichard Henderson 
635b83c4db8SRichard Henderson     return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
636b83c4db8SRichard Henderson }
637b83c4db8SRichard Henderson 
638b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the
639b83c4db8SRichard Henderson    four single-address-cycle translation windows.  */
640b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr,
641b83c4db8SRichard Henderson                              IOMMUTLBEntry *ret)
642b83c4db8SRichard Henderson {
643b83c4db8SRichard Henderson     uint32_t wba = win->wba;
644b83c4db8SRichard Henderson     uint64_t wsm = win->wsm;
645b83c4db8SRichard Henderson     uint64_t tba = win->tba;
646b83c4db8SRichard Henderson     uint64_t wsm_ext = wsm | 0xfffff;
647b83c4db8SRichard Henderson 
648b83c4db8SRichard Henderson     /* Check for window disabled.  */
649b83c4db8SRichard Henderson     if ((wba & 1) == 0) {
650b83c4db8SRichard Henderson         return false;
651b83c4db8SRichard Henderson     }
652b83c4db8SRichard Henderson 
653b83c4db8SRichard Henderson     /* Check for window hit.  */
654b83c4db8SRichard Henderson     if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
655b83c4db8SRichard Henderson         return false;
656b83c4db8SRichard Henderson     }
657b83c4db8SRichard Henderson 
658b83c4db8SRichard Henderson     if (wba & 2) {
659b83c4db8SRichard Henderson         /* Scatter-gather translation.  */
660b83c4db8SRichard Henderson         hwaddr pte_addr;
661b83c4db8SRichard Henderson 
662b83c4db8SRichard Henderson         /* See table 10-6, Generating PTE address for PCI DMA Address.  */
663b83c4db8SRichard Henderson         pte_addr  = tba & ~(wsm >> 10);
664b83c4db8SRichard Henderson         pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
665b83c4db8SRichard Henderson         return pte_translate(pte_addr, ret);
666b83c4db8SRichard Henderson     } else {
667b83c4db8SRichard Henderson         /* Direct-mapped translation.  */
668b83c4db8SRichard Henderson         return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
669b83c4db8SRichard Henderson     }
670b83c4db8SRichard Henderson }
671b83c4db8SRichard Henderson 
672b83c4db8SRichard Henderson /* Handle PCI-to-system address translation.  */
673b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the
674b83c4db8SRichard Henderson    Pchip and generate a machine check interrupt.  */
6753df9d748SAlexey Kardashevskiy static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
6763df9d748SAlexey Kardashevskiy                                              hwaddr addr,
6772c91bcf2SPeter Maydell                                              IOMMUAccessFlags flag,
6782c91bcf2SPeter Maydell                                              int iommu_idx)
679b83c4db8SRichard Henderson {
680b83c4db8SRichard Henderson     TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
681b83c4db8SRichard Henderson     IOMMUTLBEntry ret;
682b83c4db8SRichard Henderson     int i;
683b83c4db8SRichard Henderson 
684b83c4db8SRichard Henderson     if (addr <= 0xffffffffu) {
685b83c4db8SRichard Henderson         /* Single-address cycle.  */
686b83c4db8SRichard Henderson 
687b83c4db8SRichard Henderson         /* Check for the Window Hole, inhibiting matching.  */
688b83c4db8SRichard Henderson         if ((pchip->ctl & 0x20)
689b83c4db8SRichard Henderson             && addr >= 0x80000
690b83c4db8SRichard Henderson             && addr <= 0xfffff) {
691b83c4db8SRichard Henderson             goto failure;
692b83c4db8SRichard Henderson         }
693b83c4db8SRichard Henderson 
694b83c4db8SRichard Henderson         /* Check the first three windows.  */
695b83c4db8SRichard Henderson         for (i = 0; i < 3; ++i) {
696b83c4db8SRichard Henderson             if (window_translate(&pchip->win[i], addr, &ret)) {
697b83c4db8SRichard Henderson                 goto success;
698b83c4db8SRichard Henderson             }
699b83c4db8SRichard Henderson         }
700b83c4db8SRichard Henderson 
701b83c4db8SRichard Henderson         /* Check the fourth window for DAC disable.  */
702b83c4db8SRichard Henderson         if ((pchip->win[3].wba & 0x80000000000ull) == 0
703b83c4db8SRichard Henderson             && window_translate(&pchip->win[3], addr, &ret)) {
704b83c4db8SRichard Henderson             goto success;
705b83c4db8SRichard Henderson         }
706b83c4db8SRichard Henderson     } else {
707b83c4db8SRichard Henderson         /* Double-address cycle.  */
708b83c4db8SRichard Henderson 
709b83c4db8SRichard Henderson         if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
710b83c4db8SRichard Henderson             /* Check for the DMA monster window.  */
711b83c4db8SRichard Henderson             if (pchip->ctl & 0x40) {
712b83c4db8SRichard Henderson                 /* See 10.1.4.4; in particular <39:35> is ignored.  */
713b83c4db8SRichard Henderson                 make_iommu_tlbe(0, 0x007ffffffffull, &ret);
714b83c4db8SRichard Henderson                 goto success;
715b83c4db8SRichard Henderson             }
716b83c4db8SRichard Henderson         }
717b83c4db8SRichard Henderson 
7189b2caaf4SStefan Weil         if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) {
719b83c4db8SRichard Henderson             /* Check the fourth window for DAC enable and window enable.  */
720b83c4db8SRichard Henderson             if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
721b83c4db8SRichard Henderson                 uint64_t pte_addr;
722b83c4db8SRichard Henderson 
723b83c4db8SRichard Henderson                 pte_addr  = pchip->win[3].tba & 0x7ffc00000ull;
724b83c4db8SRichard Henderson                 pte_addr |= (addr & 0xffffe000u) >> 10;
725b83c4db8SRichard Henderson                 if (pte_translate(pte_addr, &ret)) {
726b83c4db8SRichard Henderson                         goto success;
727b83c4db8SRichard Henderson                 }
728b83c4db8SRichard Henderson             }
729b83c4db8SRichard Henderson         }
730b83c4db8SRichard Henderson     }
731b83c4db8SRichard Henderson 
732b83c4db8SRichard Henderson  failure:
733b83c4db8SRichard Henderson     ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
734b83c4db8SRichard Henderson  success:
735b83c4db8SRichard Henderson     return ret;
736b83c4db8SRichard Henderson }
737b83c4db8SRichard Henderson 
738b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
739b83c4db8SRichard Henderson {
740b83c4db8SRichard Henderson     TyphoonState *s = opaque;
741b83c4db8SRichard Henderson     return &s->pchip.iommu_as;
742b83c4db8SRichard Henderson }
743b83c4db8SRichard Henderson 
74480bb2ff7SRichard Henderson static void typhoon_set_irq(void *opaque, int irq, int level)
74580bb2ff7SRichard Henderson {
74680bb2ff7SRichard Henderson     TyphoonState *s = opaque;
74780bb2ff7SRichard Henderson     uint64_t drir;
74880bb2ff7SRichard Henderson     int i;
74980bb2ff7SRichard Henderson 
75080bb2ff7SRichard Henderson     /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
75180bb2ff7SRichard Henderson     drir = s->cchip.drir;
75280bb2ff7SRichard Henderson     if (level) {
75380bb2ff7SRichard Henderson         drir |= 1ull << irq;
75480bb2ff7SRichard Henderson     } else {
75580bb2ff7SRichard Henderson         drir &= ~(1ull << irq);
75680bb2ff7SRichard Henderson     }
75780bb2ff7SRichard Henderson     s->cchip.drir = drir;
75880bb2ff7SRichard Henderson 
75980bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
76080bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
76180bb2ff7SRichard Henderson     }
76280bb2ff7SRichard Henderson }
76380bb2ff7SRichard Henderson 
76480bb2ff7SRichard Henderson static void typhoon_set_isa_irq(void *opaque, int irq, int level)
76580bb2ff7SRichard Henderson {
76680bb2ff7SRichard Henderson     typhoon_set_irq(opaque, 55, level);
76780bb2ff7SRichard Henderson }
76880bb2ff7SRichard Henderson 
76980bb2ff7SRichard Henderson static void typhoon_set_timer_irq(void *opaque, int irq, int level)
77080bb2ff7SRichard Henderson {
77180bb2ff7SRichard Henderson     TyphoonState *s = opaque;
77280bb2ff7SRichard Henderson     int i;
77380bb2ff7SRichard Henderson 
77480bb2ff7SRichard Henderson     /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
77580bb2ff7SRichard Henderson        and so we don't have to worry about missing interrupts just
77680bb2ff7SRichard Henderson        because we never actually ACK the interrupt.  Just ignore any
77780bb2ff7SRichard Henderson        case of the interrupt level going low.  */
77880bb2ff7SRichard Henderson     if (level == 0) {
77980bb2ff7SRichard Henderson         return;
78080bb2ff7SRichard Henderson     }
78180bb2ff7SRichard Henderson 
78280bb2ff7SRichard Henderson     /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
78380bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
784ad601177SAndreas Färber         AlphaCPU *cpu = s->cchip.cpu[i];
785ad601177SAndreas Färber         if (cpu != NULL) {
78680bb2ff7SRichard Henderson             uint32_t iic = s->cchip.iic[i];
78780bb2ff7SRichard Henderson 
78880bb2ff7SRichard Henderson             /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
78980bb2ff7SRichard Henderson                Bit 24 is the OverFlow bit, RO, and set when the count
79080bb2ff7SRichard Henderson                decrements past 0.  When is OF cleared?  My guess is that
79180bb2ff7SRichard Henderson                OF is actually cleared when the IIC is written, and that
79280bb2ff7SRichard Henderson                the ICNT field always decrements.  At least, that's an
79380bb2ff7SRichard Henderson                interpretation that makes sense, and "allows the CPU to
79480bb2ff7SRichard Henderson                determine exactly how mant interval timer ticks were
79580bb2ff7SRichard Henderson                skipped".  At least within the next 4M ticks...  */
79680bb2ff7SRichard Henderson 
79780bb2ff7SRichard Henderson             iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
79880bb2ff7SRichard Henderson             s->cchip.iic[i] = iic;
79980bb2ff7SRichard Henderson 
80080bb2ff7SRichard Henderson             if (iic & 0x1000000) {
80180bb2ff7SRichard Henderson                 /* Set the ITI bit for this cpu.  */
80280bb2ff7SRichard Henderson                 s->cchip.misc |= 1 << (i + 4);
80380bb2ff7SRichard Henderson                 /* And signal the interrupt.  */
804c3affe56SAndreas Färber                 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
80580bb2ff7SRichard Henderson             }
80680bb2ff7SRichard Henderson         }
80780bb2ff7SRichard Henderson     }
80880bb2ff7SRichard Henderson }
80980bb2ff7SRichard Henderson 
810c781cf96SRichard Henderson static void typhoon_alarm_timer(void *opaque)
811c781cf96SRichard Henderson {
812c781cf96SRichard Henderson     TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
813c781cf96SRichard Henderson     int cpu = (uintptr_t)opaque & 3;
814c781cf96SRichard Henderson 
815c781cf96SRichard Henderson     /* Set the ITI bit for this cpu.  */
816c781cf96SRichard Henderson     s->cchip.misc |= 1 << (cpu + 4);
817c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
818c781cf96SRichard Henderson }
819c781cf96SRichard Henderson 
82071baa303SHervé Poussineau PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
82171baa303SHervé Poussineau                      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 
83194dd91d6SAndreas Färber     dev = qdev_create(NULL, 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.  */
85458c24a47SDirk Müller     memory_region_allocate_system_memory(&s->ram_region, OBJECT(s), "ram",
85558c24a47SDirk Müller                                          ram_size);
85680bb2ff7SRichard Henderson     memory_region_add_subregion(addr_space, 0, &s->ram_region);
85780bb2ff7SRichard Henderson 
85880bb2ff7SRichard Henderson     /* TIGbus, 0x801.0000.0000, 1GB.  */
85980bb2ff7SRichard Henderson     /* ??? The TIGbus is used for delivering interrupts, and access to
86080bb2ff7SRichard Henderson        the flash ROM.  I'm not sure that we need to implement it at all.  */
86180bb2ff7SRichard Henderson 
86280bb2ff7SRichard Henderson     /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
86364bde0f3SPaolo Bonzini     memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
8642b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
86502d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80180000000ULL,
86602d6516cSStefan Weil                                 &s->pchip.region);
86780bb2ff7SRichard Henderson 
86880bb2ff7SRichard Henderson     /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
86964bde0f3SPaolo Bonzini     memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
8702b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
87102d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801a0000000ULL,
87202d6516cSStefan Weil                                 &s->cchip.region);
87380bb2ff7SRichard Henderson 
87480bb2ff7SRichard Henderson     /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
87564bde0f3SPaolo Bonzini     memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
8762b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
87702d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801b0000000ULL,
87802d6516cSStefan Weil                                 &s->dchip_region);
87980bb2ff7SRichard Henderson 
88080bb2ff7SRichard Henderson     /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
8812b41742aSPhilippe Mathieu-Daudé     memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4 * GiB);
88202d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80000000000ULL,
88302d6516cSStefan Weil                                 &s->pchip.reg_mem);
88480bb2ff7SRichard Henderson 
88580bb2ff7SRichard Henderson     /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
8863661049fSRichard Henderson     memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops,
8872b41742aSPhilippe Mathieu-Daudé                           NULL, "pci0-io", 32 * MiB);
88802d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fc000000ULL,
88902d6516cSStefan Weil                                 &s->pchip.reg_io);
89080bb2ff7SRichard Henderson 
8911115ff6dSDavid Gibson     b = pci_register_root_bus(dev, "pci",
89280bb2ff7SRichard Henderson                               typhoon_set_irq, sys_map_irq, s,
893056e6baeSRichard Henderson                               &s->pchip.reg_mem, &s->pchip.reg_io,
894056e6baeSRichard Henderson                               0, 64, TYPE_PCI_BUS);
89594dd91d6SAndreas Färber     phb->bus = b;
89650d3bba9SMarcel Apfelbaum     qdev_init_nofail(dev);
89780bb2ff7SRichard Henderson 
898b83c4db8SRichard Henderson     /* Host memory as seen from the PCI side, via the IOMMU.  */
8991221a474SAlexey Kardashevskiy     memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu),
9001221a474SAlexey Kardashevskiy                              TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s),
901b83c4db8SRichard Henderson                              "iommu-typhoon", UINT64_MAX);
9023df9d748SAlexey Kardashevskiy     address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
9033df9d748SAlexey Kardashevskiy                        "pchip0-pci");
904b83c4db8SRichard Henderson     pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
905b83c4db8SRichard Henderson 
90680bb2ff7SRichard Henderson     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
907056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
9082b41742aSPhilippe Mathieu-Daudé                           b, "pci0-iack", 64 * MiB);
90902d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801f8000000ULL,
91002d6516cSStefan Weil                                 &s->pchip.reg_iack);
91180bb2ff7SRichard Henderson 
91280bb2ff7SRichard Henderson     /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
913056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
9142b41742aSPhilippe Mathieu-Daudé                           b, "pci0-conf", 16 * MiB);
91502d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fe000000ULL,
91602d6516cSStefan Weil                                 &s->pchip.reg_conf);
91780bb2ff7SRichard Henderson 
91880bb2ff7SRichard Henderson     /* For the record, these are the mappings for the second PCI bus.
91980bb2ff7SRichard Henderson        We can get away with not implementing them because we indicate
92080bb2ff7SRichard Henderson        via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
92180bb2ff7SRichard Henderson     /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
92280bb2ff7SRichard Henderson     /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
92380bb2ff7SRichard Henderson     /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
92480bb2ff7SRichard Henderson     /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
92580bb2ff7SRichard Henderson     /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
92680bb2ff7SRichard Henderson 
92780bb2ff7SRichard Henderson     /* Init the ISA bus.  */
92880bb2ff7SRichard Henderson     /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
92980bb2ff7SRichard Henderson     {
93054292736SShannon Zhao         qemu_irq *isa_irqs;
93180bb2ff7SRichard Henderson 
932d10e5432SMarkus Armbruster         *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io,
933d10e5432SMarkus Armbruster                                &error_abort);
93454292736SShannon Zhao         isa_irqs = i8259_init(*isa_bus,
93554292736SShannon Zhao                               qemu_allocate_irq(typhoon_set_isa_irq, s, 0));
93671baa303SHervé Poussineau         isa_bus_irqs(*isa_bus, isa_irqs);
93780bb2ff7SRichard Henderson     }
93880bb2ff7SRichard Henderson 
93980bb2ff7SRichard Henderson     return b;
94080bb2ff7SRichard Henderson }
94180bb2ff7SRichard Henderson 
9424240abffSAndreas Färber static const TypeInfo typhoon_pcihost_info = {
94394dd91d6SAndreas Färber     .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
9448558d942SAndreas Färber     .parent        = TYPE_PCI_HOST_BRIDGE,
94539bffca2SAnthony Liguori     .instance_size = sizeof(TyphoonState),
94680bb2ff7SRichard Henderson };
94780bb2ff7SRichard Henderson 
9481221a474SAlexey Kardashevskiy static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
9491221a474SAlexey Kardashevskiy                                                    void *data)
9501221a474SAlexey Kardashevskiy {
9511221a474SAlexey Kardashevskiy     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
9521221a474SAlexey Kardashevskiy 
9531221a474SAlexey Kardashevskiy     imrc->translate = typhoon_translate_iommu;
9541221a474SAlexey Kardashevskiy }
9551221a474SAlexey Kardashevskiy 
9561221a474SAlexey Kardashevskiy static const TypeInfo typhoon_iommu_memory_region_info = {
9571221a474SAlexey Kardashevskiy     .parent = TYPE_IOMMU_MEMORY_REGION,
9581221a474SAlexey Kardashevskiy     .name = TYPE_TYPHOON_IOMMU_MEMORY_REGION,
9591221a474SAlexey Kardashevskiy     .class_init = typhoon_iommu_memory_region_class_init,
9601221a474SAlexey Kardashevskiy };
9611221a474SAlexey Kardashevskiy 
96283f7d43aSAndreas Färber static void typhoon_register_types(void)
96380bb2ff7SRichard Henderson {
96439bffca2SAnthony Liguori     type_register_static(&typhoon_pcihost_info);
9651221a474SAlexey Kardashevskiy     type_register_static(&typhoon_iommu_memory_region_info);
96680bb2ff7SRichard Henderson }
96783f7d43aSAndreas Färber 
96883f7d43aSAndreas Färber type_init(typhoon_register_types)
969