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 33*8efbee28SCédric Le Goater 34*8efbee28SCédric Le Goater #define XDMA_AST2600_BMC_CMDQ_ADDR 0x14 35*8efbee28SCédric Le Goater #define XDMA_AST2600_BMC_CMDQ_ENDP 0x18 36*8efbee28SCédric Le Goater #define XDMA_AST2600_BMC_CMDQ_WRP 0x1c 37*8efbee28SCédric Le Goater #define XDMA_AST2600_BMC_CMDQ_RDP 0x20 38*8efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_CTRL 0x38 39*8efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_CTRL_US_COMP BIT(16) 40*8efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_CTRL_DS_COMP BIT(17) 41*8efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_CTRL_W_MASK 0x017003FF 42*8efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_STATUS 0x3c 43*8efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_STATUS_US_COMP BIT(16) 44*8efbee28SCédric Le Goater #define XDMA_AST2600_IRQ_STATUS_DS_COMP BIT(17) 45*8efbee28SCé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; 68*8efbee28SCé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 74*8efbee28SCédric Le Goater if (addr == axc->cmdq_endp) { 75118c82e7SEddie James xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK; 76*8efbee28SCé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; 79*8efbee28SCé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 { 86*8efbee28SCédric Le Goater xdma->regs[TO_REG(axc->intr_status)] |= axc->intr_complete; 87118c82e7SEddie James 88*8efbee28SCédric Le Goater if (xdma->regs[TO_REG(axc->intr_ctrl)] & axc->intr_complete) { 89118c82e7SEddie James qemu_irq_raise(xdma->irq); 90118c82e7SEddie James } 91*8efbee28SCédric Le Goater } 92*8efbee28SCé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 } 98*8efbee28SCédric Le Goater } else if (addr == axc->intr_ctrl) { 99*8efbee28SCédric Le Goater xdma->regs[TO_REG(addr)] = val32 & axc->intr_ctrl_mask; 100*8efbee28SCé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); 104*8efbee28SCédric Le Goater if (val32 & axc->intr_complete) { 105*8efbee28SCédric Le Goater xdma->regs[idx] &= ~axc->intr_complete; 106118c82e7SEddie James qemu_irq_lower(xdma->irq); 107118c82e7SEddie James } 108*8efbee28SCé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); 135*8efbee28SCé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); 139*8efbee28SCé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, 147118c82e7SEddie James .fields = (VMStateField[]) { 148118c82e7SEddie James VMSTATE_UINT32_ARRAY(regs, AspeedXDMAState, ASPEED_XDMA_NUM_REGS), 149118c82e7SEddie James VMSTATE_END_OF_LIST(), 150118c82e7SEddie James }, 151118c82e7SEddie James }; 152118c82e7SEddie James 153*8efbee28SCédric Le Goater static void aspeed_2600_xdma_class_init(ObjectClass *klass, void *data) 154*8efbee28SCédric Le Goater { 155*8efbee28SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 156*8efbee28SCédric Le Goater AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); 157*8efbee28SCédric Le Goater 158*8efbee28SCédric Le Goater dc->desc = "ASPEED 2600 XDMA Controller"; 159*8efbee28SCédric Le Goater 160*8efbee28SCédric Le Goater axc->cmdq_endp = XDMA_AST2600_BMC_CMDQ_ENDP; 161*8efbee28SCédric Le Goater axc->cmdq_wrp = XDMA_AST2600_BMC_CMDQ_WRP; 162*8efbee28SCédric Le Goater axc->cmdq_rdp = XDMA_AST2600_BMC_CMDQ_RDP; 163*8efbee28SCédric Le Goater axc->intr_ctrl = XDMA_AST2600_IRQ_CTRL; 164*8efbee28SCédric Le Goater axc->intr_ctrl_mask = XDMA_AST2600_IRQ_CTRL_W_MASK; 165*8efbee28SCédric Le Goater axc->intr_status = XDMA_AST2600_IRQ_STATUS; 166*8efbee28SCédric Le Goater axc->intr_complete = XDMA_AST2600_IRQ_STATUS_US_COMP | 167*8efbee28SCédric Le Goater XDMA_AST2600_IRQ_STATUS_DS_COMP; 168*8efbee28SCédric Le Goater } 169*8efbee28SCédric Le Goater 170*8efbee28SCédric Le Goater static const TypeInfo aspeed_2600_xdma_info = { 171*8efbee28SCédric Le Goater .name = TYPE_ASPEED_2600_XDMA, 172*8efbee28SCédric Le Goater .parent = TYPE_ASPEED_XDMA, 173*8efbee28SCédric Le Goater .class_init = aspeed_2600_xdma_class_init, 174*8efbee28SCédric Le Goater }; 175*8efbee28SCédric Le Goater 176*8efbee28SCédric Le Goater static void aspeed_2500_xdma_class_init(ObjectClass *klass, void *data) 177*8efbee28SCédric Le Goater { 178*8efbee28SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 179*8efbee28SCédric Le Goater AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); 180*8efbee28SCédric Le Goater 181*8efbee28SCédric Le Goater dc->desc = "ASPEED 2500 XDMA Controller"; 182*8efbee28SCédric Le Goater 183*8efbee28SCédric Le Goater axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP; 184*8efbee28SCédric Le Goater axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP; 185*8efbee28SCédric Le Goater axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP; 186*8efbee28SCédric Le Goater axc->intr_ctrl = XDMA_IRQ_ENG_CTRL; 187*8efbee28SCédric Le Goater axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK; 188*8efbee28SCédric Le Goater axc->intr_status = XDMA_IRQ_ENG_STAT; 189*8efbee28SCédric Le Goater axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP; 190*8efbee28SCédric Le Goater }; 191*8efbee28SCédric Le Goater 192*8efbee28SCédric Le Goater static const TypeInfo aspeed_2500_xdma_info = { 193*8efbee28SCédric Le Goater .name = TYPE_ASPEED_2500_XDMA, 194*8efbee28SCédric Le Goater .parent = TYPE_ASPEED_XDMA, 195*8efbee28SCédric Le Goater .class_init = aspeed_2500_xdma_class_init, 196*8efbee28SCédric Le Goater }; 197*8efbee28SCédric Le Goater 198*8efbee28SCédric Le Goater static void aspeed_2400_xdma_class_init(ObjectClass *klass, void *data) 199*8efbee28SCédric Le Goater { 200*8efbee28SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 201*8efbee28SCédric Le Goater AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); 202*8efbee28SCédric Le Goater 203*8efbee28SCédric Le Goater dc->desc = "ASPEED 2400 XDMA Controller"; 204*8efbee28SCédric Le Goater 205*8efbee28SCédric Le Goater axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP; 206*8efbee28SCédric Le Goater axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP; 207*8efbee28SCédric Le Goater axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP; 208*8efbee28SCédric Le Goater axc->intr_ctrl = XDMA_IRQ_ENG_CTRL; 209*8efbee28SCédric Le Goater axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK; 210*8efbee28SCédric Le Goater axc->intr_status = XDMA_IRQ_ENG_STAT; 211*8efbee28SCédric Le Goater axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP; 212*8efbee28SCédric Le Goater }; 213*8efbee28SCédric Le Goater 214*8efbee28SCédric Le Goater static const TypeInfo aspeed_2400_xdma_info = { 215*8efbee28SCédric Le Goater .name = TYPE_ASPEED_2400_XDMA, 216*8efbee28SCédric Le Goater .parent = TYPE_ASPEED_XDMA, 217*8efbee28SCédric Le Goater .class_init = aspeed_2400_xdma_class_init, 218*8efbee28SCédric Le Goater }; 219*8efbee28SCé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; 225118c82e7SEddie James dc->reset = 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, 234*8efbee28SCédric Le Goater .class_size = sizeof(AspeedXDMAClass), 235*8efbee28SCé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); 241*8efbee28SCédric Le Goater type_register_static(&aspeed_2400_xdma_info); 242*8efbee28SCédric Le Goater type_register_static(&aspeed_2500_xdma_info); 243*8efbee28SCédric Le Goater type_register_static(&aspeed_2600_xdma_info); 244118c82e7SEddie James } 245118c82e7SEddie James type_init(aspeed_xdma_register_type); 246