@samitouri / QOSamiQemu / commits / 6cf0d08c39

hw/riscv: add k230 board initial support

K230 Board compatible with Kendryte K230 SDK. Preliminarily supports the C908 small core, which can run U-Boot and Linux kernels compiled by the K230 SDK. The K230 boot flow provides its device tree from firmware or software. QEMU does not generate a K230 DTB; users can pass one with -dtb for direct Linux boot, or rely on firmware/kernel built-in DTB for other payloads. Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com> Tested-by: Peng Jiang <3160104094@zju.edu.cn> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Message-ID: <a161697a249b896e44e2748435f6c0caec12c9f4.1781246408.git.chao.liu@processmission.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Chao Liu committed Jun 12, 2026 at 15:04 UTC 6cf0d08c3953ee447cb215edc3a384834cbe48db
5 files changed +671 -1
MAINTAINERS
+7
@@ -1786,6 +1786,13 @@ F: docs/system/riscv/xiangshan-kunminghu.rst
1786 F: hw/riscv/xiangshan_kmh.c
1787 F: include/hw/riscv/xiangshan_kmh.h
1788
1789 +K230 Machines
1790 +M: Chao Liu <chao.liu.zevorn@gmail.com>
1791 +L: qemu-riscv@nongnu.org
1792 +S: Maintained
1793 +F: hw/riscv/k230.c
1794 +F: include/hw/riscv/k230.h
1795 +
1796 RX Machines
1797 -----------
1798 rx-gdbsim
hw/riscv/Kconfig
+10
@@ -138,3 +138,13 @@ config MIPS_BOSTON_AIA
138 select RISCV_MIPS_CMGCR
139 select RISCV_MIPS_CPC
140 select RISCV_MIPS_CPS
141 +
142 +config K230
143 + bool
144 + default y
145 + depends on RISCV64
146 + select RISCV_ACLINT
147 + select RISCV_APLIC
148 + select RISCV_IMSIC
149 + select SERIAL_MM
150 + select UNIMP
hw/riscv/k230.c new
+508
@@ -0,0 +1,508 @@
1 +/*
2 + * QEMU RISC-V Virt Board Compatible with Kendryte K230 SDK
3 + *
4 + * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
5 + *
6 + * SPDX-License-Identifier: GPL-2.0-or-later
7 + *
8 + * Provides a board compatible with the Kendryte K230 SDK
9 + *
10 + * K230 Technical Reference Manual V0.3.1 (2024-11-18):
11 + * https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
12 + *
13 + * For more information, see <https://www.kendryte.com/en/proDetail/230>
14 + */
15 +
16 +#include "qemu/osdep.h"
17 +#include "cpu-qom.h"
18 +#include "qemu/cutils.h"
19 +#include "qemu/error-report.h"
20 +#include "qapi/error.h"
21 +#include "system/device_tree.h"
22 +#include "system/system.h"
23 +#include "system/memory.h"
24 +#include "target/riscv/cpu.h"
25 +#include "hw/core/loader.h"
26 +#include "hw/core/sysbus.h"
27 +#include "hw/riscv/k230.h"
28 +#include "hw/riscv/boot.h"
29 +#include "hw/riscv/machines-qom.h"
30 +#include "hw/intc/riscv_aclint.h"
31 +#include "hw/intc/sifive_plic.h"
32 +#include "hw/char/serial-mm.h"
33 +#include "hw/misc/unimp.h"
34 +
35 +/* Align K230_SDK k230_canmv_defconfig */
36 +#define K230_DIRECT_OPENSBI_ADDR 0x8000000
37 +#define K230_DIRECT_KERNEL_ADDR 0x8200000
38 +#define K230_DIRECT_DTB_ADDR 0xa000000
39 +
40 +static const MemMapEntry memmap[] = {
41 + [K230_DEV_DDRC] = { 0x00000000, 0x80000000 },
42 + [K230_DEV_KPU_L2_CACHE] = { 0x80000000, 0x00200000 },
43 + [K230_DEV_SRAM] = { 0x80200000, 0x00200000 },
44 + [K230_DEV_KPU_CFG] = { 0x80400000, 0x00000800 },
45 + [K230_DEV_FFT] = { 0x80400800, 0x00000400 },
46 + [K230_DEV_AI_2D_ENGINE] = { 0x80400C00, 0x00000800 },
47 + [K230_DEV_GSDMA] = { 0x80800000, 0x00004000 },
48 + [K230_DEV_DMA] = { 0x80804000, 0x00004000 },
49 + [K230_DEV_DECOMP_GZIP] = { 0x80808000, 0x00004000 },
50 + [K230_DEV_NON_AI_2D] = { 0x8080C000, 0x00004000 },
51 + [K230_DEV_ISP] = { 0x90000000, 0x00008000 },
52 + [K230_DEV_DEWARP] = { 0x90008000, 0x00001000 },
53 + [K230_DEV_RX_CSI] = { 0x90009000, 0x00002000 },
54 + [K230_DEV_H264] = { 0x90400000, 0x00010000 },
55 + [K230_DEV_2P5D] = { 0x90800000, 0x00040000 },
56 + [K230_DEV_VO] = { 0x90840000, 0x00010000 },
57 + [K230_DEV_VO_CFG] = { 0x90850000, 0x00001000 },
58 + [K230_DEV_3D_ENGINE] = { 0x90A00000, 0x00000800 },
59 + [K230_DEV_PMU] = { 0x91000000, 0x00000C00 },
60 + [K230_DEV_RTC] = { 0x91000C00, 0x00000400 },
61 + [K230_DEV_CMU] = { 0x91100000, 0x00001000 },
62 + [K230_DEV_RMU] = { 0x91101000, 0x00001000 },
63 + [K230_DEV_BOOT] = { 0x91102000, 0x00001000 },
64 + [K230_DEV_PWR] = { 0x91103000, 0x00001000 },
65 + [K230_DEV_MAILBOX] = { 0x91104000, 0x00001000 },
66 + [K230_DEV_IOMUX] = { 0x91105000, 0x00000800 },
67 + [K230_DEV_TIMER] = { 0x91105800, 0x00000800 },
68 + [K230_DEV_WDT0] = { 0x91106000, 0x00000800 },
69 + [K230_DEV_WDT1] = { 0x91106800, 0x00000800 },
70 + [K230_DEV_TS] = { 0x91107000, 0x00000800 },
71 + [K230_DEV_HDI] = { 0x91107800, 0x00000800 },
72 + [K230_DEV_STC] = { 0x91108000, 0x00000800 },
73 + [K230_DEV_BOOTROM] = { 0x91200000, 0x00010000 },
74 + [K230_DEV_SECURITY] = { 0x91210000, 0x00008000 },
75 + [K230_DEV_UART0] = { 0x91400000, 0x00001000 },
76 + [K230_DEV_UART1] = { 0x91401000, 0x00001000 },
77 + [K230_DEV_UART2] = { 0x91402000, 0x00001000 },
78 + [K230_DEV_UART3] = { 0x91403000, 0x00001000 },
79 + [K230_DEV_UART4] = { 0x91404000, 0x00001000 },
80 + [K230_DEV_I2C0] = { 0x91405000, 0x00001000 },
81 + [K230_DEV_I2C1] = { 0x91406000, 0x00001000 },
82 + [K230_DEV_I2C2] = { 0x91407000, 0x00001000 },
83 + [K230_DEV_I2C3] = { 0x91408000, 0x00001000 },
84 + [K230_DEV_I2C4] = { 0x91409000, 0x00001000 },
85 + [K230_DEV_PWM] = { 0x9140A000, 0x00001000 },
86 + [K230_DEV_GPIO0] = { 0x9140B000, 0x00001000 },
87 + [K230_DEV_GPIO1] = { 0x9140C000, 0x00001000 },
88 + [K230_DEV_ADC] = { 0x9140D000, 0x00001000 },
89 + [K230_DEV_CODEC] = { 0x9140E000, 0x00001000 },
90 + [K230_DEV_I2S] = { 0x9140F000, 0x00001000 },
91 + [K230_DEV_USB0] = { 0x91500000, 0x00010000 },
92 + [K230_DEV_USB1] = { 0x91540000, 0x00010000 },
93 + [K230_DEV_SD0] = { 0x91580000, 0x00001000 },
94 + [K230_DEV_SD1] = { 0x91581000, 0x00001000 },
95 + [K230_DEV_QSPI0] = { 0x91582000, 0x00001000 },
96 + [K230_DEV_QSPI1] = { 0x91583000, 0x00001000 },
97 + [K230_DEV_SPI] = { 0x91584000, 0x00001000 },
98 + [K230_DEV_HI_SYS_CFG] = { 0x91585000, 0x00000400 },
99 + [K230_DEV_DDRC_CFG] = { 0x98000000, 0x02000000 },
100 + [K230_DEV_FLASH] = { 0xC0000000, 0x08000000 },
101 + [K230_DEV_PLIC] = { 0xF00000000, 0x00400000 },
102 + [K230_DEV_CLINT] = { 0xF04000000, 0x00400000 },
103 +};
104 +
105 +static void k230_soc_init(Object *obj)
106 +{
107 + K230SoCState *s = RISCV_K230_SOC(obj);
108 + RISCVHartArrayState *cpu0 = &s->c908_cpu;
109 +
110 + object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
111 + qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
112 + qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
113 + qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
114 + memmap[K230_DEV_BOOTROM].base);
115 +}
116 +
117 +static DeviceState *k230_create_plic(int base_hartid, int hartid_count)
118 +{
119 + g_autofree char *plic_hart_config = NULL;
120 +
121 + /* Per-socket PLIC hart topology configuration string */
122 + plic_hart_config = riscv_plic_hart_config_string(hartid_count);
123 +
124 + /* Per-socket PLIC */
125 + return sifive_plic_create(memmap[K230_DEV_PLIC].base,
126 + plic_hart_config, hartid_count, base_hartid,
127 + K230_PLIC_NUM_SOURCES,
128 + K230_PLIC_NUM_PRIORITIES,
129 + K230_PLIC_PRIORITY_BASE, K230_PLIC_PENDING_BASE,
130 + K230_PLIC_ENABLE_BASE, K230_PLIC_ENABLE_STRIDE,
131 + K230_PLIC_CONTEXT_BASE,
132 + K230_PLIC_CONTEXT_STRIDE,
133 + memmap[K230_DEV_PLIC].size);
134 +}
135 +
136 +static void k230_create_uart(MemoryRegion *sys_mem, DeviceState *plic,
137 + int index)
138 +{
139 + int uart_dev = K230_DEV_UART0 + index;
140 + g_autofree char *name = g_strdup_printf("uart%d", index);
141 +
142 + /* Cover the non-16550 part of the SDK's 0x1000 UART window. */
143 + create_unimplemented_device(name, memmap[uart_dev].base,
144 + memmap[uart_dev].size);
145 +
146 + serial_mm_init(sys_mem, memmap[uart_dev].base, 2,
147 + qdev_get_gpio_in(plic, K230_UART0_IRQ + index),
148 + 399193, serial_hd(index), DEVICE_LITTLE_ENDIAN);
149 +}
150 +
151 +static void k230_soc_realize(DeviceState *dev, Error **errp)
152 +{
153 + K230SoCState *s = RISCV_K230_SOC(dev);
154 + MemoryRegion *sys_mem = get_system_memory();
155 + int c908_cpus;
156 +
157 + sysbus_realize(SYS_BUS_DEVICE(&s->c908_cpu), &error_fatal);
158 +
159 + c908_cpus = s->c908_cpu.num_harts;
160 +
161 + /* SRAM */
162 + memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
163 + memmap[K230_DEV_SRAM].size, &error_fatal);
164 + memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
165 + &s->sram);
166 +
167 + /* BootROM */
168 + memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
169 + memmap[K230_DEV_BOOTROM].size, &error_fatal);
170 + memory_region_add_subregion(sys_mem, memmap[K230_DEV_BOOTROM].base,
171 + &s->bootrom);
172 +
173 + /* PLIC */
174 + s->c908_plic = k230_create_plic(C908_CPU_HARTID, c908_cpus);
175 +
176 + /* CLINT */
177 + riscv_aclint_swi_create(memmap[K230_DEV_CLINT].base,
178 + C908_CPU_HARTID, c908_cpus, false);
179 + riscv_aclint_mtimer_create(memmap[K230_DEV_CLINT].base + 0x4000,
180 + RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
181 + C908_CPU_HARTID, c908_cpus,
182 + RISCV_ACLINT_DEFAULT_MTIMECMP,
183 + RISCV_ACLINT_DEFAULT_MTIME,
184 + RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
185 +
186 + /* UART */
187 + for (int i = 0; i < K230_UART_COUNT; i++) {
188 + k230_create_uart(sys_mem, DEVICE(s->c908_plic), i);
189 + }
190 +
191 + /* unimplemented devices */
192 + create_unimplemented_device("kpu.l2-cache",
193 + memmap[K230_DEV_KPU_L2_CACHE].base,
194 + memmap[K230_DEV_KPU_L2_CACHE].size);
195 +
196 + create_unimplemented_device("kpu_cfg", memmap[K230_DEV_KPU_CFG].base,
197 + memmap[K230_DEV_KPU_CFG].size);
198 +
199 + create_unimplemented_device("fft", memmap[K230_DEV_FFT].base,
200 + memmap[K230_DEV_FFT].size);
201 +
202 + create_unimplemented_device("2d-engine.ai",
203 + memmap[K230_DEV_AI_2D_ENGINE].base,
204 + memmap[K230_DEV_AI_2D_ENGINE].size);
205 +
206 + create_unimplemented_device("gsdma", memmap[K230_DEV_GSDMA].base,
207 + memmap[K230_DEV_GSDMA].size);
208 +
209 + create_unimplemented_device("dma", memmap[K230_DEV_DMA].base,
210 + memmap[K230_DEV_DMA].size);
211 +
212 + create_unimplemented_device("decomp-gzip",
213 + memmap[K230_DEV_DECOMP_GZIP].base,
214 + memmap[K230_DEV_DECOMP_GZIP].size);
215 +
216 + create_unimplemented_device("2d-engine.non-ai",
217 + memmap[K230_DEV_NON_AI_2D].base,
218 + memmap[K230_DEV_NON_AI_2D].size);
219 +
220 + create_unimplemented_device("isp", memmap[K230_DEV_ISP].base,
221 + memmap[K230_DEV_ISP].size);
222 +
223 + create_unimplemented_device("dewarp", memmap[K230_DEV_DEWARP].base,
224 + memmap[K230_DEV_DEWARP].size);
225 +
226 + create_unimplemented_device("rx-csi", memmap[K230_DEV_RX_CSI].base,
227 + memmap[K230_DEV_RX_CSI].size);
228 +
229 + create_unimplemented_device("vpu", memmap[K230_DEV_H264].base,
230 + memmap[K230_DEV_H264].size);
231 +
232 + create_unimplemented_device("gpu", memmap[K230_DEV_2P5D].base,
233 + memmap[K230_DEV_2P5D].size);
234 +
235 + create_unimplemented_device("vo", memmap[K230_DEV_VO].base,
236 + memmap[K230_DEV_VO].size);
237 +
238 + create_unimplemented_device("vo_cfg", memmap[K230_DEV_VO_CFG].base,
239 + memmap[K230_DEV_VO_CFG].size);
240 +
241 + create_unimplemented_device("3d-engine", memmap[K230_DEV_3D_ENGINE].base,
242 + memmap[K230_DEV_3D_ENGINE].size);
243 +
244 + create_unimplemented_device("pmu", memmap[K230_DEV_PMU].base,
245 + memmap[K230_DEV_PMU].size);
246 +
247 + create_unimplemented_device("rtc", memmap[K230_DEV_RTC].base,
248 + memmap[K230_DEV_RTC].size);
249 +
250 + create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
251 + memmap[K230_DEV_CMU].size);
252 +
253 + create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
254 + memmap[K230_DEV_RMU].size);
255 +
256 + create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
257 + memmap[K230_DEV_BOOT].size);
258 +
259 + create_unimplemented_device("pwr", memmap[K230_DEV_PWR].base,
260 + memmap[K230_DEV_PWR].size);
261 +
262 + create_unimplemented_device("ipcm", memmap[K230_DEV_MAILBOX].base,
263 + memmap[K230_DEV_MAILBOX].size);
264 +
265 + create_unimplemented_device("iomux", memmap[K230_DEV_IOMUX].base,
266 + memmap[K230_DEV_IOMUX].size);
267 +
268 + create_unimplemented_device("timer", memmap[K230_DEV_TIMER].base,
269 + memmap[K230_DEV_TIMER].size);
270 +
271 + create_unimplemented_device("wdt0", memmap[K230_DEV_WDT0].base,
272 + memmap[K230_DEV_WDT0].size);
273 +
274 + create_unimplemented_device("wdt1", memmap[K230_DEV_WDT1].base,
275 + memmap[K230_DEV_WDT1].size);
276 +
277 + create_unimplemented_device("ts", memmap[K230_DEV_TS].base,
278 + memmap[K230_DEV_TS].size);
279 +
280 + create_unimplemented_device("hdi", memmap[K230_DEV_HDI].base,
281 + memmap[K230_DEV_HDI].size);
282 +
283 + create_unimplemented_device("stc", memmap[K230_DEV_STC].base,
284 + memmap[K230_DEV_STC].size);
285 +
286 + create_unimplemented_device("security", memmap[K230_DEV_SECURITY].base,
287 + memmap[K230_DEV_SECURITY].size);
288 +
289 + create_unimplemented_device("i2c0", memmap[K230_DEV_I2C0].base,
290 + memmap[K230_DEV_I2C0].size);
291 +
292 + create_unimplemented_device("i2c1", memmap[K230_DEV_I2C1].base,
293 + memmap[K230_DEV_I2C1].size);
294 +
295 + create_unimplemented_device("i2c2", memmap[K230_DEV_I2C2].base,
296 + memmap[K230_DEV_I2C2].size);
297 +
298 + create_unimplemented_device("i2c3", memmap[K230_DEV_I2C3].base,
299 + memmap[K230_DEV_I2C3].size);
300 +
301 + create_unimplemented_device("i2c4", memmap[K230_DEV_I2C4].base,
302 + memmap[K230_DEV_I2C4].size);
303 +
304 + create_unimplemented_device("pwm", memmap[K230_DEV_PWM].base,
305 + memmap[K230_DEV_PWM].size);
306 +
307 + create_unimplemented_device("gpio0", memmap[K230_DEV_GPIO0].base,
308 + memmap[K230_DEV_GPIO0].size);
309 +
310 + create_unimplemented_device("gpio1", memmap[K230_DEV_GPIO1].base,
311 + memmap[K230_DEV_GPIO1].size);
312 +
313 + create_unimplemented_device("adc", memmap[K230_DEV_ADC].base,
314 + memmap[K230_DEV_ADC].size);
315 +
316 + create_unimplemented_device("codec", memmap[K230_DEV_CODEC].base,
317 + memmap[K230_DEV_CODEC].size);
318 +
319 + create_unimplemented_device("i2s", memmap[K230_DEV_I2S].base,
320 + memmap[K230_DEV_I2S].size);
321 +
322 + create_unimplemented_device("usb0", memmap[K230_DEV_USB0].base,
323 + memmap[K230_DEV_USB0].size);
324 +
325 + create_unimplemented_device("usb1", memmap[K230_DEV_USB1].base,
326 + memmap[K230_DEV_USB1].size);
327 +
328 + create_unimplemented_device("sd0", memmap[K230_DEV_SD0].base,
329 + memmap[K230_DEV_SD0].size);
330 +
331 + create_unimplemented_device("sd1", memmap[K230_DEV_SD1].base,
332 + memmap[K230_DEV_SD1].size);
333 +
334 + create_unimplemented_device("qspi0", memmap[K230_DEV_QSPI0].base,
335 + memmap[K230_DEV_QSPI0].size);
336 +
337 + create_unimplemented_device("qspi1", memmap[K230_DEV_QSPI1].base,
338 + memmap[K230_DEV_QSPI1].size);
339 +
340 + create_unimplemented_device("spi", memmap[K230_DEV_SPI].base,
341 + memmap[K230_DEV_SPI].size);
342 +
343 + create_unimplemented_device("hi_sys_cfg", memmap[K230_DEV_HI_SYS_CFG].base,
344 + memmap[K230_DEV_HI_SYS_CFG].size);
345 +
346 + create_unimplemented_device("ddrc_cfg", memmap[K230_DEV_DDRC_CFG].base,
347 + memmap[K230_DEV_DDRC_CFG].size);
348 +
349 + create_unimplemented_device("flash", memmap[K230_DEV_FLASH].base,
350 + memmap[K230_DEV_FLASH].size);
351 +}
352 +
353 +static void k230_soc_class_init(ObjectClass *oc, const void *data)
354 +{
355 + DeviceClass *dc = DEVICE_CLASS(oc);
356 +
357 + dc->realize = k230_soc_realize;
358 +}
359 +
360 +static const TypeInfo k230_soc_type_info = {
361 + .name = TYPE_RISCV_K230_SOC,
362 + .parent = TYPE_DEVICE,
363 + .instance_size = sizeof(K230SoCState),
364 + .instance_init = k230_soc_init,
365 + .class_init = k230_soc_class_init,
366 +};
367 +
368 +static void k230_soc_register_types(void)
369 +{
370 + type_register_static(&k230_soc_type_info);
371 +}
372 +
373 +type_init(k230_soc_register_types)
374 +
375 +static void k230_direct_boot(K230MachineState *s, MachineState *machine)
376 +{
377 + const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
378 + RISCVBootInfo boot_info = {0};
379 + hwaddr start_addr = K230_DIRECT_OPENSBI_ADDR;
380 + hwaddr firmware_end_addr = 0;
381 + hwaddr kernel_entry = 0;
382 + int fdt_size = 0;
383 +
384 + if (machine->firmware && !strcmp(machine->firmware, "none")) {
385 + error_report("K230 direct boot requires OpenSBI firmware; omit "
386 + "-bios none or pass OpenSBI with -bios");
387 + exit(EXIT_FAILURE);
388 + }
389 +
390 + if (!machine->dtb) {
391 + error_report("K230 direct boot requires -dtb");
392 + exit(EXIT_FAILURE);
393 + }
394 +
395 + machine->fdt = load_device_tree(machine->dtb, &fdt_size);
396 + if (!machine->fdt) {
397 + error_report("load_device_tree() failed");
398 + exit(EXIT_FAILURE);
399 + }
400 +
401 + qemu_fdt_add_path(machine->fdt, "/chosen");
402 +
403 + riscv_boot_info_init(&boot_info, &s->soc.c908_cpu);
404 + riscv_load_kernel(machine, &boot_info, K230_DIRECT_KERNEL_ADDR, true, NULL);
405 + kernel_entry = boot_info.image_low_addr;
406 +
407 + riscv_load_fdt(K230_DIRECT_DTB_ADDR, machine->fdt);
408 +
409 + firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
410 + &start_addr, NULL);
411 + if (firmware_end_addr > K230_DIRECT_KERNEL_ADDR) {
412 + error_report("K230 firmware overlaps kernel address 0x%x",
413 + K230_DIRECT_KERNEL_ADDR);
414 + exit(EXIT_FAILURE);
415 + }
416 +
417 + riscv_setup_rom_reset_vec(machine, &s->soc.c908_cpu, start_addr,
418 + memmap[K230_DEV_BOOTROM].base,
419 + memmap[K230_DEV_BOOTROM].size, kernel_entry,
420 + K230_DIRECT_DTB_ADDR);
421 +}
422 +
423 +static void k230_firmware_boot(K230MachineState *s, MachineState *machine)
424 +{
425 + const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
426 + hwaddr start_addr = memmap[K230_DEV_DDRC].base;
427 +
428 + if (machine->dtb || (machine->kernel_cmdline && *machine->kernel_cmdline)) {
429 + error_report("K230 firmware boot does not support -dtb or -append");
430 + exit(EXIT_FAILURE);
431 + }
432 +
433 + riscv_find_and_load_firmware(machine, firmware_name, &start_addr, NULL);
434 +
435 + riscv_setup_rom_reset_vec(machine, &s->soc.c908_cpu, start_addr,
436 + memmap[K230_DEV_BOOTROM].base,
437 + memmap[K230_DEV_BOOTROM].size, 0, 0);
438 +}
439 +
440 +static void k230_machine_done(Notifier *notifier, void *data)
441 +{
442 + K230MachineState *s = container_of(notifier, K230MachineState,
443 + machine_done);
444 + MachineState *machine = MACHINE(s);
445 +
446 + if (machine->kernel_filename) {
447 + k230_direct_boot(s, machine);
448 + } else {
449 + k230_firmware_boot(s, machine);
450 + }
451 +}
452 +
453 +static void k230_machine_init(MachineState *machine)
454 +{
455 + MachineClass *mc = MACHINE_GET_CLASS(machine);
456 + K230MachineState *s = RISCV_K230_MACHINE(machine);
457 + MemoryRegion *sys_mem = get_system_memory();
458 +
459 + if (machine->ram_size < mc->default_ram_size) {
460 + char *sz = size_to_str(mc->default_ram_size);
461 + error_report("Invalid RAM size, should be %s", sz);
462 + g_free(sz);
463 + exit(EXIT_FAILURE);
464 + }
465 +
466 + /* Initialize SoC */
467 + object_initialize_child(OBJECT(machine), "soc", &s->soc,
468 + TYPE_RISCV_K230_SOC);
469 + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
470 +
471 + /* Data Memory */
472 + memory_region_add_subregion(sys_mem, memmap[K230_DEV_DDRC].base,
473 + machine->ram);
474 +
475 + s->machine_done.notify = k230_machine_done;
476 + qemu_add_machine_init_done_notifier(&s->machine_done);
477 +}
478 +
479 +static void k230_machine_instance_init(Object *obj)
480 +{
481 +}
482 +
483 +static void k230_machine_class_init(ObjectClass *oc, const void *data)
484 +{
485 + MachineClass *mc = MACHINE_CLASS(oc);
486 +
487 + mc->desc = "RISC-V Board compatible with Kendryte K230 SDK";
488 + mc->init = k230_machine_init;
489 + mc->default_cpus = 1;
490 + mc->default_ram_id = "riscv.K230.ram"; /* DDR */
491 + mc->default_ram_size = memmap[K230_DEV_DDRC].size;
492 +}
493 +
494 +static const TypeInfo k230_machine_typeinfo = {
495 + .name = TYPE_RISCV_K230_MACHINE,
496 + .parent = TYPE_MACHINE,
497 + .class_init = k230_machine_class_init,
498 + .instance_init = k230_machine_instance_init,
499 + .instance_size = sizeof(K230MachineState),
500 + .interfaces = riscv64_machine_interfaces,
501 +};
502 +
503 +static void k230_machine_init_register_types(void)
504 +{
505 + type_register_static(&k230_machine_typeinfo);
506 +}
507 +
508 +type_init(k230_machine_init_register_types)
hw/riscv/meson.build
+1 -1
@@ -14,8 +14,8 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
14 'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
15 riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
16 riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c'))
17 -
17 riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c'))
18 riscv_ss.add(when: 'CONFIG_MIPS_BOSTON_AIA', if_true: files('boston-aia.c'))
19 +riscv_ss.add(when: 'CONFIG_K230', if_true: files('k230.c'))
20
21 hw_arch += {'riscv': riscv_ss}
include/hw/riscv/k230.h new
+145
@@ -0,0 +1,145 @@
1 +/*
2 + * QEMU RISC-V Virt Board Compatible with kendryte K230 SDK
3 + *
4 + * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
5 + *
6 + * SPDX-License-Identifier: GPL-2.0-or-later
7 + *
8 + * Provides a board compatible with the kendryte K230 SDK
9 + *
10 + * K230 Technical Reference Manual V0.3.1 (2024-11-18):
11 + * https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
12 + *
13 + * For more information, see <https://www.kendryte.com/en/proDetail/230>
14 + */
15 +#ifndef HW_K230_H
16 +#define HW_K230_H
17 +
18 +#include "hw/core/boards.h"
19 +#include "hw/riscv/riscv_hart.h"
20 +
21 +#define C908_CPU_HARTID (0)
22 +
23 +#define TYPE_RISCV_K230_SOC "riscv.k230.soc"
24 +#define RISCV_K230_SOC(obj) \
25 + OBJECT_CHECK(K230SoCState, (obj), TYPE_RISCV_K230_SOC)
26 +
27 +typedef struct K230SoCState {
28 + /*< private >*/
29 + DeviceState parent_obj;
30 +
31 + /*< public >*/
32 + RISCVHartArrayState c908_cpu; /* Small core */
33 +
34 + MemoryRegion sram;
35 + MemoryRegion bootrom;
36 +
37 + DeviceState *c908_plic;
38 +} K230SoCState;
39 +
40 +#define TYPE_RISCV_K230_MACHINE MACHINE_TYPE_NAME("k230")
41 +#define RISCV_K230_MACHINE(obj) \
42 + OBJECT_CHECK(K230MachineState, (obj), TYPE_RISCV_K230_MACHINE)
43 +
44 +typedef struct K230MachineState {
45 + /*< private >*/
46 + MachineState parent_obj;
47 +
48 + /*< public >*/
49 + K230SoCState soc;
50 + Notifier machine_done;
51 +} K230MachineState;
52 +
53 +enum {
54 + K230_DEV_DDRC,
55 + K230_DEV_KPU_L2_CACHE,
56 + K230_DEV_SRAM,
57 + K230_DEV_KPU_CFG,
58 + K230_DEV_FFT,
59 + K230_DEV_AI_2D_ENGINE,
60 + K230_DEV_GSDMA,
61 + K230_DEV_DMA,
62 + K230_DEV_DECOMP_GZIP,
63 + K230_DEV_NON_AI_2D,
64 + K230_DEV_ISP,
65 + K230_DEV_DEWARP,
66 + K230_DEV_RX_CSI,
67 + K230_DEV_H264,
68 + K230_DEV_2P5D,
69 + K230_DEV_VO,
70 + K230_DEV_VO_CFG,
71 + K230_DEV_3D_ENGINE,
72 + K230_DEV_PMU,
73 + K230_DEV_RTC,
74 + K230_DEV_CMU,
75 + K230_DEV_RMU,
76 + K230_DEV_BOOT,
77 + K230_DEV_PWR,
78 + K230_DEV_MAILBOX,
79 + K230_DEV_IOMUX,
80 + K230_DEV_TIMER,
81 + K230_DEV_WDT0,
82 + K230_DEV_WDT1,
83 + K230_DEV_TS,
84 + K230_DEV_HDI,
85 + K230_DEV_STC,
86 + K230_DEV_BOOTROM,
87 + K230_DEV_SECURITY,
88 + K230_DEV_UART0,
89 + K230_DEV_UART1,
90 + K230_DEV_UART2,
91 + K230_DEV_UART3,
92 + K230_DEV_UART4,
93 + K230_DEV_I2C0,
94 + K230_DEV_I2C1,
95 + K230_DEV_I2C2,
96 + K230_DEV_I2C3,
97 + K230_DEV_I2C4,
98 + K230_DEV_PWM,
99 + K230_DEV_GPIO0,
100 + K230_DEV_GPIO1,
101 + K230_DEV_ADC,
102 + K230_DEV_CODEC,
103 + K230_DEV_I2S,
104 + K230_DEV_USB0,
105 + K230_DEV_USB1,
106 + K230_DEV_SD0,
107 + K230_DEV_SD1,
108 + K230_DEV_QSPI0,
109 + K230_DEV_QSPI1,
110 + K230_DEV_SPI,
111 + K230_DEV_HI_SYS_CFG,
112 + K230_DEV_DDRC_CFG,
113 + K230_DEV_FLASH,
114 + K230_DEV_PLIC,
115 + K230_DEV_CLINT,
116 +};
117 +
118 +enum {
119 + /*
120 + * K230 TRM v0.3.1 section 2.4 lists peripheral interrupt bits; SDK
121 + * DTBs expose the corresponding PLIC IDs as bit + 16.
122 + */
123 + K230_UART0_IRQ = 16,
124 + K230_UART1_IRQ = 17,
125 + K230_UART2_IRQ = 18,
126 + K230_UART3_IRQ = 19,
127 + K230_UART4_IRQ = 20,
128 +};
129 +
130 +#define K230_UART_COUNT 5
131 +
132 +/*
133 + * Integrates with the interrupt controller (PLIC),
134 + * which can process 208 interrupt external sources
135 + */
136 +#define K230_PLIC_NUM_SOURCES 208
137 +#define K230_PLIC_NUM_PRIORITIES 7
138 +#define K230_PLIC_PRIORITY_BASE 0x00
139 +#define K230_PLIC_PENDING_BASE 0x1000
140 +#define K230_PLIC_ENABLE_BASE 0x2000
141 +#define K230_PLIC_ENABLE_STRIDE 0x80
142 +#define K230_PLIC_CONTEXT_BASE 0x200000
143 +#define K230_PLIC_CONTEXT_STRIDE 0x1000
144 +
145 +#endif