xref: /qemu/hw/alpha/typhoon.c (revision e2e5e114624ac1a46ce9e23975d5dbf5837f4c86)
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 
9*e2e5e114SPeter Maydell #include "qemu/osdep.h"
1080bb2ff7SRichard Henderson #include "cpu.h"
1183c9f4caSPaolo Bonzini #include "hw/hw.h"
12bd2be150SPeter Maydell #include "hw/devices.h"
139c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
1447b43a1fSPaolo Bonzini #include "alpha_sys.h"
15022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
1680bb2ff7SRichard Henderson 
1780bb2ff7SRichard Henderson 
1894dd91d6SAndreas Färber #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
1994dd91d6SAndreas Färber 
2080bb2ff7SRichard Henderson typedef struct TyphoonCchip {
2180bb2ff7SRichard Henderson     MemoryRegion region;
2280bb2ff7SRichard Henderson     uint64_t misc;
2380bb2ff7SRichard Henderson     uint64_t drir;
2480bb2ff7SRichard Henderson     uint64_t dim[4];
2580bb2ff7SRichard Henderson     uint32_t iic[4];
26ad601177SAndreas Färber     AlphaCPU *cpu[4];
2780bb2ff7SRichard Henderson } TyphoonCchip;
2880bb2ff7SRichard Henderson 
2980bb2ff7SRichard Henderson typedef struct TyphoonWindow {
30b83c4db8SRichard Henderson     uint64_t wba;
31b83c4db8SRichard Henderson     uint64_t wsm;
32b83c4db8SRichard Henderson     uint64_t tba;
3380bb2ff7SRichard Henderson } TyphoonWindow;
3480bb2ff7SRichard Henderson 
3580bb2ff7SRichard Henderson typedef struct TyphoonPchip {
3680bb2ff7SRichard Henderson     MemoryRegion region;
3780bb2ff7SRichard Henderson     MemoryRegion reg_iack;
3880bb2ff7SRichard Henderson     MemoryRegion reg_mem;
3980bb2ff7SRichard Henderson     MemoryRegion reg_io;
4080bb2ff7SRichard Henderson     MemoryRegion reg_conf;
41b83c4db8SRichard Henderson 
42b83c4db8SRichard Henderson     AddressSpace iommu_as;
43b83c4db8SRichard Henderson     MemoryRegion iommu;
44b83c4db8SRichard Henderson 
4580bb2ff7SRichard Henderson     uint64_t ctl;
4680bb2ff7SRichard Henderson     TyphoonWindow win[4];
4780bb2ff7SRichard Henderson } TyphoonPchip;
4880bb2ff7SRichard Henderson 
4994dd91d6SAndreas Färber #define TYPHOON_PCI_HOST_BRIDGE(obj) \
5094dd91d6SAndreas Färber     OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE)
5194dd91d6SAndreas Färber 
5280bb2ff7SRichard Henderson typedef struct TyphoonState {
5367c332fdSAndreas Färber     PCIHostState parent_obj;
5494dd91d6SAndreas Färber 
5580bb2ff7SRichard Henderson     TyphoonCchip cchip;
5680bb2ff7SRichard Henderson     TyphoonPchip pchip;
5780bb2ff7SRichard Henderson     MemoryRegion dchip_region;
5880bb2ff7SRichard Henderson     MemoryRegion ram_region;
5980bb2ff7SRichard Henderson } TyphoonState;
6080bb2ff7SRichard Henderson 
6180bb2ff7SRichard Henderson /* Called when one of DRIR or DIM changes.  */
62ad601177SAndreas Färber static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
6380bb2ff7SRichard Henderson {
6480bb2ff7SRichard Henderson     /* If there are any non-masked interrupts, tell the cpu.  */
65ad601177SAndreas Färber     if (cpu != NULL) {
66d8ed887bSAndreas Färber         CPUState *cs = CPU(cpu);
6780bb2ff7SRichard Henderson         if (req) {
68c3affe56SAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
6980bb2ff7SRichard Henderson         } else {
70d8ed887bSAndreas Färber             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
7180bb2ff7SRichard Henderson         }
7280bb2ff7SRichard Henderson     }
7380bb2ff7SRichard Henderson }
7480bb2ff7SRichard Henderson 
75a8170e5eSAvi Kivity static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size)
7680bb2ff7SRichard Henderson {
774917cf44SAndreas Färber     CPUState *cpu = current_cpu;
7880bb2ff7SRichard Henderson     TyphoonState *s = opaque;
7980bb2ff7SRichard Henderson     uint64_t ret = 0;
8080bb2ff7SRichard Henderson 
8180bb2ff7SRichard Henderson     switch (addr) {
8280bb2ff7SRichard Henderson     case 0x0000:
8380bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
8480bb2ff7SRichard Henderson         /* All sorts of data here; probably the only thing relevant is
8580bb2ff7SRichard Henderson            PIP<14> Pchip 1 Present = 0.  */
8680bb2ff7SRichard Henderson         break;
8780bb2ff7SRichard Henderson 
8880bb2ff7SRichard Henderson     case 0x0040:
8980bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
9080bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
9180bb2ff7SRichard Henderson         break;
9280bb2ff7SRichard Henderson 
9380bb2ff7SRichard Henderson     case 0x0080:
9480bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
9555e5c285SAndreas Färber         ret = s->cchip.misc | (cpu->cpu_index & 3);
9680bb2ff7SRichard Henderson         break;
9780bb2ff7SRichard Henderson 
9880bb2ff7SRichard Henderson     case 0x00c0:
9980bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
10080bb2ff7SRichard Henderson         break;
10180bb2ff7SRichard Henderson 
10280bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
10380bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
10480bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
10580bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
10680bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
10780bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
10880bb2ff7SRichard Henderson         break;
10980bb2ff7SRichard Henderson 
11080bb2ff7SRichard Henderson     case 0x0200:
11180bb2ff7SRichard Henderson         /* DIM0: Device Interrupt Mask Register, CPU0.  */
11280bb2ff7SRichard Henderson         ret = s->cchip.dim[0];
11380bb2ff7SRichard Henderson         break;
11480bb2ff7SRichard Henderson     case 0x0240:
11580bb2ff7SRichard Henderson         /* DIM1: Device Interrupt Mask Register, CPU1.  */
11680bb2ff7SRichard Henderson         ret = s->cchip.dim[1];
11780bb2ff7SRichard Henderson         break;
11880bb2ff7SRichard Henderson     case 0x0280:
11980bb2ff7SRichard Henderson         /* DIR0: Device Interrupt Request Register, CPU0.  */
12080bb2ff7SRichard Henderson         ret = s->cchip.dim[0] & s->cchip.drir;
12180bb2ff7SRichard Henderson         break;
12280bb2ff7SRichard Henderson     case 0x02c0:
12380bb2ff7SRichard Henderson         /* DIR1: Device Interrupt Request Register, CPU1.  */
12480bb2ff7SRichard Henderson         ret = s->cchip.dim[1] & s->cchip.drir;
12580bb2ff7SRichard Henderson         break;
12680bb2ff7SRichard Henderson     case 0x0300:
12780bb2ff7SRichard Henderson         /* DRIR: Device Raw Interrupt Request Register.  */
12880bb2ff7SRichard Henderson         ret = s->cchip.drir;
12980bb2ff7SRichard Henderson         break;
13080bb2ff7SRichard Henderson 
13180bb2ff7SRichard Henderson     case 0x0340:
13280bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
13380bb2ff7SRichard Henderson         break;
13480bb2ff7SRichard Henderson 
13580bb2ff7SRichard Henderson     case 0x0380:
13680bb2ff7SRichard Henderson         /* IIC0: Interval Ignore Count Register, CPU0.  */
13780bb2ff7SRichard Henderson         ret = s->cchip.iic[0];
13880bb2ff7SRichard Henderson         break;
13980bb2ff7SRichard Henderson     case 0x03c0:
14080bb2ff7SRichard Henderson         /* IIC1: Interval Ignore Count Register, CPU1.  */
14180bb2ff7SRichard Henderson         ret = s->cchip.iic[1];
14280bb2ff7SRichard Henderson         break;
14380bb2ff7SRichard Henderson 
14480bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
14580bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
14680bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
14780bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
14880bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
14980bb2ff7SRichard Henderson         break;
15080bb2ff7SRichard Henderson 
15180bb2ff7SRichard Henderson     case 0x0580:
15280bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
15380bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
15480bb2ff7SRichard Henderson         break;
15580bb2ff7SRichard Henderson     case 0x05c0:
15680bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
15780bb2ff7SRichard Henderson         break;
15880bb2ff7SRichard Henderson 
15980bb2ff7SRichard Henderson     case 0x0600:
16080bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
16180bb2ff7SRichard Henderson         ret = s->cchip.dim[2];
16280bb2ff7SRichard Henderson         break;
16380bb2ff7SRichard Henderson     case 0x0640:
16480bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
16580bb2ff7SRichard Henderson         ret = s->cchip.dim[3];
16680bb2ff7SRichard Henderson         break;
16780bb2ff7SRichard Henderson     case 0x0680:
16880bb2ff7SRichard Henderson         /* DIR2: Device Interrupt Request Register, CPU2.  */
16980bb2ff7SRichard Henderson         ret = s->cchip.dim[2] & s->cchip.drir;
17080bb2ff7SRichard Henderson         break;
17180bb2ff7SRichard Henderson     case 0x06c0:
17280bb2ff7SRichard Henderson         /* DIR3: Device Interrupt Request Register, CPU3.  */
17380bb2ff7SRichard Henderson         ret = s->cchip.dim[3] & s->cchip.drir;
17480bb2ff7SRichard Henderson         break;
17580bb2ff7SRichard Henderson 
17680bb2ff7SRichard Henderson     case 0x0700:
17780bb2ff7SRichard Henderson         /* IIC2: Interval Ignore Count Register, CPU2.  */
17880bb2ff7SRichard Henderson         ret = s->cchip.iic[2];
17980bb2ff7SRichard Henderson         break;
18080bb2ff7SRichard Henderson     case 0x0740:
18180bb2ff7SRichard Henderson         /* IIC3: Interval Ignore Count Register, CPU3.  */
18280bb2ff7SRichard Henderson         ret = s->cchip.iic[3];
18380bb2ff7SRichard Henderson         break;
18480bb2ff7SRichard Henderson 
18580bb2ff7SRichard Henderson     case 0x0780:
18680bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
18780bb2ff7SRichard Henderson         break;
18880bb2ff7SRichard Henderson 
18980bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
19080bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
19180bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
19280bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
19380bb2ff7SRichard Henderson         break;
19480bb2ff7SRichard Henderson 
19580bb2ff7SRichard Henderson     default:
196c658b94fSAndreas Färber         cpu_unassigned_access(cpu, addr, false, false, 0, size);
19780bb2ff7SRichard Henderson         return -1;
19880bb2ff7SRichard Henderson     }
19980bb2ff7SRichard Henderson 
20080bb2ff7SRichard Henderson     return ret;
20180bb2ff7SRichard Henderson }
20280bb2ff7SRichard Henderson 
203a8170e5eSAvi Kivity static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
20480bb2ff7SRichard Henderson {
20580bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
20680bb2ff7SRichard Henderson     return 0;
20780bb2ff7SRichard Henderson }
20880bb2ff7SRichard Henderson 
209a8170e5eSAvi Kivity static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
21080bb2ff7SRichard Henderson {
21180bb2ff7SRichard Henderson     TyphoonState *s = opaque;
21280bb2ff7SRichard Henderson     uint64_t ret = 0;
21380bb2ff7SRichard Henderson 
21480bb2ff7SRichard Henderson     switch (addr) {
21580bb2ff7SRichard Henderson     case 0x0000:
21680bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
217b83c4db8SRichard Henderson         ret = s->pchip.win[0].wba;
21880bb2ff7SRichard Henderson         break;
21980bb2ff7SRichard Henderson     case 0x0040:
22080bb2ff7SRichard Henderson         /* WSBA1 */
221b83c4db8SRichard Henderson         ret = s->pchip.win[1].wba;
22280bb2ff7SRichard Henderson         break;
22380bb2ff7SRichard Henderson     case 0x0080:
22480bb2ff7SRichard Henderson         /* WSBA2 */
225b83c4db8SRichard Henderson         ret = s->pchip.win[2].wba;
22680bb2ff7SRichard Henderson         break;
22780bb2ff7SRichard Henderson     case 0x00c0:
22880bb2ff7SRichard Henderson         /* WSBA3 */
229b83c4db8SRichard Henderson         ret = s->pchip.win[3].wba;
23080bb2ff7SRichard Henderson         break;
23180bb2ff7SRichard Henderson 
23280bb2ff7SRichard Henderson     case 0x0100:
23380bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
234b83c4db8SRichard Henderson         ret = s->pchip.win[0].wsm;
23580bb2ff7SRichard Henderson         break;
23680bb2ff7SRichard Henderson     case 0x0140:
23780bb2ff7SRichard Henderson         /* WSM1 */
238b83c4db8SRichard Henderson         ret = s->pchip.win[1].wsm;
23980bb2ff7SRichard Henderson         break;
24080bb2ff7SRichard Henderson     case 0x0180:
24180bb2ff7SRichard Henderson         /* WSM2 */
242b83c4db8SRichard Henderson         ret = s->pchip.win[2].wsm;
24380bb2ff7SRichard Henderson         break;
24480bb2ff7SRichard Henderson     case 0x01c0:
24580bb2ff7SRichard Henderson         /* WSM3 */
246b83c4db8SRichard Henderson         ret = s->pchip.win[3].wsm;
24780bb2ff7SRichard Henderson         break;
24880bb2ff7SRichard Henderson 
24980bb2ff7SRichard Henderson     case 0x0200:
25080bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
251b83c4db8SRichard Henderson         ret = s->pchip.win[0].tba;
25280bb2ff7SRichard Henderson         break;
25380bb2ff7SRichard Henderson     case 0x0240:
25480bb2ff7SRichard Henderson         /* TBA1 */
255b83c4db8SRichard Henderson         ret = s->pchip.win[1].tba;
25680bb2ff7SRichard Henderson         break;
25780bb2ff7SRichard Henderson     case 0x0280:
25880bb2ff7SRichard Henderson         /* TBA2 */
259b83c4db8SRichard Henderson         ret = s->pchip.win[2].tba;
26080bb2ff7SRichard Henderson         break;
26180bb2ff7SRichard Henderson     case 0x02c0:
26280bb2ff7SRichard Henderson         /* TBA3 */
263b83c4db8SRichard Henderson         ret = s->pchip.win[3].tba;
26480bb2ff7SRichard Henderson         break;
26580bb2ff7SRichard Henderson 
26680bb2ff7SRichard Henderson     case 0x0300:
26780bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
26880bb2ff7SRichard Henderson         ret = s->pchip.ctl;
26980bb2ff7SRichard Henderson         break;
27080bb2ff7SRichard Henderson     case 0x0340:
27180bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
27280bb2ff7SRichard Henderson         break;
27380bb2ff7SRichard Henderson     case 0x03c0:
27480bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
27580bb2ff7SRichard Henderson         break;
27680bb2ff7SRichard Henderson     case 0x0400:
27780bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
27880bb2ff7SRichard Henderson         break;
27980bb2ff7SRichard Henderson     case 0x0440:
28080bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
28180bb2ff7SRichard Henderson         break;
28280bb2ff7SRichard Henderson     case 0x0480:
28380bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
28480bb2ff7SRichard Henderson         break;
28580bb2ff7SRichard Henderson     case 0x04c0:
28680bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
28780bb2ff7SRichard Henderson         break;
28880bb2ff7SRichard Henderson     case 0x0500: /* PMONCTL */
28980bb2ff7SRichard Henderson     case 0x0540: /* PMONCNT */
29080bb2ff7SRichard Henderson     case 0x0800: /* SPRST */
29180bb2ff7SRichard Henderson         break;
29280bb2ff7SRichard Henderson 
29380bb2ff7SRichard Henderson     default:
2944917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, false, false, 0, size);
29580bb2ff7SRichard Henderson         return -1;
29680bb2ff7SRichard Henderson     }
29780bb2ff7SRichard Henderson 
29880bb2ff7SRichard Henderson     return ret;
29980bb2ff7SRichard Henderson }
30080bb2ff7SRichard Henderson 
301a8170e5eSAvi Kivity static void cchip_write(void *opaque, hwaddr addr,
30267842165SRichard Henderson                         uint64_t val, unsigned size)
30380bb2ff7SRichard Henderson {
30480bb2ff7SRichard Henderson     TyphoonState *s = opaque;
30567842165SRichard Henderson     uint64_t oldval, newval;
30680bb2ff7SRichard Henderson 
30780bb2ff7SRichard Henderson     switch (addr) {
30880bb2ff7SRichard Henderson     case 0x0000:
30980bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
31080bb2ff7SRichard Henderson         /* All sorts of data here; nothing relevant RW.  */
31180bb2ff7SRichard Henderson         break;
31280bb2ff7SRichard Henderson 
31380bb2ff7SRichard Henderson     case 0x0040:
31480bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
31580bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
31680bb2ff7SRichard Henderson         break;
31780bb2ff7SRichard Henderson 
31880bb2ff7SRichard Henderson     case 0x0080:
31980bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
32080bb2ff7SRichard Henderson         newval = oldval = s->cchip.misc;
32180bb2ff7SRichard Henderson         newval &= ~(val & 0x10000ff0);     /* W1C fields */
32280bb2ff7SRichard Henderson         if (val & 0x100000) {
32380bb2ff7SRichard Henderson             newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
32480bb2ff7SRichard Henderson         } else {
32580bb2ff7SRichard Henderson             newval |= val & 0x00f00000;    /* ABT field is W1S */
32680bb2ff7SRichard Henderson             if ((newval & 0xf0000) == 0) {
32780bb2ff7SRichard Henderson                 newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
32880bb2ff7SRichard Henderson             }
32980bb2ff7SRichard Henderson         }
33080bb2ff7SRichard Henderson         newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
33180bb2ff7SRichard Henderson 
33280bb2ff7SRichard Henderson         newval &= ~0xf0000000000ull;       /* WO and RW fields */
33380bb2ff7SRichard Henderson         newval |= val & 0xf0000000000ull;
33480bb2ff7SRichard Henderson         s->cchip.misc = newval;
33580bb2ff7SRichard Henderson 
33680bb2ff7SRichard Henderson         /* Pass on changes to IPI and ITI state.  */
33780bb2ff7SRichard Henderson         if ((newval ^ oldval) & 0xff0) {
33880bb2ff7SRichard Henderson             int i;
33980bb2ff7SRichard Henderson             for (i = 0; i < 4; ++i) {
340ad601177SAndreas Färber                 AlphaCPU *cpu = s->cchip.cpu[i];
341ad601177SAndreas Färber                 if (cpu != NULL) {
342d8ed887bSAndreas Färber                     CPUState *cs = CPU(cpu);
34380bb2ff7SRichard Henderson                     /* IPI can be either cleared or set by the write.  */
34480bb2ff7SRichard Henderson                     if (newval & (1 << (i + 8))) {
345c3affe56SAndreas Färber                         cpu_interrupt(cs, CPU_INTERRUPT_SMP);
34680bb2ff7SRichard Henderson                     } else {
347d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
34880bb2ff7SRichard Henderson                     }
34980bb2ff7SRichard Henderson 
35080bb2ff7SRichard Henderson                     /* ITI can only be cleared by the write.  */
35180bb2ff7SRichard Henderson                     if ((newval & (1 << (i + 4))) == 0) {
352d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
35380bb2ff7SRichard Henderson                     }
35480bb2ff7SRichard Henderson                 }
35580bb2ff7SRichard Henderson             }
35680bb2ff7SRichard Henderson         }
35780bb2ff7SRichard Henderson         break;
35880bb2ff7SRichard Henderson 
35980bb2ff7SRichard Henderson     case 0x00c0:
36080bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
36180bb2ff7SRichard Henderson         break;
36280bb2ff7SRichard Henderson 
36380bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
36480bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
36580bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
36680bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
36780bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
36880bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
36980bb2ff7SRichard Henderson         break;
37080bb2ff7SRichard Henderson 
37180bb2ff7SRichard Henderson     case 0x0200: /* DIM0 */
37280bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU0.  */
37380bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
37480bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
37580bb2ff7SRichard Henderson         break;
37680bb2ff7SRichard Henderson     case 0x0240: /* DIM1 */
37780bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU1.  */
37880bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
37980bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
38080bb2ff7SRichard Henderson         break;
38180bb2ff7SRichard Henderson 
38280bb2ff7SRichard Henderson     case 0x0280: /* DIR0 (RO) */
38380bb2ff7SRichard Henderson     case 0x02c0: /* DIR1 (RO) */
38480bb2ff7SRichard Henderson     case 0x0300: /* DRIR (RO) */
38580bb2ff7SRichard Henderson         break;
38680bb2ff7SRichard Henderson 
38780bb2ff7SRichard Henderson     case 0x0340:
38880bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
38980bb2ff7SRichard Henderson         break;
39080bb2ff7SRichard Henderson 
39180bb2ff7SRichard Henderson     case 0x0380: /* IIC0 */
39280bb2ff7SRichard Henderson         s->cchip.iic[0] = val & 0xffffff;
39380bb2ff7SRichard Henderson         break;
39480bb2ff7SRichard Henderson     case 0x03c0: /* IIC1 */
39580bb2ff7SRichard Henderson         s->cchip.iic[1] = val & 0xffffff;
39680bb2ff7SRichard Henderson         break;
39780bb2ff7SRichard Henderson 
39880bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
39980bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
40080bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
40180bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
40280bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
40380bb2ff7SRichard Henderson         break;
40480bb2ff7SRichard Henderson 
40580bb2ff7SRichard Henderson     case 0x0580:
40680bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
40780bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
40880bb2ff7SRichard Henderson         break;
40980bb2ff7SRichard Henderson     case 0x05c0:
41080bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
41180bb2ff7SRichard Henderson         break;
41280bb2ff7SRichard Henderson 
41380bb2ff7SRichard Henderson     case 0x0600:
41480bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
41580bb2ff7SRichard Henderson         s->cchip.dim[2] = val;
41680bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
41780bb2ff7SRichard Henderson         break;
41880bb2ff7SRichard Henderson     case 0x0640:
41980bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
42080bb2ff7SRichard Henderson         s->cchip.dim[3] = val;
42180bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
42280bb2ff7SRichard Henderson         break;
42380bb2ff7SRichard Henderson 
42480bb2ff7SRichard Henderson     case 0x0680: /* DIR2 (RO) */
42580bb2ff7SRichard Henderson     case 0x06c0: /* DIR3 (RO) */
42680bb2ff7SRichard Henderson         break;
42780bb2ff7SRichard Henderson 
42880bb2ff7SRichard Henderson     case 0x0700: /* IIC2 */
42980bb2ff7SRichard Henderson         s->cchip.iic[2] = val & 0xffffff;
43080bb2ff7SRichard Henderson         break;
43180bb2ff7SRichard Henderson     case 0x0740: /* IIC3 */
43280bb2ff7SRichard Henderson         s->cchip.iic[3] = val & 0xffffff;
43380bb2ff7SRichard Henderson         break;
43480bb2ff7SRichard Henderson 
43580bb2ff7SRichard Henderson     case 0x0780:
43680bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
43780bb2ff7SRichard Henderson         break;
43880bb2ff7SRichard Henderson 
43980bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
44080bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
44180bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
44280bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
44380bb2ff7SRichard Henderson         break;
44480bb2ff7SRichard Henderson 
44580bb2ff7SRichard Henderson     default:
4464917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
44780bb2ff7SRichard Henderson         return;
44880bb2ff7SRichard Henderson     }
44980bb2ff7SRichard Henderson }
45080bb2ff7SRichard Henderson 
451a8170e5eSAvi Kivity static void dchip_write(void *opaque, hwaddr addr,
45280bb2ff7SRichard Henderson                         uint64_t val, unsigned size)
45380bb2ff7SRichard Henderson {
45480bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
45580bb2ff7SRichard Henderson }
45680bb2ff7SRichard Henderson 
457a8170e5eSAvi Kivity static void pchip_write(void *opaque, hwaddr addr,
45867842165SRichard Henderson                         uint64_t val, unsigned size)
45980bb2ff7SRichard Henderson {
46080bb2ff7SRichard Henderson     TyphoonState *s = opaque;
46167842165SRichard Henderson     uint64_t oldval;
46280bb2ff7SRichard Henderson 
46380bb2ff7SRichard Henderson     switch (addr) {
46480bb2ff7SRichard Henderson     case 0x0000:
46580bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
466b83c4db8SRichard Henderson         s->pchip.win[0].wba = val & 0xfff00003u;
46780bb2ff7SRichard Henderson         break;
46880bb2ff7SRichard Henderson     case 0x0040:
46980bb2ff7SRichard Henderson         /* WSBA1 */
470b83c4db8SRichard Henderson         s->pchip.win[1].wba = val & 0xfff00003u;
47180bb2ff7SRichard Henderson         break;
47280bb2ff7SRichard Henderson     case 0x0080:
47380bb2ff7SRichard Henderson         /* WSBA2 */
474b83c4db8SRichard Henderson         s->pchip.win[2].wba = val & 0xfff00003u;
47580bb2ff7SRichard Henderson         break;
47680bb2ff7SRichard Henderson     case 0x00c0:
47780bb2ff7SRichard Henderson         /* WSBA3 */
478b83c4db8SRichard Henderson         s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
47980bb2ff7SRichard Henderson         break;
48080bb2ff7SRichard Henderson 
48180bb2ff7SRichard Henderson     case 0x0100:
48280bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
483b83c4db8SRichard Henderson         s->pchip.win[0].wsm = val & 0xfff00000u;
48480bb2ff7SRichard Henderson         break;
48580bb2ff7SRichard Henderson     case 0x0140:
48680bb2ff7SRichard Henderson         /* WSM1 */
487b83c4db8SRichard Henderson         s->pchip.win[1].wsm = val & 0xfff00000u;
48880bb2ff7SRichard Henderson         break;
48980bb2ff7SRichard Henderson     case 0x0180:
49080bb2ff7SRichard Henderson         /* WSM2 */
491b83c4db8SRichard Henderson         s->pchip.win[2].wsm = val & 0xfff00000u;
49280bb2ff7SRichard Henderson         break;
49380bb2ff7SRichard Henderson     case 0x01c0:
49480bb2ff7SRichard Henderson         /* WSM3 */
495b83c4db8SRichard Henderson         s->pchip.win[3].wsm = val & 0xfff00000u;
49680bb2ff7SRichard Henderson         break;
49780bb2ff7SRichard Henderson 
49880bb2ff7SRichard Henderson     case 0x0200:
49980bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
500b83c4db8SRichard Henderson         s->pchip.win[0].tba = val & 0x7fffffc00ull;
50180bb2ff7SRichard Henderson         break;
50280bb2ff7SRichard Henderson     case 0x0240:
50380bb2ff7SRichard Henderson         /* TBA1 */
504b83c4db8SRichard Henderson         s->pchip.win[1].tba = val & 0x7fffffc00ull;
50580bb2ff7SRichard Henderson         break;
50680bb2ff7SRichard Henderson     case 0x0280:
50780bb2ff7SRichard Henderson         /* TBA2 */
508b83c4db8SRichard Henderson         s->pchip.win[2].tba = val & 0x7fffffc00ull;
50980bb2ff7SRichard Henderson         break;
51080bb2ff7SRichard Henderson     case 0x02c0:
51180bb2ff7SRichard Henderson         /* TBA3 */
512b83c4db8SRichard Henderson         s->pchip.win[3].tba = val & 0x7fffffc00ull;
51380bb2ff7SRichard Henderson         break;
51480bb2ff7SRichard Henderson 
51580bb2ff7SRichard Henderson     case 0x0300:
51680bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
51780bb2ff7SRichard Henderson         oldval = s->pchip.ctl;
51880bb2ff7SRichard Henderson         oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
51980bb2ff7SRichard Henderson         oldval |= val & 0x00001cff0fc7ffull;
52080bb2ff7SRichard Henderson         s->pchip.ctl = oldval;
52180bb2ff7SRichard Henderson         break;
52280bb2ff7SRichard Henderson 
52380bb2ff7SRichard Henderson     case 0x0340:
52480bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
52580bb2ff7SRichard Henderson         break;
52680bb2ff7SRichard Henderson     case 0x03c0:
52780bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
52880bb2ff7SRichard Henderson         break;
52980bb2ff7SRichard Henderson     case 0x0400:
53080bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
53180bb2ff7SRichard Henderson         break;
53280bb2ff7SRichard Henderson     case 0x0440:
53380bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
53480bb2ff7SRichard Henderson         break;
53580bb2ff7SRichard Henderson 
53680bb2ff7SRichard Henderson     case 0x0480:
53780bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
53880bb2ff7SRichard Henderson         break;
53980bb2ff7SRichard Henderson 
54080bb2ff7SRichard Henderson     case 0x04c0:
54180bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
54280bb2ff7SRichard Henderson         break;
54380bb2ff7SRichard Henderson 
54480bb2ff7SRichard Henderson     case 0x0500:
54580bb2ff7SRichard Henderson         /* PMONCTL */
54680bb2ff7SRichard Henderson     case 0x0540:
54780bb2ff7SRichard Henderson         /* PMONCNT */
54880bb2ff7SRichard Henderson     case 0x0800:
54980bb2ff7SRichard Henderson         /* SPRST */
55080bb2ff7SRichard Henderson         break;
55180bb2ff7SRichard Henderson 
55280bb2ff7SRichard Henderson     default:
5534917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
55480bb2ff7SRichard Henderson         return;
55580bb2ff7SRichard Henderson     }
55680bb2ff7SRichard Henderson }
55780bb2ff7SRichard Henderson 
55880bb2ff7SRichard Henderson static const MemoryRegionOps cchip_ops = {
55980bb2ff7SRichard Henderson     .read = cchip_read,
56080bb2ff7SRichard Henderson     .write = cchip_write,
56180bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
56280bb2ff7SRichard Henderson     .valid = {
56367842165SRichard Henderson         .min_access_size = 8,
56480bb2ff7SRichard Henderson         .max_access_size = 8,
56580bb2ff7SRichard Henderson     },
56680bb2ff7SRichard Henderson     .impl = {
56767842165SRichard Henderson         .min_access_size = 8,
56867842165SRichard Henderson         .max_access_size = 8,
56980bb2ff7SRichard Henderson     },
57080bb2ff7SRichard Henderson };
57180bb2ff7SRichard Henderson 
57280bb2ff7SRichard Henderson static const MemoryRegionOps dchip_ops = {
57380bb2ff7SRichard Henderson     .read = dchip_read,
57480bb2ff7SRichard Henderson     .write = dchip_write,
57580bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
57680bb2ff7SRichard Henderson     .valid = {
57767842165SRichard Henderson         .min_access_size = 8,
57880bb2ff7SRichard Henderson         .max_access_size = 8,
57980bb2ff7SRichard Henderson     },
58080bb2ff7SRichard Henderson     .impl = {
58167842165SRichard Henderson         .min_access_size = 8,
58280bb2ff7SRichard Henderson         .max_access_size = 8,
58380bb2ff7SRichard Henderson     },
58480bb2ff7SRichard Henderson };
58580bb2ff7SRichard Henderson 
58680bb2ff7SRichard Henderson static const MemoryRegionOps pchip_ops = {
58780bb2ff7SRichard Henderson     .read = pchip_read,
58880bb2ff7SRichard Henderson     .write = pchip_write,
58980bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
59080bb2ff7SRichard Henderson     .valid = {
59167842165SRichard Henderson         .min_access_size = 8,
59280bb2ff7SRichard Henderson         .max_access_size = 8,
59380bb2ff7SRichard Henderson     },
59480bb2ff7SRichard Henderson     .impl = {
59567842165SRichard Henderson         .min_access_size = 8,
59667842165SRichard Henderson         .max_access_size = 8,
59780bb2ff7SRichard Henderson     },
59880bb2ff7SRichard Henderson };
59980bb2ff7SRichard Henderson 
600b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
601b83c4db8SRichard Henderson    using the given translated address and mask.  */
602b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
603b83c4db8SRichard Henderson {
604b83c4db8SRichard Henderson     *ret = (IOMMUTLBEntry) {
605b83c4db8SRichard Henderson         .target_as = &address_space_memory,
606b83c4db8SRichard Henderson         .translated_addr = taddr,
607b83c4db8SRichard Henderson         .addr_mask = mask,
608b83c4db8SRichard Henderson         .perm = IOMMU_RW,
609b83c4db8SRichard Henderson     };
610b83c4db8SRichard Henderson     return true;
611b83c4db8SRichard Henderson }
612b83c4db8SRichard Henderson 
613b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather
614b83c4db8SRichard Henderson    translation, given the address of the PTE.  */
615b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
616b83c4db8SRichard Henderson {
61742874d3aSPeter Maydell     uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
61842874d3aSPeter Maydell                                      MEMTXATTRS_UNSPECIFIED, NULL);
619b83c4db8SRichard Henderson 
620b83c4db8SRichard Henderson     /* Check valid bit.  */
621b83c4db8SRichard Henderson     if ((pte & 1) == 0) {
622b83c4db8SRichard Henderson         return false;
623b83c4db8SRichard Henderson     }
624b83c4db8SRichard Henderson 
625b83c4db8SRichard Henderson     return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
626b83c4db8SRichard Henderson }
627b83c4db8SRichard Henderson 
628b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the
629b83c4db8SRichard Henderson    four single-address-cycle translation windows.  */
630b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr,
631b83c4db8SRichard Henderson                              IOMMUTLBEntry *ret)
632b83c4db8SRichard Henderson {
633b83c4db8SRichard Henderson     uint32_t wba = win->wba;
634b83c4db8SRichard Henderson     uint64_t wsm = win->wsm;
635b83c4db8SRichard Henderson     uint64_t tba = win->tba;
636b83c4db8SRichard Henderson     uint64_t wsm_ext = wsm | 0xfffff;
637b83c4db8SRichard Henderson 
638b83c4db8SRichard Henderson     /* Check for window disabled.  */
639b83c4db8SRichard Henderson     if ((wba & 1) == 0) {
640b83c4db8SRichard Henderson         return false;
641b83c4db8SRichard Henderson     }
642b83c4db8SRichard Henderson 
643b83c4db8SRichard Henderson     /* Check for window hit.  */
644b83c4db8SRichard Henderson     if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
645b83c4db8SRichard Henderson         return false;
646b83c4db8SRichard Henderson     }
647b83c4db8SRichard Henderson 
648b83c4db8SRichard Henderson     if (wba & 2) {
649b83c4db8SRichard Henderson         /* Scatter-gather translation.  */
650b83c4db8SRichard Henderson         hwaddr pte_addr;
651b83c4db8SRichard Henderson 
652b83c4db8SRichard Henderson         /* See table 10-6, Generating PTE address for PCI DMA Address.  */
653b83c4db8SRichard Henderson         pte_addr  = tba & ~(wsm >> 10);
654b83c4db8SRichard Henderson         pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
655b83c4db8SRichard Henderson         return pte_translate(pte_addr, ret);
656b83c4db8SRichard Henderson     } else {
657b83c4db8SRichard Henderson 	/* Direct-mapped translation.  */
658b83c4db8SRichard Henderson 	return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
659b83c4db8SRichard Henderson     }
660b83c4db8SRichard Henderson }
661b83c4db8SRichard Henderson 
662b83c4db8SRichard Henderson /* Handle PCI-to-system address translation.  */
663b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the
664b83c4db8SRichard Henderson    Pchip and generate a machine check interrupt.  */
6658d7b8cb9SLe Tan static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr,
6668d7b8cb9SLe Tan                                              bool is_write)
667b83c4db8SRichard Henderson {
668b83c4db8SRichard Henderson     TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
669b83c4db8SRichard Henderson     IOMMUTLBEntry ret;
670b83c4db8SRichard Henderson     int i;
671b83c4db8SRichard Henderson 
672b83c4db8SRichard Henderson     if (addr <= 0xffffffffu) {
673b83c4db8SRichard Henderson         /* Single-address cycle.  */
674b83c4db8SRichard Henderson 
675b83c4db8SRichard Henderson         /* Check for the Window Hole, inhibiting matching.  */
676b83c4db8SRichard Henderson         if ((pchip->ctl & 0x20)
677b83c4db8SRichard Henderson             && addr >= 0x80000
678b83c4db8SRichard Henderson             && addr <= 0xfffff) {
679b83c4db8SRichard Henderson             goto failure;
680b83c4db8SRichard Henderson         }
681b83c4db8SRichard Henderson 
682b83c4db8SRichard Henderson         /* Check the first three windows.  */
683b83c4db8SRichard Henderson         for (i = 0; i < 3; ++i) {
684b83c4db8SRichard Henderson             if (window_translate(&pchip->win[i], addr, &ret)) {
685b83c4db8SRichard Henderson                 goto success;
686b83c4db8SRichard Henderson             }
687b83c4db8SRichard Henderson         }
688b83c4db8SRichard Henderson 
689b83c4db8SRichard Henderson         /* Check the fourth window for DAC disable.  */
690b83c4db8SRichard Henderson         if ((pchip->win[3].wba & 0x80000000000ull) == 0
691b83c4db8SRichard Henderson 	    && window_translate(&pchip->win[3], addr, &ret)) {
692b83c4db8SRichard Henderson             goto success;
693b83c4db8SRichard Henderson         }
694b83c4db8SRichard Henderson     } else {
695b83c4db8SRichard Henderson         /* Double-address cycle.  */
696b83c4db8SRichard Henderson 
697b83c4db8SRichard Henderson         if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
698b83c4db8SRichard Henderson             /* Check for the DMA monster window.  */
699b83c4db8SRichard Henderson             if (pchip->ctl & 0x40) {
700b83c4db8SRichard Henderson                 /* See 10.1.4.4; in particular <39:35> is ignored.  */
701b83c4db8SRichard Henderson                 make_iommu_tlbe(0, 0x007ffffffffull, &ret);
702b83c4db8SRichard Henderson 		goto success;
703b83c4db8SRichard Henderson             }
704b83c4db8SRichard Henderson         }
705b83c4db8SRichard Henderson 
7069b2caaf4SStefan Weil         if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) {
707b83c4db8SRichard Henderson             /* Check the fourth window for DAC enable and window enable.  */
708b83c4db8SRichard Henderson             if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
709b83c4db8SRichard Henderson                 uint64_t pte_addr;
710b83c4db8SRichard Henderson 
711b83c4db8SRichard Henderson                 pte_addr  = pchip->win[3].tba & 0x7ffc00000ull;
712b83c4db8SRichard Henderson                 pte_addr |= (addr & 0xffffe000u) >> 10;
713b83c4db8SRichard Henderson                 if (pte_translate(pte_addr, &ret)) {
714b83c4db8SRichard Henderson 			goto success;
715b83c4db8SRichard Henderson 		}
716b83c4db8SRichard Henderson             }
717b83c4db8SRichard Henderson         }
718b83c4db8SRichard Henderson     }
719b83c4db8SRichard Henderson 
720b83c4db8SRichard Henderson  failure:
721b83c4db8SRichard Henderson     ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
722b83c4db8SRichard Henderson  success:
723b83c4db8SRichard Henderson     return ret;
724b83c4db8SRichard Henderson }
725b83c4db8SRichard Henderson 
726b83c4db8SRichard Henderson static const MemoryRegionIOMMUOps typhoon_iommu_ops = {
727b83c4db8SRichard Henderson     .translate = typhoon_translate_iommu,
728b83c4db8SRichard Henderson };
729b83c4db8SRichard Henderson 
730b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
731b83c4db8SRichard Henderson {
732b83c4db8SRichard Henderson     TyphoonState *s = opaque;
733b83c4db8SRichard Henderson     return &s->pchip.iommu_as;
734b83c4db8SRichard Henderson }
735b83c4db8SRichard Henderson 
73680bb2ff7SRichard Henderson static void typhoon_set_irq(void *opaque, int irq, int level)
73780bb2ff7SRichard Henderson {
73880bb2ff7SRichard Henderson     TyphoonState *s = opaque;
73980bb2ff7SRichard Henderson     uint64_t drir;
74080bb2ff7SRichard Henderson     int i;
74180bb2ff7SRichard Henderson 
74280bb2ff7SRichard Henderson     /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
74380bb2ff7SRichard Henderson     drir = s->cchip.drir;
74480bb2ff7SRichard Henderson     if (level) {
74580bb2ff7SRichard Henderson         drir |= 1ull << irq;
74680bb2ff7SRichard Henderson     } else {
74780bb2ff7SRichard Henderson         drir &= ~(1ull << irq);
74880bb2ff7SRichard Henderson     }
74980bb2ff7SRichard Henderson     s->cchip.drir = drir;
75080bb2ff7SRichard Henderson 
75180bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
75280bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
75380bb2ff7SRichard Henderson     }
75480bb2ff7SRichard Henderson }
75580bb2ff7SRichard Henderson 
75680bb2ff7SRichard Henderson static void typhoon_set_isa_irq(void *opaque, int irq, int level)
75780bb2ff7SRichard Henderson {
75880bb2ff7SRichard Henderson     typhoon_set_irq(opaque, 55, level);
75980bb2ff7SRichard Henderson }
76080bb2ff7SRichard Henderson 
76180bb2ff7SRichard Henderson static void typhoon_set_timer_irq(void *opaque, int irq, int level)
76280bb2ff7SRichard Henderson {
76380bb2ff7SRichard Henderson     TyphoonState *s = opaque;
76480bb2ff7SRichard Henderson     int i;
76580bb2ff7SRichard Henderson 
76680bb2ff7SRichard Henderson     /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
76780bb2ff7SRichard Henderson        and so we don't have to worry about missing interrupts just
76880bb2ff7SRichard Henderson        because we never actually ACK the interrupt.  Just ignore any
76980bb2ff7SRichard Henderson        case of the interrupt level going low.  */
77080bb2ff7SRichard Henderson     if (level == 0) {
77180bb2ff7SRichard Henderson         return;
77280bb2ff7SRichard Henderson     }
77380bb2ff7SRichard Henderson 
77480bb2ff7SRichard Henderson     /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
77580bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
776ad601177SAndreas Färber         AlphaCPU *cpu = s->cchip.cpu[i];
777ad601177SAndreas Färber         if (cpu != NULL) {
77880bb2ff7SRichard Henderson             uint32_t iic = s->cchip.iic[i];
77980bb2ff7SRichard Henderson 
78080bb2ff7SRichard Henderson             /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
78180bb2ff7SRichard Henderson                Bit 24 is the OverFlow bit, RO, and set when the count
78280bb2ff7SRichard Henderson                decrements past 0.  When is OF cleared?  My guess is that
78380bb2ff7SRichard Henderson                OF is actually cleared when the IIC is written, and that
78480bb2ff7SRichard Henderson                the ICNT field always decrements.  At least, that's an
78580bb2ff7SRichard Henderson                interpretation that makes sense, and "allows the CPU to
78680bb2ff7SRichard Henderson                determine exactly how mant interval timer ticks were
78780bb2ff7SRichard Henderson                skipped".  At least within the next 4M ticks...  */
78880bb2ff7SRichard Henderson 
78980bb2ff7SRichard Henderson             iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
79080bb2ff7SRichard Henderson             s->cchip.iic[i] = iic;
79180bb2ff7SRichard Henderson 
79280bb2ff7SRichard Henderson             if (iic & 0x1000000) {
79380bb2ff7SRichard Henderson                 /* Set the ITI bit for this cpu.  */
79480bb2ff7SRichard Henderson                 s->cchip.misc |= 1 << (i + 4);
79580bb2ff7SRichard Henderson                 /* And signal the interrupt.  */
796c3affe56SAndreas Färber                 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
79780bb2ff7SRichard Henderson             }
79880bb2ff7SRichard Henderson         }
79980bb2ff7SRichard Henderson     }
80080bb2ff7SRichard Henderson }
80180bb2ff7SRichard Henderson 
802c781cf96SRichard Henderson static void typhoon_alarm_timer(void *opaque)
803c781cf96SRichard Henderson {
804c781cf96SRichard Henderson     TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
805c781cf96SRichard Henderson     int cpu = (uintptr_t)opaque & 3;
806c781cf96SRichard Henderson 
807c781cf96SRichard Henderson     /* Set the ITI bit for this cpu.  */
808c781cf96SRichard Henderson     s->cchip.misc |= 1 << (cpu + 4);
809c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
810c781cf96SRichard Henderson }
811c781cf96SRichard Henderson 
81271baa303SHervé Poussineau PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
81371baa303SHervé Poussineau                      qemu_irq *p_rtc_irq,
814ad601177SAndreas Färber                      AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq)
81580bb2ff7SRichard Henderson {
81680bb2ff7SRichard Henderson     const uint64_t MB = 1024 * 1024;
81780bb2ff7SRichard Henderson     const uint64_t GB = 1024 * MB;
81880bb2ff7SRichard Henderson     MemoryRegion *addr_space = get_system_memory();
81980bb2ff7SRichard Henderson     DeviceState *dev;
82080bb2ff7SRichard Henderson     TyphoonState *s;
82194dd91d6SAndreas Färber     PCIHostState *phb;
82280bb2ff7SRichard Henderson     PCIBus *b;
823c781cf96SRichard Henderson     int i;
82480bb2ff7SRichard Henderson 
82594dd91d6SAndreas Färber     dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
82680bb2ff7SRichard Henderson     qdev_init_nofail(dev);
82780bb2ff7SRichard Henderson 
82894dd91d6SAndreas Färber     s = TYPHOON_PCI_HOST_BRIDGE(dev);
8298558d942SAndreas Färber     phb = PCI_HOST_BRIDGE(dev);
83080bb2ff7SRichard Henderson 
831b83c4db8SRichard Henderson     s->cchip.misc = 0x800000000ull; /* Revision: Typhoon.  */
832b83c4db8SRichard Henderson     s->pchip.win[3].wba = 2;        /* Window 3 SG always enabled. */
833b83c4db8SRichard Henderson 
83480bb2ff7SRichard Henderson     /* Remember the CPUs so that we can deliver interrupts to them.  */
835c781cf96SRichard Henderson     for (i = 0; i < 4; i++) {
836ad601177SAndreas Färber         AlphaCPU *cpu = cpus[i];
837ad601177SAndreas Färber         s->cchip.cpu[i] = cpu;
838ad601177SAndreas Färber         if (cpu != NULL) {
839bc72ad67SAlex Bligh             cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
840c781cf96SRichard Henderson                                                  typhoon_alarm_timer,
841c781cf96SRichard Henderson                                                  (void *)((uintptr_t)s + i));
842c781cf96SRichard Henderson         }
843c781cf96SRichard Henderson     }
84480bb2ff7SRichard Henderson 
84554292736SShannon Zhao     *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
84680bb2ff7SRichard Henderson 
84780bb2ff7SRichard Henderson     /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
84880bb2ff7SRichard Henderson        but the address space hole reserved at this point is 8TB.  */
84958c24a47SDirk Müller     memory_region_allocate_system_memory(&s->ram_region, OBJECT(s), "ram",
85058c24a47SDirk Müller                                          ram_size);
85180bb2ff7SRichard Henderson     memory_region_add_subregion(addr_space, 0, &s->ram_region);
85280bb2ff7SRichard Henderson 
85380bb2ff7SRichard Henderson     /* TIGbus, 0x801.0000.0000, 1GB.  */
85480bb2ff7SRichard Henderson     /* ??? The TIGbus is used for delivering interrupts, and access to
85580bb2ff7SRichard Henderson        the flash ROM.  I'm not sure that we need to implement it at all.  */
85680bb2ff7SRichard Henderson 
85780bb2ff7SRichard Henderson     /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
85864bde0f3SPaolo Bonzini     memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
85964bde0f3SPaolo Bonzini                           256*MB);
86002d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80180000000ULL,
86102d6516cSStefan Weil                                 &s->pchip.region);
86280bb2ff7SRichard Henderson 
86380bb2ff7SRichard Henderson     /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
86464bde0f3SPaolo Bonzini     memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
86564bde0f3SPaolo Bonzini                           256*MB);
86602d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801a0000000ULL,
86702d6516cSStefan Weil                                 &s->cchip.region);
86880bb2ff7SRichard Henderson 
86980bb2ff7SRichard Henderson     /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
87064bde0f3SPaolo Bonzini     memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
87164bde0f3SPaolo Bonzini                           256*MB);
87202d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801b0000000ULL,
87302d6516cSStefan Weil                                 &s->dchip_region);
87480bb2ff7SRichard Henderson 
87580bb2ff7SRichard Henderson     /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
87664bde0f3SPaolo Bonzini     memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4*GB);
87702d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80000000000ULL,
87802d6516cSStefan Weil                                 &s->pchip.reg_mem);
87980bb2ff7SRichard Henderson 
88080bb2ff7SRichard Henderson     /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
8813661049fSRichard Henderson     memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops,
8823661049fSRichard Henderson                           NULL, "pci0-io", 32*MB);
88302d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fc000000ULL,
88402d6516cSStefan Weil                                 &s->pchip.reg_io);
88580bb2ff7SRichard Henderson 
88694dd91d6SAndreas Färber     b = pci_register_bus(dev, "pci",
88780bb2ff7SRichard Henderson                          typhoon_set_irq, sys_map_irq, s,
888056e6baeSRichard Henderson                          &s->pchip.reg_mem, &s->pchip.reg_io,
889056e6baeSRichard Henderson                          0, 64, TYPE_PCI_BUS);
89094dd91d6SAndreas Färber     phb->bus = b;
89180bb2ff7SRichard Henderson 
892b83c4db8SRichard Henderson     /* Host memory as seen from the PCI side, via the IOMMU.  */
893b83c4db8SRichard Henderson     memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops,
894b83c4db8SRichard Henderson                              "iommu-typhoon", UINT64_MAX);
895b83c4db8SRichard Henderson     address_space_init(&s->pchip.iommu_as, &s->pchip.iommu, "pchip0-pci");
896b83c4db8SRichard Henderson     pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
897b83c4db8SRichard Henderson 
89880bb2ff7SRichard Henderson     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
899056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
900056e6baeSRichard Henderson                           b, "pci0-iack", 64*MB);
90102d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801f8000000ULL,
90202d6516cSStefan Weil                                 &s->pchip.reg_iack);
90380bb2ff7SRichard Henderson 
90480bb2ff7SRichard Henderson     /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
905056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
906056e6baeSRichard Henderson                           b, "pci0-conf", 16*MB);
90702d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fe000000ULL,
90802d6516cSStefan Weil                                 &s->pchip.reg_conf);
90980bb2ff7SRichard Henderson 
91080bb2ff7SRichard Henderson     /* For the record, these are the mappings for the second PCI bus.
91180bb2ff7SRichard Henderson        We can get away with not implementing them because we indicate
91280bb2ff7SRichard Henderson        via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
91380bb2ff7SRichard Henderson     /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
91480bb2ff7SRichard Henderson     /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
91580bb2ff7SRichard Henderson     /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
91680bb2ff7SRichard Henderson     /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
91780bb2ff7SRichard Henderson     /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
91880bb2ff7SRichard Henderson 
91980bb2ff7SRichard Henderson     /* Init the ISA bus.  */
92080bb2ff7SRichard Henderson     /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
92180bb2ff7SRichard Henderson     {
92254292736SShannon Zhao         qemu_irq *isa_irqs;
92380bb2ff7SRichard Henderson 
924d10e5432SMarkus Armbruster         *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io,
925d10e5432SMarkus Armbruster                                &error_abort);
92654292736SShannon Zhao         isa_irqs = i8259_init(*isa_bus,
92754292736SShannon Zhao                               qemu_allocate_irq(typhoon_set_isa_irq, s, 0));
92871baa303SHervé Poussineau         isa_bus_irqs(*isa_bus, isa_irqs);
92980bb2ff7SRichard Henderson     }
93080bb2ff7SRichard Henderson 
93180bb2ff7SRichard Henderson     return b;
93280bb2ff7SRichard Henderson }
93380bb2ff7SRichard Henderson 
93480bb2ff7SRichard Henderson static int typhoon_pcihost_init(SysBusDevice *dev)
93580bb2ff7SRichard Henderson {
93680bb2ff7SRichard Henderson     return 0;
93780bb2ff7SRichard Henderson }
93880bb2ff7SRichard Henderson 
939999e12bbSAnthony Liguori static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
940999e12bbSAnthony Liguori {
941999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
942999e12bbSAnthony Liguori 
943999e12bbSAnthony Liguori     k->init = typhoon_pcihost_init;
944999e12bbSAnthony Liguori }
945999e12bbSAnthony Liguori 
9464240abffSAndreas Färber static const TypeInfo typhoon_pcihost_info = {
94794dd91d6SAndreas Färber     .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
9488558d942SAndreas Färber     .parent        = TYPE_PCI_HOST_BRIDGE,
94939bffca2SAnthony Liguori     .instance_size = sizeof(TyphoonState),
950999e12bbSAnthony Liguori     .class_init    = typhoon_pcihost_class_init,
95180bb2ff7SRichard Henderson };
95280bb2ff7SRichard Henderson 
95383f7d43aSAndreas Färber static void typhoon_register_types(void)
95480bb2ff7SRichard Henderson {
95539bffca2SAnthony Liguori     type_register_static(&typhoon_pcihost_info);
95680bb2ff7SRichard Henderson }
95783f7d43aSAndreas Färber 
95883f7d43aSAndreas Färber type_init(typhoon_register_types)
959