master
c 490 lines 13.7 KB
Raw
1 /*
2 * SiFive Platform DMA emulation
3 *
4 * Copyright (c) 2020 Wind River Systems, Inc.
5 *
6 * Author:
7 * Bin Meng <bin.meng@windriver.com>
8 *
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.
13 *
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.
18 *
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/>.
21 */
22
23 #include "qemu/osdep.h"
24 #include "qemu/bitops.h"
25 #include "qemu/log.h"
26 #include "qapi/error.h"
27 #include "hw/core/irq.h"
28 #include "hw/core/qdev-properties.h"
29 #include "hw/core/sysbus.h"
30 #include "exec/cpu-common.h"
31 #include "migration/vmstate.h"
32 #include "system/dma.h"
33 #include "system/physmem.h"
34 #include "hw/dma/sifive_pdma.h"
35
36 #define DMA_CONTROL 0x000
37 #define CONTROL_CLAIM BIT(0)
38 #define CONTROL_RUN BIT(1)
39 #define CONTROL_DONE_IE BIT(14)
40 #define CONTROL_ERR_IE BIT(15)
41 #define CONTROL_DONE BIT(30)
42 #define CONTROL_ERR BIT(31)
43
44 #define DMA_NEXT_CONFIG 0x004
45 #define CONFIG_REPEAT BIT(2)
46 #define CONFIG_ORDER BIT(3)
47 #define CONFIG_WRSZ_SHIFT 24
48 #define CONFIG_RDSZ_SHIFT 28
49 #define CONFIG_SZ_MASK 0xf
50
51 #define DMA_NEXT_BYTES 0x008
52 #define DMA_NEXT_DST 0x010
53 #define DMA_NEXT_SRC 0x018
54 #define DMA_EXEC_CONFIG 0x104
55 #define DMA_EXEC_BYTES 0x108
56 #define DMA_EXEC_DST 0x110
57 #define DMA_EXEC_SRC 0x118
58
59 /*
60 * FU540/FU740 docs are incorrect with NextConfig.wsize/rsize reset values.
61 * The reset values tested on Unleashed/Unmatched boards are 6 instead of 0.
62 */
63 #define CONFIG_WRSZ_DEFAULT 6
64 #define CONFIG_RDSZ_DEFAULT 6
65
66 enum dma_chan_state {
67 DMA_CHAN_STATE_IDLE,
68 DMA_CHAN_STATE_STARTED,
69 DMA_CHAN_STATE_ERROR,
70 DMA_CHAN_STATE_DONE
71 };
72
73 static void sifive_pdma_run(SiFivePDMAState *s, int ch)
74 {
75 uint64_t bytes = s->chan[ch].next_bytes;
76 uint64_t dst = s->chan[ch].next_dst;
77 uint64_t src = s->chan[ch].next_src;
78 uint32_t config = s->chan[ch].next_config;
79 int wsize, rsize, size, remainder;
80 uint8_t buf[64];
81 int n;
82
83 /* do nothing if bytes to transfer is zero */
84 if (!bytes) {
85 goto done;
86 }
87
88 /*
89 * The manual does not describe how the hardware behaviors when
90 * config.wsize and config.rsize are given different values.
91 * A common case is memory to memory DMA, and in this case they
92 * are normally the same. Abort if this expectation fails.
93 */
94 wsize = (config >> CONFIG_WRSZ_SHIFT) & CONFIG_SZ_MASK;
95 rsize = (config >> CONFIG_RDSZ_SHIFT) & CONFIG_SZ_MASK;
96 if (wsize != rsize) {
97 goto error;
98 }
99
100 /*
101 * Calculate the transaction size
102 *
103 * size field is base 2 logarithm of DMA transaction size,
104 * but there is an upper limit of 64 bytes per transaction.
105 */
106 size = wsize;
107 if (size > 6) {
108 size = 6;
109 }
110 size = 1 << size;
111 remainder = bytes % size;
112
113 /* indicate a DMA transfer is started */
114 s->chan[ch].state = DMA_CHAN_STATE_STARTED;
115 s->chan[ch].control &= ~CONTROL_DONE;
116 s->chan[ch].control &= ~CONTROL_ERR;
117
118 /* load the next_ registers into their exec_ counterparts */
119 s->chan[ch].exec_config = config;
120 s->chan[ch].exec_bytes = bytes;
121 s->chan[ch].exec_dst = dst;
122 s->chan[ch].exec_src = src;
123
124 for (n = 0; n < bytes / size; n++) {
125 physical_memory_read(s->chan[ch].exec_src, buf, size);
126 physical_memory_write(s->chan[ch].exec_dst, buf, size);
127 s->chan[ch].exec_src += size;
128 s->chan[ch].exec_dst += size;
129 s->chan[ch].exec_bytes -= size;
130 }
131
132 if (remainder) {
133 physical_memory_read(s->chan[ch].exec_src, buf, remainder);
134 physical_memory_write(s->chan[ch].exec_dst, buf, remainder);
135 s->chan[ch].exec_src += remainder;
136 s->chan[ch].exec_dst += remainder;
137 s->chan[ch].exec_bytes -= remainder;
138 }
139
140 /* reload exec_ registers if repeat is required */
141 if (s->chan[ch].next_config & CONFIG_REPEAT) {
142 s->chan[ch].exec_bytes = bytes;
143 s->chan[ch].exec_dst = dst;
144 s->chan[ch].exec_src = src;
145 }
146
147 done:
148 /* indicate a DMA transfer is done */
149 s->chan[ch].state = DMA_CHAN_STATE_DONE;
150 s->chan[ch].control &= ~CONTROL_RUN;
151 s->chan[ch].control |= CONTROL_DONE;
152 return;
153
154 error:
155 s->chan[ch].state = DMA_CHAN_STATE_ERROR;
156 s->chan[ch].control |= CONTROL_ERR;
157 s->chan[ch].control |= CONTROL_DONE;
158 }
159
160 static inline void sifive_pdma_update_irq(SiFivePDMAState *s, int ch)
161 {
162 bool done_ie, err_ie;
163
164 done_ie = !!(s->chan[ch].control & CONTROL_DONE_IE);
165 err_ie = !!(s->chan[ch].control & CONTROL_ERR_IE);
166
167 if (done_ie && (s->chan[ch].control & CONTROL_DONE)) {
168 qemu_irq_raise(s->irq[ch * 2]);
169 } else {
170 qemu_irq_lower(s->irq[ch * 2]);
171 }
172
173 if (err_ie && (s->chan[ch].control & CONTROL_ERR)) {
174 qemu_irq_raise(s->irq[ch * 2 + 1]);
175 } else {
176 qemu_irq_lower(s->irq[ch * 2 + 1]);
177 }
178
179 s->chan[ch].state = DMA_CHAN_STATE_IDLE;
180 }
181
182 static uint64_t sifive_pdma_readq(SiFivePDMAState *s, int ch, hwaddr offset)
183 {
184 uint64_t val = 0;
185
186 offset &= 0xfff;
187 switch (offset) {
188 case DMA_NEXT_BYTES:
189 val = s->chan[ch].next_bytes;
190 break;
191 case DMA_NEXT_DST:
192 val = s->chan[ch].next_dst;
193 break;
194 case DMA_NEXT_SRC:
195 val = s->chan[ch].next_src;
196 break;
197 case DMA_EXEC_BYTES:
198 val = s->chan[ch].exec_bytes;
199 break;
200 case DMA_EXEC_DST:
201 val = s->chan[ch].exec_dst;
202 break;
203 case DMA_EXEC_SRC:
204 val = s->chan[ch].exec_src;
205 break;
206 default:
207 qemu_log_mask(LOG_GUEST_ERROR,
208 "%s: Unexpected 64-bit access to 0x%" HWADDR_PRIX "\n",
209 __func__, offset);
210 break;
211 }
212
213 return val;
214 }
215
216 static uint32_t sifive_pdma_readl(SiFivePDMAState *s, int ch, hwaddr offset)
217 {
218 uint32_t val = 0;
219
220 offset &= 0xfff;
221 switch (offset) {
222 case DMA_CONTROL:
223 val = s->chan[ch].control;
224 break;
225 case DMA_NEXT_CONFIG:
226 val = s->chan[ch].next_config;
227 break;
228 case DMA_NEXT_BYTES:
229 val = extract64(s->chan[ch].next_bytes, 0, 32);
230 break;
231 case DMA_NEXT_BYTES + 4:
232 val = extract64(s->chan[ch].next_bytes, 32, 32);
233 break;
234 case DMA_NEXT_DST:
235 val = extract64(s->chan[ch].next_dst, 0, 32);
236 break;
237 case DMA_NEXT_DST + 4:
238 val = extract64(s->chan[ch].next_dst, 32, 32);
239 break;
240 case DMA_NEXT_SRC:
241 val = extract64(s->chan[ch].next_src, 0, 32);
242 break;
243 case DMA_NEXT_SRC + 4:
244 val = extract64(s->chan[ch].next_src, 32, 32);
245 break;
246 case DMA_EXEC_CONFIG:
247 val = s->chan[ch].exec_config;
248 break;
249 case DMA_EXEC_BYTES:
250 val = extract64(s->chan[ch].exec_bytes, 0, 32);
251 break;
252 case DMA_EXEC_BYTES + 4:
253 val = extract64(s->chan[ch].exec_bytes, 32, 32);
254 break;
255 case DMA_EXEC_DST:
256 val = extract64(s->chan[ch].exec_dst, 0, 32);
257 break;
258 case DMA_EXEC_DST + 4:
259 val = extract64(s->chan[ch].exec_dst, 32, 32);
260 break;
261 case DMA_EXEC_SRC:
262 val = extract64(s->chan[ch].exec_src, 0, 32);
263 break;
264 case DMA_EXEC_SRC + 4:
265 val = extract64(s->chan[ch].exec_src, 32, 32);
266 break;
267 default:
268 qemu_log_mask(LOG_GUEST_ERROR,
269 "%s: Unexpected 32-bit access to 0x%" HWADDR_PRIX "\n",
270 __func__, offset);
271 break;
272 }
273
274 return val;
275 }
276
277 static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size)
278 {
279 SiFivePDMAState *s = opaque;
280 int ch = SIFIVE_PDMA_CHAN_NO(offset);
281 uint64_t val = 0;
282
283 if (ch >= SIFIVE_PDMA_CHANS) {
284 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
285 __func__, ch);
286 return 0;
287 }
288
289 switch (size) {
290 case 8:
291 val = sifive_pdma_readq(s, ch, offset);
292 break;
293 case 4:
294 val = sifive_pdma_readl(s, ch, offset);
295 break;
296 default:
297 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid read size %u to PDMA\n",
298 __func__, size);
299 return 0;
300 }
301
302 return val;
303 }
304
305 static void sifive_pdma_writeq(SiFivePDMAState *s, int ch,
306 hwaddr offset, uint64_t value)
307 {
308 offset &= 0xfff;
309 switch (offset) {
310 case DMA_NEXT_BYTES:
311 s->chan[ch].next_bytes = value;
312 break;
313 case DMA_NEXT_DST:
314 s->chan[ch].next_dst = value;
315 break;
316 case DMA_NEXT_SRC:
317 s->chan[ch].next_src = value;
318 break;
319 case DMA_EXEC_BYTES:
320 case DMA_EXEC_DST:
321 case DMA_EXEC_SRC:
322 /* these are read-only registers */
323 break;
324 default:
325 qemu_log_mask(LOG_GUEST_ERROR,
326 "%s: Unexpected 64-bit access to 0x%" HWADDR_PRIX "\n",
327 __func__, offset);
328 break;
329 }
330 }
331
332 static void sifive_pdma_writel(SiFivePDMAState *s, int ch,
333 hwaddr offset, uint32_t value)
334 {
335 bool claimed, run;
336
337 offset &= 0xfff;
338 switch (offset) {
339 case DMA_CONTROL:
340 claimed = !!(s->chan[ch].control & CONTROL_CLAIM);
341 run = !!(s->chan[ch].control & CONTROL_RUN);
342
343 if (!claimed && (value & CONTROL_CLAIM)) {
344 /* reset Next* registers */
345 s->chan[ch].next_config = (CONFIG_RDSZ_DEFAULT << CONFIG_RDSZ_SHIFT) |
346 (CONFIG_WRSZ_DEFAULT << CONFIG_WRSZ_SHIFT);
347 s->chan[ch].next_bytes = 0;
348 s->chan[ch].next_dst = 0;
349 s->chan[ch].next_src = 0;
350 }
351
352 /* claim bit can only be cleared when run is low */
353 if (run && !(value & CONTROL_CLAIM)) {
354 value |= CONTROL_CLAIM;
355 }
356
357 s->chan[ch].control = value;
358
359 /*
360 * If channel was not claimed before run bit is set,
361 * or if the channel is disclaimed when run was low,
362 * DMA won't run.
363 */
364 if (!claimed || (!run && !(value & CONTROL_CLAIM))) {
365 s->chan[ch].control &= ~CONTROL_RUN;
366 return;
367 }
368
369 if (value & CONTROL_RUN) {
370 sifive_pdma_run(s, ch);
371 }
372
373 sifive_pdma_update_irq(s, ch);
374 break;
375 case DMA_NEXT_CONFIG:
376 s->chan[ch].next_config = value;
377 break;
378 case DMA_NEXT_BYTES:
379 s->chan[ch].next_bytes =
380 deposit64(s->chan[ch].next_bytes, 0, 32, value);
381 break;
382 case DMA_NEXT_BYTES + 4:
383 s->chan[ch].next_bytes =
384 deposit64(s->chan[ch].next_bytes, 32, 32, value);
385 break;
386 case DMA_NEXT_DST:
387 s->chan[ch].next_dst = deposit64(s->chan[ch].next_dst, 0, 32, value);
388 break;
389 case DMA_NEXT_DST + 4:
390 s->chan[ch].next_dst = deposit64(s->chan[ch].next_dst, 32, 32, value);
391 break;
392 case DMA_NEXT_SRC:
393 s->chan[ch].next_src = deposit64(s->chan[ch].next_src, 0, 32, value);
394 break;
395 case DMA_NEXT_SRC + 4:
396 s->chan[ch].next_src = deposit64(s->chan[ch].next_src, 32, 32, value);
397 break;
398 case DMA_EXEC_CONFIG:
399 case DMA_EXEC_BYTES:
400 case DMA_EXEC_BYTES + 4:
401 case DMA_EXEC_DST:
402 case DMA_EXEC_DST + 4:
403 case DMA_EXEC_SRC:
404 case DMA_EXEC_SRC + 4:
405 /* these are read-only registers */
406 break;
407 default:
408 qemu_log_mask(LOG_GUEST_ERROR,
409 "%s: Unexpected 32-bit access to 0x%" HWADDR_PRIX "\n",
410 __func__, offset);
411 break;
412 }
413 }
414
415 static void sifive_pdma_write(void *opaque, hwaddr offset,
416 uint64_t value, unsigned size)
417 {
418 SiFivePDMAState *s = opaque;
419 int ch = SIFIVE_PDMA_CHAN_NO(offset);
420
421 if (ch >= SIFIVE_PDMA_CHANS) {
422 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
423 __func__, ch);
424 return;
425 }
426
427 switch (size) {
428 case 8:
429 sifive_pdma_writeq(s, ch, offset, value);
430 break;
431 case 4:
432 sifive_pdma_writel(s, ch, offset, (uint32_t) value);
433 break;
434 default:
435 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid write size %u to PDMA\n",
436 __func__, size);
437 break;
438 }
439 }
440
441 static const MemoryRegionOps sifive_pdma_ops = {
442 .read = sifive_pdma_read,
443 .write = sifive_pdma_write,
444 .endianness = DEVICE_LITTLE_ENDIAN,
445 /* there are 32-bit and 64-bit wide registers */
446 .impl = {
447 .min_access_size = 4,
448 .max_access_size = 8,
449 },
450 .valid = {
451 .min_access_size = 4,
452 .max_access_size = 8,
453 }
454 };
455
456 static void sifive_pdma_realize(DeviceState *dev, Error **errp)
457 {
458 SiFivePDMAState *s = SIFIVE_PDMA(dev);
459 int i;
460
461 memory_region_init_io(&s->iomem, OBJECT(dev), &sifive_pdma_ops, s,
462 TYPE_SIFIVE_PDMA, SIFIVE_PDMA_REG_SIZE);
463 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
464
465 for (i = 0; i < SIFIVE_PDMA_IRQS; i++) {
466 sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
467 }
468 }
469
470 static void sifive_pdma_class_init(ObjectClass *klass, const void *data)
471 {
472 DeviceClass *dc = DEVICE_CLASS(klass);
473
474 dc->desc = "SiFive Platform DMA controller";
475 dc->realize = sifive_pdma_realize;
476 }
477
478 static const TypeInfo sifive_pdma_info = {
479 .name = TYPE_SIFIVE_PDMA,
480 .parent = TYPE_SYS_BUS_DEVICE,
481 .instance_size = sizeof(SiFivePDMAState),
482 .class_init = sifive_pdma_class_init,
483 };
484
485 static void sifive_pdma_register_types(void)
486 {
487 type_register_static(&sifive_pdma_info);
488 }
489
490 type_init(sifive_pdma_register_types)