xref: /qemu/hw/alpha/typhoon.c (revision b83c4db89561e78ca5a1808329cbf937c6d75cc3)
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 
980bb2ff7SRichard Henderson #include "cpu.h"
1083c9f4caSPaolo Bonzini #include "hw/hw.h"
11bd2be150SPeter Maydell #include "hw/devices.h"
129c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
1347b43a1fSPaolo Bonzini #include "alpha_sys.h"
14022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
1580bb2ff7SRichard Henderson 
1680bb2ff7SRichard Henderson 
1794dd91d6SAndreas Färber #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
1894dd91d6SAndreas Färber 
1980bb2ff7SRichard Henderson typedef struct TyphoonCchip {
2080bb2ff7SRichard Henderson     MemoryRegion region;
2180bb2ff7SRichard Henderson     uint64_t misc;
2280bb2ff7SRichard Henderson     uint64_t drir;
2380bb2ff7SRichard Henderson     uint64_t dim[4];
2480bb2ff7SRichard Henderson     uint32_t iic[4];
25ad601177SAndreas Färber     AlphaCPU *cpu[4];
2680bb2ff7SRichard Henderson } TyphoonCchip;
2780bb2ff7SRichard Henderson 
2880bb2ff7SRichard Henderson typedef struct TyphoonWindow {
29*b83c4db8SRichard Henderson     uint64_t wba;
30*b83c4db8SRichard Henderson     uint64_t wsm;
31*b83c4db8SRichard Henderson     uint64_t tba;
3280bb2ff7SRichard Henderson } TyphoonWindow;
3380bb2ff7SRichard Henderson 
3480bb2ff7SRichard Henderson typedef struct TyphoonPchip {
3580bb2ff7SRichard Henderson     MemoryRegion region;
3680bb2ff7SRichard Henderson     MemoryRegion reg_iack;
3780bb2ff7SRichard Henderson     MemoryRegion reg_mem;
3880bb2ff7SRichard Henderson     MemoryRegion reg_io;
3980bb2ff7SRichard Henderson     MemoryRegion reg_conf;
40*b83c4db8SRichard Henderson 
41*b83c4db8SRichard Henderson     AddressSpace iommu_as;
42*b83c4db8SRichard Henderson     MemoryRegion iommu;
43*b83c4db8SRichard Henderson 
4480bb2ff7SRichard Henderson     uint64_t ctl;
4580bb2ff7SRichard Henderson     TyphoonWindow win[4];
4680bb2ff7SRichard Henderson } TyphoonPchip;
4780bb2ff7SRichard Henderson 
4894dd91d6SAndreas Färber #define TYPHOON_PCI_HOST_BRIDGE(obj) \
4994dd91d6SAndreas Färber     OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE)
5094dd91d6SAndreas Färber 
5180bb2ff7SRichard Henderson typedef struct TyphoonState {
5267c332fdSAndreas Färber     PCIHostState parent_obj;
5394dd91d6SAndreas Färber 
5480bb2ff7SRichard Henderson     TyphoonCchip cchip;
5580bb2ff7SRichard Henderson     TyphoonPchip pchip;
5680bb2ff7SRichard Henderson     MemoryRegion dchip_region;
5780bb2ff7SRichard Henderson     MemoryRegion ram_region;
5880bb2ff7SRichard Henderson } TyphoonState;
5980bb2ff7SRichard Henderson 
6080bb2ff7SRichard Henderson /* Called when one of DRIR or DIM changes.  */
61ad601177SAndreas Färber static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
6280bb2ff7SRichard Henderson {
6380bb2ff7SRichard Henderson     /* If there are any non-masked interrupts, tell the cpu.  */
64ad601177SAndreas Färber     if (cpu != NULL) {
65d8ed887bSAndreas Färber         CPUState *cs = CPU(cpu);
6680bb2ff7SRichard Henderson         if (req) {
67c3affe56SAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
6880bb2ff7SRichard Henderson         } else {
69d8ed887bSAndreas Färber             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
7080bb2ff7SRichard Henderson         }
7180bb2ff7SRichard Henderson     }
7280bb2ff7SRichard Henderson }
7380bb2ff7SRichard Henderson 
74a8170e5eSAvi Kivity static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size)
7580bb2ff7SRichard Henderson {
764917cf44SAndreas Färber     CPUState *cpu = current_cpu;
7780bb2ff7SRichard Henderson     TyphoonState *s = opaque;
7880bb2ff7SRichard Henderson     uint64_t ret = 0;
7980bb2ff7SRichard Henderson 
8080bb2ff7SRichard Henderson     switch (addr) {
8180bb2ff7SRichard Henderson     case 0x0000:
8280bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
8380bb2ff7SRichard Henderson         /* All sorts of data here; probably the only thing relevant is
8480bb2ff7SRichard Henderson            PIP<14> Pchip 1 Present = 0.  */
8580bb2ff7SRichard Henderson         break;
8680bb2ff7SRichard Henderson 
8780bb2ff7SRichard Henderson     case 0x0040:
8880bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
8980bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
9080bb2ff7SRichard Henderson         break;
9180bb2ff7SRichard Henderson 
9280bb2ff7SRichard Henderson     case 0x0080:
9380bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
9455e5c285SAndreas Färber         ret = s->cchip.misc | (cpu->cpu_index & 3);
9580bb2ff7SRichard Henderson         break;
9680bb2ff7SRichard Henderson 
9780bb2ff7SRichard Henderson     case 0x00c0:
9880bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
9980bb2ff7SRichard Henderson         break;
10080bb2ff7SRichard Henderson 
10180bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
10280bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
10380bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
10480bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
10580bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
10680bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
10780bb2ff7SRichard Henderson         break;
10880bb2ff7SRichard Henderson 
10980bb2ff7SRichard Henderson     case 0x0200:
11080bb2ff7SRichard Henderson         /* DIM0: Device Interrupt Mask Register, CPU0.  */
11180bb2ff7SRichard Henderson         ret = s->cchip.dim[0];
11280bb2ff7SRichard Henderson         break;
11380bb2ff7SRichard Henderson     case 0x0240:
11480bb2ff7SRichard Henderson         /* DIM1: Device Interrupt Mask Register, CPU1.  */
11580bb2ff7SRichard Henderson         ret = s->cchip.dim[1];
11680bb2ff7SRichard Henderson         break;
11780bb2ff7SRichard Henderson     case 0x0280:
11880bb2ff7SRichard Henderson         /* DIR0: Device Interrupt Request Register, CPU0.  */
11980bb2ff7SRichard Henderson         ret = s->cchip.dim[0] & s->cchip.drir;
12080bb2ff7SRichard Henderson         break;
12180bb2ff7SRichard Henderson     case 0x02c0:
12280bb2ff7SRichard Henderson         /* DIR1: Device Interrupt Request Register, CPU1.  */
12380bb2ff7SRichard Henderson         ret = s->cchip.dim[1] & s->cchip.drir;
12480bb2ff7SRichard Henderson         break;
12580bb2ff7SRichard Henderson     case 0x0300:
12680bb2ff7SRichard Henderson         /* DRIR: Device Raw Interrupt Request Register.  */
12780bb2ff7SRichard Henderson         ret = s->cchip.drir;
12880bb2ff7SRichard Henderson         break;
12980bb2ff7SRichard Henderson 
13080bb2ff7SRichard Henderson     case 0x0340:
13180bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
13280bb2ff7SRichard Henderson         break;
13380bb2ff7SRichard Henderson 
13480bb2ff7SRichard Henderson     case 0x0380:
13580bb2ff7SRichard Henderson         /* IIC0: Interval Ignore Count Register, CPU0.  */
13680bb2ff7SRichard Henderson         ret = s->cchip.iic[0];
13780bb2ff7SRichard Henderson         break;
13880bb2ff7SRichard Henderson     case 0x03c0:
13980bb2ff7SRichard Henderson         /* IIC1: Interval Ignore Count Register, CPU1.  */
14080bb2ff7SRichard Henderson         ret = s->cchip.iic[1];
14180bb2ff7SRichard Henderson         break;
14280bb2ff7SRichard Henderson 
14380bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
14480bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
14580bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
14680bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
14780bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
14880bb2ff7SRichard Henderson         break;
14980bb2ff7SRichard Henderson 
15080bb2ff7SRichard Henderson     case 0x0580:
15180bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
15280bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
15380bb2ff7SRichard Henderson         break;
15480bb2ff7SRichard Henderson     case 0x05c0:
15580bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
15680bb2ff7SRichard Henderson         break;
15780bb2ff7SRichard Henderson 
15880bb2ff7SRichard Henderson     case 0x0600:
15980bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
16080bb2ff7SRichard Henderson         ret = s->cchip.dim[2];
16180bb2ff7SRichard Henderson         break;
16280bb2ff7SRichard Henderson     case 0x0640:
16380bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
16480bb2ff7SRichard Henderson         ret = s->cchip.dim[3];
16580bb2ff7SRichard Henderson         break;
16680bb2ff7SRichard Henderson     case 0x0680:
16780bb2ff7SRichard Henderson         /* DIR2: Device Interrupt Request Register, CPU2.  */
16880bb2ff7SRichard Henderson         ret = s->cchip.dim[2] & s->cchip.drir;
16980bb2ff7SRichard Henderson         break;
17080bb2ff7SRichard Henderson     case 0x06c0:
17180bb2ff7SRichard Henderson         /* DIR3: Device Interrupt Request Register, CPU3.  */
17280bb2ff7SRichard Henderson         ret = s->cchip.dim[3] & s->cchip.drir;
17380bb2ff7SRichard Henderson         break;
17480bb2ff7SRichard Henderson 
17580bb2ff7SRichard Henderson     case 0x0700:
17680bb2ff7SRichard Henderson         /* IIC2: Interval Ignore Count Register, CPU2.  */
17780bb2ff7SRichard Henderson         ret = s->cchip.iic[2];
17880bb2ff7SRichard Henderson         break;
17980bb2ff7SRichard Henderson     case 0x0740:
18080bb2ff7SRichard Henderson         /* IIC3: Interval Ignore Count Register, CPU3.  */
18180bb2ff7SRichard Henderson         ret = s->cchip.iic[3];
18280bb2ff7SRichard Henderson         break;
18380bb2ff7SRichard Henderson 
18480bb2ff7SRichard Henderson     case 0x0780:
18580bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
18680bb2ff7SRichard Henderson         break;
18780bb2ff7SRichard Henderson 
18880bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
18980bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
19080bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
19180bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
19280bb2ff7SRichard Henderson         break;
19380bb2ff7SRichard Henderson 
19480bb2ff7SRichard Henderson     default:
195c658b94fSAndreas Färber         cpu_unassigned_access(cpu, addr, false, false, 0, size);
19680bb2ff7SRichard Henderson         return -1;
19780bb2ff7SRichard Henderson     }
19880bb2ff7SRichard Henderson 
19980bb2ff7SRichard Henderson     return ret;
20080bb2ff7SRichard Henderson }
20180bb2ff7SRichard Henderson 
202a8170e5eSAvi Kivity static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
20380bb2ff7SRichard Henderson {
20480bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
20580bb2ff7SRichard Henderson     return 0;
20680bb2ff7SRichard Henderson }
20780bb2ff7SRichard Henderson 
208a8170e5eSAvi Kivity static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
20980bb2ff7SRichard Henderson {
21080bb2ff7SRichard Henderson     TyphoonState *s = opaque;
21180bb2ff7SRichard Henderson     uint64_t ret = 0;
21280bb2ff7SRichard Henderson 
21380bb2ff7SRichard Henderson     switch (addr) {
21480bb2ff7SRichard Henderson     case 0x0000:
21580bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
216*b83c4db8SRichard Henderson         ret = s->pchip.win[0].wba;
21780bb2ff7SRichard Henderson         break;
21880bb2ff7SRichard Henderson     case 0x0040:
21980bb2ff7SRichard Henderson         /* WSBA1 */
220*b83c4db8SRichard Henderson         ret = s->pchip.win[1].wba;
22180bb2ff7SRichard Henderson         break;
22280bb2ff7SRichard Henderson     case 0x0080:
22380bb2ff7SRichard Henderson         /* WSBA2 */
224*b83c4db8SRichard Henderson         ret = s->pchip.win[2].wba;
22580bb2ff7SRichard Henderson         break;
22680bb2ff7SRichard Henderson     case 0x00c0:
22780bb2ff7SRichard Henderson         /* WSBA3 */
228*b83c4db8SRichard Henderson         ret = s->pchip.win[3].wba;
22980bb2ff7SRichard Henderson         break;
23080bb2ff7SRichard Henderson 
23180bb2ff7SRichard Henderson     case 0x0100:
23280bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
233*b83c4db8SRichard Henderson         ret = s->pchip.win[0].wsm;
23480bb2ff7SRichard Henderson         break;
23580bb2ff7SRichard Henderson     case 0x0140:
23680bb2ff7SRichard Henderson         /* WSM1 */
237*b83c4db8SRichard Henderson         ret = s->pchip.win[1].wsm;
23880bb2ff7SRichard Henderson         break;
23980bb2ff7SRichard Henderson     case 0x0180:
24080bb2ff7SRichard Henderson         /* WSM2 */
241*b83c4db8SRichard Henderson         ret = s->pchip.win[2].wsm;
24280bb2ff7SRichard Henderson         break;
24380bb2ff7SRichard Henderson     case 0x01c0:
24480bb2ff7SRichard Henderson         /* WSM3 */
245*b83c4db8SRichard Henderson         ret = s->pchip.win[3].wsm;
24680bb2ff7SRichard Henderson         break;
24780bb2ff7SRichard Henderson 
24880bb2ff7SRichard Henderson     case 0x0200:
24980bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
250*b83c4db8SRichard Henderson         ret = s->pchip.win[0].tba;
25180bb2ff7SRichard Henderson         break;
25280bb2ff7SRichard Henderson     case 0x0240:
25380bb2ff7SRichard Henderson         /* TBA1 */
254*b83c4db8SRichard Henderson         ret = s->pchip.win[1].tba;
25580bb2ff7SRichard Henderson         break;
25680bb2ff7SRichard Henderson     case 0x0280:
25780bb2ff7SRichard Henderson         /* TBA2 */
258*b83c4db8SRichard Henderson         ret = s->pchip.win[2].tba;
25980bb2ff7SRichard Henderson         break;
26080bb2ff7SRichard Henderson     case 0x02c0:
26180bb2ff7SRichard Henderson         /* TBA3 */
262*b83c4db8SRichard Henderson         ret = s->pchip.win[3].tba;
26380bb2ff7SRichard Henderson         break;
26480bb2ff7SRichard Henderson 
26580bb2ff7SRichard Henderson     case 0x0300:
26680bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
26780bb2ff7SRichard Henderson         ret = s->pchip.ctl;
26880bb2ff7SRichard Henderson         break;
26980bb2ff7SRichard Henderson     case 0x0340:
27080bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
27180bb2ff7SRichard Henderson         break;
27280bb2ff7SRichard Henderson     case 0x03c0:
27380bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
27480bb2ff7SRichard Henderson         break;
27580bb2ff7SRichard Henderson     case 0x0400:
27680bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
27780bb2ff7SRichard Henderson         break;
27880bb2ff7SRichard Henderson     case 0x0440:
27980bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
28080bb2ff7SRichard Henderson         break;
28180bb2ff7SRichard Henderson     case 0x0480:
28280bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
28380bb2ff7SRichard Henderson         break;
28480bb2ff7SRichard Henderson     case 0x04c0:
28580bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
28680bb2ff7SRichard Henderson         break;
28780bb2ff7SRichard Henderson     case 0x0500: /* PMONCTL */
28880bb2ff7SRichard Henderson     case 0x0540: /* PMONCNT */
28980bb2ff7SRichard Henderson     case 0x0800: /* SPRST */
29080bb2ff7SRichard Henderson         break;
29180bb2ff7SRichard Henderson 
29280bb2ff7SRichard Henderson     default:
2934917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, false, false, 0, size);
29480bb2ff7SRichard Henderson         return -1;
29580bb2ff7SRichard Henderson     }
29680bb2ff7SRichard Henderson 
29780bb2ff7SRichard Henderson     return ret;
29880bb2ff7SRichard Henderson }
29980bb2ff7SRichard Henderson 
300a8170e5eSAvi Kivity static void cchip_write(void *opaque, hwaddr addr,
30167842165SRichard Henderson                         uint64_t val, unsigned size)
30280bb2ff7SRichard Henderson {
30380bb2ff7SRichard Henderson     TyphoonState *s = opaque;
30467842165SRichard Henderson     uint64_t oldval, newval;
30580bb2ff7SRichard Henderson 
30680bb2ff7SRichard Henderson     switch (addr) {
30780bb2ff7SRichard Henderson     case 0x0000:
30880bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
30980bb2ff7SRichard Henderson         /* All sorts of data here; nothing relevant RW.  */
31080bb2ff7SRichard Henderson         break;
31180bb2ff7SRichard Henderson 
31280bb2ff7SRichard Henderson     case 0x0040:
31380bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
31480bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
31580bb2ff7SRichard Henderson         break;
31680bb2ff7SRichard Henderson 
31780bb2ff7SRichard Henderson     case 0x0080:
31880bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
31980bb2ff7SRichard Henderson         newval = oldval = s->cchip.misc;
32080bb2ff7SRichard Henderson         newval &= ~(val & 0x10000ff0);     /* W1C fields */
32180bb2ff7SRichard Henderson         if (val & 0x100000) {
32280bb2ff7SRichard Henderson             newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
32380bb2ff7SRichard Henderson         } else {
32480bb2ff7SRichard Henderson             newval |= val & 0x00f00000;    /* ABT field is W1S */
32580bb2ff7SRichard Henderson             if ((newval & 0xf0000) == 0) {
32680bb2ff7SRichard Henderson                 newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
32780bb2ff7SRichard Henderson             }
32880bb2ff7SRichard Henderson         }
32980bb2ff7SRichard Henderson         newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
33080bb2ff7SRichard Henderson 
33180bb2ff7SRichard Henderson         newval &= ~0xf0000000000ull;       /* WO and RW fields */
33280bb2ff7SRichard Henderson         newval |= val & 0xf0000000000ull;
33380bb2ff7SRichard Henderson         s->cchip.misc = newval;
33480bb2ff7SRichard Henderson 
33580bb2ff7SRichard Henderson         /* Pass on changes to IPI and ITI state.  */
33680bb2ff7SRichard Henderson         if ((newval ^ oldval) & 0xff0) {
33780bb2ff7SRichard Henderson             int i;
33880bb2ff7SRichard Henderson             for (i = 0; i < 4; ++i) {
339ad601177SAndreas Färber                 AlphaCPU *cpu = s->cchip.cpu[i];
340ad601177SAndreas Färber                 if (cpu != NULL) {
341d8ed887bSAndreas Färber                     CPUState *cs = CPU(cpu);
34280bb2ff7SRichard Henderson                     /* IPI can be either cleared or set by the write.  */
34380bb2ff7SRichard Henderson                     if (newval & (1 << (i + 8))) {
344c3affe56SAndreas Färber                         cpu_interrupt(cs, CPU_INTERRUPT_SMP);
34580bb2ff7SRichard Henderson                     } else {
346d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
34780bb2ff7SRichard Henderson                     }
34880bb2ff7SRichard Henderson 
34980bb2ff7SRichard Henderson                     /* ITI can only be cleared by the write.  */
35080bb2ff7SRichard Henderson                     if ((newval & (1 << (i + 4))) == 0) {
351d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
35280bb2ff7SRichard Henderson                     }
35380bb2ff7SRichard Henderson                 }
35480bb2ff7SRichard Henderson             }
35580bb2ff7SRichard Henderson         }
35680bb2ff7SRichard Henderson         break;
35780bb2ff7SRichard Henderson 
35880bb2ff7SRichard Henderson     case 0x00c0:
35980bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
36080bb2ff7SRichard Henderson         break;
36180bb2ff7SRichard Henderson 
36280bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
36380bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
36480bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
36580bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
36680bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
36780bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
36880bb2ff7SRichard Henderson         break;
36980bb2ff7SRichard Henderson 
37080bb2ff7SRichard Henderson     case 0x0200: /* DIM0 */
37180bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU0.  */
37280bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
37380bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
37480bb2ff7SRichard Henderson         break;
37580bb2ff7SRichard Henderson     case 0x0240: /* DIM1 */
37680bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU1.  */
37780bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
37880bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
37980bb2ff7SRichard Henderson         break;
38080bb2ff7SRichard Henderson 
38180bb2ff7SRichard Henderson     case 0x0280: /* DIR0 (RO) */
38280bb2ff7SRichard Henderson     case 0x02c0: /* DIR1 (RO) */
38380bb2ff7SRichard Henderson     case 0x0300: /* DRIR (RO) */
38480bb2ff7SRichard Henderson         break;
38580bb2ff7SRichard Henderson 
38680bb2ff7SRichard Henderson     case 0x0340:
38780bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
38880bb2ff7SRichard Henderson         break;
38980bb2ff7SRichard Henderson 
39080bb2ff7SRichard Henderson     case 0x0380: /* IIC0 */
39180bb2ff7SRichard Henderson         s->cchip.iic[0] = val & 0xffffff;
39280bb2ff7SRichard Henderson         break;
39380bb2ff7SRichard Henderson     case 0x03c0: /* IIC1 */
39480bb2ff7SRichard Henderson         s->cchip.iic[1] = val & 0xffffff;
39580bb2ff7SRichard Henderson         break;
39680bb2ff7SRichard Henderson 
39780bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
39880bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
39980bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
40080bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
40180bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
40280bb2ff7SRichard Henderson         break;
40380bb2ff7SRichard Henderson 
40480bb2ff7SRichard Henderson     case 0x0580:
40580bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
40680bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
40780bb2ff7SRichard Henderson         break;
40880bb2ff7SRichard Henderson     case 0x05c0:
40980bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
41080bb2ff7SRichard Henderson         break;
41180bb2ff7SRichard Henderson 
41280bb2ff7SRichard Henderson     case 0x0600:
41380bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
41480bb2ff7SRichard Henderson         s->cchip.dim[2] = val;
41580bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
41680bb2ff7SRichard Henderson         break;
41780bb2ff7SRichard Henderson     case 0x0640:
41880bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
41980bb2ff7SRichard Henderson         s->cchip.dim[3] = val;
42080bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
42180bb2ff7SRichard Henderson         break;
42280bb2ff7SRichard Henderson 
42380bb2ff7SRichard Henderson     case 0x0680: /* DIR2 (RO) */
42480bb2ff7SRichard Henderson     case 0x06c0: /* DIR3 (RO) */
42580bb2ff7SRichard Henderson         break;
42680bb2ff7SRichard Henderson 
42780bb2ff7SRichard Henderson     case 0x0700: /* IIC2 */
42880bb2ff7SRichard Henderson         s->cchip.iic[2] = val & 0xffffff;
42980bb2ff7SRichard Henderson         break;
43080bb2ff7SRichard Henderson     case 0x0740: /* IIC3 */
43180bb2ff7SRichard Henderson         s->cchip.iic[3] = val & 0xffffff;
43280bb2ff7SRichard Henderson         break;
43380bb2ff7SRichard Henderson 
43480bb2ff7SRichard Henderson     case 0x0780:
43580bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
43680bb2ff7SRichard Henderson         break;
43780bb2ff7SRichard Henderson 
43880bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
43980bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
44080bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
44180bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
44280bb2ff7SRichard Henderson         break;
44380bb2ff7SRichard Henderson 
44480bb2ff7SRichard Henderson     default:
4454917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
44680bb2ff7SRichard Henderson         return;
44780bb2ff7SRichard Henderson     }
44880bb2ff7SRichard Henderson }
44980bb2ff7SRichard Henderson 
450a8170e5eSAvi Kivity static void dchip_write(void *opaque, hwaddr addr,
45180bb2ff7SRichard Henderson                         uint64_t val, unsigned size)
45280bb2ff7SRichard Henderson {
45380bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
45480bb2ff7SRichard Henderson }
45580bb2ff7SRichard Henderson 
456a8170e5eSAvi Kivity static void pchip_write(void *opaque, hwaddr addr,
45767842165SRichard Henderson                         uint64_t val, unsigned size)
45880bb2ff7SRichard Henderson {
45980bb2ff7SRichard Henderson     TyphoonState *s = opaque;
46067842165SRichard Henderson     uint64_t oldval;
46180bb2ff7SRichard Henderson 
46280bb2ff7SRichard Henderson     switch (addr) {
46380bb2ff7SRichard Henderson     case 0x0000:
46480bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
465*b83c4db8SRichard Henderson         s->pchip.win[0].wba = val & 0xfff00003u;
46680bb2ff7SRichard Henderson         break;
46780bb2ff7SRichard Henderson     case 0x0040:
46880bb2ff7SRichard Henderson         /* WSBA1 */
469*b83c4db8SRichard Henderson         s->pchip.win[1].wba = val & 0xfff00003u;
47080bb2ff7SRichard Henderson         break;
47180bb2ff7SRichard Henderson     case 0x0080:
47280bb2ff7SRichard Henderson         /* WSBA2 */
473*b83c4db8SRichard Henderson         s->pchip.win[2].wba = val & 0xfff00003u;
47480bb2ff7SRichard Henderson         break;
47580bb2ff7SRichard Henderson     case 0x00c0:
47680bb2ff7SRichard Henderson         /* WSBA3 */
477*b83c4db8SRichard Henderson         s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
47880bb2ff7SRichard Henderson         break;
47980bb2ff7SRichard Henderson 
48080bb2ff7SRichard Henderson     case 0x0100:
48180bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
482*b83c4db8SRichard Henderson         s->pchip.win[0].wsm = val & 0xfff00000u;
48380bb2ff7SRichard Henderson         break;
48480bb2ff7SRichard Henderson     case 0x0140:
48580bb2ff7SRichard Henderson         /* WSM1 */
486*b83c4db8SRichard Henderson         s->pchip.win[1].wsm = val & 0xfff00000u;
48780bb2ff7SRichard Henderson         break;
48880bb2ff7SRichard Henderson     case 0x0180:
48980bb2ff7SRichard Henderson         /* WSM2 */
490*b83c4db8SRichard Henderson         s->pchip.win[2].wsm = val & 0xfff00000u;
49180bb2ff7SRichard Henderson         break;
49280bb2ff7SRichard Henderson     case 0x01c0:
49380bb2ff7SRichard Henderson         /* WSM3 */
494*b83c4db8SRichard Henderson         s->pchip.win[3].wsm = val & 0xfff00000u;
49580bb2ff7SRichard Henderson         break;
49680bb2ff7SRichard Henderson 
49780bb2ff7SRichard Henderson     case 0x0200:
49880bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
499*b83c4db8SRichard Henderson         s->pchip.win[0].tba = val & 0x7fffffc00ull;
50080bb2ff7SRichard Henderson         break;
50180bb2ff7SRichard Henderson     case 0x0240:
50280bb2ff7SRichard Henderson         /* TBA1 */
503*b83c4db8SRichard Henderson         s->pchip.win[1].tba = val & 0x7fffffc00ull;
50480bb2ff7SRichard Henderson         break;
50580bb2ff7SRichard Henderson     case 0x0280:
50680bb2ff7SRichard Henderson         /* TBA2 */
507*b83c4db8SRichard Henderson         s->pchip.win[2].tba = val & 0x7fffffc00ull;
50880bb2ff7SRichard Henderson         break;
50980bb2ff7SRichard Henderson     case 0x02c0:
51080bb2ff7SRichard Henderson         /* TBA3 */
511*b83c4db8SRichard Henderson         s->pchip.win[3].tba = val & 0x7fffffc00ull;
51280bb2ff7SRichard Henderson         break;
51380bb2ff7SRichard Henderson 
51480bb2ff7SRichard Henderson     case 0x0300:
51580bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
51680bb2ff7SRichard Henderson         oldval = s->pchip.ctl;
51780bb2ff7SRichard Henderson         oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
51880bb2ff7SRichard Henderson         oldval |= val & 0x00001cff0fc7ffull;
51980bb2ff7SRichard Henderson         s->pchip.ctl = oldval;
52080bb2ff7SRichard Henderson         break;
52180bb2ff7SRichard Henderson 
52280bb2ff7SRichard Henderson     case 0x0340:
52380bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
52480bb2ff7SRichard Henderson         break;
52580bb2ff7SRichard Henderson     case 0x03c0:
52680bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
52780bb2ff7SRichard Henderson         break;
52880bb2ff7SRichard Henderson     case 0x0400:
52980bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
53080bb2ff7SRichard Henderson         break;
53180bb2ff7SRichard Henderson     case 0x0440:
53280bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
53380bb2ff7SRichard Henderson         break;
53480bb2ff7SRichard Henderson 
53580bb2ff7SRichard Henderson     case 0x0480:
53680bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
53780bb2ff7SRichard Henderson         break;
53880bb2ff7SRichard Henderson 
53980bb2ff7SRichard Henderson     case 0x04c0:
54080bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
54180bb2ff7SRichard Henderson         break;
54280bb2ff7SRichard Henderson 
54380bb2ff7SRichard Henderson     case 0x0500:
54480bb2ff7SRichard Henderson         /* PMONCTL */
54580bb2ff7SRichard Henderson     case 0x0540:
54680bb2ff7SRichard Henderson         /* PMONCNT */
54780bb2ff7SRichard Henderson     case 0x0800:
54880bb2ff7SRichard Henderson         /* SPRST */
54980bb2ff7SRichard Henderson         break;
55080bb2ff7SRichard Henderson 
55180bb2ff7SRichard Henderson     default:
5524917cf44SAndreas Färber         cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
55380bb2ff7SRichard Henderson         return;
55480bb2ff7SRichard Henderson     }
55580bb2ff7SRichard Henderson }
55680bb2ff7SRichard Henderson 
55780bb2ff7SRichard Henderson static const MemoryRegionOps cchip_ops = {
55880bb2ff7SRichard Henderson     .read = cchip_read,
55980bb2ff7SRichard Henderson     .write = cchip_write,
56080bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
56180bb2ff7SRichard Henderson     .valid = {
56267842165SRichard Henderson         .min_access_size = 8,
56380bb2ff7SRichard Henderson         .max_access_size = 8,
56480bb2ff7SRichard Henderson     },
56580bb2ff7SRichard Henderson     .impl = {
56667842165SRichard Henderson         .min_access_size = 8,
56767842165SRichard Henderson         .max_access_size = 8,
56880bb2ff7SRichard Henderson     },
56980bb2ff7SRichard Henderson };
57080bb2ff7SRichard Henderson 
57180bb2ff7SRichard Henderson static const MemoryRegionOps dchip_ops = {
57280bb2ff7SRichard Henderson     .read = dchip_read,
57380bb2ff7SRichard Henderson     .write = dchip_write,
57480bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
57580bb2ff7SRichard Henderson     .valid = {
57667842165SRichard Henderson         .min_access_size = 8,
57780bb2ff7SRichard Henderson         .max_access_size = 8,
57880bb2ff7SRichard Henderson     },
57980bb2ff7SRichard Henderson     .impl = {
58067842165SRichard Henderson         .min_access_size = 8,
58180bb2ff7SRichard Henderson         .max_access_size = 8,
58280bb2ff7SRichard Henderson     },
58380bb2ff7SRichard Henderson };
58480bb2ff7SRichard Henderson 
58580bb2ff7SRichard Henderson static const MemoryRegionOps pchip_ops = {
58680bb2ff7SRichard Henderson     .read = pchip_read,
58780bb2ff7SRichard Henderson     .write = pchip_write,
58880bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
58980bb2ff7SRichard Henderson     .valid = {
59067842165SRichard Henderson         .min_access_size = 8,
59180bb2ff7SRichard Henderson         .max_access_size = 8,
59280bb2ff7SRichard Henderson     },
59380bb2ff7SRichard Henderson     .impl = {
59467842165SRichard Henderson         .min_access_size = 8,
59567842165SRichard Henderson         .max_access_size = 8,
59680bb2ff7SRichard Henderson     },
59780bb2ff7SRichard Henderson };
59880bb2ff7SRichard Henderson 
599*b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
600*b83c4db8SRichard Henderson    using the given translated address and mask.  */
601*b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
602*b83c4db8SRichard Henderson {
603*b83c4db8SRichard Henderson     *ret = (IOMMUTLBEntry) {
604*b83c4db8SRichard Henderson         .target_as = &address_space_memory,
605*b83c4db8SRichard Henderson         .translated_addr = taddr,
606*b83c4db8SRichard Henderson         .addr_mask = mask,
607*b83c4db8SRichard Henderson         .perm = IOMMU_RW,
608*b83c4db8SRichard Henderson     };
609*b83c4db8SRichard Henderson     return true;
610*b83c4db8SRichard Henderson }
611*b83c4db8SRichard Henderson 
612*b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather
613*b83c4db8SRichard Henderson    translation, given the address of the PTE.  */
614*b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
615*b83c4db8SRichard Henderson {
616*b83c4db8SRichard Henderson     uint64_t pte = ldq_phys(pte_addr);
617*b83c4db8SRichard Henderson 
618*b83c4db8SRichard Henderson     /* Check valid bit.  */
619*b83c4db8SRichard Henderson     if ((pte & 1) == 0) {
620*b83c4db8SRichard Henderson         return false;
621*b83c4db8SRichard Henderson     }
622*b83c4db8SRichard Henderson 
623*b83c4db8SRichard Henderson     return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
624*b83c4db8SRichard Henderson }
625*b83c4db8SRichard Henderson 
626*b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the
627*b83c4db8SRichard Henderson    four single-address-cycle translation windows.  */
628*b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr,
629*b83c4db8SRichard Henderson                              IOMMUTLBEntry *ret)
630*b83c4db8SRichard Henderson {
631*b83c4db8SRichard Henderson     uint32_t wba = win->wba;
632*b83c4db8SRichard Henderson     uint64_t wsm = win->wsm;
633*b83c4db8SRichard Henderson     uint64_t tba = win->tba;
634*b83c4db8SRichard Henderson     uint64_t wsm_ext = wsm | 0xfffff;
635*b83c4db8SRichard Henderson 
636*b83c4db8SRichard Henderson     /* Check for window disabled.  */
637*b83c4db8SRichard Henderson     if ((wba & 1) == 0) {
638*b83c4db8SRichard Henderson         return false;
639*b83c4db8SRichard Henderson     }
640*b83c4db8SRichard Henderson 
641*b83c4db8SRichard Henderson     /* Check for window hit.  */
642*b83c4db8SRichard Henderson     if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
643*b83c4db8SRichard Henderson         return false;
644*b83c4db8SRichard Henderson     }
645*b83c4db8SRichard Henderson 
646*b83c4db8SRichard Henderson     if (wba & 2) {
647*b83c4db8SRichard Henderson         /* Scatter-gather translation.  */
648*b83c4db8SRichard Henderson         hwaddr pte_addr;
649*b83c4db8SRichard Henderson 
650*b83c4db8SRichard Henderson         /* See table 10-6, Generating PTE address for PCI DMA Address.  */
651*b83c4db8SRichard Henderson         pte_addr  = tba & ~(wsm >> 10);
652*b83c4db8SRichard Henderson         pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
653*b83c4db8SRichard Henderson         return pte_translate(pte_addr, ret);
654*b83c4db8SRichard Henderson     } else {
655*b83c4db8SRichard Henderson 	/* Direct-mapped translation.  */
656*b83c4db8SRichard Henderson 	return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
657*b83c4db8SRichard Henderson     }
658*b83c4db8SRichard Henderson }
659*b83c4db8SRichard Henderson 
660*b83c4db8SRichard Henderson /* Handle PCI-to-system address translation.  */
661*b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the
662*b83c4db8SRichard Henderson    Pchip and generate a machine check interrupt.  */
663*b83c4db8SRichard Henderson static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr)
664*b83c4db8SRichard Henderson {
665*b83c4db8SRichard Henderson     TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
666*b83c4db8SRichard Henderson     IOMMUTLBEntry ret;
667*b83c4db8SRichard Henderson     int i;
668*b83c4db8SRichard Henderson 
669*b83c4db8SRichard Henderson     if (addr <= 0xffffffffu) {
670*b83c4db8SRichard Henderson         /* Single-address cycle.  */
671*b83c4db8SRichard Henderson 
672*b83c4db8SRichard Henderson         /* Check for the Window Hole, inhibiting matching.  */
673*b83c4db8SRichard Henderson         if ((pchip->ctl & 0x20)
674*b83c4db8SRichard Henderson             && addr >= 0x80000
675*b83c4db8SRichard Henderson             && addr <= 0xfffff) {
676*b83c4db8SRichard Henderson             goto failure;
677*b83c4db8SRichard Henderson         }
678*b83c4db8SRichard Henderson 
679*b83c4db8SRichard Henderson         /* Check the first three windows.  */
680*b83c4db8SRichard Henderson         for (i = 0; i < 3; ++i) {
681*b83c4db8SRichard Henderson             if (window_translate(&pchip->win[i], addr, &ret)) {
682*b83c4db8SRichard Henderson                 goto success;
683*b83c4db8SRichard Henderson             }
684*b83c4db8SRichard Henderson         }
685*b83c4db8SRichard Henderson 
686*b83c4db8SRichard Henderson         /* Check the fourth window for DAC disable.  */
687*b83c4db8SRichard Henderson         if ((pchip->win[3].wba & 0x80000000000ull) == 0
688*b83c4db8SRichard Henderson 	    && window_translate(&pchip->win[3], addr, &ret)) {
689*b83c4db8SRichard Henderson             goto success;
690*b83c4db8SRichard Henderson         }
691*b83c4db8SRichard Henderson     } else {
692*b83c4db8SRichard Henderson         /* Double-address cycle.  */
693*b83c4db8SRichard Henderson 
694*b83c4db8SRichard Henderson         if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
695*b83c4db8SRichard Henderson             /* Check for the DMA monster window.  */
696*b83c4db8SRichard Henderson             if (pchip->ctl & 0x40) {
697*b83c4db8SRichard Henderson                 /* See 10.1.4.4; in particular <39:35> is ignored.  */
698*b83c4db8SRichard Henderson                 make_iommu_tlbe(0, 0x007ffffffffull, &ret);
699*b83c4db8SRichard Henderson 		goto success;
700*b83c4db8SRichard Henderson             }
701*b83c4db8SRichard Henderson         }
702*b83c4db8SRichard Henderson 
703*b83c4db8SRichard Henderson         if (addr >= 0x80000000000 && addr <= 0xfffffffffff) {
704*b83c4db8SRichard Henderson             /* Check the fourth window for DAC enable and window enable.  */
705*b83c4db8SRichard Henderson             if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
706*b83c4db8SRichard Henderson                 uint64_t pte_addr;
707*b83c4db8SRichard Henderson 
708*b83c4db8SRichard Henderson                 pte_addr  = pchip->win[3].tba & 0x7ffc00000ull;
709*b83c4db8SRichard Henderson                 pte_addr |= (addr & 0xffffe000u) >> 10;
710*b83c4db8SRichard Henderson                 if (pte_translate(pte_addr, &ret)) {
711*b83c4db8SRichard Henderson 			goto success;
712*b83c4db8SRichard Henderson 		}
713*b83c4db8SRichard Henderson             }
714*b83c4db8SRichard Henderson         }
715*b83c4db8SRichard Henderson     }
716*b83c4db8SRichard Henderson 
717*b83c4db8SRichard Henderson  failure:
718*b83c4db8SRichard Henderson     ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
719*b83c4db8SRichard Henderson  success:
720*b83c4db8SRichard Henderson     return ret;
721*b83c4db8SRichard Henderson }
722*b83c4db8SRichard Henderson 
723*b83c4db8SRichard Henderson static const MemoryRegionIOMMUOps typhoon_iommu_ops = {
724*b83c4db8SRichard Henderson     .translate = typhoon_translate_iommu,
725*b83c4db8SRichard Henderson };
726*b83c4db8SRichard Henderson 
727*b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
728*b83c4db8SRichard Henderson {
729*b83c4db8SRichard Henderson     TyphoonState *s = opaque;
730*b83c4db8SRichard Henderson     return &s->pchip.iommu_as;
731*b83c4db8SRichard Henderson }
732*b83c4db8SRichard Henderson 
73380bb2ff7SRichard Henderson static void typhoon_set_irq(void *opaque, int irq, int level)
73480bb2ff7SRichard Henderson {
73580bb2ff7SRichard Henderson     TyphoonState *s = opaque;
73680bb2ff7SRichard Henderson     uint64_t drir;
73780bb2ff7SRichard Henderson     int i;
73880bb2ff7SRichard Henderson 
73980bb2ff7SRichard Henderson     /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
74080bb2ff7SRichard Henderson     drir = s->cchip.drir;
74180bb2ff7SRichard Henderson     if (level) {
74280bb2ff7SRichard Henderson         drir |= 1ull << irq;
74380bb2ff7SRichard Henderson     } else {
74480bb2ff7SRichard Henderson         drir &= ~(1ull << irq);
74580bb2ff7SRichard Henderson     }
74680bb2ff7SRichard Henderson     s->cchip.drir = drir;
74780bb2ff7SRichard Henderson 
74880bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
74980bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
75080bb2ff7SRichard Henderson     }
75180bb2ff7SRichard Henderson }
75280bb2ff7SRichard Henderson 
75380bb2ff7SRichard Henderson static void typhoon_set_isa_irq(void *opaque, int irq, int level)
75480bb2ff7SRichard Henderson {
75580bb2ff7SRichard Henderson     typhoon_set_irq(opaque, 55, level);
75680bb2ff7SRichard Henderson }
75780bb2ff7SRichard Henderson 
75880bb2ff7SRichard Henderson static void typhoon_set_timer_irq(void *opaque, int irq, int level)
75980bb2ff7SRichard Henderson {
76080bb2ff7SRichard Henderson     TyphoonState *s = opaque;
76180bb2ff7SRichard Henderson     int i;
76280bb2ff7SRichard Henderson 
76380bb2ff7SRichard Henderson     /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
76480bb2ff7SRichard Henderson        and so we don't have to worry about missing interrupts just
76580bb2ff7SRichard Henderson        because we never actually ACK the interrupt.  Just ignore any
76680bb2ff7SRichard Henderson        case of the interrupt level going low.  */
76780bb2ff7SRichard Henderson     if (level == 0) {
76880bb2ff7SRichard Henderson         return;
76980bb2ff7SRichard Henderson     }
77080bb2ff7SRichard Henderson 
77180bb2ff7SRichard Henderson     /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
77280bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
773ad601177SAndreas Färber         AlphaCPU *cpu = s->cchip.cpu[i];
774ad601177SAndreas Färber         if (cpu != NULL) {
77580bb2ff7SRichard Henderson             uint32_t iic = s->cchip.iic[i];
77680bb2ff7SRichard Henderson 
77780bb2ff7SRichard Henderson             /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
77880bb2ff7SRichard Henderson                Bit 24 is the OverFlow bit, RO, and set when the count
77980bb2ff7SRichard Henderson                decrements past 0.  When is OF cleared?  My guess is that
78080bb2ff7SRichard Henderson                OF is actually cleared when the IIC is written, and that
78180bb2ff7SRichard Henderson                the ICNT field always decrements.  At least, that's an
78280bb2ff7SRichard Henderson                interpretation that makes sense, and "allows the CPU to
78380bb2ff7SRichard Henderson                determine exactly how mant interval timer ticks were
78480bb2ff7SRichard Henderson                skipped".  At least within the next 4M ticks...  */
78580bb2ff7SRichard Henderson 
78680bb2ff7SRichard Henderson             iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
78780bb2ff7SRichard Henderson             s->cchip.iic[i] = iic;
78880bb2ff7SRichard Henderson 
78980bb2ff7SRichard Henderson             if (iic & 0x1000000) {
79080bb2ff7SRichard Henderson                 /* Set the ITI bit for this cpu.  */
79180bb2ff7SRichard Henderson                 s->cchip.misc |= 1 << (i + 4);
79280bb2ff7SRichard Henderson                 /* And signal the interrupt.  */
793c3affe56SAndreas Färber                 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
79480bb2ff7SRichard Henderson             }
79580bb2ff7SRichard Henderson         }
79680bb2ff7SRichard Henderson     }
79780bb2ff7SRichard Henderson }
79880bb2ff7SRichard Henderson 
799c781cf96SRichard Henderson static void typhoon_alarm_timer(void *opaque)
800c781cf96SRichard Henderson {
801c781cf96SRichard Henderson     TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
802c781cf96SRichard Henderson     int cpu = (uintptr_t)opaque & 3;
803c781cf96SRichard Henderson 
804c781cf96SRichard Henderson     /* Set the ITI bit for this cpu.  */
805c781cf96SRichard Henderson     s->cchip.misc |= 1 << (cpu + 4);
806c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
807c781cf96SRichard Henderson }
808c781cf96SRichard Henderson 
80971baa303SHervé Poussineau PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
81071baa303SHervé Poussineau                      qemu_irq *p_rtc_irq,
811ad601177SAndreas Färber                      AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq)
81280bb2ff7SRichard Henderson {
81380bb2ff7SRichard Henderson     const uint64_t MB = 1024 * 1024;
81480bb2ff7SRichard Henderson     const uint64_t GB = 1024 * MB;
81580bb2ff7SRichard Henderson     MemoryRegion *addr_space = get_system_memory();
81680bb2ff7SRichard Henderson     DeviceState *dev;
81780bb2ff7SRichard Henderson     TyphoonState *s;
81894dd91d6SAndreas Färber     PCIHostState *phb;
81980bb2ff7SRichard Henderson     PCIBus *b;
820c781cf96SRichard Henderson     int i;
82180bb2ff7SRichard Henderson 
82294dd91d6SAndreas Färber     dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
82380bb2ff7SRichard Henderson     qdev_init_nofail(dev);
82480bb2ff7SRichard Henderson 
82594dd91d6SAndreas Färber     s = TYPHOON_PCI_HOST_BRIDGE(dev);
8268558d942SAndreas Färber     phb = PCI_HOST_BRIDGE(dev);
82780bb2ff7SRichard Henderson 
828*b83c4db8SRichard Henderson     s->cchip.misc = 0x800000000ull; /* Revision: Typhoon.  */
829*b83c4db8SRichard Henderson     s->pchip.win[3].wba = 2;        /* Window 3 SG always enabled. */
830*b83c4db8SRichard Henderson 
83180bb2ff7SRichard Henderson     /* Remember the CPUs so that we can deliver interrupts to them.  */
832c781cf96SRichard Henderson     for (i = 0; i < 4; i++) {
833ad601177SAndreas Färber         AlphaCPU *cpu = cpus[i];
834ad601177SAndreas Färber         s->cchip.cpu[i] = cpu;
835ad601177SAndreas Färber         if (cpu != NULL) {
83619e0cbb8SRichard Henderson             cpu->alarm_timer = qemu_new_timer_ns(vm_clock,
837c781cf96SRichard Henderson                                                  typhoon_alarm_timer,
838c781cf96SRichard Henderson                                                  (void *)((uintptr_t)s + i));
839c781cf96SRichard Henderson         }
840c781cf96SRichard Henderson     }
84180bb2ff7SRichard Henderson 
84280bb2ff7SRichard Henderson     *p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
84380bb2ff7SRichard Henderson 
84480bb2ff7SRichard Henderson     /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
84580bb2ff7SRichard Henderson        but the address space hole reserved at this point is 8TB.  */
84664bde0f3SPaolo Bonzini     memory_region_init_ram(&s->ram_region, OBJECT(s), "ram", ram_size);
847c5705a77SAvi Kivity     vmstate_register_ram_global(&s->ram_region);
84880bb2ff7SRichard Henderson     memory_region_add_subregion(addr_space, 0, &s->ram_region);
84980bb2ff7SRichard Henderson 
85080bb2ff7SRichard Henderson     /* TIGbus, 0x801.0000.0000, 1GB.  */
85180bb2ff7SRichard Henderson     /* ??? The TIGbus is used for delivering interrupts, and access to
85280bb2ff7SRichard Henderson        the flash ROM.  I'm not sure that we need to implement it at all.  */
85380bb2ff7SRichard Henderson 
85480bb2ff7SRichard Henderson     /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
85564bde0f3SPaolo Bonzini     memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
85664bde0f3SPaolo Bonzini                           256*MB);
85702d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80180000000ULL,
85802d6516cSStefan Weil                                 &s->pchip.region);
85980bb2ff7SRichard Henderson 
86080bb2ff7SRichard Henderson     /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
86164bde0f3SPaolo Bonzini     memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
86264bde0f3SPaolo Bonzini                           256*MB);
86302d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801a0000000ULL,
86402d6516cSStefan Weil                                 &s->cchip.region);
86580bb2ff7SRichard Henderson 
86680bb2ff7SRichard Henderson     /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
86764bde0f3SPaolo Bonzini     memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
86864bde0f3SPaolo Bonzini                           256*MB);
86902d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801b0000000ULL,
87002d6516cSStefan Weil                                 &s->dchip_region);
87180bb2ff7SRichard Henderson 
87280bb2ff7SRichard Henderson     /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
87364bde0f3SPaolo Bonzini     memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4*GB);
87402d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80000000000ULL,
87502d6516cSStefan Weil                                 &s->pchip.reg_mem);
87680bb2ff7SRichard Henderson 
87780bb2ff7SRichard Henderson     /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
8783661049fSRichard Henderson     memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops,
8793661049fSRichard Henderson                           NULL, "pci0-io", 32*MB);
88002d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fc000000ULL,
88102d6516cSStefan Weil                                 &s->pchip.reg_io);
88280bb2ff7SRichard Henderson 
88394dd91d6SAndreas Färber     b = pci_register_bus(dev, "pci",
88480bb2ff7SRichard Henderson                          typhoon_set_irq, sys_map_irq, s,
885056e6baeSRichard Henderson                          &s->pchip.reg_mem, &s->pchip.reg_io,
886056e6baeSRichard Henderson                          0, 64, TYPE_PCI_BUS);
88794dd91d6SAndreas Färber     phb->bus = b;
88880bb2ff7SRichard Henderson 
889*b83c4db8SRichard Henderson     /* Host memory as seen from the PCI side, via the IOMMU.  */
890*b83c4db8SRichard Henderson     memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops,
891*b83c4db8SRichard Henderson                              "iommu-typhoon", UINT64_MAX);
892*b83c4db8SRichard Henderson     address_space_init(&s->pchip.iommu_as, &s->pchip.iommu, "pchip0-pci");
893*b83c4db8SRichard Henderson     pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
894*b83c4db8SRichard Henderson 
89580bb2ff7SRichard Henderson     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
896056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
897056e6baeSRichard Henderson                           b, "pci0-iack", 64*MB);
89802d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801f8000000ULL,
89902d6516cSStefan Weil                                 &s->pchip.reg_iack);
90080bb2ff7SRichard Henderson 
90180bb2ff7SRichard Henderson     /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
902056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
903056e6baeSRichard Henderson                           b, "pci0-conf", 16*MB);
90402d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fe000000ULL,
90502d6516cSStefan Weil                                 &s->pchip.reg_conf);
90680bb2ff7SRichard Henderson 
90780bb2ff7SRichard Henderson     /* For the record, these are the mappings for the second PCI bus.
90880bb2ff7SRichard Henderson        We can get away with not implementing them because we indicate
90980bb2ff7SRichard Henderson        via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
91080bb2ff7SRichard Henderson     /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
91180bb2ff7SRichard Henderson     /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
91280bb2ff7SRichard Henderson     /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
91380bb2ff7SRichard Henderson     /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
91480bb2ff7SRichard Henderson     /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
91580bb2ff7SRichard Henderson 
91680bb2ff7SRichard Henderson     /* Init the ISA bus.  */
91780bb2ff7SRichard Henderson     /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
91880bb2ff7SRichard Henderson     {
91980bb2ff7SRichard Henderson         qemu_irq isa_pci_irq, *isa_irqs;
92080bb2ff7SRichard Henderson 
921056e6baeSRichard Henderson         *isa_bus = isa_bus_new(NULL, &s->pchip.reg_io);
92280bb2ff7SRichard Henderson         isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1);
92371baa303SHervé Poussineau         isa_irqs = i8259_init(*isa_bus, isa_pci_irq);
92471baa303SHervé Poussineau         isa_bus_irqs(*isa_bus, isa_irqs);
92580bb2ff7SRichard Henderson     }
92680bb2ff7SRichard Henderson 
92780bb2ff7SRichard Henderson     return b;
92880bb2ff7SRichard Henderson }
92980bb2ff7SRichard Henderson 
93080bb2ff7SRichard Henderson static int typhoon_pcihost_init(SysBusDevice *dev)
93180bb2ff7SRichard Henderson {
93280bb2ff7SRichard Henderson     return 0;
93380bb2ff7SRichard Henderson }
93480bb2ff7SRichard Henderson 
935999e12bbSAnthony Liguori static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
936999e12bbSAnthony Liguori {
93739bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
938999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
939999e12bbSAnthony Liguori 
940999e12bbSAnthony Liguori     k->init = typhoon_pcihost_init;
94139bffca2SAnthony Liguori     dc->no_user = 1;
942999e12bbSAnthony Liguori }
943999e12bbSAnthony Liguori 
9444240abffSAndreas Färber static const TypeInfo typhoon_pcihost_info = {
94594dd91d6SAndreas Färber     .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
9468558d942SAndreas Färber     .parent        = TYPE_PCI_HOST_BRIDGE,
94739bffca2SAnthony Liguori     .instance_size = sizeof(TyphoonState),
948999e12bbSAnthony Liguori     .class_init    = typhoon_pcihost_class_init,
94980bb2ff7SRichard Henderson };
95080bb2ff7SRichard Henderson 
95183f7d43aSAndreas Färber static void typhoon_register_types(void)
95280bb2ff7SRichard Henderson {
95339bffca2SAnthony Liguori     type_register_static(&typhoon_pcihost_info);
95480bb2ff7SRichard Henderson }
95583f7d43aSAndreas Färber 
95683f7d43aSAndreas Färber type_init(typhoon_register_types)
957