2 * SiFive Platform DMA emulation
4 * Copyright (c) 2020 Wind River Systems, Inc.
7 * Bin Meng <bin.meng@windriver.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 or
12 * (at your option) version 3 of the License.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <http://www.gnu.org/licenses/>.
23 #include "qemu/osdep.h"
24 #include "qemu/bitops.h"
26 #include "qapi/error.h"
29 #include "hw/qdev-properties.h"
30 #include "hw/sysbus.h"
31 #include "migration/vmstate.h"
32 #include "sysemu/dma.h"
33 #include "hw/dma/sifive_pdma.h"
35 #define DMA_CONTROL 0x000
36 #define CONTROL_CLAIM BIT(0)
37 #define CONTROL_RUN BIT(1)
38 #define CONTROL_DONE_IE BIT(14)
39 #define CONTROL_ERR_IE BIT(15)
40 #define CONTROL_DONE BIT(30)
41 #define CONTROL_ERR BIT(31)
43 #define DMA_NEXT_CONFIG 0x004
44 #define CONFIG_REPEAT BIT(2)
45 #define CONFIG_ORDER BIT(3)
46 #define CONFIG_WRSZ_SHIFT 24
47 #define CONFIG_RDSZ_SHIFT 28
48 #define CONFIG_SZ_MASK 0xf
50 #define DMA_NEXT_BYTES 0x008
51 #define DMA_NEXT_DST 0x010
52 #define DMA_NEXT_SRC 0x018
53 #define DMA_EXEC_CONFIG 0x104
54 #define DMA_EXEC_BYTES 0x108
55 #define DMA_EXEC_DST 0x110
56 #define DMA_EXEC_SRC 0x118
60 DMA_CHAN_STATE_STARTED
,
65 static void sifive_pdma_run(SiFivePDMAState
*s
, int ch
)
67 uint64_t bytes
= s
->chan
[ch
].next_bytes
;
68 uint64_t dst
= s
->chan
[ch
].next_dst
;
69 uint64_t src
= s
->chan
[ch
].next_src
;
70 uint32_t config
= s
->chan
[ch
].next_config
;
71 int wsize
, rsize
, size
;
75 /* do nothing if bytes to transfer is zero */
81 * The manual does not describe how the hardware behaviors when
82 * config.wsize and config.rsize are given different values.
83 * A common case is memory to memory DMA, and in this case they
84 * are normally the same. Abort if this expectation fails.
86 wsize
= (config
>> CONFIG_WRSZ_SHIFT
) & CONFIG_SZ_MASK
;
87 rsize
= (config
>> CONFIG_RDSZ_SHIFT
) & CONFIG_SZ_MASK
;
93 * Calculate the transaction size
95 * size field is base 2 logarithm of DMA transaction size,
96 * but there is an upper limit of 64 bytes per transaction.
104 /* the bytes to transfer should be multiple of transaction size */
109 /* indicate a DMA transfer is started */
110 s
->chan
[ch
].state
= DMA_CHAN_STATE_STARTED
;
111 s
->chan
[ch
].control
&= ~CONTROL_DONE
;
112 s
->chan
[ch
].control
&= ~CONTROL_ERR
;
114 /* load the next_ registers into their exec_ counterparts */
115 s
->chan
[ch
].exec_config
= config
;
116 s
->chan
[ch
].exec_bytes
= bytes
;
117 s
->chan
[ch
].exec_dst
= dst
;
118 s
->chan
[ch
].exec_src
= src
;
120 for (n
= 0; n
< bytes
/ size
; n
++) {
121 cpu_physical_memory_read(s
->chan
[ch
].exec_src
, buf
, size
);
122 cpu_physical_memory_write(s
->chan
[ch
].exec_dst
, buf
, size
);
123 s
->chan
[ch
].exec_src
+= size
;
124 s
->chan
[ch
].exec_dst
+= size
;
125 s
->chan
[ch
].exec_bytes
-= size
;
128 /* indicate a DMA transfer is done */
129 s
->chan
[ch
].state
= DMA_CHAN_STATE_DONE
;
130 s
->chan
[ch
].control
&= ~CONTROL_RUN
;
131 s
->chan
[ch
].control
|= CONTROL_DONE
;
133 /* reload exec_ registers if repeat is required */
134 if (s
->chan
[ch
].next_config
& CONFIG_REPEAT
) {
135 s
->chan
[ch
].exec_bytes
= bytes
;
136 s
->chan
[ch
].exec_dst
= dst
;
137 s
->chan
[ch
].exec_src
= src
;
143 s
->chan
[ch
].state
= DMA_CHAN_STATE_ERROR
;
144 s
->chan
[ch
].control
|= CONTROL_ERR
;
148 static inline void sifive_pdma_update_irq(SiFivePDMAState
*s
, int ch
)
150 bool done_ie
, err_ie
;
152 done_ie
= !!(s
->chan
[ch
].control
& CONTROL_DONE_IE
);
153 err_ie
= !!(s
->chan
[ch
].control
& CONTROL_ERR_IE
);
155 if (done_ie
&& (s
->chan
[ch
].control
& CONTROL_DONE
)) {
156 qemu_irq_raise(s
->irq
[ch
* 2]);
158 qemu_irq_lower(s
->irq
[ch
* 2]);
161 if (err_ie
&& (s
->chan
[ch
].control
& CONTROL_ERR
)) {
162 qemu_irq_raise(s
->irq
[ch
* 2 + 1]);
164 qemu_irq_lower(s
->irq
[ch
* 2 + 1]);
167 s
->chan
[ch
].state
= DMA_CHAN_STATE_IDLE
;
170 static uint64_t sifive_pdma_read(void *opaque
, hwaddr offset
, unsigned size
)
172 SiFivePDMAState
*s
= opaque
;
173 int ch
= SIFIVE_PDMA_CHAN_NO(offset
);
176 if (ch
>= SIFIVE_PDMA_CHANS
) {
177 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Invalid channel no %d\n",
185 val
= s
->chan
[ch
].control
;
187 case DMA_NEXT_CONFIG
:
188 val
= s
->chan
[ch
].next_config
;
191 val
= s
->chan
[ch
].next_bytes
;
194 val
= s
->chan
[ch
].next_dst
;
197 val
= s
->chan
[ch
].next_src
;
199 case DMA_EXEC_CONFIG
:
200 val
= s
->chan
[ch
].exec_config
;
203 val
= s
->chan
[ch
].exec_bytes
;
206 val
= s
->chan
[ch
].exec_dst
;
209 val
= s
->chan
[ch
].exec_src
;
212 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Bad offset 0x%" HWADDR_PRIX
"\n",
220 static void sifive_pdma_write(void *opaque
, hwaddr offset
,
221 uint64_t value
, unsigned size
)
223 SiFivePDMAState
*s
= opaque
;
224 int ch
= SIFIVE_PDMA_CHAN_NO(offset
);
226 if (ch
>= SIFIVE_PDMA_CHANS
) {
227 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Invalid channel no %d\n",
235 s
->chan
[ch
].control
= value
;
237 if (value
& CONTROL_RUN
) {
238 sifive_pdma_run(s
, ch
);
241 sifive_pdma_update_irq(s
, ch
);
243 case DMA_NEXT_CONFIG
:
244 s
->chan
[ch
].next_config
= value
;
247 s
->chan
[ch
].next_bytes
= value
;
250 s
->chan
[ch
].next_dst
= value
;
253 s
->chan
[ch
].next_src
= value
;
255 case DMA_EXEC_CONFIG
:
259 /* these are read-only registers */
262 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Bad offset 0x%" HWADDR_PRIX
"\n",
268 static const MemoryRegionOps sifive_pdma_ops
= {
269 .read
= sifive_pdma_read
,
270 .write
= sifive_pdma_write
,
271 .endianness
= DEVICE_LITTLE_ENDIAN
,
272 /* there are 32-bit and 64-bit wide registers */
274 .min_access_size
= 4,
275 .max_access_size
= 8,
279 static void sifive_pdma_realize(DeviceState
*dev
, Error
**errp
)
281 SiFivePDMAState
*s
= SIFIVE_PDMA(dev
);
284 memory_region_init_io(&s
->iomem
, OBJECT(dev
), &sifive_pdma_ops
, s
,
285 TYPE_SIFIVE_PDMA
, SIFIVE_PDMA_REG_SIZE
);
286 sysbus_init_mmio(SYS_BUS_DEVICE(dev
), &s
->iomem
);
288 for (i
= 0; i
< SIFIVE_PDMA_IRQS
; i
++) {
289 sysbus_init_irq(SYS_BUS_DEVICE(dev
), &s
->irq
[i
]);
293 static void sifive_pdma_class_init(ObjectClass
*klass
, void *data
)
295 DeviceClass
*dc
= DEVICE_CLASS(klass
);
297 dc
->desc
= "SiFive Platform DMA controller";
298 dc
->realize
= sifive_pdma_realize
;
301 static const TypeInfo sifive_pdma_info
= {
302 .name
= TYPE_SIFIVE_PDMA
,
303 .parent
= TYPE_SYS_BUS_DEVICE
,
304 .instance_size
= sizeof(SiFivePDMAState
),
305 .class_init
= sifive_pdma_class_init
,
308 static void sifive_pdma_register_types(void)
310 type_register_static(&sifive_pdma_info
);
313 type_init(sifive_pdma_register_types
)