xref: /qemu/hw/alpha/typhoon.c (revision 3df9d748067f5a7f01b98ddc63597c98c8244a95)
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"
10da34e65cSMarkus Armbruster #include "qapi/error.h"
1180bb2ff7SRichard Henderson #include "cpu.h"
1283c9f4caSPaolo Bonzini #include "hw/hw.h"
13bd2be150SPeter Maydell #include "hw/devices.h"
149c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
1547b43a1fSPaolo Bonzini #include "alpha_sys.h"
16022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
1780bb2ff7SRichard Henderson 
1880bb2ff7SRichard Henderson 
1994dd91d6SAndreas Färber #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
2094dd91d6SAndreas Färber 
2180bb2ff7SRichard Henderson typedef struct TyphoonCchip {
2280bb2ff7SRichard Henderson     MemoryRegion region;
2380bb2ff7SRichard Henderson     uint64_t misc;
2480bb2ff7SRichard Henderson     uint64_t drir;
2580bb2ff7SRichard Henderson     uint64_t dim[4];
2680bb2ff7SRichard Henderson     uint32_t iic[4];
27ad601177SAndreas Färber     AlphaCPU *cpu[4];
2880bb2ff7SRichard Henderson } TyphoonCchip;
2980bb2ff7SRichard Henderson 
3080bb2ff7SRichard Henderson typedef struct TyphoonWindow {
31b83c4db8SRichard Henderson     uint64_t wba;
32b83c4db8SRichard Henderson     uint64_t wsm;
33b83c4db8SRichard Henderson     uint64_t tba;
3480bb2ff7SRichard Henderson } TyphoonWindow;
3580bb2ff7SRichard Henderson 
3680bb2ff7SRichard Henderson typedef struct TyphoonPchip {
3780bb2ff7SRichard Henderson     MemoryRegion region;
3880bb2ff7SRichard Henderson     MemoryRegion reg_iack;
3980bb2ff7SRichard Henderson     MemoryRegion reg_mem;
4080bb2ff7SRichard Henderson     MemoryRegion reg_io;
4180bb2ff7SRichard Henderson     MemoryRegion reg_conf;
42b83c4db8SRichard Henderson 
43b83c4db8SRichard Henderson     AddressSpace iommu_as;
44*3df9d748SAlexey Kardashevskiy     IOMMUMemoryRegion iommu;
45b83c4db8SRichard Henderson 
4680bb2ff7SRichard Henderson     uint64_t ctl;
4780bb2ff7SRichard Henderson     TyphoonWindow win[4];
4880bb2ff7SRichard Henderson } TyphoonPchip;
4980bb2ff7SRichard Henderson 
5094dd91d6SAndreas Färber #define TYPHOON_PCI_HOST_BRIDGE(obj) \
5194dd91d6SAndreas Färber     OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE)
5294dd91d6SAndreas Färber 
5380bb2ff7SRichard Henderson typedef struct TyphoonState {
5467c332fdSAndreas Färber     PCIHostState parent_obj;
5594dd91d6SAndreas Färber 
5680bb2ff7SRichard Henderson     TyphoonCchip cchip;
5780bb2ff7SRichard Henderson     TyphoonPchip pchip;
5880bb2ff7SRichard Henderson     MemoryRegion dchip_region;
5980bb2ff7SRichard Henderson     MemoryRegion ram_region;
6080bb2ff7SRichard Henderson } TyphoonState;
6180bb2ff7SRichard Henderson 
6280bb2ff7SRichard Henderson /* Called when one of DRIR or DIM changes.  */
63ad601177SAndreas Färber static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
6480bb2ff7SRichard Henderson {
6580bb2ff7SRichard Henderson     /* If there are any non-masked interrupts, tell the cpu.  */
66ad601177SAndreas Färber     if (cpu != NULL) {
67d8ed887bSAndreas Färber         CPUState *cs = CPU(cpu);
6880bb2ff7SRichard Henderson         if (req) {
69c3affe56SAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
7080bb2ff7SRichard Henderson         } else {
71d8ed887bSAndreas Färber             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
7280bb2ff7SRichard Henderson         }
7380bb2ff7SRichard Henderson     }
7480bb2ff7SRichard Henderson }
7580bb2ff7SRichard Henderson 
76a8170e5eSAvi Kivity static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size)
7780bb2ff7SRichard Henderson {
784917cf44SAndreas Färber     CPUState *cpu = current_cpu;
7980bb2ff7SRichard Henderson     TyphoonState *s = opaque;
8080bb2ff7SRichard Henderson     uint64_t ret = 0;
8180bb2ff7SRichard Henderson 
8280bb2ff7SRichard Henderson     switch (addr) {
8380bb2ff7SRichard Henderson     case 0x0000:
8480bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
8580bb2ff7SRichard Henderson         /* All sorts of data here; probably the only thing relevant is
8680bb2ff7SRichard Henderson            PIP<14> Pchip 1 Present = 0.  */
8780bb2ff7SRichard Henderson         break;
8880bb2ff7SRichard Henderson 
8980bb2ff7SRichard Henderson     case 0x0040:
9080bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
9180bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
9280bb2ff7SRichard Henderson         break;
9380bb2ff7SRichard Henderson 
9480bb2ff7SRichard Henderson     case 0x0080:
9580bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
9655e5c285SAndreas Färber         ret = s->cchip.misc | (cpu->cpu_index & 3);
9780bb2ff7SRichard Henderson         break;
9880bb2ff7SRichard Henderson 
9980bb2ff7SRichard Henderson     case 0x00c0:
10080bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
10180bb2ff7SRichard Henderson         break;
10280bb2ff7SRichard Henderson 
10380bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
10480bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
10580bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
10680bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
10780bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
10880bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
10980bb2ff7SRichard Henderson         break;
11080bb2ff7SRichard Henderson 
11180bb2ff7SRichard Henderson     case 0x0200:
11280bb2ff7SRichard Henderson         /* DIM0: Device Interrupt Mask Register, CPU0.  */
11380bb2ff7SRichard Henderson         ret = s->cchip.dim[0];
11480bb2ff7SRichard Henderson         break;
11580bb2ff7SRichard Henderson     case 0x0240:
11680bb2ff7SRichard Henderson         /* DIM1: Device Interrupt Mask Register, CPU1.  */
11780bb2ff7SRichard Henderson         ret = s->cchip.dim[1];
11880bb2ff7SRichard Henderson         break;
11980bb2ff7SRichard Henderson     case 0x0280:
12080bb2ff7SRichard Henderson         /* DIR0: Device Interrupt Request Register, CPU0.  */
12180bb2ff7SRichard Henderson         ret = s->cchip.dim[0] & s->cchip.drir;
12280bb2ff7SRichard Henderson         break;
12380bb2ff7SRichard Henderson     case 0x02c0:
12480bb2ff7SRichard Henderson         /* DIR1: Device Interrupt Request Register, CPU1.  */
12580bb2ff7SRichard Henderson         ret = s->cchip.dim[1] & s->cchip.drir;
12680bb2ff7SRichard Henderson         break;
12780bb2ff7SRichard Henderson     case 0x0300:
12880bb2ff7SRichard Henderson         /* DRIR: Device Raw Interrupt Request Register.  */
12980bb2ff7SRichard Henderson         ret = s->cchip.drir;
13080bb2ff7SRichard Henderson         break;
13180bb2ff7SRichard Henderson 
13280bb2ff7SRichard Henderson     case 0x0340:
13380bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
13480bb2ff7SRichard Henderson         break;
13580bb2ff7SRichard Henderson 
13680bb2ff7SRichard Henderson     case 0x0380:
13780bb2ff7SRichard Henderson         /* IIC0: Interval Ignore Count Register, CPU0.  */
13880bb2ff7SRichard Henderson         ret = s->cchip.iic[0];
13980bb2ff7SRichard Henderson         break;
14080bb2ff7SRichard Henderson     case 0x03c0:
14180bb2ff7SRichard Henderson         /* IIC1: Interval Ignore Count Register, CPU1.  */
14280bb2ff7SRichard Henderson         ret = s->cchip.iic[1];
14380bb2ff7SRichard Henderson         break;
14480bb2ff7SRichard Henderson 
14580bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
14680bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
14780bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
14880bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
14980bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
15080bb2ff7SRichard Henderson         break;
15180bb2ff7SRichard Henderson 
15280bb2ff7SRichard Henderson     case 0x0580:
15380bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
15480bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
15580bb2ff7SRichard Henderson         break;
15680bb2ff7SRichard Henderson     case 0x05c0:
15780bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
15880bb2ff7SRichard Henderson         break;
15980bb2ff7SRichard Henderson 
16080bb2ff7SRichard Henderson     case 0x0600:
16180bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
16280bb2ff7SRichard Henderson         ret = s->cchip.dim[2];
16380bb2ff7SRichard Henderson         break;
16480bb2ff7SRichard Henderson     case 0x0640:
16580bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
16680bb2ff7SRichard Henderson         ret = s->cchip.dim[3];
16780bb2ff7SRichard Henderson         break;
16880bb2ff7SRichard Henderson     case 0x0680:
16980bb2ff7SRichard Henderson         /* DIR2: Device Interrupt Request Register, CPU2.  */
17080bb2ff7SRichard Henderson         ret = s->cchip.dim[2] & s->cchip.drir;
17180bb2ff7SRichard Henderson         break;
17280bb2ff7SRichard Henderson     case 0x06c0:
17380bb2ff7SRichard Henderson         /* DIR3: Device Interrupt Request Register, CPU3.  */
17480bb2ff7SRichard Henderson         ret = s->cchip.dim[3] & s->cchip.drir;
17580bb2ff7SRichard Henderson         break;
17680bb2ff7SRichard Henderson 
17780bb2ff7SRichard Henderson     case 0x0700:
17880bb2ff7SRichard Henderson         /* IIC2: Interval Ignore Count Register, CPU2.  */
17980bb2ff7SRichard Henderson         ret = s->cchip.iic[2];
18080bb2ff7SRichard Henderson         break;
18180bb2ff7SRichard Henderson     case 0x0740:
18280bb2ff7SRichard Henderson         /* IIC3: Interval Ignore Count Register, CPU3.  */
18380bb2ff7SRichard Henderson         ret = s->cchip.iic[3];
18480bb2ff7SRichard Henderson         break;
18580bb2ff7SRichard Henderson 
18680bb2ff7SRichard Henderson     case 0x0780:
18780bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
18880bb2ff7SRichard Henderson         break;
18980bb2ff7SRichard Henderson 
19080bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
19180bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
19280bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
19380bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
19480bb2ff7SRichard Henderson         break;
19580bb2ff7SRichard Henderson 
19680bb2ff7SRichard Henderson     default:
197c658b94fSAndreas Färber         cpu_unassigned_access(cpu, addr, false, false, 0, size);
19880bb2ff7SRichard Henderson         return -1;
19980bb2ff7SRichard Henderson     }
20080bb2ff7SRichard Henderson 
20180bb2ff7SRichard Henderson     return ret;
20280bb2ff7SRichard Henderson }
20380bb2ff7SRichard Henderson 
204a8170e5eSAvi Kivity static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
20580bb2ff7SRichard Henderson {
20680bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
20780bb2ff7SRichard Henderson     return 0;
20880bb2ff7SRichard Henderson }
20980bb2ff7SRichard Henderson 
210a8170e5eSAvi Kivity static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
21180bb2ff7SRichard Henderson {
21280bb2ff7SRichard Henderson     TyphoonState *s = opaque;
21380bb2ff7SRichard Henderson     uint64_t ret = 0;
21480bb2ff7SRichard Henderson 
21580bb2ff7SRichard Henderson     switch (addr) {
21680bb2ff7SRichard Henderson     case 0x0000:
21780bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
218b83c4db8SRichard Henderson         ret = s->pchip.win[0].wba;
21980bb2ff7SRichard Henderson         break;
22080bb2ff7SRichard Henderson     case 0x0040:
22180bb2ff7SRichard Henderson         /* WSBA1 */
222b83c4db8SRichard Henderson         ret = s->pchip.win[1].wba;
22380bb2ff7SRichard Henderson         break;
22480bb2ff7SRichard Henderson     case 0x0080:
22580bb2ff7SRichard Henderson         /* WSBA2 */
226b83c4db8SRichard Henderson         ret = s->pchip.win[2].wba;
22780bb2ff7SRichard Henderson         break;
22880bb2ff7SRichard Henderson     case 0x00c0:
22980bb2ff7SRichard Henderson         /* WSBA3 */
230b83c4db8SRichard Henderson         ret = s->pchip.win[3].wba;
23180bb2ff7SRichard Henderson         break;
23280bb2ff7SRichard Henderson 
23380bb2ff7SRichard Henderson     case 0x0100:
23480bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
235b83c4db8SRichard Henderson         ret = s->pchip.win[0].wsm;
23680bb2ff7SRichard Henderson         break;
23780bb2ff7SRichard Henderson     case 0x0140:
23880bb2ff7SRichard Henderson         /* WSM1 */
239b83c4db8SRichard Henderson         ret = s->pchip.win[1].wsm;
24080bb2ff7SRichard Henderson         break;
24180bb2ff7SRichard Henderson     case 0x0180:
24280bb2ff7SRichard Henderson         /* WSM2 */
243b83c4db8SRichard Henderson         ret = s->pchip.win[2].wsm;
24480bb2ff7SRichard Henderson         break;
24580bb2ff7SRichard Henderson     case 0x01c0:
24680bb2ff7SRichard Henderson         /* WSM3 */
247b83c4db8SRichard Henderson         ret = s->pchip.win[3].wsm;
24880bb2ff7SRichard Henderson         break;
24980bb2ff7SRichard Henderson 
25080bb2ff7SRichard Henderson     case 0x0200:
25180bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
252b83c4db8SRichard Henderson         ret = s->pchip.win[0].tba;
25380bb2ff7SRichard Henderson         break;
25480bb2ff7SRichard Henderson     case 0x0240:
25580bb2ff7SRichard Henderson         /* TBA1 */
256b83c4db8SRichard Henderson         ret = s->pchip.win[1].tba;
25780bb2ff7SRichard Henderson         break;
25880bb2ff7SRichard Henderson     case 0x0280:
25980bb2ff7SRichard Henderson         /* TBA2 */
260b83c4db8SRichard Henderson         ret = s->pchip.win[2].tba;
26180bb2ff7SRichard Henderson         break;
26280bb2ff7SRichard Henderson     case 0x02c0:
26380bb2ff7SRichard Henderson         /* TBA3 */
264b83c4db8SRichard Henderson         ret = s->pchip.win[3].tba;
26580bb2ff7SRichard Henderson         break;
26680bb2ff7SRichard Henderson 
26780bb2ff7SRichard Henderson     case 0x0300:
26880bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
26980bb2ff7SRichard Henderson         ret = s->pchip.ctl;
27080bb2ff7SRichard Henderson         break;
27180bb2ff7SRichard Henderson     case 0x0340:
27280bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
27380bb2ff7SRichard Henderson         break;
27480bb2ff7SRichard Henderson     case 0x03c0:
27580bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
27680bb2ff7SRichard Henderson         break;
27780bb2ff7SRichard Henderson     case 0x0400:
27880bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
27980bb2ff7SRichard Henderson         break;
28080bb2ff7SRichard Henderson     case 0x0440:
28180bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
28280bb2ff7SRichard Henderson         break;
28380bb2ff7SRichard Henderson     case 0x0480:
28480bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
28580bb2ff7SRichard Henderson         break;
28680bb2ff7SRichard Henderson     case 0x04c0:
28780bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
28880bb2ff7SRichard Henderson         break;
28980bb2ff7SRichard Henderson     case 0x0500: /* PMONCTL */
29080bb2ff7SRichard Henderson     case 0x0540: /* PMONCNT */
29180bb2ff7SRichard Henderson     case 0x0800: /* SPRST */
29280bb2ff7SRichard Henderson         break;
29380bb2ff7SRichard Henderson 
29480bb2ff7SRichard Henderson     default:
2954917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, false, false, 0, size);
29680bb2ff7SRichard Henderson         return -1;
29780bb2ff7SRichard Henderson     }
29880bb2ff7SRichard Henderson 
29980bb2ff7SRichard Henderson     return ret;
30080bb2ff7SRichard Henderson }
30180bb2ff7SRichard Henderson 
302a8170e5eSAvi Kivity static void cchip_write(void *opaque, hwaddr addr,
30367842165SRichard Henderson                         uint64_t val, unsigned size)
30480bb2ff7SRichard Henderson {
30580bb2ff7SRichard Henderson     TyphoonState *s = opaque;
30667842165SRichard Henderson     uint64_t oldval, newval;
30780bb2ff7SRichard Henderson 
30880bb2ff7SRichard Henderson     switch (addr) {
30980bb2ff7SRichard Henderson     case 0x0000:
31080bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
31180bb2ff7SRichard Henderson         /* All sorts of data here; nothing relevant RW.  */
31280bb2ff7SRichard Henderson         break;
31380bb2ff7SRichard Henderson 
31480bb2ff7SRichard Henderson     case 0x0040:
31580bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
31680bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
31780bb2ff7SRichard Henderson         break;
31880bb2ff7SRichard Henderson 
31980bb2ff7SRichard Henderson     case 0x0080:
32080bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
32180bb2ff7SRichard Henderson         newval = oldval = s->cchip.misc;
32280bb2ff7SRichard Henderson         newval &= ~(val & 0x10000ff0);     /* W1C fields */
32380bb2ff7SRichard Henderson         if (val & 0x100000) {
32480bb2ff7SRichard Henderson             newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
32580bb2ff7SRichard Henderson         } else {
32680bb2ff7SRichard Henderson             newval |= val & 0x00f00000;    /* ABT field is W1S */
32780bb2ff7SRichard Henderson             if ((newval & 0xf0000) == 0) {
32880bb2ff7SRichard Henderson                 newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
32980bb2ff7SRichard Henderson             }
33080bb2ff7SRichard Henderson         }
33180bb2ff7SRichard Henderson         newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
33280bb2ff7SRichard Henderson 
33380bb2ff7SRichard Henderson         newval &= ~0xf0000000000ull;       /* WO and RW fields */
33480bb2ff7SRichard Henderson         newval |= val & 0xf0000000000ull;
33580bb2ff7SRichard Henderson         s->cchip.misc = newval;
33680bb2ff7SRichard Henderson 
33780bb2ff7SRichard Henderson         /* Pass on changes to IPI and ITI state.  */
33880bb2ff7SRichard Henderson         if ((newval ^ oldval) & 0xff0) {
33980bb2ff7SRichard Henderson             int i;
34080bb2ff7SRichard Henderson             for (i = 0; i < 4; ++i) {
341ad601177SAndreas Färber                 AlphaCPU *cpu = s->cchip.cpu[i];
342ad601177SAndreas Färber                 if (cpu != NULL) {
343d8ed887bSAndreas Färber                     CPUState *cs = CPU(cpu);
34480bb2ff7SRichard Henderson                     /* IPI can be either cleared or set by the write.  */
34580bb2ff7SRichard Henderson                     if (newval & (1 << (i + 8))) {
346c3affe56SAndreas Färber                         cpu_interrupt(cs, CPU_INTERRUPT_SMP);
34780bb2ff7SRichard Henderson                     } else {
348d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
34980bb2ff7SRichard Henderson                     }
35080bb2ff7SRichard Henderson 
35180bb2ff7SRichard Henderson                     /* ITI can only be cleared by the write.  */
35280bb2ff7SRichard Henderson                     if ((newval & (1 << (i + 4))) == 0) {
353d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
35480bb2ff7SRichard Henderson                     }
35580bb2ff7SRichard Henderson                 }
35680bb2ff7SRichard Henderson             }
35780bb2ff7SRichard Henderson         }
35880bb2ff7SRichard Henderson         break;
35980bb2ff7SRichard Henderson 
36080bb2ff7SRichard Henderson     case 0x00c0:
36180bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
36280bb2ff7SRichard Henderson         break;
36380bb2ff7SRichard Henderson 
36480bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
36580bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
36680bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
36780bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
36880bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
36980bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
37080bb2ff7SRichard Henderson         break;
37180bb2ff7SRichard Henderson 
37280bb2ff7SRichard Henderson     case 0x0200: /* DIM0 */
37380bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU0.  */
37480bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
37580bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
37680bb2ff7SRichard Henderson         break;
37780bb2ff7SRichard Henderson     case 0x0240: /* DIM1 */
37880bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU1.  */
379424ad838SRichard Henderson         s->cchip.dim[1] = val;
38080bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
38180bb2ff7SRichard Henderson         break;
38280bb2ff7SRichard Henderson 
38380bb2ff7SRichard Henderson     case 0x0280: /* DIR0 (RO) */
38480bb2ff7SRichard Henderson     case 0x02c0: /* DIR1 (RO) */
38580bb2ff7SRichard Henderson     case 0x0300: /* DRIR (RO) */
38680bb2ff7SRichard Henderson         break;
38780bb2ff7SRichard Henderson 
38880bb2ff7SRichard Henderson     case 0x0340:
38980bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
39080bb2ff7SRichard Henderson         break;
39180bb2ff7SRichard Henderson 
39280bb2ff7SRichard Henderson     case 0x0380: /* IIC0 */
39380bb2ff7SRichard Henderson         s->cchip.iic[0] = val & 0xffffff;
39480bb2ff7SRichard Henderson         break;
39580bb2ff7SRichard Henderson     case 0x03c0: /* IIC1 */
39680bb2ff7SRichard Henderson         s->cchip.iic[1] = val & 0xffffff;
39780bb2ff7SRichard Henderson         break;
39880bb2ff7SRichard Henderson 
39980bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
40080bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
40180bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
40280bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
40380bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
40480bb2ff7SRichard Henderson         break;
40580bb2ff7SRichard Henderson 
40680bb2ff7SRichard Henderson     case 0x0580:
40780bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
40880bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
40980bb2ff7SRichard Henderson         break;
41080bb2ff7SRichard Henderson     case 0x05c0:
41180bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
41280bb2ff7SRichard Henderson         break;
41380bb2ff7SRichard Henderson 
41480bb2ff7SRichard Henderson     case 0x0600:
41580bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
41680bb2ff7SRichard Henderson         s->cchip.dim[2] = val;
41780bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
41880bb2ff7SRichard Henderson         break;
41980bb2ff7SRichard Henderson     case 0x0640:
42080bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
42180bb2ff7SRichard Henderson         s->cchip.dim[3] = val;
42280bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
42380bb2ff7SRichard Henderson         break;
42480bb2ff7SRichard Henderson 
42580bb2ff7SRichard Henderson     case 0x0680: /* DIR2 (RO) */
42680bb2ff7SRichard Henderson     case 0x06c0: /* DIR3 (RO) */
42780bb2ff7SRichard Henderson         break;
42880bb2ff7SRichard Henderson 
42980bb2ff7SRichard Henderson     case 0x0700: /* IIC2 */
43080bb2ff7SRichard Henderson         s->cchip.iic[2] = val & 0xffffff;
43180bb2ff7SRichard Henderson         break;
43280bb2ff7SRichard Henderson     case 0x0740: /* IIC3 */
43380bb2ff7SRichard Henderson         s->cchip.iic[3] = val & 0xffffff;
43480bb2ff7SRichard Henderson         break;
43580bb2ff7SRichard Henderson 
43680bb2ff7SRichard Henderson     case 0x0780:
43780bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
43880bb2ff7SRichard Henderson         break;
43980bb2ff7SRichard Henderson 
44080bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
44180bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
44280bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
44380bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
44480bb2ff7SRichard Henderson         break;
44580bb2ff7SRichard Henderson 
44680bb2ff7SRichard Henderson     default:
4474917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
44880bb2ff7SRichard Henderson         return;
44980bb2ff7SRichard Henderson     }
45080bb2ff7SRichard Henderson }
45180bb2ff7SRichard Henderson 
452a8170e5eSAvi Kivity static void dchip_write(void *opaque, hwaddr addr,
45380bb2ff7SRichard Henderson                         uint64_t val, unsigned size)
45480bb2ff7SRichard Henderson {
45580bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
45680bb2ff7SRichard Henderson }
45780bb2ff7SRichard Henderson 
458a8170e5eSAvi Kivity static void pchip_write(void *opaque, hwaddr addr,
45967842165SRichard Henderson                         uint64_t val, unsigned size)
46080bb2ff7SRichard Henderson {
46180bb2ff7SRichard Henderson     TyphoonState *s = opaque;
46267842165SRichard Henderson     uint64_t oldval;
46380bb2ff7SRichard Henderson 
46480bb2ff7SRichard Henderson     switch (addr) {
46580bb2ff7SRichard Henderson     case 0x0000:
46680bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
467b83c4db8SRichard Henderson         s->pchip.win[0].wba = val & 0xfff00003u;
46880bb2ff7SRichard Henderson         break;
46980bb2ff7SRichard Henderson     case 0x0040:
47080bb2ff7SRichard Henderson         /* WSBA1 */
471b83c4db8SRichard Henderson         s->pchip.win[1].wba = val & 0xfff00003u;
47280bb2ff7SRichard Henderson         break;
47380bb2ff7SRichard Henderson     case 0x0080:
47480bb2ff7SRichard Henderson         /* WSBA2 */
475b83c4db8SRichard Henderson         s->pchip.win[2].wba = val & 0xfff00003u;
47680bb2ff7SRichard Henderson         break;
47780bb2ff7SRichard Henderson     case 0x00c0:
47880bb2ff7SRichard Henderson         /* WSBA3 */
479b83c4db8SRichard Henderson         s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
48080bb2ff7SRichard Henderson         break;
48180bb2ff7SRichard Henderson 
48280bb2ff7SRichard Henderson     case 0x0100:
48380bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
484b83c4db8SRichard Henderson         s->pchip.win[0].wsm = val & 0xfff00000u;
48580bb2ff7SRichard Henderson         break;
48680bb2ff7SRichard Henderson     case 0x0140:
48780bb2ff7SRichard Henderson         /* WSM1 */
488b83c4db8SRichard Henderson         s->pchip.win[1].wsm = val & 0xfff00000u;
48980bb2ff7SRichard Henderson         break;
49080bb2ff7SRichard Henderson     case 0x0180:
49180bb2ff7SRichard Henderson         /* WSM2 */
492b83c4db8SRichard Henderson         s->pchip.win[2].wsm = val & 0xfff00000u;
49380bb2ff7SRichard Henderson         break;
49480bb2ff7SRichard Henderson     case 0x01c0:
49580bb2ff7SRichard Henderson         /* WSM3 */
496b83c4db8SRichard Henderson         s->pchip.win[3].wsm = val & 0xfff00000u;
49780bb2ff7SRichard Henderson         break;
49880bb2ff7SRichard Henderson 
49980bb2ff7SRichard Henderson     case 0x0200:
50080bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
501b83c4db8SRichard Henderson         s->pchip.win[0].tba = val & 0x7fffffc00ull;
50280bb2ff7SRichard Henderson         break;
50380bb2ff7SRichard Henderson     case 0x0240:
50480bb2ff7SRichard Henderson         /* TBA1 */
505b83c4db8SRichard Henderson         s->pchip.win[1].tba = val & 0x7fffffc00ull;
50680bb2ff7SRichard Henderson         break;
50780bb2ff7SRichard Henderson     case 0x0280:
50880bb2ff7SRichard Henderson         /* TBA2 */
509b83c4db8SRichard Henderson         s->pchip.win[2].tba = val & 0x7fffffc00ull;
51080bb2ff7SRichard Henderson         break;
51180bb2ff7SRichard Henderson     case 0x02c0:
51280bb2ff7SRichard Henderson         /* TBA3 */
513b83c4db8SRichard Henderson         s->pchip.win[3].tba = val & 0x7fffffc00ull;
51480bb2ff7SRichard Henderson         break;
51580bb2ff7SRichard Henderson 
51680bb2ff7SRichard Henderson     case 0x0300:
51780bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
51880bb2ff7SRichard Henderson         oldval = s->pchip.ctl;
51980bb2ff7SRichard Henderson         oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
52080bb2ff7SRichard Henderson         oldval |= val & 0x00001cff0fc7ffull;
52180bb2ff7SRichard Henderson         s->pchip.ctl = oldval;
52280bb2ff7SRichard Henderson         break;
52380bb2ff7SRichard Henderson 
52480bb2ff7SRichard Henderson     case 0x0340:
52580bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
52680bb2ff7SRichard Henderson         break;
52780bb2ff7SRichard Henderson     case 0x03c0:
52880bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
52980bb2ff7SRichard Henderson         break;
53080bb2ff7SRichard Henderson     case 0x0400:
53180bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
53280bb2ff7SRichard Henderson         break;
53380bb2ff7SRichard Henderson     case 0x0440:
53480bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
53580bb2ff7SRichard Henderson         break;
53680bb2ff7SRichard Henderson 
53780bb2ff7SRichard Henderson     case 0x0480:
53880bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
53980bb2ff7SRichard Henderson         break;
54080bb2ff7SRichard Henderson 
54180bb2ff7SRichard Henderson     case 0x04c0:
54280bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
54380bb2ff7SRichard Henderson         break;
54480bb2ff7SRichard Henderson 
54580bb2ff7SRichard Henderson     case 0x0500:
54680bb2ff7SRichard Henderson         /* PMONCTL */
54780bb2ff7SRichard Henderson     case 0x0540:
54880bb2ff7SRichard Henderson         /* PMONCNT */
54980bb2ff7SRichard Henderson     case 0x0800:
55080bb2ff7SRichard Henderson         /* SPRST */
55180bb2ff7SRichard Henderson         break;
55280bb2ff7SRichard Henderson 
55380bb2ff7SRichard Henderson     default:
5544917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
55580bb2ff7SRichard Henderson         return;
55680bb2ff7SRichard Henderson     }
55780bb2ff7SRichard Henderson }
55880bb2ff7SRichard Henderson 
55980bb2ff7SRichard Henderson static const MemoryRegionOps cchip_ops = {
56080bb2ff7SRichard Henderson     .read = cchip_read,
56180bb2ff7SRichard Henderson     .write = cchip_write,
56280bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
56380bb2ff7SRichard Henderson     .valid = {
56467842165SRichard Henderson         .min_access_size = 8,
56580bb2ff7SRichard Henderson         .max_access_size = 8,
56680bb2ff7SRichard Henderson     },
56780bb2ff7SRichard Henderson     .impl = {
56867842165SRichard Henderson         .min_access_size = 8,
56967842165SRichard Henderson         .max_access_size = 8,
57080bb2ff7SRichard Henderson     },
57180bb2ff7SRichard Henderson };
57280bb2ff7SRichard Henderson 
57380bb2ff7SRichard Henderson static const MemoryRegionOps dchip_ops = {
57480bb2ff7SRichard Henderson     .read = dchip_read,
57580bb2ff7SRichard Henderson     .write = dchip_write,
57680bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
57780bb2ff7SRichard Henderson     .valid = {
57867842165SRichard Henderson         .min_access_size = 8,
57980bb2ff7SRichard Henderson         .max_access_size = 8,
58080bb2ff7SRichard Henderson     },
58180bb2ff7SRichard Henderson     .impl = {
58267842165SRichard Henderson         .min_access_size = 8,
58380bb2ff7SRichard Henderson         .max_access_size = 8,
58480bb2ff7SRichard Henderson     },
58580bb2ff7SRichard Henderson };
58680bb2ff7SRichard Henderson 
58780bb2ff7SRichard Henderson static const MemoryRegionOps pchip_ops = {
58880bb2ff7SRichard Henderson     .read = pchip_read,
58980bb2ff7SRichard Henderson     .write = pchip_write,
59080bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
59180bb2ff7SRichard Henderson     .valid = {
59267842165SRichard Henderson         .min_access_size = 8,
59380bb2ff7SRichard Henderson         .max_access_size = 8,
59480bb2ff7SRichard Henderson     },
59580bb2ff7SRichard Henderson     .impl = {
59667842165SRichard Henderson         .min_access_size = 8,
59767842165SRichard Henderson         .max_access_size = 8,
59880bb2ff7SRichard Henderson     },
59980bb2ff7SRichard Henderson };
60080bb2ff7SRichard Henderson 
601b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
602b83c4db8SRichard Henderson    using the given translated address and mask.  */
603b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
604b83c4db8SRichard Henderson {
605b83c4db8SRichard Henderson     *ret = (IOMMUTLBEntry) {
606b83c4db8SRichard Henderson         .target_as = &address_space_memory,
607b83c4db8SRichard Henderson         .translated_addr = taddr,
608b83c4db8SRichard Henderson         .addr_mask = mask,
609b83c4db8SRichard Henderson         .perm = IOMMU_RW,
610b83c4db8SRichard Henderson     };
611b83c4db8SRichard Henderson     return true;
612b83c4db8SRichard Henderson }
613b83c4db8SRichard Henderson 
614b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather
615b83c4db8SRichard Henderson    translation, given the address of the PTE.  */
616b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
617b83c4db8SRichard Henderson {
61842874d3aSPeter Maydell     uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
61942874d3aSPeter Maydell                                      MEMTXATTRS_UNSPECIFIED, NULL);
620b83c4db8SRichard Henderson 
621b83c4db8SRichard Henderson     /* Check valid bit.  */
622b83c4db8SRichard Henderson     if ((pte & 1) == 0) {
623b83c4db8SRichard Henderson         return false;
624b83c4db8SRichard Henderson     }
625b83c4db8SRichard Henderson 
626b83c4db8SRichard Henderson     return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
627b83c4db8SRichard Henderson }
628b83c4db8SRichard Henderson 
629b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the
630b83c4db8SRichard Henderson    four single-address-cycle translation windows.  */
631b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr,
632b83c4db8SRichard Henderson                              IOMMUTLBEntry *ret)
633b83c4db8SRichard Henderson {
634b83c4db8SRichard Henderson     uint32_t wba = win->wba;
635b83c4db8SRichard Henderson     uint64_t wsm = win->wsm;
636b83c4db8SRichard Henderson     uint64_t tba = win->tba;
637b83c4db8SRichard Henderson     uint64_t wsm_ext = wsm | 0xfffff;
638b83c4db8SRichard Henderson 
639b83c4db8SRichard Henderson     /* Check for window disabled.  */
640b83c4db8SRichard Henderson     if ((wba & 1) == 0) {
641b83c4db8SRichard Henderson         return false;
642b83c4db8SRichard Henderson     }
643b83c4db8SRichard Henderson 
644b83c4db8SRichard Henderson     /* Check for window hit.  */
645b83c4db8SRichard Henderson     if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
646b83c4db8SRichard Henderson         return false;
647b83c4db8SRichard Henderson     }
648b83c4db8SRichard Henderson 
649b83c4db8SRichard Henderson     if (wba & 2) {
650b83c4db8SRichard Henderson         /* Scatter-gather translation.  */
651b83c4db8SRichard Henderson         hwaddr pte_addr;
652b83c4db8SRichard Henderson 
653b83c4db8SRichard Henderson         /* See table 10-6, Generating PTE address for PCI DMA Address.  */
654b83c4db8SRichard Henderson         pte_addr  = tba & ~(wsm >> 10);
655b83c4db8SRichard Henderson         pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
656b83c4db8SRichard Henderson         return pte_translate(pte_addr, ret);
657b83c4db8SRichard Henderson     } else {
658b83c4db8SRichard Henderson 	/* Direct-mapped translation.  */
659b83c4db8SRichard Henderson 	return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
660b83c4db8SRichard Henderson     }
661b83c4db8SRichard Henderson }
662b83c4db8SRichard Henderson 
663b83c4db8SRichard Henderson /* Handle PCI-to-system address translation.  */
664b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the
665b83c4db8SRichard Henderson    Pchip and generate a machine check interrupt.  */
666*3df9d748SAlexey Kardashevskiy static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
667*3df9d748SAlexey Kardashevskiy                                              hwaddr addr,
668bf55b7afSPeter Xu                                              IOMMUAccessFlags flag)
669b83c4db8SRichard Henderson {
670b83c4db8SRichard Henderson     TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
671b83c4db8SRichard Henderson     IOMMUTLBEntry ret;
672b83c4db8SRichard Henderson     int i;
673b83c4db8SRichard Henderson 
674b83c4db8SRichard Henderson     if (addr <= 0xffffffffu) {
675b83c4db8SRichard Henderson         /* Single-address cycle.  */
676b83c4db8SRichard Henderson 
677b83c4db8SRichard Henderson         /* Check for the Window Hole, inhibiting matching.  */
678b83c4db8SRichard Henderson         if ((pchip->ctl & 0x20)
679b83c4db8SRichard Henderson             && addr >= 0x80000
680b83c4db8SRichard Henderson             && addr <= 0xfffff) {
681b83c4db8SRichard Henderson             goto failure;
682b83c4db8SRichard Henderson         }
683b83c4db8SRichard Henderson 
684b83c4db8SRichard Henderson         /* Check the first three windows.  */
685b83c4db8SRichard Henderson         for (i = 0; i < 3; ++i) {
686b83c4db8SRichard Henderson             if (window_translate(&pchip->win[i], addr, &ret)) {
687b83c4db8SRichard Henderson                 goto success;
688b83c4db8SRichard Henderson             }
689b83c4db8SRichard Henderson         }
690b83c4db8SRichard Henderson 
691b83c4db8SRichard Henderson         /* Check the fourth window for DAC disable.  */
692b83c4db8SRichard Henderson         if ((pchip->win[3].wba & 0x80000000000ull) == 0
693b83c4db8SRichard Henderson 	    && window_translate(&pchip->win[3], addr, &ret)) {
694b83c4db8SRichard Henderson             goto success;
695b83c4db8SRichard Henderson         }
696b83c4db8SRichard Henderson     } else {
697b83c4db8SRichard Henderson         /* Double-address cycle.  */
698b83c4db8SRichard Henderson 
699b83c4db8SRichard Henderson         if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
700b83c4db8SRichard Henderson             /* Check for the DMA monster window.  */
701b83c4db8SRichard Henderson             if (pchip->ctl & 0x40) {
702b83c4db8SRichard Henderson                 /* See 10.1.4.4; in particular <39:35> is ignored.  */
703b83c4db8SRichard Henderson                 make_iommu_tlbe(0, 0x007ffffffffull, &ret);
704b83c4db8SRichard Henderson 		goto success;
705b83c4db8SRichard Henderson             }
706b83c4db8SRichard Henderson         }
707b83c4db8SRichard Henderson 
7089b2caaf4SStefan Weil         if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) {
709b83c4db8SRichard Henderson             /* Check the fourth window for DAC enable and window enable.  */
710b83c4db8SRichard Henderson             if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
711b83c4db8SRichard Henderson                 uint64_t pte_addr;
712b83c4db8SRichard Henderson 
713b83c4db8SRichard Henderson                 pte_addr  = pchip->win[3].tba & 0x7ffc00000ull;
714b83c4db8SRichard Henderson                 pte_addr |= (addr & 0xffffe000u) >> 10;
715b83c4db8SRichard Henderson                 if (pte_translate(pte_addr, &ret)) {
716b83c4db8SRichard Henderson 			goto success;
717b83c4db8SRichard Henderson 		}
718b83c4db8SRichard Henderson             }
719b83c4db8SRichard Henderson         }
720b83c4db8SRichard Henderson     }
721b83c4db8SRichard Henderson 
722b83c4db8SRichard Henderson  failure:
723b83c4db8SRichard Henderson     ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
724b83c4db8SRichard Henderson  success:
725b83c4db8SRichard Henderson     return ret;
726b83c4db8SRichard Henderson }
727b83c4db8SRichard Henderson 
728b83c4db8SRichard Henderson static const MemoryRegionIOMMUOps typhoon_iommu_ops = {
729b83c4db8SRichard Henderson     .translate = typhoon_translate_iommu,
730b83c4db8SRichard Henderson };
731b83c4db8SRichard Henderson 
732b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
733b83c4db8SRichard Henderson {
734b83c4db8SRichard Henderson     TyphoonState *s = opaque;
735b83c4db8SRichard Henderson     return &s->pchip.iommu_as;
736b83c4db8SRichard Henderson }
737b83c4db8SRichard Henderson 
73880bb2ff7SRichard Henderson static void typhoon_set_irq(void *opaque, int irq, int level)
73980bb2ff7SRichard Henderson {
74080bb2ff7SRichard Henderson     TyphoonState *s = opaque;
74180bb2ff7SRichard Henderson     uint64_t drir;
74280bb2ff7SRichard Henderson     int i;
74380bb2ff7SRichard Henderson 
74480bb2ff7SRichard Henderson     /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
74580bb2ff7SRichard Henderson     drir = s->cchip.drir;
74680bb2ff7SRichard Henderson     if (level) {
74780bb2ff7SRichard Henderson         drir |= 1ull << irq;
74880bb2ff7SRichard Henderson     } else {
74980bb2ff7SRichard Henderson         drir &= ~(1ull << irq);
75080bb2ff7SRichard Henderson     }
75180bb2ff7SRichard Henderson     s->cchip.drir = drir;
75280bb2ff7SRichard Henderson 
75380bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
75480bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
75580bb2ff7SRichard Henderson     }
75680bb2ff7SRichard Henderson }
75780bb2ff7SRichard Henderson 
75880bb2ff7SRichard Henderson static void typhoon_set_isa_irq(void *opaque, int irq, int level)
75980bb2ff7SRichard Henderson {
76080bb2ff7SRichard Henderson     typhoon_set_irq(opaque, 55, level);
76180bb2ff7SRichard Henderson }
76280bb2ff7SRichard Henderson 
76380bb2ff7SRichard Henderson static void typhoon_set_timer_irq(void *opaque, int irq, int level)
76480bb2ff7SRichard Henderson {
76580bb2ff7SRichard Henderson     TyphoonState *s = opaque;
76680bb2ff7SRichard Henderson     int i;
76780bb2ff7SRichard Henderson 
76880bb2ff7SRichard Henderson     /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
76980bb2ff7SRichard Henderson        and so we don't have to worry about missing interrupts just
77080bb2ff7SRichard Henderson        because we never actually ACK the interrupt.  Just ignore any
77180bb2ff7SRichard Henderson        case of the interrupt level going low.  */
77280bb2ff7SRichard Henderson     if (level == 0) {
77380bb2ff7SRichard Henderson         return;
77480bb2ff7SRichard Henderson     }
77580bb2ff7SRichard Henderson 
77680bb2ff7SRichard Henderson     /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
77780bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
778ad601177SAndreas Färber         AlphaCPU *cpu = s->cchip.cpu[i];
779ad601177SAndreas Färber         if (cpu != NULL) {
78080bb2ff7SRichard Henderson             uint32_t iic = s->cchip.iic[i];
78180bb2ff7SRichard Henderson 
78280bb2ff7SRichard Henderson             /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
78380bb2ff7SRichard Henderson                Bit 24 is the OverFlow bit, RO, and set when the count
78480bb2ff7SRichard Henderson                decrements past 0.  When is OF cleared?  My guess is that
78580bb2ff7SRichard Henderson                OF is actually cleared when the IIC is written, and that
78680bb2ff7SRichard Henderson                the ICNT field always decrements.  At least, that's an
78780bb2ff7SRichard Henderson                interpretation that makes sense, and "allows the CPU to
78880bb2ff7SRichard Henderson                determine exactly how mant interval timer ticks were
78980bb2ff7SRichard Henderson                skipped".  At least within the next 4M ticks...  */
79080bb2ff7SRichard Henderson 
79180bb2ff7SRichard Henderson             iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
79280bb2ff7SRichard Henderson             s->cchip.iic[i] = iic;
79380bb2ff7SRichard Henderson 
79480bb2ff7SRichard Henderson             if (iic & 0x1000000) {
79580bb2ff7SRichard Henderson                 /* Set the ITI bit for this cpu.  */
79680bb2ff7SRichard Henderson                 s->cchip.misc |= 1 << (i + 4);
79780bb2ff7SRichard Henderson                 /* And signal the interrupt.  */
798c3affe56SAndreas Färber                 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
79980bb2ff7SRichard Henderson             }
80080bb2ff7SRichard Henderson         }
80180bb2ff7SRichard Henderson     }
80280bb2ff7SRichard Henderson }
80380bb2ff7SRichard Henderson 
804c781cf96SRichard Henderson static void typhoon_alarm_timer(void *opaque)
805c781cf96SRichard Henderson {
806c781cf96SRichard Henderson     TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
807c781cf96SRichard Henderson     int cpu = (uintptr_t)opaque & 3;
808c781cf96SRichard Henderson 
809c781cf96SRichard Henderson     /* Set the ITI bit for this cpu.  */
810c781cf96SRichard Henderson     s->cchip.misc |= 1 << (cpu + 4);
811c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
812c781cf96SRichard Henderson }
813c781cf96SRichard Henderson 
81471baa303SHervé Poussineau PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
81571baa303SHervé Poussineau                      qemu_irq *p_rtc_irq,
816ad601177SAndreas Färber                      AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq)
81780bb2ff7SRichard Henderson {
81880bb2ff7SRichard Henderson     const uint64_t MB = 1024 * 1024;
81980bb2ff7SRichard Henderson     const uint64_t GB = 1024 * MB;
82080bb2ff7SRichard Henderson     MemoryRegion *addr_space = get_system_memory();
82180bb2ff7SRichard Henderson     DeviceState *dev;
82280bb2ff7SRichard Henderson     TyphoonState *s;
82394dd91d6SAndreas Färber     PCIHostState *phb;
82480bb2ff7SRichard Henderson     PCIBus *b;
825c781cf96SRichard Henderson     int i;
82680bb2ff7SRichard Henderson 
82794dd91d6SAndreas Färber     dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
82880bb2ff7SRichard Henderson 
82994dd91d6SAndreas Färber     s = TYPHOON_PCI_HOST_BRIDGE(dev);
8308558d942SAndreas Färber     phb = PCI_HOST_BRIDGE(dev);
83180bb2ff7SRichard Henderson 
832b83c4db8SRichard Henderson     s->cchip.misc = 0x800000000ull; /* Revision: Typhoon.  */
833b83c4db8SRichard Henderson     s->pchip.win[3].wba = 2;        /* Window 3 SG always enabled. */
834b83c4db8SRichard Henderson 
83580bb2ff7SRichard Henderson     /* Remember the CPUs so that we can deliver interrupts to them.  */
836c781cf96SRichard Henderson     for (i = 0; i < 4; i++) {
837ad601177SAndreas Färber         AlphaCPU *cpu = cpus[i];
838ad601177SAndreas Färber         s->cchip.cpu[i] = cpu;
839ad601177SAndreas Färber         if (cpu != NULL) {
840bc72ad67SAlex Bligh             cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
841c781cf96SRichard Henderson                                                  typhoon_alarm_timer,
842c781cf96SRichard Henderson                                                  (void *)((uintptr_t)s + i));
843c781cf96SRichard Henderson         }
844c781cf96SRichard Henderson     }
84580bb2ff7SRichard Henderson 
84654292736SShannon Zhao     *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
84780bb2ff7SRichard Henderson 
84880bb2ff7SRichard Henderson     /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
84980bb2ff7SRichard Henderson        but the address space hole reserved at this point is 8TB.  */
85058c24a47SDirk Müller     memory_region_allocate_system_memory(&s->ram_region, OBJECT(s), "ram",
85158c24a47SDirk Müller                                          ram_size);
85280bb2ff7SRichard Henderson     memory_region_add_subregion(addr_space, 0, &s->ram_region);
85380bb2ff7SRichard Henderson 
85480bb2ff7SRichard Henderson     /* TIGbus, 0x801.0000.0000, 1GB.  */
85580bb2ff7SRichard Henderson     /* ??? The TIGbus is used for delivering interrupts, and access to
85680bb2ff7SRichard Henderson        the flash ROM.  I'm not sure that we need to implement it at all.  */
85780bb2ff7SRichard Henderson 
85880bb2ff7SRichard Henderson     /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
85964bde0f3SPaolo Bonzini     memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
86064bde0f3SPaolo Bonzini                           256*MB);
86102d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80180000000ULL,
86202d6516cSStefan Weil                                 &s->pchip.region);
86380bb2ff7SRichard Henderson 
86480bb2ff7SRichard Henderson     /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
86564bde0f3SPaolo Bonzini     memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
86664bde0f3SPaolo Bonzini                           256*MB);
86702d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801a0000000ULL,
86802d6516cSStefan Weil                                 &s->cchip.region);
86980bb2ff7SRichard Henderson 
87080bb2ff7SRichard Henderson     /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
87164bde0f3SPaolo Bonzini     memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
87264bde0f3SPaolo Bonzini                           256*MB);
87302d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801b0000000ULL,
87402d6516cSStefan Weil                                 &s->dchip_region);
87580bb2ff7SRichard Henderson 
87680bb2ff7SRichard Henderson     /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
87764bde0f3SPaolo Bonzini     memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4*GB);
87802d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80000000000ULL,
87902d6516cSStefan Weil                                 &s->pchip.reg_mem);
88080bb2ff7SRichard Henderson 
88180bb2ff7SRichard Henderson     /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
8823661049fSRichard Henderson     memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops,
8833661049fSRichard Henderson                           NULL, "pci0-io", 32*MB);
88402d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fc000000ULL,
88502d6516cSStefan Weil                                 &s->pchip.reg_io);
88680bb2ff7SRichard Henderson 
88794dd91d6SAndreas Färber     b = pci_register_bus(dev, "pci",
88880bb2ff7SRichard Henderson                          typhoon_set_irq, sys_map_irq, s,
889056e6baeSRichard Henderson                          &s->pchip.reg_mem, &s->pchip.reg_io,
890056e6baeSRichard Henderson                          0, 64, TYPE_PCI_BUS);
89194dd91d6SAndreas Färber     phb->bus = b;
89250d3bba9SMarcel Apfelbaum     qdev_init_nofail(dev);
89380bb2ff7SRichard Henderson 
894b83c4db8SRichard Henderson     /* Host memory as seen from the PCI side, via the IOMMU.  */
895b83c4db8SRichard Henderson     memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops,
896b83c4db8SRichard Henderson                              "iommu-typhoon", UINT64_MAX);
897*3df9d748SAlexey Kardashevskiy     address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
898*3df9d748SAlexey Kardashevskiy                        "pchip0-pci");
899b83c4db8SRichard Henderson     pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
900b83c4db8SRichard Henderson 
90180bb2ff7SRichard Henderson     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
902056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
903056e6baeSRichard Henderson                           b, "pci0-iack", 64*MB);
90402d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801f8000000ULL,
90502d6516cSStefan Weil                                 &s->pchip.reg_iack);
90680bb2ff7SRichard Henderson 
90780bb2ff7SRichard Henderson     /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
908056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
909056e6baeSRichard Henderson                           b, "pci0-conf", 16*MB);
91002d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fe000000ULL,
91102d6516cSStefan Weil                                 &s->pchip.reg_conf);
91280bb2ff7SRichard Henderson 
91380bb2ff7SRichard Henderson     /* For the record, these are the mappings for the second PCI bus.
91480bb2ff7SRichard Henderson        We can get away with not implementing them because we indicate
91580bb2ff7SRichard Henderson        via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
91680bb2ff7SRichard Henderson     /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
91780bb2ff7SRichard Henderson     /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
91880bb2ff7SRichard Henderson     /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
91980bb2ff7SRichard Henderson     /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
92080bb2ff7SRichard Henderson     /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
92180bb2ff7SRichard Henderson 
92280bb2ff7SRichard Henderson     /* Init the ISA bus.  */
92380bb2ff7SRichard Henderson     /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
92480bb2ff7SRichard Henderson     {
92554292736SShannon Zhao         qemu_irq *isa_irqs;
92680bb2ff7SRichard Henderson 
927d10e5432SMarkus Armbruster         *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io,
928d10e5432SMarkus Armbruster                                &error_abort);
92954292736SShannon Zhao         isa_irqs = i8259_init(*isa_bus,
93054292736SShannon Zhao                               qemu_allocate_irq(typhoon_set_isa_irq, s, 0));
93171baa303SHervé Poussineau         isa_bus_irqs(*isa_bus, isa_irqs);
93280bb2ff7SRichard Henderson     }
93380bb2ff7SRichard Henderson 
93480bb2ff7SRichard Henderson     return b;
93580bb2ff7SRichard Henderson }
93680bb2ff7SRichard Henderson 
93780bb2ff7SRichard Henderson static int typhoon_pcihost_init(SysBusDevice *dev)
93880bb2ff7SRichard Henderson {
93980bb2ff7SRichard Henderson     return 0;
94080bb2ff7SRichard Henderson }
94180bb2ff7SRichard Henderson 
942999e12bbSAnthony Liguori static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
943999e12bbSAnthony Liguori {
944999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
945999e12bbSAnthony Liguori 
946999e12bbSAnthony Liguori     k->init = typhoon_pcihost_init;
947999e12bbSAnthony Liguori }
948999e12bbSAnthony Liguori 
9494240abffSAndreas Färber static const TypeInfo typhoon_pcihost_info = {
95094dd91d6SAndreas Färber     .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
9518558d942SAndreas Färber     .parent        = TYPE_PCI_HOST_BRIDGE,
95239bffca2SAnthony Liguori     .instance_size = sizeof(TyphoonState),
953999e12bbSAnthony Liguori     .class_init    = typhoon_pcihost_class_init,
95480bb2ff7SRichard Henderson };
95580bb2ff7SRichard Henderson 
95683f7d43aSAndreas Färber static void typhoon_register_types(void)
95780bb2ff7SRichard Henderson {
95839bffca2SAnthony Liguori     type_register_static(&typhoon_pcihost_info);
95980bb2ff7SRichard Henderson }
96083f7d43aSAndreas Färber 
96183f7d43aSAndreas Färber type_init(typhoon_register_types)
962