* [RFC PATCH 0/2] *** Add k230 reset management unit support ***
@ 2026-07-09 3:12 jack wang
2026-07-09 3:12 ` [RFC PATCH 1/2] hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model jack wang
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: jack wang @ 2026-07-09 3:12 UTC (permalink / raw)
To: qemu-devel; +Cc: Jack Wang
From: Jack Wang <163wangjack@gmail.com>
This series adds support for reset management unit found on k230 soc and
successfully wires it up to k230 machine;
The register design are implemented based on k230 trm and linux reset driver
(drivers/reset/reset-k230.c)
detailed implementations:
1. write-enable mask for control registers(strobe in the upper 16 bits)
2. hardware auto-clearing for reset and flush request bits
3. latching of Done bits and w1c logic
4. qtest coverage for register read/write behaviors and hardware state modelin
There are some checkpatch style warnings (line length, comment
formatting) that will be addressed in v2 based on reviewer feedback.
this is my first time for hardware-unit modeling so apologies for possible mistake.
I am apprecitated for any feedback
Jack Wang (2):
hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model
hw/riscv/k230: wire up the RMU device
docs/system/riscv/k230.rst | 1 +
hw/misc/Kconfig | 3 +
hw/misc/k230_rmu.c | 280 ++++++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
hw/misc/trace-events | 6 +
hw/riscv/Kconfig | 1 +
hw/riscv/k230.c | 10 +-
include/hw/misc/k230_rmu.h | 76 ++++++++++
include/hw/riscv/k230.h | 2 +
tests/qtest/k230-rmu-test.c | 125 ++++++++++++++++
tests/qtest/meson.build | 3 +-
11 files changed, 504 insertions(+), 4 deletions(-)
create mode 100644 hw/misc/k230_rmu.c
create mode 100644 include/hw/misc/k230_rmu.h
create mode 100644 tests/qtest/k230-rmu-test.c
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [RFC PATCH 1/2] hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model
2026-07-09 3:12 [RFC PATCH 0/2] *** Add k230 reset management unit support *** jack wang
@ 2026-07-09 3:12 ` jack wang
2026-07-16 17:48 ` Daniel Henrique Barboza
2026-07-17 10:11 ` Junze Cao
2026-07-09 3:12 ` [RFC PATCH 2/2] hw/riscv/k230: wire up the RMU device jack wang
2026-07-15 11:56 ` [RFC PATCH 0/2] *** Add k230 reset management unit support *** Jack wang
2 siblings, 2 replies; 10+ messages in thread
From: jack wang @ 2026-07-09 3:12 UTC (permalink / raw)
To: qemu-devel; +Cc: Jack Wang, Paolo Bonzini, Fabiano Rosas, Laurent Vivier
From: Jack Wang <163wangjack@gmail.com>
Model the K230 Reset Management Unit (RMU / SYSCTL_RST) at 0x91101000.
Its control registers gather the software-controllable reset lines of the
SoC peripherals. The register semantics are modelled after the five reset
types described by the Linux mainline driver drivers/reset/reset-k230.c:
- CPU0/CPU1: high-half per-bit write-enable strobe plus a done bit (bit12)
- FLUSH: the CPU register bit4, auto-cleared by hardware, no done bit
- HW_DONE: no write-enable; a done bit is latched when the reset fires
and acknowledged by software with write-1-to-clear
- SW_DONE: plain read/write storage, no write-enable and no done bit
QEMU does not reset the target peripherals, so the model collapses the
hardware reset latency to zero: writing a reset request bit latches the
paired done bit and auto-clears the request bit in the same access, which
lets the kernel's readl_poll_timeout() loops succeed on the first read.
A qtest exercises the reset defaults, write-enable gating, HW_DONE latch
and write-1-to-clear, repeated resets, flush auto-clear and SW_DONE
storage behaviour.
Signed-off-by: Jack Wang <163wangjack@gmail.com>
---
hw/misc/Kconfig | 3 +
hw/misc/k230_rmu.c | 280 ++++++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
hw/misc/trace-events | 6 +
include/hw/misc/k230_rmu.h | 76 ++++++++++
tests/qtest/k230-rmu-test.c | 125 ++++++++++++++++
tests/qtest/meson.build | 3 +-
7 files changed, 493 insertions(+), 1 deletion(-)
create mode 100644 hw/misc/k230_rmu.c
create mode 100644 include/hw/misc/k230_rmu.h
create mode 100644 tests/qtest/k230-rmu-test.c
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 1543ee6653..a1470b285f 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -251,6 +251,9 @@ config DJMEMC
config IOSB
bool
+config K230_RMU
+ bool
+
config XLNX_VERSAL_TRNG
bool
diff --git a/hw/misc/k230_rmu.c b/hw/misc/k230_rmu.c
new file mode 100644
index 0000000000..f9ead7a1a0
--- /dev/null
+++ b/hw/misc/k230_rmu.c
@@ -0,0 +1,280 @@
+/*
+ * K230 Reset Management Unit (RMU / SYSCTL_RST)
+ *
+ * The RMU is a bank of reset-control registers at 0x91101000. Each register
+ * gathers the software-controllable reset lines of a group of peripherals.
+ * Register semantics are modelled after the five reset types described in the
+ * Linux mainline driver drivers/reset/reset-k230.c:
+ *
+ * - CPU0/CPU1 : have a high-half write-enable strobe and a done bit (bit12).
+ * - FLUSH : bit4 of the CPU registers; hardware auto-clears it, no done.
+ * - HW_DONE : no write-enable; a done bit is latched when the reset fires
+ * and cleared by software (write-1-to-clear).
+ * - SW_DONE : plain read/write storage, no write-enable and no done bit.
+ *
+ * QEMU never actually resets the target peripherals, so the model collapses
+ * the hardware reset latency to zero: writing a reset request bit latches the
+ * matching done bit in the same access and auto-clears the request bit, which
+ * lets the kernel's readl_poll_timeout() loops succeed on the first read.
+ *
+ * Copyright (c) 2026 Jack Wang <163wangjack@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "migration/vmstate.h"
+#include "hw/misc/k230_rmu.h"
+#include "trace.h"
+
+/* Sentinel meaning "this reset request bit has no associated done bit". */
+#define K230_RMU_NO_DONE 0xff
+
+/* A single (reset request bit -> done bit) pairing within one register. */
+typedef struct {
+ uint8_t reset_bit; /* reset request bit index, 0..15 */
+ uint8_t done_bit; /* matching done bit index, or K230_RMU_NO_DONE */
+} K230RmuPair;
+
+/* Description of one control register. */
+typedef struct {
+ hwaddr offset; /* word-aligned register offset */
+ bool has_we; /* high 16 bits are write-enable (CPU0/CPU1) */
+ const K230RmuPair *pairs; /* reset/done pairings, NULL for SW_DONE banks */
+ unsigned n_pairs; /* number of pairings (0 for SW_DONE banks) */
+} K230RmuReg;
+
+/*
+ * Per-register (reset bit -> done bit) tables, copied verbatim from the bit
+ * positions in the Linux driver's k230_resets[] table.
+ */
+static const K230RmuPair pairs_cpu0[] = { {0, 12}, {4, K230_RMU_NO_DONE} };
+static const K230RmuPair pairs_cpu1[] = { {0, 12}, {4, K230_RMU_NO_DONE} };
+static const K230RmuPair pairs_ai[] = { {0, 31} };
+static const K230RmuPair pairs_vpu[] = { {0, 31} };
+static const K230RmuPair pairs_hisys[] = { {0, 4}, {1, 5} }; /* done in low bits */
+static const K230RmuPair pairs_sdio[] = { {0, 28}, {1, 29}, {2, 30} };
+static const K230RmuPair pairs_usb[] = { {0, 28}, {1, 29}, {0, 30}, {1, 31} };
+static const K230RmuPair pairs_spi[] = { {0, 28}, {1, 29}, {2, 30} };
+static const K230RmuPair pairs_sec[] = { {0, 31} };
+static const K230RmuPair pairs_dma[] = { {0, 28}, {1, 29} };
+static const K230RmuPair pairs_decomp[] = { {0, 31} };
+static const K230RmuPair pairs_sram[] = { {0, 28}, {2, 30}, {3, 31} }; /* bit1 SW_DONE */
+static const K230RmuPair pairs_nonai2d[] = { {0, 31} };
+static const K230RmuPair pairs_mctl[] = { {0, 31} };
+static const K230RmuPair pairs_isp[] = { {6, 29}, {5, 28} }; /* other low bits SW_DONE */
+static const K230RmuPair pairs_dpu[] = { {0, 31} };
+static const K230RmuPair pairs_disp[] = { {0, 31} };
+static const K230RmuPair pairs_gpu[] = { {0, 31} };
+static const K230RmuPair pairs_audio[] = { {0, 31} };
+
+#define K230_RMU_REG(off, we, p) { (off), (we), (p), ARRAY_SIZE(p) }
+#define K230_RMU_SW(off) { (off), false, NULL, 0 } /* pure SW_DONE bank */
+
+static const K230RmuReg k230_rmu_regs[] = {
+ K230_RMU_REG(K230_RMU_CPU0_CTRL, true, pairs_cpu0),
+ K230_RMU_REG(K230_RMU_CPU1_CTRL, true, pairs_cpu1),
+ K230_RMU_REG(K230_RMU_AI_CTRL, false, pairs_ai),
+ K230_RMU_REG(K230_RMU_VPU_CTRL, false, pairs_vpu),
+ K230_RMU_SW (K230_RMU_PERI0_CTRL),
+ K230_RMU_SW (K230_RMU_PERI1_CTRL),
+ K230_RMU_REG(K230_RMU_HISYS_CTRL, false, pairs_hisys),
+ K230_RMU_REG(K230_RMU_SDIO_CTRL, false, pairs_sdio),
+ K230_RMU_REG(K230_RMU_USB_CTRL, false, pairs_usb),
+ K230_RMU_REG(K230_RMU_SPI_CTRL, false, pairs_spi),
+ K230_RMU_REG(K230_RMU_SEC_CTRL, false, pairs_sec),
+ K230_RMU_REG(K230_RMU_DMA_CTRL, false, pairs_dma),
+ K230_RMU_REG(K230_RMU_DECOMP_CTRL, false, pairs_decomp),
+ K230_RMU_REG(K230_RMU_SRAM_CTRL, false, pairs_sram),
+ K230_RMU_REG(K230_RMU_NONAI2D_CTRL, false, pairs_nonai2d),
+ K230_RMU_REG(K230_RMU_MCTL_CTRL, false, pairs_mctl),
+ K230_RMU_REG(K230_RMU_ISP_CTRL, false, pairs_isp),
+ K230_RMU_REG(K230_RMU_DPU_CTRL, false, pairs_dpu),
+ K230_RMU_REG(K230_RMU_DISP_CTRL, false, pairs_disp),
+ K230_RMU_REG(K230_RMU_GPU_CTRL, false, pairs_gpu),
+ K230_RMU_REG(K230_RMU_AUDIO_CTRL, false, pairs_audio),
+ K230_RMU_SW (K230_RMU_SPI2AXI_CTRL),
+};
+
+/* Look up the register description for a word-aligned offset, or NULL. */
+static const K230RmuReg *k230_rmu_lookup(hwaddr offset)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(k230_rmu_regs); i++) {
+ if (k230_rmu_regs[i].offset == offset) {
+ return &k230_rmu_regs[i];
+ }
+ }
+ return NULL;
+}
+
+static uint64_t k230_rmu_read(void *opaque, hwaddr offset, unsigned size)
+{
+ K230RmuState *s = K230_RMU(opaque);
+ uint32_t value;
+
+ if ((offset & 0x3) || offset >= K230_RMU_MMIO_SIZE) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad read offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return 0;
+ }
+
+ /* All hardware side effects happen on write, so a read just returns the
+ * backing store: done bits already latched, request bits already cleared.
+ */
+ value = s->regs[offset / 4];
+ trace_k230_rmu_read(offset, value);
+ return value;
+}
+
+static void k230_rmu_write(void *opaque, hwaddr offset,
+ uint64_t val64, unsigned size)
+{
+ K230RmuState *s = K230_RMU(opaque);
+ const K230RmuReg *r;
+ uint32_t v = (uint32_t)val64;
+ uint32_t old, new_val, we_gate, done_gate;
+ uint32_t reset_mask = 0, done_mask = 0, sw_mask;
+
+ if ((offset & 0x3) || offset >= K230_RMU_MMIO_SIZE) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad write offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return;
+ }
+
+ trace_k230_rmu_write(offset, v);
+ old = s->regs[offset / 4];
+ r = k230_rmu_lookup(offset);
+
+ if (!r) {
+ /* Inside the 4 KiB window but not modelled: accept the write and log
+ * it so unexpected accesses are visible while debugging.
+ */
+ qemu_log_mask(LOG_UNIMP,
+ "%s: write to unmodelled offset 0x%" HWADDR_PRIx
+ " = 0x%08x\n", __func__, offset, v);
+ s->regs[offset / 4] = v;
+ return;
+ }
+
+ /* Derive the reset/done masks for this register from its pairing table. */
+ for (unsigned i = 0; i < r->n_pairs; i++) {
+ reset_mask |= BIT(r->pairs[i].reset_bit);
+ if (r->pairs[i].done_bit != K230_RMU_NO_DONE) {
+ done_mask |= BIT(r->pairs[i].done_bit);
+ }
+ }
+
+ /*
+ * we_gate holds the low-half bits this write is allowed to modify. With
+ * write-enable (CPU0/CPU1) a low bit n is writable only when the strobe
+ * bit n+16 is also set; otherwise every low bit is directly writable.
+ */
+ we_gate = r->has_we ? ((v >> K230_RMU_WE_SHIFT) & 0xffffu) : 0xffffu;
+
+ new_val = old;
+
+ /* (A) SW_DONE storage: low-half bits that are neither reset nor done bits
+ * are plain read/write storage.
+ */
+ sw_mask = 0xffffu & ~reset_mask & ~done_mask & we_gate;
+ new_val = (new_val & ~sw_mask) | (v & sw_mask);
+
+ /* (B) Done bits are write-1-to-clear. CPU-type done bits sit in the low
+ * half and their clear is gated by write-enable (the strobe is folded
+ * into we_gate); HW_DONE done bits sit in the high half, clear direct.
+ */
+ done_gate = r->has_we ? (done_mask & we_gate) : done_mask;
+ new_val &= ~(v & done_gate);
+
+ /* (C) A reset request latches its paired done bit immediately (zero
+ * latency) and the request bit auto-clears so it can fire again.
+ * FLUSH-type pairs (done_bit == NO_DONE) only auto-clear.
+ */
+ for (unsigned i = 0; i < r->n_pairs; i++) {
+ uint32_t rbit = BIT(r->pairs[i].reset_bit);
+ bool fire = (v & rbit) &&
+ (!r->has_we || (v & (rbit << K230_RMU_WE_SHIFT)));
+
+ if (fire) {
+ if (r->pairs[i].done_bit != K230_RMU_NO_DONE) {
+ new_val |= BIT(r->pairs[i].done_bit);
+ } else {
+ trace_k230_rmu_flush(offset);
+ }
+ new_val &= ~rbit;
+ }
+ }
+
+ s->regs[offset / 4] = new_val;
+}
+
+static const MemoryRegionOps k230_rmu_ops = {
+ .read = k230_rmu_read,
+ .write = k230_rmu_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void k230_rmu_reset(DeviceState *dev)
+{
+ K230RmuState *s = K230_RMU(dev);
+
+ trace_k230_rmu_reset_device();
+ memset(s->regs, 0, sizeof(s->regs));
+}
+
+static void k230_rmu_realize(DeviceState *dev, Error **errp)
+{
+ K230RmuState *s = K230_RMU(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&s->mmio, OBJECT(dev), &k230_rmu_ops, s,
+ TYPE_K230_RMU, K230_RMU_MMIO_SIZE);
+ sysbus_init_mmio(sbd, &s->mmio);
+}
+
+static const VMStateDescription vmstate_k230_rmu = {
+ .name = "k230.rmu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, K230RmuState, K230_RMU_NUM_REGS),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void k230_rmu_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = k230_rmu_realize;
+ device_class_set_legacy_reset(dc, k230_rmu_reset);
+ dc->vmsd = &vmstate_k230_rmu;
+ dc->desc = "K230 Reset Management Unit";
+}
+
+static const TypeInfo k230_rmu_info = {
+ .name = TYPE_K230_RMU,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(K230RmuState),
+ .class_init = k230_rmu_class_init,
+};
+
+static void k230_rmu_register_type(void)
+{
+ type_register_static(&k230_rmu_info);
+}
+type_init(k230_rmu_register_type)
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 23265f6035..5e1155723f 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -111,6 +111,7 @@ system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files(
system_ss.add(when: 'CONFIG_XLNX_VERSAL_TRNG', if_true: files(
'xlnx-versal-trng.c',
))
+system_ss.add(when: 'CONFIG_K230_RMU', if_true: files('k230_rmu.c'))
system_ss.add(when: 'CONFIG_STM32_RCC', if_true: files('stm32_rcc.c'))
system_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c'))
system_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c'))
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index b88accc437..da0e32582e 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -417,3 +417,9 @@ 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_rmu.c
+k230_rmu_read(uint64_t offset, uint32_t value) "K230 RMU read: [0x%" PRIx64 "] -> 0x%08" PRIx32
+k230_rmu_write(uint64_t offset, uint32_t value) "K230 RMU write: [0x%" PRIx64 "] <- 0x%08" PRIx32
+k230_rmu_flush(uint64_t offset) "K230 RMU flush auto-clear at offset 0x%" PRIx64
+k230_rmu_reset_device(void) "K230 RMU device reset"
diff --git a/include/hw/misc/k230_rmu.h b/include/hw/misc/k230_rmu.h
new file mode 100644
index 0000000000..e6f5073c1e
--- /dev/null
+++ b/include/hw/misc/k230_rmu.h
@@ -0,0 +1,76 @@
+/*
+ * K230 Reset Management Unit (RMU / SYSCTL_RST)
+ *
+ * K230 Technical Reference Manual V0.3.1 (2024-11-18):
+ * https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * Register semantics cross-checked against the Linux mainline driver
+ * drivers/reset/reset-k230.c (compatible "canaan,k230-rst").
+ *
+ * Copyright (c) 2026 Jack Wang <163wangjack@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_MISC_K230_RMU_H
+#define HW_MISC_K230_RMU_H
+
+#include "qemu/bitops.h"
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_K230_RMU "riscv.k230.rmu"
+OBJECT_DECLARE_SIMPLE_TYPE(K230RmuState, K230_RMU)
+
+/* 1 KiB MMIO window, see K230_DEV_RMU in hw/riscv/k230.c. */
+#define K230_RMU_MMIO_SIZE 0x1000
+#define K230_RMU_NUM_REGS (K230_RMU_MMIO_SIZE / 4)
+
+/* Control register offsets used by drivers/reset/reset-k230.c. */
+#define K230_RMU_CPU0_CTRL 0x04
+#define K230_RMU_CPU1_CTRL 0x0C
+#define K230_RMU_AI_CTRL 0x14
+#define K230_RMU_VPU_CTRL 0x1C
+#define K230_RMU_PERI0_CTRL 0x20 /* SW_DONE bank: TIMERx, WDTx, MAILBOX */
+#define K230_RMU_PERI1_CTRL 0x24 /* SW_DONE bank: UARTx, I2Cx, GPIO */
+#define K230_RMU_HISYS_CTRL 0x2C
+#define K230_RMU_SDIO_CTRL 0x34
+#define K230_RMU_USB_CTRL 0x3C
+#define K230_RMU_SPI_CTRL 0x44
+#define K230_RMU_SEC_CTRL 0x4C
+#define K230_RMU_DMA_CTRL 0x54
+#define K230_RMU_DECOMP_CTRL 0x5C
+#define K230_RMU_SRAM_CTRL 0x64 /* mixed: HW_DONE bits + SW_DONE bit1 */
+#define K230_RMU_NONAI2D_CTRL 0x6C
+#define K230_RMU_MCTL_CTRL 0x74
+#define K230_RMU_ISP_CTRL 0x80 /* mixed: HW_DONE bits + SW_DONE bits */
+#define K230_RMU_DPU_CTRL 0x88
+#define K230_RMU_DISP_CTRL 0x90
+#define K230_RMU_GPU_CTRL 0x98
+#define K230_RMU_AUDIO_CTRL 0xA4
+#define K230_RMU_SPI2AXI_CTRL 0xA8 /* SW_DONE (active high) */
+
+/* Bit layout shared by the CPU0/CPU1 control registers. */
+#define K230_RMU_CPU_RESET BIT(0) /* reset request, auto/soft cleared */
+#define K230_RMU_CPU_FLUSH BIT(4) /* L2 flush request, hw auto-clears */
+#define K230_RMU_CPU_DONE BIT(12) /* done bit, write-1-to-clear */
+
+/* The high 16 bits are per-bit write-enable strobes (CPU0/CPU1 registers). */
+#define K230_RMU_WE_SHIFT 16
+
+struct K230RmuState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion mmio;
+
+ /*
+ * One 32-bit word per MMIO offset. Indexing by word offset keeps the
+ * VMState description trivial. Reset requests auto-clear, so what
+ * actually persists here is done bits and SW_DONE storage bits.
+ */
+ uint32_t regs[K230_RMU_NUM_REGS];
+};
+
+#endif /* HW_MISC_K230_RMU_H */
diff --git a/tests/qtest/k230-rmu-test.c b/tests/qtest/k230-rmu-test.c
new file mode 100644
index 0000000000..c2c862cd1d
--- /dev/null
+++ b/tests/qtest/k230-rmu-test.c
@@ -0,0 +1,125 @@
+/*
+ * QTest for the K230 Reset Management Unit.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "libqtest.h"
+#include "hw/misc/k230_rmu.h"
+
+#define K230_RMU_BASE 0x91101000ULL
+
+static inline uint32_t rd(QTestState *qts, uint64_t off)
+{
+ return qtest_readl(qts, K230_RMU_BASE + off);
+}
+static inline void wr(QTestState *qts, uint64_t off, uint32_t val)
+{
+ qtest_writel(qts, K230_RMU_BASE + off, val);
+}
+
+/* Every known register reads back as 0 after reset. */
+static void test_reset_values(void)
+{
+ QTestState *qts = qtest_init("-machine k230");
+
+ g_assert_cmphex(rd(qts, K230_RMU_CPU0_CTRL), ==, 0);
+ g_assert_cmphex(rd(qts, K230_RMU_AI_CTRL), ==, 0);
+ g_assert_cmphex(rd(qts, K230_RMU_HISYS_CTRL), ==, 0);
+ g_assert_cmphex(rd(qts, K230_RMU_PERI0_CTRL), ==, 0);
+
+ qtest_quit(qts);
+}
+
+/*
+ * CPU0: a low-half write without its strobe is ignored; with the strobe the
+ * reset request fires, latches done (bit12), and the request bit auto-clears.
+ */
+static void test_cpu_write_enable(void)
+{
+ QTestState *qts = qtest_init("-machine k230");
+
+ /* No strobe: the low-half write is dropped, reads back as 0. */
+ wr(qts, K230_RMU_CPU0_CTRL, K230_RMU_CPU_RESET);
+ g_assert_cmphex(rd(qts, K230_RMU_CPU0_CTRL), ==, 0);
+
+ /* With strobe (bit16): request bit0 takes effect, done (bit12) latches. */
+ wr(qts, K230_RMU_CPU0_CTRL,
+ K230_RMU_CPU_RESET | (K230_RMU_CPU_RESET << K230_RMU_WE_SHIFT));
+ g_assert_cmphex(rd(qts, K230_RMU_CPU0_CTRL), ==, K230_RMU_CPU_DONE);
+
+ qtest_quit(qts);
+}
+
+/*
+ * HW_DONE: no write-enable needed. Writing HISYS request bit0 latches its
+ * done bit (bit4); writing 1 to the done bit clears it.
+ */
+static void test_hw_done_and_w1c(void)
+{
+ QTestState *qts = qtest_init("-machine k230");
+ uint32_t v;
+
+ wr(qts, K230_RMU_HISYS_CTRL, BIT(0)); /* no strobe */
+ v = rd(qts, K230_RMU_HISYS_CTRL);
+ g_assert_cmphex(v & BIT(4), ==, BIT(4)); /* done latched */
+ g_assert_cmphex(v & BIT(0), ==, 0); /* request bit auto-cleared */
+
+ wr(qts, K230_RMU_HISYS_CTRL, BIT(4)); /* write-1-to-clear */
+ g_assert_cmphex(rd(qts, K230_RMU_HISYS_CTRL) & BIT(4), ==, 0);
+
+ qtest_quit(qts);
+}
+
+/* Repeated resets: one HW_DONE line can be triggered again and again. */
+static void test_repeat_reset(void)
+{
+ QTestState *qts = qtest_init("-machine k230");
+
+ for (int i = 0; i < 3; i++) {
+ wr(qts, K230_RMU_AI_CTRL, BIT(0)); /* request */
+ g_assert_cmphex(rd(qts, K230_RMU_AI_CTRL) & BIT(31), ==, BIT(31));
+ wr(qts, K230_RMU_AI_CTRL, BIT(31)); /* W1C done */
+ g_assert_cmphex(rd(qts, K230_RMU_AI_CTRL) & BIT(31), ==, 0);
+ }
+
+ qtest_quit(qts);
+}
+
+/* FLUSH: the CPU0 bit4 flush request is auto-cleared, reads back as 0. */
+static void test_flush_auto_clear(void)
+{
+ QTestState *qts = qtest_init("-machine k230");
+
+ wr(qts, K230_RMU_CPU0_CTRL,
+ K230_RMU_CPU_FLUSH | (K230_RMU_CPU_FLUSH << K230_RMU_WE_SHIFT));
+ g_assert_cmphex(rd(qts, K230_RMU_CPU0_CTRL) & K230_RMU_CPU_FLUSH, ==, 0);
+
+ qtest_quit(qts);
+}
+
+/* SW_DONE: the PERI0 low half is plain storage, no strobe and no done bit. */
+static void test_sw_done_storage(void)
+{
+ QTestState *qts = qtest_init("-machine k230");
+
+ wr(qts, K230_RMU_PERI0_CTRL, BIT(12) | BIT(13)); /* WDT0 / WDT1 reset bits */
+ g_assert_cmphex(rd(qts, K230_RMU_PERI0_CTRL), ==, (BIT(12) | BIT(13)));
+
+ qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/k230/rmu/reset_values", test_reset_values);
+ qtest_add_func("/k230/rmu/cpu_we", test_cpu_write_enable);
+ qtest_add_func("/k230/rmu/hw_done_w1c", test_hw_done_and_w1c);
+ qtest_add_func("/k230/rmu/repeat_reset", test_repeat_reset);
+ qtest_add_func("/k230/rmu/flush", test_flush_auto_clear);
+ qtest_add_func("/k230/rmu/sw_done", test_sw_done_storage);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 822e0bd286..70c9a53454 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -294,7 +294,8 @@ qtests_riscv64 = ['riscv-csr-test'] + \
(config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and
config_all_devices.has_key('CONFIG_RISCV_IOMMU') ?
['iommu-riscv-test'] : []) + \
- (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
+ (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test',
+ 'k230-rmu-test'] : [])
qtests_hexagon = ['boot-serial-test']
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH 2/2] hw/riscv/k230: wire up the RMU device
2026-07-09 3:12 [RFC PATCH 0/2] *** Add k230 reset management unit support *** jack wang
2026-07-09 3:12 ` [RFC PATCH 1/2] hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model jack wang
@ 2026-07-09 3:12 ` jack wang
2026-07-16 17:56 ` Daniel Henrique Barboza
2026-07-15 11:56 ` [RFC PATCH 0/2] *** Add k230 reset management unit support *** Jack wang
2 siblings, 1 reply; 10+ messages in thread
From: jack wang @ 2026-07-09 3:12 UTC (permalink / raw)
To: qemu-devel
Cc: Jack Wang, Chao Liu, Pierrick Bouvier, Paolo Bonzini,
Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, open list:K230 Machines
From: Jack Wang <163wangjack@gmail.com>
Replace the "rmu" create_unimplemented_device() stub with a real
K230RmuState instance mapped at the K230_DEV_RMU memmap entry, select
K230_RMU from the K230 Kconfig, and document the device.
Closes: gevico/qemu-camp-2026-k230#11
Signed-off-by: Jack Wang <163wangjack@gmail.com>
---
docs/system/riscv/k230.rst | 1 +
hw/riscv/Kconfig | 1 +
hw/riscv/k230.c | 10 +++++++---
include/hw/riscv/k230.h | 2 ++
4 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
index cea8202e55..3f2313a127 100644
--- a/docs/system/riscv/k230.rst
+++ b/docs/system/riscv/k230.rst
@@ -19,6 +19,7 @@ The ``k230`` machine supports the following devices:
* Core Local Interruptor (CLINT)
* Platform-Level Interrupt Controller (PLIC)
* 2 K230 Watchdog Timer
+* K230 Reset Management Unit (RMU)
* 5 UART
Boot options
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 54e41a6afc..bffa4e69c8 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -149,3 +149,4 @@ config K230
select SERIAL_MM
select UNIMP
select K230_WDT
+ select K230_RMU
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
index 502281c52c..b55e90c0d2 100644
--- a/hw/riscv/k230.c
+++ b/hw/riscv/k230.c
@@ -110,6 +110,7 @@ static void k230_soc_init(Object *obj)
object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT);
object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT);
+ object_initialize_child(obj, "k230-rmu", &s->rmu, TYPE_K230_RMU);
qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
@@ -206,6 +207,12 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0,
qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ));
+ /* RMU (reset management unit) */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->rmu), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rmu), 0, memmap[K230_DEV_RMU].base);
+
/* unimplemented devices */
create_unimplemented_device("kpu.l2-cache",
memmap[K230_DEV_KPU_L2_CACHE].base,
@@ -268,9 +275,6 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
memmap[K230_DEV_CMU].size);
- create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
- memmap[K230_DEV_RMU].size);
-
create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
memmap[K230_DEV_BOOT].size);
diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
index 592e1c26bf..13f2a1ab0b 100644
--- a/include/hw/riscv/k230.h
+++ b/include/hw/riscv/k230.h
@@ -18,6 +18,7 @@
#include "hw/core/boards.h"
#include "hw/riscv/riscv_hart.h"
#include "hw/watchdog/k230_wdt.h"
+#include "hw/misc/k230_rmu.h"
#define C908_CPU_HARTID (0)
@@ -33,6 +34,7 @@ typedef struct K230SoCState {
RISCVHartArrayState c908_cpu; /* Small core */
K230WdtState wdt[2];
+ K230RmuState rmu;
MemoryRegion sram;
MemoryRegion bootrom;
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/2] *** Add k230 reset management unit support ***
2026-07-09 3:12 [RFC PATCH 0/2] *** Add k230 reset management unit support *** jack wang
2026-07-09 3:12 ` [RFC PATCH 1/2] hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model jack wang
2026-07-09 3:12 ` [RFC PATCH 2/2] hw/riscv/k230: wire up the RMU device jack wang
@ 2026-07-15 11:56 ` Jack wang
2 siblings, 0 replies; 10+ messages in thread
From: Jack wang @ 2026-07-15 11:56 UTC (permalink / raw)
To: qemu-devel
Cc: chao.liu.zevorn, pierrick.bouvier, pbonzini, palmer,
alistair.francis, liwei1518, daniel.barboza, zhiwei_liu, farosas,
lvivier, qemu-riscv
Hi all,
A polite ping for this RFC series.
Could anyone please take a look when you have a moment? Any feedback or guidance would be greatly appreciated.
Thanks,
Jack Wang
> 2026年7月9日 11:12,jack wang <163wangjack@gmail.com> 写道:
>
> From: Jack Wang <163wangjack@gmail.com>
>
> This series adds support for reset management unit found on k230 soc and
> successfully wires it up to k230 machine;
>
> The register design are implemented based on k230 trm and linux reset driver
> (drivers/reset/reset-k230.c)
>
> detailed implementations:
> 1. write-enable mask for control registers(strobe in the upper 16 bits)
> 2. hardware auto-clearing for reset and flush request bits
> 3. latching of Done bits and w1c logic
> 4. qtest coverage for register read/write behaviors and hardware state modelin
>
> There are some checkpatch style warnings (line length, comment
> formatting) that will be addressed in v2 based on reviewer feedback.
>
> this is my first time for hardware-unit modeling so apologies for possible mistake.
> I am apprecitated for any feedback
>
> Jack Wang (2):
> hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model
> hw/riscv/k230: wire up the RMU device
>
> docs/system/riscv/k230.rst | 1 +
> hw/misc/Kconfig | 3 +
> hw/misc/k230_rmu.c | 280 ++++++++++++++++++++++++++++++++++++
> hw/misc/meson.build | 1 +
> hw/misc/trace-events | 6 +
> hw/riscv/Kconfig | 1 +
> hw/riscv/k230.c | 10 +-
> include/hw/misc/k230_rmu.h | 76 ++++++++++
> include/hw/riscv/k230.h | 2 +
> tests/qtest/k230-rmu-test.c | 125 ++++++++++++++++
> tests/qtest/meson.build | 3 +-
> 11 files changed, 504 insertions(+), 4 deletions(-)
> create mode 100644 hw/misc/k230_rmu.c
> create mode 100644 include/hw/misc/k230_rmu.h
> create mode 100644 tests/qtest/k230-rmu-test.c
>
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 1/2] hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model
2026-07-09 3:12 ` [RFC PATCH 1/2] hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model jack wang
@ 2026-07-16 17:48 ` Daniel Henrique Barboza
2026-07-17 10:11 ` Junze Cao
1 sibling, 0 replies; 10+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-16 17:48 UTC (permalink / raw)
To: jack wang, qemu-devel; +Cc: Paolo Bonzini, Fabiano Rosas, Laurent Vivier
Hi,
On 7/9/2026 12:12 AM, jack wang wrote:
> From: Jack Wang <163wangjack@gmail.com>
>
> Model the K230 Reset Management Unit (RMU / SYSCTL_RST) at 0x91101000.
> Its control registers gather the software-controllable reset lines of the
> SoC peripherals. The register semantics are modelled after the five reset
> types described by the Linux mainline driver drivers/reset/reset-k230.c:
>
> - CPU0/CPU1: high-half per-bit write-enable strobe plus a done bit (bit12)
> - FLUSH: the CPU register bit4, auto-cleared by hardware, no done bit
> - HW_DONE: no write-enable; a done bit is latched when the reset fires
> and acknowledged by software with write-1-to-clear
> - SW_DONE: plain read/write storage, no write-enable and no done bit
>
> QEMU does not reset the target peripherals, so the model collapses the
> hardware reset latency to zero: writing a reset request bit latches the
> paired done bit and auto-clears the request bit in the same access, which
> lets the kernel's readl_poll_timeout() loops succeed on the first read.
>
> A qtest exercises the reset defaults, write-enable gating, HW_DONE latch
> and write-1-to-clear, repeated resets, flush auto-clear and SW_DONE
> storage behaviour.
The qtest fails with this patch:
29/352 qtest+qtest-riscv64 - qemu:qtest-riscv64/k230-rmu-test ERROR 0.33s killed by signal 6 SIGABRT
Error being thrown:
# starting QEMU: exec ./qemu-system-riscv64 -qtest unix:/tmp/qtest-3816689.sock -qtest-log /dev/null -chardev socket,path=/tmp/qtest-3816689.qmp,id=char0 -object monitor-qmp,id=qmp0,chardev=char0 -display none -audio none -run-with exit-with-parent=on -machine k230 -accel qtest
ok 1 /riscv64/k230/rmu/reset_values
# starting QEMU: exec ./qemu-system-riscv64 -qtest unix:/tmp/qtest-3816689.sock -qtest-log /dev/null -chardev socket,path=/tmp/qtest-3816689.qmp,id=char0 -object monitor-qmp,id=qmp0,chardev=char0 -display none -audio none -run-with exit-with-parent=on -machine k230 -accel qtest
**
ERROR:../tests/qtest/k230-rmu-test.c:50:test_cpu_write_enable: assertion failed (rd(qts, K230_RMU_CPU0_CTRL) == K230_RMU_CPU_DONE): (0x00000000 == 0x00001000)
not ok /riscv64/k230/rmu/cpu_we - ERROR:../tests/qtest/k230-rmu-test.c:50:test_cpu_write_enable: assertion failed (rd(qts, K230_RMU_CPU0_CTRL) == K230_RMU_CPU_DONE): (0x00000000 == 0x00001000)
Bail out!
If we apply patch 2/2 the qtest succeeds. Which is good, but we aim for all
tests being green for all individual patches to ease our lives when bisecting
code.
You can either squash patch 2/2 into this one or move the new qtest to patch 2/2
where it'll pass.
The code LGTM aside from this bit:
>
> Signed-off-by: Jack Wang <163wangjack@gmail.com>
> ---
> hw/misc/Kconfig | 3 +
> hw/misc/k230_rmu.c | 280 ++++++++++++++++++++++++++++++++++++
> hw/misc/meson.build | 1 +
> hw/misc/trace-events | 6 +
> include/hw/misc/k230_rmu.h | 76 ++++++++++
> tests/qtest/k230-rmu-test.c | 125 ++++++++++++++++
> tests/qtest/meson.build | 3 +-
> 7 files changed, 493 insertions(+), 1 deletion(-)
> create mode 100644 hw/misc/k230_rmu.c
> create mode 100644 include/hw/misc/k230_rmu.h
> create mode 100644 tests/qtest/k230-rmu-test.c
>
[...]
> +static void k230_rmu_class_init(ObjectClass *klass, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->realize = k230_rmu_realize;
> + device_class_set_legacy_reset(dc, k230_rmu_reset);
This is a deprecated API. If you look at include/hw/core/qdev.h:
---
* device_class_set_legacy_reset(): set the DeviceClass::reset method
* @dc: The device class
* @dev_reset: the reset function
*
* This function sets the DeviceClass::reset method. This is widely
* used in existing code, but new code should prefer to use the
* Resettable API as documented in docs/devel/reset.rst.
---
I suggest reading docs/devel/reset.rst to understand which reset phases might
be applicable to this device. Some devices implement just the phases.hold cb,
others implement enter and/or exit. Seeing k230_rmu_reset() I think you can
get away with implementing it with just phases.hold but don't just take my word
for it. Check out the docs and see what makes sense for this RMU.
Thanks,
Daniel
> + dc->vmsd = &vmstate_k230_rmu;
> + dc->desc = "K230 Reset Management Unit";
> +}
> +
> +static const TypeInfo k230_rmu_info = {
> + .name = TYPE_K230_RMU,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(K230RmuState),
> + .class_init = k230_rmu_class_init,
> +};
> +
> +static void k230_rmu_register_type(void)
> +{
> + type_register_static(&k230_rmu_info);
> +}
> +type_init(k230_rmu_register_type)
> diff --git a/hw/misc/meson.build b/hw/misc/meson.build
> index 23265f6035..5e1155723f 100644
> --- a/hw/misc/meson.build
> +++ b/hw/misc/meson.build
> @@ -111,6 +111,7 @@ system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files(
> system_ss.add(when: 'CONFIG_XLNX_VERSAL_TRNG', if_true: files(
> 'xlnx-versal-trng.c',
> ))
> +system_ss.add(when: 'CONFIG_K230_RMU', if_true: files('k230_rmu.c'))
> system_ss.add(when: 'CONFIG_STM32_RCC', if_true: files('stm32_rcc.c'))
> system_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c'))
> system_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c'))
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index b88accc437..da0e32582e 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -417,3 +417,9 @@ 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_rmu.c
> +k230_rmu_read(uint64_t offset, uint32_t value) "K230 RMU read: [0x%" PRIx64 "] -> 0x%08" PRIx32
> +k230_rmu_write(uint64_t offset, uint32_t value) "K230 RMU write: [0x%" PRIx64 "] <- 0x%08" PRIx32
> +k230_rmu_flush(uint64_t offset) "K230 RMU flush auto-clear at offset 0x%" PRIx64
> +k230_rmu_reset_device(void) "K230 RMU device reset"
> diff --git a/include/hw/misc/k230_rmu.h b/include/hw/misc/k230_rmu.h
> new file mode 100644
> index 0000000000..e6f5073c1e
> --- /dev/null
> +++ b/include/hw/misc/k230_rmu.h
> @@ -0,0 +1,76 @@
> +/*
> + * K230 Reset Management Unit (RMU / SYSCTL_RST)
> + *
> + * K230 Technical Reference Manual V0.3.1 (2024-11-18):
> + * https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> + *
> + * Register semantics cross-checked against the Linux mainline driver
> + * drivers/reset/reset-k230.c (compatible "canaan,k230-rst").
> + *
> + * Copyright (c) 2026 Jack Wang <163wangjack@gmail.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef HW_MISC_K230_RMU_H
> +#define HW_MISC_K230_RMU_H
> +
> +#include "qemu/bitops.h"
> +#include "hw/core/sysbus.h"
> +#include "qom/object.h"
> +
> +#define TYPE_K230_RMU "riscv.k230.rmu"
> +OBJECT_DECLARE_SIMPLE_TYPE(K230RmuState, K230_RMU)
> +
> +/* 1 KiB MMIO window, see K230_DEV_RMU in hw/riscv/k230.c. */
> +#define K230_RMU_MMIO_SIZE 0x1000
> +#define K230_RMU_NUM_REGS (K230_RMU_MMIO_SIZE / 4)
> +
> +/* Control register offsets used by drivers/reset/reset-k230.c. */
> +#define K230_RMU_CPU0_CTRL 0x04
> +#define K230_RMU_CPU1_CTRL 0x0C
> +#define K230_RMU_AI_CTRL 0x14
> +#define K230_RMU_VPU_CTRL 0x1C
> +#define K230_RMU_PERI0_CTRL 0x20 /* SW_DONE bank: TIMERx, WDTx, MAILBOX */
> +#define K230_RMU_PERI1_CTRL 0x24 /* SW_DONE bank: UARTx, I2Cx, GPIO */
> +#define K230_RMU_HISYS_CTRL 0x2C
> +#define K230_RMU_SDIO_CTRL 0x34
> +#define K230_RMU_USB_CTRL 0x3C
> +#define K230_RMU_SPI_CTRL 0x44
> +#define K230_RMU_SEC_CTRL 0x4C
> +#define K230_RMU_DMA_CTRL 0x54
> +#define K230_RMU_DECOMP_CTRL 0x5C
> +#define K230_RMU_SRAM_CTRL 0x64 /* mixed: HW_DONE bits + SW_DONE bit1 */
> +#define K230_RMU_NONAI2D_CTRL 0x6C
> +#define K230_RMU_MCTL_CTRL 0x74
> +#define K230_RMU_ISP_CTRL 0x80 /* mixed: HW_DONE bits + SW_DONE bits */
> +#define K230_RMU_DPU_CTRL 0x88
> +#define K230_RMU_DISP_CTRL 0x90
> +#define K230_RMU_GPU_CTRL 0x98
> +#define K230_RMU_AUDIO_CTRL 0xA4
> +#define K230_RMU_SPI2AXI_CTRL 0xA8 /* SW_DONE (active high) */
> +
> +/* Bit layout shared by the CPU0/CPU1 control registers. */
> +#define K230_RMU_CPU_RESET BIT(0) /* reset request, auto/soft cleared */
> +#define K230_RMU_CPU_FLUSH BIT(4) /* L2 flush request, hw auto-clears */
> +#define K230_RMU_CPU_DONE BIT(12) /* done bit, write-1-to-clear */
> +
> +/* The high 16 bits are per-bit write-enable strobes (CPU0/CPU1 registers). */
> +#define K230_RMU_WE_SHIFT 16
> +
> +struct K230RmuState {
> + /*< private >*/
> + SysBusDevice parent_obj;
> +
> + /*< public >*/
> + MemoryRegion mmio;
> +
> + /*
> + * One 32-bit word per MMIO offset. Indexing by word offset keeps the
> + * VMState description trivial. Reset requests auto-clear, so what
> + * actually persists here is done bits and SW_DONE storage bits.
> + */
> + uint32_t regs[K230_RMU_NUM_REGS];
> +};
> +
> +#endif /* HW_MISC_K230_RMU_H */
> diff --git a/tests/qtest/k230-rmu-test.c b/tests/qtest/k230-rmu-test.c
> new file mode 100644
> index 0000000000..c2c862cd1d
> --- /dev/null
> +++ b/tests/qtest/k230-rmu-test.c
> @@ -0,0 +1,125 @@
> +/*
> + * QTest for the K230 Reset Management Unit.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +#include "qemu/osdep.h"
> +#include "qemu/bitops.h"
> +#include "libqtest.h"
> +#include "hw/misc/k230_rmu.h"
> +
> +#define K230_RMU_BASE 0x91101000ULL
> +
> +static inline uint32_t rd(QTestState *qts, uint64_t off)
> +{
> + return qtest_readl(qts, K230_RMU_BASE + off);
> +}
> +static inline void wr(QTestState *qts, uint64_t off, uint32_t val)
> +{
> + qtest_writel(qts, K230_RMU_BASE + off, val);
> +}
> +
> +/* Every known register reads back as 0 after reset. */
> +static void test_reset_values(void)
> +{
> + QTestState *qts = qtest_init("-machine k230");
> +
> + g_assert_cmphex(rd(qts, K230_RMU_CPU0_CTRL), ==, 0);
> + g_assert_cmphex(rd(qts, K230_RMU_AI_CTRL), ==, 0);
> + g_assert_cmphex(rd(qts, K230_RMU_HISYS_CTRL), ==, 0);
> + g_assert_cmphex(rd(qts, K230_RMU_PERI0_CTRL), ==, 0);
> +
> + qtest_quit(qts);
> +}
> +
> +/*
> + * CPU0: a low-half write without its strobe is ignored; with the strobe the
> + * reset request fires, latches done (bit12), and the request bit auto-clears.
> + */
> +static void test_cpu_write_enable(void)
> +{
> + QTestState *qts = qtest_init("-machine k230");
> +
> + /* No strobe: the low-half write is dropped, reads back as 0. */
> + wr(qts, K230_RMU_CPU0_CTRL, K230_RMU_CPU_RESET);
> + g_assert_cmphex(rd(qts, K230_RMU_CPU0_CTRL), ==, 0);
> +
> + /* With strobe (bit16): request bit0 takes effect, done (bit12) latches. */
> + wr(qts, K230_RMU_CPU0_CTRL,
> + K230_RMU_CPU_RESET | (K230_RMU_CPU_RESET << K230_RMU_WE_SHIFT));
> + g_assert_cmphex(rd(qts, K230_RMU_CPU0_CTRL), ==, K230_RMU_CPU_DONE);
> +
> + qtest_quit(qts);
> +}
> +
> +/*
> + * HW_DONE: no write-enable needed. Writing HISYS request bit0 latches its
> + * done bit (bit4); writing 1 to the done bit clears it.
> + */
> +static void test_hw_done_and_w1c(void)
> +{
> + QTestState *qts = qtest_init("-machine k230");
> + uint32_t v;
> +
> + wr(qts, K230_RMU_HISYS_CTRL, BIT(0)); /* no strobe */
> + v = rd(qts, K230_RMU_HISYS_CTRL);
> + g_assert_cmphex(v & BIT(4), ==, BIT(4)); /* done latched */
> + g_assert_cmphex(v & BIT(0), ==, 0); /* request bit auto-cleared */
> +
> + wr(qts, K230_RMU_HISYS_CTRL, BIT(4)); /* write-1-to-clear */
> + g_assert_cmphex(rd(qts, K230_RMU_HISYS_CTRL) & BIT(4), ==, 0);
> +
> + qtest_quit(qts);
> +}
> +
> +/* Repeated resets: one HW_DONE line can be triggered again and again. */
> +static void test_repeat_reset(void)
> +{
> + QTestState *qts = qtest_init("-machine k230");
> +
> + for (int i = 0; i < 3; i++) {
> + wr(qts, K230_RMU_AI_CTRL, BIT(0)); /* request */
> + g_assert_cmphex(rd(qts, K230_RMU_AI_CTRL) & BIT(31), ==, BIT(31));
> + wr(qts, K230_RMU_AI_CTRL, BIT(31)); /* W1C done */
> + g_assert_cmphex(rd(qts, K230_RMU_AI_CTRL) & BIT(31), ==, 0);
> + }
> +
> + qtest_quit(qts);
> +}
> +
> +/* FLUSH: the CPU0 bit4 flush request is auto-cleared, reads back as 0. */
> +static void test_flush_auto_clear(void)
> +{
> + QTestState *qts = qtest_init("-machine k230");
> +
> + wr(qts, K230_RMU_CPU0_CTRL,
> + K230_RMU_CPU_FLUSH | (K230_RMU_CPU_FLUSH << K230_RMU_WE_SHIFT));
> + g_assert_cmphex(rd(qts, K230_RMU_CPU0_CTRL) & K230_RMU_CPU_FLUSH, ==, 0);
> +
> + qtest_quit(qts);
> +}
> +
> +/* SW_DONE: the PERI0 low half is plain storage, no strobe and no done bit. */
> +static void test_sw_done_storage(void)
> +{
> + QTestState *qts = qtest_init("-machine k230");
> +
> + wr(qts, K230_RMU_PERI0_CTRL, BIT(12) | BIT(13)); /* WDT0 / WDT1 reset bits */
> + g_assert_cmphex(rd(qts, K230_RMU_PERI0_CTRL), ==, (BIT(12) | BIT(13)));
> +
> + qtest_quit(qts);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + g_test_init(&argc, &argv, NULL);
> +
> + qtest_add_func("/k230/rmu/reset_values", test_reset_values);
> + qtest_add_func("/k230/rmu/cpu_we", test_cpu_write_enable);
> + qtest_add_func("/k230/rmu/hw_done_w1c", test_hw_done_and_w1c);
> + qtest_add_func("/k230/rmu/repeat_reset", test_repeat_reset);
> + qtest_add_func("/k230/rmu/flush", test_flush_auto_clear);
> + qtest_add_func("/k230/rmu/sw_done", test_sw_done_storage);
> +
> + return g_test_run();
> +}
> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> index 822e0bd286..70c9a53454 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -294,7 +294,8 @@ qtests_riscv64 = ['riscv-csr-test'] + \
> (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and
> config_all_devices.has_key('CONFIG_RISCV_IOMMU') ?
> ['iommu-riscv-test'] : []) + \
> - (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
> + (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test',
> + 'k230-rmu-test'] : [])
>
> qtests_hexagon = ['boot-serial-test']
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 2/2] hw/riscv/k230: wire up the RMU device
2026-07-09 3:12 ` [RFC PATCH 2/2] hw/riscv/k230: wire up the RMU device jack wang
@ 2026-07-16 17:56 ` Daniel Henrique Barboza
2026-07-17 13:41 ` Chao Liu
0 siblings, 1 reply; 10+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-16 17:56 UTC (permalink / raw)
To: jack wang, qemu-devel
Cc: Chao Liu, Pierrick Bouvier, Paolo Bonzini, Palmer Dabbelt,
Alistair Francis, Weiwei Li, Liu Zhiwei, open list:K230 Machines
Hi,
On 7/9/2026 12:12 AM, jack wang wrote:
> From: Jack Wang <163wangjack@gmail.com>
>
> Replace the "rmu" create_unimplemented_device() stub with a real
> K230RmuState instance mapped at the K230_DEV_RMU memmap entry, select
> K230_RMU from the K230 Kconfig, and document the device.
So, as I said in patch 1, applying this patch will fix the qtest that you
introduced there. I believe we want to either squash this patch in patch
1 or move the qtest creation to this patch. Both are fine to me.
>
> Closes: gevico/qemu-camp-2026-k230#11
Not sure what gevico is (seems like a bootcamp, according to Google at least) but
the "Closes" tag usually contains a gitlab bug or any other link that is publicly
available. It's better to remove it.
Thanks,
Daniel
> Signed-off-by: Jack Wang <163wangjack@gmail.com>
> ---
> docs/system/riscv/k230.rst | 1 +
> hw/riscv/Kconfig | 1 +
> hw/riscv/k230.c | 10 +++++++---
> include/hw/riscv/k230.h | 2 ++
> 4 files changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
> index cea8202e55..3f2313a127 100644
> --- a/docs/system/riscv/k230.rst
> +++ b/docs/system/riscv/k230.rst
> @@ -19,6 +19,7 @@ The ``k230`` machine supports the following devices:
> * Core Local Interruptor (CLINT)
> * Platform-Level Interrupt Controller (PLIC)
> * 2 K230 Watchdog Timer
> +* K230 Reset Management Unit (RMU)
> * 5 UART
>
> Boot options
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 54e41a6afc..bffa4e69c8 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -149,3 +149,4 @@ config K230
> select SERIAL_MM
> select UNIMP
> select K230_WDT
> + select K230_RMU
> diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
> index 502281c52c..b55e90c0d2 100644
> --- a/hw/riscv/k230.c
> +++ b/hw/riscv/k230.c
> @@ -110,6 +110,7 @@ static void k230_soc_init(Object *obj)
> object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
> object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT);
> object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT);
> + object_initialize_child(obj, "k230-rmu", &s->rmu, TYPE_K230_RMU);
>
> qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
> qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
> @@ -206,6 +207,12 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
> sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0,
> qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ));
>
> + /* RMU (reset management unit) */
> + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rmu), errp)) {
> + return;
> + }
> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->rmu), 0, memmap[K230_DEV_RMU].base);
> +
> /* unimplemented devices */
> create_unimplemented_device("kpu.l2-cache",
> memmap[K230_DEV_KPU_L2_CACHE].base,
> @@ -268,9 +275,6 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
> create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
> memmap[K230_DEV_CMU].size);
>
> - create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
> - memmap[K230_DEV_RMU].size);
> -
> create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
> memmap[K230_DEV_BOOT].size);
>
> diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
> index 592e1c26bf..13f2a1ab0b 100644
> --- a/include/hw/riscv/k230.h
> +++ b/include/hw/riscv/k230.h
> @@ -18,6 +18,7 @@
> #include "hw/core/boards.h"
> #include "hw/riscv/riscv_hart.h"
> #include "hw/watchdog/k230_wdt.h"
> +#include "hw/misc/k230_rmu.h"
>
> #define C908_CPU_HARTID (0)
>
> @@ -33,6 +34,7 @@ typedef struct K230SoCState {
> RISCVHartArrayState c908_cpu; /* Small core */
>
> K230WdtState wdt[2];
> + K230RmuState rmu;
> MemoryRegion sram;
> MemoryRegion bootrom;
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 1/2] hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model
2026-07-09 3:12 ` [RFC PATCH 1/2] hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model jack wang
2026-07-16 17:48 ` Daniel Henrique Barboza
@ 2026-07-17 10:11 ` Junze Cao
1 sibling, 0 replies; 10+ messages in thread
From: Junze Cao @ 2026-07-17 10:11 UTC (permalink / raw)
To: Jack Wang
Cc: Junze Cao, qemu-devel, qemu-riscv, Chao Liu, Paolo Bonzini,
Fabiano Rosas, Laurent Vivier
Hi Wang,
Thanks for working on the K230 RMU model.
I reviewed this series against the K230 TRM and the upstream Linux
reset-k230 driver. The series builds and the supplied qtest passes, but
I found several issues that should be addressed in v2.
1. The RMU currently acknowledges reset requests without actually
resetting the target devices. Please connect at least the existing K230
watchdog devices and add a qtest which verifies that their state is
reset through the RMU.
2. The register reset state does not match the TRM. Please initialize
each modelled register with its documented reset value and update the
reset-value test accordingly.
3. Some register access permissions and reset types are incorrect. In
particular, some upper SW_DONE reset lines cannot be changed, reserved
bits are writable, and CPU1 is treated as self-clearing even though it
requires separate assert and deassert operations.
4. Patch 1 adds k230-rmu-test while the K230 machine still uses the
unimplemented RMU stub. K230_RMU is enabled and wired only by patch 2,
so patch 1 cannot pass its own test when checked out independently.
Please reorder the changes, move the test to patch 2, or squash the two
patches.
5. The new source, header and qtest files should be added to the K230
section in MAINTAINERS. Please address the checkpatch errors and
warnings before sending v2 as well.
6. Please consider modelling the reset timing registers. At minimum,
their reset values and writable fields should be represented. Real-time
delays may remain simplified if the zero-latency behavior is documented
and preserves guest-visible ordering.
7. Please add coverage for the corrected reset values, CPU1
transitions, upper SW_DONE fields, reserved bits, and reset propagation
to the watchdogs.
Regards,
Junze Cao
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 2/2] hw/riscv/k230: wire up the RMU device
2026-07-16 17:56 ` Daniel Henrique Barboza
@ 2026-07-17 13:41 ` Chao Liu
2026-07-17 13:56 ` Daniel Henrique Barboza
0 siblings, 1 reply; 10+ messages in thread
From: Chao Liu @ 2026-07-17 13:41 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: jack wang, qemu-devel, Pierrick Bouvier, Paolo Bonzini,
Palmer Dabbelt, Alistair Francis, Weiwei Li, Liu Zhiwei,
open list:K230 Machines
On Thu, Jul 16, 2026 at 02:56:30PM +0800, Daniel Henrique Barboza wrote:
Hi Daniel,
> Hi,
>
> On 7/9/2026 12:12 AM, jack wang wrote:
> > From: Jack Wang <163wangjack@gmail.com>
> >
> > Replace the "rmu" create_unimplemented_device() stub with a real
> > K230RmuState instance mapped at the K230_DEV_RMU memmap entry, select
> > K230_RMU from the K230 Kconfig, and document the device.
>
> So, as I said in patch 1, applying this patch will fix the qtest that you
> introduced there. I believe we want to either squash this patch in patch
> 1 or move the qtest creation to this patch. Both are fine to me.
>
> >
> > Closes: gevico/qemu-camp-2026-k230#11
>
> Not sure what gevico is (seems like a bootcamp, according to Google at least) but
> the "Closes" tag usually contains a gitlab bug or any other link that is publicly
> available. It's better to remove it.
>
I believe this link refers to:
https://github.com/gevico/qemu-camp-2026-k230/issues/11
However, according to the QEMU development collaboration workflow,
we don't need to add it.
Gevico, here is the English transliteration for the Chinese "格维". This
is a major open-source community in China focused on technical software,
which I currently organize and own.
Within our community, we run a QEMU technical training camp primarily
centered on the RISC-V architecture and exploratory work regarding
GPGPU microarchitecture.
One of our key projects involves hardware modeling for the K230, where
we are implementing a digital satellite-borne computer. The recent
contributions seen upstream were primarily patches sent by participants
of this project. We are currently in the process of contributing our
results from this stage to the QEMU upstream.
If you are interested in this, you can visit the link below.
https://qemu.gevico.online/tutorial/2026/ch3/qemu-k230/
Thanks,
Chao
>
> Thanks,
> Daniel
>
>
> > Signed-off-by: Jack Wang <163wangjack@gmail.com>
> > ---
> > docs/system/riscv/k230.rst | 1 +
> > hw/riscv/Kconfig | 1 +
> > hw/riscv/k230.c | 10 +++++++---
> > include/hw/riscv/k230.h | 2 ++
> > 4 files changed, 11 insertions(+), 3 deletions(-)
> >
> > diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
> > index cea8202e55..3f2313a127 100644
> > --- a/docs/system/riscv/k230.rst
> > +++ b/docs/system/riscv/k230.rst
> > @@ -19,6 +19,7 @@ The ``k230`` machine supports the following devices:
> > * Core Local Interruptor (CLINT)
> > * Platform-Level Interrupt Controller (PLIC)
> > * 2 K230 Watchdog Timer
> > +* K230 Reset Management Unit (RMU)
> > * 5 UART
> > Boot options
> > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> > index 54e41a6afc..bffa4e69c8 100644
> > --- a/hw/riscv/Kconfig
> > +++ b/hw/riscv/Kconfig
> > @@ -149,3 +149,4 @@ config K230
> > select SERIAL_MM
> > select UNIMP
> > select K230_WDT
> > + select K230_RMU
> > diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
> > index 502281c52c..b55e90c0d2 100644
> > --- a/hw/riscv/k230.c
> > +++ b/hw/riscv/k230.c
> > @@ -110,6 +110,7 @@ static void k230_soc_init(Object *obj)
> > object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
> > object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT);
> > object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT);
> > + object_initialize_child(obj, "k230-rmu", &s->rmu, TYPE_K230_RMU);
> > qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
> > qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
> > @@ -206,6 +207,12 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
> > sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0,
> > qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ));
> > + /* RMU (reset management unit) */
> > + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rmu), errp)) {
> > + return;
> > + }
> > + sysbus_mmio_map(SYS_BUS_DEVICE(&s->rmu), 0, memmap[K230_DEV_RMU].base);
> > +
> > /* unimplemented devices */
> > create_unimplemented_device("kpu.l2-cache",
> > memmap[K230_DEV_KPU_L2_CACHE].base,
> > @@ -268,9 +275,6 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
> > create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
> > memmap[K230_DEV_CMU].size);
> > - create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
> > - memmap[K230_DEV_RMU].size);
> > -
> > create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
> > memmap[K230_DEV_BOOT].size);
> > diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
> > index 592e1c26bf..13f2a1ab0b 100644
> > --- a/include/hw/riscv/k230.h
> > +++ b/include/hw/riscv/k230.h
> > @@ -18,6 +18,7 @@
> > #include "hw/core/boards.h"
> > #include "hw/riscv/riscv_hart.h"
> > #include "hw/watchdog/k230_wdt.h"
> > +#include "hw/misc/k230_rmu.h"
> > #define C908_CPU_HARTID (0)
> > @@ -33,6 +34,7 @@ typedef struct K230SoCState {
> > RISCVHartArrayState c908_cpu; /* Small core */
> > K230WdtState wdt[2];
> > + K230RmuState rmu;
> > MemoryRegion sram;
> > MemoryRegion bootrom;
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 2/2] hw/riscv/k230: wire up the RMU device
2026-07-17 13:41 ` Chao Liu
@ 2026-07-17 13:56 ` Daniel Henrique Barboza
2026-07-17 14:04 ` Chao Liu
0 siblings, 1 reply; 10+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-17 13:56 UTC (permalink / raw)
To: Chao Liu
Cc: jack wang, qemu-devel, Pierrick Bouvier, Paolo Bonzini,
Palmer Dabbelt, Alistair Francis, Weiwei Li, Liu Zhiwei,
open list:K230 Machines
On 7/17/2026 10:41 AM, Chao Liu wrote:
> On Thu, Jul 16, 2026 at 02:56:30PM +0800, Daniel Henrique Barboza wrote:
>
> Hi Daniel,
>> Hi,
>>
>> On 7/9/2026 12:12 AM, jack wang wrote:
>>> From: Jack Wang <163wangjack@gmail.com>
>>>
>>> Replace the "rmu" create_unimplemented_device() stub with a real
>>> K230RmuState instance mapped at the K230_DEV_RMU memmap entry, select
>>> K230_RMU from the K230 Kconfig, and document the device.
>>
>> So, as I said in patch 1, applying this patch will fix the qtest that you
>> introduced there. I believe we want to either squash this patch in patch
>> 1 or move the qtest creation to this patch. Both are fine to me.
>>
>>>
>>> Closes: gevico/qemu-camp-2026-k230#11
>>
>> Not sure what gevico is (seems like a bootcamp, according to Google at least) but
>> the "Closes" tag usually contains a gitlab bug or any other link that is publicly
>> available. It's better to remove it.
>>
> I believe this link refers to:
> https://github.com/gevico/qemu-camp-2026-k230/issues/11
>
> However, according to the QEMU development collaboration workflow,
> we don't need to add it.
>
> Gevico, here is the English transliteration for the Chinese "格维". This
> is a major open-source community in China focused on technical software,
> which I currently organize and own.
>
> Within our community, we run a QEMU technical training camp primarily
> centered on the RISC-V architecture and exploratory work regarding
> GPGPU microarchitecture.
>
> One of our key projects involves hardware modeling for the K230, where
> we are implementing a digital satellite-borne computer. The recent
> contributions seen upstream were primarily patches sent by participants
> of this project. We are currently in the process of contributing our
> results from this stage to the QEMU upstream.
Thanks for the info. This seems very interesting indeed, and please keep
the QEMU contributions flowing :D
Cheers,
Daniel
>
> If you are interested in this, you can visit the link below.
> https://qemu.gevico.online/tutorial/2026/ch3/qemu-k230/
>
> Thanks,
> Chao
>>
>> Thanks,
>> Daniel
>>
>>
>>> Signed-off-by: Jack Wang <163wangjack@gmail.com>
>>> ---
>>> docs/system/riscv/k230.rst | 1 +
>>> hw/riscv/Kconfig | 1 +
>>> hw/riscv/k230.c | 10 +++++++---
>>> include/hw/riscv/k230.h | 2 ++
>>> 4 files changed, 11 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
>>> index cea8202e55..3f2313a127 100644
>>> --- a/docs/system/riscv/k230.rst
>>> +++ b/docs/system/riscv/k230.rst
>>> @@ -19,6 +19,7 @@ The ``k230`` machine supports the following devices:
>>> * Core Local Interruptor (CLINT)
>>> * Platform-Level Interrupt Controller (PLIC)
>>> * 2 K230 Watchdog Timer
>>> +* K230 Reset Management Unit (RMU)
>>> * 5 UART
>>> Boot options
>>> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
>>> index 54e41a6afc..bffa4e69c8 100644
>>> --- a/hw/riscv/Kconfig
>>> +++ b/hw/riscv/Kconfig
>>> @@ -149,3 +149,4 @@ config K230
>>> select SERIAL_MM
>>> select UNIMP
>>> select K230_WDT
>>> + select K230_RMU
>>> diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
>>> index 502281c52c..b55e90c0d2 100644
>>> --- a/hw/riscv/k230.c
>>> +++ b/hw/riscv/k230.c
>>> @@ -110,6 +110,7 @@ static void k230_soc_init(Object *obj)
>>> object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
>>> object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT);
>>> object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT);
>>> + object_initialize_child(obj, "k230-rmu", &s->rmu, TYPE_K230_RMU);
>>> qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
>>> qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
>>> @@ -206,6 +207,12 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
>>> sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0,
>>> qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ));
>>> + /* RMU (reset management unit) */
>>> + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rmu), errp)) {
>>> + return;
>>> + }
>>> + sysbus_mmio_map(SYS_BUS_DEVICE(&s->rmu), 0, memmap[K230_DEV_RMU].base);
>>> +
>>> /* unimplemented devices */
>>> create_unimplemented_device("kpu.l2-cache",
>>> memmap[K230_DEV_KPU_L2_CACHE].base,
>>> @@ -268,9 +275,6 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
>>> create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
>>> memmap[K230_DEV_CMU].size);
>>> - create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
>>> - memmap[K230_DEV_RMU].size);
>>> -
>>> create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
>>> memmap[K230_DEV_BOOT].size);
>>> diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
>>> index 592e1c26bf..13f2a1ab0b 100644
>>> --- a/include/hw/riscv/k230.h
>>> +++ b/include/hw/riscv/k230.h
>>> @@ -18,6 +18,7 @@
>>> #include "hw/core/boards.h"
>>> #include "hw/riscv/riscv_hart.h"
>>> #include "hw/watchdog/k230_wdt.h"
>>> +#include "hw/misc/k230_rmu.h"
>>> #define C908_CPU_HARTID (0)
>>> @@ -33,6 +34,7 @@ typedef struct K230SoCState {
>>> RISCVHartArrayState c908_cpu; /* Small core */
>>> K230WdtState wdt[2];
>>> + K230RmuState rmu;
>>> MemoryRegion sram;
>>> MemoryRegion bootrom;
>>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 2/2] hw/riscv/k230: wire up the RMU device
2026-07-17 13:56 ` Daniel Henrique Barboza
@ 2026-07-17 14:04 ` Chao Liu
0 siblings, 0 replies; 10+ messages in thread
From: Chao Liu @ 2026-07-17 14:04 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: jack wang, qemu-devel, Pierrick Bouvier, Paolo Bonzini,
Palmer Dabbelt, Alistair Francis, Weiwei Li, Liu Zhiwei,
open list:K230 Machines
On Fri, Jul 17, 2026 at 10:56:17AM +0800, Daniel Henrique Barboza wrote:
>
>
> On 7/17/2026 10:41 AM, Chao Liu wrote:
> > On Thu, Jul 16, 2026 at 02:56:30PM +0800, Daniel Henrique Barboza wrote:
> >
> > Hi Daniel,
> > > Hi,
> > >
> > > On 7/9/2026 12:12 AM, jack wang wrote:
> > > > From: Jack Wang <163wangjack@gmail.com>
> > > >
> > > > Replace the "rmu" create_unimplemented_device() stub with a real
> > > > K230RmuState instance mapped at the K230_DEV_RMU memmap entry, select
> > > > K230_RMU from the K230 Kconfig, and document the device.
> > >
> > > So, as I said in patch 1, applying this patch will fix the qtest that you
> > > introduced there. I believe we want to either squash this patch in patch
> > > 1 or move the qtest creation to this patch. Both are fine to me.
> > >
> > > >
> > > > Closes: gevico/qemu-camp-2026-k230#11
> > >
> > > Not sure what gevico is (seems like a bootcamp, according to Google at least) but
> > > the "Closes" tag usually contains a gitlab bug or any other link that is publicly
> > > available. It's better to remove it.
> > >
> > I believe this link refers to:
> > https://github.com/gevico/qemu-camp-2026-k230/issues/11
> >
> > However, according to the QEMU development collaboration workflow,
> > we don't need to add it.
> >
> > Gevico, here is the English transliteration for the Chinese "格维". This
> > is a major open-source community in China focused on technical software,
> > which I currently organize and own.
> >
> > Within our community, we run a QEMU technical training camp primarily
> > centered on the RISC-V architecture and exploratory work regarding
> > GPGPU microarchitecture.
> >
> > One of our key projects involves hardware modeling for the K230, where
> > we are implementing a digital satellite-borne computer. The recent
> > contributions seen upstream were primarily patches sent by participants
> > of this project. We are currently in the process of contributing our
> > results from this stage to the QEMU upstream.
>
> Thanks for the info. This seems very interesting indeed, and please keep
> the QEMU contributions flowing :D
>
Yes, sir. :)
Thanks,
Chao
> Cheers,
> Daniel
>
> >
> > If you are interested in this, you can visit the link below.
> > https://qemu.gevico.online/tutorial/2026/ch3/qemu-k230/
> >
> > Thanks,
> > Chao
> > >
> > > Thanks,
> > > Daniel
> > >
> > >
> > > > Signed-off-by: Jack Wang <163wangjack@gmail.com>
> > > > ---
> > > > docs/system/riscv/k230.rst | 1 +
> > > > hw/riscv/Kconfig | 1 +
> > > > hw/riscv/k230.c | 10 +++++++---
> > > > include/hw/riscv/k230.h | 2 ++
> > > > 4 files changed, 11 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
> > > > index cea8202e55..3f2313a127 100644
> > > > --- a/docs/system/riscv/k230.rst
> > > > +++ b/docs/system/riscv/k230.rst
> > > > @@ -19,6 +19,7 @@ The ``k230`` machine supports the following devices:
> > > > * Core Local Interruptor (CLINT)
> > > > * Platform-Level Interrupt Controller (PLIC)
> > > > * 2 K230 Watchdog Timer
> > > > +* K230 Reset Management Unit (RMU)
> > > > * 5 UART
> > > > Boot options
> > > > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> > > > index 54e41a6afc..bffa4e69c8 100644
> > > > --- a/hw/riscv/Kconfig
> > > > +++ b/hw/riscv/Kconfig
> > > > @@ -149,3 +149,4 @@ config K230
> > > > select SERIAL_MM
> > > > select UNIMP
> > > > select K230_WDT
> > > > + select K230_RMU
> > > > diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
> > > > index 502281c52c..b55e90c0d2 100644
> > > > --- a/hw/riscv/k230.c
> > > > +++ b/hw/riscv/k230.c
> > > > @@ -110,6 +110,7 @@ static void k230_soc_init(Object *obj)
> > > > object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
> > > > object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT);
> > > > object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT);
> > > > + object_initialize_child(obj, "k230-rmu", &s->rmu, TYPE_K230_RMU);
> > > > qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
> > > > qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
> > > > @@ -206,6 +207,12 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
> > > > sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0,
> > > > qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ));
> > > > + /* RMU (reset management unit) */
> > > > + if (!sysbus_realize(SYS_BUS_DEVICE(&s->rmu), errp)) {
> > > > + return;
> > > > + }
> > > > + sysbus_mmio_map(SYS_BUS_DEVICE(&s->rmu), 0, memmap[K230_DEV_RMU].base);
> > > > +
> > > > /* unimplemented devices */
> > > > create_unimplemented_device("kpu.l2-cache",
> > > > memmap[K230_DEV_KPU_L2_CACHE].base,
> > > > @@ -268,9 +275,6 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
> > > > create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
> > > > memmap[K230_DEV_CMU].size);
> > > > - create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
> > > > - memmap[K230_DEV_RMU].size);
> > > > -
> > > > create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
> > > > memmap[K230_DEV_BOOT].size);
> > > > diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
> > > > index 592e1c26bf..13f2a1ab0b 100644
> > > > --- a/include/hw/riscv/k230.h
> > > > +++ b/include/hw/riscv/k230.h
> > > > @@ -18,6 +18,7 @@
> > > > #include "hw/core/boards.h"
> > > > #include "hw/riscv/riscv_hart.h"
> > > > #include "hw/watchdog/k230_wdt.h"
> > > > +#include "hw/misc/k230_rmu.h"
> > > > #define C908_CPU_HARTID (0)
> > > > @@ -33,6 +34,7 @@ typedef struct K230SoCState {
> > > > RISCVHartArrayState c908_cpu; /* Small core */
> > > > K230WdtState wdt[2];
> > > > + K230RmuState rmu;
> > > > MemoryRegion sram;
> > > > MemoryRegion bootrom;
> > >
>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-17 14:04 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-09 3:12 [RFC PATCH 0/2] *** Add k230 reset management unit support *** jack wang
2026-07-09 3:12 ` [RFC PATCH 1/2] hw/misc/k230_rmu: add Kendryte K230 Reset Management Unit model jack wang
2026-07-16 17:48 ` Daniel Henrique Barboza
2026-07-17 10:11 ` Junze Cao
2026-07-09 3:12 ` [RFC PATCH 2/2] hw/riscv/k230: wire up the RMU device jack wang
2026-07-16 17:56 ` Daniel Henrique Barboza
2026-07-17 13:41 ` Chao Liu
2026-07-17 13:56 ` Daniel Henrique Barboza
2026-07-17 14:04 ` Chao Liu
2026-07-15 11:56 ` [RFC PATCH 0/2] *** Add k230 reset management unit support *** Jack wang
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.