* [PATCH 0/4] Kendryte K230 CMU register model
@ 2026-08-09 6:20 Simon Law
2026-08-09 6:20 ` [PATCH 1/4] hw/misc: model K230 CMU registers Simon Law
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Simon Law @ 2026-08-09 6:20 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, chao.liu, palmer, alistair.francis, liwei1518,
daniel.barboza, zhiwei_liu, pierrick.bouvier
The Kendryte K230 machine currently lacks the Clock Management Unit (CMU)
register interface required by the K230 SDK U-Boot and the Linux K230 clock
driver. As a result, software probing the PLL and sysclk providers cannot
observe the expected reset values or register update semantics.
This series adds a minimal, deterministic K230 CMU model.
The model covers:
- four PLL register blocks at 0x91102000..0x9110203f;
- the defined sysclk registers in the 0x91100000 window;
- the software-visible SPI2AXI_CLK_DIV register at sysclk offset 0x108;
- reset values and writable/reserved/read-only masks;
- PLL control write-enable semantics;
- write-one-to-trigger update behavior;
- deterministic PLL lock and initialization status;
- VMState for stable PLL and sysclk register state;
- qtest coverage for reset, masks, write-enable, W1T, status, sysclk
updates, unknown offsets, and system reset;
- K230 machine wiring and user-facing documentation.
The model intentionally does not propagate clock frequencies to QEMU devices or
change CPU execution speed. Peripheral reset, power control, and the
guest-initiated K230 reboot backend remain outside the scope of this series.
Those functions require separate reset/power models and a matching OpenSBI
backend.
The implementation is based only on the existing K230 machine and does not
depend on unmerged RMU, Timer, SPI, or SDHCI device series.
Testing:
- QTEST_QEMU_BINARY=/workspace/qemu/build/qemu-system-riscv64
/workspace/qemu/build/tests/qtest/k230-cmu-test
(10/10 subtests passed)
- QTEST_QEMU_BINARY=/workspace/qemu/build/qemu-system-riscv64
/workspace/qemu/build/tests/qtest/k230-wdt-test
(7/7 subtests passed)
- K230 direct Linux boot and K230 U-Boot boot
- Linux K230 clock probe and clk_summary validation
- CMU source/destination migration smoke
Signed-off-by: Simon Law <0860734llx@gmail.com>
---
Simon Law (4):
hw/misc: model K230 CMU registers
hw/riscv: connect the K230 CMU
tests/qtest: add K230 CMU coverage
docs/system/riscv: document K230 CMU support
MAINTAINERS | 4 +
docs/system/riscv/k230.rst | 22 ++
hw/misc/Kconfig | 3 +
hw/misc/k230_cmu.c | 881 ++++++++++++++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
hw/misc/trace-events | 9 +
hw/riscv/Kconfig | 1 +
hw/riscv/k230.c | 14 +-
include/hw/misc/k230_cmu.h | 58 +++
include/hw/riscv/k230.h | 2 +
tests/qtest/k230-cmu-test.c | 310 ++++++++++++++++
tests/qtest/meson.build | 3 +-
12 files changed, 1302 insertions(+), 6 deletions(-)
---
base-commit: f893c46c3931b3684d235d221bf8b7844ddbf1d7
change-id: 20260809-feat-k230-cmu-9b62e6dd23f3
Best regards,
--
Simon Law <0860734llx@gmail.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/4] hw/misc: model K230 CMU registers
2026-08-09 6:20 [PATCH 0/4] Kendryte K230 CMU register model Simon Law
@ 2026-08-09 6:20 ` Simon Law
2026-08-18 5:37 ` Chao Liu
2026-08-09 6:20 ` [PATCH 2/4] hw/riscv: connect the K230 CMU Simon Law
` (3 subsequent siblings)
4 siblings, 1 reply; 8+ messages in thread
From: Simon Law @ 2026-08-09 6:20 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, chao.liu, palmer, alistair.francis, liwei1518,
daniel.barboza, zhiwei_liu, pierrick.bouvier
Signed-off-by: Simon Law <0860734llx@gmail.com>
---
MAINTAINERS | 4 +
hw/misc/Kconfig | 3 +
hw/misc/k230_cmu.c | 881 +++++++++++++++++++++++++++++++++++++++++++++
hw/misc/meson.build | 1 +
hw/misc/trace-events | 9 +
hw/riscv/Kconfig | 1 +
include/hw/misc/k230_cmu.h | 58 +++
7 files changed, 957 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 6171cc7494..d46e90cdc5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1820,14 +1820,18 @@ F: hw/riscv/xiangshan_kmh.c
F: include/hw/riscv/xiangshan_kmh.h
K230 Machines
+M: Simon Law <0860734llx@gmail.com>
M: Chao Liu <chao.liu@processmission.com>
L: qemu-riscv@nongnu.org
S: Maintained
F: docs/system/riscv/k230.rst
F: hw/riscv/k230.c
+F: hw/misc/k230_cmu.c
F: hw/watchdog/k230_wdt.c
+F: include/hw/misc/k230_cmu.h
F: include/hw/riscv/k230.h
F: include/hw/watchdog/k230_wdt.h
+F: tests/qtest/k230-cmu-test.c
F: tests/qtest/k230-wdt-test.c
RX Machines
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 1543ee6653..58a0421e84 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -101,6 +101,9 @@ config FSL_IMX8MP_ANALOG
config FSL_IMX8MP_CCM
bool
+config K230_CMU
+ bool
+
config STM32_RCC
bool
diff --git a/hw/misc/k230_cmu.c b/hw/misc/k230_cmu.c
new file mode 100644
index 0000000000..6af19d2a06
--- /dev/null
+++ b/hw/misc/k230_cmu.c
@@ -0,0 +1,881 @@
+/*
+ * Kendryte K230 Clock Management Unit
+ *
+ * Copyright (c) 2026 Simon Law <0860734llx@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Emulates the K230 PLL and system-clock register protocol. It models
+ * software-visible reset values, masks, write strobes, and PLL lock state,
+ * but does not provide cycle-accurate clocks or propagate QEMU Clock signals.
+ *
+ * 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 "hw/core/sysbus.h"
+#include "hw/core/registerfields.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qom/object.h"
+
+#include "hw/misc/k230_cmu.h"
+#include "trace.h"
+
+REG32(CMU_CFG0, 0x00)
+ FIELD(CMU_CFG0, PLL_OUT_DIV, 24, 4)
+ FIELD(CMU_CFG0, PLL_REF_DIV, 16, 6)
+ FIELD(CMU_CFG0, PLL_FB_DIV, 0, 13)
+
+REG32(CMU_CFG1, 0x04)
+ FIELD(CMU_CFG1, PLL_BYPASS, 19, 1)
+ FIELD(CMU_CFG1, PLL_TEST, 18, 1)
+ FIELD(CMU_CFG1, PLL_ENSAT, 17, 1)
+ FIELD(CMU_CFG1, PLL_FASTEN, 16, 1)
+ FIELD(CMU_CFG1, PLL_BWADJ, 0, 12)
+
+REG32(CMU_CTL, 0x08)
+ FIELD(CMU_CTL, PLL_LOCK_TIM, 4, 8)
+ FIELD(CMU_CTL, PLL_CLK_OE, 2, 1)
+ FIELD(CMU_CTL, PLL_INIT, 1, 1)
+ FIELD(CMU_CTL, PLL_PWRDWN, 0, 1)
+
+REG32(CMU_STAT, 0x0c)
+ FIELD(CMU_STAT, PLL_FSM_STAT, 4, 2)
+ FIELD(CMU_STAT, PLL_RESERVED, 3, 1)
+ FIELD(CMU_STAT, PLL_FB_SLIP, 2, 1)
+ FIELD(CMU_STAT, PLL_REF_SLIP, 1, 1)
+ FIELD(CMU_STAT, PLL_LOCK, 0, 1)
+
+#define PLL_CFG0_RW_MASK (R_CMU_CFG0_PLL_OUT_DIV_MASK | \
+ R_CMU_CFG0_PLL_REF_DIV_MASK | \
+ R_CMU_CFG0_PLL_FB_DIV_MASK)
+#define PLL_CFG1_RW_MASK (R_CMU_CFG1_PLL_BYPASS_MASK | \
+ R_CMU_CFG1_PLL_TEST_MASK | \
+ R_CMU_CFG1_PLL_ENSAT_MASK | \
+ R_CMU_CFG1_PLL_FASTEN_MASK | \
+ R_CMU_CFG1_PLL_BWADJ_MASK)
+#define PLL_CTL_RW_MASK (R_CMU_CTL_PLL_LOCK_TIM_MASK | \
+ R_CMU_CTL_PLL_CLK_OE_MASK)
+#define PLL_CTL_W1T_MASK (R_CMU_CTL_PLL_INIT_MASK | \
+ R_CMU_CTL_PLL_PWRDWN_MASK)
+#define PLL_CTL_LOW_MASK (PLL_CTL_RW_MASK | PLL_CTL_W1T_MASK)
+#define PLL_STAT_RO_MASK (R_CMU_STAT_PLL_FSM_STAT_MASK | \
+ R_CMU_STAT_PLL_RESERVED_MASK | \
+ R_CMU_STAT_PLL_FB_SLIP_MASK | \
+ R_CMU_STAT_PLL_REF_SLIP_MASK | \
+ R_CMU_STAT_PLL_LOCK_MASK)
+
+REG32(SYSCLK_CPU0_CLK_CFG, 0x000)
+ FIELD(SYSCLK_CPU0_CLK_CFG, CORE_CLK_ROOT_GDIV_UPD, 31, 1)
+ FIELD(SYSCLK_CPU0_CLK_CFG, PCLK_DIV, 15, 3)
+ FIELD(SYSCLK_CPU0_CLK_CFG, TDI_PCLK_EN, 14, 1)
+ /* FIXME: SDK get_leaf_en() reads bit 7 for this gate; */
+ /* TRM says bit 13. */
+ FIELD(SYSCLK_CPU0_CLK_CFG, PCLK_ENABLE, 13, 1)
+ FIELD(SYSCLK_CPU0_CLK_CFG, PLICLK_DIV, 10, 3)
+ FIELD(SYSCLK_CPU0_CLK_CFG, PLICLK_ENABLE, 9, 1)
+ FIELD(SYSCLK_CPU0_CLK_CFG, ACLK_DIV, 6, 3)
+ FIELD(SYSCLK_CPU0_CLK_CFG, CORE_CLK_ROOT_DIV, 1, 4)
+ FIELD(SYSCLK_CPU0_CLK_CFG, CORE_CLK_ENABLE, 0, 1)
+REG32(SYSCLK_CPU1_CLK_CFG, 0x004)
+ FIELD(SYSCLK_CPU1_CLK_CFG, CORE_CLK_DIV_UPD, 31, 1)
+ FIELD(SYSCLK_CPU1_CLK_CFG, PCLK_ENABLE, 19, 1)
+ FIELD(SYSCLK_CPU1_CLK_CFG, PLICLK_DIV, 16, 3)
+ FIELD(SYSCLK_CPU1_CLK_CFG, PLICLK_ENABLE, 15, 1)
+ FIELD(SYSCLK_CPU1_CLK_CFG, ACLK_DIV, 12, 3)
+ FIELD(SYSCLK_CPU1_CLK_CFG, CORE_CLK_ROOT_DIV, 3, 3)
+ FIELD(SYSCLK_CPU1_CLK_CFG, CORE_CLK_SEL, 1, 2)
+ FIELD(SYSCLK_CPU1_CLK_CFG, CORE_CLK_ENABLE, 0, 1)
+REG32(SYSCLK_AI_CLK_CFG, 0x008)
+ FIELD(SYSCLK_AI_CLK_CFG, CLK_DIV_UPD, 31, 1)
+ FIELD(SYSCLK_AI_CLK_CFG, ACLK_ENABLE, 10, 1)
+ FIELD(SYSCLK_AI_CLK_CFG, CLK_CDIV, 3, 3)
+ FIELD(SYSCLK_AI_CLK_CFG, CLK_SEL, 2, 1)
+ FIELD(SYSCLK_AI_CLK_CFG, CLK_ENABLE, 0, 1)
+REG32(SYSCLK_VPU_CLK_CFG, 0x00c)
+ FIELD(SYSCLK_VPU_CLK_CFG, CLK_GDIV_UPD, 31, 1)
+ FIELD(SYSCLK_VPU_CLK_CFG, CFGCLK_ROOT_DIV, 11, 4)
+ FIELD(SYSCLK_VPU_CLK_CFG, CFGCLK_ENABLE, 10, 1)
+ FIELD(SYSCLK_VPU_CLK_CFG, ACLK_ROOT_DIV, 6, 4)
+ FIELD(SYSCLK_VPU_CLK_CFG, ACLK_ENABLE, 5, 1)
+ FIELD(SYSCLK_VPU_CLK_CFG, CLK_DIV, 1, 4)
+ FIELD(SYSCLK_VPU_CLK_CFG, CLK_EN, 0, 1)
+REG32(SYSCLK_PMU_CLK_CFG, 0x010)
+ FIELD(SYSCLK_PMU_CLK_CFG, CLK_EN, 0, 1)
+REG32(SYSCLK_HS_CLKEN_CFG, 0x018)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SSI2_ACLK_ENABLE, 30, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SSI1_ACLK_ENABLE, 29, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, QSPI_ACLK_ENABLE, 28, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SSI0_ACLK_ENABLE, 27, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SSI2_CLK_ENABLE, 26, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SSI1_CLK_ENABLE, 25, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SSI0_CLK_ENABLE, 24, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, USB_REFCLK_SEL, 23, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, USB1_REFCLK_ENABLE, 22, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, USB0_REFCLK_ENABLE, 21, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD1_TMCLK_ENABLE, 20, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD1_CCLK_ENABLE, 19, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD1_BCLK_ENABLE, 18, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD1_ACLK_ENABLE, 17, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD0_TMCLK_ENABLE, 16, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD0_CCLK_ENABLE, 15, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD0_BCLK_ENABLE, 14, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD0_ACLK_ENABLE, 13, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD_TMCLK_ENABLE, 12, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD_CCLK_ENABLE, 11, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD_BCLK_ENABLE, 10, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD_ACLK_ENABLE, 9, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SSI2_HCLK_ENABLE, 8, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SSI1_HCLK_ENABLE, 7, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SSI0_HCLK_ENABLE, 6, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, USB1_HCLK_ENABLE, 5, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, USB0_HCLK_ENABLE, 4, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD1_HCLK_ENABLE, 3, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, SD0_HCLK_ENABLE, 2, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, HCLK_HIGH_ENABLE, 1, 1)
+ FIELD(SYSCLK_HS_CLKEN_CFG, HCLK_ENABLE, 0, 1)
+REG32(SYSCLK_HS_SDCLK_CFG, 0x01c)
+ FIELD(SYSCLK_HS_SDCLK_CFG, ACLK_ROOT_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_HS_SDCLK_CFG, TMCLK_DIV, 15, 5)
+ /* FIXME: SDK get_leaf_rate() uses ACLK_ROOT_DIV for SD CCLK, */
+ /* not bits 14:12. */
+ FIELD(SYSCLK_HS_SDCLK_CFG, CCLK_DIV, 12, 3)
+ FIELD(SYSCLK_HS_SDCLK_CFG, BCLK_DIV, 9, 3)
+ FIELD(SYSCLK_HS_SDCLK_CFG, ACLK_ROOT_DIV, 6, 3)
+ FIELD(SYSCLK_HS_SDCLK_CFG, HCLK_DIV, 3, 3)
+ FIELD(SYSCLK_HS_SDCLK_CFG, HCLK_HIGH_ROOT_DIV, 0, 3)
+REG32(SYSCLK_HS_SPI_CFG, 0x020)
+ FIELD(SYSCLK_HS_SPI_CFG, SSI0_ACLK_ROOT_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_HS_SPI_CFG, SSI0_CLK_SEL, 18, 1)
+ FIELD(SYSCLK_HS_SPI_CFG, USB_REFCLK_50M_DIV, 15, 3)
+ FIELD(SYSCLK_HS_SPI_CFG, QSPI_ACLK_ROOT_DIV, 12, 3)
+ FIELD(SYSCLK_HS_SPI_CFG, SSI0_ACLK_DIV, 9, 3)
+ FIELD(SYSCLK_HS_SPI_CFG, SSI2_CLK_DIV, 6, 3)
+ FIELD(SYSCLK_HS_SPI_CFG, SSI1_CLK_DIV, 3, 3)
+REG32(SYSCLK_LS_CLKEN_CFG0, 0x024)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, PDM_CLK_ENABLE, 31, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, CODEC_MCLK_DAC_ENABLE, 30, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, CODEC_MCLK_ADC_ENABLE, 29, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, AUD_DEV_CLK_ENABLE, 28, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, GPIO_DBCLK_ENABLE, 27, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, ADC_CLK_ENABLE, 26, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, I2C4_CLK_ENABLE, 25, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, I2C3_CLK_ENABLE, 24, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, I2C2_CLK_ENABLE, 23, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, I2C1_CLK_ENABLE, 22, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, I2C0_CLK_ENABLE, 21, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, UART4_CLK_ENABLE, 20, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, UART3_CLK_ENABLE, 19, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, UART2_CLK_ENABLE, 18, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, UART1_CLK_ENABLE, 17, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, UART0_CLK_ENABLE, 16, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, ADC_PCLK_ENABLE, 15, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, CODEC_PCLK_ENABLE, 14, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, AUD_DEV_PCLK_ENABLE, 13, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, PWM_PCLK_ENABLE, 12, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, GPIO_PCLK_ENABLE, 11, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, I2C4_PCLK_ENABLE, 10, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, I2C3_PCLK_ENABLE, 9, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, I2C2_PCLK_ENABLE, 8, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, I2C1_PCLK_ENABLE, 7, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, I2C0_PCLK_ENABLE, 6, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, UART4_PCLK_ENABLE, 5, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, UART3_PCLK_ENABLE, 4, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, UART2_PCLK_ENABLE, 3, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, UART1_PCLK_ENABLE, 2, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, UART0_PCLK_ENABLE, 1, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG0, PCLK_ENABLE, 0, 1)
+REG32(SYSCLK_LS_CLKEN_CFG1, 0x028)
+ FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK3_PCLK_ENABLE, 7, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK2_PCLK_ENABLE, 6, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK1_PCLK_ENABLE, 5, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK0_PCLK_ENABLE, 4, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK3_CO_ENABLE, 3, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK2_CO_ENABLE, 2, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK1_CO_ENABLE, 1, 1)
+ FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK0_CO_ENABLE, 0, 1)
+REG32(SYSCLK_UART_I2C_CLKDIV_CFG, 0x02c)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C0_CLK_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C4_CLK_DIV, 27, 3)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C3_CLK_DIV, 24, 3)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C2_CLK_DIV, 21, 3)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C1_CLK_DIV, 18, 3)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C0_CLK_DIV, 15, 3)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, UART4_SCLK_DIV, 12, 3)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, UART3_SCLK_DIV, 9, 3)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, UART2_SCLK_DIV, 6, 3)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, UART1_SCLK_DIV, 3, 3)
+ FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, UART0_SCLK_DIV, 0, 3)
+REG32(SYSCLK_LS_CLKDIV_CFG, 0x030)
+ FIELD(SYSCLK_LS_CLKDIV_CFG, JAMLINK_CO_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_LS_CLKDIV_CFG, JAMLINK_CO_DIV, 23, 8)
+ FIELD(SYSCLK_LS_CLKDIV_CFG, GPIO_DBCLK_DIV, 13, 10)
+ FIELD(SYSCLK_LS_CLKDIV_CFG, ADC_CLK_DIV, 3, 10)
+ FIELD(SYSCLK_LS_CLKDIV_CFG, PCLK_DIV, 0, 3)
+/*
+ * SDK sysctl_clk_t marks offsets 0x034..0x044 reserved; the TRM defines
+ * these registers, so the TRM layout is authoritative for the v1 model.
+ */
+REG32(SYSCLK_AUDIO_CLKDIV_CFG, 0x034)
+ FIELD(SYSCLK_AUDIO_CLKDIV_CFG, AUD_DEV_CLK_FDIV_UPD, 31, 1)
+ FIELD(SYSCLK_AUDIO_CLKDIV_CFG, AUDIO_CLK_STEP, 16, 15)
+ FIELD(SYSCLK_AUDIO_CLKDIV_CFG, AUDIO_CLK_SUM, 0, 16)
+REG32(SYSCLK_CODEC_ADC_MCLKDIV_CFG, 0x038)
+ FIELD(SYSCLK_CODEC_ADC_MCLKDIV_CFG, MCLK_ADC_FDIV_UPD, 31, 1)
+ FIELD(SYSCLK_CODEC_ADC_MCLKDIV_CFG, MCLK_ADC_STEP, 14, 13)
+ FIELD(SYSCLK_CODEC_ADC_MCLKDIV_CFG, MCLK_ADC_SUM, 0, 14)
+REG32(SYSCLK_CODEC_DAC_MCLKDIV_CFG, 0x03c)
+ FIELD(SYSCLK_CODEC_DAC_MCLKDIV_CFG, MCLK_DAC_FDIV_UPD, 31, 1)
+ FIELD(SYSCLK_CODEC_DAC_MCLKDIV_CFG, MCLK_DAC_STEP, 14, 13)
+ FIELD(SYSCLK_CODEC_DAC_MCLKDIV_CFG, MCLK_DAC_SUM, 0, 14)
+REG32(SYSCLK_PDM_CLKDIV_CFG0, 0x040)
+ FIELD(SYSCLK_PDM_CLKDIV_CFG0, CLK_SUM, 0, 17)
+REG32(SYSCLK_PDM_CLKDIV_CFG1, 0x044)
+ FIELD(SYSCLK_PDM_CLKDIV_CFG1, CLK_FDIV_UPD, 31, 1)
+ FIELD(SYSCLK_PDM_CLKDIV_CFG1, CLK_STEP, 0, 16)
+REG32(SYSCLK_SYSCTL_CLKEN_CFG, 0x050)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, HDI_CLK_ENABLE, 21, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, IOMUX_PCLK_ENABLE, 20, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, STC_CLK_EN, 19, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER5_CLK_ENABLE, 18, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER4_CLK_ENABLE, 17, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER3_CLK_ENABLE, 16, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER2_CLK_ENABLE, 15, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER1_CLK_ENABLE, 14, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER0_CLK_ENABLE, 13, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER5_CLK_SEL, 12, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER4_CLK_SEL, 11, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER3_CLK_SEL, 10, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER2_CLK_SEL, 9, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER1_CLK_SEL, 8, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER0_CLK_SEL, 7, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, WDT1_CLK_ENABLE, 6, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, WDT0_CLK_ENABLE, 5, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, MAILBOX_PCLK_ENABLE, 4, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER_PCLK_ENABLE, 3, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, WDT1_PCLK_ENABLE, 2, 1)
+ FIELD(SYSCLK_SYSCTL_CLKEN_CFG, WDT0_PCLK_ENABLE, 1, 1)
+REG32(SYSCLK_TIMER_CLK_CFG, 0x054)
+ FIELD(SYSCLK_TIMER_CLK_CFG, CLK0_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_TIMER_CLK_CFG, CLK5_DIV, 15, 3)
+ FIELD(SYSCLK_TIMER_CLK_CFG, CLK4_DIV, 12, 3)
+ FIELD(SYSCLK_TIMER_CLK_CFG, CLK3_DIV, 9, 3)
+ FIELD(SYSCLK_TIMER_CLK_CFG, CLK2_DIV, 6, 3)
+ FIELD(SYSCLK_TIMER_CLK_CFG, CLK1_DIV, 3, 3)
+ FIELD(SYSCLK_TIMER_CLK_CFG, CLK0_DIV, 0, 3)
+REG32(SYSCLK_SYSCTL_CLK_DIV_CFG, 0x058)
+ FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, PCLK_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, HDI_CLK_DIV, 28, 3)
+ FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, TS_CLK_DIV, 20, 8)
+ FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, STC_CLK_DIV, 15, 5)
+ FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, WDT1_CLK_DIV, 9, 6)
+ FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, WDT0_CLK_DIV, 3, 6)
+REG32(SYSCLK_SHRM_CLK_CFG, 0x05c)
+ FIELD(SYSCLK_SHRM_CLK_CFG, PCLK_ROOT_DIV_UPD, 31, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, PCLK_ROOT_DIV, 18, 3)
+ FIELD(SYSCLK_SHRM_CLK_CFG, SRAM_CLK_SEL, 14, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, AXIM_BRIDGE_CLK_EN, 13, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, AXIM_CLK_EN, 12, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, AXIS_CLK_EN, 11, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, SRAM_ACLK_ENABLE, 10, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, NONAI2D_ACLK_ENABLE, 9, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, NONAI2D_PCLK_ENABLE, 8, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, DECOMPRESS_ACLK_ENABLE, 7, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, DECOMPRESS_PCLK_ENABLE, 6, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, GSDMA_ACLK_ENABLE, 5, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, GSDMA_PCLK_ENABLE, 4, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, PERI_DMA_ACLK_ENABLE, 3, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, PERI_DMA_PCLK_ENABLE, 2, 1)
+ FIELD(SYSCLK_SHRM_CLK_CFG, PCLK_ENABLE, 0, 1)
+REG32(SYSCLK_DDR_CLK_CFG, 0x060)
+ FIELD(SYSCLK_DDR_CLK_CFG, CORE_CLK_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_DDR_CLK_CFG, PCLK_DIV, 14, 4)
+ FIELD(SYSCLK_DDR_CLK_CFG, CORE_CLK_DIV, 10, 4)
+ FIELD(SYSCLK_DDR_CLK_CFG, PCLK_ENABLE, 9, 1)
+ FIELD(SYSCLK_DDR_CLK_CFG, BYPASSPCLK_ENABLE, 8, 1)
+ FIELD(SYSCLK_DDR_CLK_CFG, AXI4CLK_ENABLE, 7, 1)
+ FIELD(SYSCLK_DDR_CLK_CFG, AXI3CLK_ENABLE, 6, 1)
+ FIELD(SYSCLK_DDR_CLK_CFG, AXI2CLK_ENABLE, 5, 1)
+ FIELD(SYSCLK_DDR_CLK_CFG, AXI1CLK_ENABLE, 4, 1)
+ FIELD(SYSCLK_DDR_CLK_CFG, AXI0CLK_ENABLE, 3, 1)
+ FIELD(SYSCLK_DDR_CLK_CFG, CLK_ENABLE, 2, 1)
+ FIELD(SYSCLK_DDR_CLK_CFG, CLK_SEL, 0, 2)
+/*
+ * SDK sysctl_clk_t marks offsets 0x064..0x078 reserved; the TRM defines
+ * these registers, so the TRM layout is authoritative for the v1 model.
+ */
+REG32(SYSCLK_ISP_CLKEN_CFG, 0x064)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, DW_ACLK_ENABLE, 19, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, DW_HCLK_ENABLE, 18, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, MCM_CLK_ENABLE, 17, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, VSE_CLK_ENABLE, 16, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, DWE_CLK_ENABLE, 15, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, ACLK_ENABLE, 14, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, HCLK_ENABLE, 13, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CLK_ENABLE, 12, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CSI2_PCLK_ENABLE, 11, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CSI1_PCLK_ENABLE, 10, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CSI0_PCLK_ENABLE, 9, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CSI2_PIXELCLK_ENABLE, 8, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CSI1_PIXELCLK_ENABLE, 7, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CSI0_PIXELCLK_ENABLE, 6, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, DPHY_PCLK_ENABLE, 5, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CFG2_CLK_ENABLE, 4, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CFG1_CLK_ENABLE, 3, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CFG0_CLK_ENABLE, 2, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, PCLK_ENABLE, 1, 1)
+ FIELD(SYSCLK_ISP_CLKEN_CFG, CSIPHY_CFGCLK_ENABLE, 0, 1)
+REG32(SYSCLK_ISP_CLKDIV_CFG, 0x068)
+ FIELD(SYSCLK_ISP_CLKDIV_CFG, CFG_CLK_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_ISP_CLKDIV_CFG, CLK_SEL, 29, 1)
+ FIELD(SYSCLK_ISP_CLKDIV_CFG, CLK_DIV, 26, 3)
+ FIELD(SYSCLK_ISP_CLKDIV_CFG, PCLK_DIV, 23, 3)
+ FIELD(SYSCLK_ISP_CLKDIV_CFG, CSI2_PIXEL_CLK_DIV, 17, 6)
+ FIELD(SYSCLK_ISP_CLKDIV_CFG, CSI1_PIXEL_CLK_DIV, 11, 6)
+ FIELD(SYSCLK_ISP_CLKDIV_CFG, CSI0_PIXEL_CLK_DIV, 5, 6)
+ FIELD(SYSCLK_ISP_CLKDIV_CFG, CFG_CLK_DIV, 0, 5)
+REG32(SYSCLK_MCLK_CFG, 0x06c)
+ FIELD(SYSCLK_MCLK_CFG, MCLK0_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_MCLK_CFG, MCLK2_DIV, 19, 5)
+ FIELD(SYSCLK_MCLK_CFG, MCLK2_SEL, 17, 2)
+ FIELD(SYSCLK_MCLK_CFG, MCLK1_DIV, 12, 5)
+ FIELD(SYSCLK_MCLK_CFG, MCLK1_SEL, 10, 2)
+ FIELD(SYSCLK_MCLK_CFG, MCLK0_DIV, 5, 5)
+ FIELD(SYSCLK_MCLK_CFG, MCLK0_SEL, 3, 2)
+ FIELD(SYSCLK_MCLK_CFG, MCLK2_ENABLE, 2, 1)
+ FIELD(SYSCLK_MCLK_CFG, MCLK1_ENABLE, 1, 1)
+ FIELD(SYSCLK_MCLK_CFG, MCLK0_ENABLE, 0, 1)
+REG32(SYSCLK_DPU_CLK_CFG, 0x070)
+ FIELD(SYSCLK_DPU_CLK_CFG, CLK_DIV_UPD, 31, 1)
+ FIELD(SYSCLK_DPU_CLK_CFG, PCLK_DIV, 7, 3)
+ FIELD(SYSCLK_DPU_CLK_CFG, CLK_DIV, 3, 4)
+ FIELD(SYSCLK_DPU_CLK_CFG, PCLK_ENABLE, 2, 1)
+ FIELD(SYSCLK_DPU_CLK_CFG, ACLK_ENABLE, 1, 1)
+ FIELD(SYSCLK_DPU_CLK_CFG, CLK_ENABLE, 0, 1)
+REG32(SYSCLK_VO_CLK_CFG, 0x074)
+ FIELD(SYSCLK_VO_CLK_CFG, ACLK_GPU_EN, 12, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, ACLK_VO_EN, 11, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, HCLK_GPU_EN, 10, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, PCLK_DSI_PHY_EN, 9, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, PCLK_DSI_ENABLE, 8, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, PCLK_VO_ENABLE, 7, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, CLK_GPU_ENABLE, 6, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, CLKEXT_ENABLE, 5, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, CFGCLK_ENABLE, 4, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, REFCLK_ENABLE, 3, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, DPIPCLK_ENABLE, 2, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, ACLK_ENABLE, 1, 1)
+ FIELD(SYSCLK_VO_CLK_CFG, HCLK_ENABLE, 0, 1)
+REG32(SYSCLK_DISP_CLK_DIV, 0x078)
+ FIELD(SYSCLK_DISP_CLK_DIV, HCLK_ROOT_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_DISP_CLK_DIV, CLK_GPU_DIV, 20, 4)
+ FIELD(SYSCLK_DISP_CLK_DIV, CLKEXT_DIV, 16, 4)
+ FIELD(SYSCLK_DISP_CLK_DIV, CFGCLK_DIV, 11, 5)
+ FIELD(SYSCLK_DISP_CLK_DIV, DPIPCLK_DIV, 3, 8)
+ FIELD(SYSCLK_DISP_CLK_DIV, HCLK_ROOT_DIV, 0, 3)
+REG32(SYSCLK_SEC_CLK_DIV, 0x080)
+ FIELD(SYSCLK_SEC_CLK_DIV, PCLK_DIV_UPD, 31, 1)
+ FIELD(SYSCLK_SEC_CLK_DIV, ACLK_DIV, 11, 3)
+ FIELD(SYSCLK_SEC_CLK_DIV, FIXCLK_DIV, 6, 5)
+ FIELD(SYSCLK_SEC_CLK_DIV, FIXCLK_ENABLE, 5, 1)
+ FIELD(SYSCLK_SEC_CLK_DIV, ACLK_ENABLE, 4, 1)
+ FIELD(SYSCLK_SEC_CLK_DIV, PCLK_DIV, 1, 3)
+ FIELD(SYSCLK_SEC_CLK_DIV, PCLK_ENABLE, 0, 1)
+REG32(SYSCLK_USB_TEST_CLK_DIV, 0x100)
+ FIELD(SYSCLK_USB_TEST_CLK_DIV, CLK480_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_USB_TEST_CLK_DIV, CLK100_DIV, 4, 3)
+ FIELD(SYSCLK_USB_TEST_CLK_DIV, CLK480_DIV, 1, 3)
+ FIELD(SYSCLK_USB_TEST_CLK_DIV, TEST_CLK_ENABLE, 0, 1)
+REG32(SYSCLK_DPHY_TEST_CLK_DIV, 0x104)
+ FIELD(SYSCLK_DPHY_TEST_CLK_DIV, TEST_CLK_CDIV_UPD, 31, 1)
+ FIELD(SYSCLK_DPHY_TEST_CLK_DIV, TEST_CLK_DIV, 1, 4)
+ FIELD(SYSCLK_DPHY_TEST_CLK_DIV, TEST_CLK_ENABLE, 0, 1)
+/*
+ * The TRM v0.3.1 sysclk summary ends at 0x104. Linux and the SDK both
+ * access SPI2AXI_CLK_DIV at 0x108, so v1 preserves this software ABI
+ * exception.
+ */
+REG32(SYSCLK_SPI2AXI_CLK_DIV, 0x108)
+ FIELD(SYSCLK_SPI2AXI_CLK_DIV, CLK_DIV_UPD, 31, 1)
+ FIELD(SYSCLK_SPI2AXI_CLK_DIV, CLK_DIV, 1, 3)
+ FIELD(SYSCLK_SPI2AXI_CLK_DIV, CLK_ENABLE, 0, 1)
+
+typedef struct K230PllRegDesc {
+ hwaddr offset;
+ const char *name;
+ uint32_t reset[K230_PLL_COUNT];
+ uint32_t rw_mask;
+ uint32_t ro_mask;
+ uint32_t w1t_mask;
+ uint8_t write_enable_shift;
+ uint32_t write_enable_mask;
+} K230PllRegDesc;
+
+typedef struct K230SysclkRegDesc {
+ hwaddr offset;
+ const char *name;
+ uint32_t reset;
+ uint32_t rw_mask;
+ uint32_t w1t_mask;
+} K230SysclkRegDesc;
+
+static const K230PllRegDesc k230_pll_regs[] = {
+ {
+ .offset = A_CMU_CFG0,
+ .name = "PLLx_CFG0",
+ .reset = {
+ 0x0102018f, 0x00000062, 0x00070378, 0x0102018f,
+ },
+ .rw_mask = PLL_CFG0_RW_MASK,
+ },
+ {
+ .offset = A_CMU_CFG1,
+ .name = "PLLx_CFG1",
+ .reset = {
+ 0x000200c7, 0x00020031, 0x000201bb, 0x000200c7,
+ },
+ .rw_mask = PLL_CFG1_RW_MASK,
+ },
+ {
+ .offset = A_CMU_CTL,
+ .name = "PLLx_CTL",
+ .reset = {
+ 0x00000034, 0x00000034, 0x00000034, 0x00000074,
+ },
+ .rw_mask = PLL_CTL_RW_MASK,
+ .w1t_mask = PLL_CTL_W1T_MASK,
+ .write_enable_shift = 16,
+ .write_enable_mask = PLL_CTL_LOW_MASK,
+ },
+ {
+ .offset = A_CMU_STAT,
+ .name = "PLLx_STAT",
+ .reset = {
+ 0x00000021, 0x00000021, 0x00000021, 0x00000021,
+ },
+ .ro_mask = PLL_STAT_RO_MASK,
+ },
+};
+
+#define SYSCLK_REG(_reg, _name, _reset, _rw, _w1t) \
+ { .offset = A_ ## _reg, .name = _name, .reset = _reset, \
+ .rw_mask = (_rw), .w1t_mask = (_w1t) }
+
+static const K230SysclkRegDesc k230_sysclk_regs[] = {
+ SYSCLK_REG(SYSCLK_CPU0_CLK_CFG, "CPU0_CLK_CFG", 0x0000e65f,
+ 0x0003ffdf, R_SYSCLK_CPU0_CLK_CFG_CORE_CLK_ROOT_GDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_CPU1_CLK_CFG, "CPU1_CLK_CFG", 0x0009900d,
+ 0x000f803f, R_SYSCLK_CPU1_CLK_CFG_CORE_CLK_DIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_AI_CLK_CFG, "AI_CLK_CFG", 0x0000043d,
+ 0x0000043d, R_SYSCLK_AI_CLK_CFG_CLK_DIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_VPU_CLK_CFG, "VPU_CLK_CFG", 0x00000c7f,
+ 0x00007fff, R_SYSCLK_VPU_CLK_CFG_CLK_GDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_PMU_CLK_CFG, "PMU_CLK_CFG", 0x00000001,
+ 0x00000001, 0),
+ SYSCLK_REG(SYSCLK_HS_CLKEN_CFG, "HS_CLKEN_CFG", 0x7f7fffff,
+ 0x7fffffff, 0),
+ SYSCLK_REG(SYSCLK_HS_SDCLK_CFG, "HS_SDCLK_CFG", 0x000b9248,
+ 0x000fffff, R_SYSCLK_HS_SDCLK_CFG_ACLK_ROOT_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_HS_SPI_CFG, "HS_SPI_CFG", 0x00039048,
+ 0x0007fff8, R_SYSCLK_HS_SPI_CFG_SSI0_ACLK_ROOT_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_LS_CLKEN_CFG0, "LS_CLKEN_CFG0", 0xffffffff,
+ 0xffffffff, 0),
+ SYSCLK_REG(SYSCLK_LS_CLKEN_CFG1, "LS_CLKEN_CFG1", 0x000000ff,
+ 0x000000ff, 0),
+ SYSCLK_REG(SYSCLK_UART_I2C_CLKDIV_CFG, "UART_I2C_CLKDIV_CFG",
+ 0x1b6d9249, 0x3fffffff,
+ R_SYSCLK_UART_I2C_CLKDIV_CFG_I2C0_CLK_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_LS_CLKDIV_CFG, "LS_CLKDIV_CFG", 0x01dda0c3,
+ 0x7fffffff, R_SYSCLK_LS_CLKDIV_CFG_JAMLINK_CO_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_AUDIO_CLKDIV_CFG, "AUDIO_CLKDIV_CFG", 0x01b9f424,
+ 0x7fffffff, R_SYSCLK_AUDIO_CLKDIV_CFG_AUD_DEV_CLK_FDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_CODEC_ADC_MCLKDIV_CFG, "CODEC_ADC_MCLKDIV_CFG",
+ 0x006e7d09, 0x07ffffff,
+ R_SYSCLK_CODEC_ADC_MCLKDIV_CFG_MCLK_ADC_FDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_CODEC_DAC_MCLKDIV_CFG, "CODEC_DAC_MCLKDIV_CFG",
+ 0x006e7d09, 0x07ffffff,
+ R_SYSCLK_CODEC_DAC_MCLKDIV_CFG_MCLK_DAC_FDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_PDM_CLKDIV_CFG0, "PDM_CLKDIV_CFG0", 0x0000f424,
+ 0x0001ffff, 0),
+ SYSCLK_REG(SYSCLK_PDM_CLKDIV_CFG1, "PDM_CLKDIV_CFG1", 0x000001b9,
+ 0x0000ffff, R_SYSCLK_PDM_CLKDIV_CFG1_CLK_FDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_SYSCTL_CLKEN_CFG, "SYSCTL_CLKEN_CFG", 0x003ffffe,
+ 0x003ffffe, 0),
+ SYSCLK_REG(SYSCLK_TIMER_CLK_CFG, "TIMER_CLK_CFG", 0x0003ffff,
+ 0x0003ffff, R_SYSCLK_TIMER_CLK_CFG_CLK0_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_SYSCTL_CLK_DIV_CFG, "SYSCTL_CLK_DIV_CFG", 0x1efabef9,
+ 0x7ffffff8, R_SYSCLK_SYSCTL_CLK_DIV_CFG_PCLK_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_SHRM_CLK_CFG, "SHRM_CLK_CFG", 0x000c7ffd,
+ 0x001c7ffd, R_SYSCLK_SHRM_CLK_CFG_PCLK_ROOT_DIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_DDR_CLK_CFG, "DDR_CLK_CFG", 0x000043fd,
+ 0x0003ffff, R_SYSCLK_DDR_CLK_CFG_CORE_CLK_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_ISP_CLKEN_CFG, "ISP_CLKEN_CFG", 0x000fffff,
+ 0x000fffff, 0),
+ SYSCLK_REG(SYSCLK_ISP_CLKDIV_CFG, "ISP_CLKDIV_CFG", 0x00820835,
+ 0x3fffffff, R_SYSCLK_ISP_CLKDIV_CFG_CFG_CLK_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_MCLK_CFG, "MCLK_CFG", 0x003a74ef,
+ 0x00ffffff, R_SYSCLK_MCLK_CFG_MCLK0_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_DPU_CLK_CFG, "DPU_CLK_CFG", 0x000001ff,
+ 0x000003ff, R_SYSCLK_DPU_CLK_CFG_CLK_DIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_VO_CLK_CFG, "VO_CLK_CFG", 0x00001fff,
+ 0x00001fff, 0),
+ SYSCLK_REG(SYSCLK_DISP_CLK_DIV, "DISP_CLK_DIV", 0x0000a83b,
+ 0x00ffffff, R_SYSCLK_DISP_CLK_DIV_HCLK_ROOT_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_SEC_CLK_DIV, "SEC_CLK_DIV", 0x000002f3,
+ 0x00003fff, R_SYSCLK_SEC_CLK_DIV_PCLK_DIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_USB_TEST_CLK_DIV, "USB_TEST_CLK_DIV", 0x00000039,
+ 0x0000007f, R_SYSCLK_USB_TEST_CLK_DIV_CLK480_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_DPHY_TEST_CLK_DIV, "DPHY_TEST_CLK_DIV", 0x00000009,
+ 0x0000001f,
+ R_SYSCLK_DPHY_TEST_CLK_DIV_TEST_CLK_CDIV_UPD_MASK),
+ SYSCLK_REG(SYSCLK_SPI2AXI_CLK_DIV, "SPI2AXI_CLK_DIV", 0x00000007,
+ 0x0000000f,
+ R_SYSCLK_SPI2AXI_CLK_DIV_CLK_DIV_UPD_MASK),
+};
+
+#undef SYSCLK_REG
+
+static const K230PllRegDesc *k230_pll_desc(hwaddr addr,
+ unsigned *pll_index)
+{
+ unsigned index = addr / K230_PLL_STRIDE;
+ hwaddr offset = addr % K230_PLL_STRIDE;
+
+ if (index >= K230_PLL_COUNT) {
+ return NULL;
+ }
+
+ for (unsigned i = 0; i < ARRAY_SIZE(k230_pll_regs); i++) {
+ if (k230_pll_regs[i].offset == offset) {
+ *pll_index = index;
+ return &k230_pll_regs[i];
+ }
+ }
+
+ return NULL;
+}
+
+static uint32_t k230_pll_value(const K230PllState *pll, hwaddr offset)
+{
+ switch (offset) {
+ case A_CMU_CFG0:
+ return pll->cfg0;
+ case A_CMU_CFG1:
+ return pll->cfg1;
+ case A_CMU_CTL:
+ return pll->ctl & PLL_CTL_RW_MASK;
+ case A_CMU_STAT:
+ return pll->stat & PLL_STAT_RO_MASK;
+ default:
+ return 0;
+ }
+}
+
+static uint32_t *k230_pll_storage(K230PllState *pll, hwaddr offset)
+{
+ switch (offset) {
+ case A_CMU_CFG0:
+ return &pll->cfg0;
+ case A_CMU_CFG1:
+ return &pll->cfg1;
+ case A_CMU_CTL:
+ return &pll->ctl;
+ default:
+ return NULL;
+ }
+}
+
+static uint32_t k230_merge_rw(uint32_t old_value, uint32_t write_value,
+ uint32_t rw_mask)
+{
+ return (old_value & ~rw_mask) | (write_value & rw_mask);
+}
+
+static void k230_cmu_log_undefined_access(const char *region, bool write,
+ hwaddr addr, uint32_t value)
+{
+ if (write) {
+ trace_k230_cmu_undefined_write(region, addr, value);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to undefined %s offset 0x%" PRIx64
+ " (value 0x%08" PRIx32 ")\n",
+ TYPE_K230_CMU, region, addr, value);
+ } else {
+ trace_k230_cmu_undefined_read(region, addr);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: read from undefined %s offset 0x%" PRIx64 "\n",
+ TYPE_K230_CMU, region, addr);
+ }
+}
+
+static uint64_t k230_pll_read(void *opaque, hwaddr addr, unsigned size)
+{
+ K230CmuState *s = K230_CMU(opaque);
+ unsigned index;
+ const K230PllRegDesc *desc;
+ uint32_t value;
+
+ if (size != sizeof(uint32_t)) {
+ return 0;
+ }
+
+ desc = k230_pll_desc(addr, &index);
+ if (!desc) {
+ k230_cmu_log_undefined_access("PLL", false, addr, 0);
+ return 0;
+ }
+
+ value = k230_pll_value(&s->pll[index], desc->offset);
+ trace_k230_cmu_pll_read(index, desc->offset, value);
+ return value;
+}
+
+static void k230_pll_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned size)
+{
+ K230CmuState *s = K230_CMU(opaque);
+ unsigned index;
+ const K230PllRegDesc *desc;
+ K230PllState *pll;
+ uint32_t *storage;
+ uint32_t write_value = value;
+ uint32_t old_value;
+ uint32_t new_value;
+
+ if (size != sizeof(uint32_t)) {
+ return;
+ }
+
+ desc = k230_pll_desc(addr, &index);
+ if (!desc) {
+ k230_cmu_log_undefined_access("PLL", true, addr, write_value);
+ return;
+ }
+
+ pll = &s->pll[index];
+ old_value = k230_pll_value(pll, desc->offset);
+
+ if (desc->offset == A_CMU_STAT) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to read-only PLL%u STAT\n",
+ TYPE_K230_CMU, index);
+ return;
+ }
+
+ if (desc->offset == A_CMU_CTL) {
+ uint32_t low = write_value & 0xffff;
+ uint32_t enabled = (write_value >> desc->write_enable_shift) &
+ desc->write_enable_mask;
+ uint32_t old_status = pll->stat;
+ bool powerdown = (enabled & BIT(0)) && (low & BIT(0));
+ bool init = (enabled & BIT(1)) && (low & BIT(1));
+
+ pll->ctl = k230_merge_rw(pll->ctl, low,
+ enabled & desc->rw_mask);
+
+ if (powerdown && init) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: PLL%u CTL powerdown/init conflict\n",
+ TYPE_K230_CMU, index);
+ }
+
+ if (powerdown) {
+ pll->stat = 0;
+ }
+ if (init) {
+ pll->stat = 0x00000021;
+ }
+ if (old_status != pll->stat) {
+ trace_k230_cmu_pll_status(index, old_status, pll->stat);
+ }
+ new_value = k230_pll_value(pll, desc->offset);
+ trace_k230_cmu_pll_write(index, desc->offset, write_value,
+ old_value, new_value);
+ return;
+ }
+
+ storage = k230_pll_storage(pll, desc->offset);
+ if (!storage) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: PLL%u %s has no writable storage\n",
+ TYPE_K230_CMU, index, desc->name);
+ return;
+ }
+ *storage = k230_merge_rw(*storage, write_value, desc->rw_mask);
+ new_value = k230_pll_value(pll, desc->offset);
+ trace_k230_cmu_pll_write(index, desc->offset, write_value,
+ old_value, new_value);
+}
+
+static const K230SysclkRegDesc *k230_sysclk_desc(hwaddr addr,
+ unsigned *index)
+{
+ for (unsigned i = 0; i < ARRAY_SIZE(k230_sysclk_regs); i++) {
+ if (k230_sysclk_regs[i].offset == addr) {
+ *index = i;
+ return &k230_sysclk_regs[i];
+ }
+ }
+
+ return NULL;
+}
+
+static uint64_t k230_sysclk_read(void *opaque, hwaddr addr, unsigned size)
+{
+ K230CmuState *s = K230_CMU(opaque);
+ unsigned index;
+ uint32_t value;
+
+ if (size != sizeof(uint32_t)) {
+ return 0;
+ }
+
+ if (!k230_sysclk_desc(addr, &index)) {
+ k230_cmu_log_undefined_access("sysclk", false, addr, 0);
+ return 0;
+ }
+
+ value = s->sysclk[index];
+ trace_k230_cmu_sysclk_read(addr, value);
+ return value;
+}
+
+static void k230_sysclk_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned size)
+{
+ K230CmuState *s = K230_CMU(opaque);
+ const K230SysclkRegDesc *desc;
+ unsigned index;
+ uint32_t old_value;
+ uint32_t new_value;
+
+ if (size != sizeof(uint32_t)) {
+ return;
+ }
+
+ desc = k230_sysclk_desc(addr, &index);
+ if (!desc) {
+ k230_cmu_log_undefined_access("sysclk", true, addr, value);
+ return;
+ }
+
+ old_value = s->sysclk[index];
+ new_value = k230_merge_rw(old_value, value, desc->rw_mask);
+ s->sysclk[index] = new_value;
+ trace_k230_cmu_sysclk_write(addr, value, old_value, new_value);
+}
+
+static const MemoryRegionOps k230_pll_ops = {
+ .read = k230_pll_read,
+ .write = k230_pll_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+};
+
+static const MemoryRegionOps k230_sysclk_ops = {
+ .read = k230_sysclk_read,
+ .write = k230_sysclk_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+};
+
+static void k230_cmu_reset_hold(Object *obj, ResetType type)
+{
+ K230CmuState *s = K230_CMU(obj);
+
+ for (unsigned index = 0; index < K230_PLL_COUNT; index++) {
+ s->pll[index].cfg0 = k230_pll_regs[0].reset[index];
+ s->pll[index].cfg1 = k230_pll_regs[1].reset[index];
+ s->pll[index].ctl = k230_pll_regs[2].reset[index];
+ s->pll[index].stat = k230_pll_regs[3].reset[index];
+ }
+
+ for (unsigned index = 0; index < ARRAY_SIZE(k230_sysclk_regs); index++) {
+ s->sysclk[index] = k230_sysclk_regs[index].reset;
+ }
+}
+
+static void k230_cmu_init(Object *obj)
+{
+ K230CmuState *s = K230_CMU(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&s->pll_mmio, obj, &k230_pll_ops, s,
+ "k230-cmu-pll", K230_CMU_SIZE);
+ memory_region_init_io(&s->sysclk_mmio, obj, &k230_sysclk_ops, s,
+ "k230-cmu-sysclk", K230_SYSCLK_SIZE);
+ sysbus_init_mmio(sbd, &s->pll_mmio);
+ sysbus_init_mmio(sbd, &s->sysclk_mmio);
+}
+
+static const VMStateDescription vmstate_k230_pll = {
+ .name = "riscv.k230.cmu/pll",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(cfg0, K230PllState),
+ VMSTATE_UINT32(cfg1, K230PllState),
+ VMSTATE_UINT32(ctl, K230PllState),
+ VMSTATE_UINT32(stat, K230PllState),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static const VMStateDescription vmstate_k230_cmu = {
+ .name = TYPE_K230_CMU,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_STRUCT_ARRAY(pll, K230CmuState, K230_PLL_COUNT, 1,
+ vmstate_k230_pll, K230PllState),
+ VMSTATE_UINT32_ARRAY(sysclk, K230CmuState, K230_SYSCLK_REG_COUNT),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static void k230_cmu_class_init(ObjectClass *klass, const void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ rc->phases.hold = k230_cmu_reset_hold;
+ dc->vmsd = &vmstate_k230_cmu;
+}
+
+static const TypeInfo k230_cmu_info = {
+ .name = TYPE_K230_CMU,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(K230CmuState),
+ .instance_init = k230_cmu_init,
+ .class_init = k230_cmu_class_init,
+};
+
+static void k230_cmu_register_types(void)
+{
+ type_register_static(&k230_cmu_info);
+}
+
+type_init(k230_cmu_register_types)
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 23265f6035..5f1c9c439d 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -28,6 +28,7 @@ system_ss.add(when: 'CONFIG_IOSB', if_true: files('iosb.c'))
system_ss.add(when: 'CONFIG_VIRT_CTRL', if_true: files('virt_ctrl.c'))
# RISC-V devices
+system_ss.add(when: 'CONFIG_K230_CMU', if_true: files('k230_cmu.c'))
system_ss.add(when: 'CONFIG_MCHP_PFSOC_DMC', if_true: files('mchp_pfsoc_dmc.c'))
system_ss.add(when: 'CONFIG_MCHP_PFSOC_IOSCB', if_true: files('mchp_pfsoc_ioscb.c'))
system_ss.add(when: 'CONFIG_MCHP_PFSOC_SYSREG', if_true: files('mchp_pfsoc_sysreg.c'))
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index c9a868b3ef..bcedea6954 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -66,6 +66,15 @@ ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 0x%08x"
ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = 0x%02x"
ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= 0x%02x"
+# k230_cmu.c
+k230_cmu_pll_read(unsigned int pll, uint64_t offset, uint32_t value) "PLL%u read offset=0x%"PRIx64" value=0x%08"PRIx32
+k230_cmu_pll_write(unsigned int pll, uint64_t offset, uint32_t value, uint32_t old_value, uint32_t new_value) "PLL%u write offset=0x%"PRIx64" value=0x%08"PRIx32" old=0x%08"PRIx32" new=0x%08"PRIx32
+k230_cmu_pll_status(unsigned int pll, uint32_t old_status, uint32_t new_status) "PLL%u status old=0x%08"PRIx32" new=0x%08"PRIx32
+k230_cmu_sysclk_read(uint64_t offset, uint32_t value) "sysclk read offset=0x%"PRIx64" value=0x%08"PRIx32
+k230_cmu_sysclk_write(uint64_t offset, uint32_t value, uint32_t old_value, uint32_t new_value) "sysclk write offset=0x%"PRIx64" value=0x%08"PRIx32" old=0x%08"PRIx32" new=0x%08"PRIx32
+k230_cmu_undefined_read(const char *region, uint64_t offset) "%s undefined read offset=0x%"PRIx64
+k230_cmu_undefined_write(const char *region, uint64_t offset, uint32_t value) "%s undefined write offset=0x%"PRIx64" value=0x%08"PRIx32
+
# empty_slot.c
empty_slot_write(uint64_t addr, unsigned width, uint64_t value, unsigned size, const char *name) "wr addr:0x%04"PRIx64" data:0x%0*"PRIx64" size %u [%s]"
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index de37c08cae..d2e365fd70 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -161,4 +161,5 @@ config K230
select RISCV_IMSIC
select SERIAL_MM
select UNIMP
+ select K230_CMU
select K230_WDT
diff --git a/include/hw/misc/k230_cmu.h b/include/hw/misc/k230_cmu.h
new file mode 100644
index 0000000000..e373ec0aa0
--- /dev/null
+++ b/include/hw/misc/k230_cmu.h
@@ -0,0 +1,58 @@
+/*
+ * Kendryte K230 Clock Management Unit
+ *
+ * Copyright (c) 2026 Simon Law <0860734llx@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Defines the K230 PLL and system-clock register protocol model. It keeps
+ * software-visible register state but does not provide cycle-accurate clocks
+ * or propagate QEMU Clock signals.
+ *
+ * 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_MISC_K230_CMU_H
+#define HW_MISC_K230_CMU_H
+
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_K230_CMU "riscv.k230.cmu"
+OBJECT_DECLARE_SIMPLE_TYPE(K230CmuState, K230_CMU)
+
+#define K230_PLL_COUNT 4
+#define K230_PLL_STRIDE 0x10
+#define K230_SYSCLK_REG_COUNT 32
+
+#define K230_CMU_BASE_ADDR 0x91102000
+#define K230_CMU_SIZE 0x40
+
+#define K230_SYSCLK_BASE_ADDR 0x91100000
+#define K230_SYSCLK_SIZE 0x1000
+
+typedef struct K230PllState {
+ uint32_t cfg0;
+ uint32_t cfg1;
+ uint32_t ctl;
+ uint32_t stat;
+} K230PllState;
+
+typedef struct K230CmuState {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ MemoryRegion pll_mmio;
+ MemoryRegion sysclk_mmio;
+
+ /* Properties */
+ K230PllState pll[K230_PLL_COUNT];
+ uint32_t sysclk[K230_SYSCLK_REG_COUNT];
+} K230CmuState;
+
+#endif /* HW_MISC_K230_CMU_H */
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/4] hw/riscv: connect the K230 CMU
2026-08-09 6:20 [PATCH 0/4] Kendryte K230 CMU register model Simon Law
2026-08-09 6:20 ` [PATCH 1/4] hw/misc: model K230 CMU registers Simon Law
@ 2026-08-09 6:20 ` Simon Law
2026-08-09 6:20 ` [PATCH 3/4] tests/qtest: add K230 CMU coverage Simon Law
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Simon Law @ 2026-08-09 6:20 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, chao.liu, palmer, alistair.francis, liwei1518,
daniel.barboza, zhiwei_liu, pierrick.bouvier
Signed-off-by: Simon Law <0860734llx@gmail.com>
---
hw/riscv/k230.c | 14 +++++++++-----
include/hw/riscv/k230.h | 2 ++
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
index 656f28190c..e50062f7df 100644
--- a/hw/riscv/k230.c
+++ b/hw/riscv/k230.c
@@ -108,6 +108,7 @@ 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-cmu", &s->cmu, TYPE_K230_CMU);
object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT);
object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT);
@@ -206,6 +207,12 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0,
qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ));
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->cmu), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->cmu), 0, K230_CMU_BASE_ADDR);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->cmu), 1, K230_SYSCLK_BASE_ADDR);
+
/* unimplemented devices */
create_unimplemented_device("kpu.l2-cache",
memmap[K230_DEV_KPU_L2_CACHE].base,
@@ -265,14 +272,11 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
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("boot", K230_CMU_BASE_ADDR + K230_CMU_SIZE,
+ memmap[K230_DEV_BOOT].size - K230_CMU_SIZE);
create_unimplemented_device("pwr", memmap[K230_DEV_PWR].base,
memmap[K230_DEV_PWR].size);
diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
index 592e1c26bf..5e1579c5b3 100644
--- a/include/hw/riscv/k230.h
+++ b/include/hw/riscv/k230.h
@@ -16,6 +16,7 @@
#define HW_K230_H
#include "hw/core/boards.h"
+#include "hw/misc/k230_cmu.h"
#include "hw/riscv/riscv_hart.h"
#include "hw/watchdog/k230_wdt.h"
@@ -32,6 +33,7 @@ typedef struct K230SoCState {
/*< public >*/
RISCVHartArrayState c908_cpu; /* Small core */
+ K230CmuState cmu;
K230WdtState wdt[2];
MemoryRegion sram;
MemoryRegion bootrom;
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/4] tests/qtest: add K230 CMU coverage
2026-08-09 6:20 [PATCH 0/4] Kendryte K230 CMU register model Simon Law
2026-08-09 6:20 ` [PATCH 1/4] hw/misc: model K230 CMU registers Simon Law
2026-08-09 6:20 ` [PATCH 2/4] hw/riscv: connect the K230 CMU Simon Law
@ 2026-08-09 6:20 ` Simon Law
2026-08-09 6:20 ` [PATCH 4/4] docs/system/riscv: document K230 CMU support Simon Law
2026-08-14 7:53 ` [PATCH 0/4] Kendryte K230 CMU register model Bin Meng
4 siblings, 0 replies; 8+ messages in thread
From: Simon Law @ 2026-08-09 6:20 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, chao.liu, palmer, alistair.francis, liwei1518,
daniel.barboza, zhiwei_liu, pierrick.bouvier
Signed-off-by: Simon Law <0860734llx@gmail.com>
---
tests/qtest/k230-cmu-test.c | 310 ++++++++++++++++++++++++++++++++++++++++++++
tests/qtest/meson.build | 3 +-
2 files changed, 312 insertions(+), 1 deletion(-)
diff --git a/tests/qtest/k230-cmu-test.c b/tests/qtest/k230-cmu-test.c
new file mode 100644
index 0000000000..2be6400cd8
--- /dev/null
+++ b/tests/qtest/k230-cmu-test.c
@@ -0,0 +1,310 @@
+/*
+ * QTest testcase for Kendryte K230 Clock Management Unit
+ *
+ * Copyright (c) 2026 Simon Law <0860734llx@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * K230 Technical Reference Manual V0.3.1 (2024-11-18), CMU chapter.
+ *
+ * The reset and mask oracle in this file is intentionally independent from
+ * hw/misc/k230_cmu.c, so a descriptor-table error cannot mask itself.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "libqtest.h"
+
+#define K230_PLL_BASE 0x91102000
+#define K230_SYSCLK_BASE 0x91100000
+#define K230_PLL_COUNT 4
+#define K230_PLL_STRIDE 0x10
+
+#define PLL_CFG0 0x0
+#define PLL_CFG1 0x4
+#define PLL_CTL 0x8
+#define PLL_STAT 0xc
+
+#define PLL_CFG0_RW_MASK 0x0f3f1fff
+#define PLL_CFG1_RW_MASK 0x000f0fff
+#define PLL_CTL_RW_MASK 0x00000ff4
+
+typedef struct K230SysclkOracle {
+ uint32_t offset;
+ uint32_t reset;
+ uint32_t rw_mask;
+ uint32_t w1t_mask;
+} K230SysclkOracle;
+
+static const uint32_t pll_reset[K230_PLL_COUNT][4] = {
+ { 0x0102018f, 0x000200c7, 0x00000034, 0x00000021 },
+ { 0x00000062, 0x00020031, 0x00000034, 0x00000021 },
+ { 0x00070378, 0x000201bb, 0x00000034, 0x00000021 },
+ { 0x0102018f, 0x000200c7, 0x00000074, 0x00000021 },
+};
+
+static const K230SysclkOracle sysclk_oracle[] = {
+ { 0x000, 0x0000e65f, 0x0003ffdf, BIT(31) },
+ { 0x004, 0x0009900d, 0x000f803f, BIT(31) },
+ { 0x008, 0x0000043d, 0x0000043d, BIT(31) },
+ { 0x00c, 0x00000c7f, 0x00007fff, BIT(31) },
+ { 0x010, 0x00000001, 0x00000001, 0 },
+ { 0x018, 0x7f7fffff, 0x7fffffff, 0 },
+ { 0x01c, 0x000b9248, 0x000fffff, BIT(31) },
+ { 0x020, 0x00039048, 0x0007fff8, BIT(31) },
+ { 0x024, 0xffffffff, 0xffffffff, 0 },
+ { 0x028, 0x000000ff, 0x000000ff, 0 },
+ { 0x02c, 0x1b6d9249, 0x3fffffff, BIT(31) },
+ { 0x030, 0x01dda0c3, 0x7fffffff, BIT(31) },
+ { 0x034, 0x01b9f424, 0x7fffffff, BIT(31) },
+ { 0x038, 0x006e7d09, 0x07ffffff, BIT(31) },
+ { 0x03c, 0x006e7d09, 0x07ffffff, BIT(31) },
+ { 0x040, 0x0000f424, 0x0001ffff, 0 },
+ { 0x044, 0x000001b9, 0x0000ffff, BIT(31) },
+ { 0x050, 0x003ffffe, 0x003ffffe, 0 },
+ { 0x054, 0x0003ffff, 0x0003ffff, BIT(31) },
+ { 0x058, 0x1efabef9, 0x7ffffff8, BIT(31) },
+ { 0x05c, 0x000c7ffd, 0x001c7ffd, BIT(31) },
+ { 0x060, 0x000043fd, 0x0003ffff, BIT(31) },
+ { 0x064, 0x000fffff, 0x000fffff, 0 },
+ { 0x068, 0x00820835, 0x3fffffff, BIT(31) },
+ { 0x06c, 0x003a74ef, 0x00ffffff, BIT(31) },
+ { 0x070, 0x000001ff, 0x000003ff, BIT(31) },
+ { 0x074, 0x00001fff, 0x00001fff, 0 },
+ { 0x078, 0x0000a83b, 0x00ffffff, BIT(31) },
+ { 0x080, 0x000002f3, 0x00003fff, BIT(31) },
+ { 0x100, 0x00000039, 0x0000007f, BIT(31) },
+ { 0x104, 0x00000009, 0x0000001f, BIT(31) },
+ /* TRM summary stops at 0x104; SDK/Linux ABI requires SPI2AXI at 0x108. */
+ { 0x108, 0x00000007, 0x0000000f, BIT(31) },
+};
+
+static QTestState *k230_cmu_start(void)
+{
+ return qtest_init("-machine k230");
+}
+
+static uint32_t pll_addr(unsigned index, uint32_t offset)
+{
+ g_assert_cmpuint(index, <, K230_PLL_COUNT);
+ return K230_PLL_BASE + index * K230_PLL_STRIDE + offset;
+}
+
+static uint32_t merge_rw(uint32_t old_value, uint32_t value, uint32_t mask)
+{
+ return (old_value & ~mask) | (value & mask);
+}
+
+static void assert_pll_reset(QTestState *qts)
+{
+ static const uint32_t offsets[] = { PLL_CFG0, PLL_CFG1, PLL_CTL, PLL_STAT };
+
+ for (unsigned pll = 0; pll < K230_PLL_COUNT; pll++) {
+ for (unsigned reg = 0; reg < G_N_ELEMENTS(offsets); reg++) {
+ g_assert_cmphex(qtest_readl(qts, pll_addr(pll, offsets[reg])), ==,
+ pll_reset[pll][reg]);
+ }
+ }
+}
+
+static void assert_sysclk_reset(QTestState *qts)
+{
+ for (unsigned i = 0; i < G_N_ELEMENTS(sysclk_oracle); i++) {
+ const K230SysclkOracle *reg = &sysclk_oracle[i];
+
+ g_assert_cmphex(qtest_readl(qts, K230_SYSCLK_BASE + reg->offset), ==,
+ reg->reset);
+ }
+}
+
+static void test_reset_pll(void)
+{
+ QTestState *qts = k230_cmu_start();
+
+ assert_pll_reset(qts);
+ qtest_quit(qts);
+}
+
+static void test_reset_sysclk(void)
+{
+ QTestState *qts = k230_cmu_start();
+
+ assert_sysclk_reset(qts);
+ qtest_quit(qts);
+}
+
+static void test_pll_cfg_masks(void)
+{
+ static const uint32_t offsets[] = { PLL_CFG0, PLL_CFG1 };
+ static const uint32_t masks[] = { PLL_CFG0_RW_MASK, PLL_CFG1_RW_MASK };
+ QTestState *qts = k230_cmu_start();
+
+ for (unsigned pll = 0; pll < K230_PLL_COUNT; pll++) {
+ for (unsigned reg = 0; reg < G_N_ELEMENTS(offsets); reg++) {
+ uint32_t addr = pll_addr(pll, offsets[reg]);
+ uint32_t reset = pll_reset[pll][reg];
+
+ qtest_writel(qts, addr, 0);
+ g_assert_cmphex(qtest_readl(qts, addr), ==,
+ merge_rw(reset, 0, masks[reg]));
+ qtest_writel(qts, addr, UINT32_MAX);
+ g_assert_cmphex(qtest_readl(qts, addr), ==,
+ merge_rw(merge_rw(reset, 0, masks[reg]),
+ UINT32_MAX, masks[reg]));
+
+ qtest_system_reset(qts);
+ qtest_writel(qts, addr, BIT(ctz32(masks[reg])));
+ g_assert_cmphex(qtest_readl(qts, addr), ==,
+ merge_rw(reset, BIT(ctz32(masks[reg])),
+ masks[reg]));
+
+ qtest_system_reset(qts);
+ qtest_writel(qts, addr, reset | BIT(ctz32(~masks[reg])));
+ g_assert_cmphex(qtest_readl(qts, addr), ==, reset);
+ }
+ }
+
+ qtest_quit(qts);
+}
+
+static void test_pll_ctl_write_enable(void)
+{
+ QTestState *qts = k230_cmu_start();
+ uint32_t addr = pll_addr(0, PLL_CTL);
+
+ qtest_writel(qts, addr, 0);
+ g_assert_cmphex(qtest_readl(qts, addr), ==, pll_reset[0][2]);
+
+ qtest_writel(qts, addr, BIT(16 + 2));
+ g_assert_cmphex(qtest_readl(qts, addr), ==,
+ pll_reset[0][2] & ~BIT(2));
+
+ qtest_writel(qts, addr, BIT(2) | BIT(16 + 2) | BIT(16 + 4));
+ g_assert_cmphex(qtest_readl(qts, addr), ==,
+ merge_rw(pll_reset[0][2] & ~BIT(2),
+ BIT(2), BIT(2) | BIT(4)));
+
+ qtest_writel(qts, addr, UINT32_MAX);
+ g_assert_cmphex(qtest_readl(qts, addr), ==, PLL_CTL_RW_MASK);
+ qtest_quit(qts);
+}
+
+static void test_pll_status(void)
+{
+ QTestState *qts = k230_cmu_start();
+ uint32_t ctl = pll_addr(0, PLL_CTL);
+ uint32_t stat = pll_addr(0, PLL_STAT);
+
+ qtest_writel(qts, stat, 0);
+ g_assert_cmphex(qtest_readl(qts, stat), ==, 0x00000021);
+
+ qtest_writel(qts, ctl, BIT(0) | BIT(16));
+ g_assert_cmphex(qtest_readl(qts, stat), ==, 0);
+
+ qtest_writel(qts, ctl, BIT(1) | BIT(17));
+ g_assert_cmphex(qtest_readl(qts, stat), ==, 0x00000021);
+
+ qtest_writel(qts, ctl, BIT(0) | BIT(1) | BIT(16) | BIT(17));
+ g_assert_cmphex(qtest_readl(qts, stat), ==, 0x00000021);
+ qtest_quit(qts);
+}
+
+static void test_sysclk_masks(void)
+{
+ QTestState *qts = k230_cmu_start();
+
+ for (unsigned i = 0; i < G_N_ELEMENTS(sysclk_oracle); i++) {
+ const K230SysclkOracle *reg = &sysclk_oracle[i];
+ uint32_t addr = K230_SYSCLK_BASE + reg->offset;
+ uint32_t after_zero = merge_rw(reg->reset, 0, reg->rw_mask);
+
+ qtest_writel(qts, addr, 0);
+ g_assert_cmphex(qtest_readl(qts, addr), ==, after_zero);
+ qtest_writel(qts, addr, UINT32_MAX);
+ g_assert_cmphex(qtest_readl(qts, addr), ==,
+ merge_rw(after_zero, UINT32_MAX, reg->rw_mask));
+ }
+
+ qtest_quit(qts);
+}
+
+static void test_sysclk_update(void)
+{
+ QTestState *qts = k230_cmu_start();
+
+ for (unsigned i = 0; i < G_N_ELEMENTS(sysclk_oracle); i++) {
+ const K230SysclkOracle *reg = &sysclk_oracle[i];
+ uint32_t addr;
+
+ if (!reg->w1t_mask) {
+ continue;
+ }
+
+ addr = K230_SYSCLK_BASE + reg->offset;
+ qtest_writel(qts, addr, reg->reset | reg->w1t_mask);
+ g_assert_cmphex(qtest_readl(qts, addr), ==, reg->reset);
+ }
+
+ qtest_quit(qts);
+}
+
+static void test_spi2axi(void)
+{
+ QTestState *qts = k230_cmu_start();
+ uint32_t addr = K230_SYSCLK_BASE + 0x108;
+
+ g_assert_cmphex(qtest_readl(qts, addr), ==, 0x00000007);
+ qtest_writel(qts, addr, 0x00000001);
+ g_assert_cmphex(qtest_readl(qts, addr), ==, 0x00000001);
+ qtest_writel(qts, addr, 0x8000000f);
+ g_assert_cmphex(qtest_readl(qts, addr), ==, 0x0000000f);
+ qtest_quit(qts);
+}
+
+static void test_unknown_offsets(void)
+{
+ QTestState *qts = k230_cmu_start();
+ /* The 0x40 PLL window has no undefined aligned 32-bit word. */
+ uint32_t addr = K230_SYSCLK_BASE + 0x014;
+
+ g_assert_cmphex(qtest_readl(qts, addr), ==, 0);
+ qtest_writel(qts, addr, UINT32_MAX);
+ g_assert_cmphex(qtest_readl(qts, addr), ==, 0);
+ qtest_quit(qts);
+}
+
+static void test_system_reset(void)
+{
+ QTestState *qts = k230_cmu_start();
+
+ qtest_writel(qts, pll_addr(0, PLL_CFG0), 0);
+ qtest_writel(qts, pll_addr(1, PLL_CFG1), 0);
+ qtest_writel(qts, pll_addr(2, PLL_CTL), BIT(16 + 2));
+ qtest_writel(qts, pll_addr(3, PLL_CTL), BIT(0) | BIT(16));
+ qtest_writel(qts, K230_SYSCLK_BASE + 0x000, 0);
+ qtest_writel(qts, K230_SYSCLK_BASE + 0x050, 0);
+ qtest_writel(qts, K230_SYSCLK_BASE + 0x108, 0);
+
+ qtest_system_reset(qts);
+ assert_pll_reset(qts);
+ assert_sysclk_reset(qts);
+ qtest_quit(qts);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/k230-cmu/reset/pll", test_reset_pll);
+ qtest_add_func("/k230-cmu/reset/sysclk", test_reset_sysclk);
+ qtest_add_func("/k230-cmu/pll/cfg-masks", test_pll_cfg_masks);
+ qtest_add_func("/k230-cmu/pll/ctl-write-enable", test_pll_ctl_write_enable);
+ qtest_add_func("/k230-cmu/pll/status", test_pll_status);
+ qtest_add_func("/k230-cmu/sysclk/masks", test_sysclk_masks);
+ qtest_add_func("/k230-cmu/sysclk/update", test_sysclk_update);
+ qtest_add_func("/k230-cmu/sysclk/spi2axi", test_spi2axi);
+ qtest_add_func("/k230-cmu/unknown-offsets", test_unknown_offsets);
+ qtest_add_func("/k230-cmu/system-reset", test_system_reset);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 56ff860e21..9f5c46e0bf 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -297,7 +297,8 @@ qtests_riscv64 = ['riscv-csr-test'] + \
(config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and
config_all_devices.has_key('CONFIG_RISCV_IOMMU') ?
['iommu-riscv-test'] : []) + \
- (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
+ (config_all_devices.has_key('CONFIG_K230') ?
+ ['k230-cmu-test', 'k230-wdt-test'] : [])
qtests_hexagon = ['boot-serial-test']
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/4] docs/system/riscv: document K230 CMU support
2026-08-09 6:20 [PATCH 0/4] Kendryte K230 CMU register model Simon Law
` (2 preceding siblings ...)
2026-08-09 6:20 ` [PATCH 3/4] tests/qtest: add K230 CMU coverage Simon Law
@ 2026-08-09 6:20 ` Simon Law
2026-08-14 7:53 ` [PATCH 0/4] Kendryte K230 CMU register model Bin Meng
4 siblings, 0 replies; 8+ messages in thread
From: Simon Law @ 2026-08-09 6:20 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, chao.liu, palmer, alistair.francis, liwei1518,
daniel.barboza, zhiwei_liu, pierrick.bouvier
Signed-off-by: Simon Law <0860734llx@gmail.com>
---
docs/system/riscv/k230.rst | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
index cea8202e55..dd50b0bd2e 100644
--- a/docs/system/riscv/k230.rst
+++ b/docs/system/riscv/k230.rst
@@ -18,9 +18,31 @@ The ``k230`` machine supports the following devices:
* 1 c908 cores (little core)
* Core Local Interruptor (CLINT)
* Platform-Level Interrupt Controller (PLIC)
+* Clock Management Unit (CMU)
* 2 K230 Watchdog Timer
* 5 UART
+Clock Management Unit
+---------------------
+
+The CMU model provides the register interface used by the K230 SDK U-Boot and
+the upstream Linux K230 clock driver. It implements the four PLL register
+blocks at ``0x91102000`` through ``0x9110203f`` and the defined sysclk
+registers in the ``0x91100000`` window, including the software-visible
+``SPI2AXI_CLK_DIV`` register at offset ``0x108``.
+
+The model implements reset values, writable and reserved bits, PLL control
+write-enable semantics, and write-one-to-trigger update operations. PLL lock
+and init completion are deterministic and immediate so that Linux clock probe
+does not depend on virtual time.
+
+The CMU does not propagate clock frequencies to QEMU devices or alter CPU
+execution speed. Peripheral reset, power control, and a guest-initiated K230
+system-reset backend are separate hardware blocks and are not modeled by the
+CMU. Consequently, a guest reboot requires the future K230 reset subsystem
+and matching OpenSBI reboot backend; QMP ``system_reset`` resets the CMU along
+with the rest of the machine.
+
Boot options
------------
The ``k230`` machine supports K230 SDK boot through M-mode U-Boot, which then
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 0/4] Kendryte K230 CMU register model
2026-08-09 6:20 [PATCH 0/4] Kendryte K230 CMU register model Simon Law
` (3 preceding siblings ...)
2026-08-09 6:20 ` [PATCH 4/4] docs/system/riscv: document K230 CMU support Simon Law
@ 2026-08-14 7:53 ` Bin Meng
2026-08-17 8:55 ` Niel Law
4 siblings, 1 reply; 8+ messages in thread
From: Bin Meng @ 2026-08-14 7:53 UTC (permalink / raw)
To: Simon Law
Cc: qemu-devel, qemu-riscv, chao.liu, palmer, alistair.francis,
liwei1518, daniel.barboza, zhiwei_liu, pierrick.bouvier
Hello,
On Sun, Aug 9, 2026 at 7:47 PM Simon Law <0860734llx@gmail.com> wrote:
>
> The Kendryte K230 machine currently lacks the Clock Management Unit (CMU)
> register interface required by the K230 SDK U-Boot and the Linux K230 clock
> driver. As a result, software probing the PLL and sysclk providers cannot
> observe the expected reset values or register update semantics.
>
> This series adds a minimal, deterministic K230 CMU model.
>
> The model covers:
>
> - four PLL register blocks at 0x91102000..0x9110203f;
> - the defined sysclk registers in the 0x91100000 window;
> - the software-visible SPI2AXI_CLK_DIV register at sysclk offset 0x108;
> - reset values and writable/reserved/read-only masks;
> - PLL control write-enable semantics;
> - write-one-to-trigger update behavior;
> - deterministic PLL lock and initialization status;
> - VMState for stable PLL and sysclk register state;
> - qtest coverage for reset, masks, write-enable, W1T, status, sysclk
> updates, unknown offsets, and system reset;
> - K230 machine wiring and user-facing documentation.
>
> The model intentionally does not propagate clock frequencies to QEMU devices or
> change CPU execution speed. Peripheral reset, power control, and the
> guest-initiated K230 reboot backend remain outside the scope of this series.
> Those functions require separate reset/power models and a matching OpenSBI
> backend.
>
> The implementation is based only on the existing K230 machine and does not
> depend on unmerged RMU, Timer, SPI, or SDHCI device series.
>
> Testing:
> - QTEST_QEMU_BINARY=/workspace/qemu/build/qemu-system-riscv64
> /workspace/qemu/build/tests/qtest/k230-cmu-test
> (10/10 subtests passed)
> - QTEST_QEMU_BINARY=/workspace/qemu/build/qemu-system-riscv64
> /workspace/qemu/build/tests/qtest/k230-wdt-test
> (7/7 subtests passed)
> - K230 direct Linux boot and K230 U-Boot boot
> - Linux K230 clock probe and clk_summary validation
> - CMU source/destination migration smoke
>
> Signed-off-by: Simon Law <0860734llx@gmail.com>
Is this clock modeling a must-have to make U-Boot or Linux boot on the
QEMU k230 machine?
Is an unimplemented region enough to make the software happy?
Regards,
Bin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/4] Kendryte K230 CMU register model
2026-08-14 7:53 ` [PATCH 0/4] Kendryte K230 CMU register model Bin Meng
@ 2026-08-17 8:55 ` Niel Law
0 siblings, 0 replies; 8+ messages in thread
From: Niel Law @ 2026-08-17 8:55 UTC (permalink / raw)
To: Bin Meng
Cc: qemu-devel, qemu-riscv, chao.liu, palmer, alistair.francis,
liwei1518, daniel.barboza, zhiwei_liu, pierrick.bouvier
Hi,
Thanks for your reply.
The clock model is not a must-have for the Linux build from the K230
SDK. the vendor clock driver allows PLL unlock:
[ 0.093353] thermal_sys: Registered thermal governor 'step_wise'^M^M
[ 0.409760] [ERROR K230_CLK]:pll pll0 is unlock.^M^M
[ 0.414011] [ERROR K230_CLK]:pll pll1 is unlock.^M^M
[ 0.417540] [ERROR K230_CLK]:pll pll2 is unlock.^M^M
[ 0.421088] [ERROR K230_CLK]:pll pll3 is unlock.^M^M
[ 0.456215] k230-powerdomain 91103000.sysctl_power: powerdomain init ok^M^M
But Linux mainline will boot fail, it poll STAT.bit0 of PLL forever.
From drivers/clk/clk-k230.c:
#define K230_PLL_LOCK_TIMEOUT 0
static int k230_pll_prepare(struct clk_hw *hw)
{
struct k230_pll *pll = hw_to_k230_pll(hw);
u32 reg;
/* wait for PLL lock until it reaches lock status */
return readl_poll_timeout(K230_PLLX_LOCK_ADDR(pll->reg, pll->id), reg,
reg & K230_PLL_LOCK_STATUS_MASK,
K230_PLL_LOCK_TIME_DELAY,
K230_PLL_LOCK_TIMEOUT);
}
Furthermore, SDHCI/USB PHY/SPI flash driver require valid clock
config, else causes fatal error.
Best regard,
Simon
On Fri, Aug 14, 2026 at 3:53 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> Hello,
>
> On Sun, Aug 9, 2026 at 7:47 PM Simon Law <0860734llx@gmail.com> wrote:
> >
> > The Kendryte K230 machine currently lacks the Clock Management Unit (CMU)
> > register interface required by the K230 SDK U-Boot and the Linux K230 clock
> > driver. As a result, software probing the PLL and sysclk providers cannot
> > observe the expected reset values or register update semantics.
> >
> > This series adds a minimal, deterministic K230 CMU model.
> >
> > The model covers:
> >
> > - four PLL register blocks at 0x91102000..0x9110203f;
> > - the defined sysclk registers in the 0x91100000 window;
> > - the software-visible SPI2AXI_CLK_DIV register at sysclk offset 0x108;
> > - reset values and writable/reserved/read-only masks;
> > - PLL control write-enable semantics;
> > - write-one-to-trigger update behavior;
> > - deterministic PLL lock and initialization status;
> > - VMState for stable PLL and sysclk register state;
> > - qtest coverage for reset, masks, write-enable, W1T, status, sysclk
> > updates, unknown offsets, and system reset;
> > - K230 machine wiring and user-facing documentation.
> >
> > The model intentionally does not propagate clock frequencies to QEMU devices or
> > change CPU execution speed. Peripheral reset, power control, and the
> > guest-initiated K230 reboot backend remain outside the scope of this series.
> > Those functions require separate reset/power models and a matching OpenSBI
> > backend.
> >
> > The implementation is based only on the existing K230 machine and does not
> > depend on unmerged RMU, Timer, SPI, or SDHCI device series.
> >
> > Testing:
> > - QTEST_QEMU_BINARY=/workspace/qemu/build/qemu-system-riscv64
> > /workspace/qemu/build/tests/qtest/k230-cmu-test
> > (10/10 subtests passed)
> > - QTEST_QEMU_BINARY=/workspace/qemu/build/qemu-system-riscv64
> > /workspace/qemu/build/tests/qtest/k230-wdt-test
> > (7/7 subtests passed)
> > - K230 direct Linux boot and K230 U-Boot boot
> > - Linux K230 clock probe and clk_summary validation
> > - CMU source/destination migration smoke
> >
> > Signed-off-by: Simon Law <0860734llx@gmail.com>
>
> Is this clock modeling a must-have to make U-Boot or Linux boot on the
> QEMU k230 machine?
>
> Is an unimplemented region enough to make the software happy?
>
> Regards,
> Bin
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/4] hw/misc: model K230 CMU registers
2026-08-09 6:20 ` [PATCH 1/4] hw/misc: model K230 CMU registers Simon Law
@ 2026-08-18 5:37 ` Chao Liu
0 siblings, 0 replies; 8+ messages in thread
From: Chao Liu @ 2026-08-18 5:37 UTC (permalink / raw)
To: Simon Law
Cc: qemu-devel, qemu-riscv, palmer, alistair.francis, liwei1518,
daniel.barboza, zhiwei_liu, pierrick.bouvier
On Sun, Aug 09, 2026 at 02:20:41PM +0800, Simon Law wrote:
> Signed-off-by: Simon Law <0860734llx@gmail.com>
> ---
> MAINTAINERS | 4 +
> hw/misc/Kconfig | 3 +
> hw/misc/k230_cmu.c | 881 +++++++++++++++++++++++++++++++++++++++++++++
> hw/misc/meson.build | 1 +
> hw/misc/trace-events | 9 +
> hw/riscv/Kconfig | 1 +
> include/hw/misc/k230_cmu.h | 58 +++
> 7 files changed, 957 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6171cc7494..d46e90cdc5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1820,14 +1820,18 @@ F: hw/riscv/xiangshan_kmh.c
> F: include/hw/riscv/xiangshan_kmh.h
>
> K230 Machines
> +M: Simon Law <0860734llx@gmail.com>
Thanks for helping maintain the K230 machine module. I suggest starting with
patch reviews on the upstream mailing list, like Junze Cao.
> M: Chao Liu <chao.liu@processmission.com>
> L: qemu-riscv@nongnu.org
> S: Maintained
> F: docs/system/riscv/k230.rst
> F: hw/riscv/k230.c
> +F: hw/misc/k230_cmu.c
> F: hw/watchdog/k230_wdt.c
> +F: include/hw/misc/k230_cmu.h
> F: include/hw/riscv/k230.h
> F: include/hw/watchdog/k230_wdt.h
> +F: tests/qtest/k230-cmu-test.c
> F: tests/qtest/k230-wdt-test.c
>
> RX Machines
> diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
> index 1543ee6653..58a0421e84 100644
> --- a/hw/misc/Kconfig
> +++ b/hw/misc/Kconfig
> @@ -101,6 +101,9 @@ config FSL_IMX8MP_ANALOG
> config FSL_IMX8MP_CCM
> bool
>
> +config K230_CMU
> + bool
> +
> config STM32_RCC
> bool
>
> diff --git a/hw/misc/k230_cmu.c b/hw/misc/k230_cmu.c
> new file mode 100644
> index 0000000000..6af19d2a06
> --- /dev/null
> +++ b/hw/misc/k230_cmu.c
> @@ -0,0 +1,881 @@
> +/*
> + * Kendryte K230 Clock Management Unit
> + *
> + * Copyright (c) 2026 Simon Law <0860734llx@gmail.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Emulates the K230 PLL and system-clock register protocol. It models
> + * software-visible reset values, masks, write strobes, and PLL lock state,
> + * but does not provide cycle-accurate clocks or propagate QEMU Clock signals.
> + *
> + * 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 "hw/core/sysbus.h"
> +#include "hw/core/registerfields.h"
> +#include "migration/vmstate.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "qom/object.h"
> +
> +#include "hw/misc/k230_cmu.h"
> +#include "trace.h"
> +
> +REG32(CMU_CFG0, 0x00)
> + FIELD(CMU_CFG0, PLL_OUT_DIV, 24, 4)
> + FIELD(CMU_CFG0, PLL_REF_DIV, 16, 6)
> + FIELD(CMU_CFG0, PLL_FB_DIV, 0, 13)
> +
> +REG32(CMU_CFG1, 0x04)
> + FIELD(CMU_CFG1, PLL_BYPASS, 19, 1)
> + FIELD(CMU_CFG1, PLL_TEST, 18, 1)
> + FIELD(CMU_CFG1, PLL_ENSAT, 17, 1)
> + FIELD(CMU_CFG1, PLL_FASTEN, 16, 1)
> + FIELD(CMU_CFG1, PLL_BWADJ, 0, 12)
> +
> +REG32(CMU_CTL, 0x08)
> + FIELD(CMU_CTL, PLL_LOCK_TIM, 4, 8)
> + FIELD(CMU_CTL, PLL_CLK_OE, 2, 1)
> + FIELD(CMU_CTL, PLL_INIT, 1, 1)
> + FIELD(CMU_CTL, PLL_PWRDWN, 0, 1)
> +
> +REG32(CMU_STAT, 0x0c)
> + FIELD(CMU_STAT, PLL_FSM_STAT, 4, 2)
> + FIELD(CMU_STAT, PLL_RESERVED, 3, 1)
> + FIELD(CMU_STAT, PLL_FB_SLIP, 2, 1)
> + FIELD(CMU_STAT, PLL_REF_SLIP, 1, 1)
> + FIELD(CMU_STAT, PLL_LOCK, 0, 1)
> +
> +#define PLL_CFG0_RW_MASK (R_CMU_CFG0_PLL_OUT_DIV_MASK | \
> + R_CMU_CFG0_PLL_REF_DIV_MASK | \
> + R_CMU_CFG0_PLL_FB_DIV_MASK)
> +#define PLL_CFG1_RW_MASK (R_CMU_CFG1_PLL_BYPASS_MASK | \
> + R_CMU_CFG1_PLL_TEST_MASK | \
> + R_CMU_CFG1_PLL_ENSAT_MASK | \
> + R_CMU_CFG1_PLL_FASTEN_MASK | \
> + R_CMU_CFG1_PLL_BWADJ_MASK)
> +#define PLL_CTL_RW_MASK (R_CMU_CTL_PLL_LOCK_TIM_MASK | \
> + R_CMU_CTL_PLL_CLK_OE_MASK)
> +#define PLL_CTL_W1T_MASK (R_CMU_CTL_PLL_INIT_MASK | \
> + R_CMU_CTL_PLL_PWRDWN_MASK)
> +#define PLL_CTL_LOW_MASK (PLL_CTL_RW_MASK | PLL_CTL_W1T_MASK)
> +#define PLL_STAT_RO_MASK (R_CMU_STAT_PLL_FSM_STAT_MASK | \
> + R_CMU_STAT_PLL_RESERVED_MASK | \
> + R_CMU_STAT_PLL_FB_SLIP_MASK | \
> + R_CMU_STAT_PLL_REF_SLIP_MASK | \
> + R_CMU_STAT_PLL_LOCK_MASK)
> +
> +REG32(SYSCLK_CPU0_CLK_CFG, 0x000)
> + FIELD(SYSCLK_CPU0_CLK_CFG, CORE_CLK_ROOT_GDIV_UPD, 31, 1)
> + FIELD(SYSCLK_CPU0_CLK_CFG, PCLK_DIV, 15, 3)
> + FIELD(SYSCLK_CPU0_CLK_CFG, TDI_PCLK_EN, 14, 1)
> + /* FIXME: SDK get_leaf_en() reads bit 7 for this gate; */
> + /* TRM says bit 13. */
> + FIELD(SYSCLK_CPU0_CLK_CFG, PCLK_ENABLE, 13, 1)
> + FIELD(SYSCLK_CPU0_CLK_CFG, PLICLK_DIV, 10, 3)
> + FIELD(SYSCLK_CPU0_CLK_CFG, PLICLK_ENABLE, 9, 1)
> + FIELD(SYSCLK_CPU0_CLK_CFG, ACLK_DIV, 6, 3)
> + FIELD(SYSCLK_CPU0_CLK_CFG, CORE_CLK_ROOT_DIV, 1, 4)
> + FIELD(SYSCLK_CPU0_CLK_CFG, CORE_CLK_ENABLE, 0, 1)
> +REG32(SYSCLK_CPU1_CLK_CFG, 0x004)
> + FIELD(SYSCLK_CPU1_CLK_CFG, CORE_CLK_DIV_UPD, 31, 1)
> + FIELD(SYSCLK_CPU1_CLK_CFG, PCLK_ENABLE, 19, 1)
> + FIELD(SYSCLK_CPU1_CLK_CFG, PLICLK_DIV, 16, 3)
> + FIELD(SYSCLK_CPU1_CLK_CFG, PLICLK_ENABLE, 15, 1)
> + FIELD(SYSCLK_CPU1_CLK_CFG, ACLK_DIV, 12, 3)
> + FIELD(SYSCLK_CPU1_CLK_CFG, CORE_CLK_ROOT_DIV, 3, 3)
> + FIELD(SYSCLK_CPU1_CLK_CFG, CORE_CLK_SEL, 1, 2)
> + FIELD(SYSCLK_CPU1_CLK_CFG, CORE_CLK_ENABLE, 0, 1)
> +REG32(SYSCLK_AI_CLK_CFG, 0x008)
> + FIELD(SYSCLK_AI_CLK_CFG, CLK_DIV_UPD, 31, 1)
> + FIELD(SYSCLK_AI_CLK_CFG, ACLK_ENABLE, 10, 1)
> + FIELD(SYSCLK_AI_CLK_CFG, CLK_CDIV, 3, 3)
> + FIELD(SYSCLK_AI_CLK_CFG, CLK_SEL, 2, 1)
> + FIELD(SYSCLK_AI_CLK_CFG, CLK_ENABLE, 0, 1)
> +REG32(SYSCLK_VPU_CLK_CFG, 0x00c)
> + FIELD(SYSCLK_VPU_CLK_CFG, CLK_GDIV_UPD, 31, 1)
> + FIELD(SYSCLK_VPU_CLK_CFG, CFGCLK_ROOT_DIV, 11, 4)
> + FIELD(SYSCLK_VPU_CLK_CFG, CFGCLK_ENABLE, 10, 1)
> + FIELD(SYSCLK_VPU_CLK_CFG, ACLK_ROOT_DIV, 6, 4)
> + FIELD(SYSCLK_VPU_CLK_CFG, ACLK_ENABLE, 5, 1)
> + FIELD(SYSCLK_VPU_CLK_CFG, CLK_DIV, 1, 4)
> + FIELD(SYSCLK_VPU_CLK_CFG, CLK_EN, 0, 1)
> +REG32(SYSCLK_PMU_CLK_CFG, 0x010)
> + FIELD(SYSCLK_PMU_CLK_CFG, CLK_EN, 0, 1)
> +REG32(SYSCLK_HS_CLKEN_CFG, 0x018)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SSI2_ACLK_ENABLE, 30, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SSI1_ACLK_ENABLE, 29, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, QSPI_ACLK_ENABLE, 28, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SSI0_ACLK_ENABLE, 27, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SSI2_CLK_ENABLE, 26, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SSI1_CLK_ENABLE, 25, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SSI0_CLK_ENABLE, 24, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, USB_REFCLK_SEL, 23, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, USB1_REFCLK_ENABLE, 22, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, USB0_REFCLK_ENABLE, 21, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD1_TMCLK_ENABLE, 20, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD1_CCLK_ENABLE, 19, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD1_BCLK_ENABLE, 18, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD1_ACLK_ENABLE, 17, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD0_TMCLK_ENABLE, 16, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD0_CCLK_ENABLE, 15, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD0_BCLK_ENABLE, 14, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD0_ACLK_ENABLE, 13, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD_TMCLK_ENABLE, 12, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD_CCLK_ENABLE, 11, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD_BCLK_ENABLE, 10, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD_ACLK_ENABLE, 9, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SSI2_HCLK_ENABLE, 8, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SSI1_HCLK_ENABLE, 7, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SSI0_HCLK_ENABLE, 6, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, USB1_HCLK_ENABLE, 5, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, USB0_HCLK_ENABLE, 4, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD1_HCLK_ENABLE, 3, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, SD0_HCLK_ENABLE, 2, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, HCLK_HIGH_ENABLE, 1, 1)
> + FIELD(SYSCLK_HS_CLKEN_CFG, HCLK_ENABLE, 0, 1)
> +REG32(SYSCLK_HS_SDCLK_CFG, 0x01c)
> + FIELD(SYSCLK_HS_SDCLK_CFG, ACLK_ROOT_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_HS_SDCLK_CFG, TMCLK_DIV, 15, 5)
> + /* FIXME: SDK get_leaf_rate() uses ACLK_ROOT_DIV for SD CCLK, */
> + /* not bits 14:12. */
> + FIELD(SYSCLK_HS_SDCLK_CFG, CCLK_DIV, 12, 3)
> + FIELD(SYSCLK_HS_SDCLK_CFG, BCLK_DIV, 9, 3)
> + FIELD(SYSCLK_HS_SDCLK_CFG, ACLK_ROOT_DIV, 6, 3)
> + FIELD(SYSCLK_HS_SDCLK_CFG, HCLK_DIV, 3, 3)
> + FIELD(SYSCLK_HS_SDCLK_CFG, HCLK_HIGH_ROOT_DIV, 0, 3)
> +REG32(SYSCLK_HS_SPI_CFG, 0x020)
> + FIELD(SYSCLK_HS_SPI_CFG, SSI0_ACLK_ROOT_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_HS_SPI_CFG, SSI0_CLK_SEL, 18, 1)
> + FIELD(SYSCLK_HS_SPI_CFG, USB_REFCLK_50M_DIV, 15, 3)
> + FIELD(SYSCLK_HS_SPI_CFG, QSPI_ACLK_ROOT_DIV, 12, 3)
> + FIELD(SYSCLK_HS_SPI_CFG, SSI0_ACLK_DIV, 9, 3)
> + FIELD(SYSCLK_HS_SPI_CFG, SSI2_CLK_DIV, 6, 3)
> + FIELD(SYSCLK_HS_SPI_CFG, SSI1_CLK_DIV, 3, 3)
> +REG32(SYSCLK_LS_CLKEN_CFG0, 0x024)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, PDM_CLK_ENABLE, 31, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, CODEC_MCLK_DAC_ENABLE, 30, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, CODEC_MCLK_ADC_ENABLE, 29, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, AUD_DEV_CLK_ENABLE, 28, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, GPIO_DBCLK_ENABLE, 27, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, ADC_CLK_ENABLE, 26, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, I2C4_CLK_ENABLE, 25, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, I2C3_CLK_ENABLE, 24, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, I2C2_CLK_ENABLE, 23, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, I2C1_CLK_ENABLE, 22, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, I2C0_CLK_ENABLE, 21, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, UART4_CLK_ENABLE, 20, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, UART3_CLK_ENABLE, 19, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, UART2_CLK_ENABLE, 18, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, UART1_CLK_ENABLE, 17, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, UART0_CLK_ENABLE, 16, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, ADC_PCLK_ENABLE, 15, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, CODEC_PCLK_ENABLE, 14, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, AUD_DEV_PCLK_ENABLE, 13, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, PWM_PCLK_ENABLE, 12, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, GPIO_PCLK_ENABLE, 11, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, I2C4_PCLK_ENABLE, 10, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, I2C3_PCLK_ENABLE, 9, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, I2C2_PCLK_ENABLE, 8, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, I2C1_PCLK_ENABLE, 7, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, I2C0_PCLK_ENABLE, 6, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, UART4_PCLK_ENABLE, 5, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, UART3_PCLK_ENABLE, 4, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, UART2_PCLK_ENABLE, 3, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, UART1_PCLK_ENABLE, 2, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, UART0_PCLK_ENABLE, 1, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG0, PCLK_ENABLE, 0, 1)
> +REG32(SYSCLK_LS_CLKEN_CFG1, 0x028)
> + FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK3_PCLK_ENABLE, 7, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK2_PCLK_ENABLE, 6, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK1_PCLK_ENABLE, 5, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK0_PCLK_ENABLE, 4, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK3_CO_ENABLE, 3, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK2_CO_ENABLE, 2, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK1_CO_ENABLE, 1, 1)
> + FIELD(SYSCLK_LS_CLKEN_CFG1, JAMLINK0_CO_ENABLE, 0, 1)
> +REG32(SYSCLK_UART_I2C_CLKDIV_CFG, 0x02c)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C0_CLK_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C4_CLK_DIV, 27, 3)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C3_CLK_DIV, 24, 3)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C2_CLK_DIV, 21, 3)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C1_CLK_DIV, 18, 3)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, I2C0_CLK_DIV, 15, 3)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, UART4_SCLK_DIV, 12, 3)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, UART3_SCLK_DIV, 9, 3)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, UART2_SCLK_DIV, 6, 3)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, UART1_SCLK_DIV, 3, 3)
> + FIELD(SYSCLK_UART_I2C_CLKDIV_CFG, UART0_SCLK_DIV, 0, 3)
> +REG32(SYSCLK_LS_CLKDIV_CFG, 0x030)
> + FIELD(SYSCLK_LS_CLKDIV_CFG, JAMLINK_CO_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_LS_CLKDIV_CFG, JAMLINK_CO_DIV, 23, 8)
> + FIELD(SYSCLK_LS_CLKDIV_CFG, GPIO_DBCLK_DIV, 13, 10)
> + FIELD(SYSCLK_LS_CLKDIV_CFG, ADC_CLK_DIV, 3, 10)
> + FIELD(SYSCLK_LS_CLKDIV_CFG, PCLK_DIV, 0, 3)
> +/*
> + * SDK sysctl_clk_t marks offsets 0x034..0x044 reserved; the TRM defines
> + * these registers, so the TRM layout is authoritative for the v1 model.
> + */
> +REG32(SYSCLK_AUDIO_CLKDIV_CFG, 0x034)
> + FIELD(SYSCLK_AUDIO_CLKDIV_CFG, AUD_DEV_CLK_FDIV_UPD, 31, 1)
> + FIELD(SYSCLK_AUDIO_CLKDIV_CFG, AUDIO_CLK_STEP, 16, 15)
> + FIELD(SYSCLK_AUDIO_CLKDIV_CFG, AUDIO_CLK_SUM, 0, 16)
> +REG32(SYSCLK_CODEC_ADC_MCLKDIV_CFG, 0x038)
> + FIELD(SYSCLK_CODEC_ADC_MCLKDIV_CFG, MCLK_ADC_FDIV_UPD, 31, 1)
> + FIELD(SYSCLK_CODEC_ADC_MCLKDIV_CFG, MCLK_ADC_STEP, 14, 13)
> + FIELD(SYSCLK_CODEC_ADC_MCLKDIV_CFG, MCLK_ADC_SUM, 0, 14)
> +REG32(SYSCLK_CODEC_DAC_MCLKDIV_CFG, 0x03c)
> + FIELD(SYSCLK_CODEC_DAC_MCLKDIV_CFG, MCLK_DAC_FDIV_UPD, 31, 1)
> + FIELD(SYSCLK_CODEC_DAC_MCLKDIV_CFG, MCLK_DAC_STEP, 14, 13)
> + FIELD(SYSCLK_CODEC_DAC_MCLKDIV_CFG, MCLK_DAC_SUM, 0, 14)
> +REG32(SYSCLK_PDM_CLKDIV_CFG0, 0x040)
> + FIELD(SYSCLK_PDM_CLKDIV_CFG0, CLK_SUM, 0, 17)
> +REG32(SYSCLK_PDM_CLKDIV_CFG1, 0x044)
> + FIELD(SYSCLK_PDM_CLKDIV_CFG1, CLK_FDIV_UPD, 31, 1)
> + FIELD(SYSCLK_PDM_CLKDIV_CFG1, CLK_STEP, 0, 16)
> +REG32(SYSCLK_SYSCTL_CLKEN_CFG, 0x050)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, HDI_CLK_ENABLE, 21, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, IOMUX_PCLK_ENABLE, 20, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, STC_CLK_EN, 19, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER5_CLK_ENABLE, 18, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER4_CLK_ENABLE, 17, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER3_CLK_ENABLE, 16, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER2_CLK_ENABLE, 15, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER1_CLK_ENABLE, 14, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER0_CLK_ENABLE, 13, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER5_CLK_SEL, 12, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER4_CLK_SEL, 11, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER3_CLK_SEL, 10, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER2_CLK_SEL, 9, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER1_CLK_SEL, 8, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER0_CLK_SEL, 7, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, WDT1_CLK_ENABLE, 6, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, WDT0_CLK_ENABLE, 5, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, MAILBOX_PCLK_ENABLE, 4, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, TIMER_PCLK_ENABLE, 3, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, WDT1_PCLK_ENABLE, 2, 1)
> + FIELD(SYSCLK_SYSCTL_CLKEN_CFG, WDT0_PCLK_ENABLE, 1, 1)
> +REG32(SYSCLK_TIMER_CLK_CFG, 0x054)
> + FIELD(SYSCLK_TIMER_CLK_CFG, CLK0_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_TIMER_CLK_CFG, CLK5_DIV, 15, 3)
> + FIELD(SYSCLK_TIMER_CLK_CFG, CLK4_DIV, 12, 3)
> + FIELD(SYSCLK_TIMER_CLK_CFG, CLK3_DIV, 9, 3)
> + FIELD(SYSCLK_TIMER_CLK_CFG, CLK2_DIV, 6, 3)
> + FIELD(SYSCLK_TIMER_CLK_CFG, CLK1_DIV, 3, 3)
> + FIELD(SYSCLK_TIMER_CLK_CFG, CLK0_DIV, 0, 3)
> +REG32(SYSCLK_SYSCTL_CLK_DIV_CFG, 0x058)
> + FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, PCLK_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, HDI_CLK_DIV, 28, 3)
> + FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, TS_CLK_DIV, 20, 8)
> + FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, STC_CLK_DIV, 15, 5)
> + FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, WDT1_CLK_DIV, 9, 6)
> + FIELD(SYSCLK_SYSCTL_CLK_DIV_CFG, WDT0_CLK_DIV, 3, 6)
> +REG32(SYSCLK_SHRM_CLK_CFG, 0x05c)
> + FIELD(SYSCLK_SHRM_CLK_CFG, PCLK_ROOT_DIV_UPD, 31, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, PCLK_ROOT_DIV, 18, 3)
> + FIELD(SYSCLK_SHRM_CLK_CFG, SRAM_CLK_SEL, 14, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, AXIM_BRIDGE_CLK_EN, 13, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, AXIM_CLK_EN, 12, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, AXIS_CLK_EN, 11, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, SRAM_ACLK_ENABLE, 10, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, NONAI2D_ACLK_ENABLE, 9, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, NONAI2D_PCLK_ENABLE, 8, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, DECOMPRESS_ACLK_ENABLE, 7, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, DECOMPRESS_PCLK_ENABLE, 6, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, GSDMA_ACLK_ENABLE, 5, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, GSDMA_PCLK_ENABLE, 4, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, PERI_DMA_ACLK_ENABLE, 3, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, PERI_DMA_PCLK_ENABLE, 2, 1)
> + FIELD(SYSCLK_SHRM_CLK_CFG, PCLK_ENABLE, 0, 1)
> +REG32(SYSCLK_DDR_CLK_CFG, 0x060)
> + FIELD(SYSCLK_DDR_CLK_CFG, CORE_CLK_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_DDR_CLK_CFG, PCLK_DIV, 14, 4)
> + FIELD(SYSCLK_DDR_CLK_CFG, CORE_CLK_DIV, 10, 4)
> + FIELD(SYSCLK_DDR_CLK_CFG, PCLK_ENABLE, 9, 1)
> + FIELD(SYSCLK_DDR_CLK_CFG, BYPASSPCLK_ENABLE, 8, 1)
> + FIELD(SYSCLK_DDR_CLK_CFG, AXI4CLK_ENABLE, 7, 1)
> + FIELD(SYSCLK_DDR_CLK_CFG, AXI3CLK_ENABLE, 6, 1)
> + FIELD(SYSCLK_DDR_CLK_CFG, AXI2CLK_ENABLE, 5, 1)
> + FIELD(SYSCLK_DDR_CLK_CFG, AXI1CLK_ENABLE, 4, 1)
> + FIELD(SYSCLK_DDR_CLK_CFG, AXI0CLK_ENABLE, 3, 1)
> + FIELD(SYSCLK_DDR_CLK_CFG, CLK_ENABLE, 2, 1)
> + FIELD(SYSCLK_DDR_CLK_CFG, CLK_SEL, 0, 2)
> +/*
> + * SDK sysctl_clk_t marks offsets 0x064..0x078 reserved; the TRM defines
> + * these registers, so the TRM layout is authoritative for the v1 model.
> + */
> +REG32(SYSCLK_ISP_CLKEN_CFG, 0x064)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, DW_ACLK_ENABLE, 19, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, DW_HCLK_ENABLE, 18, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, MCM_CLK_ENABLE, 17, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, VSE_CLK_ENABLE, 16, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, DWE_CLK_ENABLE, 15, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, ACLK_ENABLE, 14, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, HCLK_ENABLE, 13, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CLK_ENABLE, 12, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CSI2_PCLK_ENABLE, 11, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CSI1_PCLK_ENABLE, 10, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CSI0_PCLK_ENABLE, 9, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CSI2_PIXELCLK_ENABLE, 8, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CSI1_PIXELCLK_ENABLE, 7, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CSI0_PIXELCLK_ENABLE, 6, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, DPHY_PCLK_ENABLE, 5, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CFG2_CLK_ENABLE, 4, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CFG1_CLK_ENABLE, 3, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CFG0_CLK_ENABLE, 2, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, PCLK_ENABLE, 1, 1)
> + FIELD(SYSCLK_ISP_CLKEN_CFG, CSIPHY_CFGCLK_ENABLE, 0, 1)
> +REG32(SYSCLK_ISP_CLKDIV_CFG, 0x068)
> + FIELD(SYSCLK_ISP_CLKDIV_CFG, CFG_CLK_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_ISP_CLKDIV_CFG, CLK_SEL, 29, 1)
> + FIELD(SYSCLK_ISP_CLKDIV_CFG, CLK_DIV, 26, 3)
> + FIELD(SYSCLK_ISP_CLKDIV_CFG, PCLK_DIV, 23, 3)
> + FIELD(SYSCLK_ISP_CLKDIV_CFG, CSI2_PIXEL_CLK_DIV, 17, 6)
> + FIELD(SYSCLK_ISP_CLKDIV_CFG, CSI1_PIXEL_CLK_DIV, 11, 6)
> + FIELD(SYSCLK_ISP_CLKDIV_CFG, CSI0_PIXEL_CLK_DIV, 5, 6)
> + FIELD(SYSCLK_ISP_CLKDIV_CFG, CFG_CLK_DIV, 0, 5)
> +REG32(SYSCLK_MCLK_CFG, 0x06c)
> + FIELD(SYSCLK_MCLK_CFG, MCLK0_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_MCLK_CFG, MCLK2_DIV, 19, 5)
> + FIELD(SYSCLK_MCLK_CFG, MCLK2_SEL, 17, 2)
> + FIELD(SYSCLK_MCLK_CFG, MCLK1_DIV, 12, 5)
> + FIELD(SYSCLK_MCLK_CFG, MCLK1_SEL, 10, 2)
> + FIELD(SYSCLK_MCLK_CFG, MCLK0_DIV, 5, 5)
> + FIELD(SYSCLK_MCLK_CFG, MCLK0_SEL, 3, 2)
> + FIELD(SYSCLK_MCLK_CFG, MCLK2_ENABLE, 2, 1)
> + FIELD(SYSCLK_MCLK_CFG, MCLK1_ENABLE, 1, 1)
> + FIELD(SYSCLK_MCLK_CFG, MCLK0_ENABLE, 0, 1)
> +REG32(SYSCLK_DPU_CLK_CFG, 0x070)
> + FIELD(SYSCLK_DPU_CLK_CFG, CLK_DIV_UPD, 31, 1)
> + FIELD(SYSCLK_DPU_CLK_CFG, PCLK_DIV, 7, 3)
> + FIELD(SYSCLK_DPU_CLK_CFG, CLK_DIV, 3, 4)
> + FIELD(SYSCLK_DPU_CLK_CFG, PCLK_ENABLE, 2, 1)
> + FIELD(SYSCLK_DPU_CLK_CFG, ACLK_ENABLE, 1, 1)
> + FIELD(SYSCLK_DPU_CLK_CFG, CLK_ENABLE, 0, 1)
> +REG32(SYSCLK_VO_CLK_CFG, 0x074)
> + FIELD(SYSCLK_VO_CLK_CFG, ACLK_GPU_EN, 12, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, ACLK_VO_EN, 11, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, HCLK_GPU_EN, 10, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, PCLK_DSI_PHY_EN, 9, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, PCLK_DSI_ENABLE, 8, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, PCLK_VO_ENABLE, 7, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, CLK_GPU_ENABLE, 6, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, CLKEXT_ENABLE, 5, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, CFGCLK_ENABLE, 4, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, REFCLK_ENABLE, 3, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, DPIPCLK_ENABLE, 2, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, ACLK_ENABLE, 1, 1)
> + FIELD(SYSCLK_VO_CLK_CFG, HCLK_ENABLE, 0, 1)
> +REG32(SYSCLK_DISP_CLK_DIV, 0x078)
> + FIELD(SYSCLK_DISP_CLK_DIV, HCLK_ROOT_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_DISP_CLK_DIV, CLK_GPU_DIV, 20, 4)
> + FIELD(SYSCLK_DISP_CLK_DIV, CLKEXT_DIV, 16, 4)
> + FIELD(SYSCLK_DISP_CLK_DIV, CFGCLK_DIV, 11, 5)
> + FIELD(SYSCLK_DISP_CLK_DIV, DPIPCLK_DIV, 3, 8)
> + FIELD(SYSCLK_DISP_CLK_DIV, HCLK_ROOT_DIV, 0, 3)
> +REG32(SYSCLK_SEC_CLK_DIV, 0x080)
> + FIELD(SYSCLK_SEC_CLK_DIV, PCLK_DIV_UPD, 31, 1)
> + FIELD(SYSCLK_SEC_CLK_DIV, ACLK_DIV, 11, 3)
> + FIELD(SYSCLK_SEC_CLK_DIV, FIXCLK_DIV, 6, 5)
> + FIELD(SYSCLK_SEC_CLK_DIV, FIXCLK_ENABLE, 5, 1)
> + FIELD(SYSCLK_SEC_CLK_DIV, ACLK_ENABLE, 4, 1)
> + FIELD(SYSCLK_SEC_CLK_DIV, PCLK_DIV, 1, 3)
> + FIELD(SYSCLK_SEC_CLK_DIV, PCLK_ENABLE, 0, 1)
> +REG32(SYSCLK_USB_TEST_CLK_DIV, 0x100)
> + FIELD(SYSCLK_USB_TEST_CLK_DIV, CLK480_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_USB_TEST_CLK_DIV, CLK100_DIV, 4, 3)
> + FIELD(SYSCLK_USB_TEST_CLK_DIV, CLK480_DIV, 1, 3)
> + FIELD(SYSCLK_USB_TEST_CLK_DIV, TEST_CLK_ENABLE, 0, 1)
> +REG32(SYSCLK_DPHY_TEST_CLK_DIV, 0x104)
> + FIELD(SYSCLK_DPHY_TEST_CLK_DIV, TEST_CLK_CDIV_UPD, 31, 1)
> + FIELD(SYSCLK_DPHY_TEST_CLK_DIV, TEST_CLK_DIV, 1, 4)
> + FIELD(SYSCLK_DPHY_TEST_CLK_DIV, TEST_CLK_ENABLE, 0, 1)
> +/*
> + * The TRM v0.3.1 sysclk summary ends at 0x104. Linux and the SDK both
> + * access SPI2AXI_CLK_DIV at 0x108, so v1 preserves this software ABI
> + * exception.
> + */
> +REG32(SYSCLK_SPI2AXI_CLK_DIV, 0x108)
> + FIELD(SYSCLK_SPI2AXI_CLK_DIV, CLK_DIV_UPD, 31, 1)
> + FIELD(SYSCLK_SPI2AXI_CLK_DIV, CLK_DIV, 1, 3)
> + FIELD(SYSCLK_SPI2AXI_CLK_DIV, CLK_ENABLE, 0, 1)
> +
> +typedef struct K230PllRegDesc {
> + hwaddr offset;
> + const char *name;
> + uint32_t reset[K230_PLL_COUNT];
> + uint32_t rw_mask;
> + uint32_t ro_mask;
> + uint32_t w1t_mask;
> + uint8_t write_enable_shift;
> + uint32_t write_enable_mask;
> +} K230PllRegDesc;
> +
> +typedef struct K230SysclkRegDesc {
> + hwaddr offset;
> + const char *name;
> + uint32_t reset;
> + uint32_t rw_mask;
> + uint32_t w1t_mask;
> +} K230SysclkRegDesc;
> +
> +static const K230PllRegDesc k230_pll_regs[] = {
> + {
> + .offset = A_CMU_CFG0,
> + .name = "PLLx_CFG0",
> + .reset = {
> + 0x0102018f, 0x00000062, 0x00070378, 0x0102018f,
> + },
> + .rw_mask = PLL_CFG0_RW_MASK,
> + },
> + {
> + .offset = A_CMU_CFG1,
> + .name = "PLLx_CFG1",
> + .reset = {
> + 0x000200c7, 0x00020031, 0x000201bb, 0x000200c7,
> + },
> + .rw_mask = PLL_CFG1_RW_MASK,
> + },
> + {
> + .offset = A_CMU_CTL,
> + .name = "PLLx_CTL",
> + .reset = {
> + 0x00000034, 0x00000034, 0x00000034, 0x00000074,
> + },
> + .rw_mask = PLL_CTL_RW_MASK,
> + .w1t_mask = PLL_CTL_W1T_MASK,
Where is w1t_mask actually used?
> + .write_enable_shift = 16,
> + .write_enable_mask = PLL_CTL_LOW_MASK,
> + },
> + {
> + .offset = A_CMU_STAT,
> + .name = "PLLx_STAT",
> + .reset = {
> + 0x00000021, 0x00000021, 0x00000021, 0x00000021,
> + },
> + .ro_mask = PLL_STAT_RO_MASK,
> + },
> +};
> +
> +#define SYSCLK_REG(_reg, _name, _reset, _rw, _w1t) \
> + { .offset = A_ ## _reg, .name = _name, .reset = _reset, \
> + .rw_mask = (_rw), .w1t_mask = (_w1t) }
> +
> +static const K230SysclkRegDesc k230_sysclk_regs[] = {
> + SYSCLK_REG(SYSCLK_CPU0_CLK_CFG, "CPU0_CLK_CFG", 0x0000e65f,
> + 0x0003ffdf, R_SYSCLK_CPU0_CLK_CFG_CORE_CLK_ROOT_GDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_CPU1_CLK_CFG, "CPU1_CLK_CFG", 0x0009900d,
> + 0x000f803f, R_SYSCLK_CPU1_CLK_CFG_CORE_CLK_DIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_AI_CLK_CFG, "AI_CLK_CFG", 0x0000043d,
> + 0x0000043d, R_SYSCLK_AI_CLK_CFG_CLK_DIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_VPU_CLK_CFG, "VPU_CLK_CFG", 0x00000c7f,
> + 0x00007fff, R_SYSCLK_VPU_CLK_CFG_CLK_GDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_PMU_CLK_CFG, "PMU_CLK_CFG", 0x00000001,
> + 0x00000001, 0),
> + SYSCLK_REG(SYSCLK_HS_CLKEN_CFG, "HS_CLKEN_CFG", 0x7f7fffff,
> + 0x7fffffff, 0),
> + SYSCLK_REG(SYSCLK_HS_SDCLK_CFG, "HS_SDCLK_CFG", 0x000b9248,
> + 0x000fffff, R_SYSCLK_HS_SDCLK_CFG_ACLK_ROOT_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_HS_SPI_CFG, "HS_SPI_CFG", 0x00039048,
> + 0x0007fff8, R_SYSCLK_HS_SPI_CFG_SSI0_ACLK_ROOT_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_LS_CLKEN_CFG0, "LS_CLKEN_CFG0", 0xffffffff,
> + 0xffffffff, 0),
> + SYSCLK_REG(SYSCLK_LS_CLKEN_CFG1, "LS_CLKEN_CFG1", 0x000000ff,
> + 0x000000ff, 0),
> + SYSCLK_REG(SYSCLK_UART_I2C_CLKDIV_CFG, "UART_I2C_CLKDIV_CFG",
> + 0x1b6d9249, 0x3fffffff,
> + R_SYSCLK_UART_I2C_CLKDIV_CFG_I2C0_CLK_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_LS_CLKDIV_CFG, "LS_CLKDIV_CFG", 0x01dda0c3,
> + 0x7fffffff, R_SYSCLK_LS_CLKDIV_CFG_JAMLINK_CO_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_AUDIO_CLKDIV_CFG, "AUDIO_CLKDIV_CFG", 0x01b9f424,
> + 0x7fffffff, R_SYSCLK_AUDIO_CLKDIV_CFG_AUD_DEV_CLK_FDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_CODEC_ADC_MCLKDIV_CFG, "CODEC_ADC_MCLKDIV_CFG",
> + 0x006e7d09, 0x07ffffff,
> + R_SYSCLK_CODEC_ADC_MCLKDIV_CFG_MCLK_ADC_FDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_CODEC_DAC_MCLKDIV_CFG, "CODEC_DAC_MCLKDIV_CFG",
> + 0x006e7d09, 0x07ffffff,
> + R_SYSCLK_CODEC_DAC_MCLKDIV_CFG_MCLK_DAC_FDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_PDM_CLKDIV_CFG0, "PDM_CLKDIV_CFG0", 0x0000f424,
> + 0x0001ffff, 0),
> + SYSCLK_REG(SYSCLK_PDM_CLKDIV_CFG1, "PDM_CLKDIV_CFG1", 0x000001b9,
> + 0x0000ffff, R_SYSCLK_PDM_CLKDIV_CFG1_CLK_FDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_SYSCTL_CLKEN_CFG, "SYSCTL_CLKEN_CFG", 0x003ffffe,
> + 0x003ffffe, 0),
> + SYSCLK_REG(SYSCLK_TIMER_CLK_CFG, "TIMER_CLK_CFG", 0x0003ffff,
> + 0x0003ffff, R_SYSCLK_TIMER_CLK_CFG_CLK0_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_SYSCTL_CLK_DIV_CFG, "SYSCTL_CLK_DIV_CFG", 0x1efabef9,
> + 0x7ffffff8, R_SYSCLK_SYSCTL_CLK_DIV_CFG_PCLK_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_SHRM_CLK_CFG, "SHRM_CLK_CFG", 0x000c7ffd,
> + 0x001c7ffd, R_SYSCLK_SHRM_CLK_CFG_PCLK_ROOT_DIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_DDR_CLK_CFG, "DDR_CLK_CFG", 0x000043fd,
> + 0x0003ffff, R_SYSCLK_DDR_CLK_CFG_CORE_CLK_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_ISP_CLKEN_CFG, "ISP_CLKEN_CFG", 0x000fffff,
> + 0x000fffff, 0),
> + SYSCLK_REG(SYSCLK_ISP_CLKDIV_CFG, "ISP_CLKDIV_CFG", 0x00820835,
> + 0x3fffffff, R_SYSCLK_ISP_CLKDIV_CFG_CFG_CLK_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_MCLK_CFG, "MCLK_CFG", 0x003a74ef,
> + 0x00ffffff, R_SYSCLK_MCLK_CFG_MCLK0_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_DPU_CLK_CFG, "DPU_CLK_CFG", 0x000001ff,
> + 0x000003ff, R_SYSCLK_DPU_CLK_CFG_CLK_DIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_VO_CLK_CFG, "VO_CLK_CFG", 0x00001fff,
> + 0x00001fff, 0),
> + SYSCLK_REG(SYSCLK_DISP_CLK_DIV, "DISP_CLK_DIV", 0x0000a83b,
> + 0x00ffffff, R_SYSCLK_DISP_CLK_DIV_HCLK_ROOT_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_SEC_CLK_DIV, "SEC_CLK_DIV", 0x000002f3,
> + 0x00003fff, R_SYSCLK_SEC_CLK_DIV_PCLK_DIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_USB_TEST_CLK_DIV, "USB_TEST_CLK_DIV", 0x00000039,
> + 0x0000007f, R_SYSCLK_USB_TEST_CLK_DIV_CLK480_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_DPHY_TEST_CLK_DIV, "DPHY_TEST_CLK_DIV", 0x00000009,
> + 0x0000001f,
> + R_SYSCLK_DPHY_TEST_CLK_DIV_TEST_CLK_CDIV_UPD_MASK),
> + SYSCLK_REG(SYSCLK_SPI2AXI_CLK_DIV, "SPI2AXI_CLK_DIV", 0x00000007,
> + 0x0000000f,
> + R_SYSCLK_SPI2AXI_CLK_DIV_CLK_DIV_UPD_MASK),
> +};
> +
> +#undef SYSCLK_REG
> +
> +static const K230PllRegDesc *k230_pll_desc(hwaddr addr,
> + unsigned *pll_index)
Please align it with the first parameter after the line break.
Thanks,
Chao
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-18 5:38 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-09 6:20 [PATCH 0/4] Kendryte K230 CMU register model Simon Law
2026-08-09 6:20 ` [PATCH 1/4] hw/misc: model K230 CMU registers Simon Law
2026-08-18 5:37 ` Chao Liu
2026-08-09 6:20 ` [PATCH 2/4] hw/riscv: connect the K230 CMU Simon Law
2026-08-09 6:20 ` [PATCH 3/4] tests/qtest: add K230 CMU coverage Simon Law
2026-08-09 6:20 ` [PATCH 4/4] docs/system/riscv: document K230 CMU support Simon Law
2026-08-14 7:53 ` [PATCH 0/4] Kendryte K230 CMU register model Bin Meng
2026-08-17 8:55 ` Niel Law
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.