Decompression accelerator is mainly used to implement hardware GZIP 
decompression function.
According to the k230 SDK, this hardware will be used during the uboot phase to 
decompress 
compressed files. 

Decomp_gzip does not have the ability to access the system bus. 
Therefore, SDMA is required for data transmission. A typical scenario is SDMA 
moving compressed 
data from DDR to SRAM, and Decomp_gzip reading data from SRAM. After 
decompression, decomp_gzip 
writes the data back to SRAM, and SDMA moves the data from SRAM to DDR.

According to "K230 Technical Reference Manual v0.3.1" section 15.
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

Signed-off-by: Tao Ding <[email protected]>
---
 hw/misc/Kconfig                    |   3 +
 hw/misc/k230_decomp_gzip.c         | 498 +++++++++++++++++++++++++++++
 hw/misc/meson.build                |   1 +
 hw/misc/trace-events               |   4 +
 include/hw/misc/k230_decomp_gzip.h |  92 ++++++
 5 files changed, 598 insertions(+)
 create mode 100644 hw/misc/k230_decomp_gzip.c
 create mode 100644 include/hw/misc/k230_decomp_gzip.h

diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 1543ee6653..28687482f8 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -257,4 +257,7 @@ config XLNX_VERSAL_TRNG
 config XLNX_ZYNQ_DDRC
     bool
 
+config K230_DECOMP_GZIP
+    bool
+
 source macio/Kconfig
diff --git a/hw/misc/k230_decomp_gzip.c b/hw/misc/k230_decomp_gzip.c
new file mode 100644
index 0000000000..4284262259
--- /dev/null
+++ b/hw/misc/k230_decomp_gzip.c
@@ -0,0 +1,498 @@
+/*
+ * Kendryte K230 GZIP decompression engine
+ *
+ * Copyright (c) 2026 Tao Ding <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Decompression accelerator is mainly used to implement hardware
+ * GZIP decompression function. (K230 TRM section 15)
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/core/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "system/address-spaces.h"
+#include "hw/core/irq.h"
+#include "hw/misc/k230_decomp_gzip.h"
+#include "trace.h"
+
+#define GZIP_METHOD_DEFLATE    8
+#define GZIP_METHOD_VENDOR_9   9
+
+
+#define K230_DECOMP_GZIP_OUTPUT_SLOTS 4
+#define K230_DECOMP_GZIP_INPUT_SLOTS 2
+
+static void k230_decomp_gzip_set_output(K230DecompGzipState *s, int line,
+                                        int level)
+{
+    qemu_set_irq(s->signal_out[line], level);
+}
+
+static bool k230_decomp_gzip_read_mem(K230DecompGzipState *s, hwaddr addr,
+                                      void *buf, size_t len)
+{
+    MemTxResult ret = address_space_read(&address_space_memory,
+                                         s->sram_base + addr,
+                                         MEMTXATTRS_UNSPECIFIED, buf, len);
+
+    return ret == MEMTX_OK;
+}
+
+static bool k230_decomp_gzip_write_mem(K230DecompGzipState *s, hwaddr addr,
+                                       const void *buf, size_t len)
+{
+    return address_space_write(&address_space_memory, s->sram_base + addr,
+                               MEMTXATTRS_UNSPECIFIED, buf, len) == MEMTX_OK;
+}
+
+static hwaddr k230_decomp_gzip_output_addr(K230DecompGzipState *s)
+{
+    return K230_DECOMP_GZIP_SRAM_OUT_BASE +
+           s->output.slot * K230_DECOMP_GZIP_BLOCK_SIZE +
+           s->output.current_offset;
+}
+
+static hwaddr k230_decomp_gzip_input_addr(K230DecompGzipState *s)
+{
+    return s->input.slot * K230_DECOMP_GZIP_BLOCK_SIZE +
+           K230_DECOMP_GZIP_SRAM_IN_BASE;
+}
+
+static uint32_t k230_decomp_gzip_current_input_size(K230DecompGzipState *s)
+{
+    if (s->total_requested == 0) {
+        return 0;
+    }
+
+    return ((s->total_requested - 1) % K230_DECOMP_GZIP_BLOCK_SIZE) + 1;
+}
+
+static void k230_decomp_gzip_update_ctrl_en(K230DecompGzipState *s)
+{
+    int level = s->active && !!(s->gzip_src_size & K230_DECOMP_GZIP_CTRL_EN);
+
+    k230_decomp_gzip_set_output(s, K230_DECOMP_GZIP_GPIO_DECOMP_CTRL_EN,
+                                level);
+}
+
+static void k230_decomp_gzip_reset_stream(K230DecompGzipState *s)
+{
+    if (s->zstream_inited) {
+        inflateEnd(&s->zs);
+        s->zstream_inited = false;
+    }
+    memset(&s->zs, 0, sizeof(s->zs));
+}
+
+static void k230_decomp_gzip_finish(K230DecompGzipState *s, bool crc_ok)
+{
+    s->active = false;
+    k230_decomp_gzip_reset_stream(s);
+    k230_decomp_gzip_update_ctrl_en(s);
+    if (crc_ok) {
+        s->decomp_stat |= K230_DECOMP_GZIP_STAT_CRC_OK;
+    } else {
+        s->decomp_stat &= ~K230_DECOMP_GZIP_STAT_CRC_OK;
+    }
+}
+
+static bool k230_decomp_gzip_load_input(K230DecompGzipState *s,
+                                        uint32_t addr, uint32_t size)
+{
+    s->input.current_offset = 0;
+
+    return k230_decomp_gzip_read_mem(s, addr, s->input_buf, size);
+}
+
+static bool k230_decomp_gzip_request_input(K230DecompGzipState *s)
+{
+    uint32_t total_requested = s->total_requested;
+
+    k230_decomp_gzip_set_output(s, K230_DECOMP_GZIP_GPIO_DMA_WRITE_REQ, 1);
+    if (s->total_requested == total_requested) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: dma write request not acknowledged\n",
+                      TYPE_K230_DECOMP_GZIP);
+        return false;
+    }
+    return true;
+}
+
+static bool k230_decomp_gzip_request_output(K230DecompGzipState *s)
+{
+    uint32_t slot = s->output.slot;
+    uint32_t current_offset = s->output.current_offset;
+
+    k230_decomp_gzip_set_output(s, K230_DECOMP_GZIP_GPIO_DMA_READ_REQ, 1);
+    if (s->output.slot == slot &&
+        s->output.current_offset == current_offset) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: dma read request not acknowledged\n",
+                      TYPE_K230_DECOMP_GZIP);
+        return false;
+    }
+    return true;
+}
+
+static bool k230_decomp_gzip_init_stream(K230DecompGzipState *s)
+{
+    /* The compression script for K230 will modify the third byte to 0x9 */
+    if (s->input_buf[2] == GZIP_METHOD_VENDOR_9) {
+        s->input_buf[2] = GZIP_METHOD_DEFLATE;
+    }
+
+    if (inflateInit2(&s->zs, 15 + 16) != Z_OK) {
+        return false;
+    }
+
+    s->zstream_inited = true;
+    return true;
+}
+
+static bool k230_decomp_gzip_run_inflate(K230DecompGzipState *s)
+{
+    uint32_t output_size = s->gzip_out_size;
+    uint32_t current_input_size = k230_decomp_gzip_current_input_size(s);
+    uint32_t avail_in;
+    uint32_t avail_out;
+    uint32_t consumed;
+    uint32_t produced;
+    int ret;
+
+    avail_in = current_input_size - s->input.current_offset;
+    avail_out = K230_DECOMP_GZIP_BLOCK_SIZE - s->output.current_offset;
+
+    s->zs.next_in = s->input_buf + s->input.current_offset;
+    s->zs.avail_in = avail_in;
+    s->zs.next_out = s->output_buf;
+    s->zs.avail_out = avail_out;
+
+    ret = inflate(&s->zs, Z_NO_FLUSH);
+    if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) {
+        return false;
+    }
+
+    consumed = avail_in - s->zs.avail_in;
+    produced = avail_out - s->zs.avail_out;
+
+    if (produced) {
+        if (s->total_produced + produced > output_size ||
+            !k230_decomp_gzip_write_mem(s, k230_decomp_gzip_output_addr(s),
+                                        s->output_buf, produced)) {
+            return false;
+        }
+        s->output.current_offset += produced;
+        s->total_produced += produced;
+    }
+
+    if (consumed) {
+        s->input.current_offset += consumed;
+    }
+
+    if (ret == Z_STREAM_END) {
+        s->stream_end = true;
+        if (s->total_produced != output_size) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void k230_decomp_gzip_kick(K230DecompGzipState *s)
+{
+    if (!s->active || s->in_kick) {
+        return;
+    }
+
+    uint32_t input_size = s->gzip_src_size & K230_DECOMP_GZIP_DMA_IN_MASK;
+    s->in_kick = true;
+    while (s->active) {
+        uint32_t current_input_size = k230_decomp_gzip_current_input_size(s);
+        /* Output is full or last block */
+        if (s->output.current_offset == K230_DECOMP_GZIP_BLOCK_SIZE ||
+            (s->stream_end && s->output.current_offset != 0)) {
+            if (!k230_decomp_gzip_request_output(s)) {
+                k230_decomp_gzip_finish(s, false);
+                break;
+            }
+            continue;
+        }
+
+        if (!s->zstream_inited) {
+            if (!k230_decomp_gzip_request_input(s) ||
+                !k230_decomp_gzip_init_stream(s)) {
+                k230_decomp_gzip_finish(s, false);
+                break;
+            }
+            continue;
+        }
+
+        /* Transfer finish */
+        if (s->stream_end) {
+            k230_decomp_gzip_finish(s,
+                                    s->total_produced == s->gzip_out_size);
+            break;
+        }
+
+        /* Input buf has has been fully decompreed, need request more */
+        if (s->input.current_offset == current_input_size) {
+            if (s->total_requested < input_size) {
+                if (!k230_decomp_gzip_request_input(s)) {
+                    k230_decomp_gzip_finish(s, false);
+                    break;
+                }
+                continue;
+            }
+            k230_decomp_gzip_finish(s, false);
+            break;
+        }
+
+        /* Decompress the data, input buf or output buf are consumed in one 
block */
+        if (!k230_decomp_gzip_run_inflate(s)) {
+            k230_decomp_gzip_finish(s, false);
+            break;
+        }
+    }
+    s->in_kick = false;
+}
+
+static void k230_decomp_gzip_handle_ack(void *opaque, int n, int level)
+{
+    K230DecompGzipState *s = opaque;
+
+    if (!level || !s->active) {
+        return;
+    }
+
+    switch (n) {
+    case K230_DECOMP_GZIP_GPIO_DMA_WRITE_ACK:
+    {
+        uint32_t input_size = s->gzip_src_size & K230_DECOMP_GZIP_DMA_IN_MASK;
+        uint32_t chunk = MIN(K230_DECOMP_GZIP_BLOCK_SIZE,
+                             input_size - s->total_requested);
+
+        if (!k230_decomp_gzip_load_input(s, k230_decomp_gzip_input_addr(s),
+                                         chunk)) {
+            k230_decomp_gzip_finish(s, false);
+            return;
+        }
+        s->total_requested += chunk;
+        s->input.slot = (s->input.slot + 1) % K230_DECOMP_GZIP_INPUT_SLOTS;
+        break;
+    }
+    case K230_DECOMP_GZIP_GPIO_DMA_READ_ACK:
+        if (s->output.current_offset == 0) {
+            k230_decomp_gzip_finish(s, false);
+            return;
+        }
+        s->output.slot = (s->output.slot + 1) % K230_DECOMP_GZIP_OUTPUT_SLOTS;
+        s->output.current_offset = 0;
+        break;
+    default:
+        return;
+    }
+
+    k230_decomp_gzip_kick(s);
+}
+
+static void k230_decomp_gzip_start(K230DecompGzipState *s)
+{
+    uint32_t input_size = s->gzip_src_size & K230_DECOMP_GZIP_DMA_IN_MASK;
+
+    k230_decomp_gzip_reset_stream(s);
+    s->decomp_stat &= ~K230_DECOMP_GZIP_STAT_CRC_OK;
+    s->total_requested = 0;
+    s->total_produced = 0;
+    s->stream_end = false;
+    memset(&s->input, 0, sizeof(s->input));
+    memset(&s->output, 0, sizeof(s->output));
+
+    if (!(s->gzip_src_size & K230_DECOMP_GZIP_CTRL_EN) ||
+        input_size == 0 || s->gzip_out_size == 0) {
+        k230_decomp_gzip_finish(s, false);
+        return;
+    }
+
+    s->active = true;
+    k230_decomp_gzip_update_ctrl_en(s);
+    k230_decomp_gzip_kick(s);
+}
+
+static uint64_t k230_decomp_gzip_read(void *opaque, hwaddr offset,
+                                      unsigned size)
+{
+    K230DecompGzipState *s = opaque;
+    uint64_t value = 0;
+
+    switch (offset) {
+    case K230_DECOMP_GZIP_DECOMP_START:
+        value = s->decomp_start;
+        break;
+    case K230_DECOMP_GZIP_GZIP_SRC_SIZE:
+        value = s->gzip_src_size;
+        break;
+    case K230_DECOMP_GZIP_GZIP_OUT_SIZE:
+        value = s->gzip_out_size;
+        break;
+    case K230_DECOMP_GZIP_DECOMP_STAT:
+        value = s->decomp_stat;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: bad read offset 0x%" HWADDR_PRIx "\n",
+                      TYPE_K230_DECOMP_GZIP, offset);
+        break;
+    }
+
+    trace_k230_decomp_gzip_read(offset, size, value);
+    return value;
+}
+
+static void k230_decomp_gzip_write(void *opaque, hwaddr offset,
+                                   uint64_t value, unsigned size)
+{
+    K230DecompGzipState *s = opaque;
+
+    trace_k230_decomp_gzip_write(offset, size, value);
+
+    switch (offset) {
+    case K230_DECOMP_GZIP_DECOMP_START:
+        s->decomp_start = value;
+        if (value & K230_DECOMP_GZIP_START) {
+            k230_decomp_gzip_start(s);
+        }
+        break;
+    case K230_DECOMP_GZIP_GZIP_SRC_SIZE:
+        s->gzip_src_size = value;
+        k230_decomp_gzip_update_ctrl_en(s);
+        break;
+    case K230_DECOMP_GZIP_GZIP_OUT_SIZE:
+        s->gzip_out_size = value;
+        break;
+    case K230_DECOMP_GZIP_DECOMP_STAT:
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: bad write offset 0x%" HWADDR_PRIx "\n",
+                      TYPE_K230_DECOMP_GZIP, offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps k230_decomp_gzip_ops = {
+    .read = k230_decomp_gzip_read,
+    .write = k230_decomp_gzip_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
+};
+
+static const VMStateDescription vmstate_k230_decomp_gzip_slot = {
+    .name = "k230.decomp-gzip.slot",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32(slot, K230DecompGzipSlotState),
+        VMSTATE_UINT32(current_offset, K230DecompGzipSlotState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_k230_decomp_gzip = {
+    .name = "k230.decomp-gzip",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32(decomp_start, K230DecompGzipState),
+        VMSTATE_UINT32(gzip_src_size, K230DecompGzipState),
+        VMSTATE_UINT32(gzip_out_size, K230DecompGzipState),
+        VMSTATE_UINT32(decomp_stat, K230DecompGzipState),
+        VMSTATE_STRUCT(input, K230DecompGzipState, 1,
+                       vmstate_k230_decomp_gzip_slot,
+                       K230DecompGzipSlotState),
+        VMSTATE_STRUCT(output, K230DecompGzipState, 1,
+                       vmstate_k230_decomp_gzip_slot,
+                       K230DecompGzipSlotState),
+        VMSTATE_UINT32(total_requested, K230DecompGzipState),
+        VMSTATE_UINT32(total_produced, K230DecompGzipState),
+        VMSTATE_BOOL(active, K230DecompGzipState),
+        VMSTATE_BOOL(in_kick, K230DecompGzipState),
+        VMSTATE_BOOL(zstream_inited, K230DecompGzipState),
+        VMSTATE_BOOL(stream_end, K230DecompGzipState),
+        VMSTATE_UINT8_ARRAY(input_buf, K230DecompGzipState,
+                            K230_DECOMP_GZIP_BLOCK_SIZE),
+        VMSTATE_UINT8_ARRAY(output_buf, K230DecompGzipState,
+                            K230_DECOMP_GZIP_BLOCK_SIZE),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void k230_decomp_gzip_reset(DeviceState *dev)
+{
+    K230DecompGzipState *s = K230_DECOMP_GZIP(dev);
+
+    k230_decomp_gzip_reset_stream(s);
+    memset(&s->zs, 0, sizeof(s->zs));
+    s->decomp_start = 0;
+    s->gzip_src_size = 0;
+    s->gzip_out_size = 0;
+    s->decomp_stat = 0;
+    memset(&s->input, 0, sizeof(s->input));
+    memset(&s->output, 0, sizeof(s->output));
+    s->total_requested = 0;
+    s->total_produced = 0;
+    s->active = false;
+    s->in_kick = false;
+    s->stream_end = false;
+}
+
+static void k230_decomp_gzip_realize(DeviceState *dev, Error **errp)
+{
+    K230DecompGzipState *s = K230_DECOMP_GZIP(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->iomem, OBJECT(dev), &k230_decomp_gzip_ops, s,
+                          TYPE_K230_DECOMP_GZIP,
+                          K230_DECOMP_GZIP_MMIO_SIZE);
+    sysbus_init_mmio(sbd, &s->iomem);
+    qdev_init_gpio_in(dev, k230_decomp_gzip_handle_ack,
+                      K230_DECOMP_GZIP_NUM_GPIOS_IN);
+    qdev_init_gpio_out(dev, s->signal_out,
+                       K230_DECOMP_GZIP_NUM_GPIOS_OUT);
+}
+
+static const Property k230_decomp_gzip_properties[] = {
+    DEFINE_PROP_UINT64("sram-base", K230DecompGzipState, sram_base, 0),
+};
+
+static void k230_decomp_gzip_class_init(ObjectClass *oc, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = k230_decomp_gzip_realize;
+    device_class_set_legacy_reset(dc, k230_decomp_gzip_reset);
+    device_class_set_props(dc, k230_decomp_gzip_properties);
+    dc->vmsd = &vmstate_k230_decomp_gzip;
+    dc->desc = "Kendryte K230 GZIP decompression engine";
+}
+
+static const TypeInfo k230_decomp_gzip_info = {
+    .name = TYPE_K230_DECOMP_GZIP,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(K230DecompGzipState),
+    .class_init = k230_decomp_gzip_class_init,
+};
+
+static void k230_decomp_gzip_register_types(void)
+{
+    type_register_static(&k230_decomp_gzip_info);
+}
+
+type_init(k230_decomp_gzip_register_types)
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 23265f6035..6f6bf3c85c 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -36,6 +36,7 @@ system_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: 
files('sifive_e_prci.c'))
 system_ss.add(when: 'CONFIG_SIFIVE_E_AON', if_true: files('sifive_e_aon.c'))
 system_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c'))
 system_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c'))
+system_ss.add(when: 'CONFIG_K230_DECOMP_GZIP', if_true: 
files('k230_decomp_gzip.c'))
 
 subdir('macio')
 
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index c9a868b3ef..16db4ba0cc 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -442,3 +442,7 @@ iommu_testdev_dma_read(uint64_t gva, uint32_t len) 
"gva=0x%" PRIx64 " len=%u"
 iommu_testdev_dma_verify(uint32_t expected, uint32_t actual) "expected=0x%x 
actual=0x%x"
 iommu_testdev_dma_result(uint32_t result) "DMA completed result=0x%x"
 iommu_testdev_dma_armed(bool armed) "armed=%d"
+
+# k230_decomp_gzip.c
+k230_decomp_gzip_read(uint64_t offset, unsigned int size, uint64_t value) 
"K230 DECOMP GZIP read: [0x%"PRIx64"] size %u -> 0x%"PRIx64
+k230_decomp_gzip_write(uint64_t offset, unsigned int size, uint64_t value) 
"K230 DECOMP GZIP write: [0x%"PRIx64"] size %u <- 0x%"PRIx64
diff --git a/include/hw/misc/k230_decomp_gzip.h 
b/include/hw/misc/k230_decomp_gzip.h
new file mode 100644
index 0000000000..9911af0095
--- /dev/null
+++ b/include/hw/misc/k230_decomp_gzip.h
@@ -0,0 +1,92 @@
+/*
+ * K230 Decompress Engine
+ *
+ * Copyright (c) 2026 Tao Ding <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_MISC_K230_DECOMP_GZIP_H
+#define HW_MISC_K230_DECOMP_GZIP_H
+
+#include <zlib.h>
+#include "hw/core/sysbus.h"
+
+#define TYPE_K230_DECOMP_GZIP "riscv.k230.decomp-gzip"
+OBJECT_DECLARE_SIMPLE_TYPE(K230DecompGzipState, K230_DECOMP_GZIP)
+
+/* K230 DECOMP GZIP ACK input */
+enum {
+    K230_DECOMP_GZIP_GPIO_DMA_WRITE_ACK,
+    K230_DECOMP_GZIP_GPIO_DMA_READ_ACK,
+    K230_DECOMP_GZIP_NUM_GPIOS_IN,
+};
+
+/* K230 DECOMP GZIP REQ output */
+enum {
+    K230_DECOMP_GZIP_GPIO_DECOMP_CTRL_EN,
+    K230_DECOMP_GZIP_GPIO_DMA_WRITE_REQ,
+    K230_DECOMP_GZIP_GPIO_DMA_READ_REQ,
+    K230_DECOMP_GZIP_NUM_GPIOS_OUT,
+};
+
+#define K230_DECOMP_GZIP_MMIO_SIZE       0x4000
+
+/* K230 DECOMP GZIP Registers map */
+/* Start decompression controller */
+#define K230_DECOMP_GZIP_DECOMP_START    0x00
+/* Source data length register */
+#define K230_DECOMP_GZIP_GZIP_SRC_SIZE   0x04
+/* Output data length register */
+#define K230_DECOMP_GZIP_GZIP_OUT_SIZE   0x08
+/* Decompress status register */
+#define K230_DECOMP_GZIP_DECOMP_STAT     0x0c
+
+/* Start decompression controller */
+#define K230_DECOMP_GZIP_START           (1U << 0)
+
+#define K230_DECOMP_GZIP_CTRL_EN         (1U << 31)
+#define K230_DECOMP_GZIP_DMA_IN_MASK     0x7fffffffU
+
+#define K230_DECOMP_GZIP_STAT_CRC_OK     (1U << 10)
+#define K230_DECOMP_GZIP_STAT_STATE_MASK 0xfU
+
+#define K230_DECOMP_GZIP_BLOCK_SIZE      0x00020000
+#define K230_DECOMP_GZIP_SRAM_IN_BASE    0x80000
+#define K230_DECOMP_GZIP_SRAM_OUT_BASE   0
+
+typedef struct K230DecompGzipSlotState {
+    uint32_t slot;  /* Slot index */
+    /*
+     * Data offset in current slot.
+     * First valid data in input buffer. Last valid data in output buffer.
+     */
+    uint32_t current_offset;
+} K230DecompGzipSlotState;
+
+struct K230DecompGzipState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion iomem;
+    hwaddr sram_base;
+    qemu_irq signal_out[K230_DECOMP_GZIP_NUM_GPIOS_OUT];
+    uint32_t decomp_start;
+    uint32_t gzip_src_size;
+    uint32_t gzip_out_size;
+    uint32_t decomp_stat;
+    K230DecompGzipSlotState input;  /* decomp gzip ring input */
+    K230DecompGzipSlotState output; /* decomp gzip ring output */
+    uint32_t total_requested;
+    uint32_t total_produced;
+    bool active;
+    bool in_kick;
+    bool zstream_inited;
+    bool stream_end;
+    /* Read from ring input. */
+    uint8_t input_buf[K230_DECOMP_GZIP_BLOCK_SIZE];
+    /* Write to ring output. */
+    uint8_t output_buf[K230_DECOMP_GZIP_BLOCK_SIZE];
+    z_stream zs;
+};
+
+#endif
-- 
2.43.0


Reply via email to