On Wed, Jun 17, 2026 at 5:04 AM Kuan-Wei Chiu <[email protected]> wrote: > > Add support for the Milk-V Duo development board, which is powered by > the Sophgo CV1800B SoC. > > The implementation includes: > - Board-level machine initialization with 64mb of default ram. > - Integration of the CV1800B SoC. > - Support for loading external FDT, kernel, and initrd images. > - Proper setup of the reset vector to match the CV1800B's boot flow. > > Signed-off-by: Kuan-Wei Chiu <[email protected]>
Acked-by: Alistair Francis <[email protected]> Alistair > --- > MAINTAINERS | 11 ++ > configs/devices/riscv64-softmmu/default.mak | 1 + > hw/riscv/Kconfig | 6 + > hw/riscv/meson.build | 1 + > hw/riscv/milkv_duo.c | 124 ++++++++++++++++++++ > 5 files changed, 143 insertions(+) > create mode 100644 hw/riscv/milkv_duo.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 93df53d87f..e197dcb5b2 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -1797,6 +1797,17 @@ F: include/hw/riscv/k230.h > F: include/hw/watchdog/k230_wdt.h > F: tests/qtest/k230-wdt-test.c > > +Milk-V Duo > +M: Kuan-Wei Chiu <[email protected]> > +S: Maintained > +F: hw/char/dw8250.c > +F: hw/misc/cv1800b_clk.c > +F: hw/riscv/cv1800b.c > +F: hw/riscv/milkv_duo.c > +F: include/hw/char/dw8250.h > +F: include/hw/misc/cv1800b_clk.h > +F: include/hw/riscv/cv1800b.h > + > RX Machines > ----------- > rx-gdbsim > diff --git a/configs/devices/riscv64-softmmu/default.mak > b/configs/devices/riscv64-softmmu/default.mak > index a8e4d0ab33..2ba91b14d4 100644 > --- a/configs/devices/riscv64-softmmu/default.mak > +++ b/configs/devices/riscv64-softmmu/default.mak > @@ -13,3 +13,4 @@ > # CONFIG_SHAKTI_C=n > # CONFIG_XIANGSHAN_KUNMINGHU=n > # CONFIG_MIPS_BOSTON_AIA=n > +# CONFIG_MILKV_DUO=n > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig > index 299baed4a8..42a0e78574 100644 > --- a/hw/riscv/Kconfig > +++ b/hw/riscv/Kconfig > @@ -157,3 +157,9 @@ config SOPHGO_CV1800B > select SIFIVE_PLIC > select SOPHGO_CV1800B_CLK > select DW8250 > + > +config MILKV_DUO > + bool > + depends on RISCV64 > + default y > + select SOPHGO_CV1800B > diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build > index 6c242d77da..8c88f2bc25 100644 > --- a/hw/riscv/meson.build > +++ b/hw/riscv/meson.build > @@ -20,5 +20,6 @@ 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')) > > riscv_ss.add(when: 'CONFIG_SOPHGO_CV1800B', if_true: files('cv1800b.c')) > +riscv_ss.add(when: 'CONFIG_MILKV_DUO', if_true: files('milkv_duo.c')) > > hw_arch += {'riscv': riscv_ss} > diff --git a/hw/riscv/milkv_duo.c b/hw/riscv/milkv_duo.c > new file mode 100644 > index 0000000000..8e9a553a57 > --- /dev/null > +++ b/hw/riscv/milkv_duo.c > @@ -0,0 +1,124 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * Milk-V Duo board > + * > + * Copyright (c) 2026 Kuan-Wei Chiu <[email protected]> > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/units.h" > +#include "qapi/error.h" > +#include "hw/core/boards.h" > +#include "hw/riscv/cv1800b.h" > +#include "hw/riscv/boot.h" > +#include "target/riscv/cpu-qom.h" > +#include "system/system.h" > +#include "system/device_tree.h" > +#include "qemu/error-report.h" > +#include "hw/core/loader.h" > +#include <libfdt.h> > +#include "hw/riscv/machines-qom.h" > + > +struct MilkVDuoState { > + MachineState parent_obj; > + CV1800BSoCState soc; > +}; > + > +#define TYPE_MILK_V_DUO MACHINE_TYPE_NAME("milkv-duo") > +OBJECT_DECLARE_SIMPLE_TYPE(MilkVDuoState, MILK_V_DUO) > + > +static void milkv_duo_init(MachineState *machine) > +{ > + MilkVDuoState *s = MILK_V_DUO(machine); > + MemoryRegion *system_memory = get_system_memory(); > + RISCVBootInfo boot_info; > + hwaddr firmware_load_addr, firmware_end_addr; > + hwaddr fdt_load_addr = 0; > + int fdt_size = 0; > + uint64_t kernel_entry = 0; > + > + object_initialize_child(OBJECT(machine), "soc", &s->soc, > TYPE_CV1800B_SOC); > + qdev_realize(DEVICE(&s->soc), NULL, &error_fatal); > + > + memory_region_add_subregion(system_memory, > + cv1800b_memmap[CV1800B_DEV_DRAM].base, > + machine->ram); > + > + riscv_boot_info_init(&boot_info, &s->soc.cpus); > + > + firmware_load_addr = cv1800b_memmap[CV1800B_DEV_DRAM].base; > + firmware_end_addr = firmware_load_addr; > + if (machine->firmware) { > + firmware_end_addr = riscv_find_and_load_firmware(machine, > machine->firmware, > + > &firmware_load_addr, NULL); > + } > + > + if (machine->dtb) { > + machine->fdt = load_device_tree(machine->dtb, &fdt_size); > + if (!machine->fdt) { > + error_report("Failed to load device tree"); > + exit(1); > + } > + > + if (machine->kernel_cmdline && *machine->kernel_cmdline) { > + if (fdt_path_offset(machine->fdt, "/chosen") < 0) { > + qemu_fdt_add_subnode(machine->fdt, "/chosen"); > + } > + qemu_fdt_setprop_string(machine->fdt, "/chosen", "bootargs", > + machine->kernel_cmdline); > + } > + } > + > + if (machine->kernel_filename) { > + hwaddr 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; > + } > + > + if (machine->dtb) { > + fdt_load_addr = > riscv_compute_fdt_addr(cv1800b_memmap[CV1800B_DEV_DRAM].base, > + machine->ram_size, machine, > &boot_info); > + rom_add_blob_fixed_as("fdt", machine->fdt, fdt_size, fdt_load_addr, > + &address_space_memory); > + } > + > + riscv_setup_rom_reset_vec(machine, &s->soc.cpus, > + firmware_load_addr, > + cv1800b_memmap[CV1800B_DEV_ROM].base, > + cv1800b_memmap[CV1800B_DEV_ROM].size, > + kernel_entry, > + fdt_load_addr); > +} > + > +static void milkv_duo_machine_class_init(ObjectClass *oc, const void *data) > +{ > + MachineClass *mc = MACHINE_CLASS(oc); > + static const char *const valid_cpu_types[] = { > + TYPE_RISCV_CPU_THEAD_C906, > + NULL > + }; > + > + mc->desc = "Milk-V Duo Board (CV1800B)"; > + mc->init = milkv_duo_init; > + mc->max_cpus = 2; > + mc->default_cpu_type = TYPE_RISCV_CPU_THEAD_C906; > + mc->valid_cpu_types = valid_cpu_types; > + mc->default_ram_size = 64 * MiB; > + mc->default_ram_id = "riscv.milkv_duo.ram"; > +} > + > +static const TypeInfo milkv_duo_machine_type_info = { > + .name = TYPE_MILK_V_DUO, > + .parent = TYPE_MACHINE, > + .instance_size = sizeof(MilkVDuoState), > + .class_init = milkv_duo_machine_class_init, > + .interfaces = riscv64_machine_interfaces, > +}; > + > +static void milkv_duo_machine_register_types(void) > +{ > + type_register_static(&milkv_duo_machine_type_info); > +} > + > +type_init(milkv_duo_machine_register_types) > -- > 2.54.0.1136.gdb2ca164c4-goog > >
