@samitouri / QOSamiQemu / commits / 54bc6c4f15

hw/dma: add K230 gsdma

K230 GSDMA includes SDMA (System Direct Memory Access) and GDMA (Graphic Direct Memory Access). In this patch, add SDMA for k230 board. The following features have not been implemented: 1. axi protocol related 2. channel arbitration 3. lower power mode SDMA supports transfer data between memory, in which case SDMA is the controller. It also supports transfer data to decomp_gzip and caching it through SRAM. In this case, decomp_gzip is the controller, which controls SDMA through handshake signals. According to "K230 Technical Reference Manual v0.3.1" section 2.5.2. https://download.kendryte.com/developer/k230/HDK/K230%E7%A1%AC%E4%BB%B6%E6%96%87%E6%A1%A3/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf This commit includes: - K230 SDMA (System Direct Memory Access) model (k230_gsdma.c, k230_gsdma.h) - GSDMA trace log (trace-events) - Kconfig and meson.build - update MAINTAINERS Signed-off-by: Tao Ding <dingtao0430@163.com> Reviewed-by: Chao Liu <chao.liu@processmission.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Junze Cao <caojunze424@gmail.com> Message-ID: <20260808062227.66961-2-dingtao0430@163.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Tao Ding committed Aug 8, 2026 at 14:22 UTC 54bc6c4f15f91aee9acf43c36cd3d6c91d31320e
6 files changed +693
MAINTAINERS
+2
@@ -1847,9 +1847,11 @@ F: docs/system/riscv/k230.rst
1847 F: hw/misc/k230_ddr.c
1848 F: hw/riscv/k230.c
1849 F: hw/watchdog/k230_wdt.c
1850 +F: hw/dma/k230_gsdma.c
1851 F: include/hw/misc/k230_ddr.h
1852 F: include/hw/riscv/k230.h
1853 F: include/hw/watchdog/k230_wdt.h
1854 +F: include/hw/dma/k230_gsdma.h
1855 F: tests/functional/riscv64/test_k230.py
1856 F: tests/qtest/k230-ddr-test.c
1857 F: tests/qtest/k230-wdt-test.c
hw/dma/Kconfig
+3
@@ -30,3 +30,6 @@ config SIFIVE_PDMA
30 config XLNX_CSU_DMA
31 bool
32 select REGISTER
33 +
34 +config K230_GSDMA
35 + bool
\ No newline at end of file
hw/dma/k230_gsdma.c new
+551
@@ -0,0 +1,551 @@
1 +/*
2 + * Kendryte K230 GSDMA
3 + *
4 + * Copyright (c) 2026 Tao Ding <dingtao0430@163.com>
5 + *
6 + * SPDX-License-Identifier: GPL-2.0-or-later
7 + *
8 + * GSDMA includes SDMA (System Direct Memory Access, K230 TRM section 10.2) and
9 + * GDMA (Graphic Direct Memory Access, K230 TRM section 2.5.2).
10 + */
11 +
12 +#include "qemu/osdep.h"
13 +#include "qemu/bitops.h"
14 +#include "qemu/log.h"
15 +#include "qemu/module.h"
16 +#include "migration/vmstate.h"
17 +#include "system/address-spaces.h"
18 +#include "hw/dma/k230_gsdma.h"
19 +#include "hw/core/irq.h"
20 +#include "trace.h"
21 +
22 +static void k230_gsdma_update_irq(K230GSDMAState *s)
23 +{
24 + qemu_set_irq(s->irq, !!(s->dma_int_stat & ~s->dma_int_mask));
25 +}
26 +
27 +static bool k230_gsdma_decomp_enabled(K230GSDMAState *s)
28 +{
29 + /* Only sdma channel 0 has decomp enable flag */
30 + return !!(s->channels[0].cfg & K230_GSDMA_CH0_CFG_DECOMP_CTRL_EN);
31 +}
32 +
33 +static bool k230_gsdma_read_sdma_llt(hwaddr addr, K230GSDMALLT *llt)
34 +{
35 + bool ok = address_space_read(&address_space_memory, addr,
36 + MEMTXATTRS_UNSPECIFIED, llt,
37 + sizeof(*llt)) == MEMTX_OK;
38 +
39 + if (ok) {
40 + trace_k230_gsdma_read_sdma_llt(addr, le32_to_cpu(llt->cfg),
41 + le32_to_cpu(llt->src_addr),
42 + le32_to_cpu(llt->line_size),
43 + le32_to_cpu(llt->line_cfg),
44 + le32_to_cpu(llt->dst_addr),
45 + le32_to_cpu(llt->next_llt_addr));
46 + } else {
47 + trace_k230_gsdma_read_sdma_llt_failed(addr);
48 + }
49 +
50 + return ok;
51 +}
52 +
53 +static unsigned int k230_gsdma_usr_data_size(uint32_t cfg)
54 +{
55 + /* decode usr_dat_size in CH_CFG register */
56 + switch (extract32(cfg, K230_GSDMA_CH_CFG_USR_DATA_SIZE_SHIFT, 2)) {
57 + case 0:
58 + return 1;
59 + case 1:
60 + return 2;
61 + default:
62 + return 4;
63 + }
64 +}
65 +
66 +static void k230_gsdma_convert_endian(uint8_t *buf, uint32_t len, uint32_t cfg)
67 +{
68 + unsigned int mode = extract32(cfg,
69 + K230_GSDMA_CH_CFG_DAT_ENDIAN_SHIFT, 2);
70 + unsigned int unit_size;
71 + unsigned int offset;
72 +
73 + if (mode == 0) {
74 + return;
75 + }
76 +
77 + unit_size = 1U << mode;
78 + for (offset = 0; offset + unit_size <= len; offset += unit_size) {
79 + unsigned int i;
80 +
81 + for (i = 0; i < unit_size / 2; i++) {
82 + uint8_t tmp = buf[offset + i];
83 +
84 + buf[offset + i] = buf[offset + unit_size - i - 1];
85 + buf[offset + unit_size - i - 1] = tmp;
86 + }
87 + }
88 +}
89 +
90 +static bool k230_gsdma_transfer_llt(K230GSDMAChannel *c, const K230GSDMALLT *llt)
91 +{
92 + uint32_t llt_cfg = le32_to_cpu(llt->cfg);
93 + hwaddr src = le32_to_cpu(llt->src_addr);
94 + hwaddr dst = le32_to_cpu(llt->dst_addr);
95 + uint32_t line_size = le32_to_cpu(llt->line_size);
96 + uint32_t line_cfg = le32_to_cpu(llt->line_cfg);
97 + /* Number of lines required for 2d mode */
98 + uint32_t line_num =
99 + (llt_cfg & K230_GSDMA_LLT_2D_MODE) ? extract32(line_cfg, 0, 16) : 1;
100 + /* Stride line size required for 2d mode */
101 + uint32_t line_space = extract32(line_cfg, 16, 16);
102 +
103 + bool dat_mode = c->cfg & K230_GSDMA_CH_CFG_DAT_MODE;
104 + bool src_fixed = c->cfg & K230_GSDMA_CH_CFG_SRC_FIXED;
105 + bool dst_fixed = c->cfg & K230_GSDMA_CH_CFG_DST_FIXED;
106 +
107 + uint8_t buf[8]; /* K230 sdma axi data width is 64-bit */
108 + uint8_t fill[4]; /* Usr data is 32-bit*/
109 + unsigned int fill_len = k230_gsdma_usr_data_size(c->cfg);
110 + uint32_t i;
111 +
112 + memcpy(fill, &c->usr_data, sizeof(fill));
113 +
114 + for (i = 0; i < line_num; i++) {
115 + uint32_t remaining = line_size;
116 + hwaddr line_src = src;
117 + hwaddr line_dst = dst;
118 +
119 + while (remaining) {
120 + uint32_t chunk = MIN(remaining, (uint32_t)sizeof(buf));
121 +
122 + if (dat_mode) {
123 + uint32_t j;
124 +
125 + for (j = 0; j < chunk; j++) {
126 + buf[j] = fill[j % fill_len];
127 + }
128 + } else if (address_space_read(&address_space_memory, line_src,
129 + MEMTXATTRS_UNSPECIFIED, buf,
130 + chunk) != MEMTX_OK) {
131 + return false;
132 + }
133 +
134 + k230_gsdma_convert_endian(buf, chunk, c->cfg);
135 +
136 + if (address_space_write(&address_space_memory, line_dst,
137 + MEMTXATTRS_UNSPECIFIED, buf,
138 + chunk) != MEMTX_OK) {
139 + return false;
140 + }
141 +
142 + if (!dat_mode && !src_fixed) {
143 + line_src += chunk;
144 + }
145 + if (!dst_fixed) {
146 + line_dst += chunk;
147 + }
148 + remaining -= chunk;
149 + }
150 +
151 + if (!dat_mode && !src_fixed) {
152 + if (llt_cfg & K230_GSDMA_LLT_2D_MODE) { /* 2d mode */
153 + src += line_size + line_space;
154 + } else {
155 + src += line_size;
156 + }
157 + }
158 +
159 + if (!dst_fixed) {
160 + dst += line_size;
161 + }
162 + }
163 +
164 + return true;
165 +}
166 +
167 +static void k230_gsdma_sdma_set_idle(K230GSDMAChannel *c)
168 +{
169 + c->status &= ~(K230_GSDMA_SDMA_STATUS_BUSY | K230_GSDMA_SDMA_STATUS_PAUSE);
170 + c->next_llt = 0;
171 +}
172 +
173 +static void k230_gsdma_sdma_set_paused(K230GSDMAChannel *c, hwaddr next_llt)
174 +{
175 + c->status &= ~K230_GSDMA_SDMA_STATUS_BUSY;
176 + c->status |= K230_GSDMA_SDMA_STATUS_PAUSE;
177 + c->next_llt = next_llt;
178 +}
179 +
180 +static void k230_gsdma_run_sdma(K230GSDMAState *s, unsigned int ch, hwaddr addr)
181 +{
182 + K230GSDMAChannel *c = &s->channels[ch];
183 +
184 + c->status &= ~K230_GSDMA_SDMA_STATUS_PAUSE;
185 + c->status |= K230_GSDMA_SDMA_STATUS_BUSY;
186 + c->next_llt = 0;
187 + c->current_llt = addr;
188 +
189 + while (addr) {
190 + K230GSDMALLT llt;
191 + uint32_t cfg;
192 + hwaddr next;
193 +
194 + if (!k230_gsdma_read_sdma_llt(addr, &llt)) {
195 + k230_gsdma_sdma_set_idle(c);
196 + return;
197 + }
198 +
199 + cfg = le32_to_cpu(llt.cfg);
200 + next = le32_to_cpu(llt.next_llt_addr);
201 + c->current_llt = addr;
202 +
203 + if (!k230_gsdma_transfer_llt(c, &llt)) {
204 + k230_gsdma_sdma_set_idle(c);
205 + return;
206 + }
207 +
208 + if (cfg & K230_GSDMA_LLT_NODE_INTR) {
209 + s->dma_int_stat |= K230_GSDMA_SDMA_ITEM_INT(ch);
210 + }
211 +
212 + if (cfg & K230_GSDMA_LLT_PAUSE) {
213 + s->dma_int_stat |= K230_GSDMA_SDMA_PAUSE_INT(ch);
214 + k230_gsdma_sdma_set_paused(c, next);
215 + k230_gsdma_update_irq(s);
216 + return;
217 + }
218 +
219 + addr = next;
220 + }
221 +
222 + s->dma_int_stat |= K230_GSDMA_SDMA_DONE_INT(ch);
223 + s->dma_ch_en &= ~BIT(ch);
224 + k230_gsdma_sdma_set_idle(c);
225 + k230_gsdma_update_irq(s);
226 +}
227 +
228 +/* Decomp gzip request step sdma */
229 +static void k230_gsdma_step_sdma(K230GSDMAState *s, unsigned int ch, hwaddr addr)
230 +{
231 + K230GSDMAChannel *c = &s->channels[ch];
232 + K230GSDMALLT llt;
233 + uint32_t cfg;
234 + hwaddr next;
235 +
236 + if (!addr || !k230_gsdma_read_sdma_llt(addr, &llt)) {
237 + k230_gsdma_sdma_set_idle(c);
238 + return;
239 + }
240 +
241 + cfg = le32_to_cpu(llt.cfg);
242 + next = le32_to_cpu(llt.next_llt_addr);
243 +
244 + c->status |= K230_GSDMA_SDMA_STATUS_BUSY;
245 + c->status &= ~K230_GSDMA_SDMA_STATUS_PAUSE;
246 + c->current_llt = addr;
247 +
248 + if (!k230_gsdma_transfer_llt(c, &llt)) {
249 + k230_gsdma_sdma_set_idle(c);
250 + return;
251 + }
252 +
253 + if (cfg & K230_GSDMA_LLT_NODE_INTR) {
254 + s->dma_int_stat |= K230_GSDMA_SDMA_ITEM_INT(ch);
255 + }
256 +
257 + c->status &= ~K230_GSDMA_SDMA_STATUS_BUSY;
258 + c->next_llt = next;
259 + if (next == 0) {
260 + s->dma_int_stat |= K230_GSDMA_SDMA_DONE_INT(ch);
261 + s->dma_ch_en &= ~BIT(ch);
262 + }
263 +
264 + k230_gsdma_update_irq(s);
265 +}
266 +
267 +static const VMStateDescription vmstate_k230_gsdma_channel = {
268 + .name = "k230.gsdma.channel",
269 + .version_id = 1,
270 + .minimum_version_id = 1,
271 + .fields = (const VMStateField[]) {
272 + VMSTATE_UINT32(ctl, K230GSDMAChannel),
273 + VMSTATE_UINT32(status, K230GSDMAChannel),
274 + VMSTATE_UINT32(cfg, K230GSDMAChannel),
275 + VMSTATE_UINT32(usr_data, K230GSDMAChannel),
276 + VMSTATE_UINT32(llt_saddr, K230GSDMAChannel),
277 + VMSTATE_UINT32(current_llt, K230GSDMAChannel),
278 + VMSTATE_UINT32(next_llt, K230GSDMAChannel),
279 + VMSTATE_END_OF_LIST()
280 + }
281 +};
282 +
283 +static const VMStateDescription vmstate_k230_gsdma = {
284 + .name = "k230.gsdma",
285 + .version_id = 1,
286 + .minimum_version_id = 1,
287 + .fields = (const VMStateField[]) {
288 + VMSTATE_UINT32(dma_ch_en, K230GSDMAState),
289 + VMSTATE_UINT32(dma_int_mask, K230GSDMAState),
290 + VMSTATE_UINT32(dma_int_stat, K230GSDMAState),
291 + VMSTATE_UINT32(dma_cfg, K230GSDMAState),
292 + VMSTATE_UINT32(dma_weight, K230GSDMAState),
293 + VMSTATE_STRUCT_ARRAY(channels, K230GSDMAState,
294 + K230_GSDMA_NUM_SDMA_CHANNELS, 2,
295 + vmstate_k230_gsdma_channel, K230GSDMAChannel),
296 + VMSTATE_END_OF_LIST()
297 + }
298 +};
299 +
300 +static uint64_t k230_gsdma_read(void *opaque, hwaddr addr, unsigned int size)
301 +{
302 + K230GSDMAState *s = K230_GSDMA(opaque);
303 + unsigned int ch;
304 + hwaddr ch_off;
305 + uint64_t ret = 0;
306 +
307 + switch (addr) {
308 + case K230_GSDMA_DMA_CH_EN:
309 + ret = s->dma_ch_en;
310 + break;
311 + case K230_GSDMA_DMA_INT_MASK:
312 + ret = s->dma_int_mask;
313 + break;
314 + case K230_GSDMA_DMA_INT_STAT:
315 + ret = s->dma_int_stat;
316 + break;
317 + case K230_GSDMA_DMA_CFG:
318 + ret = s->dma_cfg;
319 + break;
320 + case K230_GSDMA_DMA_WEIGHT:
321 + ret = s->dma_weight;
322 + break;
323 + default:
324 + if (addr < K230_GSDMA_CH_BASE) {
325 + qemu_log_mask(LOG_GUEST_ERROR,
326 + "%s: not implement gdma at offset 0x%" HWADDR_PRIx
327 + "\n", __func__, addr);
328 + }
329 + break;
330 + }
331 +
332 + ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE;
333 + ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE;
334 + if (ch < K230_GSDMA_NUM_SDMA_CHANNELS) {
335 + switch (ch_off) {
336 + case K230_GSDMA_CH_CTL:
337 + break;
338 + case K230_GSDMA_CH_STATUS:
339 + ret = s->channels[ch].status;
340 + break;
341 + case K230_GSDMA_CH_CFG:
342 + ret = s->channels[ch].cfg;
343 + break;
344 + case K230_GSDMA_CH_USR_DATA:
345 + ret = s->channels[ch].usr_data;
346 + break;
347 + case K230_GSDMA_CH_LLT_SADDR:
348 + ret = s->channels[ch].llt_saddr;
349 + break;
350 + case K230_GSDMA_CH_CURRENT_LLT:
351 + ret = s->channels[ch].current_llt;
352 + break;
353 + default:
354 + break;
355 + }
356 + }
357 +
358 + trace_k230_gsdma_read(addr, size, ret);
359 + return ret;
360 +}
361 +
362 +static void k230_gsdma_write_channel(K230GSDMAState *s, unsigned int ch,
363 + hwaddr ch_off, uint32_t value)
364 +{
365 + K230GSDMAChannel *c = &s->channels[ch];
366 + bool handshake_mode = ch < 2 && k230_gsdma_decomp_enabled(s);
367 +
368 + switch (ch_off) {
369 + case K230_GSDMA_CH_CTL:
370 + c->ctl = value;
371 + if ((value & K230_GSDMA_CTL_STOP) != 0) {
372 + c->started = false;
373 + k230_gsdma_sdma_set_idle(c);
374 + break;
375 + }
376 + if ((value & K230_GSDMA_CTL_RESUME) != 0 &&
377 + (c->status & K230_GSDMA_SDMA_STATUS_PAUSE) && c->next_llt != 0) {
378 + k230_gsdma_run_sdma(s, ch, c->next_llt);
379 + break;
380 + }
381 + if (handshake_mode && (value & K230_GSDMA_CTL_START) != 0) {
382 + c->started = true;
383 + c->status &= ~(K230_GSDMA_SDMA_STATUS_BUSY |
384 + K230_GSDMA_SDMA_STATUS_PAUSE);
385 + c->current_llt = 0;
386 + c->next_llt = 0;
387 + break;
388 + }
389 + if ((value & K230_GSDMA_CTL_START) != 0 &&
390 + (s->dma_ch_en & BIT(ch)) && c->llt_saddr != 0) {
391 + c->started = true;
392 + k230_gsdma_run_sdma(s, ch, c->llt_saddr);
393 + }
394 + break;
395 + case K230_GSDMA_CH_CFG:
396 + c->cfg = value;
397 + break;
398 + case K230_GSDMA_CH_USR_DATA:
399 + c->usr_data = value;
400 + break;
401 + case K230_GSDMA_CH_LLT_SADDR:
402 + c->llt_saddr = value;
403 + break;
404 + case K230_GSDMA_CH_CURRENT_LLT:
405 + break;
406 + default:
407 + break;
408 + }
409 +}
410 +
411 +static void k230_gsdma_write(void *opaque, hwaddr addr,
412 + uint64_t value, unsigned int size)
413 +{
414 + K230GSDMAState *s = K230_GSDMA(opaque);
415 + unsigned int ch;
416 + hwaddr ch_off;
417 + uint32_t v = value;
418 +
419 + trace_k230_gsdma_write(addr, size, value);
420 +
421 + switch (addr) {
422 + case K230_GSDMA_DMA_CH_EN:
423 + s->dma_ch_en = v & K230_GSDMA_DMA_CH_EN_MASK;
424 + return;
425 + case K230_GSDMA_DMA_INT_MASK:
426 + s->dma_int_mask = v;
427 + k230_gsdma_update_irq(s);
428 + return;
429 + case K230_GSDMA_DMA_INT_STAT:
430 + s->dma_int_stat &= ~v;
431 + k230_gsdma_update_irq(s);
432 + return;
433 + case K230_GSDMA_DMA_CFG:
434 + s->dma_cfg = v;
435 + return;
436 + case K230_GSDMA_DMA_WEIGHT:
437 + s->dma_weight = v & 0x00ffffff;
438 + return;
439 + default:
440 + break;
441 + }
442 +
443 + if (addr < K230_GSDMA_CH_BASE) {
444 + qemu_log_mask(LOG_GUEST_ERROR,
445 + "%s: not implement gdma at offset 0x%" HWADDR_PRIx
446 + "\n", __func__, addr);
447 + return;
448 + }
449 +
450 + ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE;
451 + ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE;
452 + if (ch >= K230_GSDMA_NUM_SDMA_CHANNELS) {
453 + return;
454 + }
455 +
456 + k230_gsdma_write_channel(s, ch, ch_off, v);
457 +}
458 +
459 +static void k230_gsdma_handle_signal(void *opaque, int n, int level)
460 +{
461 + K230GSDMAState *s = opaque;
462 + K230GSDMAChannel *c;
463 + hwaddr addr;
464 + unsigned int ch;
465 +
466 + if (!level || n == K230_GSDMA_GPIO_DECOMP_CTRL_EN) {
467 + return;
468 + }
469 +
470 + ch = n - 1;
471 +
472 + c = &s->channels[ch];
473 + if (!k230_gsdma_decomp_enabled(s) || !(s->dma_ch_en & BIT(ch)) || !c->started) {
474 + return;
475 + }
476 +
477 + if (c->current_llt == 0) {
478 + addr = c->llt_saddr;
479 + } else {
480 + addr = c->next_llt;
481 + }
482 + if (!addr) {
483 + return;
484 + }
485 +
486 + k230_gsdma_step_sdma(s, ch, addr);
487 + qemu_set_irq(s->handshake_out[n - 1], 1);
488 + qemu_set_irq(s->handshake_out[n - 1], 0);
489 +}
490 +
491 +static const MemoryRegionOps k230_gsdma_ops = {
492 + .read = k230_gsdma_read,
493 + .write = k230_gsdma_write,
494 + .endianness = DEVICE_LITTLE_ENDIAN,
495 + .impl.min_access_size = 4,
496 + .impl.max_access_size = 4,
497 + .valid.min_access_size = 4,
498 + .valid.max_access_size = 4,
499 +};
500 +
501 +static void k230_gsdma_reset_hold(Object *obj, ResetType type)
502 +{
503 + K230GSDMAState *s = K230_GSDMA(obj);
504 +
505 + memset(s->channels, 0, sizeof(s->channels));
506 + s->dma_ch_en = 0;
507 + s->dma_int_mask = 0;
508 + s->dma_int_stat = 0;
509 + s->dma_cfg = K230_GSDMA_DMA_CFG_RESET;
510 + s->dma_weight = 0;
511 +}
512 +
513 +static void k230_gsdma_realize(DeviceState *dev, Error **errp)
514 +{
515 + K230GSDMAState *s = K230_GSDMA(dev);
516 + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
517 +
518 + memory_region_init_io(&s->iomem, OBJECT(dev), &k230_gsdma_ops, s,
519 + TYPE_K230_GSDMA, K230_GSDMA_MMIO_SIZE);
520 + sysbus_init_mmio(sbd, &s->iomem);
521 + sysbus_init_irq(sbd, &s->irq);
522 + qdev_init_gpio_in(DEVICE(dev), k230_gsdma_handle_signal,
523 + K230_GSDMA_NUM_GPIOS_IN);
524 + qdev_init_gpio_out(DEVICE(dev), s->handshake_out,
525 + K230_GSDMA_NUM_GPIOS_OUT);
526 +}
527 +
528 +static void k230_gsdma_class_init(ObjectClass *klass, const void *data)
529 +{
530 + DeviceClass *dc = DEVICE_CLASS(klass);
531 + ResettableClass *rc = RESETTABLE_CLASS(klass);
532 +
533 + dc->realize = k230_gsdma_realize;
534 + rc->phases.hold = k230_gsdma_reset_hold;
535 + dc->vmsd = &vmstate_k230_gsdma;
536 + dc->desc = "Kendryte K230 GSDMA";
537 +}
538 +
539 +static const TypeInfo k230_gsdma_info = {
540 + .name = TYPE_K230_GSDMA,
541 + .parent = TYPE_SYS_BUS_DEVICE,
542 + .instance_size = sizeof(K230GSDMAState),
543 + .class_init = k230_gsdma_class_init,
544 +};
545 +
546 +static void k230_gsdma_register_types(void)
547 +{
548 + type_register_static(&k230_gsdma_info);
549 +}
550 +
551 +type_init(k230_gsdma_register_types)
hw/dma/meson.build
+1
@@ -12,3 +12,4 @@ system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c'))
12 system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c'))
13 system_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c'))
14 system_ss.add(when: 'CONFIG_XLNX_CSU_DMA', if_true: files('xlnx_csu_dma.c'))
15 +system_ss.add(when: 'CONFIG_K230_GSDMA', if_true: files('k230_gsdma.c'))
hw/dma/trace-events
+6
@@ -47,3 +47,9 @@ pl330_iomem_read(uint32_t addr, uint32_t data) "addr: 0x%08"PRIx32" data: 0x%08"
47
48 # xilinx_axidma.c
49 xilinx_axidma_loading_desc_fail(uint32_t res) "error:%u"
50 +
51 +# k230_gsdma.c
52 +k230_gsdma_read(uint64_t addr, unsigned int size, uint64_t data) "K230 GSDMA read: [0x%"PRIx64"] size %u -> 0x%"PRIx64
53 +k230_gsdma_write(uint64_t addr, unsigned int size, uint64_t data) "K230 GSDMA write: [0x%"PRIx64"] size %u <- 0x%"PRIx64
54 +k230_gsdma_read_sdma_llt(uint64_t addr, uint32_t cfg, uint32_t src_addr, uint32_t line_size, uint32_t line_cfg, uint32_t dst_addr, uint32_t next_llt_addr) "K230 GSDMA read SDMA LLT: addr=0x%"PRIx64" cfg=0x%"PRIx32" src=0x%"PRIx32" line_size=0x%"PRIx32" line_cfg=0x%"PRIx32" dst=0x%"PRIx32" next=0x%"PRIx32
55 +k230_gsdma_read_sdma_llt_failed(uint64_t addr) "K230 GSDMA read SDMA LLT failed: addr=0x%"PRIx64
include/hw/dma/k230_gsdma.h new
+130
@@ -0,0 +1,130 @@
1 +/*
2 + * K230 GSDMA
3 + *
4 + * Copyright (c) 2026 Tao Ding <dingtao0430@163.com>
5 + *
6 + * SPDX-License-Identifier: GPL-2.0-or-later
7 + */
8 +
9 +#ifndef HW_DMA_K230_GSDMA_H
10 +#define HW_DMA_K230_GSDMA_H
11 +
12 +#include "hw/core/sysbus.h"
13 +
14 +#define TYPE_K230_GSDMA "riscv.k230.gsdma"
15 +OBJECT_DECLARE_SIMPLE_TYPE(K230GSDMAState, K230_GSDMA)
16 +
17 +#define K230_GSDMA_MMIO_SIZE 0x4000
18 +#define K230_GSDMA_NUM_SDMA_CHANNELS 4
19 +
20 +#define K230_GSDMA_CH_STRIDE 0x30
21 +#define K230_GSDMA_CH_BASE 0x50
22 +
23 +/* K230 SDMA request input */
24 +enum {
25 + K230_GSDMA_GPIO_DECOMP_CTRL_EN,
26 + K230_GSDMA_GPIO_DMA_WRITE_REQ,
27 + K230_GSDMA_GPIO_DMA_READ_REQ,
28 + K230_GSDMA_NUM_GPIOS_IN,
29 +};
30 +
31 +/* K230 SDMA ACK output */
32 +enum {
33 + K230_GSDMA_GPIO_DMA_WRITE_ACK,
34 + K230_GSDMA_GPIO_DMA_READ_ACK,
35 + K230_GSDMA_NUM_GPIOS_OUT,
36 +};
37 +
38 +/* K230 GSDMA Registers Map */
39 +#define K230_GSDMA_DMA_CH_EN 0x00
40 +#define K230_GSDMA_DMA_INT_MASK 0x04
41 +#define K230_GSDMA_DMA_INT_STAT 0x08
42 +#define K230_GSDMA_DMA_CFG 0x0c
43 +#define K230_GSDMA_GDMA_CTRL 0x10
44 +#define K230_GSDMA_GDMA_LLI_BASE 0x14
45 +#define K230_GSDMA_GDMA_CH_CNT0 0x18
46 +#define K230_GSDMA_GDMA_CH_CNT_LAST 0x34
47 +#define K230_GSDMA_GDMA_CURRENT_LLT 0x38
48 +#define K230_GSDMA_DMA_WEIGHT 0x48
49 +
50 +/* K230 GSDMA SDMA Channel Register Map */
51 +#define K230_GSDMA_CH_CTL 0x00
52 +#define K230_GSDMA_CH_STATUS 0x04
53 +#define K230_GSDMA_CH_CFG 0x08
54 +#define K230_GSDMA_CH_USR_DATA 0x0c
55 +#define K230_GSDMA_CH_LLT_SADDR 0x10
56 +#define K230_GSDMA_CH_CURRENT_LLT 0x14
57 +
58 +/* K230 SDMA Control bit */
59 +#define K230_GSDMA_CTL_START BIT(0)
60 +#define K230_GSDMA_CTL_STOP BIT(1)
61 +#define K230_GSDMA_CTL_RESUME BIT(2)
62 +
63 +/* K230 SDMA States bit */
64 +#define K230_GSDMA_SDMA_STATUS_BUSY BIT(0)
65 +#define K230_GSDMA_SDMA_STATUS_PAUSE BIT(1)
66 +
67 +/* K230 SDMA Interrupt bit */
68 +#define K230_GSDMA_SDMA_DONE_INT(ch) BIT(ch)
69 +#define K230_GSDMA_SDMA_ITEM_INT(ch) BIT((ch) + 4)
70 +#define K230_GSDMA_SDMA_PAUSE_INT(ch) BIT((ch) + 8)
71 +
72 +
73 +#define K230_GSDMA_DMA_CH_EN_MASK MAKE_64BIT_MASK(0, 5)
74 +#define K230_GSDMA_DMA_CFG_RESET 0x000007ff
75 +
76 +/* K230 SDMA Linked List bit */
77 +#define K230_GSDMA_LLT_2D_MODE BIT(28)
78 +#define K230_GSDMA_LLT_PAUSE BIT(29)
79 +#define K230_GSDMA_LLT_NODE_INTR BIT(30)
80 +#define K230_GSDMA_GDMA_LLT_GCH_SHIFT 16
81 +#define K230_GSDMA_GDMA_LLT_GCH_MASK 0x7
82 +#define K230_GSDMA_CH_CFG_DAT_MODE BIT(0)
83 +#define K230_GSDMA_CH_CFG_USR_DATA_SIZE_SHIFT 1
84 +#define K230_GSDMA_CH_CFG_USR_DATA_SIZE_MASK 0x3
85 +#define K230_GSDMA_CH_CFG_DAT_ENDIAN_SHIFT 4
86 +#define K230_GSDMA_CH_CFG_DAT_ENDIAN_MASK 0x3
87 +#define K230_GSDMA_CH_CFG_SRC_FIXED BIT(8)
88 +#define K230_GSDMA_CH_CFG_DST_FIXED BIT(9)
89 +#define K230_GSDMA_CH0_CFG_DECOMP_CTRL_EN BIT(10)
90 +
91 +/* K230 SDMA channel state */
92 +typedef struct K230GSDMAChannel {
93 + uint32_t ctl;
94 + uint32_t status;
95 + uint32_t cfg;
96 + uint32_t usr_data;
97 + uint32_t llt_saddr;
98 + uint32_t current_llt;
99 + uint32_t next_llt;
100 + bool started;
101 +} K230GSDMAChannel;
102 +
103 +/* K230 SDMA Linked List */
104 +typedef struct K230GSDMALLT {
105 + uint32_t cfg;
106 + uint32_t src_addr;
107 + uint32_t line_size;
108 + uint32_t line_cfg;
109 + uint32_t dst_addr;
110 + uint32_t next_llt_addr;
111 +} K230GSDMALLT;
112 +
113 +/* K230 GSDMA state */
114 +struct K230GSDMAState {
115 + SysBusDevice parent_obj;
116 +
117 + MemoryRegion iomem;
118 + qemu_irq irq;
119 + qemu_irq handshake_out[K230_GSDMA_NUM_GPIOS_OUT];
120 +
121 + uint32_t dma_ch_en;
122 + uint32_t dma_int_mask;
123 + uint32_t dma_int_stat;
124 + uint32_t dma_cfg;
125 + uint32_t dma_weight;
126 +
127 + K230GSDMAChannel channels[K230_GSDMA_NUM_SDMA_CHANNELS];
128 +};
129 +
130 +#endif