180bb2ff7SRichard Henderson /* 280bb2ff7SRichard Henderson * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation. 380bb2ff7SRichard Henderson * 480bb2ff7SRichard Henderson * Written by Richard Henderson. 580bb2ff7SRichard Henderson * 680bb2ff7SRichard Henderson * This work is licensed under the GNU GPL license version 2 or later. 780bb2ff7SRichard Henderson */ 880bb2ff7SRichard Henderson 9e2e5e114SPeter Maydell #include "qemu/osdep.h" 10da34e65cSMarkus Armbruster #include "qapi/error.h" 1180bb2ff7SRichard Henderson #include "cpu.h" 1283c9f4caSPaolo Bonzini #include "hw/hw.h" 13bd2be150SPeter Maydell #include "hw/devices.h" 149c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 1547b43a1fSPaolo Bonzini #include "alpha_sys.h" 16022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 1780bb2ff7SRichard Henderson 1880bb2ff7SRichard Henderson 1994dd91d6SAndreas Färber #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost" 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 5194dd91d6SAndreas Färber #define TYPHOON_PCI_HOST_BRIDGE(obj) \ 5294dd91d6SAndreas Färber OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE) 5394dd91d6SAndreas Färber 5480bb2ff7SRichard Henderson typedef struct TyphoonState { 5567c332fdSAndreas Färber PCIHostState parent_obj; 5694dd91d6SAndreas Färber 5780bb2ff7SRichard Henderson TyphoonCchip cchip; 5880bb2ff7SRichard Henderson TyphoonPchip pchip; 5980bb2ff7SRichard Henderson MemoryRegion dchip_region; 6080bb2ff7SRichard Henderson MemoryRegion ram_region; 6180bb2ff7SRichard Henderson } TyphoonState; 6280bb2ff7SRichard Henderson 6380bb2ff7SRichard Henderson /* Called when one of DRIR or DIM changes. */ 64ad601177SAndreas Färber static void cpu_irq_change(AlphaCPU *cpu, uint64_t req) 6580bb2ff7SRichard Henderson { 6680bb2ff7SRichard Henderson /* If there are any non-masked interrupts, tell the cpu. */ 67ad601177SAndreas Färber if (cpu != NULL) { 68d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 6980bb2ff7SRichard Henderson if (req) { 70c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 7180bb2ff7SRichard Henderson } else { 72d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 7380bb2ff7SRichard Henderson } 7480bb2ff7SRichard Henderson } 7580bb2ff7SRichard Henderson } 7680bb2ff7SRichard Henderson 77a8170e5eSAvi Kivity static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) 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: 198c658b94fSAndreas Färber cpu_unassigned_access(cpu, addr, false, false, 0, size); 19980bb2ff7SRichard Henderson return -1; 20080bb2ff7SRichard Henderson } 20180bb2ff7SRichard Henderson 20280bb2ff7SRichard Henderson return ret; 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 211a8170e5eSAvi Kivity static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size) 21280bb2ff7SRichard Henderson { 21380bb2ff7SRichard Henderson TyphoonState *s = opaque; 21480bb2ff7SRichard Henderson uint64_t ret = 0; 21580bb2ff7SRichard Henderson 21680bb2ff7SRichard Henderson switch (addr) { 21780bb2ff7SRichard Henderson case 0x0000: 21880bb2ff7SRichard Henderson /* WSBA0: Window Space Base Address Register. */ 219b83c4db8SRichard Henderson ret = s->pchip.win[0].wba; 22080bb2ff7SRichard Henderson break; 22180bb2ff7SRichard Henderson case 0x0040: 22280bb2ff7SRichard Henderson /* WSBA1 */ 223b83c4db8SRichard Henderson ret = s->pchip.win[1].wba; 22480bb2ff7SRichard Henderson break; 22580bb2ff7SRichard Henderson case 0x0080: 22680bb2ff7SRichard Henderson /* WSBA2 */ 227b83c4db8SRichard Henderson ret = s->pchip.win[2].wba; 22880bb2ff7SRichard Henderson break; 22980bb2ff7SRichard Henderson case 0x00c0: 23080bb2ff7SRichard Henderson /* WSBA3 */ 231b83c4db8SRichard Henderson ret = s->pchip.win[3].wba; 23280bb2ff7SRichard Henderson break; 23380bb2ff7SRichard Henderson 23480bb2ff7SRichard Henderson case 0x0100: 23580bb2ff7SRichard Henderson /* WSM0: Window Space Mask Register. */ 236b83c4db8SRichard Henderson ret = s->pchip.win[0].wsm; 23780bb2ff7SRichard Henderson break; 23880bb2ff7SRichard Henderson case 0x0140: 23980bb2ff7SRichard Henderson /* WSM1 */ 240b83c4db8SRichard Henderson ret = s->pchip.win[1].wsm; 24180bb2ff7SRichard Henderson break; 24280bb2ff7SRichard Henderson case 0x0180: 24380bb2ff7SRichard Henderson /* WSM2 */ 244b83c4db8SRichard Henderson ret = s->pchip.win[2].wsm; 24580bb2ff7SRichard Henderson break; 24680bb2ff7SRichard Henderson case 0x01c0: 24780bb2ff7SRichard Henderson /* WSM3 */ 248b83c4db8SRichard Henderson ret = s->pchip.win[3].wsm; 24980bb2ff7SRichard Henderson break; 25080bb2ff7SRichard Henderson 25180bb2ff7SRichard Henderson case 0x0200: 25280bb2ff7SRichard Henderson /* TBA0: Translated Base Address Register. */ 253b83c4db8SRichard Henderson ret = s->pchip.win[0].tba; 25480bb2ff7SRichard Henderson break; 25580bb2ff7SRichard Henderson case 0x0240: 25680bb2ff7SRichard Henderson /* TBA1 */ 257b83c4db8SRichard Henderson ret = s->pchip.win[1].tba; 25880bb2ff7SRichard Henderson break; 25980bb2ff7SRichard Henderson case 0x0280: 26080bb2ff7SRichard Henderson /* TBA2 */ 261b83c4db8SRichard Henderson ret = s->pchip.win[2].tba; 26280bb2ff7SRichard Henderson break; 26380bb2ff7SRichard Henderson case 0x02c0: 26480bb2ff7SRichard Henderson /* TBA3 */ 265b83c4db8SRichard Henderson ret = s->pchip.win[3].tba; 26680bb2ff7SRichard Henderson break; 26780bb2ff7SRichard Henderson 26880bb2ff7SRichard Henderson case 0x0300: 26980bb2ff7SRichard Henderson /* PCTL: Pchip Control Register. */ 27080bb2ff7SRichard Henderson ret = s->pchip.ctl; 27180bb2ff7SRichard Henderson break; 27280bb2ff7SRichard Henderson case 0x0340: 27380bb2ff7SRichard Henderson /* PLAT: Pchip Master Latency Register. */ 27480bb2ff7SRichard Henderson break; 27580bb2ff7SRichard Henderson case 0x03c0: 27680bb2ff7SRichard Henderson /* PERROR: Pchip Error Register. */ 27780bb2ff7SRichard Henderson break; 27880bb2ff7SRichard Henderson case 0x0400: 27980bb2ff7SRichard Henderson /* PERRMASK: Pchip Error Mask Register. */ 28080bb2ff7SRichard Henderson break; 28180bb2ff7SRichard Henderson case 0x0440: 28280bb2ff7SRichard Henderson /* PERRSET: Pchip Error Set Register. */ 28380bb2ff7SRichard Henderson break; 28480bb2ff7SRichard Henderson case 0x0480: 28580bb2ff7SRichard Henderson /* TLBIV: Translation Buffer Invalidate Virtual Register (WO). */ 28680bb2ff7SRichard Henderson break; 28780bb2ff7SRichard Henderson case 0x04c0: 28880bb2ff7SRichard Henderson /* TLBIA: Translation Buffer Invalidate All Register (WO). */ 28980bb2ff7SRichard Henderson break; 29080bb2ff7SRichard Henderson case 0x0500: /* PMONCTL */ 29180bb2ff7SRichard Henderson case 0x0540: /* PMONCNT */ 29280bb2ff7SRichard Henderson case 0x0800: /* SPRST */ 29380bb2ff7SRichard Henderson break; 29480bb2ff7SRichard Henderson 29580bb2ff7SRichard Henderson default: 2964917cf44SAndreas Färber cpu_unassigned_access(current_cpu, addr, false, false, 0, size); 29780bb2ff7SRichard Henderson return -1; 29880bb2ff7SRichard Henderson } 29980bb2ff7SRichard Henderson 30080bb2ff7SRichard Henderson return ret; 30180bb2ff7SRichard Henderson } 30280bb2ff7SRichard Henderson 303a8170e5eSAvi Kivity static void cchip_write(void *opaque, hwaddr addr, 30467842165SRichard Henderson uint64_t val, unsigned size) 30580bb2ff7SRichard Henderson { 30680bb2ff7SRichard Henderson TyphoonState *s = opaque; 30767842165SRichard Henderson uint64_t oldval, newval; 30880bb2ff7SRichard Henderson 30980bb2ff7SRichard Henderson switch (addr) { 31080bb2ff7SRichard Henderson case 0x0000: 31180bb2ff7SRichard Henderson /* CSC: Cchip System Configuration Register. */ 31280bb2ff7SRichard Henderson /* All sorts of data here; nothing relevant RW. */ 31380bb2ff7SRichard Henderson break; 31480bb2ff7SRichard Henderson 31580bb2ff7SRichard Henderson case 0x0040: 31680bb2ff7SRichard Henderson /* MTR: Memory Timing Register. */ 31780bb2ff7SRichard Henderson /* All sorts of stuff related to real DRAM. */ 31880bb2ff7SRichard Henderson break; 31980bb2ff7SRichard Henderson 32080bb2ff7SRichard Henderson case 0x0080: 32180bb2ff7SRichard Henderson /* MISC: Miscellaneous Register. */ 32280bb2ff7SRichard Henderson newval = oldval = s->cchip.misc; 32380bb2ff7SRichard Henderson newval &= ~(val & 0x10000ff0); /* W1C fields */ 32480bb2ff7SRichard Henderson if (val & 0x100000) { 32580bb2ff7SRichard Henderson newval &= ~0xff0000ull; /* ACL clears ABT and ABW */ 32680bb2ff7SRichard Henderson } else { 32780bb2ff7SRichard Henderson newval |= val & 0x00f00000; /* ABT field is W1S */ 32880bb2ff7SRichard Henderson if ((newval & 0xf0000) == 0) { 32980bb2ff7SRichard Henderson newval |= val & 0xf0000; /* ABW field is W1S iff zero */ 33080bb2ff7SRichard Henderson } 33180bb2ff7SRichard Henderson } 33280bb2ff7SRichard Henderson newval |= (val & 0xf000) >> 4; /* IPREQ field sets IPINTR. */ 33380bb2ff7SRichard Henderson 33480bb2ff7SRichard Henderson newval &= ~0xf0000000000ull; /* WO and RW fields */ 33580bb2ff7SRichard Henderson newval |= val & 0xf0000000000ull; 33680bb2ff7SRichard Henderson s->cchip.misc = newval; 33780bb2ff7SRichard Henderson 33880bb2ff7SRichard Henderson /* Pass on changes to IPI and ITI state. */ 33980bb2ff7SRichard Henderson if ((newval ^ oldval) & 0xff0) { 34080bb2ff7SRichard Henderson int i; 34180bb2ff7SRichard Henderson for (i = 0; i < 4; ++i) { 342ad601177SAndreas Färber AlphaCPU *cpu = s->cchip.cpu[i]; 343ad601177SAndreas Färber if (cpu != NULL) { 344d8ed887bSAndreas Färber CPUState *cs = CPU(cpu); 34580bb2ff7SRichard Henderson /* IPI can be either cleared or set by the write. */ 34680bb2ff7SRichard Henderson if (newval & (1 << (i + 8))) { 347c3affe56SAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_SMP); 34880bb2ff7SRichard Henderson } else { 349d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP); 35080bb2ff7SRichard Henderson } 35180bb2ff7SRichard Henderson 35280bb2ff7SRichard Henderson /* ITI can only be cleared by the write. */ 35380bb2ff7SRichard Henderson if ((newval & (1 << (i + 4))) == 0) { 354d8ed887bSAndreas Färber cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER); 35580bb2ff7SRichard Henderson } 35680bb2ff7SRichard Henderson } 35780bb2ff7SRichard Henderson } 35880bb2ff7SRichard Henderson } 35980bb2ff7SRichard Henderson break; 36080bb2ff7SRichard Henderson 36180bb2ff7SRichard Henderson case 0x00c0: 36280bb2ff7SRichard Henderson /* MPD: Memory Presence Detect Register. */ 36380bb2ff7SRichard Henderson break; 36480bb2ff7SRichard Henderson 36580bb2ff7SRichard Henderson case 0x0100: /* AAR0 */ 36680bb2ff7SRichard Henderson case 0x0140: /* AAR1 */ 36780bb2ff7SRichard Henderson case 0x0180: /* AAR2 */ 36880bb2ff7SRichard Henderson case 0x01c0: /* AAR3 */ 36980bb2ff7SRichard Henderson /* AAR: Array Address Register. */ 37080bb2ff7SRichard Henderson /* All sorts of information about DRAM. */ 37180bb2ff7SRichard Henderson break; 37280bb2ff7SRichard Henderson 37380bb2ff7SRichard Henderson case 0x0200: /* DIM0 */ 37480bb2ff7SRichard Henderson /* DIM: Device Interrupt Mask Register, CPU0. */ 37580bb2ff7SRichard Henderson s->cchip.dim[0] = val; 37680bb2ff7SRichard Henderson cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir); 37780bb2ff7SRichard Henderson break; 37880bb2ff7SRichard Henderson case 0x0240: /* DIM1 */ 37980bb2ff7SRichard Henderson /* DIM: Device Interrupt Mask Register, CPU1. */ 380424ad838SRichard Henderson s->cchip.dim[1] = val; 38180bb2ff7SRichard Henderson cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir); 38280bb2ff7SRichard Henderson break; 38380bb2ff7SRichard Henderson 38480bb2ff7SRichard Henderson case 0x0280: /* DIR0 (RO) */ 38580bb2ff7SRichard Henderson case 0x02c0: /* DIR1 (RO) */ 38680bb2ff7SRichard Henderson case 0x0300: /* DRIR (RO) */ 38780bb2ff7SRichard Henderson break; 38880bb2ff7SRichard Henderson 38980bb2ff7SRichard Henderson case 0x0340: 39080bb2ff7SRichard Henderson /* PRBEN: Probe Enable Register. */ 39180bb2ff7SRichard Henderson break; 39280bb2ff7SRichard Henderson 39380bb2ff7SRichard Henderson case 0x0380: /* IIC0 */ 39480bb2ff7SRichard Henderson s->cchip.iic[0] = val & 0xffffff; 39580bb2ff7SRichard Henderson break; 39680bb2ff7SRichard Henderson case 0x03c0: /* IIC1 */ 39780bb2ff7SRichard Henderson s->cchip.iic[1] = val & 0xffffff; 39880bb2ff7SRichard Henderson break; 39980bb2ff7SRichard Henderson 40080bb2ff7SRichard Henderson case 0x0400: /* MPR0 */ 40180bb2ff7SRichard Henderson case 0x0440: /* MPR1 */ 40280bb2ff7SRichard Henderson case 0x0480: /* MPR2 */ 40380bb2ff7SRichard Henderson case 0x04c0: /* MPR3 */ 40480bb2ff7SRichard Henderson /* MPR: Memory Programming Register. */ 40580bb2ff7SRichard Henderson break; 40680bb2ff7SRichard Henderson 40780bb2ff7SRichard Henderson case 0x0580: 40880bb2ff7SRichard Henderson /* TTR: TIGbus Timing Register. */ 40980bb2ff7SRichard Henderson /* All sorts of stuff related to interrupt delivery timings. */ 41080bb2ff7SRichard Henderson break; 41180bb2ff7SRichard Henderson case 0x05c0: 41280bb2ff7SRichard Henderson /* TDR: TIGbug Device Timing Register. */ 41380bb2ff7SRichard Henderson break; 41480bb2ff7SRichard Henderson 41580bb2ff7SRichard Henderson case 0x0600: 41680bb2ff7SRichard Henderson /* DIM2: Device Interrupt Mask Register, CPU2. */ 41780bb2ff7SRichard Henderson s->cchip.dim[2] = val; 41880bb2ff7SRichard Henderson cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir); 41980bb2ff7SRichard Henderson break; 42080bb2ff7SRichard Henderson case 0x0640: 42180bb2ff7SRichard Henderson /* DIM3: Device Interrupt Mask Register, CPU3. */ 42280bb2ff7SRichard Henderson s->cchip.dim[3] = val; 42380bb2ff7SRichard Henderson cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir); 42480bb2ff7SRichard Henderson break; 42580bb2ff7SRichard Henderson 42680bb2ff7SRichard Henderson case 0x0680: /* DIR2 (RO) */ 42780bb2ff7SRichard Henderson case 0x06c0: /* DIR3 (RO) */ 42880bb2ff7SRichard Henderson break; 42980bb2ff7SRichard Henderson 43080bb2ff7SRichard Henderson case 0x0700: /* IIC2 */ 43180bb2ff7SRichard Henderson s->cchip.iic[2] = val & 0xffffff; 43280bb2ff7SRichard Henderson break; 43380bb2ff7SRichard Henderson case 0x0740: /* IIC3 */ 43480bb2ff7SRichard Henderson s->cchip.iic[3] = val & 0xffffff; 43580bb2ff7SRichard Henderson break; 43680bb2ff7SRichard Henderson 43780bb2ff7SRichard Henderson case 0x0780: 43880bb2ff7SRichard Henderson /* PWR: Power Management Control. */ 43980bb2ff7SRichard Henderson break; 44080bb2ff7SRichard Henderson 44180bb2ff7SRichard Henderson case 0x0c00: /* CMONCTLA */ 44280bb2ff7SRichard Henderson case 0x0c40: /* CMONCTLB */ 44380bb2ff7SRichard Henderson case 0x0c80: /* CMONCNT01 */ 44480bb2ff7SRichard Henderson case 0x0cc0: /* CMONCNT23 */ 44580bb2ff7SRichard Henderson break; 44680bb2ff7SRichard Henderson 44780bb2ff7SRichard Henderson default: 4484917cf44SAndreas Färber cpu_unassigned_access(current_cpu, addr, true, false, 0, size); 44980bb2ff7SRichard Henderson return; 45080bb2ff7SRichard Henderson } 45180bb2ff7SRichard Henderson } 45280bb2ff7SRichard Henderson 453a8170e5eSAvi Kivity static void dchip_write(void *opaque, hwaddr addr, 45480bb2ff7SRichard Henderson uint64_t val, unsigned size) 45580bb2ff7SRichard Henderson { 45680bb2ff7SRichard Henderson /* Skip this. It's all related to DRAM timing and setup. */ 45780bb2ff7SRichard Henderson } 45880bb2ff7SRichard Henderson 459a8170e5eSAvi Kivity static void pchip_write(void *opaque, hwaddr addr, 46067842165SRichard Henderson uint64_t val, unsigned size) 46180bb2ff7SRichard Henderson { 46280bb2ff7SRichard Henderson TyphoonState *s = opaque; 46367842165SRichard Henderson uint64_t oldval; 46480bb2ff7SRichard Henderson 46580bb2ff7SRichard Henderson switch (addr) { 46680bb2ff7SRichard Henderson case 0x0000: 46780bb2ff7SRichard Henderson /* WSBA0: Window Space Base Address Register. */ 468b83c4db8SRichard Henderson s->pchip.win[0].wba = val & 0xfff00003u; 46980bb2ff7SRichard Henderson break; 47080bb2ff7SRichard Henderson case 0x0040: 47180bb2ff7SRichard Henderson /* WSBA1 */ 472b83c4db8SRichard Henderson s->pchip.win[1].wba = val & 0xfff00003u; 47380bb2ff7SRichard Henderson break; 47480bb2ff7SRichard Henderson case 0x0080: 47580bb2ff7SRichard Henderson /* WSBA2 */ 476b83c4db8SRichard Henderson s->pchip.win[2].wba = val & 0xfff00003u; 47780bb2ff7SRichard Henderson break; 47880bb2ff7SRichard Henderson case 0x00c0: 47980bb2ff7SRichard Henderson /* WSBA3 */ 480b83c4db8SRichard Henderson s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2; 48180bb2ff7SRichard Henderson break; 48280bb2ff7SRichard Henderson 48380bb2ff7SRichard Henderson case 0x0100: 48480bb2ff7SRichard Henderson /* WSM0: Window Space Mask Register. */ 485b83c4db8SRichard Henderson s->pchip.win[0].wsm = val & 0xfff00000u; 48680bb2ff7SRichard Henderson break; 48780bb2ff7SRichard Henderson case 0x0140: 48880bb2ff7SRichard Henderson /* WSM1 */ 489b83c4db8SRichard Henderson s->pchip.win[1].wsm = val & 0xfff00000u; 49080bb2ff7SRichard Henderson break; 49180bb2ff7SRichard Henderson case 0x0180: 49280bb2ff7SRichard Henderson /* WSM2 */ 493b83c4db8SRichard Henderson s->pchip.win[2].wsm = val & 0xfff00000u; 49480bb2ff7SRichard Henderson break; 49580bb2ff7SRichard Henderson case 0x01c0: 49680bb2ff7SRichard Henderson /* WSM3 */ 497b83c4db8SRichard Henderson s->pchip.win[3].wsm = val & 0xfff00000u; 49880bb2ff7SRichard Henderson break; 49980bb2ff7SRichard Henderson 50080bb2ff7SRichard Henderson case 0x0200: 50180bb2ff7SRichard Henderson /* TBA0: Translated Base Address Register. */ 502b83c4db8SRichard Henderson s->pchip.win[0].tba = val & 0x7fffffc00ull; 50380bb2ff7SRichard Henderson break; 50480bb2ff7SRichard Henderson case 0x0240: 50580bb2ff7SRichard Henderson /* TBA1 */ 506b83c4db8SRichard Henderson s->pchip.win[1].tba = val & 0x7fffffc00ull; 50780bb2ff7SRichard Henderson break; 50880bb2ff7SRichard Henderson case 0x0280: 50980bb2ff7SRichard Henderson /* TBA2 */ 510b83c4db8SRichard Henderson s->pchip.win[2].tba = val & 0x7fffffc00ull; 51180bb2ff7SRichard Henderson break; 51280bb2ff7SRichard Henderson case 0x02c0: 51380bb2ff7SRichard Henderson /* TBA3 */ 514b83c4db8SRichard Henderson s->pchip.win[3].tba = val & 0x7fffffc00ull; 51580bb2ff7SRichard Henderson break; 51680bb2ff7SRichard Henderson 51780bb2ff7SRichard Henderson case 0x0300: 51880bb2ff7SRichard Henderson /* PCTL: Pchip Control Register. */ 51980bb2ff7SRichard Henderson oldval = s->pchip.ctl; 52080bb2ff7SRichard Henderson oldval &= ~0x00001cff0fc7ffull; /* RW fields */ 52180bb2ff7SRichard Henderson oldval |= val & 0x00001cff0fc7ffull; 52280bb2ff7SRichard Henderson s->pchip.ctl = oldval; 52380bb2ff7SRichard Henderson break; 52480bb2ff7SRichard Henderson 52580bb2ff7SRichard Henderson case 0x0340: 52680bb2ff7SRichard Henderson /* PLAT: Pchip Master Latency Register. */ 52780bb2ff7SRichard Henderson break; 52880bb2ff7SRichard Henderson case 0x03c0: 52980bb2ff7SRichard Henderson /* PERROR: Pchip Error Register. */ 53080bb2ff7SRichard Henderson break; 53180bb2ff7SRichard Henderson case 0x0400: 53280bb2ff7SRichard Henderson /* PERRMASK: Pchip Error Mask Register. */ 53380bb2ff7SRichard Henderson break; 53480bb2ff7SRichard Henderson case 0x0440: 53580bb2ff7SRichard Henderson /* PERRSET: Pchip Error Set Register. */ 53680bb2ff7SRichard Henderson break; 53780bb2ff7SRichard Henderson 53880bb2ff7SRichard Henderson case 0x0480: 53980bb2ff7SRichard Henderson /* TLBIV: Translation Buffer Invalidate Virtual Register. */ 54080bb2ff7SRichard Henderson break; 54180bb2ff7SRichard Henderson 54280bb2ff7SRichard Henderson case 0x04c0: 54380bb2ff7SRichard Henderson /* TLBIA: Translation Buffer Invalidate All Register (WO). */ 54480bb2ff7SRichard Henderson break; 54580bb2ff7SRichard Henderson 54680bb2ff7SRichard Henderson case 0x0500: 54780bb2ff7SRichard Henderson /* PMONCTL */ 54880bb2ff7SRichard Henderson case 0x0540: 54980bb2ff7SRichard Henderson /* PMONCNT */ 55080bb2ff7SRichard Henderson case 0x0800: 55180bb2ff7SRichard Henderson /* SPRST */ 55280bb2ff7SRichard Henderson break; 55380bb2ff7SRichard Henderson 55480bb2ff7SRichard Henderson default: 5554917cf44SAndreas Färber cpu_unassigned_access(current_cpu, addr, true, false, 0, size); 55680bb2ff7SRichard Henderson return; 55780bb2ff7SRichard Henderson } 55880bb2ff7SRichard Henderson } 55980bb2ff7SRichard Henderson 56080bb2ff7SRichard Henderson static const MemoryRegionOps cchip_ops = { 56180bb2ff7SRichard Henderson .read = cchip_read, 56280bb2ff7SRichard Henderson .write = cchip_write, 56380bb2ff7SRichard Henderson .endianness = DEVICE_LITTLE_ENDIAN, 56480bb2ff7SRichard Henderson .valid = { 56567842165SRichard Henderson .min_access_size = 8, 56680bb2ff7SRichard Henderson .max_access_size = 8, 56780bb2ff7SRichard Henderson }, 56880bb2ff7SRichard Henderson .impl = { 56967842165SRichard Henderson .min_access_size = 8, 57067842165SRichard Henderson .max_access_size = 8, 57180bb2ff7SRichard Henderson }, 57280bb2ff7SRichard Henderson }; 57380bb2ff7SRichard Henderson 57480bb2ff7SRichard Henderson static const MemoryRegionOps dchip_ops = { 57580bb2ff7SRichard Henderson .read = dchip_read, 57680bb2ff7SRichard Henderson .write = dchip_write, 57780bb2ff7SRichard Henderson .endianness = DEVICE_LITTLE_ENDIAN, 57880bb2ff7SRichard Henderson .valid = { 57967842165SRichard Henderson .min_access_size = 8, 58080bb2ff7SRichard Henderson .max_access_size = 8, 58180bb2ff7SRichard Henderson }, 58280bb2ff7SRichard Henderson .impl = { 58367842165SRichard Henderson .min_access_size = 8, 58480bb2ff7SRichard Henderson .max_access_size = 8, 58580bb2ff7SRichard Henderson }, 58680bb2ff7SRichard Henderson }; 58780bb2ff7SRichard Henderson 58880bb2ff7SRichard Henderson static const MemoryRegionOps pchip_ops = { 58980bb2ff7SRichard Henderson .read = pchip_read, 59080bb2ff7SRichard Henderson .write = pchip_write, 59180bb2ff7SRichard Henderson .endianness = DEVICE_LITTLE_ENDIAN, 59280bb2ff7SRichard Henderson .valid = { 59367842165SRichard Henderson .min_access_size = 8, 59480bb2ff7SRichard Henderson .max_access_size = 8, 59580bb2ff7SRichard Henderson }, 59680bb2ff7SRichard Henderson .impl = { 59767842165SRichard Henderson .min_access_size = 8, 59867842165SRichard Henderson .max_access_size = 8, 59980bb2ff7SRichard Henderson }, 60080bb2ff7SRichard Henderson }; 60180bb2ff7SRichard Henderson 602b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry 603b83c4db8SRichard Henderson using the given translated address and mask. */ 604b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret) 605b83c4db8SRichard Henderson { 606b83c4db8SRichard Henderson *ret = (IOMMUTLBEntry) { 607b83c4db8SRichard Henderson .target_as = &address_space_memory, 608b83c4db8SRichard Henderson .translated_addr = taddr, 609b83c4db8SRichard Henderson .addr_mask = mask, 610b83c4db8SRichard Henderson .perm = IOMMU_RW, 611b83c4db8SRichard Henderson }; 612b83c4db8SRichard Henderson return true; 613b83c4db8SRichard Henderson } 614b83c4db8SRichard Henderson 615b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather 616b83c4db8SRichard Henderson translation, given the address of the PTE. */ 617b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret) 618b83c4db8SRichard Henderson { 61942874d3aSPeter Maydell uint64_t pte = address_space_ldq(&address_space_memory, pte_addr, 62042874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, NULL); 621b83c4db8SRichard Henderson 622b83c4db8SRichard Henderson /* Check valid bit. */ 623b83c4db8SRichard Henderson if ((pte & 1) == 0) { 624b83c4db8SRichard Henderson return false; 625b83c4db8SRichard Henderson } 626b83c4db8SRichard Henderson 627b83c4db8SRichard Henderson return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret); 628b83c4db8SRichard Henderson } 629b83c4db8SRichard Henderson 630b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the 631b83c4db8SRichard Henderson four single-address-cycle translation windows. */ 632b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr, 633b83c4db8SRichard Henderson IOMMUTLBEntry *ret) 634b83c4db8SRichard Henderson { 635b83c4db8SRichard Henderson uint32_t wba = win->wba; 636b83c4db8SRichard Henderson uint64_t wsm = win->wsm; 637b83c4db8SRichard Henderson uint64_t tba = win->tba; 638b83c4db8SRichard Henderson uint64_t wsm_ext = wsm | 0xfffff; 639b83c4db8SRichard Henderson 640b83c4db8SRichard Henderson /* Check for window disabled. */ 641b83c4db8SRichard Henderson if ((wba & 1) == 0) { 642b83c4db8SRichard Henderson return false; 643b83c4db8SRichard Henderson } 644b83c4db8SRichard Henderson 645b83c4db8SRichard Henderson /* Check for window hit. */ 646b83c4db8SRichard Henderson if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) { 647b83c4db8SRichard Henderson return false; 648b83c4db8SRichard Henderson } 649b83c4db8SRichard Henderson 650b83c4db8SRichard Henderson if (wba & 2) { 651b83c4db8SRichard Henderson /* Scatter-gather translation. */ 652b83c4db8SRichard Henderson hwaddr pte_addr; 653b83c4db8SRichard Henderson 654b83c4db8SRichard Henderson /* See table 10-6, Generating PTE address for PCI DMA Address. */ 655b83c4db8SRichard Henderson pte_addr = tba & ~(wsm >> 10); 656b83c4db8SRichard Henderson pte_addr |= (addr & (wsm | 0xfe000)) >> 10; 657b83c4db8SRichard Henderson return pte_translate(pte_addr, ret); 658b83c4db8SRichard Henderson } else { 659b83c4db8SRichard Henderson /* Direct-mapped translation. */ 660b83c4db8SRichard Henderson return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret); 661b83c4db8SRichard Henderson } 662b83c4db8SRichard Henderson } 663b83c4db8SRichard Henderson 664b83c4db8SRichard Henderson /* Handle PCI-to-system address translation. */ 665b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the 666b83c4db8SRichard Henderson Pchip and generate a machine check interrupt. */ 6673df9d748SAlexey Kardashevskiy static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu, 6683df9d748SAlexey Kardashevskiy hwaddr addr, 669*2c91bcf2SPeter Maydell IOMMUAccessFlags flag, 670*2c91bcf2SPeter Maydell int iommu_idx) 671b83c4db8SRichard Henderson { 672b83c4db8SRichard Henderson TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu); 673b83c4db8SRichard Henderson IOMMUTLBEntry ret; 674b83c4db8SRichard Henderson int i; 675b83c4db8SRichard Henderson 676b83c4db8SRichard Henderson if (addr <= 0xffffffffu) { 677b83c4db8SRichard Henderson /* Single-address cycle. */ 678b83c4db8SRichard Henderson 679b83c4db8SRichard Henderson /* Check for the Window Hole, inhibiting matching. */ 680b83c4db8SRichard Henderson if ((pchip->ctl & 0x20) 681b83c4db8SRichard Henderson && addr >= 0x80000 682b83c4db8SRichard Henderson && addr <= 0xfffff) { 683b83c4db8SRichard Henderson goto failure; 684b83c4db8SRichard Henderson } 685b83c4db8SRichard Henderson 686b83c4db8SRichard Henderson /* Check the first three windows. */ 687b83c4db8SRichard Henderson for (i = 0; i < 3; ++i) { 688b83c4db8SRichard Henderson if (window_translate(&pchip->win[i], addr, &ret)) { 689b83c4db8SRichard Henderson goto success; 690b83c4db8SRichard Henderson } 691b83c4db8SRichard Henderson } 692b83c4db8SRichard Henderson 693b83c4db8SRichard Henderson /* Check the fourth window for DAC disable. */ 694b83c4db8SRichard Henderson if ((pchip->win[3].wba & 0x80000000000ull) == 0 695b83c4db8SRichard Henderson && window_translate(&pchip->win[3], addr, &ret)) { 696b83c4db8SRichard Henderson goto success; 697b83c4db8SRichard Henderson } 698b83c4db8SRichard Henderson } else { 699b83c4db8SRichard Henderson /* Double-address cycle. */ 700b83c4db8SRichard Henderson 701b83c4db8SRichard Henderson if (addr >= 0x10000000000ull && addr < 0x20000000000ull) { 702b83c4db8SRichard Henderson /* Check for the DMA monster window. */ 703b83c4db8SRichard Henderson if (pchip->ctl & 0x40) { 704b83c4db8SRichard Henderson /* See 10.1.4.4; in particular <39:35> is ignored. */ 705b83c4db8SRichard Henderson make_iommu_tlbe(0, 0x007ffffffffull, &ret); 706b83c4db8SRichard Henderson goto success; 707b83c4db8SRichard Henderson } 708b83c4db8SRichard Henderson } 709b83c4db8SRichard Henderson 7109b2caaf4SStefan Weil if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) { 711b83c4db8SRichard Henderson /* Check the fourth window for DAC enable and window enable. */ 712b83c4db8SRichard Henderson if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) { 713b83c4db8SRichard Henderson uint64_t pte_addr; 714b83c4db8SRichard Henderson 715b83c4db8SRichard Henderson pte_addr = pchip->win[3].tba & 0x7ffc00000ull; 716b83c4db8SRichard Henderson pte_addr |= (addr & 0xffffe000u) >> 10; 717b83c4db8SRichard Henderson if (pte_translate(pte_addr, &ret)) { 718b83c4db8SRichard Henderson goto success; 719b83c4db8SRichard Henderson } 720b83c4db8SRichard Henderson } 721b83c4db8SRichard Henderson } 722b83c4db8SRichard Henderson } 723b83c4db8SRichard Henderson 724b83c4db8SRichard Henderson failure: 725b83c4db8SRichard Henderson ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE }; 726b83c4db8SRichard Henderson success: 727b83c4db8SRichard Henderson return ret; 728b83c4db8SRichard Henderson } 729b83c4db8SRichard Henderson 730b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) 731b83c4db8SRichard Henderson { 732b83c4db8SRichard Henderson TyphoonState *s = opaque; 733b83c4db8SRichard Henderson return &s->pchip.iommu_as; 734b83c4db8SRichard Henderson } 735b83c4db8SRichard Henderson 73680bb2ff7SRichard Henderson static void typhoon_set_irq(void *opaque, int irq, int level) 73780bb2ff7SRichard Henderson { 73880bb2ff7SRichard Henderson TyphoonState *s = opaque; 73980bb2ff7SRichard Henderson uint64_t drir; 74080bb2ff7SRichard Henderson int i; 74180bb2ff7SRichard Henderson 74280bb2ff7SRichard Henderson /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL. */ 74380bb2ff7SRichard Henderson drir = s->cchip.drir; 74480bb2ff7SRichard Henderson if (level) { 74580bb2ff7SRichard Henderson drir |= 1ull << irq; 74680bb2ff7SRichard Henderson } else { 74780bb2ff7SRichard Henderson drir &= ~(1ull << irq); 74880bb2ff7SRichard Henderson } 74980bb2ff7SRichard Henderson s->cchip.drir = drir; 75080bb2ff7SRichard Henderson 75180bb2ff7SRichard Henderson for (i = 0; i < 4; ++i) { 75280bb2ff7SRichard Henderson cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir); 75380bb2ff7SRichard Henderson } 75480bb2ff7SRichard Henderson } 75580bb2ff7SRichard Henderson 75680bb2ff7SRichard Henderson static void typhoon_set_isa_irq(void *opaque, int irq, int level) 75780bb2ff7SRichard Henderson { 75880bb2ff7SRichard Henderson typhoon_set_irq(opaque, 55, level); 75980bb2ff7SRichard Henderson } 76080bb2ff7SRichard Henderson 76180bb2ff7SRichard Henderson static void typhoon_set_timer_irq(void *opaque, int irq, int level) 76280bb2ff7SRichard Henderson { 76380bb2ff7SRichard Henderson TyphoonState *s = opaque; 76480bb2ff7SRichard Henderson int i; 76580bb2ff7SRichard Henderson 76680bb2ff7SRichard Henderson /* Thankfully, the mc146818rtc code doesn't track the IRQ state, 76780bb2ff7SRichard Henderson and so we don't have to worry about missing interrupts just 76880bb2ff7SRichard Henderson because we never actually ACK the interrupt. Just ignore any 76980bb2ff7SRichard Henderson case of the interrupt level going low. */ 77080bb2ff7SRichard Henderson if (level == 0) { 77180bb2ff7SRichard Henderson return; 77280bb2ff7SRichard Henderson } 77380bb2ff7SRichard Henderson 77480bb2ff7SRichard Henderson /* Deliver the interrupt to each CPU, considering each CPU's IIC. */ 77580bb2ff7SRichard Henderson for (i = 0; i < 4; ++i) { 776ad601177SAndreas Färber AlphaCPU *cpu = s->cchip.cpu[i]; 777ad601177SAndreas Färber if (cpu != NULL) { 77880bb2ff7SRichard Henderson uint32_t iic = s->cchip.iic[i]; 77980bb2ff7SRichard Henderson 78080bb2ff7SRichard Henderson /* ??? The verbage in Section 10.2.2.10 isn't 100% clear. 78180bb2ff7SRichard Henderson Bit 24 is the OverFlow bit, RO, and set when the count 78280bb2ff7SRichard Henderson decrements past 0. When is OF cleared? My guess is that 78380bb2ff7SRichard Henderson OF is actually cleared when the IIC is written, and that 78480bb2ff7SRichard Henderson the ICNT field always decrements. At least, that's an 78580bb2ff7SRichard Henderson interpretation that makes sense, and "allows the CPU to 78680bb2ff7SRichard Henderson determine exactly how mant interval timer ticks were 78780bb2ff7SRichard Henderson skipped". At least within the next 4M ticks... */ 78880bb2ff7SRichard Henderson 78980bb2ff7SRichard Henderson iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000); 79080bb2ff7SRichard Henderson s->cchip.iic[i] = iic; 79180bb2ff7SRichard Henderson 79280bb2ff7SRichard Henderson if (iic & 0x1000000) { 79380bb2ff7SRichard Henderson /* Set the ITI bit for this cpu. */ 79480bb2ff7SRichard Henderson s->cchip.misc |= 1 << (i + 4); 79580bb2ff7SRichard Henderson /* And signal the interrupt. */ 796c3affe56SAndreas Färber cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER); 79780bb2ff7SRichard Henderson } 79880bb2ff7SRichard Henderson } 79980bb2ff7SRichard Henderson } 80080bb2ff7SRichard Henderson } 80180bb2ff7SRichard Henderson 802c781cf96SRichard Henderson static void typhoon_alarm_timer(void *opaque) 803c781cf96SRichard Henderson { 804c781cf96SRichard Henderson TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3); 805c781cf96SRichard Henderson int cpu = (uintptr_t)opaque & 3; 806c781cf96SRichard Henderson 807c781cf96SRichard Henderson /* Set the ITI bit for this cpu. */ 808c781cf96SRichard Henderson s->cchip.misc |= 1 << (cpu + 4); 809c3affe56SAndreas Färber cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER); 810c781cf96SRichard Henderson } 811c781cf96SRichard Henderson 81271baa303SHervé Poussineau PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, 81371baa303SHervé Poussineau qemu_irq *p_rtc_irq, 814ad601177SAndreas Färber AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq) 81580bb2ff7SRichard Henderson { 81680bb2ff7SRichard Henderson const uint64_t MB = 1024 * 1024; 81780bb2ff7SRichard Henderson const uint64_t GB = 1024 * MB; 81880bb2ff7SRichard Henderson MemoryRegion *addr_space = get_system_memory(); 81980bb2ff7SRichard Henderson DeviceState *dev; 82080bb2ff7SRichard Henderson TyphoonState *s; 82194dd91d6SAndreas Färber PCIHostState *phb; 82280bb2ff7SRichard Henderson PCIBus *b; 823c781cf96SRichard Henderson int i; 82480bb2ff7SRichard Henderson 82594dd91d6SAndreas Färber dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE); 82680bb2ff7SRichard Henderson 82794dd91d6SAndreas Färber s = TYPHOON_PCI_HOST_BRIDGE(dev); 8288558d942SAndreas Färber phb = PCI_HOST_BRIDGE(dev); 82980bb2ff7SRichard Henderson 830b83c4db8SRichard Henderson s->cchip.misc = 0x800000000ull; /* Revision: Typhoon. */ 831b83c4db8SRichard Henderson s->pchip.win[3].wba = 2; /* Window 3 SG always enabled. */ 832b83c4db8SRichard Henderson 83380bb2ff7SRichard Henderson /* Remember the CPUs so that we can deliver interrupts to them. */ 834c781cf96SRichard Henderson for (i = 0; i < 4; i++) { 835ad601177SAndreas Färber AlphaCPU *cpu = cpus[i]; 836ad601177SAndreas Färber s->cchip.cpu[i] = cpu; 837ad601177SAndreas Färber if (cpu != NULL) { 838bc72ad67SAlex Bligh cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 839c781cf96SRichard Henderson typhoon_alarm_timer, 840c781cf96SRichard Henderson (void *)((uintptr_t)s + i)); 841c781cf96SRichard Henderson } 842c781cf96SRichard Henderson } 84380bb2ff7SRichard Henderson 84454292736SShannon Zhao *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0); 84580bb2ff7SRichard Henderson 84680bb2ff7SRichard Henderson /* Main memory region, 0x00.0000.0000. Real hardware supports 32GB, 84780bb2ff7SRichard Henderson but the address space hole reserved at this point is 8TB. */ 84858c24a47SDirk Müller memory_region_allocate_system_memory(&s->ram_region, OBJECT(s), "ram", 84958c24a47SDirk Müller ram_size); 85080bb2ff7SRichard Henderson memory_region_add_subregion(addr_space, 0, &s->ram_region); 85180bb2ff7SRichard Henderson 85280bb2ff7SRichard Henderson /* TIGbus, 0x801.0000.0000, 1GB. */ 85380bb2ff7SRichard Henderson /* ??? The TIGbus is used for delivering interrupts, and access to 85480bb2ff7SRichard Henderson the flash ROM. I'm not sure that we need to implement it at all. */ 85580bb2ff7SRichard Henderson 85680bb2ff7SRichard Henderson /* Pchip0 CSRs, 0x801.8000.0000, 256MB. */ 85764bde0f3SPaolo Bonzini memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0", 85864bde0f3SPaolo Bonzini 256*MB); 85902d6516cSStefan Weil memory_region_add_subregion(addr_space, 0x80180000000ULL, 86002d6516cSStefan Weil &s->pchip.region); 86180bb2ff7SRichard Henderson 86280bb2ff7SRichard Henderson /* Cchip CSRs, 0x801.A000.0000, 256MB. */ 86364bde0f3SPaolo Bonzini memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0", 86464bde0f3SPaolo Bonzini 256*MB); 86502d6516cSStefan Weil memory_region_add_subregion(addr_space, 0x801a0000000ULL, 86602d6516cSStefan Weil &s->cchip.region); 86780bb2ff7SRichard Henderson 86880bb2ff7SRichard Henderson /* Dchip CSRs, 0x801.B000.0000, 256MB. */ 86964bde0f3SPaolo Bonzini memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0", 87064bde0f3SPaolo Bonzini 256*MB); 87102d6516cSStefan Weil memory_region_add_subregion(addr_space, 0x801b0000000ULL, 87202d6516cSStefan Weil &s->dchip_region); 87380bb2ff7SRichard Henderson 87480bb2ff7SRichard Henderson /* Pchip0 PCI memory, 0x800.0000.0000, 4GB. */ 87564bde0f3SPaolo Bonzini memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4*GB); 87602d6516cSStefan Weil memory_region_add_subregion(addr_space, 0x80000000000ULL, 87702d6516cSStefan Weil &s->pchip.reg_mem); 87880bb2ff7SRichard Henderson 87980bb2ff7SRichard Henderson /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB. */ 8803661049fSRichard Henderson memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops, 8813661049fSRichard Henderson NULL, "pci0-io", 32*MB); 88202d6516cSStefan Weil memory_region_add_subregion(addr_space, 0x801fc000000ULL, 88302d6516cSStefan Weil &s->pchip.reg_io); 88480bb2ff7SRichard Henderson 8851115ff6dSDavid Gibson b = pci_register_root_bus(dev, "pci", 88680bb2ff7SRichard Henderson typhoon_set_irq, sys_map_irq, s, 887056e6baeSRichard Henderson &s->pchip.reg_mem, &s->pchip.reg_io, 888056e6baeSRichard Henderson 0, 64, TYPE_PCI_BUS); 88994dd91d6SAndreas Färber phb->bus = b; 89050d3bba9SMarcel Apfelbaum qdev_init_nofail(dev); 89180bb2ff7SRichard Henderson 892b83c4db8SRichard Henderson /* Host memory as seen from the PCI side, via the IOMMU. */ 8931221a474SAlexey Kardashevskiy memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu), 8941221a474SAlexey Kardashevskiy TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s), 895b83c4db8SRichard Henderson "iommu-typhoon", UINT64_MAX); 8963df9d748SAlexey Kardashevskiy address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu), 8973df9d748SAlexey Kardashevskiy "pchip0-pci"); 898b83c4db8SRichard Henderson pci_setup_iommu(b, typhoon_pci_dma_iommu, s); 899b83c4db8SRichard Henderson 90080bb2ff7SRichard Henderson /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */ 901056e6baeSRichard Henderson memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops, 902056e6baeSRichard Henderson b, "pci0-iack", 64*MB); 90302d6516cSStefan Weil memory_region_add_subregion(addr_space, 0x801f8000000ULL, 90402d6516cSStefan Weil &s->pchip.reg_iack); 90580bb2ff7SRichard Henderson 90680bb2ff7SRichard Henderson /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB. */ 907056e6baeSRichard Henderson memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops, 908056e6baeSRichard Henderson b, "pci0-conf", 16*MB); 90902d6516cSStefan Weil memory_region_add_subregion(addr_space, 0x801fe000000ULL, 91002d6516cSStefan Weil &s->pchip.reg_conf); 91180bb2ff7SRichard Henderson 91280bb2ff7SRichard Henderson /* For the record, these are the mappings for the second PCI bus. 91380bb2ff7SRichard Henderson We can get away with not implementing them because we indicate 91480bb2ff7SRichard Henderson via the Cchip.CSC<PIP> bit that Pchip1 is not present. */ 91580bb2ff7SRichard Henderson /* Pchip1 PCI memory, 0x802.0000.0000, 4GB. */ 91680bb2ff7SRichard Henderson /* Pchip1 CSRs, 0x802.8000.0000, 256MB. */ 91780bb2ff7SRichard Henderson /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB. */ 91880bb2ff7SRichard Henderson /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB. */ 91980bb2ff7SRichard Henderson /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB. */ 92080bb2ff7SRichard Henderson 92180bb2ff7SRichard Henderson /* Init the ISA bus. */ 92280bb2ff7SRichard Henderson /* ??? Technically there should be a cy82c693ub pci-isa bridge. */ 92380bb2ff7SRichard Henderson { 92454292736SShannon Zhao qemu_irq *isa_irqs; 92580bb2ff7SRichard Henderson 926d10e5432SMarkus Armbruster *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io, 927d10e5432SMarkus Armbruster &error_abort); 92854292736SShannon Zhao isa_irqs = i8259_init(*isa_bus, 92954292736SShannon Zhao qemu_allocate_irq(typhoon_set_isa_irq, s, 0)); 93071baa303SHervé Poussineau isa_bus_irqs(*isa_bus, isa_irqs); 93180bb2ff7SRichard Henderson } 93280bb2ff7SRichard Henderson 93380bb2ff7SRichard Henderson return b; 93480bb2ff7SRichard Henderson } 93580bb2ff7SRichard Henderson 93680bb2ff7SRichard Henderson static int typhoon_pcihost_init(SysBusDevice *dev) 93780bb2ff7SRichard Henderson { 93880bb2ff7SRichard Henderson return 0; 93980bb2ff7SRichard Henderson } 94080bb2ff7SRichard Henderson 941999e12bbSAnthony Liguori static void typhoon_pcihost_class_init(ObjectClass *klass, void *data) 942999e12bbSAnthony Liguori { 943999e12bbSAnthony Liguori SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 944999e12bbSAnthony Liguori 945999e12bbSAnthony Liguori k->init = typhoon_pcihost_init; 946999e12bbSAnthony Liguori } 947999e12bbSAnthony Liguori 9484240abffSAndreas Färber static const TypeInfo typhoon_pcihost_info = { 94994dd91d6SAndreas Färber .name = TYPE_TYPHOON_PCI_HOST_BRIDGE, 9508558d942SAndreas Färber .parent = TYPE_PCI_HOST_BRIDGE, 95139bffca2SAnthony Liguori .instance_size = sizeof(TyphoonState), 952999e12bbSAnthony Liguori .class_init = typhoon_pcihost_class_init, 95380bb2ff7SRichard Henderson }; 95480bb2ff7SRichard Henderson 9551221a474SAlexey Kardashevskiy static void typhoon_iommu_memory_region_class_init(ObjectClass *klass, 9561221a474SAlexey Kardashevskiy void *data) 9571221a474SAlexey Kardashevskiy { 9581221a474SAlexey Kardashevskiy IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); 9591221a474SAlexey Kardashevskiy 9601221a474SAlexey Kardashevskiy imrc->translate = typhoon_translate_iommu; 9611221a474SAlexey Kardashevskiy } 9621221a474SAlexey Kardashevskiy 9631221a474SAlexey Kardashevskiy static const TypeInfo typhoon_iommu_memory_region_info = { 9641221a474SAlexey Kardashevskiy .parent = TYPE_IOMMU_MEMORY_REGION, 9651221a474SAlexey Kardashevskiy .name = TYPE_TYPHOON_IOMMU_MEMORY_REGION, 9661221a474SAlexey Kardashevskiy .class_init = typhoon_iommu_memory_region_class_init, 9671221a474SAlexey Kardashevskiy }; 9681221a474SAlexey Kardashevskiy 96983f7d43aSAndreas Färber static void typhoon_register_types(void) 97080bb2ff7SRichard Henderson { 97139bffca2SAnthony Liguori type_register_static(&typhoon_pcihost_info); 9721221a474SAlexey Kardashevskiy type_register_static(&typhoon_iommu_memory_region_info); 97380bb2ff7SRichard Henderson } 97483f7d43aSAndreas Färber 97583f7d43aSAndreas Färber type_init(typhoon_register_types) 976