1118c82e7SEddie James /* 2118c82e7SEddie James * ASPEED XDMA Controller 3118c82e7SEddie James * Eddie James <eajames@linux.ibm.com> 4118c82e7SEddie James * 5118c82e7SEddie James * Copyright (C) 2019 IBM Corp 65054ba10SRyan Finnie * SPDX-License-Identifier: GPL-2.0-or-later 7118c82e7SEddie James */ 8118c82e7SEddie James 9118c82e7SEddie James #include "qemu/osdep.h" 10118c82e7SEddie James #include "qemu/log.h" 11118c82e7SEddie James #include "qemu/error-report.h" 1264552b6bSMarkus Armbruster #include "hw/irq.h" 13118c82e7SEddie James #include "hw/misc/aspeed_xdma.h" 14d6454270SMarkus Armbruster #include "migration/vmstate.h" 15118c82e7SEddie James #include "qapi/error.h" 16118c82e7SEddie James 17118c82e7SEddie James #include "trace.h" 18118c82e7SEddie James 19118c82e7SEddie James #define XDMA_BMC_CMDQ_ADDR 0x10 20118c82e7SEddie James #define XDMA_BMC_CMDQ_ENDP 0x14 21118c82e7SEddie James #define XDMA_BMC_CMDQ_WRP 0x18 22118c82e7SEddie James #define XDMA_BMC_CMDQ_W_MASK 0x0003FFFF 23118c82e7SEddie James #define XDMA_BMC_CMDQ_RDP 0x1C 24118c82e7SEddie James #define XDMA_BMC_CMDQ_RDP_MAGIC 0xEE882266 25118c82e7SEddie James #define XDMA_IRQ_ENG_CTRL 0x20 26118c82e7SEddie James #define XDMA_IRQ_ENG_CTRL_US_COMP BIT(4) 27118c82e7SEddie James #define XDMA_IRQ_ENG_CTRL_DS_COMP BIT(5) 28118c82e7SEddie James #define XDMA_IRQ_ENG_CTRL_W_MASK 0xBFEFF07F 29118c82e7SEddie James #define XDMA_IRQ_ENG_STAT 0x24 30118c82e7SEddie James #define XDMA_IRQ_ENG_STAT_US_COMP BIT(4) 31118c82e7SEddie James #define XDMA_IRQ_ENG_STAT_DS_COMP BIT(5) 32118c82e7SEddie James #define XDMA_IRQ_ENG_STAT_RESET 0xF8000000 338efbee28SCédric Le Goater 348efbee28SCédric Le Goater #define XDMA_AST2600_BMC_CMDQ_ADDR 0x14 358efbee28SCédric Le Goater #define XDMA_AST2600_BMC_CMDQ_ENDP 0x18 368efbee28SCédric Le Goater #define XDMA_AST2600_BMC_CMDQ_WRP 0x1c 378efbee28SCédric Le Goater #define XDMA_AST2600_BMC_CMDQ_RDP 0x20 388efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_CTRL 0x38 398efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_CTRL_US_COMP BIT(16) 408efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_CTRL_DS_COMP BIT(17) 418efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_CTRL_W_MASK 0x017003FF 428efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_STATUS 0x3c 438efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_STATUS_US_COMP BIT(16) 448efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_STATUS_DS_COMP BIT(17) 458efbee28SCédric Le Goater 46118c82e7SEddie James #define XDMA_MEM_SIZE 0x1000 47118c82e7SEddie James 48118c82e7SEddie James #define TO_REG(addr) ((addr) / sizeof(uint32_t)) 49118c82e7SEddie James 50118c82e7SEddie James static uint64_t aspeed_xdma_read(void *opaque, hwaddr addr, unsigned int size) 51118c82e7SEddie James { 52118c82e7SEddie James uint32_t val = 0; 53118c82e7SEddie James AspeedXDMAState *xdma = opaque; 54118c82e7SEddie James 55118c82e7SEddie James if (addr < ASPEED_XDMA_REG_SIZE) { 56118c82e7SEddie James val = xdma->regs[TO_REG(addr)]; 57118c82e7SEddie James } 58118c82e7SEddie James 59118c82e7SEddie James return (uint64_t)val; 60118c82e7SEddie James } 61118c82e7SEddie James 62118c82e7SEddie James static void aspeed_xdma_write(void *opaque, hwaddr addr, uint64_t val, 63118c82e7SEddie James unsigned int size) 64118c82e7SEddie James { 65118c82e7SEddie James unsigned int idx; 66118c82e7SEddie James uint32_t val32 = (uint32_t)val; 67118c82e7SEddie James AspeedXDMAState *xdma = opaque; 688efbee28SCédric Le Goater AspeedXDMAClass *axc = ASPEED_XDMA_GET_CLASS(xdma); 69118c82e7SEddie James 70118c82e7SEddie James if (addr >= ASPEED_XDMA_REG_SIZE) { 71118c82e7SEddie James return; 72118c82e7SEddie James } 73118c82e7SEddie James 748efbee28SCédric Le Goater if (addr == axc->cmdq_endp) { 75118c82e7SEddie James xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK; 768efbee28SCédric Le Goater } else if (addr == axc->cmdq_wrp) { 77118c82e7SEddie James idx = TO_REG(addr); 78118c82e7SEddie James xdma->regs[idx] = val32 & XDMA_BMC_CMDQ_W_MASK; 798efbee28SCédric Le Goater xdma->regs[TO_REG(axc->cmdq_rdp)] = xdma->regs[idx]; 80118c82e7SEddie James 81118c82e7SEddie James trace_aspeed_xdma_write(addr, val); 82118c82e7SEddie James 83118c82e7SEddie James if (xdma->bmc_cmdq_readp_set) { 84118c82e7SEddie James xdma->bmc_cmdq_readp_set = 0; 85118c82e7SEddie James } else { 868efbee28SCédric Le Goater xdma->regs[TO_REG(axc->intr_status)] |= axc->intr_complete; 87118c82e7SEddie James 888efbee28SCédric Le Goater if (xdma->regs[TO_REG(axc->intr_ctrl)] & axc->intr_complete) { 89118c82e7SEddie James qemu_irq_raise(xdma->irq); 90118c82e7SEddie James } 918efbee28SCédric Le Goater } 928efbee28SCédric Le Goater } else if (addr == axc->cmdq_rdp) { 93118c82e7SEddie James trace_aspeed_xdma_write(addr, val); 94118c82e7SEddie James 95118c82e7SEddie James if (val32 == XDMA_BMC_CMDQ_RDP_MAGIC) { 96118c82e7SEddie James xdma->bmc_cmdq_readp_set = 1; 97118c82e7SEddie James } 988efbee28SCédric Le Goater } else if (addr == axc->intr_ctrl) { 998efbee28SCédric Le Goater xdma->regs[TO_REG(addr)] = val32 & axc->intr_ctrl_mask; 1008efbee28SCédric Le Goater } else if (addr == axc->intr_status) { 101118c82e7SEddie James trace_aspeed_xdma_write(addr, val); 102118c82e7SEddie James 103118c82e7SEddie James idx = TO_REG(addr); 1048efbee28SCédric Le Goater if (val32 & axc->intr_complete) { 1058efbee28SCédric Le Goater xdma->regs[idx] &= ~axc->intr_complete; 106118c82e7SEddie James qemu_irq_lower(xdma->irq); 107118c82e7SEddie James } 1088efbee28SCédric Le Goater } else { 109118c82e7SEddie James xdma->regs[TO_REG(addr)] = val32; 110118c82e7SEddie James } 111118c82e7SEddie James } 112118c82e7SEddie James 113118c82e7SEddie James static const MemoryRegionOps aspeed_xdma_ops = { 114118c82e7SEddie James .read = aspeed_xdma_read, 115118c82e7SEddie James .write = aspeed_xdma_write, 116118c82e7SEddie James .endianness = DEVICE_NATIVE_ENDIAN, 117118c82e7SEddie James .valid.min_access_size = 4, 118118c82e7SEddie James .valid.max_access_size = 4, 119118c82e7SEddie James }; 120118c82e7SEddie James 121118c82e7SEddie James static void aspeed_xdma_realize(DeviceState *dev, Error **errp) 122118c82e7SEddie James { 123118c82e7SEddie James SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 124118c82e7SEddie James AspeedXDMAState *xdma = ASPEED_XDMA(dev); 125118c82e7SEddie James 126118c82e7SEddie James sysbus_init_irq(sbd, &xdma->irq); 127118c82e7SEddie James memory_region_init_io(&xdma->iomem, OBJECT(xdma), &aspeed_xdma_ops, xdma, 128118c82e7SEddie James TYPE_ASPEED_XDMA, XDMA_MEM_SIZE); 129118c82e7SEddie James sysbus_init_mmio(sbd, &xdma->iomem); 130118c82e7SEddie James } 131118c82e7SEddie James 132118c82e7SEddie James static void aspeed_xdma_reset(DeviceState *dev) 133118c82e7SEddie James { 134118c82e7SEddie James AspeedXDMAState *xdma = ASPEED_XDMA(dev); 1358efbee28SCédric Le Goater AspeedXDMAClass *axc = ASPEED_XDMA_GET_CLASS(xdma); 136118c82e7SEddie James 137118c82e7SEddie James xdma->bmc_cmdq_readp_set = 0; 138118c82e7SEddie James memset(xdma->regs, 0, ASPEED_XDMA_REG_SIZE); 1398efbee28SCédric Le Goater xdma->regs[TO_REG(axc->intr_status)] = XDMA_IRQ_ENG_STAT_RESET; 140118c82e7SEddie James 141118c82e7SEddie James qemu_irq_lower(xdma->irq); 142118c82e7SEddie James } 143118c82e7SEddie James 144118c82e7SEddie James static const VMStateDescription aspeed_xdma_vmstate = { 145118c82e7SEddie James .name = TYPE_ASPEED_XDMA, 146118c82e7SEddie James .version_id = 1, 147e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 148118c82e7SEddie James VMSTATE_UINT32_ARRAY(regs, AspeedXDMAState, ASPEED_XDMA_NUM_REGS), 149118c82e7SEddie James VMSTATE_END_OF_LIST(), 150118c82e7SEddie James }, 151118c82e7SEddie James }; 152118c82e7SEddie James 1538efbee28SCédric Le Goater static void aspeed_2600_xdma_class_init(ObjectClass *klass, void *data) 1548efbee28SCédric Le Goater { 1558efbee28SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1568efbee28SCédric Le Goater AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); 1578efbee28SCédric Le Goater 1588efbee28SCédric Le Goater dc->desc = "ASPEED 2600 XDMA Controller"; 1598efbee28SCédric Le Goater 1608efbee28SCédric Le Goater axc->cmdq_endp = XDMA_AST2600_BMC_CMDQ_ENDP; 1618efbee28SCédric Le Goater axc->cmdq_wrp = XDMA_AST2600_BMC_CMDQ_WRP; 1628efbee28SCédric Le Goater axc->cmdq_rdp = XDMA_AST2600_BMC_CMDQ_RDP; 1638efbee28SCédric Le Goater axc->intr_ctrl = XDMA_AST2600_IRQ_CTRL; 1648efbee28SCédric Le Goater axc->intr_ctrl_mask = XDMA_AST2600_IRQ_CTRL_W_MASK; 1658efbee28SCédric Le Goater axc->intr_status = XDMA_AST2600_IRQ_STATUS; 1668efbee28SCédric Le Goater axc->intr_complete = XDMA_AST2600_IRQ_STATUS_US_COMP | 1678efbee28SCédric Le Goater XDMA_AST2600_IRQ_STATUS_DS_COMP; 1688efbee28SCédric Le Goater } 1698efbee28SCédric Le Goater 1708efbee28SCédric Le Goater static const TypeInfo aspeed_2600_xdma_info = { 1718efbee28SCédric Le Goater .name = TYPE_ASPEED_2600_XDMA, 1728efbee28SCédric Le Goater .parent = TYPE_ASPEED_XDMA, 1738efbee28SCédric Le Goater .class_init = aspeed_2600_xdma_class_init, 1748efbee28SCédric Le Goater }; 1758efbee28SCédric Le Goater 1768efbee28SCédric Le Goater static void aspeed_2500_xdma_class_init(ObjectClass *klass, void *data) 1778efbee28SCédric Le Goater { 1788efbee28SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1798efbee28SCédric Le Goater AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); 1808efbee28SCédric Le Goater 1818efbee28SCédric Le Goater dc->desc = "ASPEED 2500 XDMA Controller"; 1828efbee28SCédric Le Goater 1838efbee28SCédric Le Goater axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP; 1848efbee28SCédric Le Goater axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP; 1858efbee28SCédric Le Goater axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP; 1868efbee28SCédric Le Goater axc->intr_ctrl = XDMA_IRQ_ENG_CTRL; 1878efbee28SCédric Le Goater axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK; 1888efbee28SCédric Le Goater axc->intr_status = XDMA_IRQ_ENG_STAT; 1898efbee28SCédric Le Goater axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP; 1908efbee28SCédric Le Goater }; 1918efbee28SCédric Le Goater 1928efbee28SCédric Le Goater static const TypeInfo aspeed_2500_xdma_info = { 1938efbee28SCédric Le Goater .name = TYPE_ASPEED_2500_XDMA, 1948efbee28SCédric Le Goater .parent = TYPE_ASPEED_XDMA, 1958efbee28SCédric Le Goater .class_init = aspeed_2500_xdma_class_init, 1968efbee28SCédric Le Goater }; 1978efbee28SCédric Le Goater 1988efbee28SCédric Le Goater static void aspeed_2400_xdma_class_init(ObjectClass *klass, void *data) 1998efbee28SCédric Le Goater { 2008efbee28SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 2018efbee28SCédric Le Goater AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); 2028efbee28SCédric Le Goater 2038efbee28SCédric Le Goater dc->desc = "ASPEED 2400 XDMA Controller"; 2048efbee28SCédric Le Goater 2058efbee28SCédric Le Goater axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP; 2068efbee28SCédric Le Goater axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP; 2078efbee28SCédric Le Goater axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP; 2088efbee28SCédric Le Goater axc->intr_ctrl = XDMA_IRQ_ENG_CTRL; 2098efbee28SCédric Le Goater axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK; 2108efbee28SCédric Le Goater axc->intr_status = XDMA_IRQ_ENG_STAT; 2118efbee28SCédric Le Goater axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP; 2128efbee28SCédric Le Goater }; 2138efbee28SCédric Le Goater 2148efbee28SCédric Le Goater static const TypeInfo aspeed_2400_xdma_info = { 2158efbee28SCédric Le Goater .name = TYPE_ASPEED_2400_XDMA, 2168efbee28SCédric Le Goater .parent = TYPE_ASPEED_XDMA, 2178efbee28SCédric Le Goater .class_init = aspeed_2400_xdma_class_init, 2188efbee28SCédric Le Goater }; 2198efbee28SCédric Le Goater 220118c82e7SEddie James static void aspeed_xdma_class_init(ObjectClass *classp, void *data) 221118c82e7SEddie James { 222118c82e7SEddie James DeviceClass *dc = DEVICE_CLASS(classp); 223118c82e7SEddie James 224118c82e7SEddie James dc->realize = aspeed_xdma_realize; 225*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, aspeed_xdma_reset); 226118c82e7SEddie James dc->vmsd = &aspeed_xdma_vmstate; 227118c82e7SEddie James } 228118c82e7SEddie James 229118c82e7SEddie James static const TypeInfo aspeed_xdma_info = { 230118c82e7SEddie James .name = TYPE_ASPEED_XDMA, 231118c82e7SEddie James .parent = TYPE_SYS_BUS_DEVICE, 232118c82e7SEddie James .instance_size = sizeof(AspeedXDMAState), 233118c82e7SEddie James .class_init = aspeed_xdma_class_init, 2348efbee28SCédric Le Goater .class_size = sizeof(AspeedXDMAClass), 2358efbee28SCédric Le Goater .abstract = true, 236118c82e7SEddie James }; 237118c82e7SEddie James 238118c82e7SEddie James static void aspeed_xdma_register_type(void) 239118c82e7SEddie James { 240118c82e7SEddie James type_register_static(&aspeed_xdma_info); 2418efbee28SCédric Le Goater type_register_static(&aspeed_2400_xdma_info); 2428efbee28SCédric Le Goater type_register_static(&aspeed_2500_xdma_info); 2438efbee28SCédric Le Goater type_register_static(&aspeed_2600_xdma_info); 244118c82e7SEddie James } 245118c82e7SEddie James type_init(aspeed_xdma_register_type); 246