xref: /qemu/hw/alpha/typhoon.c (revision 2b41742a8d852cb07c58b2682851fa2cc5e50bd0)
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*2b41742aSPhilippe Mathieu-Daudé #include "qemu/units.h"
11da34e65cSMarkus Armbruster #include "qapi/error.h"
1280bb2ff7SRichard Henderson #include "cpu.h"
1383c9f4caSPaolo Bonzini #include "hw/hw.h"
14bd2be150SPeter Maydell #include "hw/devices.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 
78a8170e5eSAvi Kivity static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size)
7980bb2ff7SRichard Henderson {
804917cf44SAndreas Färber     CPUState *cpu = current_cpu;
8180bb2ff7SRichard Henderson     TyphoonState *s = opaque;
8280bb2ff7SRichard Henderson     uint64_t ret = 0;
8380bb2ff7SRichard Henderson 
8480bb2ff7SRichard Henderson     switch (addr) {
8580bb2ff7SRichard Henderson     case 0x0000:
8680bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
8780bb2ff7SRichard Henderson         /* All sorts of data here; probably the only thing relevant is
8880bb2ff7SRichard Henderson            PIP<14> Pchip 1 Present = 0.  */
8980bb2ff7SRichard Henderson         break;
9080bb2ff7SRichard Henderson 
9180bb2ff7SRichard Henderson     case 0x0040:
9280bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
9380bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
9480bb2ff7SRichard Henderson         break;
9580bb2ff7SRichard Henderson 
9680bb2ff7SRichard Henderson     case 0x0080:
9780bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
9855e5c285SAndreas Färber         ret = s->cchip.misc | (cpu->cpu_index & 3);
9980bb2ff7SRichard Henderson         break;
10080bb2ff7SRichard Henderson 
10180bb2ff7SRichard Henderson     case 0x00c0:
10280bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
10380bb2ff7SRichard Henderson         break;
10480bb2ff7SRichard Henderson 
10580bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
10680bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
10780bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
10880bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
10980bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
11080bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
11180bb2ff7SRichard Henderson         break;
11280bb2ff7SRichard Henderson 
11380bb2ff7SRichard Henderson     case 0x0200:
11480bb2ff7SRichard Henderson         /* DIM0: Device Interrupt Mask Register, CPU0.  */
11580bb2ff7SRichard Henderson         ret = s->cchip.dim[0];
11680bb2ff7SRichard Henderson         break;
11780bb2ff7SRichard Henderson     case 0x0240:
11880bb2ff7SRichard Henderson         /* DIM1: Device Interrupt Mask Register, CPU1.  */
11980bb2ff7SRichard Henderson         ret = s->cchip.dim[1];
12080bb2ff7SRichard Henderson         break;
12180bb2ff7SRichard Henderson     case 0x0280:
12280bb2ff7SRichard Henderson         /* DIR0: Device Interrupt Request Register, CPU0.  */
12380bb2ff7SRichard Henderson         ret = s->cchip.dim[0] & s->cchip.drir;
12480bb2ff7SRichard Henderson         break;
12580bb2ff7SRichard Henderson     case 0x02c0:
12680bb2ff7SRichard Henderson         /* DIR1: Device Interrupt Request Register, CPU1.  */
12780bb2ff7SRichard Henderson         ret = s->cchip.dim[1] & s->cchip.drir;
12880bb2ff7SRichard Henderson         break;
12980bb2ff7SRichard Henderson     case 0x0300:
13080bb2ff7SRichard Henderson         /* DRIR: Device Raw Interrupt Request Register.  */
13180bb2ff7SRichard Henderson         ret = s->cchip.drir;
13280bb2ff7SRichard Henderson         break;
13380bb2ff7SRichard Henderson 
13480bb2ff7SRichard Henderson     case 0x0340:
13580bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
13680bb2ff7SRichard Henderson         break;
13780bb2ff7SRichard Henderson 
13880bb2ff7SRichard Henderson     case 0x0380:
13980bb2ff7SRichard Henderson         /* IIC0: Interval Ignore Count Register, CPU0.  */
14080bb2ff7SRichard Henderson         ret = s->cchip.iic[0];
14180bb2ff7SRichard Henderson         break;
14280bb2ff7SRichard Henderson     case 0x03c0:
14380bb2ff7SRichard Henderson         /* IIC1: Interval Ignore Count Register, CPU1.  */
14480bb2ff7SRichard Henderson         ret = s->cchip.iic[1];
14580bb2ff7SRichard Henderson         break;
14680bb2ff7SRichard Henderson 
14780bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
14880bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
14980bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
15080bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
15180bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
15280bb2ff7SRichard Henderson         break;
15380bb2ff7SRichard Henderson 
15480bb2ff7SRichard Henderson     case 0x0580:
15580bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
15680bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
15780bb2ff7SRichard Henderson         break;
15880bb2ff7SRichard Henderson     case 0x05c0:
15980bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
16080bb2ff7SRichard Henderson         break;
16180bb2ff7SRichard Henderson 
16280bb2ff7SRichard Henderson     case 0x0600:
16380bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
16480bb2ff7SRichard Henderson         ret = s->cchip.dim[2];
16580bb2ff7SRichard Henderson         break;
16680bb2ff7SRichard Henderson     case 0x0640:
16780bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
16880bb2ff7SRichard Henderson         ret = s->cchip.dim[3];
16980bb2ff7SRichard Henderson         break;
17080bb2ff7SRichard Henderson     case 0x0680:
17180bb2ff7SRichard Henderson         /* DIR2: Device Interrupt Request Register, CPU2.  */
17280bb2ff7SRichard Henderson         ret = s->cchip.dim[2] & s->cchip.drir;
17380bb2ff7SRichard Henderson         break;
17480bb2ff7SRichard Henderson     case 0x06c0:
17580bb2ff7SRichard Henderson         /* DIR3: Device Interrupt Request Register, CPU3.  */
17680bb2ff7SRichard Henderson         ret = s->cchip.dim[3] & s->cchip.drir;
17780bb2ff7SRichard Henderson         break;
17880bb2ff7SRichard Henderson 
17980bb2ff7SRichard Henderson     case 0x0700:
18080bb2ff7SRichard Henderson         /* IIC2: Interval Ignore Count Register, CPU2.  */
18180bb2ff7SRichard Henderson         ret = s->cchip.iic[2];
18280bb2ff7SRichard Henderson         break;
18380bb2ff7SRichard Henderson     case 0x0740:
18480bb2ff7SRichard Henderson         /* IIC3: Interval Ignore Count Register, CPU3.  */
18580bb2ff7SRichard Henderson         ret = s->cchip.iic[3];
18680bb2ff7SRichard Henderson         break;
18780bb2ff7SRichard Henderson 
18880bb2ff7SRichard Henderson     case 0x0780:
18980bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
19080bb2ff7SRichard Henderson         break;
19180bb2ff7SRichard Henderson 
19280bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
19380bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
19480bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
19580bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
19680bb2ff7SRichard Henderson         break;
19780bb2ff7SRichard Henderson 
19880bb2ff7SRichard Henderson     default:
199c658b94fSAndreas Färber         cpu_unassigned_access(cpu, addr, false, false, 0, size);
20080bb2ff7SRichard Henderson         return -1;
20180bb2ff7SRichard Henderson     }
20280bb2ff7SRichard Henderson 
20380bb2ff7SRichard Henderson     return ret;
20480bb2ff7SRichard Henderson }
20580bb2ff7SRichard Henderson 
206a8170e5eSAvi Kivity static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
20780bb2ff7SRichard Henderson {
20880bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
20980bb2ff7SRichard Henderson     return 0;
21080bb2ff7SRichard Henderson }
21180bb2ff7SRichard Henderson 
212a8170e5eSAvi Kivity static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
21380bb2ff7SRichard Henderson {
21480bb2ff7SRichard Henderson     TyphoonState *s = opaque;
21580bb2ff7SRichard Henderson     uint64_t ret = 0;
21680bb2ff7SRichard Henderson 
21780bb2ff7SRichard Henderson     switch (addr) {
21880bb2ff7SRichard Henderson     case 0x0000:
21980bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
220b83c4db8SRichard Henderson         ret = s->pchip.win[0].wba;
22180bb2ff7SRichard Henderson         break;
22280bb2ff7SRichard Henderson     case 0x0040:
22380bb2ff7SRichard Henderson         /* WSBA1 */
224b83c4db8SRichard Henderson         ret = s->pchip.win[1].wba;
22580bb2ff7SRichard Henderson         break;
22680bb2ff7SRichard Henderson     case 0x0080:
22780bb2ff7SRichard Henderson         /* WSBA2 */
228b83c4db8SRichard Henderson         ret = s->pchip.win[2].wba;
22980bb2ff7SRichard Henderson         break;
23080bb2ff7SRichard Henderson     case 0x00c0:
23180bb2ff7SRichard Henderson         /* WSBA3 */
232b83c4db8SRichard Henderson         ret = s->pchip.win[3].wba;
23380bb2ff7SRichard Henderson         break;
23480bb2ff7SRichard Henderson 
23580bb2ff7SRichard Henderson     case 0x0100:
23680bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
237b83c4db8SRichard Henderson         ret = s->pchip.win[0].wsm;
23880bb2ff7SRichard Henderson         break;
23980bb2ff7SRichard Henderson     case 0x0140:
24080bb2ff7SRichard Henderson         /* WSM1 */
241b83c4db8SRichard Henderson         ret = s->pchip.win[1].wsm;
24280bb2ff7SRichard Henderson         break;
24380bb2ff7SRichard Henderson     case 0x0180:
24480bb2ff7SRichard Henderson         /* WSM2 */
245b83c4db8SRichard Henderson         ret = s->pchip.win[2].wsm;
24680bb2ff7SRichard Henderson         break;
24780bb2ff7SRichard Henderson     case 0x01c0:
24880bb2ff7SRichard Henderson         /* WSM3 */
249b83c4db8SRichard Henderson         ret = s->pchip.win[3].wsm;
25080bb2ff7SRichard Henderson         break;
25180bb2ff7SRichard Henderson 
25280bb2ff7SRichard Henderson     case 0x0200:
25380bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
254b83c4db8SRichard Henderson         ret = s->pchip.win[0].tba;
25580bb2ff7SRichard Henderson         break;
25680bb2ff7SRichard Henderson     case 0x0240:
25780bb2ff7SRichard Henderson         /* TBA1 */
258b83c4db8SRichard Henderson         ret = s->pchip.win[1].tba;
25980bb2ff7SRichard Henderson         break;
26080bb2ff7SRichard Henderson     case 0x0280:
26180bb2ff7SRichard Henderson         /* TBA2 */
262b83c4db8SRichard Henderson         ret = s->pchip.win[2].tba;
26380bb2ff7SRichard Henderson         break;
26480bb2ff7SRichard Henderson     case 0x02c0:
26580bb2ff7SRichard Henderson         /* TBA3 */
266b83c4db8SRichard Henderson         ret = s->pchip.win[3].tba;
26780bb2ff7SRichard Henderson         break;
26880bb2ff7SRichard Henderson 
26980bb2ff7SRichard Henderson     case 0x0300:
27080bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
27180bb2ff7SRichard Henderson         ret = s->pchip.ctl;
27280bb2ff7SRichard Henderson         break;
27380bb2ff7SRichard Henderson     case 0x0340:
27480bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
27580bb2ff7SRichard Henderson         break;
27680bb2ff7SRichard Henderson     case 0x03c0:
27780bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
27880bb2ff7SRichard Henderson         break;
27980bb2ff7SRichard Henderson     case 0x0400:
28080bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
28180bb2ff7SRichard Henderson         break;
28280bb2ff7SRichard Henderson     case 0x0440:
28380bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
28480bb2ff7SRichard Henderson         break;
28580bb2ff7SRichard Henderson     case 0x0480:
28680bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
28780bb2ff7SRichard Henderson         break;
28880bb2ff7SRichard Henderson     case 0x04c0:
28980bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
29080bb2ff7SRichard Henderson         break;
29180bb2ff7SRichard Henderson     case 0x0500: /* PMONCTL */
29280bb2ff7SRichard Henderson     case 0x0540: /* PMONCNT */
29380bb2ff7SRichard Henderson     case 0x0800: /* SPRST */
29480bb2ff7SRichard Henderson         break;
29580bb2ff7SRichard Henderson 
29680bb2ff7SRichard Henderson     default:
2974917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, false, false, 0, size);
29880bb2ff7SRichard Henderson         return -1;
29980bb2ff7SRichard Henderson     }
30080bb2ff7SRichard Henderson 
30180bb2ff7SRichard Henderson     return ret;
30280bb2ff7SRichard Henderson }
30380bb2ff7SRichard Henderson 
304a8170e5eSAvi Kivity static void cchip_write(void *opaque, hwaddr addr,
30567842165SRichard Henderson                         uint64_t val, unsigned size)
30680bb2ff7SRichard Henderson {
30780bb2ff7SRichard Henderson     TyphoonState *s = opaque;
30867842165SRichard Henderson     uint64_t oldval, newval;
30980bb2ff7SRichard Henderson 
31080bb2ff7SRichard Henderson     switch (addr) {
31180bb2ff7SRichard Henderson     case 0x0000:
31280bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
31380bb2ff7SRichard Henderson         /* All sorts of data here; nothing relevant RW.  */
31480bb2ff7SRichard Henderson         break;
31580bb2ff7SRichard Henderson 
31680bb2ff7SRichard Henderson     case 0x0040:
31780bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
31880bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
31980bb2ff7SRichard Henderson         break;
32080bb2ff7SRichard Henderson 
32180bb2ff7SRichard Henderson     case 0x0080:
32280bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
32380bb2ff7SRichard Henderson         newval = oldval = s->cchip.misc;
32480bb2ff7SRichard Henderson         newval &= ~(val & 0x10000ff0);     /* W1C fields */
32580bb2ff7SRichard Henderson         if (val & 0x100000) {
32680bb2ff7SRichard Henderson             newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
32780bb2ff7SRichard Henderson         } else {
32880bb2ff7SRichard Henderson             newval |= val & 0x00f00000;    /* ABT field is W1S */
32980bb2ff7SRichard Henderson             if ((newval & 0xf0000) == 0) {
33080bb2ff7SRichard Henderson                 newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
33180bb2ff7SRichard Henderson             }
33280bb2ff7SRichard Henderson         }
33380bb2ff7SRichard Henderson         newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
33480bb2ff7SRichard Henderson 
33580bb2ff7SRichard Henderson         newval &= ~0xf0000000000ull;       /* WO and RW fields */
33680bb2ff7SRichard Henderson         newval |= val & 0xf0000000000ull;
33780bb2ff7SRichard Henderson         s->cchip.misc = newval;
33880bb2ff7SRichard Henderson 
33980bb2ff7SRichard Henderson         /* Pass on changes to IPI and ITI state.  */
34080bb2ff7SRichard Henderson         if ((newval ^ oldval) & 0xff0) {
34180bb2ff7SRichard Henderson             int i;
34280bb2ff7SRichard Henderson             for (i = 0; i < 4; ++i) {
343ad601177SAndreas Färber                 AlphaCPU *cpu = s->cchip.cpu[i];
344ad601177SAndreas Färber                 if (cpu != NULL) {
345d8ed887bSAndreas Färber                     CPUState *cs = CPU(cpu);
34680bb2ff7SRichard Henderson                     /* IPI can be either cleared or set by the write.  */
34780bb2ff7SRichard Henderson                     if (newval & (1 << (i + 8))) {
348c3affe56SAndreas Färber                         cpu_interrupt(cs, CPU_INTERRUPT_SMP);
34980bb2ff7SRichard Henderson                     } else {
350d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
35180bb2ff7SRichard Henderson                     }
35280bb2ff7SRichard Henderson 
35380bb2ff7SRichard Henderson                     /* ITI can only be cleared by the write.  */
35480bb2ff7SRichard Henderson                     if ((newval & (1 << (i + 4))) == 0) {
355d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
35680bb2ff7SRichard Henderson                     }
35780bb2ff7SRichard Henderson                 }
35880bb2ff7SRichard Henderson             }
35980bb2ff7SRichard Henderson         }
36080bb2ff7SRichard Henderson         break;
36180bb2ff7SRichard Henderson 
36280bb2ff7SRichard Henderson     case 0x00c0:
36380bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
36480bb2ff7SRichard Henderson         break;
36580bb2ff7SRichard Henderson 
36680bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
36780bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
36880bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
36980bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
37080bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
37180bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
37280bb2ff7SRichard Henderson         break;
37380bb2ff7SRichard Henderson 
37480bb2ff7SRichard Henderson     case 0x0200: /* DIM0 */
37580bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU0.  */
37680bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
37780bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
37880bb2ff7SRichard Henderson         break;
37980bb2ff7SRichard Henderson     case 0x0240: /* DIM1 */
38080bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU1.  */
381424ad838SRichard Henderson         s->cchip.dim[1] = val;
38280bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
38380bb2ff7SRichard Henderson         break;
38480bb2ff7SRichard Henderson 
38580bb2ff7SRichard Henderson     case 0x0280: /* DIR0 (RO) */
38680bb2ff7SRichard Henderson     case 0x02c0: /* DIR1 (RO) */
38780bb2ff7SRichard Henderson     case 0x0300: /* DRIR (RO) */
38880bb2ff7SRichard Henderson         break;
38980bb2ff7SRichard Henderson 
39080bb2ff7SRichard Henderson     case 0x0340:
39180bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
39280bb2ff7SRichard Henderson         break;
39380bb2ff7SRichard Henderson 
39480bb2ff7SRichard Henderson     case 0x0380: /* IIC0 */
39580bb2ff7SRichard Henderson         s->cchip.iic[0] = val & 0xffffff;
39680bb2ff7SRichard Henderson         break;
39780bb2ff7SRichard Henderson     case 0x03c0: /* IIC1 */
39880bb2ff7SRichard Henderson         s->cchip.iic[1] = val & 0xffffff;
39980bb2ff7SRichard Henderson         break;
40080bb2ff7SRichard Henderson 
40180bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
40280bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
40380bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
40480bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
40580bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
40680bb2ff7SRichard Henderson         break;
40780bb2ff7SRichard Henderson 
40880bb2ff7SRichard Henderson     case 0x0580:
40980bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
41080bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
41180bb2ff7SRichard Henderson         break;
41280bb2ff7SRichard Henderson     case 0x05c0:
41380bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
41480bb2ff7SRichard Henderson         break;
41580bb2ff7SRichard Henderson 
41680bb2ff7SRichard Henderson     case 0x0600:
41780bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
41880bb2ff7SRichard Henderson         s->cchip.dim[2] = val;
41980bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
42080bb2ff7SRichard Henderson         break;
42180bb2ff7SRichard Henderson     case 0x0640:
42280bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
42380bb2ff7SRichard Henderson         s->cchip.dim[3] = val;
42480bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
42580bb2ff7SRichard Henderson         break;
42680bb2ff7SRichard Henderson 
42780bb2ff7SRichard Henderson     case 0x0680: /* DIR2 (RO) */
42880bb2ff7SRichard Henderson     case 0x06c0: /* DIR3 (RO) */
42980bb2ff7SRichard Henderson         break;
43080bb2ff7SRichard Henderson 
43180bb2ff7SRichard Henderson     case 0x0700: /* IIC2 */
43280bb2ff7SRichard Henderson         s->cchip.iic[2] = val & 0xffffff;
43380bb2ff7SRichard Henderson         break;
43480bb2ff7SRichard Henderson     case 0x0740: /* IIC3 */
43580bb2ff7SRichard Henderson         s->cchip.iic[3] = val & 0xffffff;
43680bb2ff7SRichard Henderson         break;
43780bb2ff7SRichard Henderson 
43880bb2ff7SRichard Henderson     case 0x0780:
43980bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
44080bb2ff7SRichard Henderson         break;
44180bb2ff7SRichard Henderson 
44280bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
44380bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
44480bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
44580bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
44680bb2ff7SRichard Henderson         break;
44780bb2ff7SRichard Henderson 
44880bb2ff7SRichard Henderson     default:
4494917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
45080bb2ff7SRichard Henderson         return;
45180bb2ff7SRichard Henderson     }
45280bb2ff7SRichard Henderson }
45380bb2ff7SRichard Henderson 
454a8170e5eSAvi Kivity static void dchip_write(void *opaque, hwaddr addr,
45580bb2ff7SRichard Henderson                         uint64_t val, unsigned size)
45680bb2ff7SRichard Henderson {
45780bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
45880bb2ff7SRichard Henderson }
45980bb2ff7SRichard Henderson 
460a8170e5eSAvi Kivity static void pchip_write(void *opaque, hwaddr addr,
46167842165SRichard Henderson                         uint64_t val, unsigned size)
46280bb2ff7SRichard Henderson {
46380bb2ff7SRichard Henderson     TyphoonState *s = opaque;
46467842165SRichard Henderson     uint64_t oldval;
46580bb2ff7SRichard Henderson 
46680bb2ff7SRichard Henderson     switch (addr) {
46780bb2ff7SRichard Henderson     case 0x0000:
46880bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
469b83c4db8SRichard Henderson         s->pchip.win[0].wba = val & 0xfff00003u;
47080bb2ff7SRichard Henderson         break;
47180bb2ff7SRichard Henderson     case 0x0040:
47280bb2ff7SRichard Henderson         /* WSBA1 */
473b83c4db8SRichard Henderson         s->pchip.win[1].wba = val & 0xfff00003u;
47480bb2ff7SRichard Henderson         break;
47580bb2ff7SRichard Henderson     case 0x0080:
47680bb2ff7SRichard Henderson         /* WSBA2 */
477b83c4db8SRichard Henderson         s->pchip.win[2].wba = val & 0xfff00003u;
47880bb2ff7SRichard Henderson         break;
47980bb2ff7SRichard Henderson     case 0x00c0:
48080bb2ff7SRichard Henderson         /* WSBA3 */
481b83c4db8SRichard Henderson         s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
48280bb2ff7SRichard Henderson         break;
48380bb2ff7SRichard Henderson 
48480bb2ff7SRichard Henderson     case 0x0100:
48580bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
486b83c4db8SRichard Henderson         s->pchip.win[0].wsm = val & 0xfff00000u;
48780bb2ff7SRichard Henderson         break;
48880bb2ff7SRichard Henderson     case 0x0140:
48980bb2ff7SRichard Henderson         /* WSM1 */
490b83c4db8SRichard Henderson         s->pchip.win[1].wsm = val & 0xfff00000u;
49180bb2ff7SRichard Henderson         break;
49280bb2ff7SRichard Henderson     case 0x0180:
49380bb2ff7SRichard Henderson         /* WSM2 */
494b83c4db8SRichard Henderson         s->pchip.win[2].wsm = val & 0xfff00000u;
49580bb2ff7SRichard Henderson         break;
49680bb2ff7SRichard Henderson     case 0x01c0:
49780bb2ff7SRichard Henderson         /* WSM3 */
498b83c4db8SRichard Henderson         s->pchip.win[3].wsm = val & 0xfff00000u;
49980bb2ff7SRichard Henderson         break;
50080bb2ff7SRichard Henderson 
50180bb2ff7SRichard Henderson     case 0x0200:
50280bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
503b83c4db8SRichard Henderson         s->pchip.win[0].tba = val & 0x7fffffc00ull;
50480bb2ff7SRichard Henderson         break;
50580bb2ff7SRichard Henderson     case 0x0240:
50680bb2ff7SRichard Henderson         /* TBA1 */
507b83c4db8SRichard Henderson         s->pchip.win[1].tba = val & 0x7fffffc00ull;
50880bb2ff7SRichard Henderson         break;
50980bb2ff7SRichard Henderson     case 0x0280:
51080bb2ff7SRichard Henderson         /* TBA2 */
511b83c4db8SRichard Henderson         s->pchip.win[2].tba = val & 0x7fffffc00ull;
51280bb2ff7SRichard Henderson         break;
51380bb2ff7SRichard Henderson     case 0x02c0:
51480bb2ff7SRichard Henderson         /* TBA3 */
515b83c4db8SRichard Henderson         s->pchip.win[3].tba = val & 0x7fffffc00ull;
51680bb2ff7SRichard Henderson         break;
51780bb2ff7SRichard Henderson 
51880bb2ff7SRichard Henderson     case 0x0300:
51980bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
52080bb2ff7SRichard Henderson         oldval = s->pchip.ctl;
52180bb2ff7SRichard Henderson         oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
52280bb2ff7SRichard Henderson         oldval |= val & 0x00001cff0fc7ffull;
52380bb2ff7SRichard Henderson         s->pchip.ctl = oldval;
52480bb2ff7SRichard Henderson         break;
52580bb2ff7SRichard Henderson 
52680bb2ff7SRichard Henderson     case 0x0340:
52780bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
52880bb2ff7SRichard Henderson         break;
52980bb2ff7SRichard Henderson     case 0x03c0:
53080bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
53180bb2ff7SRichard Henderson         break;
53280bb2ff7SRichard Henderson     case 0x0400:
53380bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
53480bb2ff7SRichard Henderson         break;
53580bb2ff7SRichard Henderson     case 0x0440:
53680bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
53780bb2ff7SRichard Henderson         break;
53880bb2ff7SRichard Henderson 
53980bb2ff7SRichard Henderson     case 0x0480:
54080bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
54180bb2ff7SRichard Henderson         break;
54280bb2ff7SRichard Henderson 
54380bb2ff7SRichard Henderson     case 0x04c0:
54480bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
54580bb2ff7SRichard Henderson         break;
54680bb2ff7SRichard Henderson 
54780bb2ff7SRichard Henderson     case 0x0500:
54880bb2ff7SRichard Henderson         /* PMONCTL */
54980bb2ff7SRichard Henderson     case 0x0540:
55080bb2ff7SRichard Henderson         /* PMONCNT */
55180bb2ff7SRichard Henderson     case 0x0800:
55280bb2ff7SRichard Henderson         /* SPRST */
55380bb2ff7SRichard Henderson         break;
55480bb2ff7SRichard Henderson 
55580bb2ff7SRichard Henderson     default:
5564917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
55780bb2ff7SRichard Henderson         return;
55880bb2ff7SRichard Henderson     }
55980bb2ff7SRichard Henderson }
56080bb2ff7SRichard Henderson 
56180bb2ff7SRichard Henderson static const MemoryRegionOps cchip_ops = {
56280bb2ff7SRichard Henderson     .read = cchip_read,
56380bb2ff7SRichard Henderson     .write = cchip_write,
56480bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
56580bb2ff7SRichard Henderson     .valid = {
56667842165SRichard Henderson         .min_access_size = 8,
56780bb2ff7SRichard Henderson         .max_access_size = 8,
56880bb2ff7SRichard Henderson     },
56980bb2ff7SRichard Henderson     .impl = {
57067842165SRichard Henderson         .min_access_size = 8,
57167842165SRichard Henderson         .max_access_size = 8,
57280bb2ff7SRichard Henderson     },
57380bb2ff7SRichard Henderson };
57480bb2ff7SRichard Henderson 
57580bb2ff7SRichard Henderson static const MemoryRegionOps dchip_ops = {
57680bb2ff7SRichard Henderson     .read = dchip_read,
57780bb2ff7SRichard Henderson     .write = dchip_write,
57880bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
57980bb2ff7SRichard Henderson     .valid = {
58067842165SRichard Henderson         .min_access_size = 8,
58180bb2ff7SRichard Henderson         .max_access_size = 8,
58280bb2ff7SRichard Henderson     },
58380bb2ff7SRichard Henderson     .impl = {
58467842165SRichard Henderson         .min_access_size = 8,
58580bb2ff7SRichard Henderson         .max_access_size = 8,
58680bb2ff7SRichard Henderson     },
58780bb2ff7SRichard Henderson };
58880bb2ff7SRichard Henderson 
58980bb2ff7SRichard Henderson static const MemoryRegionOps pchip_ops = {
59080bb2ff7SRichard Henderson     .read = pchip_read,
59180bb2ff7SRichard Henderson     .write = pchip_write,
59280bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
59380bb2ff7SRichard Henderson     .valid = {
59467842165SRichard Henderson         .min_access_size = 8,
59580bb2ff7SRichard Henderson         .max_access_size = 8,
59680bb2ff7SRichard Henderson     },
59780bb2ff7SRichard Henderson     .impl = {
59867842165SRichard Henderson         .min_access_size = 8,
59967842165SRichard Henderson         .max_access_size = 8,
60080bb2ff7SRichard Henderson     },
60180bb2ff7SRichard Henderson };
60280bb2ff7SRichard Henderson 
603b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
604b83c4db8SRichard Henderson    using the given translated address and mask.  */
605b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
606b83c4db8SRichard Henderson {
607b83c4db8SRichard Henderson     *ret = (IOMMUTLBEntry) {
608b83c4db8SRichard Henderson         .target_as = &address_space_memory,
609b83c4db8SRichard Henderson         .translated_addr = taddr,
610b83c4db8SRichard Henderson         .addr_mask = mask,
611b83c4db8SRichard Henderson         .perm = IOMMU_RW,
612b83c4db8SRichard Henderson     };
613b83c4db8SRichard Henderson     return true;
614b83c4db8SRichard Henderson }
615b83c4db8SRichard Henderson 
616b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather
617b83c4db8SRichard Henderson    translation, given the address of the PTE.  */
618b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
619b83c4db8SRichard Henderson {
62042874d3aSPeter Maydell     uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
62142874d3aSPeter Maydell                                      MEMTXATTRS_UNSPECIFIED, NULL);
622b83c4db8SRichard Henderson 
623b83c4db8SRichard Henderson     /* Check valid bit.  */
624b83c4db8SRichard Henderson     if ((pte & 1) == 0) {
625b83c4db8SRichard Henderson         return false;
626b83c4db8SRichard Henderson     }
627b83c4db8SRichard Henderson 
628b83c4db8SRichard Henderson     return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
629b83c4db8SRichard Henderson }
630b83c4db8SRichard Henderson 
631b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the
632b83c4db8SRichard Henderson    four single-address-cycle translation windows.  */
633b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr,
634b83c4db8SRichard Henderson                              IOMMUTLBEntry *ret)
635b83c4db8SRichard Henderson {
636b83c4db8SRichard Henderson     uint32_t wba = win->wba;
637b83c4db8SRichard Henderson     uint64_t wsm = win->wsm;
638b83c4db8SRichard Henderson     uint64_t tba = win->tba;
639b83c4db8SRichard Henderson     uint64_t wsm_ext = wsm | 0xfffff;
640b83c4db8SRichard Henderson 
641b83c4db8SRichard Henderson     /* Check for window disabled.  */
642b83c4db8SRichard Henderson     if ((wba & 1) == 0) {
643b83c4db8SRichard Henderson         return false;
644b83c4db8SRichard Henderson     }
645b83c4db8SRichard Henderson 
646b83c4db8SRichard Henderson     /* Check for window hit.  */
647b83c4db8SRichard Henderson     if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
648b83c4db8SRichard Henderson         return false;
649b83c4db8SRichard Henderson     }
650b83c4db8SRichard Henderson 
651b83c4db8SRichard Henderson     if (wba & 2) {
652b83c4db8SRichard Henderson         /* Scatter-gather translation.  */
653b83c4db8SRichard Henderson         hwaddr pte_addr;
654b83c4db8SRichard Henderson 
655b83c4db8SRichard Henderson         /* See table 10-6, Generating PTE address for PCI DMA Address.  */
656b83c4db8SRichard Henderson         pte_addr  = tba & ~(wsm >> 10);
657b83c4db8SRichard Henderson         pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
658b83c4db8SRichard Henderson         return pte_translate(pte_addr, ret);
659b83c4db8SRichard Henderson     } else {
660b83c4db8SRichard Henderson 	/* Direct-mapped translation.  */
661b83c4db8SRichard Henderson 	return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
662b83c4db8SRichard Henderson     }
663b83c4db8SRichard Henderson }
664b83c4db8SRichard Henderson 
665b83c4db8SRichard Henderson /* Handle PCI-to-system address translation.  */
666b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the
667b83c4db8SRichard Henderson    Pchip and generate a machine check interrupt.  */
6683df9d748SAlexey Kardashevskiy static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
6693df9d748SAlexey Kardashevskiy                                              hwaddr addr,
6702c91bcf2SPeter Maydell                                              IOMMUAccessFlags flag,
6712c91bcf2SPeter Maydell                                              int iommu_idx)
672b83c4db8SRichard Henderson {
673b83c4db8SRichard Henderson     TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
674b83c4db8SRichard Henderson     IOMMUTLBEntry ret;
675b83c4db8SRichard Henderson     int i;
676b83c4db8SRichard Henderson 
677b83c4db8SRichard Henderson     if (addr <= 0xffffffffu) {
678b83c4db8SRichard Henderson         /* Single-address cycle.  */
679b83c4db8SRichard Henderson 
680b83c4db8SRichard Henderson         /* Check for the Window Hole, inhibiting matching.  */
681b83c4db8SRichard Henderson         if ((pchip->ctl & 0x20)
682b83c4db8SRichard Henderson             && addr >= 0x80000
683b83c4db8SRichard Henderson             && addr <= 0xfffff) {
684b83c4db8SRichard Henderson             goto failure;
685b83c4db8SRichard Henderson         }
686b83c4db8SRichard Henderson 
687b83c4db8SRichard Henderson         /* Check the first three windows.  */
688b83c4db8SRichard Henderson         for (i = 0; i < 3; ++i) {
689b83c4db8SRichard Henderson             if (window_translate(&pchip->win[i], addr, &ret)) {
690b83c4db8SRichard Henderson                 goto success;
691b83c4db8SRichard Henderson             }
692b83c4db8SRichard Henderson         }
693b83c4db8SRichard Henderson 
694b83c4db8SRichard Henderson         /* Check the fourth window for DAC disable.  */
695b83c4db8SRichard Henderson         if ((pchip->win[3].wba & 0x80000000000ull) == 0
696b83c4db8SRichard Henderson 	    && window_translate(&pchip->win[3], addr, &ret)) {
697b83c4db8SRichard Henderson             goto success;
698b83c4db8SRichard Henderson         }
699b83c4db8SRichard Henderson     } else {
700b83c4db8SRichard Henderson         /* Double-address cycle.  */
701b83c4db8SRichard Henderson 
702b83c4db8SRichard Henderson         if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
703b83c4db8SRichard Henderson             /* Check for the DMA monster window.  */
704b83c4db8SRichard Henderson             if (pchip->ctl & 0x40) {
705b83c4db8SRichard Henderson                 /* See 10.1.4.4; in particular <39:35> is ignored.  */
706b83c4db8SRichard Henderson                 make_iommu_tlbe(0, 0x007ffffffffull, &ret);
707b83c4db8SRichard Henderson 		goto success;
708b83c4db8SRichard Henderson             }
709b83c4db8SRichard Henderson         }
710b83c4db8SRichard Henderson 
7119b2caaf4SStefan Weil         if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) {
712b83c4db8SRichard Henderson             /* Check the fourth window for DAC enable and window enable.  */
713b83c4db8SRichard Henderson             if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
714b83c4db8SRichard Henderson                 uint64_t pte_addr;
715b83c4db8SRichard Henderson 
716b83c4db8SRichard Henderson                 pte_addr  = pchip->win[3].tba & 0x7ffc00000ull;
717b83c4db8SRichard Henderson                 pte_addr |= (addr & 0xffffe000u) >> 10;
718b83c4db8SRichard Henderson                 if (pte_translate(pte_addr, &ret)) {
719b83c4db8SRichard Henderson 			goto success;
720b83c4db8SRichard Henderson 		}
721b83c4db8SRichard Henderson             }
722b83c4db8SRichard Henderson         }
723b83c4db8SRichard Henderson     }
724b83c4db8SRichard Henderson 
725b83c4db8SRichard Henderson  failure:
726b83c4db8SRichard Henderson     ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
727b83c4db8SRichard Henderson  success:
728b83c4db8SRichard Henderson     return ret;
729b83c4db8SRichard Henderson }
730b83c4db8SRichard Henderson 
731b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
732b83c4db8SRichard Henderson {
733b83c4db8SRichard Henderson     TyphoonState *s = opaque;
734b83c4db8SRichard Henderson     return &s->pchip.iommu_as;
735b83c4db8SRichard Henderson }
736b83c4db8SRichard Henderson 
73780bb2ff7SRichard Henderson static void typhoon_set_irq(void *opaque, int irq, int level)
73880bb2ff7SRichard Henderson {
73980bb2ff7SRichard Henderson     TyphoonState *s = opaque;
74080bb2ff7SRichard Henderson     uint64_t drir;
74180bb2ff7SRichard Henderson     int i;
74280bb2ff7SRichard Henderson 
74380bb2ff7SRichard Henderson     /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
74480bb2ff7SRichard Henderson     drir = s->cchip.drir;
74580bb2ff7SRichard Henderson     if (level) {
74680bb2ff7SRichard Henderson         drir |= 1ull << irq;
74780bb2ff7SRichard Henderson     } else {
74880bb2ff7SRichard Henderson         drir &= ~(1ull << irq);
74980bb2ff7SRichard Henderson     }
75080bb2ff7SRichard Henderson     s->cchip.drir = drir;
75180bb2ff7SRichard Henderson 
75280bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
75380bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
75480bb2ff7SRichard Henderson     }
75580bb2ff7SRichard Henderson }
75680bb2ff7SRichard Henderson 
75780bb2ff7SRichard Henderson static void typhoon_set_isa_irq(void *opaque, int irq, int level)
75880bb2ff7SRichard Henderson {
75980bb2ff7SRichard Henderson     typhoon_set_irq(opaque, 55, level);
76080bb2ff7SRichard Henderson }
76180bb2ff7SRichard Henderson 
76280bb2ff7SRichard Henderson static void typhoon_set_timer_irq(void *opaque, int irq, int level)
76380bb2ff7SRichard Henderson {
76480bb2ff7SRichard Henderson     TyphoonState *s = opaque;
76580bb2ff7SRichard Henderson     int i;
76680bb2ff7SRichard Henderson 
76780bb2ff7SRichard Henderson     /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
76880bb2ff7SRichard Henderson        and so we don't have to worry about missing interrupts just
76980bb2ff7SRichard Henderson        because we never actually ACK the interrupt.  Just ignore any
77080bb2ff7SRichard Henderson        case of the interrupt level going low.  */
77180bb2ff7SRichard Henderson     if (level == 0) {
77280bb2ff7SRichard Henderson         return;
77380bb2ff7SRichard Henderson     }
77480bb2ff7SRichard Henderson 
77580bb2ff7SRichard Henderson     /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
77680bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
777ad601177SAndreas Färber         AlphaCPU *cpu = s->cchip.cpu[i];
778ad601177SAndreas Färber         if (cpu != NULL) {
77980bb2ff7SRichard Henderson             uint32_t iic = s->cchip.iic[i];
78080bb2ff7SRichard Henderson 
78180bb2ff7SRichard Henderson             /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
78280bb2ff7SRichard Henderson                Bit 24 is the OverFlow bit, RO, and set when the count
78380bb2ff7SRichard Henderson                decrements past 0.  When is OF cleared?  My guess is that
78480bb2ff7SRichard Henderson                OF is actually cleared when the IIC is written, and that
78580bb2ff7SRichard Henderson                the ICNT field always decrements.  At least, that's an
78680bb2ff7SRichard Henderson                interpretation that makes sense, and "allows the CPU to
78780bb2ff7SRichard Henderson                determine exactly how mant interval timer ticks were
78880bb2ff7SRichard Henderson                skipped".  At least within the next 4M ticks...  */
78980bb2ff7SRichard Henderson 
79080bb2ff7SRichard Henderson             iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
79180bb2ff7SRichard Henderson             s->cchip.iic[i] = iic;
79280bb2ff7SRichard Henderson 
79380bb2ff7SRichard Henderson             if (iic & 0x1000000) {
79480bb2ff7SRichard Henderson                 /* Set the ITI bit for this cpu.  */
79580bb2ff7SRichard Henderson                 s->cchip.misc |= 1 << (i + 4);
79680bb2ff7SRichard Henderson                 /* And signal the interrupt.  */
797c3affe56SAndreas Färber                 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
79880bb2ff7SRichard Henderson             }
79980bb2ff7SRichard Henderson         }
80080bb2ff7SRichard Henderson     }
80180bb2ff7SRichard Henderson }
80280bb2ff7SRichard Henderson 
803c781cf96SRichard Henderson static void typhoon_alarm_timer(void *opaque)
804c781cf96SRichard Henderson {
805c781cf96SRichard Henderson     TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
806c781cf96SRichard Henderson     int cpu = (uintptr_t)opaque & 3;
807c781cf96SRichard Henderson 
808c781cf96SRichard Henderson     /* Set the ITI bit for this cpu.  */
809c781cf96SRichard Henderson     s->cchip.misc |= 1 << (cpu + 4);
810c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
811c781cf96SRichard Henderson }
812c781cf96SRichard Henderson 
81371baa303SHervé Poussineau PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
81471baa303SHervé Poussineau                      qemu_irq *p_rtc_irq,
815ad601177SAndreas Färber                      AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq)
81680bb2ff7SRichard Henderson {
81780bb2ff7SRichard Henderson     MemoryRegion *addr_space = get_system_memory();
81880bb2ff7SRichard Henderson     DeviceState *dev;
81980bb2ff7SRichard Henderson     TyphoonState *s;
82094dd91d6SAndreas Färber     PCIHostState *phb;
82180bb2ff7SRichard Henderson     PCIBus *b;
822c781cf96SRichard Henderson     int i;
82380bb2ff7SRichard Henderson 
82494dd91d6SAndreas Färber     dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
82580bb2ff7SRichard Henderson 
82694dd91d6SAndreas Färber     s = TYPHOON_PCI_HOST_BRIDGE(dev);
8278558d942SAndreas Färber     phb = PCI_HOST_BRIDGE(dev);
82880bb2ff7SRichard Henderson 
829b83c4db8SRichard Henderson     s->cchip.misc = 0x800000000ull; /* Revision: Typhoon.  */
830b83c4db8SRichard Henderson     s->pchip.win[3].wba = 2;        /* Window 3 SG always enabled. */
831b83c4db8SRichard Henderson 
83280bb2ff7SRichard Henderson     /* Remember the CPUs so that we can deliver interrupts to them.  */
833c781cf96SRichard Henderson     for (i = 0; i < 4; i++) {
834ad601177SAndreas Färber         AlphaCPU *cpu = cpus[i];
835ad601177SAndreas Färber         s->cchip.cpu[i] = cpu;
836ad601177SAndreas Färber         if (cpu != NULL) {
837bc72ad67SAlex Bligh             cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
838c781cf96SRichard Henderson                                                  typhoon_alarm_timer,
839c781cf96SRichard Henderson                                                  (void *)((uintptr_t)s + i));
840c781cf96SRichard Henderson         }
841c781cf96SRichard Henderson     }
84280bb2ff7SRichard Henderson 
84354292736SShannon Zhao     *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
84480bb2ff7SRichard Henderson 
84580bb2ff7SRichard Henderson     /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
84680bb2ff7SRichard Henderson        but the address space hole reserved at this point is 8TB.  */
84758c24a47SDirk Müller     memory_region_allocate_system_memory(&s->ram_region, OBJECT(s), "ram",
84858c24a47SDirk Müller                                          ram_size);
84980bb2ff7SRichard Henderson     memory_region_add_subregion(addr_space, 0, &s->ram_region);
85080bb2ff7SRichard Henderson 
85180bb2ff7SRichard Henderson     /* TIGbus, 0x801.0000.0000, 1GB.  */
85280bb2ff7SRichard Henderson     /* ??? The TIGbus is used for delivering interrupts, and access to
85380bb2ff7SRichard Henderson        the flash ROM.  I'm not sure that we need to implement it at all.  */
85480bb2ff7SRichard Henderson 
85580bb2ff7SRichard Henderson     /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
85664bde0f3SPaolo Bonzini     memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
857*2b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
85802d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80180000000ULL,
85902d6516cSStefan Weil                                 &s->pchip.region);
86080bb2ff7SRichard Henderson 
86180bb2ff7SRichard Henderson     /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
86264bde0f3SPaolo Bonzini     memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
863*2b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
86402d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801a0000000ULL,
86502d6516cSStefan Weil                                 &s->cchip.region);
86680bb2ff7SRichard Henderson 
86780bb2ff7SRichard Henderson     /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
86864bde0f3SPaolo Bonzini     memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
869*2b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
87002d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801b0000000ULL,
87102d6516cSStefan Weil                                 &s->dchip_region);
87280bb2ff7SRichard Henderson 
87380bb2ff7SRichard Henderson     /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
874*2b41742aSPhilippe Mathieu-Daudé     memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4 * GiB);
87502d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80000000000ULL,
87602d6516cSStefan Weil                                 &s->pchip.reg_mem);
87780bb2ff7SRichard Henderson 
87880bb2ff7SRichard Henderson     /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
8793661049fSRichard Henderson     memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops,
880*2b41742aSPhilippe Mathieu-Daudé                           NULL, "pci0-io", 32 * MiB);
88102d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fc000000ULL,
88202d6516cSStefan Weil                                 &s->pchip.reg_io);
88380bb2ff7SRichard Henderson 
8841115ff6dSDavid Gibson     b = pci_register_root_bus(dev, "pci",
88580bb2ff7SRichard Henderson                               typhoon_set_irq, sys_map_irq, s,
886056e6baeSRichard Henderson                               &s->pchip.reg_mem, &s->pchip.reg_io,
887056e6baeSRichard Henderson                               0, 64, TYPE_PCI_BUS);
88894dd91d6SAndreas Färber     phb->bus = b;
88950d3bba9SMarcel Apfelbaum     qdev_init_nofail(dev);
89080bb2ff7SRichard Henderson 
891b83c4db8SRichard Henderson     /* Host memory as seen from the PCI side, via the IOMMU.  */
8921221a474SAlexey Kardashevskiy     memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu),
8931221a474SAlexey Kardashevskiy                              TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s),
894b83c4db8SRichard Henderson                              "iommu-typhoon", UINT64_MAX);
8953df9d748SAlexey Kardashevskiy     address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
8963df9d748SAlexey Kardashevskiy                        "pchip0-pci");
897b83c4db8SRichard Henderson     pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
898b83c4db8SRichard Henderson 
89980bb2ff7SRichard Henderson     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
900056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
901*2b41742aSPhilippe Mathieu-Daudé                           b, "pci0-iack", 64 * MiB);
90202d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801f8000000ULL,
90302d6516cSStefan Weil                                 &s->pchip.reg_iack);
90480bb2ff7SRichard Henderson 
90580bb2ff7SRichard Henderson     /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
906056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
907*2b41742aSPhilippe Mathieu-Daudé                           b, "pci0-conf", 16 * MiB);
90802d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fe000000ULL,
90902d6516cSStefan Weil                                 &s->pchip.reg_conf);
91080bb2ff7SRichard Henderson 
91180bb2ff7SRichard Henderson     /* For the record, these are the mappings for the second PCI bus.
91280bb2ff7SRichard Henderson        We can get away with not implementing them because we indicate
91380bb2ff7SRichard Henderson        via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
91480bb2ff7SRichard Henderson     /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
91580bb2ff7SRichard Henderson     /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
91680bb2ff7SRichard Henderson     /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
91780bb2ff7SRichard Henderson     /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
91880bb2ff7SRichard Henderson     /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
91980bb2ff7SRichard Henderson 
92080bb2ff7SRichard Henderson     /* Init the ISA bus.  */
92180bb2ff7SRichard Henderson     /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
92280bb2ff7SRichard Henderson     {
92354292736SShannon Zhao         qemu_irq *isa_irqs;
92480bb2ff7SRichard Henderson 
925d10e5432SMarkus Armbruster         *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io,
926d10e5432SMarkus Armbruster                                &error_abort);
92754292736SShannon Zhao         isa_irqs = i8259_init(*isa_bus,
92854292736SShannon Zhao                               qemu_allocate_irq(typhoon_set_isa_irq, s, 0));
92971baa303SHervé Poussineau         isa_bus_irqs(*isa_bus, isa_irqs);
93080bb2ff7SRichard Henderson     }
93180bb2ff7SRichard Henderson 
93280bb2ff7SRichard Henderson     return b;
93380bb2ff7SRichard Henderson }
93480bb2ff7SRichard Henderson 
93580bb2ff7SRichard Henderson static int typhoon_pcihost_init(SysBusDevice *dev)
93680bb2ff7SRichard Henderson {
93780bb2ff7SRichard Henderson     return 0;
93880bb2ff7SRichard Henderson }
93980bb2ff7SRichard Henderson 
940999e12bbSAnthony Liguori static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
941999e12bbSAnthony Liguori {
942999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
943999e12bbSAnthony Liguori 
944999e12bbSAnthony Liguori     k->init = typhoon_pcihost_init;
945999e12bbSAnthony Liguori }
946999e12bbSAnthony Liguori 
9474240abffSAndreas Färber static const TypeInfo typhoon_pcihost_info = {
94894dd91d6SAndreas Färber     .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
9498558d942SAndreas Färber     .parent        = TYPE_PCI_HOST_BRIDGE,
95039bffca2SAnthony Liguori     .instance_size = sizeof(TyphoonState),
951999e12bbSAnthony Liguori     .class_init    = typhoon_pcihost_class_init,
95280bb2ff7SRichard Henderson };
95380bb2ff7SRichard Henderson 
9541221a474SAlexey Kardashevskiy static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
9551221a474SAlexey Kardashevskiy                                                    void *data)
9561221a474SAlexey Kardashevskiy {
9571221a474SAlexey Kardashevskiy     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
9581221a474SAlexey Kardashevskiy 
9591221a474SAlexey Kardashevskiy     imrc->translate = typhoon_translate_iommu;
9601221a474SAlexey Kardashevskiy }
9611221a474SAlexey Kardashevskiy 
9621221a474SAlexey Kardashevskiy static const TypeInfo typhoon_iommu_memory_region_info = {
9631221a474SAlexey Kardashevskiy     .parent = TYPE_IOMMU_MEMORY_REGION,
9641221a474SAlexey Kardashevskiy     .name = TYPE_TYPHOON_IOMMU_MEMORY_REGION,
9651221a474SAlexey Kardashevskiy     .class_init = typhoon_iommu_memory_region_class_init,
9661221a474SAlexey Kardashevskiy };
9671221a474SAlexey Kardashevskiy 
96883f7d43aSAndreas Färber static void typhoon_register_types(void)
96980bb2ff7SRichard Henderson {
97039bffca2SAnthony Liguori     type_register_static(&typhoon_pcihost_info);
9711221a474SAlexey Kardashevskiy     type_register_static(&typhoon_iommu_memory_region_info);
97280bb2ff7SRichard Henderson }
97383f7d43aSAndreas Färber 
97483f7d43aSAndreas Färber type_init(typhoon_register_types)
975