xref: /qemu/hw/alpha/typhoon.c (revision 3a8233dc1fe2fb5d0b51c9ae895e27b96a6d830e)
180bb2ff7SRichard Henderson /*
280bb2ff7SRichard Henderson  * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
380bb2ff7SRichard Henderson  *
480bb2ff7SRichard Henderson  * Written by Richard Henderson.
580bb2ff7SRichard Henderson  *
680bb2ff7SRichard Henderson  * This work is licensed under the GNU GPL license version 2 or later.
780bb2ff7SRichard Henderson  */
880bb2ff7SRichard Henderson 
9e2e5e114SPeter Maydell #include "qemu/osdep.h"
100b8fa32fSMarkus Armbruster #include "qemu/module.h"
112b41742aSPhilippe Mathieu-Daudé #include "qemu/units.h"
12da34e65cSMarkus Armbruster #include "qapi/error.h"
1380bb2ff7SRichard Henderson #include "cpu.h"
1464552b6bSMarkus Armbruster #include "hw/irq.h"
1547b43a1fSPaolo Bonzini #include "alpha_sys.h"
16db1015e9SEduardo Habkost #include "qom/object.h"
1780bb2ff7SRichard Henderson 
1880bb2ff7SRichard Henderson 
1994dd91d6SAndreas Färber #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
201221a474SAlexey Kardashevskiy #define TYPE_TYPHOON_IOMMU_MEMORY_REGION "typhoon-iommu-memory-region"
2194dd91d6SAndreas Färber 
2280bb2ff7SRichard Henderson typedef struct TyphoonCchip {
2380bb2ff7SRichard Henderson     MemoryRegion region;
2480bb2ff7SRichard Henderson     uint64_t misc;
2580bb2ff7SRichard Henderson     uint64_t drir;
2680bb2ff7SRichard Henderson     uint64_t dim[4];
2780bb2ff7SRichard Henderson     uint32_t iic[4];
28ad601177SAndreas Färber     AlphaCPU *cpu[4];
2980bb2ff7SRichard Henderson } TyphoonCchip;
3080bb2ff7SRichard Henderson 
3180bb2ff7SRichard Henderson typedef struct TyphoonWindow {
32b83c4db8SRichard Henderson     uint64_t wba;
33b83c4db8SRichard Henderson     uint64_t wsm;
34b83c4db8SRichard Henderson     uint64_t tba;
3580bb2ff7SRichard Henderson } TyphoonWindow;
3680bb2ff7SRichard Henderson 
3780bb2ff7SRichard Henderson typedef struct TyphoonPchip {
3880bb2ff7SRichard Henderson     MemoryRegion region;
3980bb2ff7SRichard Henderson     MemoryRegion reg_iack;
4080bb2ff7SRichard Henderson     MemoryRegion reg_mem;
4180bb2ff7SRichard Henderson     MemoryRegion reg_io;
4280bb2ff7SRichard Henderson     MemoryRegion reg_conf;
43b83c4db8SRichard Henderson 
44b83c4db8SRichard Henderson     AddressSpace iommu_as;
453df9d748SAlexey Kardashevskiy     IOMMUMemoryRegion iommu;
46b83c4db8SRichard Henderson 
4780bb2ff7SRichard Henderson     uint64_t ctl;
4880bb2ff7SRichard Henderson     TyphoonWindow win[4];
4980bb2ff7SRichard Henderson } TyphoonPchip;
5080bb2ff7SRichard Henderson 
518063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(TyphoonState, TYPHOON_PCI_HOST_BRIDGE)
5294dd91d6SAndreas Färber 
53db1015e9SEduardo Habkost struct TyphoonState {
5467c332fdSAndreas Färber     PCIHostState parent_obj;
5594dd91d6SAndreas Färber 
5680bb2ff7SRichard Henderson     TyphoonCchip cchip;
5780bb2ff7SRichard Henderson     TyphoonPchip pchip;
5880bb2ff7SRichard Henderson     MemoryRegion dchip_region;
59db1015e9SEduardo Habkost };
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 
75b7ed683aSPeter Maydell static MemTxResult cchip_read(void *opaque, hwaddr addr,
76b7ed683aSPeter Maydell                               uint64_t *data, unsigned size,
77b7ed683aSPeter Maydell                               MemTxAttrs attrs)
7880bb2ff7SRichard Henderson {
794917cf44SAndreas Färber     CPUState *cpu = current_cpu;
8080bb2ff7SRichard Henderson     TyphoonState *s = opaque;
8180bb2ff7SRichard Henderson     uint64_t ret = 0;
8280bb2ff7SRichard Henderson 
8380bb2ff7SRichard Henderson     switch (addr) {
8480bb2ff7SRichard Henderson     case 0x0000:
8580bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
8680bb2ff7SRichard Henderson         /* All sorts of data here; probably the only thing relevant is
8780bb2ff7SRichard Henderson            PIP<14> Pchip 1 Present = 0.  */
8880bb2ff7SRichard Henderson         break;
8980bb2ff7SRichard Henderson 
9080bb2ff7SRichard Henderson     case 0x0040:
9180bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
9280bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
9380bb2ff7SRichard Henderson         break;
9480bb2ff7SRichard Henderson 
9580bb2ff7SRichard Henderson     case 0x0080:
9680bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
9755e5c285SAndreas Färber         ret = s->cchip.misc | (cpu->cpu_index & 3);
9880bb2ff7SRichard Henderson         break;
9980bb2ff7SRichard Henderson 
10080bb2ff7SRichard Henderson     case 0x00c0:
10180bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
10280bb2ff7SRichard Henderson         break;
10380bb2ff7SRichard Henderson 
10480bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
10580bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
10680bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
10780bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
10880bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
10980bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
11080bb2ff7SRichard Henderson         break;
11180bb2ff7SRichard Henderson 
11280bb2ff7SRichard Henderson     case 0x0200:
11380bb2ff7SRichard Henderson         /* DIM0: Device Interrupt Mask Register, CPU0.  */
11480bb2ff7SRichard Henderson         ret = s->cchip.dim[0];
11580bb2ff7SRichard Henderson         break;
11680bb2ff7SRichard Henderson     case 0x0240:
11780bb2ff7SRichard Henderson         /* DIM1: Device Interrupt Mask Register, CPU1.  */
11880bb2ff7SRichard Henderson         ret = s->cchip.dim[1];
11980bb2ff7SRichard Henderson         break;
12080bb2ff7SRichard Henderson     case 0x0280:
12180bb2ff7SRichard Henderson         /* DIR0: Device Interrupt Request Register, CPU0.  */
12280bb2ff7SRichard Henderson         ret = s->cchip.dim[0] & s->cchip.drir;
12380bb2ff7SRichard Henderson         break;
12480bb2ff7SRichard Henderson     case 0x02c0:
12580bb2ff7SRichard Henderson         /* DIR1: Device Interrupt Request Register, CPU1.  */
12680bb2ff7SRichard Henderson         ret = s->cchip.dim[1] & s->cchip.drir;
12780bb2ff7SRichard Henderson         break;
12880bb2ff7SRichard Henderson     case 0x0300:
12980bb2ff7SRichard Henderson         /* DRIR: Device Raw Interrupt Request Register.  */
13080bb2ff7SRichard Henderson         ret = s->cchip.drir;
13180bb2ff7SRichard Henderson         break;
13280bb2ff7SRichard Henderson 
13380bb2ff7SRichard Henderson     case 0x0340:
13480bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
13580bb2ff7SRichard Henderson         break;
13680bb2ff7SRichard Henderson 
13780bb2ff7SRichard Henderson     case 0x0380:
13880bb2ff7SRichard Henderson         /* IIC0: Interval Ignore Count Register, CPU0.  */
13980bb2ff7SRichard Henderson         ret = s->cchip.iic[0];
14080bb2ff7SRichard Henderson         break;
14180bb2ff7SRichard Henderson     case 0x03c0:
14280bb2ff7SRichard Henderson         /* IIC1: Interval Ignore Count Register, CPU1.  */
14380bb2ff7SRichard Henderson         ret = s->cchip.iic[1];
14480bb2ff7SRichard Henderson         break;
14580bb2ff7SRichard Henderson 
14680bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
14780bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
14880bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
14980bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
15080bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
15180bb2ff7SRichard Henderson         break;
15280bb2ff7SRichard Henderson 
15380bb2ff7SRichard Henderson     case 0x0580:
15480bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
15580bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
15680bb2ff7SRichard Henderson         break;
15780bb2ff7SRichard Henderson     case 0x05c0:
15880bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
15980bb2ff7SRichard Henderson         break;
16080bb2ff7SRichard Henderson 
16180bb2ff7SRichard Henderson     case 0x0600:
16280bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
16380bb2ff7SRichard Henderson         ret = s->cchip.dim[2];
16480bb2ff7SRichard Henderson         break;
16580bb2ff7SRichard Henderson     case 0x0640:
16680bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
16780bb2ff7SRichard Henderson         ret = s->cchip.dim[3];
16880bb2ff7SRichard Henderson         break;
16980bb2ff7SRichard Henderson     case 0x0680:
17080bb2ff7SRichard Henderson         /* DIR2: Device Interrupt Request Register, CPU2.  */
17180bb2ff7SRichard Henderson         ret = s->cchip.dim[2] & s->cchip.drir;
17280bb2ff7SRichard Henderson         break;
17380bb2ff7SRichard Henderson     case 0x06c0:
17480bb2ff7SRichard Henderson         /* DIR3: Device Interrupt Request Register, CPU3.  */
17580bb2ff7SRichard Henderson         ret = s->cchip.dim[3] & s->cchip.drir;
17680bb2ff7SRichard Henderson         break;
17780bb2ff7SRichard Henderson 
17880bb2ff7SRichard Henderson     case 0x0700:
17980bb2ff7SRichard Henderson         /* IIC2: Interval Ignore Count Register, CPU2.  */
18080bb2ff7SRichard Henderson         ret = s->cchip.iic[2];
18180bb2ff7SRichard Henderson         break;
18280bb2ff7SRichard Henderson     case 0x0740:
18380bb2ff7SRichard Henderson         /* IIC3: Interval Ignore Count Register, CPU3.  */
18480bb2ff7SRichard Henderson         ret = s->cchip.iic[3];
18580bb2ff7SRichard Henderson         break;
18680bb2ff7SRichard Henderson 
18780bb2ff7SRichard Henderson     case 0x0780:
18880bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
18980bb2ff7SRichard Henderson         break;
19080bb2ff7SRichard Henderson 
19180bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
19280bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
19380bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
19480bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
19580bb2ff7SRichard Henderson         break;
19680bb2ff7SRichard Henderson 
19780bb2ff7SRichard Henderson     default:
198b7ed683aSPeter Maydell         return MEMTX_ERROR;
19980bb2ff7SRichard Henderson     }
20080bb2ff7SRichard Henderson 
201b7ed683aSPeter Maydell     *data = ret;
202b7ed683aSPeter Maydell     return MEMTX_OK;
20380bb2ff7SRichard Henderson }
20480bb2ff7SRichard Henderson 
205a8170e5eSAvi Kivity static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
20680bb2ff7SRichard Henderson {
20780bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
20880bb2ff7SRichard Henderson     return 0;
20980bb2ff7SRichard Henderson }
21080bb2ff7SRichard Henderson 
211b7ed683aSPeter Maydell static MemTxResult pchip_read(void *opaque, hwaddr addr, uint64_t *data,
212b7ed683aSPeter Maydell                               unsigned size, MemTxAttrs attrs)
21380bb2ff7SRichard Henderson {
21480bb2ff7SRichard Henderson     TyphoonState *s = opaque;
21580bb2ff7SRichard Henderson     uint64_t ret = 0;
21680bb2ff7SRichard Henderson 
21780bb2ff7SRichard Henderson     switch (addr) {
21880bb2ff7SRichard Henderson     case 0x0000:
21980bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
220b83c4db8SRichard Henderson         ret = s->pchip.win[0].wba;
22180bb2ff7SRichard Henderson         break;
22280bb2ff7SRichard Henderson     case 0x0040:
22380bb2ff7SRichard Henderson         /* WSBA1 */
224b83c4db8SRichard Henderson         ret = s->pchip.win[1].wba;
22580bb2ff7SRichard Henderson         break;
22680bb2ff7SRichard Henderson     case 0x0080:
22780bb2ff7SRichard Henderson         /* WSBA2 */
228b83c4db8SRichard Henderson         ret = s->pchip.win[2].wba;
22980bb2ff7SRichard Henderson         break;
23080bb2ff7SRichard Henderson     case 0x00c0:
23180bb2ff7SRichard Henderson         /* WSBA3 */
232b83c4db8SRichard Henderson         ret = s->pchip.win[3].wba;
23380bb2ff7SRichard Henderson         break;
23480bb2ff7SRichard Henderson 
23580bb2ff7SRichard Henderson     case 0x0100:
23680bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
237b83c4db8SRichard Henderson         ret = s->pchip.win[0].wsm;
23880bb2ff7SRichard Henderson         break;
23980bb2ff7SRichard Henderson     case 0x0140:
24080bb2ff7SRichard Henderson         /* WSM1 */
241b83c4db8SRichard Henderson         ret = s->pchip.win[1].wsm;
24280bb2ff7SRichard Henderson         break;
24380bb2ff7SRichard Henderson     case 0x0180:
24480bb2ff7SRichard Henderson         /* WSM2 */
245b83c4db8SRichard Henderson         ret = s->pchip.win[2].wsm;
24680bb2ff7SRichard Henderson         break;
24780bb2ff7SRichard Henderson     case 0x01c0:
24880bb2ff7SRichard Henderson         /* WSM3 */
249b83c4db8SRichard Henderson         ret = s->pchip.win[3].wsm;
25080bb2ff7SRichard Henderson         break;
25180bb2ff7SRichard Henderson 
25280bb2ff7SRichard Henderson     case 0x0200:
25380bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
254b83c4db8SRichard Henderson         ret = s->pchip.win[0].tba;
25580bb2ff7SRichard Henderson         break;
25680bb2ff7SRichard Henderson     case 0x0240:
25780bb2ff7SRichard Henderson         /* TBA1 */
258b83c4db8SRichard Henderson         ret = s->pchip.win[1].tba;
25980bb2ff7SRichard Henderson         break;
26080bb2ff7SRichard Henderson     case 0x0280:
26180bb2ff7SRichard Henderson         /* TBA2 */
262b83c4db8SRichard Henderson         ret = s->pchip.win[2].tba;
26380bb2ff7SRichard Henderson         break;
26480bb2ff7SRichard Henderson     case 0x02c0:
26580bb2ff7SRichard Henderson         /* TBA3 */
266b83c4db8SRichard Henderson         ret = s->pchip.win[3].tba;
26780bb2ff7SRichard Henderson         break;
26880bb2ff7SRichard Henderson 
26980bb2ff7SRichard Henderson     case 0x0300:
27080bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
27180bb2ff7SRichard Henderson         ret = s->pchip.ctl;
27280bb2ff7SRichard Henderson         break;
27380bb2ff7SRichard Henderson     case 0x0340:
27480bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
27580bb2ff7SRichard Henderson         break;
27680bb2ff7SRichard Henderson     case 0x03c0:
27780bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
27880bb2ff7SRichard Henderson         break;
27980bb2ff7SRichard Henderson     case 0x0400:
28080bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
28180bb2ff7SRichard Henderson         break;
28280bb2ff7SRichard Henderson     case 0x0440:
28380bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
28480bb2ff7SRichard Henderson         break;
28580bb2ff7SRichard Henderson     case 0x0480:
28680bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
28780bb2ff7SRichard Henderson         break;
28880bb2ff7SRichard Henderson     case 0x04c0:
28980bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
29080bb2ff7SRichard Henderson         break;
29180bb2ff7SRichard Henderson     case 0x0500: /* PMONCTL */
29280bb2ff7SRichard Henderson     case 0x0540: /* PMONCNT */
29380bb2ff7SRichard Henderson     case 0x0800: /* SPRST */
29480bb2ff7SRichard Henderson         break;
29580bb2ff7SRichard Henderson 
29680bb2ff7SRichard Henderson     default:
297b7ed683aSPeter Maydell         return MEMTX_ERROR;
29880bb2ff7SRichard Henderson     }
29980bb2ff7SRichard Henderson 
300b7ed683aSPeter Maydell     *data = ret;
301b7ed683aSPeter Maydell     return MEMTX_OK;
30280bb2ff7SRichard Henderson }
30380bb2ff7SRichard Henderson 
304b7ed683aSPeter Maydell static MemTxResult cchip_write(void *opaque, hwaddr addr,
305b7ed683aSPeter Maydell                                uint64_t val, unsigned size,
306b7ed683aSPeter Maydell                                MemTxAttrs attrs)
30780bb2ff7SRichard Henderson {
30880bb2ff7SRichard Henderson     TyphoonState *s = opaque;
30967842165SRichard Henderson     uint64_t oldval, newval;
31080bb2ff7SRichard Henderson 
31180bb2ff7SRichard Henderson     switch (addr) {
31280bb2ff7SRichard Henderson     case 0x0000:
31380bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
31480bb2ff7SRichard Henderson         /* All sorts of data here; nothing relevant RW.  */
31580bb2ff7SRichard Henderson         break;
31680bb2ff7SRichard Henderson 
31780bb2ff7SRichard Henderson     case 0x0040:
31880bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
31980bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
32080bb2ff7SRichard Henderson         break;
32180bb2ff7SRichard Henderson 
32280bb2ff7SRichard Henderson     case 0x0080:
32380bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
32480bb2ff7SRichard Henderson         newval = oldval = s->cchip.misc;
32580bb2ff7SRichard Henderson         newval &= ~(val & 0x10000ff0);     /* W1C fields */
32680bb2ff7SRichard Henderson         if (val & 0x100000) {
32780bb2ff7SRichard Henderson             newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
32880bb2ff7SRichard Henderson         } else {
32980bb2ff7SRichard Henderson             newval |= val & 0x00f00000;    /* ABT field is W1S */
33080bb2ff7SRichard Henderson             if ((newval & 0xf0000) == 0) {
33180bb2ff7SRichard Henderson                 newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
33280bb2ff7SRichard Henderson             }
33380bb2ff7SRichard Henderson         }
33480bb2ff7SRichard Henderson         newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
33580bb2ff7SRichard Henderson 
33680bb2ff7SRichard Henderson         newval &= ~0xf0000000000ull;       /* WO and RW fields */
33780bb2ff7SRichard Henderson         newval |= val & 0xf0000000000ull;
33880bb2ff7SRichard Henderson         s->cchip.misc = newval;
33980bb2ff7SRichard Henderson 
34080bb2ff7SRichard Henderson         /* Pass on changes to IPI and ITI state.  */
34180bb2ff7SRichard Henderson         if ((newval ^ oldval) & 0xff0) {
34280bb2ff7SRichard Henderson             int i;
34380bb2ff7SRichard Henderson             for (i = 0; i < 4; ++i) {
344ad601177SAndreas Färber                 AlphaCPU *cpu = s->cchip.cpu[i];
345ad601177SAndreas Färber                 if (cpu != NULL) {
346d8ed887bSAndreas Färber                     CPUState *cs = CPU(cpu);
34780bb2ff7SRichard Henderson                     /* IPI can be either cleared or set by the write.  */
34880bb2ff7SRichard Henderson                     if (newval & (1 << (i + 8))) {
349c3affe56SAndreas Färber                         cpu_interrupt(cs, CPU_INTERRUPT_SMP);
35080bb2ff7SRichard Henderson                     } else {
351d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
35280bb2ff7SRichard Henderson                     }
35380bb2ff7SRichard Henderson 
35480bb2ff7SRichard Henderson                     /* ITI can only be cleared by the write.  */
35580bb2ff7SRichard Henderson                     if ((newval & (1 << (i + 4))) == 0) {
356d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
35780bb2ff7SRichard Henderson                     }
35880bb2ff7SRichard Henderson                 }
35980bb2ff7SRichard Henderson             }
36080bb2ff7SRichard Henderson         }
36180bb2ff7SRichard Henderson         break;
36280bb2ff7SRichard Henderson 
36380bb2ff7SRichard Henderson     case 0x00c0:
36480bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
36580bb2ff7SRichard Henderson         break;
36680bb2ff7SRichard Henderson 
36780bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
36880bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
36980bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
37080bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
37180bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
37280bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
37380bb2ff7SRichard Henderson         break;
37480bb2ff7SRichard Henderson 
37580bb2ff7SRichard Henderson     case 0x0200: /* DIM0 */
37680bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU0.  */
37780bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
37880bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
37980bb2ff7SRichard Henderson         break;
38080bb2ff7SRichard Henderson     case 0x0240: /* DIM1 */
38180bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU1.  */
382424ad838SRichard Henderson         s->cchip.dim[1] = val;
38380bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
38480bb2ff7SRichard Henderson         break;
38580bb2ff7SRichard Henderson 
38680bb2ff7SRichard Henderson     case 0x0280: /* DIR0 (RO) */
38780bb2ff7SRichard Henderson     case 0x02c0: /* DIR1 (RO) */
38880bb2ff7SRichard Henderson     case 0x0300: /* DRIR (RO) */
38980bb2ff7SRichard Henderson         break;
39080bb2ff7SRichard Henderson 
39180bb2ff7SRichard Henderson     case 0x0340:
39280bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
39380bb2ff7SRichard Henderson         break;
39480bb2ff7SRichard Henderson 
39580bb2ff7SRichard Henderson     case 0x0380: /* IIC0 */
39680bb2ff7SRichard Henderson         s->cchip.iic[0] = val & 0xffffff;
39780bb2ff7SRichard Henderson         break;
39880bb2ff7SRichard Henderson     case 0x03c0: /* IIC1 */
39980bb2ff7SRichard Henderson         s->cchip.iic[1] = val & 0xffffff;
40080bb2ff7SRichard Henderson         break;
40180bb2ff7SRichard Henderson 
40280bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
40380bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
40480bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
40580bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
40680bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
40780bb2ff7SRichard Henderson         break;
40880bb2ff7SRichard Henderson 
40980bb2ff7SRichard Henderson     case 0x0580:
41080bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
41180bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
41280bb2ff7SRichard Henderson         break;
41380bb2ff7SRichard Henderson     case 0x05c0:
41480bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
41580bb2ff7SRichard Henderson         break;
41680bb2ff7SRichard Henderson 
41780bb2ff7SRichard Henderson     case 0x0600:
41880bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
41980bb2ff7SRichard Henderson         s->cchip.dim[2] = val;
42080bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
42180bb2ff7SRichard Henderson         break;
42280bb2ff7SRichard Henderson     case 0x0640:
42380bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
42480bb2ff7SRichard Henderson         s->cchip.dim[3] = val;
42580bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
42680bb2ff7SRichard Henderson         break;
42780bb2ff7SRichard Henderson 
42880bb2ff7SRichard Henderson     case 0x0680: /* DIR2 (RO) */
42980bb2ff7SRichard Henderson     case 0x06c0: /* DIR3 (RO) */
43080bb2ff7SRichard Henderson         break;
43180bb2ff7SRichard Henderson 
43280bb2ff7SRichard Henderson     case 0x0700: /* IIC2 */
43380bb2ff7SRichard Henderson         s->cchip.iic[2] = val & 0xffffff;
43480bb2ff7SRichard Henderson         break;
43580bb2ff7SRichard Henderson     case 0x0740: /* IIC3 */
43680bb2ff7SRichard Henderson         s->cchip.iic[3] = val & 0xffffff;
43780bb2ff7SRichard Henderson         break;
43880bb2ff7SRichard Henderson 
43980bb2ff7SRichard Henderson     case 0x0780:
44080bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
44180bb2ff7SRichard Henderson         break;
44280bb2ff7SRichard Henderson 
44380bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
44480bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
44580bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
44680bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
44780bb2ff7SRichard Henderson         break;
44880bb2ff7SRichard Henderson 
44980bb2ff7SRichard Henderson     default:
450b7ed683aSPeter Maydell         return MEMTX_ERROR;
45180bb2ff7SRichard Henderson     }
452b7ed683aSPeter Maydell 
453b7ed683aSPeter Maydell     return MEMTX_OK;
45480bb2ff7SRichard Henderson }
45580bb2ff7SRichard Henderson 
456a8170e5eSAvi Kivity static void dchip_write(void *opaque, hwaddr addr,
45780bb2ff7SRichard Henderson                         uint64_t val, unsigned size)
45880bb2ff7SRichard Henderson {
45980bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
46080bb2ff7SRichard Henderson }
46180bb2ff7SRichard Henderson 
462b7ed683aSPeter Maydell static MemTxResult pchip_write(void *opaque, hwaddr addr,
463b7ed683aSPeter Maydell                                uint64_t val, unsigned size,
464b7ed683aSPeter Maydell                                MemTxAttrs attrs)
46580bb2ff7SRichard Henderson {
46680bb2ff7SRichard Henderson     TyphoonState *s = opaque;
46767842165SRichard Henderson     uint64_t oldval;
46880bb2ff7SRichard Henderson 
46980bb2ff7SRichard Henderson     switch (addr) {
47080bb2ff7SRichard Henderson     case 0x0000:
47180bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
472b83c4db8SRichard Henderson         s->pchip.win[0].wba = val & 0xfff00003u;
47380bb2ff7SRichard Henderson         break;
47480bb2ff7SRichard Henderson     case 0x0040:
47580bb2ff7SRichard Henderson         /* WSBA1 */
476b83c4db8SRichard Henderson         s->pchip.win[1].wba = val & 0xfff00003u;
47780bb2ff7SRichard Henderson         break;
47880bb2ff7SRichard Henderson     case 0x0080:
47980bb2ff7SRichard Henderson         /* WSBA2 */
480b83c4db8SRichard Henderson         s->pchip.win[2].wba = val & 0xfff00003u;
48180bb2ff7SRichard Henderson         break;
48280bb2ff7SRichard Henderson     case 0x00c0:
48380bb2ff7SRichard Henderson         /* WSBA3 */
484b83c4db8SRichard Henderson         s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
48580bb2ff7SRichard Henderson         break;
48680bb2ff7SRichard Henderson 
48780bb2ff7SRichard Henderson     case 0x0100:
48880bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
489b83c4db8SRichard Henderson         s->pchip.win[0].wsm = val & 0xfff00000u;
49080bb2ff7SRichard Henderson         break;
49180bb2ff7SRichard Henderson     case 0x0140:
49280bb2ff7SRichard Henderson         /* WSM1 */
493b83c4db8SRichard Henderson         s->pchip.win[1].wsm = val & 0xfff00000u;
49480bb2ff7SRichard Henderson         break;
49580bb2ff7SRichard Henderson     case 0x0180:
49680bb2ff7SRichard Henderson         /* WSM2 */
497b83c4db8SRichard Henderson         s->pchip.win[2].wsm = val & 0xfff00000u;
49880bb2ff7SRichard Henderson         break;
49980bb2ff7SRichard Henderson     case 0x01c0:
50080bb2ff7SRichard Henderson         /* WSM3 */
501b83c4db8SRichard Henderson         s->pchip.win[3].wsm = val & 0xfff00000u;
50280bb2ff7SRichard Henderson         break;
50380bb2ff7SRichard Henderson 
50480bb2ff7SRichard Henderson     case 0x0200:
50580bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
506b83c4db8SRichard Henderson         s->pchip.win[0].tba = val & 0x7fffffc00ull;
50780bb2ff7SRichard Henderson         break;
50880bb2ff7SRichard Henderson     case 0x0240:
50980bb2ff7SRichard Henderson         /* TBA1 */
510b83c4db8SRichard Henderson         s->pchip.win[1].tba = val & 0x7fffffc00ull;
51180bb2ff7SRichard Henderson         break;
51280bb2ff7SRichard Henderson     case 0x0280:
51380bb2ff7SRichard Henderson         /* TBA2 */
514b83c4db8SRichard Henderson         s->pchip.win[2].tba = val & 0x7fffffc00ull;
51580bb2ff7SRichard Henderson         break;
51680bb2ff7SRichard Henderson     case 0x02c0:
51780bb2ff7SRichard Henderson         /* TBA3 */
518b83c4db8SRichard Henderson         s->pchip.win[3].tba = val & 0x7fffffc00ull;
51980bb2ff7SRichard Henderson         break;
52080bb2ff7SRichard Henderson 
52180bb2ff7SRichard Henderson     case 0x0300:
52280bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
52380bb2ff7SRichard Henderson         oldval = s->pchip.ctl;
52480bb2ff7SRichard Henderson         oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
52580bb2ff7SRichard Henderson         oldval |= val & 0x00001cff0fc7ffull;
52680bb2ff7SRichard Henderson         s->pchip.ctl = oldval;
52780bb2ff7SRichard Henderson         break;
52880bb2ff7SRichard Henderson 
52980bb2ff7SRichard Henderson     case 0x0340:
53080bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
53180bb2ff7SRichard Henderson         break;
53280bb2ff7SRichard Henderson     case 0x03c0:
53380bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
53480bb2ff7SRichard Henderson         break;
53580bb2ff7SRichard Henderson     case 0x0400:
53680bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
53780bb2ff7SRichard Henderson         break;
53880bb2ff7SRichard Henderson     case 0x0440:
53980bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
54080bb2ff7SRichard Henderson         break;
54180bb2ff7SRichard Henderson 
54280bb2ff7SRichard Henderson     case 0x0480:
54380bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
54480bb2ff7SRichard Henderson         break;
54580bb2ff7SRichard Henderson 
54680bb2ff7SRichard Henderson     case 0x04c0:
54780bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
54880bb2ff7SRichard Henderson         break;
54980bb2ff7SRichard Henderson 
55080bb2ff7SRichard Henderson     case 0x0500:
55180bb2ff7SRichard Henderson         /* PMONCTL */
55280bb2ff7SRichard Henderson     case 0x0540:
55380bb2ff7SRichard Henderson         /* PMONCNT */
55480bb2ff7SRichard Henderson     case 0x0800:
55580bb2ff7SRichard Henderson         /* SPRST */
55680bb2ff7SRichard Henderson         break;
55780bb2ff7SRichard Henderson 
55880bb2ff7SRichard Henderson     default:
559b7ed683aSPeter Maydell         return MEMTX_ERROR;
56080bb2ff7SRichard Henderson     }
561b7ed683aSPeter Maydell 
562b7ed683aSPeter Maydell     return MEMTX_OK;
56380bb2ff7SRichard Henderson }
56480bb2ff7SRichard Henderson 
56580bb2ff7SRichard Henderson static const MemoryRegionOps cchip_ops = {
566b7ed683aSPeter Maydell     .read_with_attrs = cchip_read,
567b7ed683aSPeter Maydell     .write_with_attrs = cchip_write,
56880bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
56980bb2ff7SRichard Henderson     .valid = {
57067842165SRichard Henderson         .min_access_size = 8,
57180bb2ff7SRichard Henderson         .max_access_size = 8,
57280bb2ff7SRichard Henderson     },
57380bb2ff7SRichard Henderson     .impl = {
57467842165SRichard Henderson         .min_access_size = 8,
57567842165SRichard Henderson         .max_access_size = 8,
57680bb2ff7SRichard Henderson     },
57780bb2ff7SRichard Henderson };
57880bb2ff7SRichard Henderson 
57980bb2ff7SRichard Henderson static const MemoryRegionOps dchip_ops = {
58080bb2ff7SRichard Henderson     .read = dchip_read,
58180bb2ff7SRichard Henderson     .write = dchip_write,
58280bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
58380bb2ff7SRichard Henderson     .valid = {
58467842165SRichard Henderson         .min_access_size = 8,
58580bb2ff7SRichard Henderson         .max_access_size = 8,
58680bb2ff7SRichard Henderson     },
58780bb2ff7SRichard Henderson     .impl = {
58867842165SRichard Henderson         .min_access_size = 8,
58980bb2ff7SRichard Henderson         .max_access_size = 8,
59080bb2ff7SRichard Henderson     },
59180bb2ff7SRichard Henderson };
59280bb2ff7SRichard Henderson 
59380bb2ff7SRichard Henderson static const MemoryRegionOps pchip_ops = {
594b7ed683aSPeter Maydell     .read_with_attrs = pchip_read,
595b7ed683aSPeter Maydell     .write_with_attrs = pchip_write,
59680bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
59780bb2ff7SRichard Henderson     .valid = {
59867842165SRichard Henderson         .min_access_size = 8,
59980bb2ff7SRichard Henderson         .max_access_size = 8,
60080bb2ff7SRichard Henderson     },
60180bb2ff7SRichard Henderson     .impl = {
60267842165SRichard Henderson         .min_access_size = 8,
60367842165SRichard Henderson         .max_access_size = 8,
60480bb2ff7SRichard Henderson     },
60580bb2ff7SRichard Henderson };
60680bb2ff7SRichard Henderson 
607b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
608b83c4db8SRichard Henderson    using the given translated address and mask.  */
609b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
610b83c4db8SRichard Henderson {
611b83c4db8SRichard Henderson     *ret = (IOMMUTLBEntry) {
612b83c4db8SRichard Henderson         .target_as = &address_space_memory,
613b83c4db8SRichard Henderson         .translated_addr = taddr,
614b83c4db8SRichard Henderson         .addr_mask = mask,
615b83c4db8SRichard Henderson         .perm = IOMMU_RW,
616b83c4db8SRichard Henderson     };
617b83c4db8SRichard Henderson     return true;
618b83c4db8SRichard Henderson }
619b83c4db8SRichard Henderson 
620b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather
621b83c4db8SRichard Henderson    translation, given the address of the PTE.  */
622b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
623b83c4db8SRichard Henderson {
62442874d3aSPeter Maydell     uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
62542874d3aSPeter Maydell                                      MEMTXATTRS_UNSPECIFIED, NULL);
626b83c4db8SRichard Henderson 
627b83c4db8SRichard Henderson     /* Check valid bit.  */
628b83c4db8SRichard Henderson     if ((pte & 1) == 0) {
629b83c4db8SRichard Henderson         return false;
630b83c4db8SRichard Henderson     }
631b83c4db8SRichard Henderson 
632b83c4db8SRichard Henderson     return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
633b83c4db8SRichard Henderson }
634b83c4db8SRichard Henderson 
635b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the
636b83c4db8SRichard Henderson    four single-address-cycle translation windows.  */
637b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr,
638b83c4db8SRichard Henderson                              IOMMUTLBEntry *ret)
639b83c4db8SRichard Henderson {
640b83c4db8SRichard Henderson     uint32_t wba = win->wba;
641b83c4db8SRichard Henderson     uint64_t wsm = win->wsm;
642b83c4db8SRichard Henderson     uint64_t tba = win->tba;
643b83c4db8SRichard Henderson     uint64_t wsm_ext = wsm | 0xfffff;
644b83c4db8SRichard Henderson 
645b83c4db8SRichard Henderson     /* Check for window disabled.  */
646b83c4db8SRichard Henderson     if ((wba & 1) == 0) {
647b83c4db8SRichard Henderson         return false;
648b83c4db8SRichard Henderson     }
649b83c4db8SRichard Henderson 
650b83c4db8SRichard Henderson     /* Check for window hit.  */
651b83c4db8SRichard Henderson     if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
652b83c4db8SRichard Henderson         return false;
653b83c4db8SRichard Henderson     }
654b83c4db8SRichard Henderson 
655b83c4db8SRichard Henderson     if (wba & 2) {
656b83c4db8SRichard Henderson         /* Scatter-gather translation.  */
657b83c4db8SRichard Henderson         hwaddr pte_addr;
658b83c4db8SRichard Henderson 
659b83c4db8SRichard Henderson         /* See table 10-6, Generating PTE address for PCI DMA Address.  */
660b83c4db8SRichard Henderson         pte_addr  = tba & ~(wsm >> 10);
661b83c4db8SRichard Henderson         pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
662b83c4db8SRichard Henderson         return pte_translate(pte_addr, ret);
663b83c4db8SRichard Henderson     } else {
664b83c4db8SRichard Henderson         /* Direct-mapped translation.  */
665b83c4db8SRichard Henderson         return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
666b83c4db8SRichard Henderson     }
667b83c4db8SRichard Henderson }
668b83c4db8SRichard Henderson 
669b83c4db8SRichard Henderson /* Handle PCI-to-system address translation.  */
670b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the
671b83c4db8SRichard Henderson    Pchip and generate a machine check interrupt.  */
6723df9d748SAlexey Kardashevskiy static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
6733df9d748SAlexey Kardashevskiy                                              hwaddr addr,
6742c91bcf2SPeter Maydell                                              IOMMUAccessFlags flag,
6752c91bcf2SPeter Maydell                                              int iommu_idx)
676b83c4db8SRichard Henderson {
677b83c4db8SRichard Henderson     TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
678b83c4db8SRichard Henderson     IOMMUTLBEntry ret;
679b83c4db8SRichard Henderson     int i;
680b83c4db8SRichard Henderson 
681b83c4db8SRichard Henderson     if (addr <= 0xffffffffu) {
682b83c4db8SRichard Henderson         /* Single-address cycle.  */
683b83c4db8SRichard Henderson 
684b83c4db8SRichard Henderson         /* Check for the Window Hole, inhibiting matching.  */
685b83c4db8SRichard Henderson         if ((pchip->ctl & 0x20)
686b83c4db8SRichard Henderson             && addr >= 0x80000
687b83c4db8SRichard Henderson             && addr <= 0xfffff) {
688b83c4db8SRichard Henderson             goto failure;
689b83c4db8SRichard Henderson         }
690b83c4db8SRichard Henderson 
691b83c4db8SRichard Henderson         /* Check the first three windows.  */
692b83c4db8SRichard Henderson         for (i = 0; i < 3; ++i) {
693b83c4db8SRichard Henderson             if (window_translate(&pchip->win[i], addr, &ret)) {
694b83c4db8SRichard Henderson                 goto success;
695b83c4db8SRichard Henderson             }
696b83c4db8SRichard Henderson         }
697b83c4db8SRichard Henderson 
698b83c4db8SRichard Henderson         /* Check the fourth window for DAC disable.  */
699b83c4db8SRichard Henderson         if ((pchip->win[3].wba & 0x80000000000ull) == 0
700b83c4db8SRichard Henderson             && window_translate(&pchip->win[3], addr, &ret)) {
701b83c4db8SRichard Henderson             goto success;
702b83c4db8SRichard Henderson         }
703b83c4db8SRichard Henderson     } else {
704b83c4db8SRichard Henderson         /* Double-address cycle.  */
705b83c4db8SRichard Henderson 
706b83c4db8SRichard Henderson         if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
707b83c4db8SRichard Henderson             /* Check for the DMA monster window.  */
708b83c4db8SRichard Henderson             if (pchip->ctl & 0x40) {
709b83c4db8SRichard Henderson                 /* See 10.1.4.4; in particular <39:35> is ignored.  */
710b83c4db8SRichard Henderson                 make_iommu_tlbe(0, 0x007ffffffffull, &ret);
711b83c4db8SRichard Henderson                 goto success;
712b83c4db8SRichard Henderson             }
713b83c4db8SRichard Henderson         }
714b83c4db8SRichard Henderson 
7159b2caaf4SStefan Weil         if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) {
716b83c4db8SRichard Henderson             /* Check the fourth window for DAC enable and window enable.  */
717b83c4db8SRichard Henderson             if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
718b83c4db8SRichard Henderson                 uint64_t pte_addr;
719b83c4db8SRichard Henderson 
720b83c4db8SRichard Henderson                 pte_addr  = pchip->win[3].tba & 0x7ffc00000ull;
721b83c4db8SRichard Henderson                 pte_addr |= (addr & 0xffffe000u) >> 10;
722b83c4db8SRichard Henderson                 if (pte_translate(pte_addr, &ret)) {
723b83c4db8SRichard Henderson                         goto success;
724b83c4db8SRichard Henderson                 }
725b83c4db8SRichard Henderson             }
726b83c4db8SRichard Henderson         }
727b83c4db8SRichard Henderson     }
728b83c4db8SRichard Henderson 
729b83c4db8SRichard Henderson  failure:
730b83c4db8SRichard Henderson     ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
731b83c4db8SRichard Henderson  success:
732b83c4db8SRichard Henderson     return ret;
733b83c4db8SRichard Henderson }
734b83c4db8SRichard Henderson 
735b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
736b83c4db8SRichard Henderson {
737b83c4db8SRichard Henderson     TyphoonState *s = opaque;
738b83c4db8SRichard Henderson     return &s->pchip.iommu_as;
739b83c4db8SRichard Henderson }
740b83c4db8SRichard Henderson 
74180bb2ff7SRichard Henderson static void typhoon_set_irq(void *opaque, int irq, int level)
74280bb2ff7SRichard Henderson {
74380bb2ff7SRichard Henderson     TyphoonState *s = opaque;
74480bb2ff7SRichard Henderson     uint64_t drir;
74580bb2ff7SRichard Henderson     int i;
74680bb2ff7SRichard Henderson 
74780bb2ff7SRichard Henderson     /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
74880bb2ff7SRichard Henderson     drir = s->cchip.drir;
74980bb2ff7SRichard Henderson     if (level) {
75080bb2ff7SRichard Henderson         drir |= 1ull << irq;
75180bb2ff7SRichard Henderson     } else {
75280bb2ff7SRichard Henderson         drir &= ~(1ull << irq);
75380bb2ff7SRichard Henderson     }
75480bb2ff7SRichard Henderson     s->cchip.drir = drir;
75580bb2ff7SRichard Henderson 
75680bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
75780bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
75880bb2ff7SRichard Henderson     }
75980bb2ff7SRichard Henderson }
76080bb2ff7SRichard Henderson 
76180bb2ff7SRichard Henderson static void typhoon_set_isa_irq(void *opaque, int irq, int level)
76280bb2ff7SRichard Henderson {
76380bb2ff7SRichard Henderson     typhoon_set_irq(opaque, 55, level);
76480bb2ff7SRichard Henderson }
76580bb2ff7SRichard Henderson 
76680bb2ff7SRichard Henderson static void typhoon_set_timer_irq(void *opaque, int irq, int level)
76780bb2ff7SRichard Henderson {
76880bb2ff7SRichard Henderson     TyphoonState *s = opaque;
76980bb2ff7SRichard Henderson     int i;
77080bb2ff7SRichard Henderson 
77180bb2ff7SRichard Henderson     /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
77280bb2ff7SRichard Henderson        and so we don't have to worry about missing interrupts just
77380bb2ff7SRichard Henderson        because we never actually ACK the interrupt.  Just ignore any
77480bb2ff7SRichard Henderson        case of the interrupt level going low.  */
77580bb2ff7SRichard Henderson     if (level == 0) {
77680bb2ff7SRichard Henderson         return;
77780bb2ff7SRichard Henderson     }
77880bb2ff7SRichard Henderson 
77980bb2ff7SRichard Henderson     /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
78080bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
781ad601177SAndreas Färber         AlphaCPU *cpu = s->cchip.cpu[i];
782ad601177SAndreas Färber         if (cpu != NULL) {
78380bb2ff7SRichard Henderson             uint32_t iic = s->cchip.iic[i];
78480bb2ff7SRichard Henderson 
78580bb2ff7SRichard Henderson             /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
78680bb2ff7SRichard Henderson                Bit 24 is the OverFlow bit, RO, and set when the count
78780bb2ff7SRichard Henderson                decrements past 0.  When is OF cleared?  My guess is that
78880bb2ff7SRichard Henderson                OF is actually cleared when the IIC is written, and that
78980bb2ff7SRichard Henderson                the ICNT field always decrements.  At least, that's an
79080bb2ff7SRichard Henderson                interpretation that makes sense, and "allows the CPU to
79180bb2ff7SRichard Henderson                determine exactly how mant interval timer ticks were
79280bb2ff7SRichard Henderson                skipped".  At least within the next 4M ticks...  */
79380bb2ff7SRichard Henderson 
79480bb2ff7SRichard Henderson             iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
79580bb2ff7SRichard Henderson             s->cchip.iic[i] = iic;
79680bb2ff7SRichard Henderson 
79780bb2ff7SRichard Henderson             if (iic & 0x1000000) {
79880bb2ff7SRichard Henderson                 /* Set the ITI bit for this cpu.  */
79980bb2ff7SRichard Henderson                 s->cchip.misc |= 1 << (i + 4);
80080bb2ff7SRichard Henderson                 /* And signal the interrupt.  */
801c3affe56SAndreas Färber                 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
80280bb2ff7SRichard Henderson             }
80380bb2ff7SRichard Henderson         }
80480bb2ff7SRichard Henderson     }
80580bb2ff7SRichard Henderson }
80680bb2ff7SRichard Henderson 
807c781cf96SRichard Henderson static void typhoon_alarm_timer(void *opaque)
808c781cf96SRichard Henderson {
809c781cf96SRichard Henderson     TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
810c781cf96SRichard Henderson     int cpu = (uintptr_t)opaque & 3;
811c781cf96SRichard Henderson 
812c781cf96SRichard Henderson     /* Set the ITI bit for this cpu.  */
813c781cf96SRichard Henderson     s->cchip.misc |= 1 << (cpu + 4);
814c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
815c781cf96SRichard Henderson }
816c781cf96SRichard Henderson 
817b844d822SIgor Mammedov PCIBus *typhoon_init(MemoryRegion *ram, ISABus **isa_bus, qemu_irq *p_rtc_irq,
818*3a8233dcSJason Thorpe                      AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq,
819*3a8233dcSJason Thorpe                      uint8_t devfn_min)
82080bb2ff7SRichard Henderson {
82180bb2ff7SRichard Henderson     MemoryRegion *addr_space = get_system_memory();
82280bb2ff7SRichard Henderson     DeviceState *dev;
82380bb2ff7SRichard Henderson     TyphoonState *s;
82494dd91d6SAndreas Färber     PCIHostState *phb;
82580bb2ff7SRichard Henderson     PCIBus *b;
826c781cf96SRichard Henderson     int i;
82780bb2ff7SRichard Henderson 
8283e80f690SMarkus Armbruster     dev = qdev_new(TYPE_TYPHOON_PCI_HOST_BRIDGE);
82980bb2ff7SRichard Henderson 
83094dd91d6SAndreas Färber     s = TYPHOON_PCI_HOST_BRIDGE(dev);
8318558d942SAndreas Färber     phb = PCI_HOST_BRIDGE(dev);
83280bb2ff7SRichard Henderson 
833b83c4db8SRichard Henderson     s->cchip.misc = 0x800000000ull; /* Revision: Typhoon.  */
834b83c4db8SRichard Henderson     s->pchip.win[3].wba = 2;        /* Window 3 SG always enabled. */
835b83c4db8SRichard Henderson 
83680bb2ff7SRichard Henderson     /* Remember the CPUs so that we can deliver interrupts to them.  */
837c781cf96SRichard Henderson     for (i = 0; i < 4; i++) {
838ad601177SAndreas Färber         AlphaCPU *cpu = cpus[i];
839ad601177SAndreas Färber         s->cchip.cpu[i] = cpu;
840ad601177SAndreas Färber         if (cpu != NULL) {
841bc72ad67SAlex Bligh             cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
842c781cf96SRichard Henderson                                                  typhoon_alarm_timer,
843c781cf96SRichard Henderson                                                  (void *)((uintptr_t)s + i));
844c781cf96SRichard Henderson         }
845c781cf96SRichard Henderson     }
84680bb2ff7SRichard Henderson 
84754292736SShannon Zhao     *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
84880bb2ff7SRichard Henderson 
84980bb2ff7SRichard Henderson     /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
85080bb2ff7SRichard Henderson        but the address space hole reserved at this point is 8TB.  */
851b844d822SIgor Mammedov     memory_region_add_subregion(addr_space, 0, ram);
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",
8592b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
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",
8652b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
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",
8712b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
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.  */
8762b41742aSPhilippe Mathieu-Daudé     memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4 * GiB);
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,
8822b41742aSPhilippe Mathieu-Daudé                           NULL, "pci0-io", 32 * MiB);
88302d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fc000000ULL,
88402d6516cSStefan Weil                                 &s->pchip.reg_io);
88580bb2ff7SRichard Henderson 
8861115ff6dSDavid Gibson     b = pci_register_root_bus(dev, "pci",
88780bb2ff7SRichard Henderson                               typhoon_set_irq, sys_map_irq, s,
888056e6baeSRichard Henderson                               &s->pchip.reg_mem, &s->pchip.reg_io,
889*3a8233dcSJason Thorpe                               devfn_min, 64, TYPE_PCI_BUS);
89094dd91d6SAndreas Färber     phb->bus = b;
8913c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
89280bb2ff7SRichard Henderson 
893b83c4db8SRichard Henderson     /* Host memory as seen from the PCI side, via the IOMMU.  */
8941221a474SAlexey Kardashevskiy     memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu),
8951221a474SAlexey Kardashevskiy                              TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s),
896b83c4db8SRichard Henderson                              "iommu-typhoon", UINT64_MAX);
8973df9d748SAlexey Kardashevskiy     address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
8983df9d748SAlexey Kardashevskiy                        "pchip0-pci");
899b83c4db8SRichard Henderson     pci_setup_iommu(b, typhoon_pci_dma_iommu, s);
900b83c4db8SRichard Henderson 
90180bb2ff7SRichard Henderson     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
902056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
9032b41742aSPhilippe Mathieu-Daudé                           b, "pci0-iack", 64 * MiB);
90402d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801f8000000ULL,
90502d6516cSStefan Weil                                 &s->pchip.reg_iack);
90680bb2ff7SRichard Henderson 
90780bb2ff7SRichard Henderson     /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
908056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
9092b41742aSPhilippe Mathieu-Daudé                           b, "pci0-conf", 16 * MiB);
91002d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fe000000ULL,
91102d6516cSStefan Weil                                 &s->pchip.reg_conf);
91280bb2ff7SRichard Henderson 
91380bb2ff7SRichard Henderson     /* For the record, these are the mappings for the second PCI bus.
91480bb2ff7SRichard Henderson        We can get away with not implementing them because we indicate
91580bb2ff7SRichard Henderson        via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
91680bb2ff7SRichard Henderson     /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
91780bb2ff7SRichard Henderson     /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
91880bb2ff7SRichard Henderson     /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
91980bb2ff7SRichard Henderson     /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
92080bb2ff7SRichard Henderson     /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
92180bb2ff7SRichard Henderson 
92280bb2ff7SRichard Henderson     /* Init the ISA bus.  */
92380bb2ff7SRichard Henderson     /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
92480bb2ff7SRichard Henderson     {
92554292736SShannon Zhao         qemu_irq *isa_irqs;
92680bb2ff7SRichard Henderson 
927d10e5432SMarkus Armbruster         *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io,
928d10e5432SMarkus Armbruster                                &error_abort);
92954292736SShannon Zhao         isa_irqs = i8259_init(*isa_bus,
93054292736SShannon Zhao                               qemu_allocate_irq(typhoon_set_isa_irq, s, 0));
93171baa303SHervé Poussineau         isa_bus_irqs(*isa_bus, isa_irqs);
93280bb2ff7SRichard Henderson     }
93380bb2ff7SRichard Henderson 
93480bb2ff7SRichard Henderson     return b;
93580bb2ff7SRichard Henderson }
93680bb2ff7SRichard Henderson 
9374240abffSAndreas Färber static const TypeInfo typhoon_pcihost_info = {
93894dd91d6SAndreas Färber     .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
9398558d942SAndreas Färber     .parent        = TYPE_PCI_HOST_BRIDGE,
94039bffca2SAnthony Liguori     .instance_size = sizeof(TyphoonState),
94180bb2ff7SRichard Henderson };
94280bb2ff7SRichard Henderson 
9431221a474SAlexey Kardashevskiy static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
9441221a474SAlexey Kardashevskiy                                                    void *data)
9451221a474SAlexey Kardashevskiy {
9461221a474SAlexey Kardashevskiy     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
9471221a474SAlexey Kardashevskiy 
9481221a474SAlexey Kardashevskiy     imrc->translate = typhoon_translate_iommu;
9491221a474SAlexey Kardashevskiy }
9501221a474SAlexey Kardashevskiy 
9511221a474SAlexey Kardashevskiy static const TypeInfo typhoon_iommu_memory_region_info = {
9521221a474SAlexey Kardashevskiy     .parent = TYPE_IOMMU_MEMORY_REGION,
9531221a474SAlexey Kardashevskiy     .name = TYPE_TYPHOON_IOMMU_MEMORY_REGION,
9541221a474SAlexey Kardashevskiy     .class_init = typhoon_iommu_memory_region_class_init,
9551221a474SAlexey Kardashevskiy };
9561221a474SAlexey Kardashevskiy 
95783f7d43aSAndreas Färber static void typhoon_register_types(void)
95880bb2ff7SRichard Henderson {
95939bffca2SAnthony Liguori     type_register_static(&typhoon_pcihost_info);
9601221a474SAlexey Kardashevskiy     type_register_static(&typhoon_iommu_memory_region_info);
96180bb2ff7SRichard Henderson }
96283f7d43aSAndreas Färber 
96383f7d43aSAndreas Färber type_init(typhoon_register_types)
964