On Sun, 2026-09-27 at 20:13 +0000, Kuan-Wei Chiu wrote: > Add a stub for the CV1800B clock controller. This is specifically > required for the SDHCI controller to function correctly under Linux. > > The Linux 'sophgo,cv1800-clk' driver probes this device to determine > the clock tree configuration. This implementation sets the bypass > registers (CLK_BYP_0 and CLK_BYP_1) to 0xFFFFFFFF during reset, > matching the POR default state. This bypasses the PLLs and allows the > SDHCI and other peripherals to operate using the 25MHz reference > clock. > > Without this device, the SD card driver fails to initialize, > preventing > the system from mounting the root filesystem from the SD card. > > Signed-off-by: Kuan-Wei Chiu <[email protected]>
Acked-by: Alistair Francis <[email protected]> Alistair > --- > hw/misc/Kconfig | 3 ++ > hw/misc/cv1800b_clk.c | 98 > +++++++++++++++++++++++++++++++++++ > hw/misc/meson.build | 1 + > include/hw/misc/cv1800b_clk.h | 26 ++++++++++ > 4 files changed, 128 insertions(+) > create mode 100644 hw/misc/cv1800b_clk.c > create mode 100644 include/hw/misc/cv1800b_clk.h > > diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig > index 46e3c03cc8..7abd22869a 100644 > --- a/hw/misc/Kconfig > +++ b/hw/misc/Kconfig > @@ -263,4 +263,7 @@ config AXIADO_CLK > config K230_DECOMP_GZIP > bool > > +config SOPHGO_CV1800B_CLK > + bool > + > source macio/Kconfig > diff --git a/hw/misc/cv1800b_clk.c b/hw/misc/cv1800b_clk.c > new file mode 100644 > index 0000000000..38807995ac > --- /dev/null > +++ b/hw/misc/cv1800b_clk.c > @@ -0,0 +1,98 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * Sophgo CV1800B Clock Controller > + * > + * Copyright (c) 2026 Kuan-Wei Chiu <[email protected]> > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/log.h" > +#include "hw/misc/cv1800b_clk.h" > + > +#define REG_BYTE_WIDTH (sizeof(uint32_t)) > +#define REG_CLK_BYP_0 (0x030 / REG_BYTE_WIDTH) > +#define REG_CLK_BYP_1 (0x034 / REG_BYTE_WIDTH) > + > +static uint64_t cv1800b_clk_read(void *opaque, hwaddr addr, unsigned > int size) > +{ > + CV1800BClkState *s = opaque; > + uint32_t val = 0; > + > + if (addr < CV1800B_CLK_IOSIZE) { > + val = s->regs[addr / REG_BYTE_WIDTH]; > + } else { > + qemu_log_mask(LOG_GUEST_ERROR, > + "%s: Out-of-bounds read at offset 0x%" > HWADDR_PRIx "\n", > + __func__, addr); > + } > + > + return val; > +} > + > +static void cv1800b_clk_write(void *opaque, hwaddr addr, uint64_t > val, unsigned int size) > +{ > + CV1800BClkState *s = opaque; > + > + if (addr < CV1800B_CLK_IOSIZE) { > + s->regs[addr / REG_BYTE_WIDTH] = val; > + } else { > + qemu_log_mask(LOG_GUEST_ERROR, > + "%s: Out-of-bounds write at offset 0x%" > HWADDR_PRIx "\n", > + __func__, addr); > + } > +} > + > +static const MemoryRegionOps cv1800b_clk_ops = { > + .read = cv1800b_clk_read, > + .write = cv1800b_clk_write, > + .endianness = DEVICE_LITTLE_ENDIAN, > + .valid = { > + .min_access_size = 4, > + .max_access_size = 4, > + }, > +}; > + > +static void cv1800b_clk_reset_hold(Object *obj, ResetType type) > +{ > + CV1800BClkState *s = CV1800B_CLK(obj); > + > + memset(s->regs, 0, sizeof(s->regs)); > + > + /* > + * TODO: Implement proper PLL state machines. > + * For now, use POR default to bypass PLLs and boot via 25MHz > XTAL. > + */ > + s->regs[REG_CLK_BYP_0] = 0xFFFFFFFF; > + s->regs[REG_CLK_BYP_1] = 0xFFFFFFFF; > +} > + > +static void cv1800b_clk_init(Object *obj) > +{ > + CV1800BClkState *s = CV1800B_CLK(obj); > + > + memory_region_init_io(&s->iomem, obj, &cv1800b_clk_ops, s, > + TYPE_CV1800B_CLK, CV1800B_CLK_IOSIZE); > + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); > +} > + > +static void cv1800b_clk_class_init(ObjectClass *klass, const void > *data) > +{ > + ResettableClass *rc = RESETTABLE_CLASS(klass); > + > + rc->phases.hold = cv1800b_clk_reset_hold; > +} > + > +static const TypeInfo cv1800b_clk_info = { > + .name = TYPE_CV1800B_CLK, > + .parent = TYPE_SYS_BUS_DEVICE, > + .instance_size = sizeof(CV1800BClkState), > + .instance_init = cv1800b_clk_init, > + .class_init = cv1800b_clk_class_init, > +}; > + > +static void cv1800b_clk_register_types(void) > +{ > + type_register_static(&cv1800b_clk_info); > +} > + > +type_init(cv1800b_clk_register_types) > diff --git a/hw/misc/meson.build b/hw/misc/meson.build > index 9790afa104..244bf278a9 100644 > --- a/hw/misc/meson.build > +++ b/hw/misc/meson.build > @@ -39,6 +39,7 @@ system_ss.add(when: 'CONFIG_SIFIVE_E_AON', if_true: > files('sifive_e_aon.c')) > system_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: > files('sifive_u_otp.c')) > system_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: > files('sifive_u_prci.c')) > system_ss.add(when: 'CONFIG_K230_DECOMP_GZIP', if_true: > files('k230_decomp_gzip.c')) > +system_ss.add(when: 'CONFIG_SOPHGO_CV1800B_CLK', if_true: > files('cv1800b_clk.c')) > > subdir('macio') > > diff --git a/include/hw/misc/cv1800b_clk.h > b/include/hw/misc/cv1800b_clk.h > new file mode 100644 > index 0000000000..4d03d887c6 > --- /dev/null > +++ b/include/hw/misc/cv1800b_clk.h > @@ -0,0 +1,26 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * Sophgo CV1800B Clock Controller > + * > + * Copyright (c) 2026 Kuan-Wei Chiu <[email protected]> > + */ > + > +#ifndef HW_MISC_CV1800B_CLK_H > +#define HW_MISC_CV1800B_CLK_H > + > +#include "hw/core/sysbus.h" > +#include "qom/object.h" > + > +#define TYPE_CV1800B_CLK "cv1800b-clk" > +OBJECT_DECLARE_SIMPLE_TYPE(CV1800BClkState, CV1800B_CLK) > + > +#define CV1800B_CLK_IOSIZE 0x1000 > + > +struct CV1800BClkState { > + SysBusDevice parent_obj; > + > + MemoryRegion iomem; > + uint32_t regs[CV1800B_CLK_IOSIZE / sizeof(uint32_t)]; > +}; > + > +#endif
