From: Chao Liu <chao.liu@processmission.com>
To: Tao Ding <dingtao0430@163.com>
Cc: qemu-devel@nongnu.org, qemu-riscv@nongnu.org,
pbonzini@redhat.com, palmer@dabbelt.com,
alistair.francis@wdc.com, liwei1518@gmail.com,
daniel.barboza@oss.qualcomm.com, zhiwei_liu@linux.alibaba.com,
farosas@suse.de, lvivier@redhat.com,
pierrick.bouvier@oss.qualcomm.com, caojunze424@gmail.com
Subject: Re: [PATCH v2 1/7] hw/dma: add K230 gsdma
Date: Fri, 7 Aug 2026 12:46:26 +0800 [thread overview]
Message-ID: <anViwt5s3g16eCKG@ChaodeMacBook-Pro.local> (raw)
In-Reply-To: <20260727155702.36484-2-dingtao0430@163.com>
On Mon, Jul 27, 2026 at 11:56:56PM +0800, Tao Ding wrote:
> K230 GSDMA includes SDMA (System Direct Memory Access) and GDMA (Graphic Direct Memory Access).
line length exceeds 76 characters.
> 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>
Thanks,
Chao
> ---
> In patchv1, the reviewer identified some missing features and bugs, which have been fixed.
> bug:
> src_addr should not increment in 2d-mode and src_fixed
> feature:
> data endian conversion
> enhance:
> use new reset interface
>
> MAINTAINERS | 2 +
> hw/dma/Kconfig | 3 +
> hw/dma/k230_gsdma.c | 562 ++++++++++++++++++++++++++++++++++++
> hw/dma/meson.build | 1 +
> hw/dma/trace-events | 6 +
> include/hw/dma/k230_gsdma.h | 130 +++++++++
> 6 files changed, 704 insertions(+)
> create mode 100644 hw/dma/k230_gsdma.c
> create mode 100644 include/hw/dma/k230_gsdma.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a28935c898..49c8013d5f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1829,8 +1829,10 @@ S: Maintained
> F: docs/system/riscv/k230.rst
> F: hw/riscv/k230.c
> F: hw/watchdog/k230_wdt.c
> +F: hw/dma/k230_gsdma.c
> F: include/hw/riscv/k230.h
> F: include/hw/watchdog/k230_wdt.h
> +F: include/hw/dma/k230_gsdma.h
> F: tests/functional/riscv64/test_k230.py
> F: tests/qtest/k230-wdt-test.c
>
> diff --git a/hw/dma/Kconfig b/hw/dma/Kconfig
> index 98fbb1bb04..0a23e7d7b8 100644
> --- a/hw/dma/Kconfig
> +++ b/hw/dma/Kconfig
> @@ -30,3 +30,6 @@ config SIFIVE_PDMA
> config XLNX_CSU_DMA
> bool
> select REGISTER
> +
> +config K230_GSDMA
> + bool
> \ No newline at end of file
> diff --git a/hw/dma/k230_gsdma.c b/hw/dma/k230_gsdma.c
> new file mode 100644
> index 0000000000..032733047c
> --- /dev/null
> +++ b/hw/dma/k230_gsdma.c
> @@ -0,0 +1,562 @@
> +/*
> + * Kendryte K230 GSDMA
> + *
> + * Copyright (c) 2026 Tao Ding <dingtao0430@163.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * GSDMA includes SDMA (System Direct Memory Access, K230 TRM section 10.2) and
> + * GDMA (Graphic Direct Memory Access, K230 TRM section 2.5.2).
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/bitops.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "migration/vmstate.h"
> +#include "system/address-spaces.h"
> +#include "hw/dma/k230_gsdma.h"
> +#include "hw/core/irq.h"
> +#include "trace.h"
> +
> +static void k230_gsdma_update_irq(K230GSDMAState *s)
> +{
> + qemu_set_irq(s->irq, !!(s->dma_int_stat & ~s->dma_int_mask));
> +}
> +
> +static bool k230_gsdma_decomp_enabled(K230GSDMAState *s)
> +{
> + /* Only sdma channel 0 has decomp enable flag */
> + return !!(s->channels[0].cfg & K230_GSDMA_CH0_CFG_DECOMP_CTRL_EN);
> +}
> +
> +static bool k230_gsdma_read_sdma_llt(hwaddr addr, K230GSDMALLT *llt)
> +{
> + bool ok = address_space_read(&address_space_memory, addr,
> + MEMTXATTRS_UNSPECIFIED, llt,
> + sizeof(*llt)) == MEMTX_OK;
> +
> + if (ok) {
> + trace_k230_gsdma_read_sdma_llt(addr, le32_to_cpu(llt->cfg),
> + le32_to_cpu(llt->src_addr),
> + le32_to_cpu(llt->line_size),
> + le32_to_cpu(llt->line_cfg),
> + le32_to_cpu(llt->dst_addr),
> + le32_to_cpu(llt->next_llt_addr));
> + } else {
> + trace_k230_gsdma_read_sdma_llt_failed(addr);
> + }
> +
> + return ok;
> +}
> +
> +static unsigned int k230_gsdma_usr_data_size(uint32_t cfg)
> +{
> + /* decode usr_dat_size in CH_CFG register */
> + switch (extract32(cfg, K230_GSDMA_CH_CFG_USR_DATA_SIZE_SHIFT, 2)) {
> + case 0:
> + return 1;
> + case 1:
> + return 2;
> + default:
> + return 4;
> + }
> +}
> +
> +static void k230_gsdma_convert_endian(uint8_t *buf, uint32_t len, uint32_t cfg)
> +{
> + unsigned int mode = extract32(cfg,
> + K230_GSDMA_CH_CFG_DAT_ENDIAN_SHIFT, 2);
> + unsigned int unit_size;
> + unsigned int offset;
> +
> + if (mode == 0) {
> + return;
> + }
> +
> + unit_size = 1U << mode;
> + for (offset = 0; offset + unit_size <= len; offset += unit_size) {
> + unsigned int i;
> +
> + for (i = 0; i < unit_size / 2; i++) {
> + uint8_t tmp = buf[offset + i];
> +
> + buf[offset + i] = buf[offset + unit_size - i - 1];
> + buf[offset + unit_size - i - 1] = tmp;
> + }
> + }
> +}
> +
> +static bool k230_gsdma_transfer_llt(K230GSDMAChannel *c, const K230GSDMALLT *llt)
> +{
> + uint32_t llt_cfg = le32_to_cpu(llt->cfg);
> + hwaddr src = le32_to_cpu(llt->src_addr);
> + hwaddr dst = le32_to_cpu(llt->dst_addr);
> + uint32_t line_size = le32_to_cpu(llt->line_size);
> + uint32_t line_cfg = le32_to_cpu(llt->line_cfg);
> + /* Number of lines required for 2d mode */
> + uint32_t line_num =
> + (llt_cfg & K230_GSDMA_LLT_2D_MODE) ? extract32(line_cfg, 0, 16) : 1;
> + /* Stride line size required for 2d mode */
> + uint32_t line_space = extract32(line_cfg, 16, 16);
> +
> + bool dat_mode = c->cfg & K230_GSDMA_CH_CFG_DAT_MODE;
> + bool src_fixed = c->cfg & K230_GSDMA_CH_CFG_SRC_FIXED;
> + bool dst_fixed = c->cfg & K230_GSDMA_CH_CFG_DST_FIXED;
> +
> + uint8_t buf[8]; /* K230 sdma axi data width is 64-bit */
> + uint8_t fill[4]; /* Usr data is 32-bit*/
> + unsigned int fill_len = k230_gsdma_usr_data_size(c->cfg);
> + uint32_t i;
> +
> + memcpy(fill, &c->usr_data, sizeof(fill));
> +
> + for (i = 0; i < line_num; i++) {
> + uint32_t remaining = line_size;
> + hwaddr line_src = src;
> + hwaddr line_dst = dst;
> +
> + while (remaining) {
> + uint32_t chunk = MIN(remaining, (uint32_t)sizeof(buf));
> +
> + if (dat_mode) {
> + uint32_t j;
> +
> + for (j = 0; j < chunk; j++) {
> + buf[j] = fill[j % fill_len];
> + }
> + } else if (address_space_read(&address_space_memory, line_src,
> + MEMTXATTRS_UNSPECIFIED, buf,
> + chunk) != MEMTX_OK) {
> + return false;
> + }
> +
> + k230_gsdma_convert_endian(buf, chunk, c->cfg);
> +
> + if (address_space_write(&address_space_memory, line_dst,
> + MEMTXATTRS_UNSPECIFIED, buf,
> + chunk) != MEMTX_OK) {
> + return false;
> + }
> +
> + if (!dat_mode && !src_fixed) {
> + line_src += chunk;
> + }
> + if (!dst_fixed) {
> + line_dst += chunk;
> + }
> + remaining -= chunk;
> + }
> +
> + if (!dat_mode && !src_fixed) {
> + if (llt_cfg & K230_GSDMA_LLT_2D_MODE) { /* 2d mode */
> + src += line_size + line_space;
> + } else {
> + src += line_size;
> + }
> + }
> +
> + if (!dst_fixed) {
> + dst += line_size;
> + }
> + }
> +
> + return true;
> +}
> +
> +static void k230_gsdma_sdma_set_idle(K230GSDMAChannel *c)
> +{
> + c->status &= ~(K230_GSDMA_SDMA_STATUS_BUSY | K230_GSDMA_SDMA_STATUS_PAUSE);
> + c->next_llt = 0;
> +}
> +
> +static void k230_gsdma_sdma_set_paused(K230GSDMAChannel *c, hwaddr next_llt)
> +{
> + c->status &= ~K230_GSDMA_SDMA_STATUS_BUSY;
> + c->status |= K230_GSDMA_SDMA_STATUS_PAUSE;
> + c->next_llt = next_llt;
> +}
> +
> +static void k230_gsdma_run_sdma(K230GSDMAState *s, unsigned int ch, hwaddr addr)
> +{
> + K230GSDMAChannel *c = &s->channels[ch];
> +
> + c->status &= ~K230_GSDMA_SDMA_STATUS_PAUSE;
> + c->status |= K230_GSDMA_SDMA_STATUS_BUSY;
> + c->next_llt = 0;
> + c->current_llt = addr;
> +
> + while (addr) {
> + K230GSDMALLT llt;
> + uint32_t cfg;
> + hwaddr next;
> +
> + if (!k230_gsdma_read_sdma_llt(addr, &llt)) {
> + k230_gsdma_sdma_set_idle(c);
> + return;
> + }
> +
> + cfg = le32_to_cpu(llt.cfg);
> + next = le32_to_cpu(llt.next_llt_addr);
> + c->current_llt = addr;
> +
> + if (!k230_gsdma_transfer_llt(c, &llt)) {
> + k230_gsdma_sdma_set_idle(c);
> + return;
> + }
> +
> + if (cfg & K230_GSDMA_LLT_NODE_INTR) {
> + s->dma_int_stat |= K230_GSDMA_SDMA_ITEM_INT(ch);
> + }
> +
> + if (cfg & K230_GSDMA_LLT_PAUSE) {
> + s->dma_int_stat |= K230_GSDMA_SDMA_PAUSE_INT(ch);
> + k230_gsdma_sdma_set_paused(c, next);
> + k230_gsdma_update_irq(s);
> + return;
> + }
> +
> + addr = next;
> + }
> +
> + s->dma_int_stat |= K230_GSDMA_SDMA_DONE_INT(ch);
> + s->dma_ch_en &= ~BIT(ch);
> + k230_gsdma_sdma_set_idle(c);
> + k230_gsdma_update_irq(s);
> +}
> +
> +/* Decomp gzip request step sdma */
> +static void k230_gsdma_step_sdma(K230GSDMAState *s, unsigned int ch, hwaddr addr)
> +{
> + K230GSDMAChannel *c = &s->channels[ch];
> + K230GSDMALLT llt;
> + uint32_t cfg;
> + hwaddr next;
> +
> + if (!addr || !k230_gsdma_read_sdma_llt(addr, &llt)) {
> + k230_gsdma_sdma_set_idle(c);
> + return;
> + }
> +
> + cfg = le32_to_cpu(llt.cfg);
> + next = le32_to_cpu(llt.next_llt_addr);
> +
> + c->status |= K230_GSDMA_SDMA_STATUS_BUSY;
> + c->status &= ~K230_GSDMA_SDMA_STATUS_PAUSE;
> + c->current_llt = addr;
> +
> + if (!k230_gsdma_transfer_llt(c, &llt)) {
> + k230_gsdma_sdma_set_idle(c);
> + return;
> + }
> +
> + if (cfg & K230_GSDMA_LLT_NODE_INTR) {
> + s->dma_int_stat |= K230_GSDMA_SDMA_ITEM_INT(ch);
> + }
> +
> + c->status &= ~K230_GSDMA_SDMA_STATUS_BUSY;
> + c->next_llt = next;
> + if (next == 0) {
> + s->dma_int_stat |= K230_GSDMA_SDMA_DONE_INT(ch);
> + s->dma_ch_en &= ~BIT(ch);
> + }
> +
> + k230_gsdma_update_irq(s);
> +}
> +
> +static const VMStateDescription vmstate_k230_gsdma_channel = {
> + .name = "k230.gsdma.channel",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (const VMStateField[]) {
> + VMSTATE_UINT32(ctl, K230GSDMAChannel),
> + VMSTATE_UINT32(status, K230GSDMAChannel),
> + VMSTATE_UINT32(cfg, K230GSDMAChannel),
> + VMSTATE_UINT32(usr_data, K230GSDMAChannel),
> + VMSTATE_UINT32(llt_saddr, K230GSDMAChannel),
> + VMSTATE_UINT32(current_llt, K230GSDMAChannel),
> + VMSTATE_UINT32(next_llt, K230GSDMAChannel),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static const VMStateDescription vmstate_k230_gsdma = {
> + .name = "k230.gsdma",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (const VMStateField[]) {
> + VMSTATE_UINT32(dma_ch_en, K230GSDMAState),
> + VMSTATE_UINT32(dma_int_mask, K230GSDMAState),
> + VMSTATE_UINT32(dma_int_stat, K230GSDMAState),
> + VMSTATE_UINT32(dma_cfg, K230GSDMAState),
> + VMSTATE_UINT32(dma_weight, K230GSDMAState),
> + VMSTATE_STRUCT_ARRAY(channels, K230GSDMAState,
> + K230_GSDMA_NUM_SDMA_CHANNELS, 2,
> + vmstate_k230_gsdma_channel, K230GSDMAChannel),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static uint64_t k230_gsdma_read(void *opaque, hwaddr addr, unsigned int size)
> +{
> + K230GSDMAState *s = K230_GSDMA(opaque);
> + unsigned int ch;
> + hwaddr ch_off;
> + uint64_t ret = 0;
> +
> + switch (addr) {
> + case K230_GSDMA_DMA_CH_EN:
> + ret = s->dma_ch_en;
> + break;
> + case K230_GSDMA_DMA_INT_MASK:
> + ret = s->dma_int_mask;
> + break;
> + case K230_GSDMA_DMA_INT_STAT:
> + ret = s->dma_int_stat;
> + break;
> + case K230_GSDMA_DMA_CFG:
> + ret = s->dma_cfg;
> + break;
> + case K230_GSDMA_GDMA_CTRL:
> + case K230_GSDMA_GDMA_LLI_BASE:
> + case K230_GSDMA_GDMA_CURRENT_LLT:
> + case K230_GSDMA_GDMA_CH_CNT0 ... K230_GSDMA_GDMA_CH_CNT_LAST:
> + break;
> + case K230_GSDMA_DMA_WEIGHT:
> + ret = s->dma_weight;
> + break;
> + default:
> + break;
> + }
> +
> + ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE;
> + ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE;
> + if (ch < K230_GSDMA_NUM_SDMA_CHANNELS) {
> + switch (ch_off) {
> + case K230_GSDMA_CH_CTL:
> + break;
> + case K230_GSDMA_CH_STATUS:
> + ret = s->channels[ch].status;
> + break;
> + case K230_GSDMA_CH_CFG:
> + ret = s->channels[ch].cfg;
> + break;
> + case K230_GSDMA_CH_USR_DATA:
> + ret = s->channels[ch].usr_data;
> + break;
> + case K230_GSDMA_CH_LLT_SADDR:
> + ret = s->channels[ch].llt_saddr;
> + break;
> + case K230_GSDMA_CH_CURRENT_LLT:
> + ret = s->channels[ch].current_llt;
> + break;
> + default:
> + break;
> + }
> + }
> +
> + trace_k230_gsdma_read(addr, size, ret);
> + return ret;
> +}
> +
> +static void k230_gsdma_write_gdma(K230GSDMAState *s, hwaddr addr, uint32_t value)
> +{
> + switch (addr) {
> + case K230_GSDMA_GDMA_CTRL:
> + case K230_GSDMA_GDMA_LLI_BASE:
> + case K230_GSDMA_GDMA_CURRENT_LLT:
> + case K230_GSDMA_GDMA_CH_CNT0 ... K230_GSDMA_GDMA_CH_CNT_LAST:
> + return;
> + default:
> + return;
> + }
> +}
> +
> +static void k230_gsdma_write_channel(K230GSDMAState *s, unsigned int ch,
> + hwaddr ch_off, uint32_t value)
> +{
> + K230GSDMAChannel *c = &s->channels[ch];
> + bool handshake_mode = ch < 2 && k230_gsdma_decomp_enabled(s);
> +
> + switch (ch_off) {
> + case K230_GSDMA_CH_CTL:
> + c->ctl = value;
> + if ((value & K230_GSDMA_CTL_STOP) != 0) {
> + c->started = false;
> + k230_gsdma_sdma_set_idle(c);
> + break;
> + }
> + if ((value & K230_GSDMA_CTL_RESUME) != 0 &&
> + (c->status & K230_GSDMA_SDMA_STATUS_PAUSE) && c->next_llt != 0) {
> + k230_gsdma_run_sdma(s, ch, c->next_llt);
> + break;
> + }
> + if (handshake_mode && (value & K230_GSDMA_CTL_START) != 0) {
> + c->started = true;
> + c->status &= ~(K230_GSDMA_SDMA_STATUS_BUSY |
> + K230_GSDMA_SDMA_STATUS_PAUSE);
> + c->current_llt = 0;
> + c->next_llt = 0;
> + break;
> + }
> + if ((value & K230_GSDMA_CTL_START) != 0 &&
> + (s->dma_ch_en & BIT(ch)) && c->llt_saddr != 0) {
> + c->started = true;
> + k230_gsdma_run_sdma(s, ch, c->llt_saddr);
> + }
> + break;
> + case K230_GSDMA_CH_CFG:
> + c->cfg = value;
> + break;
> + case K230_GSDMA_CH_USR_DATA:
> + c->usr_data = value;
> + break;
> + case K230_GSDMA_CH_LLT_SADDR:
> + c->llt_saddr = value;
> + break;
> + case K230_GSDMA_CH_CURRENT_LLT:
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static void k230_gsdma_write(void *opaque, hwaddr addr,
> + uint64_t value, unsigned int size)
> +{
> + K230GSDMAState *s = K230_GSDMA(opaque);
> + unsigned int ch;
> + hwaddr ch_off;
> + uint32_t v = value;
> +
> + trace_k230_gsdma_write(addr, size, value);
> +
> + switch (addr) {
> + case K230_GSDMA_DMA_CH_EN:
> + s->dma_ch_en = v & K230_GSDMA_DMA_CH_EN_MASK;
> + return;
> + case K230_GSDMA_DMA_INT_MASK:
> + s->dma_int_mask = v;
> + k230_gsdma_update_irq(s);
> + return;
> + case K230_GSDMA_DMA_INT_STAT:
> + s->dma_int_stat &= ~v;
> + k230_gsdma_update_irq(s);
> + return;
> + case K230_GSDMA_DMA_CFG:
> + s->dma_cfg = v;
> + return;
> + case K230_GSDMA_DMA_WEIGHT:
> + s->dma_weight = v & 0x00ffffff;
> + return;
> + default:
> + break;
> + }
> +
> + if (addr < K230_GSDMA_CH_BASE) {
> + k230_gsdma_write_gdma(s, addr, v);
> + return;
> + }
> +
> + ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE;
> + ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE;
> + if (ch >= K230_GSDMA_NUM_SDMA_CHANNELS) {
> + return;
> + }
> +
> + k230_gsdma_write_channel(s, ch, ch_off, v);
> +}
> +
> +static void k230_gsdma_handle_signal(void *opaque, int n, int level)
> +{
> + K230GSDMAState *s = opaque;
> + K230GSDMAChannel *c;
> + hwaddr addr;
> + unsigned int ch;
> +
> + if (!level || n == K230_GSDMA_GPIO_DECOMP_CTRL_EN) {
> + return;
> + }
> +
> + ch = n - 1;
> +
> + c = &s->channels[ch];
> + if (!k230_gsdma_decomp_enabled(s) || !(s->dma_ch_en & BIT(ch)) || !c->started) {
> + return;
> + }
> +
> + if (c->current_llt == 0) {
> + addr = c->llt_saddr;
> + } else {
> + addr = c->next_llt;
> + }
> + if (!addr) {
> + return;
> + }
> +
> + k230_gsdma_step_sdma(s, ch, addr);
> + qemu_set_irq(s->handshake_out[n - 1], 1);
> + qemu_set_irq(s->handshake_out[n - 1], 0);
> +}
> +
> +static const MemoryRegionOps k230_gsdma_ops = {
> + .read = k230_gsdma_read,
> + .write = k230_gsdma_write,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> + .impl.min_access_size = 4,
> + .impl.max_access_size = 4,
> + .valid.min_access_size = 4,
> + .valid.max_access_size = 4,
> +};
> +
> +static void k230_gsdma_reset_hold(Object *obj, ResetType type)
> +{
> + K230GSDMAState *s = K230_GSDMA(obj);
> +
> + memset(s->channels, 0, sizeof(s->channels));
> + s->dma_ch_en = 0;
> + s->dma_int_mask = 0;
> + s->dma_int_stat = 0;
> + s->dma_cfg = K230_GSDMA_DMA_CFG_RESET;
> + s->dma_weight = 0;
> +}
> +
> +static void k230_gsdma_realize(DeviceState *dev, Error **errp)
> +{
> + K230GSDMAState *s = K230_GSDMA(dev);
> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +
> + memory_region_init_io(&s->iomem, OBJECT(dev), &k230_gsdma_ops, s,
> + TYPE_K230_GSDMA, K230_GSDMA_MMIO_SIZE);
> + sysbus_init_mmio(sbd, &s->iomem);
> + sysbus_init_irq(sbd, &s->irq);
> + qdev_init_gpio_in(DEVICE(dev), k230_gsdma_handle_signal,
> + K230_GSDMA_NUM_GPIOS_IN);
> + qdev_init_gpio_out(DEVICE(dev), s->handshake_out,
> + K230_GSDMA_NUM_GPIOS_OUT);
> +}
> +
> +static void k230_gsdma_class_init(ObjectClass *klass, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + ResettableClass *rc = RESETTABLE_CLASS(klass);
> +
> + dc->realize = k230_gsdma_realize;
> + rc->phases.hold = k230_gsdma_reset_hold;
> + dc->vmsd = &vmstate_k230_gsdma;
> + dc->desc = "Kendryte K230 GSDMA";
> +}
> +
> +static const TypeInfo k230_gsdma_info = {
> + .name = TYPE_K230_GSDMA,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(K230GSDMAState),
> + .class_init = k230_gsdma_class_init,
> +};
> +
> +static void k230_gsdma_register_types(void)
> +{
> + type_register_static(&k230_gsdma_info);
> +}
> +
> +type_init(k230_gsdma_register_types)
> diff --git a/hw/dma/meson.build b/hw/dma/meson.build
> index cc7810beb8..45db5e7357 100644
> --- a/hw/dma/meson.build
> +++ b/hw/dma/meson.build
> @@ -12,3 +12,4 @@ system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c'))
> system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c'))
> system_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c'))
> system_ss.add(when: 'CONFIG_XLNX_CSU_DMA', if_true: files('xlnx_csu_dma.c'))
> +system_ss.add(when: 'CONFIG_K230_GSDMA', if_true: files('k230_gsdma.c'))
> diff --git a/hw/dma/trace-events b/hw/dma/trace-events
> index 4c09790f9a..a494755b5a 100644
> --- a/hw/dma/trace-events
> +++ b/hw/dma/trace-events
> @@ -47,3 +47,9 @@ pl330_iomem_read(uint32_t addr, uint32_t data) "addr: 0x%08"PRIx32" data: 0x%08"
>
> # xilinx_axidma.c
> xilinx_axidma_loading_desc_fail(uint32_t res) "error:%u"
> +
> +# k230_gsdma.c
> +k230_gsdma_read(uint64_t addr, unsigned int size, uint64_t data) "K230 GSDMA read: [0x%"PRIx64"] size %u -> 0x%"PRIx64
> +k230_gsdma_write(uint64_t addr, unsigned int size, uint64_t data) "K230 GSDMA write: [0x%"PRIx64"] size %u <- 0x%"PRIx64
> +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
> +k230_gsdma_read_sdma_llt_failed(uint64_t addr) "K230 GSDMA read SDMA LLT failed: addr=0x%"PRIx64
> diff --git a/include/hw/dma/k230_gsdma.h b/include/hw/dma/k230_gsdma.h
> new file mode 100644
> index 0000000000..629cce29f8
> --- /dev/null
> +++ b/include/hw/dma/k230_gsdma.h
> @@ -0,0 +1,130 @@
> +/*
> + * K230 GSDMA
> + *
> + * Copyright (c) 2026 Tao Ding <dingtao0430@163.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef HW_DMA_K230_GSDMA_H
> +#define HW_DMA_K230_GSDMA_H
> +
> +#include "hw/core/sysbus.h"
> +
> +#define TYPE_K230_GSDMA "riscv.k230.gsdma"
> +OBJECT_DECLARE_SIMPLE_TYPE(K230GSDMAState, K230_GSDMA)
> +
> +#define K230_GSDMA_MMIO_SIZE 0x4000
> +#define K230_GSDMA_NUM_SDMA_CHANNELS 4
> +
> +#define K230_GSDMA_CH_STRIDE 0x30
> +#define K230_GSDMA_CH_BASE 0x50
> +
> +/* K230 SDMA request input */
> +enum {
> + K230_GSDMA_GPIO_DECOMP_CTRL_EN,
> + K230_GSDMA_GPIO_DMA_WRITE_REQ,
> + K230_GSDMA_GPIO_DMA_READ_REQ,
> + K230_GSDMA_NUM_GPIOS_IN,
> +};
> +
> +/* K230 SDMA ACK output */
> +enum {
> + K230_GSDMA_GPIO_DMA_WRITE_ACK,
> + K230_GSDMA_GPIO_DMA_READ_ACK,
> + K230_GSDMA_NUM_GPIOS_OUT,
> +};
> +
> +/* K230 GSDMA Registers Map */
> +#define K230_GSDMA_DMA_CH_EN 0x00
> +#define K230_GSDMA_DMA_INT_MASK 0x04
> +#define K230_GSDMA_DMA_INT_STAT 0x08
> +#define K230_GSDMA_DMA_CFG 0x0c
> +#define K230_GSDMA_GDMA_CTRL 0x10
> +#define K230_GSDMA_GDMA_LLI_BASE 0x14
> +#define K230_GSDMA_GDMA_CH_CNT0 0x18
> +#define K230_GSDMA_GDMA_CH_CNT_LAST 0x34
> +#define K230_GSDMA_GDMA_CURRENT_LLT 0x38
> +#define K230_GSDMA_DMA_WEIGHT 0x48
> +
> +/* K230 GSDMA SDMA Channel Register Map */
> +#define K230_GSDMA_CH_CTL 0x00
> +#define K230_GSDMA_CH_STATUS 0x04
> +#define K230_GSDMA_CH_CFG 0x08
> +#define K230_GSDMA_CH_USR_DATA 0x0c
> +#define K230_GSDMA_CH_LLT_SADDR 0x10
> +#define K230_GSDMA_CH_CURRENT_LLT 0x14
> +
> +/* K230 SDMA Control bit */
> +#define K230_GSDMA_CTL_START BIT(0)
> +#define K230_GSDMA_CTL_STOP BIT(1)
> +#define K230_GSDMA_CTL_RESUME BIT(2)
> +
> +/* K230 SDMA States bit */
> +#define K230_GSDMA_SDMA_STATUS_BUSY BIT(0)
> +#define K230_GSDMA_SDMA_STATUS_PAUSE BIT(1)
> +
> +/* K230 SDMA Interrupt bit */
> +#define K230_GSDMA_SDMA_DONE_INT(ch) BIT(ch)
> +#define K230_GSDMA_SDMA_ITEM_INT(ch) BIT((ch) + 4)
> +#define K230_GSDMA_SDMA_PAUSE_INT(ch) BIT((ch) + 8)
> +
> +
> +#define K230_GSDMA_DMA_CH_EN_MASK MAKE_64BIT_MASK(0, 5)
> +#define K230_GSDMA_DMA_CFG_RESET 0x000007ff
> +
> +/* K230 SDMA Linked List bit */
> +#define K230_GSDMA_LLT_2D_MODE BIT(28)
> +#define K230_GSDMA_LLT_PAUSE BIT(29)
> +#define K230_GSDMA_LLT_NODE_INTR BIT(30)
> +#define K230_GSDMA_GDMA_LLT_GCH_SHIFT 16
> +#define K230_GSDMA_GDMA_LLT_GCH_MASK 0x7
> +#define K230_GSDMA_CH_CFG_DAT_MODE BIT(0)
> +#define K230_GSDMA_CH_CFG_USR_DATA_SIZE_SHIFT 1
> +#define K230_GSDMA_CH_CFG_USR_DATA_SIZE_MASK 0x3
> +#define K230_GSDMA_CH_CFG_DAT_ENDIAN_SHIFT 4
> +#define K230_GSDMA_CH_CFG_DAT_ENDIAN_MASK 0x3
> +#define K230_GSDMA_CH_CFG_SRC_FIXED BIT(8)
> +#define K230_GSDMA_CH_CFG_DST_FIXED BIT(9)
> +#define K230_GSDMA_CH0_CFG_DECOMP_CTRL_EN BIT(10)
> +
> +/* K230 SDMA channel state */
> +typedef struct K230GSDMAChannel {
> + uint32_t ctl;
> + uint32_t status;
> + uint32_t cfg;
> + uint32_t usr_data;
> + uint32_t llt_saddr;
> + uint32_t current_llt;
> + uint32_t next_llt;
> + bool started;
> +} K230GSDMAChannel;
> +
> +/* K230 SDMA Linked List */
> +typedef struct K230GSDMALLT {
> + uint32_t cfg;
> + uint32_t src_addr;
> + uint32_t line_size;
> + uint32_t line_cfg;
> + uint32_t dst_addr;
> + uint32_t next_llt_addr;
> +} K230GSDMALLT;
> +
> +/* K230 GSDMA state */
> +struct K230GSDMAState {
> + SysBusDevice parent_obj;
> +
> + MemoryRegion iomem;
> + qemu_irq irq;
> + qemu_irq handshake_out[K230_GSDMA_NUM_GPIOS_OUT];
> +
> + uint32_t dma_ch_en;
> + uint32_t dma_int_mask;
> + uint32_t dma_int_stat;
> + uint32_t dma_cfg;
> + uint32_t dma_weight;
> +
> + K230GSDMAChannel channels[K230_GSDMA_NUM_SDMA_CHANNELS];
> +};
> +
> +#endif
> --
> 2.43.0
>
next prev parent reply other threads:[~2026-08-07 4:47 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-27 15:56 [PATCH v2 0/7] K230: add gsdma and decomp_gzip Tao Ding
2026-07-27 15:56 ` [PATCH v2 1/7] hw/dma: add K230 gsdma Tao Ding
2026-08-06 11:34 ` Daniel Henrique Barboza
2026-08-07 4:46 ` Chao Liu [this message]
2026-07-27 15:56 ` [PATCH v2 2/7] hw/riscv: k230: add gsdma in K230 board Tao Ding
2026-08-06 11:34 ` Daniel Henrique Barboza
2026-07-27 15:56 ` [PATCH v2 3/7] tests/qtest: add test for K230 gsdma Tao Ding
2026-08-06 11:36 ` Daniel Henrique Barboza
2026-07-27 15:56 ` [PATCH v2 4/7] hw/misc: add K230 decomp gzip Tao Ding
2026-08-06 11:47 ` Daniel Henrique Barboza
2026-07-27 15:57 ` [PATCH v2 5/7] hw/riscv: k230: add decomp gzip in K230 board Tao Ding
2026-08-06 11:48 ` Daniel Henrique Barboza
2026-07-27 15:57 ` [PATCH v2 6/7] tests/qtest: add test for K230 decomp gzip Tao Ding
2026-08-06 12:14 ` Daniel Henrique Barboza
2026-07-27 15:57 ` [PATCH v2 7/7] hw/riscv: k230: add a noc stub region in K230 board Tao Ding
2026-08-06 12:15 ` Daniel Henrique Barboza
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=anViwt5s3g16eCKG@ChaodeMacBook-Pro.local \
--to=chao.liu@processmission.com \
--cc=alistair.francis@wdc.com \
--cc=caojunze424@gmail.com \
--cc=daniel.barboza@oss.qualcomm.com \
--cc=dingtao0430@163.com \
--cc=farosas@suse.de \
--cc=liwei1518@gmail.com \
--cc=lvivier@redhat.com \
--cc=palmer@dabbelt.com \
--cc=pbonzini@redhat.com \
--cc=pierrick.bouvier@oss.qualcomm.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=zhiwei_liu@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.