qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/5] Add K230 board and thead-c908 CPU support
@ 2025-11-30  9:21 Chao Liu
  2025-11-30  9:21 ` [PATCH v1 1/5] target/riscv: add thead-c908 cpu support Chao Liu
                   ` (4 more replies)
  0 siblings, 5 replies; 16+ messages in thread
From: Chao Liu @ 2025-11-30  9:21 UTC (permalink / raw)
  To: richard.henderson, paolo.savini, npiggin, ebiggers, dbarboza,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches,
	Chao Liu

Hi,

This patch series adds support for the K230 development board,
which is based on the T-Head C908 RISC-V CPU. The series includes
the following key features:

- patch1: Add T-Head C908 and C908v CPU support
- patch2: Add K230 board initial support(big core is not supported yet)
- patch3: Add Programmable Watchdog Timer (WDT) peripheral support
- patch4: Add QEMU test for K230 watchdog
- patch5: Add documentation for K230 machine

Thanks,
Chao

Chao Liu (5):
  target/riscv: add thead-c908 cpu support
  hw/riscv: add k230 board initial support
  hw/watchdog: add k230 watchdog initial support
  tests/qtest: add test for K230 watchdog
  docs/system/riscv: add documentation for k230 machine

 MAINTAINERS                    |  10 +
 docs/system/riscv/k230.rst     |  48 ++++
 hw/riscv/Kconfig               |  11 +
 hw/riscv/k230.c                | 501 +++++++++++++++++++++++++++++++++
 hw/riscv/meson.build           |   2 +-
 hw/watchdog/Kconfig            |   4 +
 hw/watchdog/k230_wdt.c         | 307 ++++++++++++++++++++
 hw/watchdog/meson.build        |   1 +
 hw/watchdog/trace-events       |   9 +
 include/hw/riscv/k230.h        | 153 ++++++++++
 include/hw/watchdog/k230_wdt.h | 130 +++++++++
 target/riscv/cpu-qom.h         |   2 +
 target/riscv/cpu.c             |  43 +++
 target/riscv/th_csr.c          | 380 ++++++++++++++++++++++++-
 tests/qtest/k230-wdt-test.c    | 199 +++++++++++++
 tests/qtest/meson.build        |   3 +-
 16 files changed, 1800 insertions(+), 3 deletions(-)
 create mode 100644 docs/system/riscv/k230.rst
 create mode 100644 hw/riscv/k230.c
 create mode 100644 hw/watchdog/k230_wdt.c
 create mode 100644 include/hw/riscv/k230.h
 create mode 100644 include/hw/watchdog/k230_wdt.h
 create mode 100644 tests/qtest/k230-wdt-test.c

-- 
2.51.0



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v1 1/5] target/riscv: add thead-c908 cpu support
  2025-11-30  9:21 [PATCH v1 0/5] Add K230 board and thead-c908 CPU support Chao Liu
@ 2025-11-30  9:21 ` Chao Liu
  2025-12-03 16:33   ` Daniel Henrique Barboza
  2025-12-03 17:12   ` Conor Dooley
  2025-11-30  9:21 ` [PATCH v1 2/5] hw/riscv: add k230 board initial support Chao Liu
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 16+ messages in thread
From: Chao Liu @ 2025-11-30  9:21 UTC (permalink / raw)
  To: richard.henderson, paolo.savini, npiggin, ebiggers, dbarboza,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches,
	Chao Liu

The C908 processor is based on the RV64GCB[V] instruction
set, compatible to RVA22 Profile and implements the XIE
(XuanTie Instruction Extension) technology.

Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
---
 target/riscv/cpu-qom.h |   2 +
 target/riscv/cpu.c     |  43 +++++
 target/riscv/th_csr.c  | 380 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 424 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
index 75f4e43408..1ddb5a6a6c 100644
--- a/target/riscv/cpu-qom.h
+++ b/target/riscv/cpu-qom.h
@@ -52,6 +52,8 @@
 #define TYPE_RISCV_CPU_SIFIVE_U34       RISCV_CPU_TYPE_NAME("sifive-u34")
 #define TYPE_RISCV_CPU_SIFIVE_U54       RISCV_CPU_TYPE_NAME("sifive-u54")
 #define TYPE_RISCV_CPU_THEAD_C906       RISCV_CPU_TYPE_NAME("thead-c906")
+#define TYPE_RISCV_CPU_THEAD_C908       RISCV_CPU_TYPE_NAME("thead-c908")
+#define TYPE_RISCV_CPU_THEAD_C908V      RISCV_CPU_TYPE_NAME("thead-c908v")
 #define TYPE_RISCV_CPU_VEYRON_V1        RISCV_CPU_TYPE_NAME("veyron-v1")
 #define TYPE_RISCV_CPU_TT_ASCALON       RISCV_CPU_TYPE_NAME("tt-ascalon")
 #define TYPE_RISCV_CPU_XIANGSHAN_NANHU  RISCV_CPU_TYPE_NAME("xiangshan-nanhu")
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index d055ddf462..202ff130ee 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -3091,6 +3091,49 @@ static const TypeInfo riscv_cpu_type_infos[] = {
 #endif
     ),
 
+    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908, TYPE_RISCV_VENDOR_CPU,
+        .misa_mxl_max = MXL_RV64,
+        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU,
+        .priv_spec = PRIV_VERSION_1_12_0,
+
+        /* ISA extensions */
+        .cfg.ext_xtheadba = true,
+        .cfg.ext_xtheadbb = true,
+        .cfg.ext_xtheadbs = true,
+        .cfg.ext_xtheadcmo = true,
+        .cfg.ext_xtheadcondmov = true,
+        .cfg.ext_xtheadmac = true,
+        .cfg.ext_xtheadmemidx = true,
+        .cfg.ext_xtheadmempair = true,
+        .cfg.ext_xtheadsync = true,
+        .cfg.ext_zba = true,
+        .cfg.ext_zbb = true,
+        .cfg.ext_zbc = true,
+        .cfg.ext_zbs = true,
+        .cfg.ext_zkt = true,
+        .cfg.ext_zbkc = true,
+        .cfg.ext_zicsr = true,
+        .cfg.ext_zifencei = true,
+        .cfg.ext_zihintpause = true,
+        .cfg.ext_zicbom = true,
+        .cfg.ext_zicboz = true,
+        .cfg.ext_zfh = true,
+        .cfg.ext_xtheadfmv = true,
+        .cfg.ext_xtheadfmemidx = true,
+        .cfg.pmp = true,
+
+        .cfg.marchid = 0x8d143000,
+        .cfg.mvendorid = THEAD_VENDOR_ID,
+#ifndef CONFIG_USER_ONLY
+        .custom_csrs = th_csr_list,
+#endif
+    ),
+
+    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908V, TYPE_RISCV_CPU_THEAD_C908,
+        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU | RVV,
+        .vext_spec = VEXT_VERSION_1_00_0,
+    ),
+
     DEFINE_RISCV_CPU(TYPE_RISCV_CPU_TT_ASCALON, TYPE_RISCV_VENDOR_CPU,
         .misa_mxl_max = MXL_RV64,
         .misa_ext = RVG | RVC | RVS | RVU | RVH | RVV,
diff --git a/target/riscv/th_csr.c b/target/riscv/th_csr.c
index 49eb7bbab5..3b59939f05 100644
--- a/target/riscv/th_csr.c
+++ b/target/riscv/th_csr.c
@@ -2,6 +2,9 @@
  * T-Head-specific CSRs.
  *
  * Copyright (c) 2024 VRULL GmbH
+ * Copyright (c) 2025 Chao Liu <chao.liu@zevorn.cn>
+ *
+ * For more information, see XuanTie-C908-UserManual_xrvm_20240530.pdf
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -20,13 +23,88 @@
 #include "cpu.h"
 #include "cpu_vendorid.h"
 
-#define CSR_TH_SXSTATUS 0x5c0
+/* Extended M-mode control registers of T-Head */
+#define CSR_TH_MXSTATUS        0x7c0
+#define CSR_TH_MHCR            0x7c1
+#define CSR_TH_MCOR            0x7c2
+#define CSR_TH_MCCR2           0x7c3
+#define CSR_TH_MHINT           0x7c5
+#define CSR_TH_MRVBR           0x7c7
+#define CSR_TH_MCOUNTERWEN     0x7c9
+#define CSR_TH_MCOUNTERINTEN   0x7ca
+#define CSR_TH_MCOUNTEROF      0x7cb
+#define CSR_TH_MCINS           0x7d2
+#define CSR_TH_MCINDEX         0x7d3
+#define CSR_TH_MCDATA0         0x7d4
+#define CSR_TH_MCDATA1         0x7d5
+#define CSR_TH_MSMPR           0x7f3
+#define CSR_TH_CPUID           0xfc0
+#define CSR_TH_MAPBADDR        0xfc1
+
+/* TH_MXSTATUS bits */
+#define TH_MXSTATUS_UCME        BIT(16)
+#define TH_MXSTATUS_MAEE        BIT(21)
+#define TH_MXSTATUS_THEADISAEE  BIT(22)
+
+/* Extended S-mode control registers of T-Head */
+#define CSR_TH_SXSTATUS        0x5c0
+#define CSR_TH_SHCR            0x5c1
+#define CSR_TH_SCER2           0x5c2
+#define CSR_TH_SCER            0x5c3
+#define CSR_TH_SCOUNTERINTEN   0x5c4
+#define CSR_TH_SCOUNTEROF      0x5c5
+#define CSR_TH_SCYCLE          0x5e0
+#define CSR_TH_SHPMCOUNTER3    0x5e3
+#define CSR_TH_SHPMCOUNTER4    0x5e4
+#define CSR_TH_SHPMCOUNTER5    0x5e5
+#define CSR_TH_SHPMCOUNTER6    0x5e6
+#define CSR_TH_SHPMCOUNTER7    0x5e7
+#define CSR_TH_SHPMCOUNTER8    0x5e8
+#define CSR_TH_SHPMCOUNTER9    0x5e9
+#define CSR_TH_SHPMCOUNTER10   0x5ea
+#define CSR_TH_SHPMCOUNTER11   0x5eb
+#define CSR_TH_SHPMCOUNTER12   0x5ec
+#define CSR_TH_SHPMCOUNTER13   0x5ed
+#define CSR_TH_SHPMCOUNTER14   0x5ee
+#define CSR_TH_SHPMCOUNTER15   0x5ef
+#define CSR_TH_SHPMCOUNTER16   0x5f0
+#define CSR_TH_SHPMCOUNTER17   0x5f1
+#define CSR_TH_SHPMCOUNTER18   0x5f2
+#define CSR_TH_SHPMCOUNTER19   0x5f3
+#define CSR_TH_SHPMCOUNTER20   0x5f4
+#define CSR_TH_SHPMCOUNTER21   0x5f5
+#define CSR_TH_SHPMCOUNTER22   0x5f6
+#define CSR_TH_SHPMCOUNTER23   0x5f7
+#define CSR_TH_SHPMCOUNTER24   0x5f8
+#define CSR_TH_SHPMCOUNTER25   0x5f9
+#define CSR_TH_SHPMCOUNTER26   0x5fa
+#define CSR_TH_SHPMCOUNTER27   0x5fb
+#define CSR_TH_SHPMCOUNTER28   0x5fc
+#define CSR_TH_SHPMCOUNTER29   0x5fd
+#define CSR_TH_SHPMCOUNTER30   0x5fe
+#define CSR_TH_SHPMCOUNTER31   0x5ff
+#define CSR_TH_SMIR            0x9c0
+#define CSR_TH_SMLO0           0x9c1
+#define CSR_TH_SMEH            0x9c2
+#define CSR_TH_SMCIR           0x9c3
+
+/* Extended U-mode control registers of T-Head */
+#define CSR_TH_FXCR            0x800
 
 /* TH_SXSTATUS bits */
 #define TH_SXSTATUS_UCME        BIT(16)
 #define TH_SXSTATUS_MAEE        BIT(21)
 #define TH_SXSTATUS_THEADISAEE  BIT(22)
 
+static RISCVException mmode(CPURISCVState *env, int csrno)
+{
+    if (riscv_has_ext(env, RVM)) {
+        return RISCV_EXCP_NONE;
+    }
+
+    return RISCV_EXCP_ILLEGAL_INST;
+}
+
 static RISCVException smode(CPURISCVState *env, int csrno)
 {
     if (riscv_has_ext(env, RVS)) {
@@ -36,11 +114,31 @@ static RISCVException smode(CPURISCVState *env, int csrno)
     return RISCV_EXCP_ILLEGAL_INST;
 }
 
+static RISCVException any(CPURISCVState *env, int csrno)
+{
+    return RISCV_EXCP_NONE;
+}
+
 static bool test_thead_mvendorid(RISCVCPU *cpu)
 {
     return cpu->cfg.mvendorid == THEAD_VENDOR_ID;
 }
 
+static RISCVException read_th_mxstatus(CPURISCVState *env, int csrno,
+                                       target_ulong *val)
+{
+    /* We don't set MAEE here, because QEMU does not implement MAEE. */
+    *val = TH_MXSTATUS_UCME | TH_MXSTATUS_THEADISAEE;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_unimp_th_csr(CPURISCVState *env, int csrno,
+                                        target_ulong *val)
+{
+    *val = 0;
+    return RISCV_EXCP_NONE;
+}
+
 static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
                                        target_ulong *val)
 {
@@ -50,10 +148,290 @@ static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
 }
 
 const RISCVCSR th_csr_list[] = {
+    {
+        .csrno = CSR_TH_MXSTATUS,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mxstatus", mmode, read_th_mxstatus }
+    },
+    {
+        .csrno = CSR_TH_MHCR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mhcr", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcor", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCCR2,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mccr2", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MHINT,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mhint", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MRVBR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mrvbr", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOUNTERWEN,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcounterwen", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOUNTERINTEN,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcounterinten", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOUNTEROF,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcounterof", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCINS,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcins", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCINDEX,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcindex", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCDATA0,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcdata0", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCDATA1,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcdata1", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MSMPR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.msmpr", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_CPUID,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.cpuid", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MAPBADDR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mapbaddr", mmode, read_unimp_th_csr }
+    },
     {
         .csrno = CSR_TH_SXSTATUS,
         .insertion_test = test_thead_mvendorid,
         .csr_ops = { "th.sxstatus", smode, read_th_sxstatus }
     },
+    {
+        .csrno = CSR_TH_SHCR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shcr", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCER2,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scer2", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCER,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scer", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCOUNTERINTEN,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scounterinten", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCOUNTEROF,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scounterof", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCYCLE,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scycle", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER3,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter3", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER4,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter4", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER5,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter5", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER6,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter6", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER7,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter7", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER8,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter8", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER9,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter9", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER10,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter10", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER11,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter11", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER12,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter12", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER13,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter13", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER14,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter14", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER15,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter15", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER16,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter16", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER17,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter17", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER18,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter18", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER19,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter19", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER20,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter20", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER21,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter21", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER22,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter22", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER23,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter23", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER24,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter24", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER25,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter25", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER26,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter26", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER27,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter27", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER28,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter28", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER29,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter29", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER30,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter30", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER31,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter31", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMIR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smir", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMLO0,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smlo0", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMEH,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smeh", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMCIR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smcir", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_FXCR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.fxcr", any, read_unimp_th_csr }
+    },
     { }
 };
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 2/5] hw/riscv: add k230 board initial support
  2025-11-30  9:21 [PATCH v1 0/5] Add K230 board and thead-c908 CPU support Chao Liu
  2025-11-30  9:21 ` [PATCH v1 1/5] target/riscv: add thead-c908 cpu support Chao Liu
@ 2025-11-30  9:21 ` Chao Liu
  2025-12-03 17:02   ` Daniel Henrique Barboza
  2025-11-30  9:21 ` [PATCH v1 3/5] hw/watchdog: add k230 watchdog " Chao Liu
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 16+ messages in thread
From: Chao Liu @ 2025-11-30  9:21 UTC (permalink / raw)
  To: richard.henderson, paolo.savini, npiggin, ebiggers, dbarboza,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches,
	Chao Liu

K230 Board Compatible with kendryte K230 SDK.

Preliminarily supports the C908 small core, which can
run the U-Boot and Linux kernel compiled by the K230 SDK.

Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
---
 MAINTAINERS             |   7 +
 hw/riscv/Kconfig        |  10 +
 hw/riscv/k230.c         | 483 ++++++++++++++++++++++++++++++++++++++++
 hw/riscv/meson.build    |   2 +-
 include/hw/riscv/k230.h | 149 +++++++++++++
 5 files changed, 650 insertions(+), 1 deletion(-)
 create mode 100644 hw/riscv/k230.c
 create mode 100644 include/hw/riscv/k230.h

diff --git a/MAINTAINERS b/MAINTAINERS
index a07086ed76..703d9e6b82 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1710,6 +1710,13 @@ F: docs/system/riscv/xiangshan-kunminghu.rst
 F: hw/riscv/xiangshan_kmh.c
 F: include/hw/riscv/xiangshan_kmh.h
 
+K230 Machines
+M: Chao Liu <chao.liu@zevorn.cn>
+S: Maintained
+F: docs/system/riscv/k230.rst
+F: hw/riscv/k230.c
+F: include/hw/riscv/k230.h
+
 RX Machines
 -----------
 rx-gdbsim
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index fc9c35bd98..624f166244 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -128,3 +128,13 @@ config XIANGSHAN_KUNMINGHU
     select RISCV_APLIC
     select RISCV_IMSIC
     select SERIAL_MM
+
+config K230
+    bool
+    default y
+    depends on RISCV64
+    select RISCV_ACLINT
+    select RISCV_APLIC
+    select RISCV_IMSIC
+    select SERIAL_MM
+    select UNIMP
\ No newline at end of file
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
new file mode 100644
index 0000000000..f41e9b7002
--- /dev/null
+++ b/hw/riscv/k230.c
@@ -0,0 +1,483 @@
+/*
+ * QEMU RISC-V Virt Board Compatible with Kendryte K230 SDK
+ *
+ * Copyright (c) 2025 Chao Liu <chao.liu@zevorn.cn>
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the Kendryte K230 SDK
+ *
+ * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu-qom.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "system/system.h"
+#include "system/memory.h"
+#include "target/riscv/cpu.h"
+#include "chardev/char.h"
+#include "hw/loader.h"
+#include "hw/sysbus.h"
+#include "hw/riscv/k230.h"
+#include "hw/riscv/boot.h"
+#include "hw/intc/riscv_aclint.h"
+#include "hw/intc/sifive_plic.h"
+#include "hw/char/serial-mm.h"
+#include "hw/misc/unimp.h"
+
+static const MemMapEntry memmap[] = {
+    [K230_DEV_DDRC] =         { 0x00000000, 0x80000000 },
+    [K230_DEV_KPU_L2_CACHE] = { 0x80000000, 0x00200000 },
+    [K230_DEV_SRAM] =         { 0x80200000, 0x00200000 },
+    [K230_DEV_KPU_CFG] =      { 0x80400000, 0x00000800 },
+    [K230_DEV_FFT] =          { 0x80400800, 0x00000400 },
+    [K230_DEV_AI_2D_ENGINE] = { 0x80400C00, 0x00000800 },
+    [K230_DEV_GSDMA] =        { 0x80800000, 0x00004000 },
+    [K230_DEV_DMA] =          { 0x80804000, 0x00004000 },
+    [K230_DEV_DECOMP_GZIP] =  { 0x80808000, 0x00004000 },
+    [K230_DEV_NON_AI_2D] =    { 0x8080C000, 0x00004000 },
+    [K230_DEV_ISP] =          { 0x90000000, 0x00008000 },
+    [K230_DEV_DEWARP] =       { 0x90008000, 0x00001000 },
+    [K230_DEV_RX_CSI] =       { 0x90009000, 0x00002000 },
+    [K230_DEV_H264] =         { 0x90400000, 0x00010000 },
+    [K230_DEV_2P5D] =         { 0x90800000, 0x00040000 },
+    [K230_DEV_VO] =           { 0x90840000, 0x00010000 },
+    [K230_DEV_VO_CFG] =       { 0x90850000, 0x00001000 },
+    [K230_DEV_3D_ENGINE] =    { 0x90A00000, 0x00000800 },
+    [K230_DEV_PMU] =          { 0x91000000, 0x00000C00 },
+    [K230_DEV_RTC] =          { 0x91000C00, 0x00000400 },
+    [K230_DEV_CMU] =          { 0x91100000, 0x00001000 },
+    [K230_DEV_RMU] =          { 0x91101000, 0x00001000 },
+    [K230_DEV_BOOT] =         { 0x91102000, 0x00001000 },
+    [K230_DEV_PWR] =          { 0x91103000, 0x00001000 },
+    [K230_DEV_MAILBOX] =      { 0x91104000, 0x00001000 },
+    [K230_DEV_IOMUX] =        { 0x91105000, 0x00000800 },
+    [K230_DEV_TIMER] =        { 0x91105800, 0x00000800 },
+    [K230_DEV_WDT0] =         { 0x91106000, 0x00000800 },
+    [K230_DEV_WDT1] =         { 0x91106800, 0x00000800 },
+    [K230_DEV_TS] =           { 0x91107000, 0x00000800 },
+    [K230_DEV_HDI] =          { 0x91107800, 0x00000800 },
+    [K230_DEV_STC] =          { 0x91108000, 0x00000800 },
+    [K230_DEV_BOOTROM] =      { 0x91200000, 0x00010000 },
+    [K230_DEV_SECURITY] =     { 0x91210000, 0x00008000 },
+    [K230_DEV_UART0] =        { 0x91400000, 0x00001000 },
+    [K230_DEV_UART1] =        { 0x91401000, 0x00001000 },
+    [K230_DEV_UART2] =        { 0x91402000, 0x00001000 },
+    [K230_DEV_UART3] =        { 0x91403000, 0x00001000 },
+    [K230_DEV_UART4] =        { 0x91404000, 0x00001000 },
+    [K230_DEV_I2C0] =         { 0x91405000, 0x00001000 },
+    [K230_DEV_I2C1] =         { 0x91406000, 0x00001000 },
+    [K230_DEV_I2C2] =         { 0x91407000, 0x00001000 },
+    [K230_DEV_I2C3] =         { 0x91408000, 0x00001000 },
+    [K230_DEV_I2C4] =         { 0x91409000, 0x00001000 },
+    [K230_DEV_PWM] =          { 0x9140A000, 0x00001000 },
+    [K230_DEV_GPIO0] =        { 0x9140B000, 0x00001000 },
+    [K230_DEV_GPIO1] =        { 0x9140C000, 0x00001000 },
+    [K230_DEV_ADC] =          { 0x9140D000, 0x00001000 },
+    [K230_DEV_CODEC] =        { 0x9140E000, 0x00001000 },
+    [K230_DEV_I2S] =          { 0x9140F000, 0x00001000 },
+    [K230_DEV_USB0] =         { 0x91500000, 0x00010000 },
+    [K230_DEV_USB1] =         { 0x91540000, 0x00010000 },
+    [K230_DEV_SD0] =          { 0x91580000, 0x00001000 },
+    [K230_DEV_SD1] =          { 0x91581000, 0x00001000 },
+    [K230_DEV_QSPI0] =        { 0x91582000, 0x00001000 },
+    [K230_DEV_QSPI1] =        { 0x91583000, 0x00001000 },
+    [K230_DEV_SPI] =          { 0x91584000, 0x00001000 },
+    [K230_DEV_HI_SYS_CFG] =   { 0x91585000, 0x00000400 },
+    [K230_DEV_DDRC_CFG] =     { 0x98000000, 0x02000000 },
+    [K230_DEV_FLASH] =        { 0xC0000000, 0x08000000 },
+    [K230_DEV_PLIC] =         { 0xF0000000, 0x00400000 },
+    [K230_DEV_CLINT] =        { 0xF0400000, 0x00400000 },
+};
+
+static void k230_soc_init(Object *obj)
+{
+    K230SoCState *s = RISCV_K230_SOC(obj);
+    RISCVHartArrayState *cpu0 = &s->c908_cpu;
+
+    object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
+    qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
+    qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
+    qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
+                         memmap[K230_DEV_BOOTROM].base);
+}
+
+static DeviceState *k230_create_plic(int base_hartid, int hartid_count)
+{
+    g_autofree char *plic_hart_config = NULL;
+
+    /* Per-socket PLIC hart topology configuration string */
+    plic_hart_config = riscv_plic_hart_config_string(hartid_count);
+
+    /* Per-socket PLIC */
+    return sifive_plic_create(memmap[K230_DEV_PLIC].base,
+                              plic_hart_config, hartid_count, base_hartid,
+                              K230_PLIC_NUM_SOURCES,
+                              K230_PLIC_NUM_PRIORITIES,
+                              K230_PLIC_PRIORITY_BASE, K230_PLIC_PENDING_BASE,
+                              K230_PLIC_ENABLE_BASE, K230_PLIC_ENABLE_STRIDE,
+                              K230_PLIC_CONTEXT_BASE,
+                              K230_PLIC_CONTEXT_STRIDE,
+                              memmap[K230_DEV_PLIC].size);
+}
+
+static void k230_soc_realize(DeviceState *dev, Error **errp)
+{
+    K230SoCState *s = RISCV_K230_SOC(dev);
+    MemoryRegion *sys_mem = get_system_memory();
+    int c908_cpus;
+
+    sysbus_realize(SYS_BUS_DEVICE(&s->c908_cpu), &error_fatal);
+
+    c908_cpus = s->c908_cpu.num_harts;
+
+    /* SRAM */
+    memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
+                           memmap[K230_DEV_SRAM].size, &error_fatal);
+    memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
+                                &s->sram);
+
+    /* BootROM */
+    memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
+                           memmap[K230_DEV_BOOTROM].size, &error_fatal);
+    memory_region_add_subregion(sys_mem, memmap[K230_DEV_BOOTROM].base,
+                                &s->bootrom);
+
+    /* PLIC */
+    s->c908_plic = k230_create_plic(C908_CPU_HARTID, c908_cpus);
+
+    /* CLINT */
+    riscv_aclint_swi_create(memmap[K230_DEV_CLINT].base,
+                            C908_CPU_HARTID, c908_cpus, false);
+    riscv_aclint_mtimer_create(memmap[K230_DEV_CLINT].base + 0x4000,
+                               RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
+                               C908_CPU_HARTID, c908_cpus,
+                               RISCV_ACLINT_DEFAULT_MTIMECMP,
+                               RISCV_ACLINT_DEFAULT_MTIME,
+                               RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
+
+    /* UART */
+    serial_mm_init(sys_mem, memmap[K230_DEV_UART0].base, 2,
+                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART0_IRQ),
+                   399193, serial_hd(0), DEVICE_LITTLE_ENDIAN);
+    serial_mm_init(sys_mem, memmap[K230_DEV_UART1].base, 2,
+                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART1_IRQ),
+                   399193, serial_hd(1), DEVICE_LITTLE_ENDIAN);
+    serial_mm_init(sys_mem, memmap[K230_DEV_UART2].base, 2,
+                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART2_IRQ),
+                   399193, serial_hd(2), DEVICE_LITTLE_ENDIAN);
+    serial_mm_init(sys_mem, memmap[K230_DEV_UART3].base, 2,
+                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART3_IRQ),
+                   399193, serial_hd(3), DEVICE_LITTLE_ENDIAN);
+    serial_mm_init(sys_mem, memmap[K230_DEV_UART4].base, 2,
+                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART4_IRQ),
+                   399193, serial_hd(4), DEVICE_LITTLE_ENDIAN);
+
+    /* unimplemented devices */
+    create_unimplemented_device("kpu.l2-cache",
+                                memmap[K230_DEV_KPU_L2_CACHE].base,
+                                memmap[K230_DEV_KPU_L2_CACHE].size);
+
+    create_unimplemented_device("kpu_cfg", memmap[K230_DEV_KPU_CFG].base,
+                                memmap[K230_DEV_KPU_CFG].size);
+
+    create_unimplemented_device("fft", memmap[K230_DEV_FFT].base,
+                                memmap[K230_DEV_FFT].size);
+
+    create_unimplemented_device("2d-engine.ai",
+                                memmap[K230_DEV_AI_2D_ENGINE].base,
+                                memmap[K230_DEV_AI_2D_ENGINE].size);
+
+    create_unimplemented_device("gsdma", memmap[K230_DEV_GSDMA].base,
+                                memmap[K230_DEV_GSDMA].size);
+
+    create_unimplemented_device("dma", memmap[K230_DEV_DMA].base,
+                                memmap[K230_DEV_DMA].size);
+
+    create_unimplemented_device("decomp-gzip",
+                                memmap[K230_DEV_DECOMP_GZIP].base,
+                                memmap[K230_DEV_DECOMP_GZIP].size);
+
+    create_unimplemented_device("2d-engine.non-ai",
+                                memmap[K230_DEV_NON_AI_2D].base,
+                                memmap[K230_DEV_NON_AI_2D].size);
+
+    create_unimplemented_device("isp", memmap[K230_DEV_ISP].base,
+                                memmap[K230_DEV_ISP].size);
+
+    create_unimplemented_device("dewarp", memmap[K230_DEV_DEWARP].base,
+                                memmap[K230_DEV_DEWARP].size);
+
+    create_unimplemented_device("rx-csi", memmap[K230_DEV_RX_CSI].base,
+                                memmap[K230_DEV_RX_CSI].size);
+
+    create_unimplemented_device("vpu", memmap[K230_DEV_H264].base,
+                                memmap[K230_DEV_H264].size);
+
+    create_unimplemented_device("gpu", memmap[K230_DEV_2P5D].base,
+                                memmap[K230_DEV_2P5D].size);
+
+    create_unimplemented_device("vo", memmap[K230_DEV_VO].base,
+                                memmap[K230_DEV_VO].size);
+
+    create_unimplemented_device("vo_cfg", memmap[K230_DEV_VO_CFG].base,
+                                memmap[K230_DEV_VO_CFG].size);
+
+    create_unimplemented_device("3d-engine", memmap[K230_DEV_3D_ENGINE].base,
+                                memmap[K230_DEV_3D_ENGINE].size);
+
+    create_unimplemented_device("pmu", memmap[K230_DEV_PMU].base,
+                                memmap[K230_DEV_PMU].size);
+
+    create_unimplemented_device("rtc", memmap[K230_DEV_RTC].base,
+                                memmap[K230_DEV_RTC].size);
+
+    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);
+
+    create_unimplemented_device("pwr", memmap[K230_DEV_PWR].base,
+                                memmap[K230_DEV_PWR].size);
+
+    create_unimplemented_device("ipcm", memmap[K230_DEV_MAILBOX].base,
+                                memmap[K230_DEV_MAILBOX].size);
+
+    create_unimplemented_device("iomux", memmap[K230_DEV_IOMUX].base,
+                                memmap[K230_DEV_IOMUX].size);
+
+    create_unimplemented_device("timer", memmap[K230_DEV_TIMER].base,
+                                memmap[K230_DEV_TIMER].size);
+
+    create_unimplemented_device("wdt0", memmap[K230_DEV_WDT0].base,
+                                memmap[K230_DEV_WDT0].size);
+
+    create_unimplemented_device("wdt1", memmap[K230_DEV_WDT1].base,
+                                memmap[K230_DEV_WDT1].size);
+
+    create_unimplemented_device("ts", memmap[K230_DEV_TS].base,
+                                memmap[K230_DEV_TS].size);
+
+    create_unimplemented_device("hdi", memmap[K230_DEV_HDI].base,
+                                memmap[K230_DEV_HDI].size);
+
+    create_unimplemented_device("stc", memmap[K230_DEV_STC].base,
+                                memmap[K230_DEV_STC].size);
+
+    create_unimplemented_device("security", memmap[K230_DEV_SECURITY].base,
+                                memmap[K230_DEV_SECURITY].size);
+
+    create_unimplemented_device("i2c0", memmap[K230_DEV_I2C0].base,
+                                memmap[K230_DEV_I2C0].size);
+
+    create_unimplemented_device("i2c1", memmap[K230_DEV_I2C1].base,
+                                memmap[K230_DEV_I2C1].size);
+
+    create_unimplemented_device("i2c2", memmap[K230_DEV_I2C2].base,
+                                memmap[K230_DEV_I2C2].size);
+
+    create_unimplemented_device("i2c3", memmap[K230_DEV_I2C3].base,
+                                memmap[K230_DEV_I2C3].size);
+
+    create_unimplemented_device("i2c4", memmap[K230_DEV_I2C4].base,
+                                memmap[K230_DEV_I2C4].size);
+
+    create_unimplemented_device("pwm", memmap[K230_DEV_PWM].base,
+                                memmap[K230_DEV_PWM].size);
+
+    create_unimplemented_device("gpio0", memmap[K230_DEV_GPIO0].base,
+                                memmap[K230_DEV_GPIO0].size);
+
+    create_unimplemented_device("gpio1", memmap[K230_DEV_GPIO1].base,
+                                memmap[K230_DEV_GPIO1].size);
+
+    create_unimplemented_device("adc", memmap[K230_DEV_ADC].base,
+                                memmap[K230_DEV_ADC].size);
+
+    create_unimplemented_device("codec", memmap[K230_DEV_CODEC].base,
+                                memmap[K230_DEV_CODEC].size);
+
+    create_unimplemented_device("i2s", memmap[K230_DEV_I2S].base,
+                                memmap[K230_DEV_I2S].size);
+
+    create_unimplemented_device("usb0", memmap[K230_DEV_USB0].base,
+                                memmap[K230_DEV_USB0].size);
+
+    create_unimplemented_device("usb1", memmap[K230_DEV_USB1].base,
+                                memmap[K230_DEV_USB1].size);
+
+    create_unimplemented_device("sd0", memmap[K230_DEV_SD0].base,
+                                memmap[K230_DEV_SD0].size);
+
+    create_unimplemented_device("sd1", memmap[K230_DEV_SD1].base,
+                                memmap[K230_DEV_SD1].size);
+
+    create_unimplemented_device("qspi0", memmap[K230_DEV_QSPI0].base,
+                                memmap[K230_DEV_QSPI0].size);
+
+    create_unimplemented_device("qspi1", memmap[K230_DEV_QSPI1].base,
+                                memmap[K230_DEV_QSPI1].size);
+
+    create_unimplemented_device("spi", memmap[K230_DEV_SPI].base,
+                                memmap[K230_DEV_SPI].size);
+
+    create_unimplemented_device("hi_sys_cfg", memmap[K230_DEV_HI_SYS_CFG].base,
+                                memmap[K230_DEV_HI_SYS_CFG].size);
+
+    create_unimplemented_device("ddrc_cfg", memmap[K230_DEV_DDRC_CFG].base,
+                                memmap[K230_DEV_DDRC_CFG].size);
+
+    create_unimplemented_device("flash", memmap[K230_DEV_FLASH].base,
+                                memmap[K230_DEV_FLASH].size);
+}
+
+static void k230_soc_class_init(ObjectClass *oc, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = k230_soc_realize;
+}
+
+static const TypeInfo k230_soc_type_info = {
+    .name = TYPE_RISCV_K230_SOC,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(K230SoCState),
+    .instance_init = k230_soc_init,
+    .class_init = k230_soc_class_init,
+};
+
+static void k230_soc_register_types(void)
+{
+    type_register_static(&k230_soc_type_info);
+}
+
+type_init(k230_soc_register_types)
+
+static void k230_machine_done(Notifier *notifier, void *data)
+{
+    K230MachineState *s = container_of(notifier, K230MachineState,
+                                     machine_done);
+    MachineState *machine = MACHINE(s);
+    hwaddr start_addr = memmap[K230_DEV_DDRC].base;
+    target_ulong firmware_end_addr, kernel_start_addr;
+    const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
+    uint64_t kernel_entry = 0;
+    RISCVBootInfo boot_info;
+
+    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
+                                                     &start_addr, NULL);
+
+    /* Mask ROM reset vector */
+    uint32_t reset_vec[] = {
+        /* 0x91200000: auipc  t0, 0x0              */ 0x00000297,
+        /* 0x91200004: addi   t0, t0, 36 # <trap>  */ 0x02428293,
+        /* 0x91200008: csrw   mtvec, t0            */ 0x30529073,
+        /* 0x9120000C: csrr   a0, misa             */ 0x301012F3,
+        /* 0x91200010: lui    t0, 0x1              */ 0x000012B7,
+        /* 0x91200014: slli   t0, t0, 1            */ 0x00129293,
+        /* 0x91200018: and    t0, a0, t0           */ 0x005572B3,
+        /* 0x9120001C: bnez   t0, loop             */ 0x00511063,
+        /* entry:                                  */
+        /* 0x91200020: addiw  t0, zero, 1          */ 0x0010029b,
+        /* 0x91200024: slli   t0, t0, 0x1b         */ 0x01b29293,
+        /* 0x91200028: jr     t0 # uboot 0x8000000 */ 0x00028067,
+        /* loop:                                   */
+        /* 0x9120002C: j      0x9120002C # <loop>  */ 0x0000006f,
+        /* trap:                                   */
+        /* 0x91200030: j      0x91200030 # <trap>  */ 0x0000006f,
+    };
+
+    /* copy in the reset vector in little_endian byte order */
+    for (int i = 0; i < sizeof(reset_vec) >> 2; i++) {
+        reset_vec[i] = cpu_to_le32(reset_vec[i]);
+    }
+    rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
+                          memmap[K230_DEV_BOOTROM].base, &address_space_memory);
+
+    riscv_boot_info_init(&boot_info, &s->soc.c908_cpu);
+
+    if (machine->kernel_filename && !kernel_entry) {
+        kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
+                                                         firmware_end_addr);
+        riscv_load_kernel(machine, &boot_info, kernel_start_addr,
+                          true, NULL);
+        kernel_entry = boot_info.image_low_addr;
+    }
+}
+
+static void k230_machine_init(MachineState *machine)
+{
+    MachineClass *mc = MACHINE_GET_CLASS(machine);
+
+    K230MachineState *s = RISCV_K230_MACHINE(machine);
+    MemoryRegion *sys_mem = get_system_memory();
+
+    if (machine->ram_size < mc->default_ram_size) {
+        char *sz = size_to_str(mc->default_ram_size);
+        error_report("Invalid RAM size, should be %s", sz);
+        g_free(sz);
+        exit(EXIT_FAILURE);
+    }
+
+    /* Initialize SoC */
+    object_initialize_child(OBJECT(machine), "soc", &s->soc,
+                            TYPE_RISCV_K230_SOC);
+    qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
+
+    /* Data Memory */
+    memory_region_add_subregion(sys_mem, memmap[K230_DEV_DDRC].base,
+                                machine->ram);
+
+    s->machine_done.notify = k230_machine_done;
+    qemu_add_machine_init_done_notifier(&s->machine_done);
+}
+
+static void k230_machine_instance_init(Object *obj)
+{
+}
+
+static void k230_machine_class_init(ObjectClass *oc, const void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "RISC-V Board compatible with Kendryte K230 SDK";
+    mc->init = k230_machine_init;
+    mc->default_cpus = 2;
+    mc->default_ram_id = "riscv.K230.ram"; /* DDR */
+    mc->default_ram_size = memmap[K230_DEV_DDRC].size;
+}
+
+static const TypeInfo k230_machine_typeinfo = {
+    .name       = TYPE_RISCV_K230_MACHINE,
+    .parent     = TYPE_MACHINE,
+    .class_init = k230_machine_class_init,
+    .instance_init = k230_machine_instance_init,
+    .instance_size = sizeof(K230MachineState),
+};
+
+static void k230_machine_init_register_types(void)
+{
+    type_register_static(&k230_machine_typeinfo);
+}
+
+type_init(k230_machine_init_register_types)
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 2a8d5b136c..1e5ce511d4 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -14,5 +14,5 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
 	'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
 riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
 riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c'))
-
+riscv_ss.add(when: 'CONFIG_K230', if_true: files('k230.c'))
 hw_arch += {'riscv': riscv_ss}
diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
new file mode 100644
index 0000000000..3158381e8f
--- /dev/null
+++ b/include/hw/riscv/k230.h
@@ -0,0 +1,149 @@
+/*
+ * QEMU RISC-V Virt Board Compatible with kendryte K230 SDK
+ *
+ * Copyright (c) 2025 Chao Liu <chao.liu@zevorn.cn>
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the kendryte K230 SDK
+ *
+ * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef HW_K230_H
+#define HW_K230_H
+
+#include "hw/boards.h"
+#include "hw/riscv/riscv_hart.h"
+
+#define C908_CPU_HARTID   (0)
+
+#define TYPE_RISCV_K230_SOC "riscv.k230.soc"
+#define RISCV_K230_SOC(obj) \
+    OBJECT_CHECK(K230SoCState, (obj), TYPE_RISCV_K230_SOC)
+
+typedef struct K230SoCState {
+    /*< private >*/
+    DeviceState parent_obj;
+
+    /*< public >*/
+    RISCVHartArrayState c908_cpu; /* Small core */
+
+    MemoryRegion sram;
+    MemoryRegion bootrom;
+
+    DeviceState *c908_plic;
+} K230SoCState;
+
+#define TYPE_RISCV_K230_MACHINE MACHINE_TYPE_NAME("k230")
+#define RISCV_K230_MACHINE(obj) \
+    OBJECT_CHECK(K230MachineState, (obj), TYPE_RISCV_K230_MACHINE)
+
+typedef struct K230MachineState {
+    /*< private >*/
+    MachineState parent_obj;
+
+    /*< public >*/
+    K230SoCState soc;
+    Notifier machine_done;
+} K230MachineState;
+
+enum {
+    K230_DEV_DDRC,
+    K230_DEV_KPU_L2_CACHE,
+    K230_DEV_SRAM,
+    K230_DEV_KPU_CFG,
+    K230_DEV_FFT,
+    K230_DEV_AI_2D_ENGINE,
+    K230_DEV_GSDMA,
+    K230_DEV_DMA,
+    K230_DEV_DECOMP_GZIP,
+    K230_DEV_NON_AI_2D,
+    K230_DEV_ISP,
+    K230_DEV_DEWARP,
+    K230_DEV_RX_CSI,
+    K230_DEV_H264,
+    K230_DEV_2P5D,
+    K230_DEV_VO,
+    K230_DEV_VO_CFG,
+    K230_DEV_3D_ENGINE,
+    K230_DEV_PMU,
+    K230_DEV_RTC,
+    K230_DEV_CMU,
+    K230_DEV_RMU,
+    K230_DEV_BOOT,
+    K230_DEV_PWR,
+    K230_DEV_MAILBOX,
+    K230_DEV_IOMUX,
+    K230_DEV_TIMER,
+    K230_DEV_WDT0,
+    K230_DEV_WDT1,
+    K230_DEV_TS,
+    K230_DEV_HDI,
+    K230_DEV_STC,
+    K230_DEV_BOOTROM,
+    K230_DEV_SECURITY,
+    K230_DEV_UART0,
+    K230_DEV_UART1,
+    K230_DEV_UART2,
+    K230_DEV_UART3,
+    K230_DEV_UART4,
+    K230_DEV_I2C0,
+    K230_DEV_I2C1,
+    K230_DEV_I2C2,
+    K230_DEV_I2C3,
+    K230_DEV_I2C4,
+    K230_DEV_PWM,
+    K230_DEV_GPIO0,
+    K230_DEV_GPIO1,
+    K230_DEV_ADC,
+    K230_DEV_CODEC,
+    K230_DEV_I2S,
+    K230_DEV_USB0,
+    K230_DEV_USB1,
+    K230_DEV_SD0,
+    K230_DEV_SD1,
+    K230_DEV_QSPI0,
+    K230_DEV_QSPI1,
+    K230_DEV_SPI,
+    K230_DEV_HI_SYS_CFG,
+    K230_DEV_DDRC_CFG,
+    K230_DEV_FLASH,
+    K230_DEV_PLIC,
+    K230_DEV_CLINT,
+};
+
+enum {
+    K230_UART0_IRQ  = 16,
+    K230_UART1_IRQ  = 17,
+    K230_UART2_IRQ  = 18,
+    K230_UART3_IRQ  = 19,
+    K230_UART4_IRQ  = 20,
+};
+
+/*
+ * Integrates with the interrupt controller (PLIC),
+ * which can process 208 interrupt external sources
+ */
+#define K230_PLIC_NUM_SOURCES 208
+#define K230_PLIC_NUM_PRIORITIES 7
+#define K230_PLIC_PRIORITY_BASE 0x00
+#define K230_PLIC_PENDING_BASE 0x1000
+#define K230_PLIC_ENABLE_BASE 0x2000
+#define K230_PLIC_ENABLE_STRIDE 0x80
+#define K230_PLIC_CONTEXT_BASE 0x200000
+#define K230_PLIC_CONTEXT_STRIDE 0x1000
+
+#endif
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 3/5] hw/watchdog: add k230 watchdog initial support
  2025-11-30  9:21 [PATCH v1 0/5] Add K230 board and thead-c908 CPU support Chao Liu
  2025-11-30  9:21 ` [PATCH v1 1/5] target/riscv: add thead-c908 cpu support Chao Liu
  2025-11-30  9:21 ` [PATCH v1 2/5] hw/riscv: add k230 board initial support Chao Liu
@ 2025-11-30  9:21 ` Chao Liu
  2025-12-03 17:07   ` Daniel Henrique Barboza
  2025-11-30  9:21 ` [PATCH v1 4/5] tests/qtest: add test for K230 watchdog Chao Liu
  2025-11-30  9:21 ` [PATCH v1 5/5] docs/system/riscv: add documentation for k230 machine Chao Liu
  4 siblings, 1 reply; 16+ messages in thread
From: Chao Liu @ 2025-11-30  9:21 UTC (permalink / raw)
  To: richard.henderson, paolo.savini, npiggin, ebiggers, dbarboza,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches,
	Chao Liu, Mig Yang

Add programmable Watchdog Timer (WDT) peripheral for K230 machine.

Signed-off-by: Mig Yang <temashking@foxmail.com>
Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
---
 MAINTAINERS                    |   2 +
 hw/riscv/Kconfig               |   3 +-
 hw/riscv/k230.c                |  18 ++
 hw/watchdog/Kconfig            |   4 +
 hw/watchdog/k230_wdt.c         | 307 +++++++++++++++++++++++++++++++++
 hw/watchdog/meson.build        |   1 +
 hw/watchdog/trace-events       |   9 +
 include/hw/riscv/k230.h        |   4 +
 include/hw/watchdog/k230_wdt.h | 130 ++++++++++++++
 9 files changed, 477 insertions(+), 1 deletion(-)
 create mode 100644 hw/watchdog/k230_wdt.c
 create mode 100644 include/hw/watchdog/k230_wdt.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 703d9e6b82..564c2af56d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1715,7 +1715,9 @@ M: Chao Liu <chao.liu@zevorn.cn>
 S: Maintained
 F: docs/system/riscv/k230.rst
 F: hw/riscv/k230.c
+F: hw/watchdog/k230_wdt.c
 F: include/hw/riscv/k230.h
+F: include/hw/watchdog/k230_wdt.h
 
 RX Machines
 -----------
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 624f166244..6faaa5cccc 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -137,4 +137,5 @@ config K230
     select RISCV_APLIC
     select RISCV_IMSIC
     select SERIAL_MM
-    select UNIMP
\ No newline at end of file
+    select UNIMP
+    select K230_WDT
\ No newline at end of file
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
index f41e9b7002..1460572429 100644
--- a/hw/riscv/k230.c
+++ b/hw/riscv/k230.c
@@ -112,6 +112,9 @@ static void k230_soc_init(Object *obj)
     RISCVHartArrayState *cpu0 = &s->c908_cpu;
 
     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);
+
     qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
     qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
     qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
@@ -189,6 +192,21 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
                    qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART4_IRQ),
                    399193, serial_hd(4), DEVICE_LITTLE_ENDIAN);
 
+    /* Watchdog */
+    for (int i = 0; i < 2; i++) {
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
+            return;
+        }
+    }
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[0]), 0, memmap[K230_DEV_WDT0].base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[0]), 0,
+                       qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT0_IRQ));
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[1]), 0, memmap[K230_DEV_WDT1].base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0,
+                       qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ));
+
     /* unimplemented devices */
     create_unimplemented_device("kpu.l2-cache",
                                 memmap[K230_DEV_KPU_L2_CACHE].base,
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
index 861fd00334..55f77c5c84 100644
--- a/hw/watchdog/Kconfig
+++ b/hw/watchdog/Kconfig
@@ -18,6 +18,10 @@ config WDT_DIAG288
 config WDT_IMX2
     bool
 
+config K230_WDT
+    bool
+    select PTIMER
+
 config WDT_SBSA
     bool
 
diff --git a/hw/watchdog/k230_wdt.c b/hw/watchdog/k230_wdt.c
new file mode 100644
index 0000000000..f385319836
--- /dev/null
+++ b/hw/watchdog/k230_wdt.c
@@ -0,0 +1,307 @@
+/*
+ *  * K230 Watchdog Compatible with kendryte K230 SDK
+ *
+ * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
+ * Copyright (c) 2025 Chao Liu <chao.liu@zevorn.cn>
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the kendryte K230 SDK
+ *
+ * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/module.h"
+#include "system/watchdog.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+
+#include "hw/watchdog/k230_wdt.h"
+#include "trace.h"
+
+static void k230_wdt_timeout(void *opaque)
+{
+    K230WdtState *s = K230_WDT(opaque);
+
+    trace_k230_wdt_timeout();
+
+    /* Set interrupt status if in interrupt mode */
+    if (s->cr & K230_WDT_CR_RMOD) {
+        s->stat |= K230_WDT_STAT_INT;
+        s->interrupt_pending = true;
+        qemu_set_irq(s->irq, 1);
+        trace_k230_wdt_interrupt();
+    } else {
+        /* Direct reset mode */
+        trace_k230_wdt_reset();
+        watchdog_perform_action();
+    }
+
+    /* Restart counter */
+    s->current_count = s->timeout_value;
+    ptimer_set_count(s->timer, s->current_count);
+    ptimer_run(s->timer, 1);
+}
+
+static void k230_wdt_reset(DeviceState *dev)
+{
+    K230WdtState *s = K230_WDT(dev);
+
+    trace_k230_wdt_reset_device();
+
+    ptimer_transaction_begin(s->timer);
+    ptimer_stop(s->timer);
+    ptimer_transaction_commit(s->timer);
+
+    /* Reset registers to default values */
+    s->cr = 0;
+    s->torr = 0;
+    s->ccvr = 0xFFFFFFFF;
+    s->stat = 0;
+    s->prot_level = 0x2;
+
+    s->interrupt_pending = false;
+    s->enabled = false;
+    s->timeout_value = 0;
+    s->current_count = 0xFFFFFFFF;
+}
+
+static uint64_t k230_wdt_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    K230WdtState *s = K230_WDT(opaque);
+    uint32_t value = 0;
+
+    switch (addr) {
+    case K230_WDT_CR:
+        value = s->cr;
+        break;
+    case K230_WDT_TORR:
+        value = s->torr;
+        break;
+    case K230_WDT_CCVR:
+        if (s->enabled) {
+            value = ptimer_get_count(s->timer);
+        } else {
+            value = s->current_count;
+        }
+        break;
+    case K230_WDT_STAT:
+        value = s->stat;
+        break;
+    case K230_WDT_PROT_LEVEL:
+        value = s->prot_level;
+        break;
+    case K230_WDT_COMP_PARAM_5:
+        value = 0; /* Upper limit of Timeout Period parameters */
+        break;
+    case K230_WDT_COMP_PARAM_4:
+        value = 0; /* Upper limit of Initial Timeout Period parameters */
+        break;
+    case K230_WDT_COMP_PARAM_3:
+        value = 0; /* Derived from WDT_TOP_RST parameter */
+        break;
+    case K230_WDT_COMP_PARAM_2:
+        value = 0xFFFFFFFF; /* Derived from WDT_RST_CNT parameter */
+        break;
+    case K230_WDT_COMP_PARAM_1:
+        /* Component parameters */
+        value = (32 << K230_WDT_CNT_WIDTH_SHIFT) |  /* 32-bit counter */
+                (0 << K230_WDT_DFLT_TOP_INIT_SHIFT) |
+                (0 << K230_WDT_DFLT_TOP_SHIFT) |
+                (K230_WDT_RPL_16_CYCLES << K230_WDT_DFLT_RPL_SHIFT) |
+                (2 << K230_WDT_APB_DATA_WIDTH_SHIFT) | /* 32-bit APB */
+                K230_WDT_USE_FIX_TOP; /* Use fixed timeout values */
+        break;
+    case K230_WDT_COMP_VERSION:
+        value = K230_WDT_COMP_VERSION_VAL;
+        break;
+    case K230_WDT_COMP_TYPE:
+        value = K230_WDT_COMP_TYPE_VAL;
+        break;
+    default:
+        /* Other registers return 0 */
+        break;
+    }
+
+    trace_k230_wdt_read(addr, value);
+    return value;
+}
+
+static void k230_wdt_update_timer(K230WdtState *s)
+{
+    ptimer_transaction_begin(s->timer);
+
+    if (s->enabled && s->timeout_value > 0) {
+        ptimer_set_count(s->timer, s->current_count);
+        ptimer_run(s->timer, 1);
+    } else {
+        ptimer_stop(s->timer);
+    }
+
+    ptimer_transaction_commit(s->timer);
+}
+
+static uint32_t k230_wdt_calculate_timeout(uint32_t top_value)
+{
+    /* Calculate timeout based on TOP value */
+    /* For fixed timeout mode: 2^(16 + top_value) */
+    if (top_value <= 15) {
+        return 1 << (16 + top_value);
+    }
+    return 1 << 31; /* Maximum value for 32-bit counter */
+}
+
+static void k230_wdt_write(void *opaque, hwaddr addr,
+                           uint64_t value, unsigned int size)
+{
+    K230WdtState *s = K230_WDT(opaque);
+
+    trace_k230_wdt_write(addr, value);
+
+    switch (addr) {
+    case K230_WDT_CR:
+        s->cr = value & (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT |
+                         K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+
+        /* Update enabled state */
+        s->enabled = (s->cr & K230_WDT_CR_WDT_EN) != 0;
+
+        /* Update timer */
+        k230_wdt_update_timer(s);
+        break;
+
+    case K230_WDT_TORR:
+        s->torr = value & K230_WDT_TORR_TOP_MASK;
+
+        /* Calculate new timeout value */
+        s->timeout_value = k230_wdt_calculate_timeout(s->torr);
+        s->current_count = s->timeout_value;
+
+        /* Update timer if enabled */
+        if (s->enabled) {
+            k230_wdt_update_timer(s);
+        }
+        break;
+
+    case K230_WDT_CRR:
+        /* Restart counter with magic value 0x76 */
+        if ((value & 0xFF) == K230_WDT_CRR_RESTART) {
+            trace_k230_wdt_restart();
+            s->current_count = s->timeout_value;
+
+            /* Clear interrupt if pending */
+            if (s->interrupt_pending) {
+                s->stat &= ~K230_WDT_STAT_INT;
+                s->interrupt_pending = false;
+                qemu_set_irq(s->irq, 0);
+            }
+
+            /* Update timer */
+            k230_wdt_update_timer(s);
+        }
+        break;
+
+    case K230_WDT_EOI:
+        /* Clear interrupt */
+        s->stat &= ~K230_WDT_STAT_INT;
+        s->interrupt_pending = false;
+        qemu_set_irq(s->irq, 0);
+        break;
+
+    case K230_WDT_PROT_LEVEL:
+        s->prot_level = value & 0x7;
+        break;
+
+    default:
+        /* Read-only registers, ignore writes */
+        break;
+    }
+}
+
+static const MemoryRegionOps k230_wdt_ops = {
+    .read  = k230_wdt_read,
+    .write = k230_wdt_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false,
+    },
+};
+
+static const VMStateDescription vmstate_k230_wdt = {
+    .name = "k230.wdt",
+    .fields = (const VMStateField[]) {
+        VMSTATE_PTIMER(timer, K230WdtState),
+        VMSTATE_UINT32(cr, K230WdtState),
+        VMSTATE_UINT32(torr, K230WdtState),
+        VMSTATE_UINT32(ccvr, K230WdtState),
+        VMSTATE_UINT32(stat, K230WdtState),
+        VMSTATE_UINT32(prot_level, K230WdtState),
+        VMSTATE_BOOL(interrupt_pending, K230WdtState),
+        VMSTATE_BOOL(enabled, K230WdtState),
+        VMSTATE_UINT32(timeout_value, K230WdtState),
+        VMSTATE_UINT32(current_count, K230WdtState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void k230_wdt_realize(DeviceState *dev, Error **errp)
+{
+    K230WdtState *s = K230_WDT(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->mmio, OBJECT(dev),
+                          &k230_wdt_ops, s,
+                          TYPE_K230_WDT,
+                          K230_WDT_MMIO_SIZE);
+    sysbus_init_mmio(sbd, &s->mmio);
+    sysbus_init_irq(sbd, &s->irq);
+
+    s->timer = ptimer_init(k230_wdt_timeout, s,
+                           PTIMER_POLICY_NO_IMMEDIATE_TRIGGER |
+                           PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
+                           PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
+
+    ptimer_transaction_begin(s->timer);
+    ptimer_set_freq(s->timer, K230_WDT_DEFAULT_FREQ);
+    ptimer_transaction_commit(s->timer);
+}
+
+static void k230_wdt_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = k230_wdt_realize;
+    device_class_set_legacy_reset(dc, k230_wdt_reset);
+    dc->vmsd = &vmstate_k230_wdt;
+    dc->desc = "K230 watchdog timer";
+    set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
+}
+
+static const TypeInfo k230_wdt_info = {
+    .name          = TYPE_K230_WDT,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(K230WdtState),
+    .class_init    = k230_wdt_class_init,
+};
+
+static void k230_wdt_register_type(void)
+{
+    type_register_static(&k230_wdt_info);
+}
+type_init(k230_wdt_register_type)
diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
index 15370565bd..5edae65a36 100644
--- a/hw/watchdog/meson.build
+++ b/hw/watchdog/meson.build
@@ -6,5 +6,6 @@ system_ss.add(when: 'CONFIG_WDT_IB700', if_true: files('wdt_ib700.c'))
 system_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
 system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
 system_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
+system_ss.add(when: 'CONFIG_K230_WDT', if_true: files('k230_wdt.c'))
 system_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
 specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_watchdog.c'))
diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events
index ad3be1e9bd..d85b3ca769 100644
--- a/hw/watchdog/trace-events
+++ b/hw/watchdog/trace-events
@@ -33,3 +33,12 @@ spapr_watchdog_expired(uint64_t num, unsigned action) "num=%" PRIu64 " action=%u
 # watchdog.c
 watchdog_perform_action(unsigned int action) "action=%u"
 watchdog_set_action(unsigned int action) "action=%u"
+
+# k230_wdt.c
+k230_wdt_read(uint64_t addr, uint32_t data) "K230 WDT read: [0x%" PRIx64 "] -> 0x%" PRIx32
+k230_wdt_write(uint64_t addr, uint64_t data) "K230 WDT write: [0x%" PRIx64 "] <- 0x%" PRIx64
+k230_wdt_timeout(void) "K230 WDT timeout"
+k230_wdt_interrupt(void) "K230 WDT interrupt"
+k230_wdt_reset(void) "K230 WDT system reset"
+k230_wdt_restart(void) "K230 WDT restart"
+k230_wdt_reset_device(void) "K230 WDT device reset"
diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
index 3158381e8f..f2eedd5f70 100644
--- a/include/hw/riscv/k230.h
+++ b/include/hw/riscv/k230.h
@@ -27,6 +27,7 @@
 
 #include "hw/boards.h"
 #include "hw/riscv/riscv_hart.h"
+#include "hw/watchdog/k230_wdt.h"
 
 #define C908_CPU_HARTID   (0)
 
@@ -41,6 +42,7 @@ typedef struct K230SoCState {
     /*< public >*/
     RISCVHartArrayState c908_cpu; /* Small core */
 
+    K230WdtState wdt[2];
     MemoryRegion sram;
     MemoryRegion bootrom;
 
@@ -131,6 +133,8 @@ enum {
     K230_UART2_IRQ  = 18,
     K230_UART3_IRQ  = 19,
     K230_UART4_IRQ  = 20,
+    K230_WDT0_IRQ   = 32,
+    K230_WDT1_IRQ   = 33,
 };
 
 /*
diff --git a/include/hw/watchdog/k230_wdt.h b/include/hw/watchdog/k230_wdt.h
new file mode 100644
index 0000000000..9371602387
--- /dev/null
+++ b/include/hw/watchdog/k230_wdt.h
@@ -0,0 +1,130 @@
+/*
+ * K230 Watchdog Timer
+ *
+ * Based on K230 technical documentation
+ *
+ * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef K230_WDT_H
+#define K230_WDT_H
+
+#include "qemu/bitops.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "hw/ptimer.h"
+#include "qom/object.h"
+
+#define TYPE_K230_WDT "riscv.k230.wdt"
+OBJECT_DECLARE_SIMPLE_TYPE(K230WdtState, K230_WDT)
+
+#define K230_WDT_DEFAULT_FREQ (32768)
+
+/* K230 Watchdog Register Map */
+enum K230WdtRegisters {
+    K230_WDT_CR      = 0x00,  /* Control Register */
+    K230_WDT_TORR    = 0x04,  /* Timeout Range Register */
+    K230_WDT_CCVR    = 0x08,  /* Current Counter Value Register */
+    K230_WDT_CRR     = 0x0c,  /* Counter Restart Register */
+    K230_WDT_STAT    = 0x10,  /* Interrupt Status Register */
+    K230_WDT_EOI     = 0x14,  /* Interrupt Clear Register */
+    K230_WDT_PROT_LEVEL = 0x1c, /* Protection Level Register */
+    K230_WDT_COMP_PARAM_5 = 0xe4, /* Component Parameters Register 5 */
+    K230_WDT_COMP_PARAM_4 = 0xe8, /* Component Parameters Register 4 */
+    K230_WDT_COMP_PARAM_3 = 0xec, /* Component Parameters Register 3 */
+    K230_WDT_COMP_PARAM_2 = 0xf0, /* Component Parameters Register 2 */
+    K230_WDT_COMP_PARAM_1 = 0xf4, /* Component Parameters Register 1 */
+    K230_WDT_COMP_VERSION = 0xf8, /* Component Version Register */
+    K230_WDT_COMP_TYPE = 0xfc, /* Component Type Register */
+};
+
+#define K230_WDT_MMIO_SIZE 0x100
+
+/* Control Register (WDT_CR) definitions */
+#define K230_WDT_CR_RPL_MASK    0x7        /* Reset Pulse Length */
+#define K230_WDT_CR_RPL_SHIFT   2
+#define K230_WDT_CR_RMOD        BIT(1)     /* Response Mode */
+#define K230_WDT_CR_WDT_EN      BIT(0)     /* Watchdog Enable */
+
+/* Reset Pulse Length values */
+#define K230_WDT_RPL_2_CYCLES   0x0
+#define K230_WDT_RPL_4_CYCLES   0x1
+#define K230_WDT_RPL_8_CYCLES   0x2
+#define K230_WDT_RPL_16_CYCLES  0x3
+#define K230_WDT_RPL_32_CYCLES  0x4
+#define K230_WDT_RPL_64_CYCLES  0x5
+#define K230_WDT_RPL_128_CYCLES 0x6
+#define K230_WDT_RPL_256_CYCLES 0x7
+
+/* Timeout Range Register (WDT_TORR) definitions */
+#define K230_WDT_TORR_TOP_MASK  0xf        /* Timeout Period */
+
+/* Interrupt Status Register (WDT_STAT) definitions */
+#define K230_WDT_STAT_INT       BIT(0)     /* Interrupt Status */
+
+/* Counter Restart Register (WDT_CRR) magic value */
+#define K230_WDT_CRR_RESTART    0x76       /* Restart command */
+
+/* Component Parameters Register 1 (WDT_COMP_PARAM_1) definitions */
+#define K230_WDT_CNT_WIDTH_MASK 0x1f000000 /* Counter Width */
+#define K230_WDT_CNT_WIDTH_SHIFT 24
+#define K230_WDT_DFLT_TOP_INIT_MASK 0xf00000 /* Default Initial Timeout */
+#define K230_WDT_DFLT_TOP_INIT_SHIFT 20
+#define K230_WDT_DFLT_TOP_MASK  0xf0000    /* Default Timeout */
+#define K230_WDT_DFLT_TOP_SHIFT 16
+#define K230_WDT_DFLT_RPL_MASK  0x7        /* Default Reset Pulse Length */
+#define K230_WDT_DFLT_RPL_SHIFT 10
+#define K230_WDT_APB_DATA_WIDTH_MASK 0x3   /* APB Data Width */
+#define K230_WDT_APB_DATA_WIDTH_SHIFT 8
+#define K230_WDT_USE_FIX_TOP    BIT(6)     /* Use Fixed Timeout Values */
+#define K230_WDT_HC_TOP         BIT(5)     /* Hard-coded Timeout */
+#define K230_WDT_HC_RPL         BIT(4)     /* Hard-coded Reset Pulse Length */
+#define K230_WDT_HC_RMOD        BIT(3)     /* Hard-coded Response Mode */
+#define K230_WDT_DUAL_TOP       BIT(2)     /* Dual Timeout Period */
+#define K230_WDT_DFLT_RMOD      BIT(1)     /* Default Response Mode */
+#define K230_WDT_ALWAYS_EN      BIT(0)     /* Always Enabled */
+
+/* Component Type Register value */
+#define K230_WDT_COMP_TYPE_VAL  0x44570120
+
+/* Component Version Register value */
+#define K230_WDT_COMP_VERSION_VAL 0x3131302a  /* "110*" */
+
+struct K230WdtState {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion mmio;
+    qemu_irq irq;
+
+    struct ptimer_state *timer;
+
+    /* Register state */
+    uint32_t cr;           /* Control Register */
+    uint32_t torr;         /* Timeout Range Register */
+    uint32_t ccvr;         /* Current Counter Value Register */
+    uint32_t stat;         /* Interrupt Status Register */
+    uint32_t prot_level;   /* Protection Level Register */
+
+    /* Internal state */
+    bool interrupt_pending;
+    bool enabled;
+    uint32_t timeout_value;
+    uint32_t current_count;
+};
+
+#endif /* K230_WDT_H */
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 4/5] tests/qtest: add test for K230 watchdog
  2025-11-30  9:21 [PATCH v1 0/5] Add K230 board and thead-c908 CPU support Chao Liu
                   ` (2 preceding siblings ...)
  2025-11-30  9:21 ` [PATCH v1 3/5] hw/watchdog: add k230 watchdog " Chao Liu
@ 2025-11-30  9:21 ` Chao Liu
  2025-12-03 17:08   ` Daniel Henrique Barboza
  2025-11-30  9:21 ` [PATCH v1 5/5] docs/system/riscv: add documentation for k230 machine Chao Liu
  4 siblings, 1 reply; 16+ messages in thread
From: Chao Liu @ 2025-11-30  9:21 UTC (permalink / raw)
  To: richard.henderson, paolo.savini, npiggin, ebiggers, dbarboza,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches,
	Chao Liu, Mig Yang

Testing the Basic Functions of K230 WDT:
1. Reset Function
2. Timeout Check
3. Interrupt Function

Signed-off-by: Mig Yang <temashking@foxmail.com>
---
 MAINTAINERS                 |   1 +
 tests/qtest/k230-wdt-test.c | 199 ++++++++++++++++++++++++++++++++++++
 tests/qtest/meson.build     |   3 +-
 3 files changed, 202 insertions(+), 1 deletion(-)
 create mode 100644 tests/qtest/k230-wdt-test.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 564c2af56d..bfa63f832e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1718,6 +1718,7 @@ F: hw/riscv/k230.c
 F: hw/watchdog/k230_wdt.c
 F: include/hw/riscv/k230.h
 F: include/hw/watchdog/k230_wdt.h
+F: tests/qtest/k230-wdt-test.c
 
 RX Machines
 -----------
diff --git a/tests/qtest/k230-wdt-test.c b/tests/qtest/k230-wdt-test.c
new file mode 100644
index 0000000000..2550cebd10
--- /dev/null
+++ b/tests/qtest/k230-wdt-test.c
@@ -0,0 +1,199 @@
+/*
+ * QTest testcase for K230 Watchdog
+ *
+ * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the kendryte K230 SDK
+ *
+ * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "qemu/bitops.h"
+#include "libqtest.h"
+#include "hw/watchdog/k230_wdt.h"
+
+/* K230 WDT0 base address */
+#define K230_WDT0_BASE 0x91106000
+#define K230_WDT1_BASE 0x91106800
+
+/* Test WDT0 by default */
+#define WDT_BASE K230_WDT0_BASE
+
+static void test_register_read_write(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Test Control Register (CR) read/write */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_CR), ==,
+                    (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT) |
+                    K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+
+    /* Test Timeout Range Register (TORR) read/write */
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_TORR), ==,
+                    K230_WDT_TORR_TOP_MASK);
+
+    /* Test Protection Level Register read/write */
+    qtest_writel(qts, WDT_BASE + K230_WDT_PROT_LEVEL, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_PROT_LEVEL), ==, 0x7);
+
+    qtest_quit(qts);
+}
+
+static void test_counter_restart(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Enable watchdog and set timeout */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x5); /* TOP = 5 */
+
+    /* Read current counter value */
+    uint32_t initial_count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
+    g_assert_cmpuint(initial_count, >, 0);
+
+    /* Restart counter with magic value */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CRR, K230_WDT_CRR_RESTART);
+
+    /* Wait for time */
+    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 2);
+
+    /* Counter should be reset to timeout value */
+    uint32_t new_count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
+    g_assert_cmpuint(new_count, >, 0);
+    g_assert_cmpuint(new_count, !=, initial_count);
+
+    qtest_quit(qts);
+}
+
+static void test_interrupt_mode(void)
+{
+    QTestState *qts = qtest_init("-machine k230 --trace k230_*,file=k230.log");
+
+    /* Set interrupt mode and enable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR,
+                 K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x1); /* Short timeout */
+
+    /* Wait for timeout to trigger interrupt */
+    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 10);
+
+    /* Check interrupt status */
+    uint32_t stat = qtest_readl(qts, WDT_BASE + K230_WDT_STAT);
+    g_assert_cmphex(stat & K230_WDT_STAT_INT, ==, K230_WDT_STAT_INT);
+
+    /* Clear interrupt */
+    qtest_writel(qts, WDT_BASE + K230_WDT_EOI, 0x1);
+    stat = qtest_readl(qts, WDT_BASE + K230_WDT_STAT);
+    g_assert_cmphex(stat & K230_WDT_STAT_INT, ==, 0);
+
+    qtest_quit(qts);
+}
+
+static void test_reset_mode(void)
+{
+    QTestState *qts = qtest_init("-machine k230 -no-reboot");
+
+    /* Set reset mode and enable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x1); /* Short timeout */
+
+    /* Wait for timeout to trigger reset */
+    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 2);
+
+    /* In reset mode, the system should reset */
+    /* This test verifies that reset mode is properly configured */
+
+    qtest_quit(qts);
+}
+
+static void test_timeout_calculation(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Test different timeout values */
+    for (uint32_t top = 0; top <= 15; top++) {
+        qtest_writel(qts, WDT_BASE + K230_WDT_TORR, top);
+        qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+
+        /* Read current counter value */
+        uint32_t count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
+        g_assert_cmpuint(count, >, 0);
+
+        /* Disable watchdog for next iteration */
+        qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0);
+    }
+
+    qtest_quit(qts);
+}
+
+static void test_wdt1_registers(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Test WDT1 registers (second watchdog) */
+    qtest_writel(qts, K230_WDT1_BASE + K230_WDT_CR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, K230_WDT1_BASE + K230_WDT_CR), ==,
+                    (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT) |
+                    K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+
+    qtest_writel(qts, K230_WDT1_BASE + K230_WDT_TORR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, K230_WDT1_BASE + K230_WDT_TORR), ==,
+                    K230_WDT_TORR_TOP_MASK);
+
+    qtest_quit(qts);
+}
+
+static void test_enable_disable(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Initially disabled */
+    uint32_t cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
+    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, 0);
+
+    /* Enable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+    cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
+    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, K230_WDT_CR_WDT_EN);
+
+    /* Disable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0);
+    cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
+    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, 0);
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char *argv[])
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/k230-wdt/register_read_write", test_register_read_write);
+    qtest_add_func("/k230-wdt/counter_restart", test_counter_restart);
+    qtest_add_func("/k230-wdt/interrupt_mode", test_interrupt_mode);
+    qtest_add_func("/k230-wdt/reset_mode", test_reset_mode);
+    qtest_add_func("/k230-wdt/timeout_calculation", test_timeout_calculation);
+    qtest_add_func("/k230-wdt/wdt1_registers", test_wdt1_registers);
+    qtest_add_func("/k230-wdt/enable_disable", test_enable_disable);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 669d07c06b..0d9339e938 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -282,7 +282,8 @@ qtests_riscv32 = \
   (config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? ['sifive-e-aon-watchdog-test'] : [])
 
 qtests_riscv64 = ['riscv-csr-test'] + \
-  (unpack_edk2_blobs ? ['bios-tables-test'] : [])
+  (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
+  (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
 
 qos_test_ss = ss.source_set()
 qos_test_ss.add(
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 5/5] docs/system/riscv: add documentation for k230 machine
  2025-11-30  9:21 [PATCH v1 0/5] Add K230 board and thead-c908 CPU support Chao Liu
                   ` (3 preceding siblings ...)
  2025-11-30  9:21 ` [PATCH v1 4/5] tests/qtest: add test for K230 watchdog Chao Liu
@ 2025-11-30  9:21 ` Chao Liu
  2025-12-03 17:19   ` Daniel Henrique Barboza
  4 siblings, 1 reply; 16+ messages in thread
From: Chao Liu @ 2025-11-30  9:21 UTC (permalink / raw)
  To: richard.henderson, paolo.savini, npiggin, ebiggers, dbarboza,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches,
	Chao Liu

Add documentation for k230 virt reference platform.

Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
---
 docs/system/riscv/k230.rst | 48 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 docs/system/riscv/k230.rst

diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
new file mode 100644
index 0000000000..3e6ca295df
--- /dev/null
+++ b/docs/system/riscv/k230.rst
@@ -0,0 +1,48 @@
+Kendryte K230 virt reference platform (``k230``)
+==========================================================================
+The ``k230`` machine is compatible with with Kendryte K230 SDK.
+
+The K230 is a chip from the AIoT SoC series made by Kendryte ® — a part of
+Canaan Inc. It uses a brand-new multi-heterogeneous unit accelerated computing
+structure.
+
+This chip has 2 RISC-V computing cores and a new-generation KPU (Knowledge
+Process Unit) smart computing unit.
+
+It has multi-precision AI computing ability, works with many common AI computing
+frameworks, and for some typical networks, its usage rate is over 70%. Besides,
+the K230 chip supports many peripheral connections and has several special
+hardware acceleration units (like 2D and 2.5D accelerators). It can speed up
+different tasks (such as image processing, video processing, audio processing
+and AI computing). It also has many good features: low delay, high performance,
+low power use and fast start-up.
+
+For more information, see <https://www.kendryte.com/en/proDetail/230>
+
+Supported devices
+-----------------
+The ``k230`` machine supports the following devices:
+
+* 1 c908 cores
+* Core Local Interruptor (CLINT)
+* Incoming MSI Controller (IMSIC)
+* 2 K230 Watchdog Timer
+* 4 UART
+
+Boot options
+------------
+The ``k230`` machine can start using the standard ``-bios``
+functionality for loading the boot image. You need to compile and link
+the firmware, kernel, and Device Tree (FDT) into a single binary file with
+K230 SDK(k230_canmv_defconfig), such as ``uboot``.
+
+Running
+-------
+Below is an example command line for running the ``k230``
+machine:
+
+.. code-block:: bash
+
+   $ qemu-system-riscv64 -machine k230 \
+      -bios k230_sdk/output/k230_canmv_defconfig/little/uboot/u-boot \
+      -nographic
-- 
2.51.0



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/5] target/riscv: add thead-c908 cpu support
  2025-11-30  9:21 ` [PATCH v1 1/5] target/riscv: add thead-c908 cpu support Chao Liu
@ 2025-12-03 16:33   ` Daniel Henrique Barboza
  2025-12-03 17:12   ` Conor Dooley
  1 sibling, 0 replies; 16+ messages in thread
From: Daniel Henrique Barboza @ 2025-12-03 16:33 UTC (permalink / raw)
  To: Chao Liu, richard.henderson, paolo.savini, npiggin, ebiggers,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches



On 11/30/25 6:21 AM, Chao Liu wrote:
> The C908 processor is based on the RV64GCB[V] instruction
> set, compatible to RVA22 Profile and implements the XIE
> (XuanTie Instruction Extension) technology.
> 
> Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
> Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> ---


Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>

>   target/riscv/cpu-qom.h |   2 +
>   target/riscv/cpu.c     |  43 +++++
>   target/riscv/th_csr.c  | 380 ++++++++++++++++++++++++++++++++++++++++-
>   3 files changed, 424 insertions(+), 1 deletion(-)
> 
> diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
> index 75f4e43408..1ddb5a6a6c 100644
> --- a/target/riscv/cpu-qom.h
> +++ b/target/riscv/cpu-qom.h
> @@ -52,6 +52,8 @@
>   #define TYPE_RISCV_CPU_SIFIVE_U34       RISCV_CPU_TYPE_NAME("sifive-u34")
>   #define TYPE_RISCV_CPU_SIFIVE_U54       RISCV_CPU_TYPE_NAME("sifive-u54")
>   #define TYPE_RISCV_CPU_THEAD_C906       RISCV_CPU_TYPE_NAME("thead-c906")
> +#define TYPE_RISCV_CPU_THEAD_C908       RISCV_CPU_TYPE_NAME("thead-c908")
> +#define TYPE_RISCV_CPU_THEAD_C908V      RISCV_CPU_TYPE_NAME("thead-c908v")
>   #define TYPE_RISCV_CPU_VEYRON_V1        RISCV_CPU_TYPE_NAME("veyron-v1")
>   #define TYPE_RISCV_CPU_TT_ASCALON       RISCV_CPU_TYPE_NAME("tt-ascalon")
>   #define TYPE_RISCV_CPU_XIANGSHAN_NANHU  RISCV_CPU_TYPE_NAME("xiangshan-nanhu")
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index d055ddf462..202ff130ee 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -3091,6 +3091,49 @@ static const TypeInfo riscv_cpu_type_infos[] = {
>   #endif
>       ),
>   
> +    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908, TYPE_RISCV_VENDOR_CPU,
> +        .misa_mxl_max = MXL_RV64,
> +        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU,
> +        .priv_spec = PRIV_VERSION_1_12_0,
> +
> +        /* ISA extensions */
> +        .cfg.ext_xtheadba = true,
> +        .cfg.ext_xtheadbb = true,
> +        .cfg.ext_xtheadbs = true,
> +        .cfg.ext_xtheadcmo = true,
> +        .cfg.ext_xtheadcondmov = true,
> +        .cfg.ext_xtheadmac = true,
> +        .cfg.ext_xtheadmemidx = true,
> +        .cfg.ext_xtheadmempair = true,
> +        .cfg.ext_xtheadsync = true,
> +        .cfg.ext_zba = true,
> +        .cfg.ext_zbb = true,
> +        .cfg.ext_zbc = true,
> +        .cfg.ext_zbs = true,
> +        .cfg.ext_zkt = true,
> +        .cfg.ext_zbkc = true,
> +        .cfg.ext_zicsr = true,
> +        .cfg.ext_zifencei = true,
> +        .cfg.ext_zihintpause = true,
> +        .cfg.ext_zicbom = true,
> +        .cfg.ext_zicboz = true,
> +        .cfg.ext_zfh = true,
> +        .cfg.ext_xtheadfmv = true,
> +        .cfg.ext_xtheadfmemidx = true,
> +        .cfg.pmp = true,
> +
> +        .cfg.marchid = 0x8d143000,
> +        .cfg.mvendorid = THEAD_VENDOR_ID,
> +#ifndef CONFIG_USER_ONLY
> +        .custom_csrs = th_csr_list,
> +#endif
> +    ),
> +
> +    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908V, TYPE_RISCV_CPU_THEAD_C908,
> +        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU | RVV,
> +        .vext_spec = VEXT_VERSION_1_00_0,
> +    ),
> +
>       DEFINE_RISCV_CPU(TYPE_RISCV_CPU_TT_ASCALON, TYPE_RISCV_VENDOR_CPU,
>           .misa_mxl_max = MXL_RV64,
>           .misa_ext = RVG | RVC | RVS | RVU | RVH | RVV,
> diff --git a/target/riscv/th_csr.c b/target/riscv/th_csr.c
> index 49eb7bbab5..3b59939f05 100644
> --- a/target/riscv/th_csr.c
> +++ b/target/riscv/th_csr.c
> @@ -2,6 +2,9 @@
>    * T-Head-specific CSRs.
>    *
>    * Copyright (c) 2024 VRULL GmbH
> + * Copyright (c) 2025 Chao Liu <chao.liu@zevorn.cn>
> + *
> + * For more information, see XuanTie-C908-UserManual_xrvm_20240530.pdf
>    *
>    * This program is free software; you can redistribute it and/or modify it
>    * under the terms and conditions of the GNU General Public License,
> @@ -20,13 +23,88 @@
>   #include "cpu.h"
>   #include "cpu_vendorid.h"
>   
> -#define CSR_TH_SXSTATUS 0x5c0
> +/* Extended M-mode control registers of T-Head */
> +#define CSR_TH_MXSTATUS        0x7c0
> +#define CSR_TH_MHCR            0x7c1
> +#define CSR_TH_MCOR            0x7c2
> +#define CSR_TH_MCCR2           0x7c3
> +#define CSR_TH_MHINT           0x7c5
> +#define CSR_TH_MRVBR           0x7c7
> +#define CSR_TH_MCOUNTERWEN     0x7c9
> +#define CSR_TH_MCOUNTERINTEN   0x7ca
> +#define CSR_TH_MCOUNTEROF      0x7cb
> +#define CSR_TH_MCINS           0x7d2
> +#define CSR_TH_MCINDEX         0x7d3
> +#define CSR_TH_MCDATA0         0x7d4
> +#define CSR_TH_MCDATA1         0x7d5
> +#define CSR_TH_MSMPR           0x7f3
> +#define CSR_TH_CPUID           0xfc0
> +#define CSR_TH_MAPBADDR        0xfc1
> +
> +/* TH_MXSTATUS bits */
> +#define TH_MXSTATUS_UCME        BIT(16)
> +#define TH_MXSTATUS_MAEE        BIT(21)
> +#define TH_MXSTATUS_THEADISAEE  BIT(22)
> +
> +/* Extended S-mode control registers of T-Head */
> +#define CSR_TH_SXSTATUS        0x5c0
> +#define CSR_TH_SHCR            0x5c1
> +#define CSR_TH_SCER2           0x5c2
> +#define CSR_TH_SCER            0x5c3
> +#define CSR_TH_SCOUNTERINTEN   0x5c4
> +#define CSR_TH_SCOUNTEROF      0x5c5
> +#define CSR_TH_SCYCLE          0x5e0
> +#define CSR_TH_SHPMCOUNTER3    0x5e3
> +#define CSR_TH_SHPMCOUNTER4    0x5e4
> +#define CSR_TH_SHPMCOUNTER5    0x5e5
> +#define CSR_TH_SHPMCOUNTER6    0x5e6
> +#define CSR_TH_SHPMCOUNTER7    0x5e7
> +#define CSR_TH_SHPMCOUNTER8    0x5e8
> +#define CSR_TH_SHPMCOUNTER9    0x5e9
> +#define CSR_TH_SHPMCOUNTER10   0x5ea
> +#define CSR_TH_SHPMCOUNTER11   0x5eb
> +#define CSR_TH_SHPMCOUNTER12   0x5ec
> +#define CSR_TH_SHPMCOUNTER13   0x5ed
> +#define CSR_TH_SHPMCOUNTER14   0x5ee
> +#define CSR_TH_SHPMCOUNTER15   0x5ef
> +#define CSR_TH_SHPMCOUNTER16   0x5f0
> +#define CSR_TH_SHPMCOUNTER17   0x5f1
> +#define CSR_TH_SHPMCOUNTER18   0x5f2
> +#define CSR_TH_SHPMCOUNTER19   0x5f3
> +#define CSR_TH_SHPMCOUNTER20   0x5f4
> +#define CSR_TH_SHPMCOUNTER21   0x5f5
> +#define CSR_TH_SHPMCOUNTER22   0x5f6
> +#define CSR_TH_SHPMCOUNTER23   0x5f7
> +#define CSR_TH_SHPMCOUNTER24   0x5f8
> +#define CSR_TH_SHPMCOUNTER25   0x5f9
> +#define CSR_TH_SHPMCOUNTER26   0x5fa
> +#define CSR_TH_SHPMCOUNTER27   0x5fb
> +#define CSR_TH_SHPMCOUNTER28   0x5fc
> +#define CSR_TH_SHPMCOUNTER29   0x5fd
> +#define CSR_TH_SHPMCOUNTER30   0x5fe
> +#define CSR_TH_SHPMCOUNTER31   0x5ff
> +#define CSR_TH_SMIR            0x9c0
> +#define CSR_TH_SMLO0           0x9c1
> +#define CSR_TH_SMEH            0x9c2
> +#define CSR_TH_SMCIR           0x9c3
> +
> +/* Extended U-mode control registers of T-Head */
> +#define CSR_TH_FXCR            0x800
>   
>   /* TH_SXSTATUS bits */
>   #define TH_SXSTATUS_UCME        BIT(16)
>   #define TH_SXSTATUS_MAEE        BIT(21)
>   #define TH_SXSTATUS_THEADISAEE  BIT(22)
>   
> +static RISCVException mmode(CPURISCVState *env, int csrno)
> +{
> +    if (riscv_has_ext(env, RVM)) {
> +        return RISCV_EXCP_NONE;
> +    }
> +
> +    return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
>   static RISCVException smode(CPURISCVState *env, int csrno)
>   {
>       if (riscv_has_ext(env, RVS)) {
> @@ -36,11 +114,31 @@ static RISCVException smode(CPURISCVState *env, int csrno)
>       return RISCV_EXCP_ILLEGAL_INST;
>   }
>   
> +static RISCVException any(CPURISCVState *env, int csrno)
> +{
> +    return RISCV_EXCP_NONE;
> +}
> +
>   static bool test_thead_mvendorid(RISCVCPU *cpu)
>   {
>       return cpu->cfg.mvendorid == THEAD_VENDOR_ID;
>   }
>   
> +static RISCVException read_th_mxstatus(CPURISCVState *env, int csrno,
> +                                       target_ulong *val)
> +{
> +    /* We don't set MAEE here, because QEMU does not implement MAEE. */
> +    *val = TH_MXSTATUS_UCME | TH_MXSTATUS_THEADISAEE;
> +    return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException read_unimp_th_csr(CPURISCVState *env, int csrno,
> +                                        target_ulong *val)
> +{
> +    *val = 0;
> +    return RISCV_EXCP_NONE;
> +}
> +
>   static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
>                                          target_ulong *val)
>   {
> @@ -50,10 +148,290 @@ static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
>   }
>   
>   const RISCVCSR th_csr_list[] = {
> +    {
> +        .csrno = CSR_TH_MXSTATUS,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mxstatus", mmode, read_th_mxstatus }
> +    },
> +    {
> +        .csrno = CSR_TH_MHCR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mhcr", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCOR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcor", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCCR2,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mccr2", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MHINT,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mhint", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MRVBR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mrvbr", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCOUNTERWEN,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcounterwen", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCOUNTERINTEN,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcounterinten", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCOUNTEROF,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcounterof", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCINS,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcins", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCINDEX,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcindex", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCDATA0,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcdata0", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCDATA1,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcdata1", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MSMPR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.msmpr", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_CPUID,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.cpuid", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MAPBADDR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mapbaddr", mmode, read_unimp_th_csr }
> +    },
>       {
>           .csrno = CSR_TH_SXSTATUS,
>           .insertion_test = test_thead_mvendorid,
>           .csr_ops = { "th.sxstatus", smode, read_th_sxstatus }
>       },
> +    {
> +        .csrno = CSR_TH_SHCR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shcr", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SCER2,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.scer2", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SCER,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.scer", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SCOUNTERINTEN,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.scounterinten", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SCOUNTEROF,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.scounterof", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SCYCLE,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.scycle", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER3,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter3", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER4,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter4", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER5,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter5", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER6,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter6", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER7,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter7", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER8,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter8", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER9,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter9", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER10,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter10", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER11,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter11", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER12,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter12", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER13,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter13", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER14,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter14", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER15,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter15", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER16,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter16", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER17,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter17", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER18,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter18", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER19,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter19", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER20,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter20", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER21,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter21", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER22,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter22", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER23,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter23", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER24,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter24", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER25,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter25", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER26,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter26", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER27,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter27", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER28,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter28", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER29,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter29", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER30,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter30", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER31,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter31", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SMIR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.smir", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SMLO0,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.smlo0", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SMEH,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.smeh", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SMCIR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.smcir", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_FXCR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.fxcr", any, read_unimp_th_csr }
> +    },
>       { }
>   };



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 2/5] hw/riscv: add k230 board initial support
  2025-11-30  9:21 ` [PATCH v1 2/5] hw/riscv: add k230 board initial support Chao Liu
@ 2025-12-03 17:02   ` Daniel Henrique Barboza
  2025-12-04  1:12     ` Chao Liu
  0 siblings, 1 reply; 16+ messages in thread
From: Daniel Henrique Barboza @ 2025-12-03 17:02 UTC (permalink / raw)
  To: Chao Liu, richard.henderson, paolo.savini, npiggin, ebiggers,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches



On 11/30/25 6:21 AM, Chao Liu wrote:
> K230 Board Compatible with kendryte K230 SDK.
> 
> Preliminarily supports the C908 small core, which can
> run the U-Boot and Linux kernel compiled by the K230 SDK.
> 
> Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
> ---
>   MAINTAINERS             |   7 +
>   hw/riscv/Kconfig        |  10 +
>   hw/riscv/k230.c         | 483 ++++++++++++++++++++++++++++++++++++++++
>   hw/riscv/meson.build    |   2 +-
>   include/hw/riscv/k230.h | 149 +++++++++++++
>   5 files changed, 650 insertions(+), 1 deletion(-)
>   create mode 100644 hw/riscv/k230.c
>   create mode 100644 include/hw/riscv/k230.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a07086ed76..703d9e6b82 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1710,6 +1710,13 @@ F: docs/system/riscv/xiangshan-kunminghu.rst
>   F: hw/riscv/xiangshan_kmh.c
>   F: include/hw/riscv/xiangshan_kmh.h
>   
> +K230 Machines
> +M: Chao Liu <chao.liu@zevorn.cn>
> +S: Maintained
> +F: docs/system/riscv/k230.rst

Nit: at this point there's no k230.rst file (it's on patch 5). A minor comment.

LGTM otherwise. Thanks,

Daniel

> +F: hw/riscv/k230.c
> +F: include/hw/riscv/k230.h
> +
>   RX Machines
>   -----------
>   rx-gdbsim
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index fc9c35bd98..624f166244 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -128,3 +128,13 @@ config XIANGSHAN_KUNMINGHU
>       select RISCV_APLIC
>       select RISCV_IMSIC
>       select SERIAL_MM
> +
> +config K230
> +    bool
> +    default y
> +    depends on RISCV64
> +    select RISCV_ACLINT
> +    select RISCV_APLIC
> +    select RISCV_IMSIC
> +    select SERIAL_MM
> +    select UNIMP
> \ No newline at end of file
> diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
> new file mode 100644
> index 0000000000..f41e9b7002
> --- /dev/null
> +++ b/hw/riscv/k230.c
> @@ -0,0 +1,483 @@
> +/*
> + * QEMU RISC-V Virt Board Compatible with Kendryte K230 SDK
> + *
> + * Copyright (c) 2025 Chao Liu <chao.liu@zevorn.cn>
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Provides a board compatible with the Kendryte K230 SDK
> + *
> + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> + *
> + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "cpu-qom.h"
> +#include "qemu/cutils.h"
> +#include "qemu/error-report.h"
> +#include "qapi/error.h"
> +#include "system/system.h"
> +#include "system/memory.h"
> +#include "target/riscv/cpu.h"
> +#include "chardev/char.h"
> +#include "hw/loader.h"
> +#include "hw/sysbus.h"
> +#include "hw/riscv/k230.h"
> +#include "hw/riscv/boot.h"
> +#include "hw/intc/riscv_aclint.h"
> +#include "hw/intc/sifive_plic.h"
> +#include "hw/char/serial-mm.h"
> +#include "hw/misc/unimp.h"
> +
> +static const MemMapEntry memmap[] = {
> +    [K230_DEV_DDRC] =         { 0x00000000, 0x80000000 },
> +    [K230_DEV_KPU_L2_CACHE] = { 0x80000000, 0x00200000 },
> +    [K230_DEV_SRAM] =         { 0x80200000, 0x00200000 },
> +    [K230_DEV_KPU_CFG] =      { 0x80400000, 0x00000800 },
> +    [K230_DEV_FFT] =          { 0x80400800, 0x00000400 },
> +    [K230_DEV_AI_2D_ENGINE] = { 0x80400C00, 0x00000800 },
> +    [K230_DEV_GSDMA] =        { 0x80800000, 0x00004000 },
> +    [K230_DEV_DMA] =          { 0x80804000, 0x00004000 },
> +    [K230_DEV_DECOMP_GZIP] =  { 0x80808000, 0x00004000 },
> +    [K230_DEV_NON_AI_2D] =    { 0x8080C000, 0x00004000 },
> +    [K230_DEV_ISP] =          { 0x90000000, 0x00008000 },
> +    [K230_DEV_DEWARP] =       { 0x90008000, 0x00001000 },
> +    [K230_DEV_RX_CSI] =       { 0x90009000, 0x00002000 },
> +    [K230_DEV_H264] =         { 0x90400000, 0x00010000 },
> +    [K230_DEV_2P5D] =         { 0x90800000, 0x00040000 },
> +    [K230_DEV_VO] =           { 0x90840000, 0x00010000 },
> +    [K230_DEV_VO_CFG] =       { 0x90850000, 0x00001000 },
> +    [K230_DEV_3D_ENGINE] =    { 0x90A00000, 0x00000800 },
> +    [K230_DEV_PMU] =          { 0x91000000, 0x00000C00 },
> +    [K230_DEV_RTC] =          { 0x91000C00, 0x00000400 },
> +    [K230_DEV_CMU] =          { 0x91100000, 0x00001000 },
> +    [K230_DEV_RMU] =          { 0x91101000, 0x00001000 },
> +    [K230_DEV_BOOT] =         { 0x91102000, 0x00001000 },
> +    [K230_DEV_PWR] =          { 0x91103000, 0x00001000 },
> +    [K230_DEV_MAILBOX] =      { 0x91104000, 0x00001000 },
> +    [K230_DEV_IOMUX] =        { 0x91105000, 0x00000800 },
> +    [K230_DEV_TIMER] =        { 0x91105800, 0x00000800 },
> +    [K230_DEV_WDT0] =         { 0x91106000, 0x00000800 },
> +    [K230_DEV_WDT1] =         { 0x91106800, 0x00000800 },
> +    [K230_DEV_TS] =           { 0x91107000, 0x00000800 },
> +    [K230_DEV_HDI] =          { 0x91107800, 0x00000800 },
> +    [K230_DEV_STC] =          { 0x91108000, 0x00000800 },
> +    [K230_DEV_BOOTROM] =      { 0x91200000, 0x00010000 },
> +    [K230_DEV_SECURITY] =     { 0x91210000, 0x00008000 },
> +    [K230_DEV_UART0] =        { 0x91400000, 0x00001000 },
> +    [K230_DEV_UART1] =        { 0x91401000, 0x00001000 },
> +    [K230_DEV_UART2] =        { 0x91402000, 0x00001000 },
> +    [K230_DEV_UART3] =        { 0x91403000, 0x00001000 },
> +    [K230_DEV_UART4] =        { 0x91404000, 0x00001000 },
> +    [K230_DEV_I2C0] =         { 0x91405000, 0x00001000 },
> +    [K230_DEV_I2C1] =         { 0x91406000, 0x00001000 },
> +    [K230_DEV_I2C2] =         { 0x91407000, 0x00001000 },
> +    [K230_DEV_I2C3] =         { 0x91408000, 0x00001000 },
> +    [K230_DEV_I2C4] =         { 0x91409000, 0x00001000 },
> +    [K230_DEV_PWM] =          { 0x9140A000, 0x00001000 },
> +    [K230_DEV_GPIO0] =        { 0x9140B000, 0x00001000 },
> +    [K230_DEV_GPIO1] =        { 0x9140C000, 0x00001000 },
> +    [K230_DEV_ADC] =          { 0x9140D000, 0x00001000 },
> +    [K230_DEV_CODEC] =        { 0x9140E000, 0x00001000 },
> +    [K230_DEV_I2S] =          { 0x9140F000, 0x00001000 },
> +    [K230_DEV_USB0] =         { 0x91500000, 0x00010000 },
> +    [K230_DEV_USB1] =         { 0x91540000, 0x00010000 },
> +    [K230_DEV_SD0] =          { 0x91580000, 0x00001000 },
> +    [K230_DEV_SD1] =          { 0x91581000, 0x00001000 },
> +    [K230_DEV_QSPI0] =        { 0x91582000, 0x00001000 },
> +    [K230_DEV_QSPI1] =        { 0x91583000, 0x00001000 },
> +    [K230_DEV_SPI] =          { 0x91584000, 0x00001000 },
> +    [K230_DEV_HI_SYS_CFG] =   { 0x91585000, 0x00000400 },
> +    [K230_DEV_DDRC_CFG] =     { 0x98000000, 0x02000000 },
> +    [K230_DEV_FLASH] =        { 0xC0000000, 0x08000000 },
> +    [K230_DEV_PLIC] =         { 0xF0000000, 0x00400000 },
> +    [K230_DEV_CLINT] =        { 0xF0400000, 0x00400000 },
> +};
> +
> +static void k230_soc_init(Object *obj)
> +{
> +    K230SoCState *s = RISCV_K230_SOC(obj);
> +    RISCVHartArrayState *cpu0 = &s->c908_cpu;
> +
> +    object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
> +    qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
> +    qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
> +    qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
> +                         memmap[K230_DEV_BOOTROM].base);
> +}
> +
> +static DeviceState *k230_create_plic(int base_hartid, int hartid_count)
> +{
> +    g_autofree char *plic_hart_config = NULL;
> +
> +    /* Per-socket PLIC hart topology configuration string */
> +    plic_hart_config = riscv_plic_hart_config_string(hartid_count);
> +
> +    /* Per-socket PLIC */
> +    return sifive_plic_create(memmap[K230_DEV_PLIC].base,
> +                              plic_hart_config, hartid_count, base_hartid,
> +                              K230_PLIC_NUM_SOURCES,
> +                              K230_PLIC_NUM_PRIORITIES,
> +                              K230_PLIC_PRIORITY_BASE, K230_PLIC_PENDING_BASE,
> +                              K230_PLIC_ENABLE_BASE, K230_PLIC_ENABLE_STRIDE,
> +                              K230_PLIC_CONTEXT_BASE,
> +                              K230_PLIC_CONTEXT_STRIDE,
> +                              memmap[K230_DEV_PLIC].size);
> +}
> +
> +static void k230_soc_realize(DeviceState *dev, Error **errp)
> +{
> +    K230SoCState *s = RISCV_K230_SOC(dev);
> +    MemoryRegion *sys_mem = get_system_memory();
> +    int c908_cpus;
> +
> +    sysbus_realize(SYS_BUS_DEVICE(&s->c908_cpu), &error_fatal);
> +
> +    c908_cpus = s->c908_cpu.num_harts;
> +
> +    /* SRAM */
> +    memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
> +                           memmap[K230_DEV_SRAM].size, &error_fatal);
> +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
> +                                &s->sram);
> +
> +    /* BootROM */
> +    memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
> +                           memmap[K230_DEV_BOOTROM].size, &error_fatal);
> +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_BOOTROM].base,
> +                                &s->bootrom);
> +
> +    /* PLIC */
> +    s->c908_plic = k230_create_plic(C908_CPU_HARTID, c908_cpus);
> +
> +    /* CLINT */
> +    riscv_aclint_swi_create(memmap[K230_DEV_CLINT].base,
> +                            C908_CPU_HARTID, c908_cpus, false);
> +    riscv_aclint_mtimer_create(memmap[K230_DEV_CLINT].base + 0x4000,
> +                               RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
> +                               C908_CPU_HARTID, c908_cpus,
> +                               RISCV_ACLINT_DEFAULT_MTIMECMP,
> +                               RISCV_ACLINT_DEFAULT_MTIME,
> +                               RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
> +
> +    /* UART */
> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART0].base, 2,
> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART0_IRQ),
> +                   399193, serial_hd(0), DEVICE_LITTLE_ENDIAN);
> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART1].base, 2,
> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART1_IRQ),
> +                   399193, serial_hd(1), DEVICE_LITTLE_ENDIAN);
> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART2].base, 2,
> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART2_IRQ),
> +                   399193, serial_hd(2), DEVICE_LITTLE_ENDIAN);
> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART3].base, 2,
> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART3_IRQ),
> +                   399193, serial_hd(3), DEVICE_LITTLE_ENDIAN);
> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART4].base, 2,
> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART4_IRQ),
> +                   399193, serial_hd(4), DEVICE_LITTLE_ENDIAN);
> +
> +    /* unimplemented devices */
> +    create_unimplemented_device("kpu.l2-cache",
> +                                memmap[K230_DEV_KPU_L2_CACHE].base,
> +                                memmap[K230_DEV_KPU_L2_CACHE].size);
> +
> +    create_unimplemented_device("kpu_cfg", memmap[K230_DEV_KPU_CFG].base,
> +                                memmap[K230_DEV_KPU_CFG].size);
> +
> +    create_unimplemented_device("fft", memmap[K230_DEV_FFT].base,
> +                                memmap[K230_DEV_FFT].size);
> +
> +    create_unimplemented_device("2d-engine.ai",
> +                                memmap[K230_DEV_AI_2D_ENGINE].base,
> +                                memmap[K230_DEV_AI_2D_ENGINE].size);
> +
> +    create_unimplemented_device("gsdma", memmap[K230_DEV_GSDMA].base,
> +                                memmap[K230_DEV_GSDMA].size);
> +
> +    create_unimplemented_device("dma", memmap[K230_DEV_DMA].base,
> +                                memmap[K230_DEV_DMA].size);
> +
> +    create_unimplemented_device("decomp-gzip",
> +                                memmap[K230_DEV_DECOMP_GZIP].base,
> +                                memmap[K230_DEV_DECOMP_GZIP].size);
> +
> +    create_unimplemented_device("2d-engine.non-ai",
> +                                memmap[K230_DEV_NON_AI_2D].base,
> +                                memmap[K230_DEV_NON_AI_2D].size);
> +
> +    create_unimplemented_device("isp", memmap[K230_DEV_ISP].base,
> +                                memmap[K230_DEV_ISP].size);
> +
> +    create_unimplemented_device("dewarp", memmap[K230_DEV_DEWARP].base,
> +                                memmap[K230_DEV_DEWARP].size);
> +
> +    create_unimplemented_device("rx-csi", memmap[K230_DEV_RX_CSI].base,
> +                                memmap[K230_DEV_RX_CSI].size);
> +
> +    create_unimplemented_device("vpu", memmap[K230_DEV_H264].base,
> +                                memmap[K230_DEV_H264].size);
> +
> +    create_unimplemented_device("gpu", memmap[K230_DEV_2P5D].base,
> +                                memmap[K230_DEV_2P5D].size);
> +
> +    create_unimplemented_device("vo", memmap[K230_DEV_VO].base,
> +                                memmap[K230_DEV_VO].size);
> +
> +    create_unimplemented_device("vo_cfg", memmap[K230_DEV_VO_CFG].base,
> +                                memmap[K230_DEV_VO_CFG].size);
> +
> +    create_unimplemented_device("3d-engine", memmap[K230_DEV_3D_ENGINE].base,
> +                                memmap[K230_DEV_3D_ENGINE].size);
> +
> +    create_unimplemented_device("pmu", memmap[K230_DEV_PMU].base,
> +                                memmap[K230_DEV_PMU].size);
> +
> +    create_unimplemented_device("rtc", memmap[K230_DEV_RTC].base,
> +                                memmap[K230_DEV_RTC].size);
> +
> +    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);
> +
> +    create_unimplemented_device("pwr", memmap[K230_DEV_PWR].base,
> +                                memmap[K230_DEV_PWR].size);
> +
> +    create_unimplemented_device("ipcm", memmap[K230_DEV_MAILBOX].base,
> +                                memmap[K230_DEV_MAILBOX].size);
> +
> +    create_unimplemented_device("iomux", memmap[K230_DEV_IOMUX].base,
> +                                memmap[K230_DEV_IOMUX].size);
> +
> +    create_unimplemented_device("timer", memmap[K230_DEV_TIMER].base,
> +                                memmap[K230_DEV_TIMER].size);
> +
> +    create_unimplemented_device("wdt0", memmap[K230_DEV_WDT0].base,
> +                                memmap[K230_DEV_WDT0].size);
> +
> +    create_unimplemented_device("wdt1", memmap[K230_DEV_WDT1].base,
> +                                memmap[K230_DEV_WDT1].size);
> +
> +    create_unimplemented_device("ts", memmap[K230_DEV_TS].base,
> +                                memmap[K230_DEV_TS].size);
> +
> +    create_unimplemented_device("hdi", memmap[K230_DEV_HDI].base,
> +                                memmap[K230_DEV_HDI].size);
> +
> +    create_unimplemented_device("stc", memmap[K230_DEV_STC].base,
> +                                memmap[K230_DEV_STC].size);
> +
> +    create_unimplemented_device("security", memmap[K230_DEV_SECURITY].base,
> +                                memmap[K230_DEV_SECURITY].size);
> +
> +    create_unimplemented_device("i2c0", memmap[K230_DEV_I2C0].base,
> +                                memmap[K230_DEV_I2C0].size);
> +
> +    create_unimplemented_device("i2c1", memmap[K230_DEV_I2C1].base,
> +                                memmap[K230_DEV_I2C1].size);
> +
> +    create_unimplemented_device("i2c2", memmap[K230_DEV_I2C2].base,
> +                                memmap[K230_DEV_I2C2].size);
> +
> +    create_unimplemented_device("i2c3", memmap[K230_DEV_I2C3].base,
> +                                memmap[K230_DEV_I2C3].size);
> +
> +    create_unimplemented_device("i2c4", memmap[K230_DEV_I2C4].base,
> +                                memmap[K230_DEV_I2C4].size);
> +
> +    create_unimplemented_device("pwm", memmap[K230_DEV_PWM].base,
> +                                memmap[K230_DEV_PWM].size);
> +
> +    create_unimplemented_device("gpio0", memmap[K230_DEV_GPIO0].base,
> +                                memmap[K230_DEV_GPIO0].size);
> +
> +    create_unimplemented_device("gpio1", memmap[K230_DEV_GPIO1].base,
> +                                memmap[K230_DEV_GPIO1].size);
> +
> +    create_unimplemented_device("adc", memmap[K230_DEV_ADC].base,
> +                                memmap[K230_DEV_ADC].size);
> +
> +    create_unimplemented_device("codec", memmap[K230_DEV_CODEC].base,
> +                                memmap[K230_DEV_CODEC].size);
> +
> +    create_unimplemented_device("i2s", memmap[K230_DEV_I2S].base,
> +                                memmap[K230_DEV_I2S].size);
> +
> +    create_unimplemented_device("usb0", memmap[K230_DEV_USB0].base,
> +                                memmap[K230_DEV_USB0].size);
> +
> +    create_unimplemented_device("usb1", memmap[K230_DEV_USB1].base,
> +                                memmap[K230_DEV_USB1].size);
> +
> +    create_unimplemented_device("sd0", memmap[K230_DEV_SD0].base,
> +                                memmap[K230_DEV_SD0].size);
> +
> +    create_unimplemented_device("sd1", memmap[K230_DEV_SD1].base,
> +                                memmap[K230_DEV_SD1].size);
> +
> +    create_unimplemented_device("qspi0", memmap[K230_DEV_QSPI0].base,
> +                                memmap[K230_DEV_QSPI0].size);
> +
> +    create_unimplemented_device("qspi1", memmap[K230_DEV_QSPI1].base,
> +                                memmap[K230_DEV_QSPI1].size);
> +
> +    create_unimplemented_device("spi", memmap[K230_DEV_SPI].base,
> +                                memmap[K230_DEV_SPI].size);
> +
> +    create_unimplemented_device("hi_sys_cfg", memmap[K230_DEV_HI_SYS_CFG].base,
> +                                memmap[K230_DEV_HI_SYS_CFG].size);
> +
> +    create_unimplemented_device("ddrc_cfg", memmap[K230_DEV_DDRC_CFG].base,
> +                                memmap[K230_DEV_DDRC_CFG].size);
> +
> +    create_unimplemented_device("flash", memmap[K230_DEV_FLASH].base,
> +                                memmap[K230_DEV_FLASH].size);
> +}
> +
> +static void k230_soc_class_init(ObjectClass *oc, const void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +
> +    dc->realize = k230_soc_realize;
> +}
> +
> +static const TypeInfo k230_soc_type_info = {
> +    .name = TYPE_RISCV_K230_SOC,
> +    .parent = TYPE_DEVICE,
> +    .instance_size = sizeof(K230SoCState),
> +    .instance_init = k230_soc_init,
> +    .class_init = k230_soc_class_init,
> +};
> +
> +static void k230_soc_register_types(void)
> +{
> +    type_register_static(&k230_soc_type_info);
> +}
> +
> +type_init(k230_soc_register_types)
> +
> +static void k230_machine_done(Notifier *notifier, void *data)
> +{
> +    K230MachineState *s = container_of(notifier, K230MachineState,
> +                                     machine_done);
> +    MachineState *machine = MACHINE(s);
> +    hwaddr start_addr = memmap[K230_DEV_DDRC].base;
> +    target_ulong firmware_end_addr, kernel_start_addr;
> +    const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
> +    uint64_t kernel_entry = 0;
> +    RISCVBootInfo boot_info;
> +
> +    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
> +                                                     &start_addr, NULL);
> +
> +    /* Mask ROM reset vector */
> +    uint32_t reset_vec[] = {
> +        /* 0x91200000: auipc  t0, 0x0              */ 0x00000297,
> +        /* 0x91200004: addi   t0, t0, 36 # <trap>  */ 0x02428293,
> +        /* 0x91200008: csrw   mtvec, t0            */ 0x30529073,
> +        /* 0x9120000C: csrr   a0, misa             */ 0x301012F3,
> +        /* 0x91200010: lui    t0, 0x1              */ 0x000012B7,
> +        /* 0x91200014: slli   t0, t0, 1            */ 0x00129293,
> +        /* 0x91200018: and    t0, a0, t0           */ 0x005572B3,
> +        /* 0x9120001C: bnez   t0, loop             */ 0x00511063,
> +        /* entry:                                  */
> +        /* 0x91200020: addiw  t0, zero, 1          */ 0x0010029b,
> +        /* 0x91200024: slli   t0, t0, 0x1b         */ 0x01b29293,
> +        /* 0x91200028: jr     t0 # uboot 0x8000000 */ 0x00028067,
> +        /* loop:                                   */
> +        /* 0x9120002C: j      0x9120002C # <loop>  */ 0x0000006f,
> +        /* trap:                                   */
> +        /* 0x91200030: j      0x91200030 # <trap>  */ 0x0000006f,
> +    };
> +
> +    /* copy in the reset vector in little_endian byte order */
> +    for (int i = 0; i < sizeof(reset_vec) >> 2; i++) {
> +        reset_vec[i] = cpu_to_le32(reset_vec[i]);
> +    }
> +    rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
> +                          memmap[K230_DEV_BOOTROM].base, &address_space_memory);
> +
> +    riscv_boot_info_init(&boot_info, &s->soc.c908_cpu);
> +
> +    if (machine->kernel_filename && !kernel_entry) {
> +        kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
> +                                                         firmware_end_addr);
> +        riscv_load_kernel(machine, &boot_info, kernel_start_addr,
> +                          true, NULL);
> +        kernel_entry = boot_info.image_low_addr;
> +    }
> +}
> +
> +static void k230_machine_init(MachineState *machine)
> +{
> +    MachineClass *mc = MACHINE_GET_CLASS(machine);
> +
> +    K230MachineState *s = RISCV_K230_MACHINE(machine);
> +    MemoryRegion *sys_mem = get_system_memory();
> +
> +    if (machine->ram_size < mc->default_ram_size) {
> +        char *sz = size_to_str(mc->default_ram_size);
> +        error_report("Invalid RAM size, should be %s", sz);
> +        g_free(sz);
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    /* Initialize SoC */
> +    object_initialize_child(OBJECT(machine), "soc", &s->soc,
> +                            TYPE_RISCV_K230_SOC);
> +    qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
> +
> +    /* Data Memory */
> +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_DDRC].base,
> +                                machine->ram);
> +
> +    s->machine_done.notify = k230_machine_done;
> +    qemu_add_machine_init_done_notifier(&s->machine_done);
> +}
> +
> +static void k230_machine_instance_init(Object *obj)
> +{
> +}
> +
> +static void k230_machine_class_init(ObjectClass *oc, const void *data)
> +{
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +
> +    mc->desc = "RISC-V Board compatible with Kendryte K230 SDK";
> +    mc->init = k230_machine_init;
> +    mc->default_cpus = 2;
> +    mc->default_ram_id = "riscv.K230.ram"; /* DDR */
> +    mc->default_ram_size = memmap[K230_DEV_DDRC].size;
> +}
> +
> +static const TypeInfo k230_machine_typeinfo = {
> +    .name       = TYPE_RISCV_K230_MACHINE,
> +    .parent     = TYPE_MACHINE,
> +    .class_init = k230_machine_class_init,
> +    .instance_init = k230_machine_instance_init,
> +    .instance_size = sizeof(K230MachineState),
> +};
> +
> +static void k230_machine_init_register_types(void)
> +{
> +    type_register_static(&k230_machine_typeinfo);
> +}
> +
> +type_init(k230_machine_init_register_types)
> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> index 2a8d5b136c..1e5ce511d4 100644
> --- a/hw/riscv/meson.build
> +++ b/hw/riscv/meson.build
> @@ -14,5 +14,5 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
>   	'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
>   riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
>   riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c'))
> -
> +riscv_ss.add(when: 'CONFIG_K230', if_true: files('k230.c'))
>   hw_arch += {'riscv': riscv_ss}
> diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
> new file mode 100644
> index 0000000000..3158381e8f
> --- /dev/null
> +++ b/include/hw/riscv/k230.h
> @@ -0,0 +1,149 @@
> +/*
> + * QEMU RISC-V Virt Board Compatible with kendryte K230 SDK
> + *
> + * Copyright (c) 2025 Chao Liu <chao.liu@zevorn.cn>
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Provides a board compatible with the kendryte K230 SDK
> + *
> + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> + *
> + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef HW_K230_H
> +#define HW_K230_H
> +
> +#include "hw/boards.h"
> +#include "hw/riscv/riscv_hart.h"
> +
> +#define C908_CPU_HARTID   (0)
> +
> +#define TYPE_RISCV_K230_SOC "riscv.k230.soc"
> +#define RISCV_K230_SOC(obj) \
> +    OBJECT_CHECK(K230SoCState, (obj), TYPE_RISCV_K230_SOC)
> +
> +typedef struct K230SoCState {
> +    /*< private >*/
> +    DeviceState parent_obj;
> +
> +    /*< public >*/
> +    RISCVHartArrayState c908_cpu; /* Small core */
> +
> +    MemoryRegion sram;
> +    MemoryRegion bootrom;
> +
> +    DeviceState *c908_plic;
> +} K230SoCState;
> +
> +#define TYPE_RISCV_K230_MACHINE MACHINE_TYPE_NAME("k230")
> +#define RISCV_K230_MACHINE(obj) \
> +    OBJECT_CHECK(K230MachineState, (obj), TYPE_RISCV_K230_MACHINE)
> +
> +typedef struct K230MachineState {
> +    /*< private >*/
> +    MachineState parent_obj;
> +
> +    /*< public >*/
> +    K230SoCState soc;
> +    Notifier machine_done;
> +} K230MachineState;
> +
> +enum {
> +    K230_DEV_DDRC,
> +    K230_DEV_KPU_L2_CACHE,
> +    K230_DEV_SRAM,
> +    K230_DEV_KPU_CFG,
> +    K230_DEV_FFT,
> +    K230_DEV_AI_2D_ENGINE,
> +    K230_DEV_GSDMA,
> +    K230_DEV_DMA,
> +    K230_DEV_DECOMP_GZIP,
> +    K230_DEV_NON_AI_2D,
> +    K230_DEV_ISP,
> +    K230_DEV_DEWARP,
> +    K230_DEV_RX_CSI,
> +    K230_DEV_H264,
> +    K230_DEV_2P5D,
> +    K230_DEV_VO,
> +    K230_DEV_VO_CFG,
> +    K230_DEV_3D_ENGINE,
> +    K230_DEV_PMU,
> +    K230_DEV_RTC,
> +    K230_DEV_CMU,
> +    K230_DEV_RMU,
> +    K230_DEV_BOOT,
> +    K230_DEV_PWR,
> +    K230_DEV_MAILBOX,
> +    K230_DEV_IOMUX,
> +    K230_DEV_TIMER,
> +    K230_DEV_WDT0,
> +    K230_DEV_WDT1,
> +    K230_DEV_TS,
> +    K230_DEV_HDI,
> +    K230_DEV_STC,
> +    K230_DEV_BOOTROM,
> +    K230_DEV_SECURITY,
> +    K230_DEV_UART0,
> +    K230_DEV_UART1,
> +    K230_DEV_UART2,
> +    K230_DEV_UART3,
> +    K230_DEV_UART4,
> +    K230_DEV_I2C0,
> +    K230_DEV_I2C1,
> +    K230_DEV_I2C2,
> +    K230_DEV_I2C3,
> +    K230_DEV_I2C4,
> +    K230_DEV_PWM,
> +    K230_DEV_GPIO0,
> +    K230_DEV_GPIO1,
> +    K230_DEV_ADC,
> +    K230_DEV_CODEC,
> +    K230_DEV_I2S,
> +    K230_DEV_USB0,
> +    K230_DEV_USB1,
> +    K230_DEV_SD0,
> +    K230_DEV_SD1,
> +    K230_DEV_QSPI0,
> +    K230_DEV_QSPI1,
> +    K230_DEV_SPI,
> +    K230_DEV_HI_SYS_CFG,
> +    K230_DEV_DDRC_CFG,
> +    K230_DEV_FLASH,
> +    K230_DEV_PLIC,
> +    K230_DEV_CLINT,
> +};
> +
> +enum {
> +    K230_UART0_IRQ  = 16,
> +    K230_UART1_IRQ  = 17,
> +    K230_UART2_IRQ  = 18,
> +    K230_UART3_IRQ  = 19,
> +    K230_UART4_IRQ  = 20,
> +};
> +
> +/*
> + * Integrates with the interrupt controller (PLIC),
> + * which can process 208 interrupt external sources
> + */
> +#define K230_PLIC_NUM_SOURCES 208
> +#define K230_PLIC_NUM_PRIORITIES 7
> +#define K230_PLIC_PRIORITY_BASE 0x00
> +#define K230_PLIC_PENDING_BASE 0x1000
> +#define K230_PLIC_ENABLE_BASE 0x2000
> +#define K230_PLIC_ENABLE_STRIDE 0x80
> +#define K230_PLIC_CONTEXT_BASE 0x200000
> +#define K230_PLIC_CONTEXT_STRIDE 0x1000
> +
> +#endif



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 3/5] hw/watchdog: add k230 watchdog initial support
  2025-11-30  9:21 ` [PATCH v1 3/5] hw/watchdog: add k230 watchdog " Chao Liu
@ 2025-12-03 17:07   ` Daniel Henrique Barboza
  0 siblings, 0 replies; 16+ messages in thread
From: Daniel Henrique Barboza @ 2025-12-03 17:07 UTC (permalink / raw)
  To: Chao Liu, richard.henderson, paolo.savini, npiggin, ebiggers,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches,
	Mig Yang



On 11/30/25 6:21 AM, Chao Liu wrote:
> Add programmable Watchdog Timer (WDT) peripheral for K230 machine.
> 
> Signed-off-by: Mig Yang <temashking@foxmail.com>
> Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
> ---

Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>



>   MAINTAINERS                    |   2 +
>   hw/riscv/Kconfig               |   3 +-
>   hw/riscv/k230.c                |  18 ++
>   hw/watchdog/Kconfig            |   4 +
>   hw/watchdog/k230_wdt.c         | 307 +++++++++++++++++++++++++++++++++
>   hw/watchdog/meson.build        |   1 +
>   hw/watchdog/trace-events       |   9 +
>   include/hw/riscv/k230.h        |   4 +
>   include/hw/watchdog/k230_wdt.h | 130 ++++++++++++++
>   9 files changed, 477 insertions(+), 1 deletion(-)
>   create mode 100644 hw/watchdog/k230_wdt.c
>   create mode 100644 include/hw/watchdog/k230_wdt.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 703d9e6b82..564c2af56d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1715,7 +1715,9 @@ M: Chao Liu <chao.liu@zevorn.cn>
>   S: Maintained
>   F: docs/system/riscv/k230.rst
>   F: hw/riscv/k230.c
> +F: hw/watchdog/k230_wdt.c
>   F: include/hw/riscv/k230.h
> +F: include/hw/watchdog/k230_wdt.h
>   
>   RX Machines
>   -----------
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 624f166244..6faaa5cccc 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -137,4 +137,5 @@ config K230
>       select RISCV_APLIC
>       select RISCV_IMSIC
>       select SERIAL_MM
> -    select UNIMP
> \ No newline at end of file
> +    select UNIMP
> +    select K230_WDT
> \ No newline at end of file
> diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
> index f41e9b7002..1460572429 100644
> --- a/hw/riscv/k230.c
> +++ b/hw/riscv/k230.c
> @@ -112,6 +112,9 @@ static void k230_soc_init(Object *obj)
>       RISCVHartArrayState *cpu0 = &s->c908_cpu;
>   
>       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);
> +
>       qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
>       qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
>       qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
> @@ -189,6 +192,21 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
>                      qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART4_IRQ),
>                      399193, serial_hd(4), DEVICE_LITTLE_ENDIAN);
>   
> +    /* Watchdog */
> +    for (int i = 0; i < 2; i++) {
> +        if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
> +            return;
> +        }
> +    }
> +
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[0]), 0, memmap[K230_DEV_WDT0].base);
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[0]), 0,
> +                       qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT0_IRQ));
> +
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[1]), 0, memmap[K230_DEV_WDT1].base);
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0,
> +                       qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ));
> +
>       /* unimplemented devices */
>       create_unimplemented_device("kpu.l2-cache",
>                                   memmap[K230_DEV_KPU_L2_CACHE].base,
> diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
> index 861fd00334..55f77c5c84 100644
> --- a/hw/watchdog/Kconfig
> +++ b/hw/watchdog/Kconfig
> @@ -18,6 +18,10 @@ config WDT_DIAG288
>   config WDT_IMX2
>       bool
>   
> +config K230_WDT
> +    bool
> +    select PTIMER
> +
>   config WDT_SBSA
>       bool
>   
> diff --git a/hw/watchdog/k230_wdt.c b/hw/watchdog/k230_wdt.c
> new file mode 100644
> index 0000000000..f385319836
> --- /dev/null
> +++ b/hw/watchdog/k230_wdt.c
> @@ -0,0 +1,307 @@
> +/*
> + *  * K230 Watchdog Compatible with kendryte K230 SDK
> + *
> + * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
> + * Copyright (c) 2025 Chao Liu <chao.liu@zevorn.cn>
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Provides a board compatible with the kendryte K230 SDK
> + *
> + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> + *
> + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#include "qemu/osdep.h"
> +#include "qemu/bitops.h"
> +#include "qemu/module.h"
> +#include "system/watchdog.h"
> +#include "migration/vmstate.h"
> +#include "hw/qdev-properties.h"
> +
> +#include "hw/watchdog/k230_wdt.h"
> +#include "trace.h"
> +
> +static void k230_wdt_timeout(void *opaque)
> +{
> +    K230WdtState *s = K230_WDT(opaque);
> +
> +    trace_k230_wdt_timeout();
> +
> +    /* Set interrupt status if in interrupt mode */
> +    if (s->cr & K230_WDT_CR_RMOD) {
> +        s->stat |= K230_WDT_STAT_INT;
> +        s->interrupt_pending = true;
> +        qemu_set_irq(s->irq, 1);
> +        trace_k230_wdt_interrupt();
> +    } else {
> +        /* Direct reset mode */
> +        trace_k230_wdt_reset();
> +        watchdog_perform_action();
> +    }
> +
> +    /* Restart counter */
> +    s->current_count = s->timeout_value;
> +    ptimer_set_count(s->timer, s->current_count);
> +    ptimer_run(s->timer, 1);
> +}
> +
> +static void k230_wdt_reset(DeviceState *dev)
> +{
> +    K230WdtState *s = K230_WDT(dev);
> +
> +    trace_k230_wdt_reset_device();
> +
> +    ptimer_transaction_begin(s->timer);
> +    ptimer_stop(s->timer);
> +    ptimer_transaction_commit(s->timer);
> +
> +    /* Reset registers to default values */
> +    s->cr = 0;
> +    s->torr = 0;
> +    s->ccvr = 0xFFFFFFFF;
> +    s->stat = 0;
> +    s->prot_level = 0x2;
> +
> +    s->interrupt_pending = false;
> +    s->enabled = false;
> +    s->timeout_value = 0;
> +    s->current_count = 0xFFFFFFFF;
> +}
> +
> +static uint64_t k230_wdt_read(void *opaque, hwaddr addr, unsigned int size)
> +{
> +    K230WdtState *s = K230_WDT(opaque);
> +    uint32_t value = 0;
> +
> +    switch (addr) {
> +    case K230_WDT_CR:
> +        value = s->cr;
> +        break;
> +    case K230_WDT_TORR:
> +        value = s->torr;
> +        break;
> +    case K230_WDT_CCVR:
> +        if (s->enabled) {
> +            value = ptimer_get_count(s->timer);
> +        } else {
> +            value = s->current_count;
> +        }
> +        break;
> +    case K230_WDT_STAT:
> +        value = s->stat;
> +        break;
> +    case K230_WDT_PROT_LEVEL:
> +        value = s->prot_level;
> +        break;
> +    case K230_WDT_COMP_PARAM_5:
> +        value = 0; /* Upper limit of Timeout Period parameters */
> +        break;
> +    case K230_WDT_COMP_PARAM_4:
> +        value = 0; /* Upper limit of Initial Timeout Period parameters */
> +        break;
> +    case K230_WDT_COMP_PARAM_3:
> +        value = 0; /* Derived from WDT_TOP_RST parameter */
> +        break;
> +    case K230_WDT_COMP_PARAM_2:
> +        value = 0xFFFFFFFF; /* Derived from WDT_RST_CNT parameter */
> +        break;
> +    case K230_WDT_COMP_PARAM_1:
> +        /* Component parameters */
> +        value = (32 << K230_WDT_CNT_WIDTH_SHIFT) |  /* 32-bit counter */
> +                (0 << K230_WDT_DFLT_TOP_INIT_SHIFT) |
> +                (0 << K230_WDT_DFLT_TOP_SHIFT) |
> +                (K230_WDT_RPL_16_CYCLES << K230_WDT_DFLT_RPL_SHIFT) |
> +                (2 << K230_WDT_APB_DATA_WIDTH_SHIFT) | /* 32-bit APB */
> +                K230_WDT_USE_FIX_TOP; /* Use fixed timeout values */
> +        break;
> +    case K230_WDT_COMP_VERSION:
> +        value = K230_WDT_COMP_VERSION_VAL;
> +        break;
> +    case K230_WDT_COMP_TYPE:
> +        value = K230_WDT_COMP_TYPE_VAL;
> +        break;
> +    default:
> +        /* Other registers return 0 */
> +        break;
> +    }
> +
> +    trace_k230_wdt_read(addr, value);
> +    return value;
> +}
> +
> +static void k230_wdt_update_timer(K230WdtState *s)
> +{
> +    ptimer_transaction_begin(s->timer);
> +
> +    if (s->enabled && s->timeout_value > 0) {
> +        ptimer_set_count(s->timer, s->current_count);
> +        ptimer_run(s->timer, 1);
> +    } else {
> +        ptimer_stop(s->timer);
> +    }
> +
> +    ptimer_transaction_commit(s->timer);
> +}
> +
> +static uint32_t k230_wdt_calculate_timeout(uint32_t top_value)
> +{
> +    /* Calculate timeout based on TOP value */
> +    /* For fixed timeout mode: 2^(16 + top_value) */
> +    if (top_value <= 15) {
> +        return 1 << (16 + top_value);
> +    }
> +    return 1 << 31; /* Maximum value for 32-bit counter */
> +}
> +
> +static void k230_wdt_write(void *opaque, hwaddr addr,
> +                           uint64_t value, unsigned int size)
> +{
> +    K230WdtState *s = K230_WDT(opaque);
> +
> +    trace_k230_wdt_write(addr, value);
> +
> +    switch (addr) {
> +    case K230_WDT_CR:
> +        s->cr = value & (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT |
> +                         K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
> +
> +        /* Update enabled state */
> +        s->enabled = (s->cr & K230_WDT_CR_WDT_EN) != 0;
> +
> +        /* Update timer */
> +        k230_wdt_update_timer(s);
> +        break;
> +
> +    case K230_WDT_TORR:
> +        s->torr = value & K230_WDT_TORR_TOP_MASK;
> +
> +        /* Calculate new timeout value */
> +        s->timeout_value = k230_wdt_calculate_timeout(s->torr);
> +        s->current_count = s->timeout_value;
> +
> +        /* Update timer if enabled */
> +        if (s->enabled) {
> +            k230_wdt_update_timer(s);
> +        }
> +        break;
> +
> +    case K230_WDT_CRR:
> +        /* Restart counter with magic value 0x76 */
> +        if ((value & 0xFF) == K230_WDT_CRR_RESTART) {
> +            trace_k230_wdt_restart();
> +            s->current_count = s->timeout_value;
> +
> +            /* Clear interrupt if pending */
> +            if (s->interrupt_pending) {
> +                s->stat &= ~K230_WDT_STAT_INT;
> +                s->interrupt_pending = false;
> +                qemu_set_irq(s->irq, 0);
> +            }
> +
> +            /* Update timer */
> +            k230_wdt_update_timer(s);
> +        }
> +        break;
> +
> +    case K230_WDT_EOI:
> +        /* Clear interrupt */
> +        s->stat &= ~K230_WDT_STAT_INT;
> +        s->interrupt_pending = false;
> +        qemu_set_irq(s->irq, 0);
> +        break;
> +
> +    case K230_WDT_PROT_LEVEL:
> +        s->prot_level = value & 0x7;
> +        break;
> +
> +    default:
> +        /* Read-only registers, ignore writes */
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps k230_wdt_ops = {
> +    .read  = k230_wdt_read,
> +    .write = k230_wdt_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +        .unaligned = false,
> +    },
> +};
> +
> +static const VMStateDescription vmstate_k230_wdt = {
> +    .name = "k230.wdt",
> +    .fields = (const VMStateField[]) {
> +        VMSTATE_PTIMER(timer, K230WdtState),
> +        VMSTATE_UINT32(cr, K230WdtState),
> +        VMSTATE_UINT32(torr, K230WdtState),
> +        VMSTATE_UINT32(ccvr, K230WdtState),
> +        VMSTATE_UINT32(stat, K230WdtState),
> +        VMSTATE_UINT32(prot_level, K230WdtState),
> +        VMSTATE_BOOL(interrupt_pending, K230WdtState),
> +        VMSTATE_BOOL(enabled, K230WdtState),
> +        VMSTATE_UINT32(timeout_value, K230WdtState),
> +        VMSTATE_UINT32(current_count, K230WdtState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void k230_wdt_realize(DeviceState *dev, Error **errp)
> +{
> +    K230WdtState *s = K230_WDT(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +
> +    memory_region_init_io(&s->mmio, OBJECT(dev),
> +                          &k230_wdt_ops, s,
> +                          TYPE_K230_WDT,
> +                          K230_WDT_MMIO_SIZE);
> +    sysbus_init_mmio(sbd, &s->mmio);
> +    sysbus_init_irq(sbd, &s->irq);
> +
> +    s->timer = ptimer_init(k230_wdt_timeout, s,
> +                           PTIMER_POLICY_NO_IMMEDIATE_TRIGGER |
> +                           PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
> +                           PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
> +
> +    ptimer_transaction_begin(s->timer);
> +    ptimer_set_freq(s->timer, K230_WDT_DEFAULT_FREQ);
> +    ptimer_transaction_commit(s->timer);
> +}
> +
> +static void k230_wdt_class_init(ObjectClass *klass, const void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = k230_wdt_realize;
> +    device_class_set_legacy_reset(dc, k230_wdt_reset);
> +    dc->vmsd = &vmstate_k230_wdt;
> +    dc->desc = "K230 watchdog timer";
> +    set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
> +}
> +
> +static const TypeInfo k230_wdt_info = {
> +    .name          = TYPE_K230_WDT,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(K230WdtState),
> +    .class_init    = k230_wdt_class_init,
> +};
> +
> +static void k230_wdt_register_type(void)
> +{
> +    type_register_static(&k230_wdt_info);
> +}
> +type_init(k230_wdt_register_type)
> diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
> index 15370565bd..5edae65a36 100644
> --- a/hw/watchdog/meson.build
> +++ b/hw/watchdog/meson.build
> @@ -6,5 +6,6 @@ system_ss.add(when: 'CONFIG_WDT_IB700', if_true: files('wdt_ib700.c'))
>   system_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
>   system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
>   system_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
> +system_ss.add(when: 'CONFIG_K230_WDT', if_true: files('k230_wdt.c'))
>   system_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
>   specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_watchdog.c'))
> diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events
> index ad3be1e9bd..d85b3ca769 100644
> --- a/hw/watchdog/trace-events
> +++ b/hw/watchdog/trace-events
> @@ -33,3 +33,12 @@ spapr_watchdog_expired(uint64_t num, unsigned action) "num=%" PRIu64 " action=%u
>   # watchdog.c
>   watchdog_perform_action(unsigned int action) "action=%u"
>   watchdog_set_action(unsigned int action) "action=%u"
> +
> +# k230_wdt.c
> +k230_wdt_read(uint64_t addr, uint32_t data) "K230 WDT read: [0x%" PRIx64 "] -> 0x%" PRIx32
> +k230_wdt_write(uint64_t addr, uint64_t data) "K230 WDT write: [0x%" PRIx64 "] <- 0x%" PRIx64
> +k230_wdt_timeout(void) "K230 WDT timeout"
> +k230_wdt_interrupt(void) "K230 WDT interrupt"
> +k230_wdt_reset(void) "K230 WDT system reset"
> +k230_wdt_restart(void) "K230 WDT restart"
> +k230_wdt_reset_device(void) "K230 WDT device reset"
> diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
> index 3158381e8f..f2eedd5f70 100644
> --- a/include/hw/riscv/k230.h
> +++ b/include/hw/riscv/k230.h
> @@ -27,6 +27,7 @@
>   
>   #include "hw/boards.h"
>   #include "hw/riscv/riscv_hart.h"
> +#include "hw/watchdog/k230_wdt.h"
>   
>   #define C908_CPU_HARTID   (0)
>   
> @@ -41,6 +42,7 @@ typedef struct K230SoCState {
>       /*< public >*/
>       RISCVHartArrayState c908_cpu; /* Small core */
>   
> +    K230WdtState wdt[2];
>       MemoryRegion sram;
>       MemoryRegion bootrom;
>   
> @@ -131,6 +133,8 @@ enum {
>       K230_UART2_IRQ  = 18,
>       K230_UART3_IRQ  = 19,
>       K230_UART4_IRQ  = 20,
> +    K230_WDT0_IRQ   = 32,
> +    K230_WDT1_IRQ   = 33,
>   };
>   
>   /*
> diff --git a/include/hw/watchdog/k230_wdt.h b/include/hw/watchdog/k230_wdt.h
> new file mode 100644
> index 0000000000..9371602387
> --- /dev/null
> +++ b/include/hw/watchdog/k230_wdt.h
> @@ -0,0 +1,130 @@
> +/*
> + * K230 Watchdog Timer
> + *
> + * Based on K230 technical documentation
> + *
> + * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef K230_WDT_H
> +#define K230_WDT_H
> +
> +#include "qemu/bitops.h"
> +#include "hw/sysbus.h"
> +#include "hw/irq.h"
> +#include "hw/ptimer.h"
> +#include "qom/object.h"
> +
> +#define TYPE_K230_WDT "riscv.k230.wdt"
> +OBJECT_DECLARE_SIMPLE_TYPE(K230WdtState, K230_WDT)
> +
> +#define K230_WDT_DEFAULT_FREQ (32768)
> +
> +/* K230 Watchdog Register Map */
> +enum K230WdtRegisters {
> +    K230_WDT_CR      = 0x00,  /* Control Register */
> +    K230_WDT_TORR    = 0x04,  /* Timeout Range Register */
> +    K230_WDT_CCVR    = 0x08,  /* Current Counter Value Register */
> +    K230_WDT_CRR     = 0x0c,  /* Counter Restart Register */
> +    K230_WDT_STAT    = 0x10,  /* Interrupt Status Register */
> +    K230_WDT_EOI     = 0x14,  /* Interrupt Clear Register */
> +    K230_WDT_PROT_LEVEL = 0x1c, /* Protection Level Register */
> +    K230_WDT_COMP_PARAM_5 = 0xe4, /* Component Parameters Register 5 */
> +    K230_WDT_COMP_PARAM_4 = 0xe8, /* Component Parameters Register 4 */
> +    K230_WDT_COMP_PARAM_3 = 0xec, /* Component Parameters Register 3 */
> +    K230_WDT_COMP_PARAM_2 = 0xf0, /* Component Parameters Register 2 */
> +    K230_WDT_COMP_PARAM_1 = 0xf4, /* Component Parameters Register 1 */
> +    K230_WDT_COMP_VERSION = 0xf8, /* Component Version Register */
> +    K230_WDT_COMP_TYPE = 0xfc, /* Component Type Register */
> +};
> +
> +#define K230_WDT_MMIO_SIZE 0x100
> +
> +/* Control Register (WDT_CR) definitions */
> +#define K230_WDT_CR_RPL_MASK    0x7        /* Reset Pulse Length */
> +#define K230_WDT_CR_RPL_SHIFT   2
> +#define K230_WDT_CR_RMOD        BIT(1)     /* Response Mode */
> +#define K230_WDT_CR_WDT_EN      BIT(0)     /* Watchdog Enable */
> +
> +/* Reset Pulse Length values */
> +#define K230_WDT_RPL_2_CYCLES   0x0
> +#define K230_WDT_RPL_4_CYCLES   0x1
> +#define K230_WDT_RPL_8_CYCLES   0x2
> +#define K230_WDT_RPL_16_CYCLES  0x3
> +#define K230_WDT_RPL_32_CYCLES  0x4
> +#define K230_WDT_RPL_64_CYCLES  0x5
> +#define K230_WDT_RPL_128_CYCLES 0x6
> +#define K230_WDT_RPL_256_CYCLES 0x7
> +
> +/* Timeout Range Register (WDT_TORR) definitions */
> +#define K230_WDT_TORR_TOP_MASK  0xf        /* Timeout Period */
> +
> +/* Interrupt Status Register (WDT_STAT) definitions */
> +#define K230_WDT_STAT_INT       BIT(0)     /* Interrupt Status */
> +
> +/* Counter Restart Register (WDT_CRR) magic value */
> +#define K230_WDT_CRR_RESTART    0x76       /* Restart command */
> +
> +/* Component Parameters Register 1 (WDT_COMP_PARAM_1) definitions */
> +#define K230_WDT_CNT_WIDTH_MASK 0x1f000000 /* Counter Width */
> +#define K230_WDT_CNT_WIDTH_SHIFT 24
> +#define K230_WDT_DFLT_TOP_INIT_MASK 0xf00000 /* Default Initial Timeout */
> +#define K230_WDT_DFLT_TOP_INIT_SHIFT 20
> +#define K230_WDT_DFLT_TOP_MASK  0xf0000    /* Default Timeout */
> +#define K230_WDT_DFLT_TOP_SHIFT 16
> +#define K230_WDT_DFLT_RPL_MASK  0x7        /* Default Reset Pulse Length */
> +#define K230_WDT_DFLT_RPL_SHIFT 10
> +#define K230_WDT_APB_DATA_WIDTH_MASK 0x3   /* APB Data Width */
> +#define K230_WDT_APB_DATA_WIDTH_SHIFT 8
> +#define K230_WDT_USE_FIX_TOP    BIT(6)     /* Use Fixed Timeout Values */
> +#define K230_WDT_HC_TOP         BIT(5)     /* Hard-coded Timeout */
> +#define K230_WDT_HC_RPL         BIT(4)     /* Hard-coded Reset Pulse Length */
> +#define K230_WDT_HC_RMOD        BIT(3)     /* Hard-coded Response Mode */
> +#define K230_WDT_DUAL_TOP       BIT(2)     /* Dual Timeout Period */
> +#define K230_WDT_DFLT_RMOD      BIT(1)     /* Default Response Mode */
> +#define K230_WDT_ALWAYS_EN      BIT(0)     /* Always Enabled */
> +
> +/* Component Type Register value */
> +#define K230_WDT_COMP_TYPE_VAL  0x44570120
> +
> +/* Component Version Register value */
> +#define K230_WDT_COMP_VERSION_VAL 0x3131302a  /* "110*" */
> +
> +struct K230WdtState {
> +    /* <private> */
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion mmio;
> +    qemu_irq irq;
> +
> +    struct ptimer_state *timer;
> +
> +    /* Register state */
> +    uint32_t cr;           /* Control Register */
> +    uint32_t torr;         /* Timeout Range Register */
> +    uint32_t ccvr;         /* Current Counter Value Register */
> +    uint32_t stat;         /* Interrupt Status Register */
> +    uint32_t prot_level;   /* Protection Level Register */
> +
> +    /* Internal state */
> +    bool interrupt_pending;
> +    bool enabled;
> +    uint32_t timeout_value;
> +    uint32_t current_count;
> +};
> +
> +#endif /* K230_WDT_H */



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 4/5] tests/qtest: add test for K230 watchdog
  2025-11-30  9:21 ` [PATCH v1 4/5] tests/qtest: add test for K230 watchdog Chao Liu
@ 2025-12-03 17:08   ` Daniel Henrique Barboza
  0 siblings, 0 replies; 16+ messages in thread
From: Daniel Henrique Barboza @ 2025-12-03 17:08 UTC (permalink / raw)
  To: Chao Liu, richard.henderson, paolo.savini, npiggin, ebiggers,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches,
	Mig Yang



On 11/30/25 6:21 AM, Chao Liu wrote:
> Testing the Basic Functions of K230 WDT:
> 1. Reset Function
> 2. Timeout Check
> 3. Interrupt Function
> 
> Signed-off-by: Mig Yang <temashking@foxmail.com>
> ---


Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>

>   MAINTAINERS                 |   1 +
>   tests/qtest/k230-wdt-test.c | 199 ++++++++++++++++++++++++++++++++++++
>   tests/qtest/meson.build     |   3 +-
>   3 files changed, 202 insertions(+), 1 deletion(-)
>   create mode 100644 tests/qtest/k230-wdt-test.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 564c2af56d..bfa63f832e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1718,6 +1718,7 @@ F: hw/riscv/k230.c
>   F: hw/watchdog/k230_wdt.c
>   F: include/hw/riscv/k230.h
>   F: include/hw/watchdog/k230_wdt.h
> +F: tests/qtest/k230-wdt-test.c
>   
>   RX Machines
>   -----------
> diff --git a/tests/qtest/k230-wdt-test.c b/tests/qtest/k230-wdt-test.c
> new file mode 100644
> index 0000000000..2550cebd10
> --- /dev/null
> +++ b/tests/qtest/k230-wdt-test.c
> @@ -0,0 +1,199 @@
> +/*
> + * QTest testcase for K230 Watchdog
> + *
> + * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Provides a board compatible with the kendryte K230 SDK
> + *
> + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> + *
> + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/timer.h"
> +#include "qemu/bitops.h"
> +#include "libqtest.h"
> +#include "hw/watchdog/k230_wdt.h"
> +
> +/* K230 WDT0 base address */
> +#define K230_WDT0_BASE 0x91106000
> +#define K230_WDT1_BASE 0x91106800
> +
> +/* Test WDT0 by default */
> +#define WDT_BASE K230_WDT0_BASE
> +
> +static void test_register_read_write(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    /* Test Control Register (CR) read/write */
> +    qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0xFFFFFFFF);
> +    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_CR), ==,
> +                    (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT) |
> +                    K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
> +
> +    /* Test Timeout Range Register (TORR) read/write */
> +    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0xFFFFFFFF);
> +    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_TORR), ==,
> +                    K230_WDT_TORR_TOP_MASK);
> +
> +    /* Test Protection Level Register read/write */
> +    qtest_writel(qts, WDT_BASE + K230_WDT_PROT_LEVEL, 0xFFFFFFFF);
> +    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_PROT_LEVEL), ==, 0x7);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_counter_restart(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    /* Enable watchdog and set timeout */
> +    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
> +    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x5); /* TOP = 5 */
> +
> +    /* Read current counter value */
> +    uint32_t initial_count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
> +    g_assert_cmpuint(initial_count, >, 0);
> +
> +    /* Restart counter with magic value */
> +    qtest_writel(qts, WDT_BASE + K230_WDT_CRR, K230_WDT_CRR_RESTART);
> +
> +    /* Wait for time */
> +    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 2);
> +
> +    /* Counter should be reset to timeout value */
> +    uint32_t new_count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
> +    g_assert_cmpuint(new_count, >, 0);
> +    g_assert_cmpuint(new_count, !=, initial_count);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_interrupt_mode(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230 --trace k230_*,file=k230.log");
> +
> +    /* Set interrupt mode and enable watchdog */
> +    qtest_writel(qts, WDT_BASE + K230_WDT_CR,
> +                 K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
> +    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x1); /* Short timeout */
> +
> +    /* Wait for timeout to trigger interrupt */
> +    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 10);
> +
> +    /* Check interrupt status */
> +    uint32_t stat = qtest_readl(qts, WDT_BASE + K230_WDT_STAT);
> +    g_assert_cmphex(stat & K230_WDT_STAT_INT, ==, K230_WDT_STAT_INT);
> +
> +    /* Clear interrupt */
> +    qtest_writel(qts, WDT_BASE + K230_WDT_EOI, 0x1);
> +    stat = qtest_readl(qts, WDT_BASE + K230_WDT_STAT);
> +    g_assert_cmphex(stat & K230_WDT_STAT_INT, ==, 0);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_reset_mode(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230 -no-reboot");
> +
> +    /* Set reset mode and enable watchdog */
> +    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
> +    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x1); /* Short timeout */
> +
> +    /* Wait for timeout to trigger reset */
> +    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 2);
> +
> +    /* In reset mode, the system should reset */
> +    /* This test verifies that reset mode is properly configured */
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_timeout_calculation(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    /* Test different timeout values */
> +    for (uint32_t top = 0; top <= 15; top++) {
> +        qtest_writel(qts, WDT_BASE + K230_WDT_TORR, top);
> +        qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
> +
> +        /* Read current counter value */
> +        uint32_t count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
> +        g_assert_cmpuint(count, >, 0);
> +
> +        /* Disable watchdog for next iteration */
> +        qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0);
> +    }
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_wdt1_registers(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    /* Test WDT1 registers (second watchdog) */
> +    qtest_writel(qts, K230_WDT1_BASE + K230_WDT_CR, 0xFFFFFFFF);
> +    g_assert_cmphex(qtest_readl(qts, K230_WDT1_BASE + K230_WDT_CR), ==,
> +                    (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT) |
> +                    K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
> +
> +    qtest_writel(qts, K230_WDT1_BASE + K230_WDT_TORR, 0xFFFFFFFF);
> +    g_assert_cmphex(qtest_readl(qts, K230_WDT1_BASE + K230_WDT_TORR), ==,
> +                    K230_WDT_TORR_TOP_MASK);
> +
> +    qtest_quit(qts);
> +}
> +
> +static void test_enable_disable(void)
> +{
> +    QTestState *qts = qtest_init("-machine k230");
> +
> +    /* Initially disabled */
> +    uint32_t cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
> +    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, 0);
> +
> +    /* Enable watchdog */
> +    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
> +    cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
> +    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, K230_WDT_CR_WDT_EN);
> +
> +    /* Disable watchdog */
> +    qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0);
> +    cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
> +    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, 0);
> +
> +    qtest_quit(qts);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    g_test_init(&argc, &argv, NULL);
> +
> +    qtest_add_func("/k230-wdt/register_read_write", test_register_read_write);
> +    qtest_add_func("/k230-wdt/counter_restart", test_counter_restart);
> +    qtest_add_func("/k230-wdt/interrupt_mode", test_interrupt_mode);
> +    qtest_add_func("/k230-wdt/reset_mode", test_reset_mode);
> +    qtest_add_func("/k230-wdt/timeout_calculation", test_timeout_calculation);
> +    qtest_add_func("/k230-wdt/wdt1_registers", test_wdt1_registers);
> +    qtest_add_func("/k230-wdt/enable_disable", test_enable_disable);
> +
> +    return g_test_run();
> +}
> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> index 669d07c06b..0d9339e938 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -282,7 +282,8 @@ qtests_riscv32 = \
>     (config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? ['sifive-e-aon-watchdog-test'] : [])
>   
>   qtests_riscv64 = ['riscv-csr-test'] + \
> -  (unpack_edk2_blobs ? ['bios-tables-test'] : [])
> +  (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
> +  (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
>   
>   qos_test_ss = ss.source_set()
>   qos_test_ss.add(



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/5] target/riscv: add thead-c908 cpu support
  2025-11-30  9:21 ` [PATCH v1 1/5] target/riscv: add thead-c908 cpu support Chao Liu
  2025-12-03 16:33   ` Daniel Henrique Barboza
@ 2025-12-03 17:12   ` Conor Dooley
  2025-12-03 17:13     ` Conor Dooley
  1 sibling, 1 reply; 16+ messages in thread
From: Conor Dooley @ 2025-12-03 17:12 UTC (permalink / raw)
  To: Chao Liu
  Cc: richard.henderson, paolo.savini, npiggin, ebiggers, dbarboza,
	palmer, alistair.francis, liwei1518, zhiwei_liu, qemu-riscv,
	qemu-devel, chao.liu, hust-os-kernel-patches

[-- Attachment #1: Type: text/plain, Size: 2959 bytes --]

On Sun, Nov 30, 2025 at 05:21:06PM +0800, Chao Liu wrote:
> The C908 processor is based on the RV64GCB[V] instruction
> set, compatible to RVA22 Profile and implements the XIE
> (XuanTie Instruction Extension) technology.
> 
> Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
> Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> ---
>  target/riscv/cpu-qom.h |   2 +
>  target/riscv/cpu.c     |  43 +++++
>  target/riscv/th_csr.c  | 380 ++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 424 insertions(+), 1 deletion(-)
> 
> diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
> index 75f4e43408..1ddb5a6a6c 100644
> --- a/target/riscv/cpu-qom.h
> +++ b/target/riscv/cpu-qom.h
> @@ -52,6 +52,8 @@
>  #define TYPE_RISCV_CPU_SIFIVE_U34       RISCV_CPU_TYPE_NAME("sifive-u34")
>  #define TYPE_RISCV_CPU_SIFIVE_U54       RISCV_CPU_TYPE_NAME("sifive-u54")
>  #define TYPE_RISCV_CPU_THEAD_C906       RISCV_CPU_TYPE_NAME("thead-c906")
> +#define TYPE_RISCV_CPU_THEAD_C908       RISCV_CPU_TYPE_NAME("thead-c908")
> +#define TYPE_RISCV_CPU_THEAD_C908V      RISCV_CPU_TYPE_NAME("thead-c908v")
>  #define TYPE_RISCV_CPU_VEYRON_V1        RISCV_CPU_TYPE_NAME("veyron-v1")
>  #define TYPE_RISCV_CPU_TT_ASCALON       RISCV_CPU_TYPE_NAME("tt-ascalon")
>  #define TYPE_RISCV_CPU_XIANGSHAN_NANHU  RISCV_CPU_TYPE_NAME("xiangshan-nanhu")
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index d055ddf462..202ff130ee 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -3091,6 +3091,49 @@ static const TypeInfo riscv_cpu_type_infos[] = {
>  #endif
>      ),
>  
> +    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908, TYPE_RISCV_VENDOR_CPU,
> +        .misa_mxl_max = MXL_RV64,
> +        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU,
> +        .priv_spec = PRIV_VERSION_1_12_0,
> +
> +        /* ISA extensions */
> +        .cfg.ext_xtheadba = true,
> +        .cfg.ext_xtheadbb = true,
> +        .cfg.ext_xtheadbs = true,
> +        .cfg.ext_xtheadcmo = true,
> +        .cfg.ext_xtheadcondmov = true,
> +        .cfg.ext_xtheadmac = true,
> +        .cfg.ext_xtheadmemidx = true,
> +        .cfg.ext_xtheadmempair = true,
> +        .cfg.ext_xtheadsync = true,
> +        .cfg.ext_zba = true,
> +        .cfg.ext_zbb = true,
> +        .cfg.ext_zbc = true,
> +        .cfg.ext_zbs = true,
> +        .cfg.ext_zkt = true,
> +        .cfg.ext_zbkc = true,
> +        .cfg.ext_zicsr = true,
> +        .cfg.ext_zifencei = true,
> +        .cfg.ext_zihintpause = true,
> +        .cfg.ext_zicbom = true,
> +        .cfg.ext_zicboz = true,
> +        .cfg.ext_zfh = true,
> +        .cfg.ext_xtheadfmv = true,
> +        .cfg.ext_xtheadfmemidx = true,
> +        .cfg.pmp = true,

I think Svpbmt is missing here, both it and the T-Head MAEE stuff are
supported on the k230. What I will end up merging into mainline for the
k230 uses Svpbmt instead of MAEE.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/5] target/riscv: add thead-c908 cpu support
  2025-12-03 17:12   ` Conor Dooley
@ 2025-12-03 17:13     ` Conor Dooley
  2025-12-04  2:59       ` Chao Liu
  0 siblings, 1 reply; 16+ messages in thread
From: Conor Dooley @ 2025-12-03 17:13 UTC (permalink / raw)
  To: Chao Liu
  Cc: richard.henderson, paolo.savini, npiggin, ebiggers, dbarboza,
	palmer, alistair.francis, liwei1518, zhiwei_liu, qemu-riscv,
	qemu-devel, chao.liu, hust-os-kernel-patches

[-- Attachment #1: Type: text/plain, Size: 3237 bytes --]

On Wed, Dec 03, 2025 at 05:12:37PM +0000, Conor Dooley wrote:
> On Sun, Nov 30, 2025 at 05:21:06PM +0800, Chao Liu wrote:
> > The C908 processor is based on the RV64GCB[V] instruction
> > set, compatible to RVA22 Profile and implements the XIE
> > (XuanTie Instruction Extension) technology.
> > 
> > Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
> > Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> > ---
> >  target/riscv/cpu-qom.h |   2 +
> >  target/riscv/cpu.c     |  43 +++++
> >  target/riscv/th_csr.c  | 380 ++++++++++++++++++++++++++++++++++++++++-
> >  3 files changed, 424 insertions(+), 1 deletion(-)
> > 
> > diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
> > index 75f4e43408..1ddb5a6a6c 100644
> > --- a/target/riscv/cpu-qom.h
> > +++ b/target/riscv/cpu-qom.h
> > @@ -52,6 +52,8 @@
> >  #define TYPE_RISCV_CPU_SIFIVE_U34       RISCV_CPU_TYPE_NAME("sifive-u34")
> >  #define TYPE_RISCV_CPU_SIFIVE_U54       RISCV_CPU_TYPE_NAME("sifive-u54")
> >  #define TYPE_RISCV_CPU_THEAD_C906       RISCV_CPU_TYPE_NAME("thead-c906")
> > +#define TYPE_RISCV_CPU_THEAD_C908       RISCV_CPU_TYPE_NAME("thead-c908")
> > +#define TYPE_RISCV_CPU_THEAD_C908V      RISCV_CPU_TYPE_NAME("thead-c908v")
> >  #define TYPE_RISCV_CPU_VEYRON_V1        RISCV_CPU_TYPE_NAME("veyron-v1")
> >  #define TYPE_RISCV_CPU_TT_ASCALON       RISCV_CPU_TYPE_NAME("tt-ascalon")
> >  #define TYPE_RISCV_CPU_XIANGSHAN_NANHU  RISCV_CPU_TYPE_NAME("xiangshan-nanhu")
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index d055ddf462..202ff130ee 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -3091,6 +3091,49 @@ static const TypeInfo riscv_cpu_type_infos[] = {
> >  #endif
> >      ),
> >  
> > +    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908, TYPE_RISCV_VENDOR_CPU,
> > +        .misa_mxl_max = MXL_RV64,
> > +        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU,
> > +        .priv_spec = PRIV_VERSION_1_12_0,
> > +
> > +        /* ISA extensions */
> > +        .cfg.ext_xtheadba = true,
> > +        .cfg.ext_xtheadbb = true,
> > +        .cfg.ext_xtheadbs = true,
> > +        .cfg.ext_xtheadcmo = true,
> > +        .cfg.ext_xtheadcondmov = true,
> > +        .cfg.ext_xtheadmac = true,
> > +        .cfg.ext_xtheadmemidx = true,
> > +        .cfg.ext_xtheadmempair = true,
> > +        .cfg.ext_xtheadsync = true,
> > +        .cfg.ext_zba = true,
> > +        .cfg.ext_zbb = true,
> > +        .cfg.ext_zbc = true,
> > +        .cfg.ext_zbs = true,
> > +        .cfg.ext_zkt = true,
> > +        .cfg.ext_zbkc = true,
> > +        .cfg.ext_zicsr = true,
> > +        .cfg.ext_zifencei = true,
> > +        .cfg.ext_zihintpause = true,
> > +        .cfg.ext_zicbom = true,
> > +        .cfg.ext_zicboz = true,
> > +        .cfg.ext_zfh = true,
> > +        .cfg.ext_xtheadfmv = true,
> > +        .cfg.ext_xtheadfmemidx = true,
> > +        .cfg.pmp = true,
> 
> I think Svpbmt is missing here, both it and the T-Head MAEE stuff are
> supported on the k230. What I will end up merging into mainline for the

Whoops, should have specified that I meant the mainline linux kernel.

> k230 uses Svpbmt instead of MAEE.



[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 5/5] docs/system/riscv: add documentation for k230 machine
  2025-11-30  9:21 ` [PATCH v1 5/5] docs/system/riscv: add documentation for k230 machine Chao Liu
@ 2025-12-03 17:19   ` Daniel Henrique Barboza
  2025-12-04  3:03     ` Chao Liu
  0 siblings, 1 reply; 16+ messages in thread
From: Daniel Henrique Barboza @ 2025-12-03 17:19 UTC (permalink / raw)
  To: Chao Liu, richard.henderson, paolo.savini, npiggin, ebiggers,
	palmer, alistair.francis, liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, chao.liu, hust-os-kernel-patches

Hi,

This patch won't build in my env:

[3031/3032] Generating docs/QEMU manual with a custom command
FAILED: docs/docs.stamp
/usr/bin/env CONFDIR=etc/qemu /home/danielhb/work/qemu/build/pyvenv/bin/sphinx-build -q -W -Dkerneldoc_werror=1 -j auto -Dversion=10.1.92 -Drelease= -Ddepfile=docs/docs.d -Ddepfile_stamp=docs/docs.stamp -b html -d /home/danielhb/work/qemu/build/docs/manual.p /home/danielhb/work/qemu/docs /home/danielhb/work/qemu/build/docs/manual
/home/danielhb/work/qemu/docs/system/riscv/k230.rst: WARNING: document isn't included in any toctree
ninja: build stopped: subcommand failed.



This diff fixes it:


$ git diff
diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
index 89b2cb732c..2103ff6173 100644
--- a/docs/system/target-riscv.rst
+++ b/docs/system/target-riscv.rst
@@ -66,6 +66,7 @@ undocumented; you can get a complete list by running
  .. toctree::
     :maxdepth: 1
  
+   riscv/k230
     riscv/microblaze-v-generic
     riscv/microchip-icicle-kit
     riscv/shakti-c



Thanks,

Daniel


On 11/30/25 6:21 AM, Chao Liu wrote:
> Add documentation for k230 virt reference platform.
> 
> Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
> ---
>   docs/system/riscv/k230.rst | 48 ++++++++++++++++++++++++++++++++++++++
>   1 file changed, 48 insertions(+)
>   create mode 100644 docs/system/riscv/k230.rst
> 
> diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
> new file mode 100644
> index 0000000000..3e6ca295df
> --- /dev/null
> +++ b/docs/system/riscv/k230.rst
> @@ -0,0 +1,48 @@
> +Kendryte K230 virt reference platform (``k230``)
> +==========================================================================
> +The ``k230`` machine is compatible with with Kendryte K230 SDK.
> +
> +The K230 is a chip from the AIoT SoC series made by Kendryte ® — a part of
> +Canaan Inc. It uses a brand-new multi-heterogeneous unit accelerated computing
> +structure.
> +
> +This chip has 2 RISC-V computing cores and a new-generation KPU (Knowledge
> +Process Unit) smart computing unit.
> +
> +It has multi-precision AI computing ability, works with many common AI computing
> +frameworks, and for some typical networks, its usage rate is over 70%. Besides,
> +the K230 chip supports many peripheral connections and has several special
> +hardware acceleration units (like 2D and 2.5D accelerators). It can speed up
> +different tasks (such as image processing, video processing, audio processing
> +and AI computing). It also has many good features: low delay, high performance,
> +low power use and fast start-up.
> +
> +For more information, see <https://www.kendryte.com/en/proDetail/230>
> +
> +Supported devices
> +-----------------
> +The ``k230`` machine supports the following devices:
> +
> +* 1 c908 cores
> +* Core Local Interruptor (CLINT)
> +* Incoming MSI Controller (IMSIC)
> +* 2 K230 Watchdog Timer
> +* 4 UART
> +
> +Boot options
> +------------
> +The ``k230`` machine can start using the standard ``-bios``
> +functionality for loading the boot image. You need to compile and link
> +the firmware, kernel, and Device Tree (FDT) into a single binary file with
> +K230 SDK(k230_canmv_defconfig), such as ``uboot``.
> +
> +Running
> +-------
> +Below is an example command line for running the ``k230``
> +machine:
> +
> +.. code-block:: bash
> +
> +   $ qemu-system-riscv64 -machine k230 \
> +      -bios k230_sdk/output/k230_canmv_defconfig/little/uboot/u-boot \
> +      -nographic



^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 2/5] hw/riscv: add k230 board initial support
  2025-12-03 17:02   ` Daniel Henrique Barboza
@ 2025-12-04  1:12     ` Chao Liu
  0 siblings, 0 replies; 16+ messages in thread
From: Chao Liu @ 2025-12-04  1:12 UTC (permalink / raw)
  To: Daniel Henrique Barboza, Chao Liu, richard.henderson,
	paolo.savini, npiggin, ebiggers, palmer, alistair.francis,
	liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, hust-os-kernel-patches

On 12/4/2025 1:02 AM, Daniel Henrique Barboza wrote:
> 
> 
> On 11/30/25 6:21 AM, Chao Liu wrote:
>> K230 Board Compatible with kendryte K230 SDK.
>>
>> Preliminarily supports the C908 small core, which can
>> run the U-Boot and Linux kernel compiled by the K230 SDK.
>>
>> Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
>> ---
>>   MAINTAINERS             |   7 +
>>   hw/riscv/Kconfig        |  10 +
>>   hw/riscv/k230.c         | 483 ++++++++++++++++++++++++++++++++++++++++
>>   hw/riscv/meson.build    |   2 +-
>>   include/hw/riscv/k230.h | 149 +++++++++++++
>>   5 files changed, 650 insertions(+), 1 deletion(-)
>>   create mode 100644 hw/riscv/k230.c
>>   create mode 100644 include/hw/riscv/k230.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index a07086ed76..703d9e6b82 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -1710,6 +1710,13 @@ F: docs/system/riscv/xiangshan-kunminghu.rst
>>   F: hw/riscv/xiangshan_kmh.c
>>   F: include/hw/riscv/xiangshan_kmh.h
>>   +K230 Machines
>> +M: Chao Liu <chao.liu@zevorn.cn>
>> +S: Maintained
>> +F: docs/system/riscv/k230.rst
> 
> Nit: at this point there's no k230.rst file (it's on patch 5). A minor comment.
> 
I found this issue too, and I will fix it in PATCH v2

Thanks,
Chao
> LGTM otherwise. Thanks,
> 
> Daniel
> 
>> +F: hw/riscv/k230.c
>> +F: include/hw/riscv/k230.h
>> +
>>   RX Machines
>>   -----------
>>   rx-gdbsim
>> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
>> index fc9c35bd98..624f166244 100644
>> --- a/hw/riscv/Kconfig
>> +++ b/hw/riscv/Kconfig
>> @@ -128,3 +128,13 @@ config XIANGSHAN_KUNMINGHU
>>       select RISCV_APLIC
>>       select RISCV_IMSIC
>>       select SERIAL_MM
>> +
>> +config K230
>> +    bool
>> +    default y
>> +    depends on RISCV64
>> +    select RISCV_ACLINT
>> +    select RISCV_APLIC
>> +    select RISCV_IMSIC
>> +    select SERIAL_MM
>> +    select UNIMP
>> \ No newline at end of file
>> diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
>> new file mode 100644
>> index 0000000000..f41e9b7002
>> --- /dev/null
>> +++ b/hw/riscv/k230.c
>> @@ -0,0 +1,483 @@
>> +/*
>> + * QEMU RISC-V Virt Board Compatible with Kendryte K230 SDK
>> + *
>> + * Copyright (c) 2025 Chao Liu <chao.liu@zevorn.cn>
>> + * SPDX-License-Identifier: GPL-2.0-or-later
>> + *
>> + * Provides a board compatible with the Kendryte K230 SDK
>> + *
>> + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
>> + *
>> + * For more information, see <https://www.kendryte.com/en/proDetail/230>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms and conditions of the GNU General Public License,
>> + * version 2 or later, as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "cpu-qom.h"
>> +#include "qemu/cutils.h"
>> +#include "qemu/error-report.h"
>> +#include "qapi/error.h"
>> +#include "system/system.h"
>> +#include "system/memory.h"
>> +#include "target/riscv/cpu.h"
>> +#include "chardev/char.h"
>> +#include "hw/loader.h"
>> +#include "hw/sysbus.h"
>> +#include "hw/riscv/k230.h"
>> +#include "hw/riscv/boot.h"
>> +#include "hw/intc/riscv_aclint.h"
>> +#include "hw/intc/sifive_plic.h"
>> +#include "hw/char/serial-mm.h"
>> +#include "hw/misc/unimp.h"
>> +
>> +static const MemMapEntry memmap[] = {
>> +    [K230_DEV_DDRC] =         { 0x00000000, 0x80000000 },
>> +    [K230_DEV_KPU_L2_CACHE] = { 0x80000000, 0x00200000 },
>> +    [K230_DEV_SRAM] =         { 0x80200000, 0x00200000 },
>> +    [K230_DEV_KPU_CFG] =      { 0x80400000, 0x00000800 },
>> +    [K230_DEV_FFT] =          { 0x80400800, 0x00000400 },
>> +    [K230_DEV_AI_2D_ENGINE] = { 0x80400C00, 0x00000800 },
>> +    [K230_DEV_GSDMA] =        { 0x80800000, 0x00004000 },
>> +    [K230_DEV_DMA] =          { 0x80804000, 0x00004000 },
>> +    [K230_DEV_DECOMP_GZIP] =  { 0x80808000, 0x00004000 },
>> +    [K230_DEV_NON_AI_2D] =    { 0x8080C000, 0x00004000 },
>> +    [K230_DEV_ISP] =          { 0x90000000, 0x00008000 },
>> +    [K230_DEV_DEWARP] =       { 0x90008000, 0x00001000 },
>> +    [K230_DEV_RX_CSI] =       { 0x90009000, 0x00002000 },
>> +    [K230_DEV_H264] =         { 0x90400000, 0x00010000 },
>> +    [K230_DEV_2P5D] =         { 0x90800000, 0x00040000 },
>> +    [K230_DEV_VO] =           { 0x90840000, 0x00010000 },
>> +    [K230_DEV_VO_CFG] =       { 0x90850000, 0x00001000 },
>> +    [K230_DEV_3D_ENGINE] =    { 0x90A00000, 0x00000800 },
>> +    [K230_DEV_PMU] =          { 0x91000000, 0x00000C00 },
>> +    [K230_DEV_RTC] =          { 0x91000C00, 0x00000400 },
>> +    [K230_DEV_CMU] =          { 0x91100000, 0x00001000 },
>> +    [K230_DEV_RMU] =          { 0x91101000, 0x00001000 },
>> +    [K230_DEV_BOOT] =         { 0x91102000, 0x00001000 },
>> +    [K230_DEV_PWR] =          { 0x91103000, 0x00001000 },
>> +    [K230_DEV_MAILBOX] =      { 0x91104000, 0x00001000 },
>> +    [K230_DEV_IOMUX] =        { 0x91105000, 0x00000800 },
>> +    [K230_DEV_TIMER] =        { 0x91105800, 0x00000800 },
>> +    [K230_DEV_WDT0] =         { 0x91106000, 0x00000800 },
>> +    [K230_DEV_WDT1] =         { 0x91106800, 0x00000800 },
>> +    [K230_DEV_TS] =           { 0x91107000, 0x00000800 },
>> +    [K230_DEV_HDI] =          { 0x91107800, 0x00000800 },
>> +    [K230_DEV_STC] =          { 0x91108000, 0x00000800 },
>> +    [K230_DEV_BOOTROM] =      { 0x91200000, 0x00010000 },
>> +    [K230_DEV_SECURITY] =     { 0x91210000, 0x00008000 },
>> +    [K230_DEV_UART0] =        { 0x91400000, 0x00001000 },
>> +    [K230_DEV_UART1] =        { 0x91401000, 0x00001000 },
>> +    [K230_DEV_UART2] =        { 0x91402000, 0x00001000 },
>> +    [K230_DEV_UART3] =        { 0x91403000, 0x00001000 },
>> +    [K230_DEV_UART4] =        { 0x91404000, 0x00001000 },
>> +    [K230_DEV_I2C0] =         { 0x91405000, 0x00001000 },
>> +    [K230_DEV_I2C1] =         { 0x91406000, 0x00001000 },
>> +    [K230_DEV_I2C2] =         { 0x91407000, 0x00001000 },
>> +    [K230_DEV_I2C3] =         { 0x91408000, 0x00001000 },
>> +    [K230_DEV_I2C4] =         { 0x91409000, 0x00001000 },
>> +    [K230_DEV_PWM] =          { 0x9140A000, 0x00001000 },
>> +    [K230_DEV_GPIO0] =        { 0x9140B000, 0x00001000 },
>> +    [K230_DEV_GPIO1] =        { 0x9140C000, 0x00001000 },
>> +    [K230_DEV_ADC] =          { 0x9140D000, 0x00001000 },
>> +    [K230_DEV_CODEC] =        { 0x9140E000, 0x00001000 },
>> +    [K230_DEV_I2S] =          { 0x9140F000, 0x00001000 },
>> +    [K230_DEV_USB0] =         { 0x91500000, 0x00010000 },
>> +    [K230_DEV_USB1] =         { 0x91540000, 0x00010000 },
>> +    [K230_DEV_SD0] =          { 0x91580000, 0x00001000 },
>> +    [K230_DEV_SD1] =          { 0x91581000, 0x00001000 },
>> +    [K230_DEV_QSPI0] =        { 0x91582000, 0x00001000 },
>> +    [K230_DEV_QSPI1] =        { 0x91583000, 0x00001000 },
>> +    [K230_DEV_SPI] =          { 0x91584000, 0x00001000 },
>> +    [K230_DEV_HI_SYS_CFG] =   { 0x91585000, 0x00000400 },
>> +    [K230_DEV_DDRC_CFG] =     { 0x98000000, 0x02000000 },
>> +    [K230_DEV_FLASH] =        { 0xC0000000, 0x08000000 },
>> +    [K230_DEV_PLIC] =         { 0xF0000000, 0x00400000 },
>> +    [K230_DEV_CLINT] =        { 0xF0400000, 0x00400000 },
>> +};
>> +
>> +static void k230_soc_init(Object *obj)
>> +{
>> +    K230SoCState *s = RISCV_K230_SOC(obj);
>> +    RISCVHartArrayState *cpu0 = &s->c908_cpu;
>> +
>> +    object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
>> +    qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
>> +    qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
>> +    qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
>> +                         memmap[K230_DEV_BOOTROM].base);
>> +}
>> +
>> +static DeviceState *k230_create_plic(int base_hartid, int hartid_count)
>> +{
>> +    g_autofree char *plic_hart_config = NULL;
>> +
>> +    /* Per-socket PLIC hart topology configuration string */
>> +    plic_hart_config = riscv_plic_hart_config_string(hartid_count);
>> +
>> +    /* Per-socket PLIC */
>> +    return sifive_plic_create(memmap[K230_DEV_PLIC].base,
>> +                              plic_hart_config, hartid_count, base_hartid,
>> +                              K230_PLIC_NUM_SOURCES,
>> +                              K230_PLIC_NUM_PRIORITIES,
>> +                              K230_PLIC_PRIORITY_BASE, K230_PLIC_PENDING_BASE,
>> +                              K230_PLIC_ENABLE_BASE, K230_PLIC_ENABLE_STRIDE,
>> +                              K230_PLIC_CONTEXT_BASE,
>> +                              K230_PLIC_CONTEXT_STRIDE,
>> +                              memmap[K230_DEV_PLIC].size);
>> +}
>> +
>> +static void k230_soc_realize(DeviceState *dev, Error **errp)
>> +{
>> +    K230SoCState *s = RISCV_K230_SOC(dev);
>> +    MemoryRegion *sys_mem = get_system_memory();
>> +    int c908_cpus;
>> +
>> +    sysbus_realize(SYS_BUS_DEVICE(&s->c908_cpu), &error_fatal);
>> +
>> +    c908_cpus = s->c908_cpu.num_harts;
>> +
>> +    /* SRAM */
>> +    memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
>> +                           memmap[K230_DEV_SRAM].size, &error_fatal);
>> +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
>> +                                &s->sram);
>> +
>> +    /* BootROM */
>> +    memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
>> +                           memmap[K230_DEV_BOOTROM].size, &error_fatal);
>> +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_BOOTROM].base,
>> +                                &s->bootrom);
>> +
>> +    /* PLIC */
>> +    s->c908_plic = k230_create_plic(C908_CPU_HARTID, c908_cpus);
>> +
>> +    /* CLINT */
>> +    riscv_aclint_swi_create(memmap[K230_DEV_CLINT].base,
>> +                            C908_CPU_HARTID, c908_cpus, false);
>> +    riscv_aclint_mtimer_create(memmap[K230_DEV_CLINT].base + 0x4000,
>> +                               RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
>> +                               C908_CPU_HARTID, c908_cpus,
>> +                               RISCV_ACLINT_DEFAULT_MTIMECMP,
>> +                               RISCV_ACLINT_DEFAULT_MTIME,
>> +                               RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
>> +
>> +    /* UART */
>> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART0].base, 2,
>> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART0_IRQ),
>> +                   399193, serial_hd(0), DEVICE_LITTLE_ENDIAN);
>> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART1].base, 2,
>> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART1_IRQ),
>> +                   399193, serial_hd(1), DEVICE_LITTLE_ENDIAN);
>> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART2].base, 2,
>> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART2_IRQ),
>> +                   399193, serial_hd(2), DEVICE_LITTLE_ENDIAN);
>> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART3].base, 2,
>> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART3_IRQ),
>> +                   399193, serial_hd(3), DEVICE_LITTLE_ENDIAN);
>> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART4].base, 2,
>> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART4_IRQ),
>> +                   399193, serial_hd(4), DEVICE_LITTLE_ENDIAN);
>> +
>> +    /* unimplemented devices */
>> +    create_unimplemented_device("kpu.l2-cache",
>> +                                memmap[K230_DEV_KPU_L2_CACHE].base,
>> +                                memmap[K230_DEV_KPU_L2_CACHE].size);
>> +
>> +    create_unimplemented_device("kpu_cfg", memmap[K230_DEV_KPU_CFG].base,
>> +                                memmap[K230_DEV_KPU_CFG].size);
>> +
>> +    create_unimplemented_device("fft", memmap[K230_DEV_FFT].base,
>> +                                memmap[K230_DEV_FFT].size);
>> +
>> +    create_unimplemented_device("2d-engine.ai",
>> +                                memmap[K230_DEV_AI_2D_ENGINE].base,
>> +                                memmap[K230_DEV_AI_2D_ENGINE].size);
>> +
>> +    create_unimplemented_device("gsdma", memmap[K230_DEV_GSDMA].base,
>> +                                memmap[K230_DEV_GSDMA].size);
>> +
>> +    create_unimplemented_device("dma", memmap[K230_DEV_DMA].base,
>> +                                memmap[K230_DEV_DMA].size);
>> +
>> +    create_unimplemented_device("decomp-gzip",
>> +                                memmap[K230_DEV_DECOMP_GZIP].base,
>> +                                memmap[K230_DEV_DECOMP_GZIP].size);
>> +
>> +    create_unimplemented_device("2d-engine.non-ai",
>> +                                memmap[K230_DEV_NON_AI_2D].base,
>> +                                memmap[K230_DEV_NON_AI_2D].size);
>> +
>> +    create_unimplemented_device("isp", memmap[K230_DEV_ISP].base,
>> +                                memmap[K230_DEV_ISP].size);
>> +
>> +    create_unimplemented_device("dewarp", memmap[K230_DEV_DEWARP].base,
>> +                                memmap[K230_DEV_DEWARP].size);
>> +
>> +    create_unimplemented_device("rx-csi", memmap[K230_DEV_RX_CSI].base,
>> +                                memmap[K230_DEV_RX_CSI].size);
>> +
>> +    create_unimplemented_device("vpu", memmap[K230_DEV_H264].base,
>> +                                memmap[K230_DEV_H264].size);
>> +
>> +    create_unimplemented_device("gpu", memmap[K230_DEV_2P5D].base,
>> +                                memmap[K230_DEV_2P5D].size);
>> +
>> +    create_unimplemented_device("vo", memmap[K230_DEV_VO].base,
>> +                                memmap[K230_DEV_VO].size);
>> +
>> +    create_unimplemented_device("vo_cfg", memmap[K230_DEV_VO_CFG].base,
>> +                                memmap[K230_DEV_VO_CFG].size);
>> +
>> +    create_unimplemented_device("3d-engine", memmap[K230_DEV_3D_ENGINE].base,
>> +                                memmap[K230_DEV_3D_ENGINE].size);
>> +
>> +    create_unimplemented_device("pmu", memmap[K230_DEV_PMU].base,
>> +                                memmap[K230_DEV_PMU].size);
>> +
>> +    create_unimplemented_device("rtc", memmap[K230_DEV_RTC].base,
>> +                                memmap[K230_DEV_RTC].size);
>> +
>> +    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);
>> +
>> +    create_unimplemented_device("pwr", memmap[K230_DEV_PWR].base,
>> +                                memmap[K230_DEV_PWR].size);
>> +
>> +    create_unimplemented_device("ipcm", memmap[K230_DEV_MAILBOX].base,
>> +                                memmap[K230_DEV_MAILBOX].size);
>> +
>> +    create_unimplemented_device("iomux", memmap[K230_DEV_IOMUX].base,
>> +                                memmap[K230_DEV_IOMUX].size);
>> +
>> +    create_unimplemented_device("timer", memmap[K230_DEV_TIMER].base,
>> +                                memmap[K230_DEV_TIMER].size);
>> +
>> +    create_unimplemented_device("wdt0", memmap[K230_DEV_WDT0].base,
>> +                                memmap[K230_DEV_WDT0].size);
>> +
>> +    create_unimplemented_device("wdt1", memmap[K230_DEV_WDT1].base,
>> +                                memmap[K230_DEV_WDT1].size);
>> +
>> +    create_unimplemented_device("ts", memmap[K230_DEV_TS].base,
>> +                                memmap[K230_DEV_TS].size);
>> +
>> +    create_unimplemented_device("hdi", memmap[K230_DEV_HDI].base,
>> +                                memmap[K230_DEV_HDI].size);
>> +
>> +    create_unimplemented_device("stc", memmap[K230_DEV_STC].base,
>> +                                memmap[K230_DEV_STC].size);
>> +
>> +    create_unimplemented_device("security", memmap[K230_DEV_SECURITY].base,
>> +                                memmap[K230_DEV_SECURITY].size);
>> +
>> +    create_unimplemented_device("i2c0", memmap[K230_DEV_I2C0].base,
>> +                                memmap[K230_DEV_I2C0].size);
>> +
>> +    create_unimplemented_device("i2c1", memmap[K230_DEV_I2C1].base,
>> +                                memmap[K230_DEV_I2C1].size);
>> +
>> +    create_unimplemented_device("i2c2", memmap[K230_DEV_I2C2].base,
>> +                                memmap[K230_DEV_I2C2].size);
>> +
>> +    create_unimplemented_device("i2c3", memmap[K230_DEV_I2C3].base,
>> +                                memmap[K230_DEV_I2C3].size);
>> +
>> +    create_unimplemented_device("i2c4", memmap[K230_DEV_I2C4].base,
>> +                                memmap[K230_DEV_I2C4].size);
>> +
>> +    create_unimplemented_device("pwm", memmap[K230_DEV_PWM].base,
>> +                                memmap[K230_DEV_PWM].size);
>> +
>> +    create_unimplemented_device("gpio0", memmap[K230_DEV_GPIO0].base,
>> +                                memmap[K230_DEV_GPIO0].size);
>> +
>> +    create_unimplemented_device("gpio1", memmap[K230_DEV_GPIO1].base,
>> +                                memmap[K230_DEV_GPIO1].size);
>> +
>> +    create_unimplemented_device("adc", memmap[K230_DEV_ADC].base,
>> +                                memmap[K230_DEV_ADC].size);
>> +
>> +    create_unimplemented_device("codec", memmap[K230_DEV_CODEC].base,
>> +                                memmap[K230_DEV_CODEC].size);
>> +
>> +    create_unimplemented_device("i2s", memmap[K230_DEV_I2S].base,
>> +                                memmap[K230_DEV_I2S].size);
>> +
>> +    create_unimplemented_device("usb0", memmap[K230_DEV_USB0].base,
>> +                                memmap[K230_DEV_USB0].size);
>> +
>> +    create_unimplemented_device("usb1", memmap[K230_DEV_USB1].base,
>> +                                memmap[K230_DEV_USB1].size);
>> +
>> +    create_unimplemented_device("sd0", memmap[K230_DEV_SD0].base,
>> +                                memmap[K230_DEV_SD0].size);
>> +
>> +    create_unimplemented_device("sd1", memmap[K230_DEV_SD1].base,
>> +                                memmap[K230_DEV_SD1].size);
>> +
>> +    create_unimplemented_device("qspi0", memmap[K230_DEV_QSPI0].base,
>> +                                memmap[K230_DEV_QSPI0].size);
>> +
>> +    create_unimplemented_device("qspi1", memmap[K230_DEV_QSPI1].base,
>> +                                memmap[K230_DEV_QSPI1].size);
>> +
>> +    create_unimplemented_device("spi", memmap[K230_DEV_SPI].base,
>> +                                memmap[K230_DEV_SPI].size);
>> +
>> +    create_unimplemented_device("hi_sys_cfg", memmap[K230_DEV_HI_SYS_CFG].base,
>> +                                memmap[K230_DEV_HI_SYS_CFG].size);
>> +
>> +    create_unimplemented_device("ddrc_cfg", memmap[K230_DEV_DDRC_CFG].base,
>> +                                memmap[K230_DEV_DDRC_CFG].size);
>> +
>> +    create_unimplemented_device("flash", memmap[K230_DEV_FLASH].base,
>> +                                memmap[K230_DEV_FLASH].size);
>> +}
>> +
>> +static void k230_soc_class_init(ObjectClass *oc, const void *data)
>> +{
>> +    DeviceClass *dc = DEVICE_CLASS(oc);
>> +
>> +    dc->realize = k230_soc_realize;
>> +}
>> +
>> +static const TypeInfo k230_soc_type_info = {
>> +    .name = TYPE_RISCV_K230_SOC,
>> +    .parent = TYPE_DEVICE,
>> +    .instance_size = sizeof(K230SoCState),
>> +    .instance_init = k230_soc_init,
>> +    .class_init = k230_soc_class_init,
>> +};
>> +
>> +static void k230_soc_register_types(void)
>> +{
>> +    type_register_static(&k230_soc_type_info);
>> +}
>> +
>> +type_init(k230_soc_register_types)
>> +
>> +static void k230_machine_done(Notifier *notifier, void *data)
>> +{
>> +    K230MachineState *s = container_of(notifier, K230MachineState,
>> +                                     machine_done);
>> +    MachineState *machine = MACHINE(s);
>> +    hwaddr start_addr = memmap[K230_DEV_DDRC].base;
>> +    target_ulong firmware_end_addr, kernel_start_addr;
>> +    const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
>> +    uint64_t kernel_entry = 0;
>> +    RISCVBootInfo boot_info;
>> +
>> +    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
>> +                                                     &start_addr, NULL);
>> +
>> +    /* Mask ROM reset vector */
>> +    uint32_t reset_vec[] = {
>> +        /* 0x91200000: auipc  t0, 0x0              */ 0x00000297,
>> +        /* 0x91200004: addi   t0, t0, 36 # <trap>  */ 0x02428293,
>> +        /* 0x91200008: csrw   mtvec, t0            */ 0x30529073,
>> +        /* 0x9120000C: csrr   a0, misa             */ 0x301012F3,
>> +        /* 0x91200010: lui    t0, 0x1              */ 0x000012B7,
>> +        /* 0x91200014: slli   t0, t0, 1            */ 0x00129293,
>> +        /* 0x91200018: and    t0, a0, t0           */ 0x005572B3,
>> +        /* 0x9120001C: bnez   t0, loop             */ 0x00511063,
>> +        /* entry:                                  */
>> +        /* 0x91200020: addiw  t0, zero, 1          */ 0x0010029b,
>> +        /* 0x91200024: slli   t0, t0, 0x1b         */ 0x01b29293,
>> +        /* 0x91200028: jr     t0 # uboot 0x8000000 */ 0x00028067,
>> +        /* loop:                                   */
>> +        /* 0x9120002C: j      0x9120002C # <loop>  */ 0x0000006f,
>> +        /* trap:                                   */
>> +        /* 0x91200030: j      0x91200030 # <trap>  */ 0x0000006f,
>> +    };
>> +
>> +    /* copy in the reset vector in little_endian byte order */
>> +    for (int i = 0; i < sizeof(reset_vec) >> 2; i++) {
>> +        reset_vec[i] = cpu_to_le32(reset_vec[i]);
>> +    }
>> +    rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
>> +                          memmap[K230_DEV_BOOTROM].base, &address_space_memory);
>> +
>> +    riscv_boot_info_init(&boot_info, &s->soc.c908_cpu);
>> +
>> +    if (machine->kernel_filename && !kernel_entry) {
>> +        kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
>> +                                                         firmware_end_addr);
>> +        riscv_load_kernel(machine, &boot_info, kernel_start_addr,
>> +                          true, NULL);
>> +        kernel_entry = boot_info.image_low_addr;
>> +    }
>> +}
>> +
>> +static void k230_machine_init(MachineState *machine)
>> +{
>> +    MachineClass *mc = MACHINE_GET_CLASS(machine);
>> +
>> +    K230MachineState *s = RISCV_K230_MACHINE(machine);
>> +    MemoryRegion *sys_mem = get_system_memory();
>> +
>> +    if (machine->ram_size < mc->default_ram_size) {
>> +        char *sz = size_to_str(mc->default_ram_size);
>> +        error_report("Invalid RAM size, should be %s", sz);
>> +        g_free(sz);
>> +        exit(EXIT_FAILURE);
>> +    }
>> +
>> +    /* Initialize SoC */
>> +    object_initialize_child(OBJECT(machine), "soc", &s->soc,
>> +                            TYPE_RISCV_K230_SOC);
>> +    qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
>> +
>> +    /* Data Memory */
>> +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_DDRC].base,
>> +                                machine->ram);
>> +
>> +    s->machine_done.notify = k230_machine_done;
>> +    qemu_add_machine_init_done_notifier(&s->machine_done);
>> +}
>> +
>> +static void k230_machine_instance_init(Object *obj)
>> +{
>> +}
>> +
>> +static void k230_machine_class_init(ObjectClass *oc, const void *data)
>> +{
>> +    MachineClass *mc = MACHINE_CLASS(oc);
>> +
>> +    mc->desc = "RISC-V Board compatible with Kendryte K230 SDK";
>> +    mc->init = k230_machine_init;
>> +    mc->default_cpus = 2;
>> +    mc->default_ram_id = "riscv.K230.ram"; /* DDR */
>> +    mc->default_ram_size = memmap[K230_DEV_DDRC].size;
>> +}
>> +
>> +static const TypeInfo k230_machine_typeinfo = {
>> +    .name       = TYPE_RISCV_K230_MACHINE,
>> +    .parent     = TYPE_MACHINE,
>> +    .class_init = k230_machine_class_init,
>> +    .instance_init = k230_machine_instance_init,
>> +    .instance_size = sizeof(K230MachineState),
>> +};
>> +
>> +static void k230_machine_init_register_types(void)
>> +{
>> +    type_register_static(&k230_machine_typeinfo);
>> +}
>> +
>> +type_init(k230_machine_init_register_types)
>> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
>> index 2a8d5b136c..1e5ce511d4 100644
>> --- a/hw/riscv/meson.build
>> +++ b/hw/riscv/meson.build
>> @@ -14,5 +14,5 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
>>       'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-
>> hpm.c'))
>>   riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-
>> generic.c'))
>>   riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true:
>> files('xiangshan_kmh.c'))
>> -
>> +riscv_ss.add(when: 'CONFIG_K230', if_true: files('k230.c'))
>>   hw_arch += {'riscv': riscv_ss}
>> diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
>> new file mode 100644
>> index 0000000000..3158381e8f
>> --- /dev/null
>> +++ b/include/hw/riscv/k230.h
>> @@ -0,0 +1,149 @@
>> +/*
>> + * QEMU RISC-V Virt Board Compatible with kendryte K230 SDK
>> + *
>> + * Copyright (c) 2025 Chao Liu <chao.liu@zevorn.cn>
>> + * SPDX-License-Identifier: GPL-2.0-or-later
>> + *
>> + * Provides a board compatible with the kendryte K230 SDK
>> + *
>> + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
>> + *
>> + * For more information, see <https://www.kendryte.com/en/proDetail/230>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms and conditions of the GNU General Public License,
>> + * version 2 or later, as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +#ifndef HW_K230_H
>> +#define HW_K230_H
>> +
>> +#include "hw/boards.h"
>> +#include "hw/riscv/riscv_hart.h"
>> +
>> +#define C908_CPU_HARTID   (0)
>> +
>> +#define TYPE_RISCV_K230_SOC "riscv.k230.soc"
>> +#define RISCV_K230_SOC(obj) \
>> +    OBJECT_CHECK(K230SoCState, (obj), TYPE_RISCV_K230_SOC)
>> +
>> +typedef struct K230SoCState {
>> +    /*< private >*/
>> +    DeviceState parent_obj;
>> +
>> +    /*< public >*/
>> +    RISCVHartArrayState c908_cpu; /* Small core */
>> +
>> +    MemoryRegion sram;
>> +    MemoryRegion bootrom;
>> +
>> +    DeviceState *c908_plic;
>> +} K230SoCState;
>> +
>> +#define TYPE_RISCV_K230_MACHINE MACHINE_TYPE_NAME("k230")
>> +#define RISCV_K230_MACHINE(obj) \
>> +    OBJECT_CHECK(K230MachineState, (obj), TYPE_RISCV_K230_MACHINE)
>> +
>> +typedef struct K230MachineState {
>> +    /*< private >*/
>> +    MachineState parent_obj;
>> +
>> +    /*< public >*/
>> +    K230SoCState soc;
>> +    Notifier machine_done;
>> +} K230MachineState;
>> +
>> +enum {
>> +    K230_DEV_DDRC,
>> +    K230_DEV_KPU_L2_CACHE,
>> +    K230_DEV_SRAM,
>> +    K230_DEV_KPU_CFG,
>> +    K230_DEV_FFT,
>> +    K230_DEV_AI_2D_ENGINE,
>> +    K230_DEV_GSDMA,
>> +    K230_DEV_DMA,
>> +    K230_DEV_DECOMP_GZIP,
>> +    K230_DEV_NON_AI_2D,
>> +    K230_DEV_ISP,
>> +    K230_DEV_DEWARP,
>> +    K230_DEV_RX_CSI,
>> +    K230_DEV_H264,
>> +    K230_DEV_2P5D,
>> +    K230_DEV_VO,
>> +    K230_DEV_VO_CFG,
>> +    K230_DEV_3D_ENGINE,
>> +    K230_DEV_PMU,
>> +    K230_DEV_RTC,
>> +    K230_DEV_CMU,
>> +    K230_DEV_RMU,
>> +    K230_DEV_BOOT,
>> +    K230_DEV_PWR,
>> +    K230_DEV_MAILBOX,
>> +    K230_DEV_IOMUX,
>> +    K230_DEV_TIMER,
>> +    K230_DEV_WDT0,
>> +    K230_DEV_WDT1,
>> +    K230_DEV_TS,
>> +    K230_DEV_HDI,
>> +    K230_DEV_STC,
>> +    K230_DEV_BOOTROM,
>> +    K230_DEV_SECURITY,
>> +    K230_DEV_UART0,
>> +    K230_DEV_UART1,
>> +    K230_DEV_UART2,
>> +    K230_DEV_UART3,
>> +    K230_DEV_UART4,
>> +    K230_DEV_I2C0,
>> +    K230_DEV_I2C1,
>> +    K230_DEV_I2C2,
>> +    K230_DEV_I2C3,
>> +    K230_DEV_I2C4,
>> +    K230_DEV_PWM,
>> +    K230_DEV_GPIO0,
>> +    K230_DEV_GPIO1,
>> +    K230_DEV_ADC,
>> +    K230_DEV_CODEC,
>> +    K230_DEV_I2S,
>> +    K230_DEV_USB0,
>> +    K230_DEV_USB1,
>> +    K230_DEV_SD0,
>> +    K230_DEV_SD1,
>> +    K230_DEV_QSPI0,
>> +    K230_DEV_QSPI1,
>> +    K230_DEV_SPI,
>> +    K230_DEV_HI_SYS_CFG,
>> +    K230_DEV_DDRC_CFG,
>> +    K230_DEV_FLASH,
>> +    K230_DEV_PLIC,
>> +    K230_DEV_CLINT,
>> +};
>> +
>> +enum {
>> +    K230_UART0_IRQ  = 16,
>> +    K230_UART1_IRQ  = 17,
>> +    K230_UART2_IRQ  = 18,
>> +    K230_UART3_IRQ  = 19,
>> +    K230_UART4_IRQ  = 20,
>> +};
>> +
>> +/*
>> + * Integrates with the interrupt controller (PLIC),
>> + * which can process 208 interrupt external sources
>> + */
>> +#define K230_PLIC_NUM_SOURCES 208
>> +#define K230_PLIC_NUM_PRIORITIES 7
>> +#define K230_PLIC_PRIORITY_BASE 0x00
>> +#define K230_PLIC_PENDING_BASE 0x1000
>> +#define K230_PLIC_ENABLE_BASE 0x2000
>> +#define K230_PLIC_ENABLE_STRIDE 0x80
>> +#define K230_PLIC_CONTEXT_BASE 0x200000
>> +#define K230_PLIC_CONTEXT_STRIDE 0x1000
>> +
>> +#endif
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/5] target/riscv: add thead-c908 cpu support
  2025-12-03 17:13     ` Conor Dooley
@ 2025-12-04  2:59       ` Chao Liu
  0 siblings, 0 replies; 16+ messages in thread
From: Chao Liu @ 2025-12-04  2:59 UTC (permalink / raw)
  To: Conor Dooley, Chao Liu
  Cc: richard.henderson, paolo.savini, npiggin, ebiggers, dbarboza,
	palmer, alistair.francis, liwei1518, zhiwei_liu, qemu-riscv,
	qemu-devel, hust-os-kernel-patches

On 12/4/2025 1:13 AM, Conor Dooley wrote:
> On Wed, Dec 03, 2025 at 05:12:37PM +0000, Conor Dooley wrote:
>> On Sun, Nov 30, 2025 at 05:21:06PM +0800, Chao Liu wrote:
>>> The C908 processor is based on the RV64GCB[V] instruction
>>> set, compatible to RVA22 Profile and implements the XIE
>>> (XuanTie Instruction Extension) technology.
>>>
>>> Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
>>> Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
>>> ---
>>>  target/riscv/cpu-qom.h |   2 +
>>>  target/riscv/cpu.c     |  43 +++++
>>>  target/riscv/th_csr.c  | 380 ++++++++++++++++++++++++++++++++++++++++-
>>>  3 files changed, 424 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
>>> index 75f4e43408..1ddb5a6a6c 100644
>>> --- a/target/riscv/cpu-qom.h
>>> +++ b/target/riscv/cpu-qom.h
>>> @@ -52,6 +52,8 @@
>>>  #define TYPE_RISCV_CPU_SIFIVE_U34       RISCV_CPU_TYPE_NAME("sifive-u34")
>>>  #define TYPE_RISCV_CPU_SIFIVE_U54       RISCV_CPU_TYPE_NAME("sifive-u54")
>>>  #define TYPE_RISCV_CPU_THEAD_C906       RISCV_CPU_TYPE_NAME("thead-c906")
>>> +#define TYPE_RISCV_CPU_THEAD_C908       RISCV_CPU_TYPE_NAME("thead-c908")
>>> +#define TYPE_RISCV_CPU_THEAD_C908V      RISCV_CPU_TYPE_NAME("thead-c908v")
>>>  #define TYPE_RISCV_CPU_VEYRON_V1        RISCV_CPU_TYPE_NAME("veyron-v1")
>>>  #define TYPE_RISCV_CPU_TT_ASCALON       RISCV_CPU_TYPE_NAME("tt-ascalon")
>>>  #define TYPE_RISCV_CPU_XIANGSHAN_NANHU  RISCV_CPU_TYPE_NAME("xiangshan-nanhu")
>>> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
>>> index d055ddf462..202ff130ee 100644
>>> --- a/target/riscv/cpu.c
>>> +++ b/target/riscv/cpu.c
>>> @@ -3091,6 +3091,49 @@ static const TypeInfo riscv_cpu_type_infos[] = {
>>>  #endif
>>>      ),
>>>  
>>> +    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908, TYPE_RISCV_VENDOR_CPU,
>>> +        .misa_mxl_max = MXL_RV64,
>>> +        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU,
>>> +        .priv_spec = PRIV_VERSION_1_12_0,
>>> +
>>> +        /* ISA extensions */
>>> +        .cfg.ext_xtheadba = true,
>>> +        .cfg.ext_xtheadbb = true,
>>> +        .cfg.ext_xtheadbs = true,
>>> +        .cfg.ext_xtheadcmo = true,
>>> +        .cfg.ext_xtheadcondmov = true,
>>> +        .cfg.ext_xtheadmac = true,
>>> +        .cfg.ext_xtheadmemidx = true,
>>> +        .cfg.ext_xtheadmempair = true,
>>> +        .cfg.ext_xtheadsync = true,
>>> +        .cfg.ext_zba = true,
>>> +        .cfg.ext_zbb = true,
>>> +        .cfg.ext_zbc = true,
>>> +        .cfg.ext_zbs = true,
>>> +        .cfg.ext_zkt = true,
>>> +        .cfg.ext_zbkc = true,
>>> +        .cfg.ext_zicsr = true,
>>> +        .cfg.ext_zifencei = true,
>>> +        .cfg.ext_zihintpause = true,
>>> +        .cfg.ext_zicbom = true,
>>> +        .cfg.ext_zicboz = true,
>>> +        .cfg.ext_zfh = true,
>>> +        .cfg.ext_xtheadfmv = true,
>>> +        .cfg.ext_xtheadfmemidx = true,
>>> +        .cfg.pmp = true,
>>
>> I think Svpbmt is missing here, both it and the T-Head MAEE stuff are
>> supported on the k230. What I will end up merging into mainline for the
> 
> Whoops, should have specified that I meant the mainline linux kernel.
> 
You're right, I will enable the Svpbmt extension in PATCH v2.

Thanks,
Chao
>> k230 uses Svpbmt instead of MAEE.
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 5/5] docs/system/riscv: add documentation for k230 machine
  2025-12-03 17:19   ` Daniel Henrique Barboza
@ 2025-12-04  3:03     ` Chao Liu
  0 siblings, 0 replies; 16+ messages in thread
From: Chao Liu @ 2025-12-04  3:03 UTC (permalink / raw)
  To: Daniel Henrique Barboza, Chao Liu, richard.henderson,
	paolo.savini, npiggin, ebiggers, palmer, alistair.francis,
	liwei1518, zhiwei_liu
  Cc: qemu-riscv, qemu-devel, hust-os-kernel-patches

On 12/4/2025 1:19 AM, Daniel Henrique Barboza wrote:
> Hi,
> 
> This patch won't build in my env:
> 
> [3031/3032] Generating docs/QEMU manual with a custom command
> FAILED: docs/docs.stamp
> /usr/bin/env CONFDIR=etc/qemu /home/danielhb/work/qemu/build/pyvenv/bin/sphinx-
> build -q -W -Dkerneldoc_werror=1 -j auto -Dversion=10.1.92 -Drelease= -
> Ddepfile=docs/docs.d -Ddepfile_stamp=docs/docs.stamp -b html -d /home/danielhb/
> work/qemu/build/docs/manual.p /home/danielhb/work/qemu/docs /home/danielhb/work/
> qemu/build/docs/manual
> /home/danielhb/work/qemu/docs/system/riscv/k230.rst: WARNING: document isn't
> included in any toctree
> ninja: build stopped: subcommand failed.
> 
> 
> 
> This diff fixes it:
> 
> 
> $ git diff
> diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
> index 89b2cb732c..2103ff6173 100644
> --- a/docs/system/target-riscv.rst
> +++ b/docs/system/target-riscv.rst
> @@ -66,6 +66,7 @@ undocumented; you can get a complete list by running
>  .. toctree::
>     :maxdepth: 1
>  
> +   riscv/k230
>     riscv/microblaze-v-generic
>     riscv/microchip-icicle-kit
>     riscv/shakti-c
> 
Nice :)

Thanks, Daniel, for fixing this issue. I will apply this bugfix in PATCH v2.

Chao
> 
> 
> Thanks,
> 
> Daniel
> 
> 
> On 11/30/25 6:21 AM, Chao Liu wrote:
>> Add documentation for k230 virt reference platform.
>>
>> Signed-off-by: Chao Liu <chao.liu@zevorn.cn>
>> ---
>>   docs/system/riscv/k230.rst | 48 ++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 48 insertions(+)
>>   create mode 100644 docs/system/riscv/k230.rst
>>
>> diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
>> new file mode 100644
>> index 0000000000..3e6ca295df
>> --- /dev/null
>> +++ b/docs/system/riscv/k230.rst
>> @@ -0,0 +1,48 @@
>> +Kendryte K230 virt reference platform (``k230``)
>> +==========================================================================
>> +The ``k230`` machine is compatible with with Kendryte K230 SDK.
>> +
>> +The K230 is a chip from the AIoT SoC series made by Kendryte ® — a part of
>> +Canaan Inc. It uses a brand-new multi-heterogeneous unit accelerated computing
>> +structure.
>> +
>> +This chip has 2 RISC-V computing cores and a new-generation KPU (Knowledge
>> +Process Unit) smart computing unit.
>> +
>> +It has multi-precision AI computing ability, works with many common AI computing
>> +frameworks, and for some typical networks, its usage rate is over 70%. Besides,
>> +the K230 chip supports many peripheral connections and has several special
>> +hardware acceleration units (like 2D and 2.5D accelerators). It can speed up
>> +different tasks (such as image processing, video processing, audio processing
>> +and AI computing). It also has many good features: low delay, high performance,
>> +low power use and fast start-up.
>> +
>> +For more information, see <https://www.kendryte.com/en/proDetail/230>
>> +
>> +Supported devices
>> +-----------------
>> +The ``k230`` machine supports the following devices:
>> +
>> +* 1 c908 cores
>> +* Core Local Interruptor (CLINT)
>> +* Incoming MSI Controller (IMSIC)
>> +* 2 K230 Watchdog Timer
>> +* 4 UART
>> +
>> +Boot options
>> +------------
>> +The ``k230`` machine can start using the standard ``-bios``
>> +functionality for loading the boot image. You need to compile and link
>> +the firmware, kernel, and Device Tree (FDT) into a single binary file with
>> +K230 SDK(k230_canmv_defconfig), such as ``uboot``.
>> +
>> +Running
>> +-------
>> +Below is an example command line for running the ``k230``
>> +machine:
>> +
>> +.. code-block:: bash
>> +
>> +   $ qemu-system-riscv64 -machine k230 \
>> +      -bios k230_sdk/output/k230_canmv_defconfig/little/uboot/u-boot \
>> +      -nographic
>


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2025-12-04  3:04 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-30  9:21 [PATCH v1 0/5] Add K230 board and thead-c908 CPU support Chao Liu
2025-11-30  9:21 ` [PATCH v1 1/5] target/riscv: add thead-c908 cpu support Chao Liu
2025-12-03 16:33   ` Daniel Henrique Barboza
2025-12-03 17:12   ` Conor Dooley
2025-12-03 17:13     ` Conor Dooley
2025-12-04  2:59       ` Chao Liu
2025-11-30  9:21 ` [PATCH v1 2/5] hw/riscv: add k230 board initial support Chao Liu
2025-12-03 17:02   ` Daniel Henrique Barboza
2025-12-04  1:12     ` Chao Liu
2025-11-30  9:21 ` [PATCH v1 3/5] hw/watchdog: add k230 watchdog " Chao Liu
2025-12-03 17:07   ` Daniel Henrique Barboza
2025-11-30  9:21 ` [PATCH v1 4/5] tests/qtest: add test for K230 watchdog Chao Liu
2025-12-03 17:08   ` Daniel Henrique Barboza
2025-11-30  9:21 ` [PATCH v1 5/5] docs/system/riscv: add documentation for k230 machine Chao Liu
2025-12-03 17:19   ` Daniel Henrique Barboza
2025-12-04  3:03     ` Chao Liu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).