On Tue, May 12, 2026 at 2:32 AM Chao Liu <[email protected]> wrote: > > 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 <[email protected]> > Tested-by: Peng Jiang <[email protected]>
Acked-by: Alistair Francis <[email protected]> Alistair > --- > MAINTAINERS | 7 + > hw/riscv/Kconfig | 10 + > hw/riscv/k230.c | 506 ++++++++++++++++++++++++++++++++++++++++ > hw/riscv/meson.build | 2 +- > include/hw/riscv/k230.h | 145 ++++++++++++ > 5 files changed, 669 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 f109e46172..196b476abe 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -1780,6 +1780,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 <[email protected]> > +L: [email protected] > +S: Maintained > +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 0222c93f87..b1a7357866 100644 > --- a/hw/riscv/Kconfig > +++ b/hw/riscv/Kconfig > @@ -134,3 +134,13 @@ config MIPS_BOSTON_AIA > default y > select PCI_EXPRESS > select PCI_EXPRESS_XILINX > + > +config K230 > + bool > + default y > + depends on RISCV64 > + select RISCV_ACLINT > + select RISCV_APLIC > + select RISCV_IMSIC > + select SERIAL_MM > + select UNIMP > diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c > new file mode 100644 > index 0000000000..327355b565 > --- /dev/null > +++ b/hw/riscv/k230.c > @@ -0,0 +1,506 @@ > +/* > + * QEMU RISC-V Virt Board Compatible with Kendryte K230 SDK > + * > + * Copyright (c) 2025 Chao Liu <[email protected]> > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + * > + * Provides a board compatible with the Kendryte K230 SDK > + * > + * K230 Technical Reference Manual V0.3.1 (2024-11-18): > + * > https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf > + * > + * For more information, see <https://www.kendryte.com/en/proDetail/230> > + */ > + > +#include "qemu/osdep.h" > +#include "cpu-qom.h" > +#include "qemu/cutils.h" > +#include "qemu/error-report.h" > +#include "qapi/error.h" > +#include "system/device_tree.h" > +#include "system/system.h" > +#include "system/memory.h" > +#include "target/riscv/cpu.h" > +#include "hw/core/loader.h" > +#include "hw/core/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" > + > +/* Align K230_SDK k230_canmv_defconfig */ > +#define K230_DIRECT_OPENSBI_ADDR 0x8000000 > +#define K230_DIRECT_KERNEL_ADDR 0x8200000 > +#define K230_DIRECT_DTB_ADDR 0xa000000 > + > +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] = { 0xF00000000, 0x00400000 }, > + [K230_DEV_CLINT] = { 0xF04000000, 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_create_uart(MemoryRegion *sys_mem, DeviceState *plic, > + int index) > +{ > + int uart_dev = K230_DEV_UART0 + index; > + g_autofree char *name = g_strdup_printf("uart%d", index); > + > + /* Cover the non-16550 part of the SDK's 0x1000 UART window. */ > + create_unimplemented_device(name, memmap[uart_dev].base, > + memmap[uart_dev].size); > + > + serial_mm_init(sys_mem, memmap[uart_dev].base, 2, > + qdev_get_gpio_in(plic, K230_UART0_IRQ + index), > + 399193, serial_hd(index), DEVICE_LITTLE_ENDIAN); > +} > + > +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 */ > + for (int i = 0; i < K230_UART_COUNT; i++) { > + k230_create_uart(sys_mem, DEVICE(s->c908_plic), i); > + } > + > + /* 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_direct_boot(K230MachineState *s, MachineState *machine) > +{ > + const char *firmware_name = > riscv_default_firmware_name(&s->soc.c908_cpu); > + RISCVBootInfo boot_info = {0}; > + hwaddr start_addr = K230_DIRECT_OPENSBI_ADDR; > + hwaddr firmware_end_addr = 0; > + hwaddr kernel_entry = 0; > + int fdt_size = 0; > + > + if (machine->firmware && !strcmp(machine->firmware, "none")) { > + error_report("K230 direct boot requires OpenSBI firmware; omit " > + "-bios none or pass OpenSBI with -bios"); > + exit(EXIT_FAILURE); > + } > + > + if (!machine->dtb) { > + error_report("K230 direct boot requires -dtb"); > + exit(EXIT_FAILURE); > + } > + > + machine->fdt = load_device_tree(machine->dtb, &fdt_size); > + if (!machine->fdt) { > + error_report("load_device_tree() failed"); > + exit(EXIT_FAILURE); > + } > + > + qemu_fdt_add_path(machine->fdt, "/chosen"); > + > + riscv_boot_info_init(&boot_info, &s->soc.c908_cpu); > + riscv_load_kernel(machine, &boot_info, K230_DIRECT_KERNEL_ADDR, true, > NULL); > + kernel_entry = boot_info.image_low_addr; > + > + riscv_load_fdt(K230_DIRECT_DTB_ADDR, machine->fdt); > + > + firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, > + &start_addr, NULL); > + if (firmware_end_addr > K230_DIRECT_KERNEL_ADDR) { > + error_report("K230 firmware overlaps kernel address 0x%x", > + K230_DIRECT_KERNEL_ADDR); > + exit(EXIT_FAILURE); > + } > + > + riscv_setup_rom_reset_vec(machine, &s->soc.c908_cpu, start_addr, > + memmap[K230_DEV_BOOTROM].base, > + memmap[K230_DEV_BOOTROM].size, kernel_entry, > + K230_DIRECT_DTB_ADDR); > +} > + > +static void k230_firmware_boot(K230MachineState *s, MachineState *machine) > +{ > + const char *firmware_name = > riscv_default_firmware_name(&s->soc.c908_cpu); > + hwaddr start_addr = memmap[K230_DEV_DDRC].base; > + > + if (machine->dtb || (machine->kernel_cmdline && > *machine->kernel_cmdline)) { > + error_report("K230 firmware boot does not support -dtb or -append"); > + exit(EXIT_FAILURE); > + } > + > + riscv_find_and_load_firmware(machine, firmware_name, &start_addr, NULL); > + > + riscv_setup_rom_reset_vec(machine, &s->soc.c908_cpu, start_addr, > + memmap[K230_DEV_BOOTROM].base, > + memmap[K230_DEV_BOOTROM].size, 0, 0); > +} > + > +static void k230_machine_done(Notifier *notifier, void *data) > +{ > + K230MachineState *s = container_of(notifier, K230MachineState, > + machine_done); > + MachineState *machine = MACHINE(s); > + > + if (machine->kernel_filename) { > + k230_direct_boot(s, machine); > + } else { > + k230_firmware_boot(s, machine); > + } > +} > + > +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 = 1; > + 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 533472e22a..09cf855984 100644 > --- a/hw/riscv/meson.build > +++ b/hw/riscv/meson.build > @@ -14,8 +14,8 @@ 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_RISCV_MIPS_CPS', if_true: files('cps.c')) > riscv_ss.add(when: 'CONFIG_MIPS_BOSTON_AIA', if_true: files('boston-aia.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..dcfde39096 > --- /dev/null > +++ b/include/hw/riscv/k230.h > @@ -0,0 +1,145 @@ > +/* > + * QEMU RISC-V Virt Board Compatible with kendryte K230 SDK > + * > + * Copyright (c) 2025 Chao Liu <[email protected]> > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + * > + * Provides a board compatible with the kendryte K230 SDK > + * > + * K230 Technical Reference Manual V0.3.1 (2024-11-18): > + * > https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf > + * > + * For more information, see <https://www.kendryte.com/en/proDetail/230> > + */ > +#ifndef HW_K230_H > +#define HW_K230_H > + > +#include "hw/core/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 TRM v0.3.1 section 2.4 lists peripheral interrupt bits; SDK > + * DTBs expose the corresponding PLIC IDs as bit + 16. > + */ > + K230_UART0_IRQ = 16, > + K230_UART1_IRQ = 17, > + K230_UART2_IRQ = 18, > + K230_UART3_IRQ = 19, > + K230_UART4_IRQ = 20, > +}; > + > +#define K230_UART_COUNT 5 > + > +/* > + * 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 >
