xref: /openbmc/qemu/hw/misc/aspeed_xdma.c (revision 64552b6b)
1 /*
2  * ASPEED XDMA Controller
3  * Eddie James <eajames@linux.ibm.com>
4  *
5  * Copyright (C) 2019 IBM Corp
6  * SPDX-License-Identifer: GPL-2.0-or-later
7  */
8 
9 #include "qemu/osdep.h"
10 #include "qemu/log.h"
11 #include "qemu/error-report.h"
12 #include "hw/irq.h"
13 #include "hw/misc/aspeed_xdma.h"
14 #include "qapi/error.h"
15 
16 #include "trace.h"
17 
18 #define XDMA_BMC_CMDQ_ADDR         0x10
19 #define XDMA_BMC_CMDQ_ENDP         0x14
20 #define XDMA_BMC_CMDQ_WRP          0x18
21 #define  XDMA_BMC_CMDQ_W_MASK      0x0003FFFF
22 #define XDMA_BMC_CMDQ_RDP          0x1C
23 #define  XDMA_BMC_CMDQ_RDP_MAGIC   0xEE882266
24 #define XDMA_IRQ_ENG_CTRL          0x20
25 #define  XDMA_IRQ_ENG_CTRL_US_COMP BIT(4)
26 #define  XDMA_IRQ_ENG_CTRL_DS_COMP BIT(5)
27 #define  XDMA_IRQ_ENG_CTRL_W_MASK  0xBFEFF07F
28 #define XDMA_IRQ_ENG_STAT          0x24
29 #define  XDMA_IRQ_ENG_STAT_US_COMP BIT(4)
30 #define  XDMA_IRQ_ENG_STAT_DS_COMP BIT(5)
31 #define  XDMA_IRQ_ENG_STAT_RESET   0xF8000000
32 #define XDMA_MEM_SIZE              0x1000
33 
34 #define TO_REG(addr) ((addr) / sizeof(uint32_t))
35 
36 static uint64_t aspeed_xdma_read(void *opaque, hwaddr addr, unsigned int size)
37 {
38     uint32_t val = 0;
39     AspeedXDMAState *xdma = opaque;
40 
41     if (addr < ASPEED_XDMA_REG_SIZE) {
42         val = xdma->regs[TO_REG(addr)];
43     }
44 
45     return (uint64_t)val;
46 }
47 
48 static void aspeed_xdma_write(void *opaque, hwaddr addr, uint64_t val,
49                               unsigned int size)
50 {
51     unsigned int idx;
52     uint32_t val32 = (uint32_t)val;
53     AspeedXDMAState *xdma = opaque;
54 
55     if (addr >= ASPEED_XDMA_REG_SIZE) {
56         return;
57     }
58 
59     switch (addr) {
60     case XDMA_BMC_CMDQ_ENDP:
61         xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK;
62         break;
63     case XDMA_BMC_CMDQ_WRP:
64         idx = TO_REG(addr);
65         xdma->regs[idx] = val32 & XDMA_BMC_CMDQ_W_MASK;
66         xdma->regs[TO_REG(XDMA_BMC_CMDQ_RDP)] = xdma->regs[idx];
67 
68         trace_aspeed_xdma_write(addr, val);
69 
70         if (xdma->bmc_cmdq_readp_set) {
71             xdma->bmc_cmdq_readp_set = 0;
72         } else {
73             xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] |=
74                 XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
75 
76             if (xdma->regs[TO_REG(XDMA_IRQ_ENG_CTRL)] &
77                 (XDMA_IRQ_ENG_CTRL_US_COMP | XDMA_IRQ_ENG_CTRL_DS_COMP))
78                 qemu_irq_raise(xdma->irq);
79         }
80         break;
81     case XDMA_BMC_CMDQ_RDP:
82         trace_aspeed_xdma_write(addr, val);
83 
84         if (val32 == XDMA_BMC_CMDQ_RDP_MAGIC) {
85             xdma->bmc_cmdq_readp_set = 1;
86         }
87         break;
88     case XDMA_IRQ_ENG_CTRL:
89         xdma->regs[TO_REG(addr)] = val32 & XDMA_IRQ_ENG_CTRL_W_MASK;
90         break;
91     case XDMA_IRQ_ENG_STAT:
92         trace_aspeed_xdma_write(addr, val);
93 
94         idx = TO_REG(addr);
95         if (val32 & (XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP)) {
96             xdma->regs[idx] &=
97                 ~(XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP);
98             qemu_irq_lower(xdma->irq);
99         }
100         break;
101     default:
102         xdma->regs[TO_REG(addr)] = val32;
103         break;
104     }
105 }
106 
107 static const MemoryRegionOps aspeed_xdma_ops = {
108     .read = aspeed_xdma_read,
109     .write = aspeed_xdma_write,
110     .endianness = DEVICE_NATIVE_ENDIAN,
111     .valid.min_access_size = 4,
112     .valid.max_access_size = 4,
113 };
114 
115 static void aspeed_xdma_realize(DeviceState *dev, Error **errp)
116 {
117     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
118     AspeedXDMAState *xdma = ASPEED_XDMA(dev);
119 
120     sysbus_init_irq(sbd, &xdma->irq);
121     memory_region_init_io(&xdma->iomem, OBJECT(xdma), &aspeed_xdma_ops, xdma,
122                           TYPE_ASPEED_XDMA, XDMA_MEM_SIZE);
123     sysbus_init_mmio(sbd, &xdma->iomem);
124 }
125 
126 static void aspeed_xdma_reset(DeviceState *dev)
127 {
128     AspeedXDMAState *xdma = ASPEED_XDMA(dev);
129 
130     xdma->bmc_cmdq_readp_set = 0;
131     memset(xdma->regs, 0, ASPEED_XDMA_REG_SIZE);
132     xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] = XDMA_IRQ_ENG_STAT_RESET;
133 
134     qemu_irq_lower(xdma->irq);
135 }
136 
137 static const VMStateDescription aspeed_xdma_vmstate = {
138     .name = TYPE_ASPEED_XDMA,
139     .version_id = 1,
140     .fields = (VMStateField[]) {
141         VMSTATE_UINT32_ARRAY(regs, AspeedXDMAState, ASPEED_XDMA_NUM_REGS),
142         VMSTATE_END_OF_LIST(),
143     },
144 };
145 
146 static void aspeed_xdma_class_init(ObjectClass *classp, void *data)
147 {
148     DeviceClass *dc = DEVICE_CLASS(classp);
149 
150     dc->realize = aspeed_xdma_realize;
151     dc->reset = aspeed_xdma_reset;
152     dc->vmsd = &aspeed_xdma_vmstate;
153 }
154 
155 static const TypeInfo aspeed_xdma_info = {
156     .name          = TYPE_ASPEED_XDMA,
157     .parent        = TYPE_SYS_BUS_DEVICE,
158     .instance_size = sizeof(AspeedXDMAState),
159     .class_init    = aspeed_xdma_class_init,
160 };
161 
162 static void aspeed_xdma_register_type(void)
163 {
164     type_register_static(&aspeed_xdma_info);
165 }
166 type_init(aspeed_xdma_register_type);
167