U-Boot Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] clk: sophgo: milkv_duo: Add and enable clock controller driver
@ 2024-06-11  9:41 Kongyang Liu
  2024-06-11  9:41 ` [PATCH v2 1/4] dt-bindings: clk: import header for clock controller of sophgo CV1800B Kongyang Liu
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Kongyang Liu @ 2024-06-11  9:41 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Arturs Artamonovs, Caleb Connolly, Greg Malysa,
	Leo, Lukasz Majewski, Marek Vasut, Michal Simek,
	Nathan Barrett-Morrison, Rick Chen, Samuel Holland, Sean Anderson,
	Sumit Garg, Tom Rini, Utsav Agarwal, Vasileios Bimpikas

This series of patches introduces the clock controller driver for the Sophgo
CV1800B SoC, updates the device tree sources to use the new clock controller,
and enables the clock controller in the configuration for the Milk-V Duo board.

Changes in v2:
- Fix compilation error
- Remove unused code

Kongyang Liu (4):
  dt-bindings: clk: import header for clock controller of sophgo CV1800B
  clk: sophgo: cv1800b: Add clock controller driver for cv1800b SoC
  configs: milkv_duo: Enable clock controller
  riscv: dts: sophgo: Replace device clocks with real clocks.

 arch/riscv/dts/cv18xx.dtsi                |  40 +-
 configs/milkv_duo_defconfig               |   9 +-
 drivers/clk/Kconfig                       |   1 +
 drivers/clk/Makefile                      |   1 +
 drivers/clk/sophgo/Kconfig                |  14 +
 drivers/clk/sophgo/Makefile               |   6 +
 drivers/clk/sophgo/clk-common.h           |  74 +++
 drivers/clk/sophgo/clk-cv1800b.c          | 754 ++++++++++++++++++++++
 drivers/clk/sophgo/clk-cv1800b.h          | 123 ++++
 drivers/clk/sophgo/clk-ip.c               | 594 +++++++++++++++++
 drivers/clk/sophgo/clk-ip.h               | 288 +++++++++
 drivers/clk/sophgo/clk-pll.c              | 275 ++++++++
 drivers/clk/sophgo/clk-pll.h              |  74 +++
 include/dt-bindings/clock/sophgo,cv1800.h | 176 +++++
 14 files changed, 2401 insertions(+), 28 deletions(-)
 create mode 100644 drivers/clk/sophgo/Kconfig
 create mode 100644 drivers/clk/sophgo/Makefile
 create mode 100644 drivers/clk/sophgo/clk-common.h
 create mode 100644 drivers/clk/sophgo/clk-cv1800b.c
 create mode 100644 drivers/clk/sophgo/clk-cv1800b.h
 create mode 100644 drivers/clk/sophgo/clk-ip.c
 create mode 100644 drivers/clk/sophgo/clk-ip.h
 create mode 100644 drivers/clk/sophgo/clk-pll.c
 create mode 100644 drivers/clk/sophgo/clk-pll.h
 create mode 100644 include/dt-bindings/clock/sophgo,cv1800.h

-- 
2.41.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 1/4] dt-bindings: clk: import header for clock controller of sophgo CV1800B
  2024-06-11  9:41 [PATCH v2 0/4] clk: sophgo: milkv_duo: Add and enable clock controller driver Kongyang Liu
@ 2024-06-11  9:41 ` Kongyang Liu
  2024-09-09  6:00   ` Leo Liang
  2024-06-11  9:41 ` [PATCH v2 2/4] clk: sophgo: cv1800b: Add clock controller driver for cv1800b SoC Kongyang Liu
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Kongyang Liu @ 2024-06-11  9:41 UTC (permalink / raw)
  To: u-boot; +Cc: Tom Rini

Import header file of sophgo cv1800b clock controller from kernel

Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>
Link: https://lore.kernel.org/all/IA1PR20MB4953637E7A6C121D7A700F1CBB8BA@IA1PR20MB4953.namprd20.prod.outlook.com/

---

(no changes since v1)

 include/dt-bindings/clock/sophgo,cv1800.h | 176 ++++++++++++++++++++++
 1 file changed, 176 insertions(+)
 create mode 100644 include/dt-bindings/clock/sophgo,cv1800.h

diff --git a/include/dt-bindings/clock/sophgo,cv1800.h b/include/dt-bindings/clock/sophgo,cv1800.h
new file mode 100644
index 0000000000..cfbeca25a6
--- /dev/null
+++ b/include/dt-bindings/clock/sophgo,cv1800.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/*
+ * Copyright (C) 2023 Sophgo Ltd.
+ */
+
+#ifndef __DT_BINDINGS_SOPHGO_CV1800_CLK_H__
+#define __DT_BINDINGS_SOPHGO_CV1800_CLK_H__
+
+#define CLK_MPLL			0
+#define CLK_TPLL			1
+#define CLK_FPLL			2
+#define CLK_MIPIMPLL			3
+#define CLK_A0PLL			4
+#define CLK_DISPPLL			5
+#define CLK_CAM0PLL			6
+#define CLK_CAM1PLL			7
+
+#define CLK_MIPIMPLL_D3			8
+#define CLK_CAM0PLL_D2			9
+#define CLK_CAM0PLL_D3			10
+
+#define CLK_TPU				11
+#define CLK_TPU_FAB			12
+#define CLK_AHB_ROM			13
+#define CLK_DDR_AXI_REG			14
+#define CLK_RTC_25M			15
+#define CLK_SRC_RTC_SYS_0		16
+#define CLK_TEMPSEN			17
+#define CLK_SARADC			18
+#define CLK_EFUSE			19
+#define CLK_APB_EFUSE			20
+#define CLK_DEBUG			21
+#define CLK_AP_DEBUG			22
+#define CLK_XTAL_MISC			23
+#define CLK_AXI4_EMMC			24
+#define CLK_EMMC			25
+#define CLK_EMMC_100K			26
+#define CLK_AXI4_SD0			27
+#define CLK_SD0				28
+#define CLK_SD0_100K			29
+#define CLK_AXI4_SD1			30
+#define CLK_SD1				31
+#define CLK_SD1_100K			32
+#define CLK_SPI_NAND			33
+#define CLK_ETH0_500M			34
+#define CLK_AXI4_ETH0			35
+#define CLK_ETH1_500M			36
+#define CLK_AXI4_ETH1			37
+#define CLK_APB_GPIO			38
+#define CLK_APB_GPIO_INTR		39
+#define CLK_GPIO_DB			40
+#define CLK_AHB_SF			41
+#define CLK_AHB_SF1			42
+#define CLK_A24M			43
+#define CLK_AUDSRC			44
+#define CLK_APB_AUDSRC			45
+#define CLK_SDMA_AXI			46
+#define CLK_SDMA_AUD0			47
+#define CLK_SDMA_AUD1			48
+#define CLK_SDMA_AUD2			49
+#define CLK_SDMA_AUD3			50
+#define CLK_I2C				51
+#define CLK_APB_I2C			52
+#define CLK_APB_I2C0			53
+#define CLK_APB_I2C1			54
+#define CLK_APB_I2C2			55
+#define CLK_APB_I2C3			56
+#define CLK_APB_I2C4			57
+#define CLK_APB_WDT			58
+#define CLK_PWM_SRC			59
+#define CLK_PWM				60
+#define CLK_SPI				61
+#define CLK_APB_SPI0			62
+#define CLK_APB_SPI1			63
+#define CLK_APB_SPI2			64
+#define CLK_APB_SPI3			65
+#define CLK_1M				66
+#define CLK_CAM0_200			67
+#define CLK_PM				68
+#define CLK_TIMER0			69
+#define CLK_TIMER1			70
+#define CLK_TIMER2			71
+#define CLK_TIMER3			72
+#define CLK_TIMER4			73
+#define CLK_TIMER5			74
+#define CLK_TIMER6			75
+#define CLK_TIMER7			76
+#define CLK_UART0			77
+#define CLK_APB_UART0			78
+#define CLK_UART1			79
+#define CLK_APB_UART1			80
+#define CLK_UART2			81
+#define CLK_APB_UART2			82
+#define CLK_UART3			83
+#define CLK_APB_UART3			84
+#define CLK_UART4			85
+#define CLK_APB_UART4			86
+#define CLK_APB_I2S0			87
+#define CLK_APB_I2S1			88
+#define CLK_APB_I2S2			89
+#define CLK_APB_I2S3			90
+#define CLK_AXI4_USB			91
+#define CLK_APB_USB			92
+#define CLK_USB_125M			93
+#define CLK_USB_33K			94
+#define CLK_USB_12M			95
+#define CLK_AXI4			96
+#define CLK_AXI6			97
+#define CLK_DSI_ESC			98
+#define CLK_AXI_VIP			99
+#define CLK_SRC_VIP_SYS_0		100
+#define CLK_SRC_VIP_SYS_1		101
+#define CLK_SRC_VIP_SYS_2		102
+#define CLK_SRC_VIP_SYS_3		103
+#define CLK_SRC_VIP_SYS_4		104
+#define CLK_CSI_BE_VIP			105
+#define CLK_CSI_MAC0_VIP		106
+#define CLK_CSI_MAC1_VIP		107
+#define CLK_CSI_MAC2_VIP		108
+#define CLK_CSI0_RX_VIP			109
+#define CLK_CSI1_RX_VIP			110
+#define CLK_ISP_TOP_VIP			111
+#define CLK_IMG_D_VIP			112
+#define CLK_IMG_V_VIP			113
+#define CLK_SC_TOP_VIP			114
+#define CLK_SC_D_VIP			115
+#define CLK_SC_V1_VIP			116
+#define CLK_SC_V2_VIP			117
+#define CLK_SC_V3_VIP			118
+#define CLK_DWA_VIP			119
+#define CLK_BT_VIP			120
+#define CLK_DISP_VIP			121
+#define CLK_DSI_MAC_VIP			122
+#define CLK_LVDS0_VIP			123
+#define CLK_LVDS1_VIP			124
+#define CLK_PAD_VI_VIP			125
+#define CLK_PAD_VI1_VIP			126
+#define CLK_PAD_VI2_VIP			127
+#define CLK_CFG_REG_VIP			128
+#define CLK_VIP_IP0			129
+#define CLK_VIP_IP1			130
+#define CLK_VIP_IP2			131
+#define CLK_VIP_IP3			132
+#define CLK_IVE_VIP			133
+#define CLK_RAW_VIP			134
+#define CLK_OSDC_VIP			135
+#define CLK_CAM0_VIP			136
+#define CLK_AXI_VIDEO_CODEC		137
+#define CLK_VC_SRC0			138
+#define CLK_VC_SRC1			139
+#define CLK_VC_SRC2			140
+#define CLK_H264C			141
+#define CLK_APB_H264C			142
+#define CLK_H265C			143
+#define CLK_APB_H265C			144
+#define CLK_JPEG			145
+#define CLK_APB_JPEG			146
+#define CLK_CAM0			147
+#define CLK_CAM1			148
+#define CLK_WGN				149
+#define CLK_WGN0			150
+#define CLK_WGN1			151
+#define CLK_WGN2			152
+#define CLK_KEYSCAN			153
+#define CLK_CFG_REG_VC			154
+#define CLK_C906_0			155
+#define CLK_C906_1			156
+#define CLK_A53				157
+#define CLK_CPU_AXI0			158
+#define CLK_CPU_GIC			159
+#define CLK_XTAL_AP			160
+
+// Only for CV181x
+#define CLK_DISP_SRC_VIP		161
+
+#endif /* __DT_BINDINGS_SOPHGO_CV1800_CLK_H__ */
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 2/4] clk: sophgo: cv1800b: Add clock controller driver for cv1800b SoC
  2024-06-11  9:41 [PATCH v2 0/4] clk: sophgo: milkv_duo: Add and enable clock controller driver Kongyang Liu
  2024-06-11  9:41 ` [PATCH v2 1/4] dt-bindings: clk: import header for clock controller of sophgo CV1800B Kongyang Liu
@ 2024-06-11  9:41 ` Kongyang Liu
  2024-09-09  6:02   ` Leo Liang
  2024-06-11  9:41 ` [PATCH v2 3/4] configs: milkv_duo: Enable clock controller Kongyang Liu
  2024-06-11  9:41 ` [PATCH v2 4/4] riscv: dts: sophgo: Replace device clocks with real clocks Kongyang Liu
  3 siblings, 1 reply; 9+ messages in thread
From: Kongyang Liu @ 2024-06-11  9:41 UTC (permalink / raw)
  To: u-boot
  Cc: Andre Przywara, Arturs Artamonovs, Caleb Connolly, Greg Malysa,
	Leo Yu-Chi Liang, Lukasz Majewski, Marek Vasut, Michal Simek,
	Nathan Barrett-Morrison, Samuel Holland, Sean Anderson,
	Sumit Garg, Tom Rini, Utsav Agarwal, Vasileios Bimpikas

Add clock controller driver for sophgo cv1800b SoC

Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>

---

Changes in v2:
- Fix compilation error
- Remove unused code

 drivers/clk/Kconfig              |   1 +
 drivers/clk/Makefile             |   1 +
 drivers/clk/sophgo/Kconfig       |  14 +
 drivers/clk/sophgo/Makefile      |   6 +
 drivers/clk/sophgo/clk-common.h  |  74 +++
 drivers/clk/sophgo/clk-cv1800b.c | 754 +++++++++++++++++++++++++++++++
 drivers/clk/sophgo/clk-cv1800b.h | 123 +++++
 drivers/clk/sophgo/clk-ip.c      | 594 ++++++++++++++++++++++++
 drivers/clk/sophgo/clk-ip.h      | 288 ++++++++++++
 drivers/clk/sophgo/clk-pll.c     | 275 +++++++++++
 drivers/clk/sophgo/clk-pll.h     |  74 +++
 11 files changed, 2204 insertions(+)
 create mode 100644 drivers/clk/sophgo/Kconfig
 create mode 100644 drivers/clk/sophgo/Makefile
 create mode 100644 drivers/clk/sophgo/clk-common.h
 create mode 100644 drivers/clk/sophgo/clk-cv1800b.c
 create mode 100644 drivers/clk/sophgo/clk-cv1800b.h
 create mode 100644 drivers/clk/sophgo/clk-ip.c
 create mode 100644 drivers/clk/sophgo/clk-ip.h
 create mode 100644 drivers/clk/sophgo/clk-pll.c
 create mode 100644 drivers/clk/sophgo/clk-pll.h

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index bda6873be3..0a16b88f78 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -256,6 +256,7 @@ source "drivers/clk/mvebu/Kconfig"
 source "drivers/clk/owl/Kconfig"
 source "drivers/clk/qcom/Kconfig"
 source "drivers/clk/renesas/Kconfig"
+source "drivers/clk/sophgo/Kconfig"
 source "drivers/clk/sunxi/Kconfig"
 source "drivers/clk/sifive/Kconfig"
 source "drivers/clk/starfive/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 638ad04bae..d9b1e5a341 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_CLK_QCOM) += qcom/
 obj-$(CONFIG_CLK_RENESAS) += renesas/
 obj-$(CONFIG_$(SPL_TPL_)CLK_SCMI) += clk_scmi.o
 obj-$(CONFIG_CLK_SIFIVE) += sifive/
+obj-$(CONFIG_CLK_SOPHGO) += sophgo/
 obj-$(CONFIG_CLK_SUNXI) += sunxi/
 obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
 obj-$(CONFIG_CLK_VERSACLOCK) += clk_versaclock.o
diff --git a/drivers/clk/sophgo/Kconfig b/drivers/clk/sophgo/Kconfig
new file mode 100644
index 0000000000..59b51608fe
--- /dev/null
+++ b/drivers/clk/sophgo/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+
+config CLK_SOPHGO
+	bool
+
+config CLK_SOPHGO_CV1800B
+	bool "Sophgo CV1800B clock support"
+	depends on CLK
+	select CLK_CCF
+	select CLK_SOPHGO
+	help
+	  This enables support clock driver for Sophgo CV1800B SoC.
diff --git a/drivers/clk/sophgo/Makefile b/drivers/clk/sophgo/Makefile
new file mode 100644
index 0000000000..caec76222b
--- /dev/null
+++ b/drivers/clk/sophgo/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+
+obj-y += clk-ip.o clk-pll.o
+obj-$(CONFIG_CLK_SOPHGO_CV1800B) += clk-cv1800b.o
diff --git a/drivers/clk/sophgo/clk-common.h b/drivers/clk/sophgo/clk-common.h
new file mode 100644
index 0000000000..95b82e968d
--- /dev/null
+++ b/drivers/clk/sophgo/clk-common.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ *
+ */
+
+#ifndef __CLK_SOPHGO_COMMON_H__
+#define __CLK_SOPHGO_COMMON_H__
+
+#include <linux/bitops.h>
+#include <linux/io.h>
+
+#define CV1800B_CLK_OSC 1
+#define CV1800B_CLK_BYPASS 2
+#define CV1800B_CLK_ID_TRANSFORM(_id) ((_id) + 3)
+
+struct cv1800b_clk_regbit {
+	u32 offset;
+	u8 shift;
+};
+
+struct cv1800b_clk_regfield {
+	u32 offset;
+	u8 shift;
+	u8 width;
+};
+
+#define CV1800B_CLK_REGBIT(_offset, _shift)	\
+	{					\
+		.offset = _offset,		\
+		.shift = _shift,		\
+	}
+
+#define CV1800B_CLK_REGFIELD(_offset, _shift, _width)	\
+	{						\
+		.offset = _offset,			\
+		.shift = _shift,			\
+		.width = _width,			\
+	}
+
+static inline u32 cv1800b_clk_getbit(void *base, struct cv1800b_clk_regbit *bit)
+{
+	return readl(base + bit->offset) & (BIT(bit->shift));
+}
+
+static inline u32 cv1800b_clk_setbit(void *base, struct cv1800b_clk_regbit *bit)
+{
+	return setbits_le32(base + bit->offset, BIT(bit->shift));
+}
+
+static inline u32 cv1800b_clk_clrbit(void *base, struct cv1800b_clk_regbit *bit)
+{
+	return clrbits_le32(base + bit->offset, BIT(bit->shift));
+}
+
+static inline u32 cv1800b_clk_getfield(void *base,
+				       struct cv1800b_clk_regfield *field)
+{
+	u32 mask = GENMASK(field->shift + field->width - 1, field->shift);
+
+	return (readl(base + field->offset) & mask) >> field->shift;
+}
+
+static inline void
+cv1800b_clk_setfield(void *base, struct cv1800b_clk_regfield *field, u32 val)
+{
+	u32 mask = GENMASK(field->shift + field->width - 1, field->shift);
+	u32 new_val = (readl(base + field->offset) & ~mask) |
+		      ((val << field->shift) & mask);
+
+	return writel(new_val, base + field->offset);
+}
+
+#endif /* __CLK_SOPHGO_COMMON_H__ */
diff --git a/drivers/clk/sophgo/clk-cv1800b.c b/drivers/clk/sophgo/clk-cv1800b.c
new file mode 100644
index 0000000000..d946ea57a4
--- /dev/null
+++ b/drivers/clk/sophgo/clk-cv1800b.c
@@ -0,0 +1,754 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/clk-provider.h>
+
+#include "clk-common.h"
+#include "clk-cv1800b.h"
+#include "clk-ip.h"
+#include "clk-pll.h"
+
+static const char *const clk_cam_parents[] = {
+	"clk_cam0pll",
+	"clk_cam0pll_d2",
+	"clk_cam0pll_d3",
+	"clk_mipimpll_d3"
+};
+
+static const char *const clk_tpu_parents[] = {
+	"clk_tpll",
+	"clk_a0pll",
+	"clk_mipimpll",
+	"clk_fpll"
+};
+
+static const char *const clk_axi4_parents[] = { "clk_fpll", "clk_disppll" };
+static const char *const clk_aud_parents[] = { "clk_a0pll", "clk_a24m" };
+static const char *const clk_cam0_200_parents[] = { "osc", "clk_disppll" };
+
+static const char *const clk_vip_sys_parents[] = {
+	"clk_mipimpll",
+	"clk_cam0pll",
+	"clk_disppll",
+	"clk_fpll"
+};
+
+static const char *const clk_axi_video_codec_parents[] = {
+	"clk_a0pll",
+	"clk_mipimpll",
+	"clk_cam1pll",
+	"clk_fpll"
+};
+
+static const char *const clk_vc_src0_parents[] = {
+	"clk_disppll",
+	"clk_mipimpll",
+	"clk_cam1pll",
+	"clk_fpll"
+};
+
+static const struct cv1800b_mmux_parent_info clk_c906_0_parents[] = {
+	{ "clk_tpll", 0, 0 },
+	{ "clk_a0pll", 0, 1 },
+	{ "clk_mipimpll", 0, 2 },
+	{ "clk_mpll", 0, 3 },
+	{ "clk_fpll", 1, 0 },
+};
+
+static const struct cv1800b_mmux_parent_info clk_c906_1_parents[] = {
+	{ "clk_tpll", 0, 0 },
+	{ "clk_a0pll", 0, 1 },
+	{ "clk_disppll", 0, 2 },
+	{ "clk_mpll", 0, 3 },
+	{ "clk_fpll", 1, 0 },
+};
+
+static const struct cv1800b_mmux_parent_info clk_a53_parents[] = {
+	{ "clk_tpll", 0, 0 },
+	{ "clk_a0pll", 0, 1 },
+	{ "clk_mipimpll", 0, 2 },
+	{ "clk_mpll", 0, 3 },
+	{ "clk_fpll", 1, 0 },
+};
+
+static struct cv1800b_clk_gate cv1800b_gate_info[] = {
+	CV1800B_GATE(CLK_XTAL_AP, "clk_xtal_ap", "osc", REG_CLK_EN_0, 3, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_RTC_25M, "clk_rtc_25m", "osc", REG_CLK_EN_0, 8, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_TEMPSEN, "clk_tempsen", "osc", REG_CLK_EN_0, 9, 0),
+	CV1800B_GATE(CLK_SARADC, "clk_saradc", "osc", REG_CLK_EN_0, 10, 0),
+	CV1800B_GATE(CLK_EFUSE, "clk_efuse", "osc", REG_CLK_EN_0, 11, 0),
+	CV1800B_GATE(CLK_APB_EFUSE, "clk_apb_efuse", "osc", REG_CLK_EN_0, 12, 0),
+	CV1800B_GATE(CLK_DEBUG, "clk_debug", "osc", REG_CLK_EN_0, 13, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_XTAL_MISC, "clk_xtal_misc", "osc", REG_CLK_EN_0, 14, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_APB_WDT, "clk_apb_wdt", "osc", REG_CLK_EN_1, 7, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_WGN, "clk_wgn", "osc", REG_CLK_EN_3, 22, 0),
+	CV1800B_GATE(CLK_WGN0, "clk_wgn0", "osc", REG_CLK_EN_3, 23, 0),
+	CV1800B_GATE(CLK_WGN1, "clk_wgn1", "osc", REG_CLK_EN_3, 24, 0),
+	CV1800B_GATE(CLK_WGN2, "clk_wgn2", "osc", REG_CLK_EN_3, 25, 0),
+	CV1800B_GATE(CLK_KEYSCAN, "clk_keyscan", "osc", REG_CLK_EN_3, 26, 0),
+	CV1800B_GATE(CLK_TPU_FAB, "clk_tpu_fab", "clk_mipimpll", REG_CLK_EN_0, 5, 0),
+	CV1800B_GATE(CLK_AHB_ROM, "clk_ahb_rom", "clk_axi4", REG_CLK_EN_0, 6, 0),
+	CV1800B_GATE(CLK_AXI4_EMMC, "clk_axi4_emmc", "clk_axi4", REG_CLK_EN_0, 15, 0),
+	CV1800B_GATE(CLK_AXI4_SD0, "clk_axi4_sd0", "clk_axi4", REG_CLK_EN_0, 18, 0),
+	CV1800B_GATE(CLK_AXI4_SD1, "clk_axi4_sd1", "clk_axi4", REG_CLK_EN_0, 21, 0),
+	CV1800B_GATE(CLK_AXI4_ETH0, "clk_axi4_eth0", "clk_axi4", REG_CLK_EN_0, 26, 0),
+	CV1800B_GATE(CLK_AXI4_ETH1, "clk_axi4_eth1", "clk_axi4", REG_CLK_EN_0, 28, 0),
+	CV1800B_GATE(CLK_AHB_SF, "clk_ahb_sf", "clk_axi4", REG_CLK_EN_1, 0, 0),
+	CV1800B_GATE(CLK_SDMA_AXI, "clk_sdma_axi", "clk_axi4", REG_CLK_EN_1, 1, 0),
+	CV1800B_GATE(CLK_APB_I2C, "clk_apb_i2c", "clk_axi4", REG_CLK_EN_1, 6, 0),
+	CV1800B_GATE(CLK_APB_SPI0, "clk_apb_spi0", "clk_axi4", REG_CLK_EN_1, 9, 0),
+	CV1800B_GATE(CLK_APB_SPI1, "clk_apb_spi1", "clk_axi4", REG_CLK_EN_1, 10, 0),
+	CV1800B_GATE(CLK_APB_SPI2, "clk_apb_spi2", "clk_axi4", REG_CLK_EN_1, 11, 0),
+	CV1800B_GATE(CLK_APB_SPI3, "clk_apb_spi3", "clk_axi4", REG_CLK_EN_1, 12, 0),
+	CV1800B_GATE(CLK_APB_UART0, "clk_apb_uart0", "clk_axi4", REG_CLK_EN_1, 15, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_APB_UART1, "clk_apb_uart1", "clk_axi4", REG_CLK_EN_1, 17, 0),
+	CV1800B_GATE(CLK_APB_UART2, "clk_apb_uart2", "clk_axi4", REG_CLK_EN_1, 19, 0),
+	CV1800B_GATE(CLK_APB_UART3, "clk_apb_uart3", "clk_axi4", REG_CLK_EN_1, 21, 0),
+	CV1800B_GATE(CLK_APB_UART4, "clk_apb_uart4", "clk_axi4", REG_CLK_EN_1, 23, 0),
+	CV1800B_GATE(CLK_APB_I2S0, "clk_apb_i2s0", "clk_axi4", REG_CLK_EN_1, 24, 0),
+	CV1800B_GATE(CLK_APB_I2S1, "clk_apb_i2s1", "clk_axi4", REG_CLK_EN_1, 25, 0),
+	CV1800B_GATE(CLK_APB_I2S2, "clk_apb_i2s2", "clk_axi4", REG_CLK_EN_1, 26, 0),
+	CV1800B_GATE(CLK_APB_I2S3, "clk_apb_i2s3", "clk_axi4", REG_CLK_EN_1, 27, 0),
+	CV1800B_GATE(CLK_AXI4_USB, "clk_axi4_usb", "clk_axi4", REG_CLK_EN_1, 28, 0),
+	CV1800B_GATE(CLK_APB_USB, "clk_apb_usb", "clk_axi4", REG_CLK_EN_1, 29, 0),
+	CV1800B_GATE(CLK_APB_I2C0, "clk_apb_i2c0", "clk_axi4", REG_CLK_EN_3, 17, 0),
+	CV1800B_GATE(CLK_APB_I2C1, "clk_apb_i2c1", "clk_axi4", REG_CLK_EN_3, 18, 0),
+	CV1800B_GATE(CLK_APB_I2C2, "clk_apb_i2c2", "clk_axi4", REG_CLK_EN_3, 19, 0),
+	CV1800B_GATE(CLK_APB_I2C3, "clk_apb_i2c3", "clk_axi4", REG_CLK_EN_3, 20, 0),
+	CV1800B_GATE(CLK_APB_I2C4, "clk_apb_i2c4", "clk_axi4", REG_CLK_EN_3, 21, 0),
+	CV1800B_GATE(CLK_AHB_SF1, "clk_ahb_sf1", "clk_axi4", REG_CLK_EN_3, 27, 0),
+	CV1800B_GATE(CLK_APB_AUDSRC, "clk_apb_audsrc", "clk_axi4", REG_CLK_EN_4, 2, 0),
+	CV1800B_GATE(CLK_DDR_AXI_REG, "clk_ddr_axi_reg", "clk_axi6", REG_CLK_EN_0, 7,
+		     CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_APB_GPIO, "clk_apb_gpio", "clk_axi6", REG_CLK_EN_0, 29, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_APB_GPIO_INTR, "clk_apb_gpio_intr", "clk_axi6", REG_CLK_EN_0, 30,
+		     CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_APB_JPEG, "clk_apb_jpeg", "clk_axi6", REG_CLK_EN_2, 13, CLK_IGNORE_UNUSED),
+	CV1800B_GATE(CLK_APB_H264C, "clk_apb_h264c", "clk_axi6", REG_CLK_EN_2, 14, 0),
+	CV1800B_GATE(CLK_APB_H265C, "clk_apb_h265c", "clk_axi6", REG_CLK_EN_2, 15, 0),
+	CV1800B_GATE(CLK_PM, "clk_pm", "clk_axi6", REG_CLK_EN_3, 8, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_CFG_REG_VIP, "clk_cfg_reg_vip", "clk_axi6", REG_CLK_EN_3, 31, 0),
+	CV1800B_GATE(CLK_CFG_REG_VC, "clk_cfg_reg_vc", "clk_axi6", REG_CLK_EN_4, 0,
+		     CLK_IGNORE_UNUSED),
+	CV1800B_GATE(CLK_PWM, "clk_pwm", "clk_pwm_src", REG_CLK_EN_1, 8, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_UART0, "clk_uart0", "clk_cam0_200", REG_CLK_EN_1, 14, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_UART1, "clk_uart1", "clk_cam0_200", REG_CLK_EN_1, 16, 0),
+	CV1800B_GATE(CLK_UART2, "clk_uart2", "clk_cam0_200", REG_CLK_EN_1, 18, 0),
+	CV1800B_GATE(CLK_UART3, "clk_uart3", "clk_cam0_200", REG_CLK_EN_1, 20, 0),
+	CV1800B_GATE(CLK_UART4, "clk_uart4", "clk_cam0_200", REG_CLK_EN_1, 22, 0),
+	CV1800B_GATE(CLK_H264C, "clk_h264c", "clk_axi_video_codec", REG_CLK_EN_2, 10, 0),
+	CV1800B_GATE(CLK_H265C, "clk_h265c", "clk_axi_video_codec", REG_CLK_EN_2, 11, 0),
+	CV1800B_GATE(CLK_JPEG, "clk_jpeg", "clk_axi_video_codec", REG_CLK_EN_2, 12,
+		     CLK_IGNORE_UNUSED),
+	CV1800B_GATE(CLK_CSI_MAC0_VIP, "clk_csi_mac0_vip", "clk_axi_vip", REG_CLK_EN_2, 18, 0),
+	CV1800B_GATE(CLK_CSI_MAC1_VIP, "clk_csi_mac1_vip", "clk_axi_vip", REG_CLK_EN_2, 19, 0),
+	CV1800B_GATE(CLK_ISP_TOP_VIP, "clk_isp_top_vip", "clk_axi_vip", REG_CLK_EN_2, 20, 0),
+	CV1800B_GATE(CLK_IMG_D_VIP, "clk_img_d_vip", "clk_axi_vip", REG_CLK_EN_2, 21, 0),
+	CV1800B_GATE(CLK_IMG_V_VIP, "clk_img_v_vip", "clk_axi_vip", REG_CLK_EN_2, 22, 0),
+	CV1800B_GATE(CLK_SC_TOP_VIP, "clk_sc_top_vip", "clk_axi_vip", REG_CLK_EN_2, 23, 0),
+	CV1800B_GATE(CLK_SC_D_VIP, "clk_sc_d_vip", "clk_axi_vip", REG_CLK_EN_2, 24, 0),
+	CV1800B_GATE(CLK_SC_V1_VIP, "clk_sc_v1_vip", "clk_axi_vip", REG_CLK_EN_2, 25, 0),
+	CV1800B_GATE(CLK_SC_V2_VIP, "clk_sc_v2_vip", "clk_axi_vip", REG_CLK_EN_2, 26, 0),
+	CV1800B_GATE(CLK_SC_V3_VIP, "clk_sc_v3_vip", "clk_axi_vip", REG_CLK_EN_2, 27, 0),
+	CV1800B_GATE(CLK_DWA_VIP, "clk_dwa_vip", "clk_axi_vip", REG_CLK_EN_2, 28, 0),
+	CV1800B_GATE(CLK_BT_VIP, "clk_bt_vip", "clk_axi_vip", REG_CLK_EN_2, 29, 0),
+	CV1800B_GATE(CLK_DISP_VIP, "clk_disp_vip", "clk_axi_vip", REG_CLK_EN_2, 30, 0),
+	CV1800B_GATE(CLK_DSI_MAC_VIP, "clk_dsi_mac_vip", "clk_axi_vip", REG_CLK_EN_2, 31, 0),
+	CV1800B_GATE(CLK_LVDS0_VIP, "clk_lvds0_vip", "clk_axi_vip", REG_CLK_EN_3, 0, 0),
+	CV1800B_GATE(CLK_LVDS1_VIP, "clk_lvds1_vip", "clk_axi_vip", REG_CLK_EN_3, 1, 0),
+	CV1800B_GATE(CLK_CSI0_RX_VIP, "clk_csi0_rx_vip", "clk_axi_vip", REG_CLK_EN_3, 2, 0),
+	CV1800B_GATE(CLK_CSI1_RX_VIP, "clk_csi1_rx_vip", "clk_axi_vip", REG_CLK_EN_3, 3, 0),
+	CV1800B_GATE(CLK_PAD_VI_VIP, "clk_pad_vi_vip", "clk_axi_vip", REG_CLK_EN_3, 4, 0),
+	CV1800B_GATE(CLK_PAD_VI1_VIP, "clk_pad_vi1_vip", "clk_axi_vip", REG_CLK_EN_3, 30, 0),
+	CV1800B_GATE(CLK_PAD_VI2_VIP, "clk_pad_vi2_vip", "clk_axi_vip", REG_CLK_EN_4, 7, 0),
+	CV1800B_GATE(CLK_CSI_BE_VIP, "clk_csi_be_vip", "clk_axi_vip", REG_CLK_EN_4, 8, 0),
+	CV1800B_GATE(CLK_VIP_IP0, "clk_vip_ip0", "clk_axi_vip", REG_CLK_EN_4, 9, 0),
+	CV1800B_GATE(CLK_VIP_IP1, "clk_vip_ip1", "clk_axi_vip", REG_CLK_EN_4, 10, 0),
+	CV1800B_GATE(CLK_VIP_IP2, "clk_vip_ip2", "clk_axi_vip", REG_CLK_EN_4, 11, 0),
+	CV1800B_GATE(CLK_VIP_IP3, "clk_vip_ip3", "clk_axi_vip", REG_CLK_EN_4, 12, 0),
+	CV1800B_GATE(CLK_IVE_VIP, "clk_ive_vip", "clk_axi_vip", REG_CLK_EN_4, 17, 0),
+	CV1800B_GATE(CLK_RAW_VIP, "clk_raw_vip", "clk_axi_vip", REG_CLK_EN_4, 18, 0),
+	CV1800B_GATE(CLK_OSDC_VIP, "clk_osdc_vip", "clk_axi_vip", REG_CLK_EN_4, 19, 0),
+	CV1800B_GATE(CLK_CSI_MAC2_VIP, "clk_csi_mac2_vip", "clk_axi_vip", REG_CLK_EN_4, 20, 0),
+	CV1800B_GATE(CLK_CAM0_VIP, "clk_cam0_vip", "clk_axi_vip", REG_CLK_EN_4, 21, 0),
+	CV1800B_GATE(CLK_TIMER0, "clk_timer0", "clk_xtal_misc", REG_CLK_EN_3, 9, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_TIMER1, "clk_timer1", "clk_xtal_misc", REG_CLK_EN_3, 10, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_TIMER2, "clk_timer2", "clk_xtal_misc", REG_CLK_EN_3, 11, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_TIMER3, "clk_timer3", "clk_xtal_misc", REG_CLK_EN_3, 12, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_TIMER4, "clk_timer4", "clk_xtal_misc", REG_CLK_EN_3, 13, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_TIMER5, "clk_timer5", "clk_xtal_misc", REG_CLK_EN_3, 14, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_TIMER6, "clk_timer6", "clk_xtal_misc", REG_CLK_EN_3, 15, CLK_IS_CRITICAL),
+	CV1800B_GATE(CLK_TIMER7, "clk_timer7", "clk_xtal_misc", REG_CLK_EN_3, 16, CLK_IS_CRITICAL),
+};
+
+struct cv1800b_clk_div cv1800b_div_info[] = {
+	CV1800B_DIV(CLK_1M, "clk_1m", "osc", REG_CLK_EN_3, 5,
+		    REG_DIV_CLK_1M, 16, 6, 25, CLK_IS_CRITICAL),
+	CV1800B_DIV(CLK_EMMC_100K, "clk_emmc_100k", "clk_1m", REG_CLK_EN_0, 17,
+		    REG_DIV_CLK_EMMC_100K, 16, 8, 10, 0),
+	CV1800B_DIV(CLK_SD0_100K, "clk_sd0_100k", "clk_1m", REG_CLK_EN_0, 20,
+		    REG_DIV_CLK_SD0_100K, 16, 8, 10, 0),
+	CV1800B_DIV(CLK_SD1_100K, "clk_sd1_100k", "clk_1m", REG_CLK_EN_0, 23,
+		    REG_DIV_CLK_SD1_100K, 16, 8, 10, 0),
+	CV1800B_DIV(CLK_GPIO_DB, "clk_gpio_db", "clk_1m", REG_CLK_EN_0, 31,
+		    REG_DIV_CLK_GPIO_DB, 16, 16, 10, CLK_IS_CRITICAL)
+};
+
+struct cv1800b_clk_bypass_div cv1800b_bypass_div_info[] = {
+	CV1800B_BYPASS_DIV(CLK_AP_DEBUG, "clk_ap_debug", "clk_fpll", REG_CLK_EN_4, 5,
+			   REG_DIV_CLK_AP_DEBUG, 16, 4, 5, REG_CLK_BYP_1, 4, CLK_IS_CRITICAL),
+	CV1800B_BYPASS_DIV(CLK_SRC_RTC_SYS_0, "clk_src_rtc_sys_0", "clk_fpll", REG_CLK_EN_4, 6,
+			   REG_DIV_CLK_RTCSYS_SRC_0, 16, 4, 5, REG_CLK_BYP_1, 5, CLK_IS_CRITICAL),
+	CV1800B_BYPASS_DIV(CLK_CPU_GIC, "clk_cpu_gic", "clk_fpll", REG_CLK_EN_0, 2,
+			   REG_DIV_CLK_CPU_GIC, 16, 4, 5, REG_CLK_BYP_0, 2, CLK_IS_CRITICAL),
+	CV1800B_BYPASS_DIV(CLK_ETH0_500M, "clk_eth0_500m", "clk_fpll", REG_CLK_EN_0, 25,
+			   REG_DIV_CLK_GPIO_DB, 16, 4, 3, REG_CLK_BYP_0, 9, 0),
+	CV1800B_BYPASS_DIV(CLK_ETH1_500M, "clk_eth1_500m", "clk_fpll", REG_CLK_EN_0, 27,
+			   REG_DIV_CLK_GPIO_DB, 16, 4, 3, REG_CLK_BYP_0, 10, 0),
+	CV1800B_BYPASS_DIV(CLK_AXI6, "clk_axi6", "clk_fpll", REG_CLK_EN_2, 2, REG_DIV_CLK_AXI6, 16,
+			   4, 15, REG_CLK_BYP_0, 20, CLK_IS_CRITICAL),
+	CV1800B_BYPASS_DIV(CLK_SPI, "clk_spi", "clk_fpll", REG_CLK_EN_3, 6, REG_DIV_CLK_SPI, 16, 6,
+			   8, REG_CLK_BYP_0, 30, 0),
+	CV1800B_BYPASS_DIV(CLK_DISP_SRC_VIP, "clk_disp_src_vip", "clk_disppll", REG_CLK_EN_2, 7,
+			   REG_DIV_CLK_DISP_SRC_VIP, 16, 4, 8, REG_CLK_BYP_0, 25, 0),
+	CV1800B_BYPASS_DIV(CLK_CPU_AXI0, "clk_cpu_axi0", "clk_axi4", REG_CLK_EN_0, 1,
+			   REG_DIV_CLK_CPU_AXI0, 16, 4, 3, REG_CLK_BYP_0, 1, CLK_IS_CRITICAL),
+	CV1800B_BYPASS_DIV(CLK_DSI_ESC, "clk_dsi_esc", "clk_axi6", REG_CLK_EN_2, 3,
+			   REG_DIV_CLK_DSI_ESC, 16, 4, 5, REG_CLK_BYP_0, 21, 0),
+	CV1800B_BYPASS_DIV(CLK_I2C, "clk_i2c", "clk_axi6", REG_CLK_EN_3, 7, REG_DIV_CLK_I2C, 16, 4,
+			   1, REG_CLK_BYP_0, 31, 0),
+};
+
+struct cv1800b_clk_fixed_div cv1800b_fixed_div_info[] = {
+	CV1800B_FIXED_DIV(CLK_CAM0PLL_D2, "clk_cam0pll_d2", "clk_cam0pll",
+			  REG_CAM0PLL_CLK_CSR, 1, 2,
+			  CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),
+	CV1800B_FIXED_DIV(CLK_CAM0PLL_D3, "clk_cam0pll_d3", "clk_cam0pll",
+			  REG_CAM0PLL_CLK_CSR, 2, 3,
+			  CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),
+	CV1800B_FIXED_DIV(CLK_MIPIMPLL_D3, "clk_mipimpll_d3", "clk_mipimpll",
+			  REG_MIPIMPLL_CLK_CSR, 2, 3,
+			  CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),
+	CV1800B_FIXED_DIV(CLK_USB_33K, "clk_usb_33k", "clk_1m",
+			  REG_CLK_EN_1, 31, 3,
+			  0),
+};
+
+struct cv1800b_clk_bypass_fixed_div cv1800b_bypass_fixed_div_info[] = {
+	CV1800B_BYPASS_FIXED_DIV(CLK_USB_125M, "clk_usb_125m", "clk_fpll",
+				 REG_CLK_EN_1, 30, 12,
+				 REG_CLK_BYP_0, 17,
+				 CLK_SET_RATE_PARENT),
+	CV1800B_BYPASS_FIXED_DIV(CLK_USB_12M, "clk_usb_12m", "clk_fpll",
+				 REG_CLK_EN_2, 0, 125,
+				 REG_CLK_BYP_0, 18,
+				 CLK_SET_RATE_PARENT),
+	CV1800B_BYPASS_FIXED_DIV(CLK_VC_SRC1, "clk_vc_src1", "clk_fpll",
+				 REG_CLK_EN_3, 28, 2,
+				 REG_CLK_BYP_1, 0,
+				 CLK_SET_RATE_PARENT),
+	CV1800B_BYPASS_FIXED_DIV(CLK_VC_SRC2, "clk_vc_src2", "clk_fpll",
+				 REG_CLK_EN_4, 3, 3,
+				 REG_CLK_BYP_1, 3,
+				 CLK_SET_RATE_PARENT),
+};
+
+struct cv1800b_clk_mux cv1800b_mux_info[] = {
+	CV1800B_MUX(CLK_CAM0, "clk_cam0", clk_cam_parents,
+		    REG_CLK_EN_2, 16,
+		    REG_CLK_CAM0_SRC_DIV, 16, 6, 0,
+		    REG_CLK_CAM0_SRC_DIV, 8, 2,
+		    CLK_IGNORE_UNUSED),
+	CV1800B_MUX(CLK_CAM1, "clk_cam1", clk_cam_parents,
+		    REG_CLK_EN_2, 17,
+		    REG_CLK_CAM1_SRC_DIV, 16, 6, 0,
+		    REG_CLK_CAM1_SRC_DIV, 8, 2,
+		    CLK_IGNORE_UNUSED),
+};
+
+struct cv1800b_clk_bypass_mux cv1800b_bypass_mux_info[] = {
+	CV1800B_BYPASS_MUX(CLK_TPU, "clk_tpu", clk_tpu_parents,
+			   REG_CLK_EN_0, 4,
+			   REG_DIV_CLK_TPU, 16, 4, 3,
+			   REG_DIV_CLK_TPU, 8, 2,
+			   REG_CLK_BYP_0, 3,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_EMMC, "clk_emmc", clk_axi4_parents,
+			   REG_CLK_EN_0, 16,
+			   REG_DIV_CLK_EMMC, 16, 5, 15,
+			   REG_DIV_CLK_EMMC, 8, 2,
+			   REG_CLK_BYP_0, 5,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SD0, "clk_sd0", clk_axi4_parents,
+			   REG_CLK_EN_0, 19,
+			   REG_DIV_CLK_SD0, 16, 5, 15,
+			   REG_DIV_CLK_SD0, 8, 2,
+			   REG_CLK_BYP_0, 6,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SD1, "clk_sd1", clk_axi4_parents,
+			   REG_CLK_EN_0, 22,
+			   REG_DIV_CLK_SD1, 16, 5, 15,
+			   REG_DIV_CLK_SD1, 8, 2,
+			   REG_CLK_BYP_0, 7,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SPI_NAND, "clk_spi_nand", clk_axi4_parents,
+			   REG_CLK_EN_0, 24,
+			   REG_DIV_CLK_SPI_NAND, 16, 5, 8,
+			   REG_DIV_CLK_SPI_NAND, 8, 2,
+			   REG_CLK_BYP_0, 8,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_AXI4, "clk_axi4", clk_axi4_parents,
+			   REG_CLK_EN_2, 1,
+			   REG_DIV_CLK_AXI4, 16, 4, 5,
+			   REG_DIV_CLK_AXI4, 8, 2,
+			   REG_CLK_BYP_0, 19,
+			   CLK_IS_CRITICAL),
+	CV1800B_BYPASS_MUX(CLK_PWM_SRC, "clk_pwm_src", clk_axi4_parents,
+			   REG_CLK_EN_4, 4,
+			   REG_DIV_CLK_PWM_SRC_0, 16, 6, 10,
+			   REG_DIV_CLK_PWM_SRC_0, 8, 2,
+			   REG_CLK_BYP_0, 15,
+			   CLK_IS_CRITICAL),
+	CV1800B_BYPASS_MUX(CLK_AUDSRC, "clk_audsrc", clk_aud_parents,
+			   REG_CLK_EN_4, 1,
+			   REG_DIV_CLK_AUDSRC, 16, 8, 18,
+			   REG_DIV_CLK_AUDSRC, 8, 2,
+			   REG_CLK_BYP_1, 2,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SDMA_AUD0, "clk_sdma_aud0", clk_aud_parents,
+			   REG_CLK_EN_1, 2,
+			   REG_DIV_CLK_SDMA_AUD0, 16, 8, 18,
+			   REG_DIV_CLK_SDMA_AUD0, 8, 2,
+			   REG_CLK_BYP_0, 11,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SDMA_AUD1, "clk_sdma_aud1", clk_aud_parents,
+			   REG_CLK_EN_1, 3,
+			   REG_DIV_CLK_SDMA_AUD1, 16, 8, 18,
+			   REG_DIV_CLK_SDMA_AUD1, 8, 2,
+			   REG_CLK_BYP_0, 12,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SDMA_AUD2, "clk_sdma_aud2", clk_aud_parents,
+			   REG_CLK_EN_1, 3,
+			   REG_DIV_CLK_SDMA_AUD2, 16, 8, 18,
+			   REG_DIV_CLK_SDMA_AUD2, 8, 2,
+			   REG_CLK_BYP_0, 13,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SDMA_AUD3, "clk_sdma_aud3", clk_aud_parents,
+			   REG_CLK_EN_1, 3,
+			   REG_DIV_CLK_SDMA_AUD3, 16, 8, 18,
+			   REG_DIV_CLK_SDMA_AUD3, 8, 2,
+			   REG_CLK_BYP_0, 14,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_CAM0_200, "clk_cam0_200", clk_cam0_200_parents,
+			   REG_CLK_EN_1, 13,
+			   REG_DIV_CLK_CAM0_200, 16, 4, 1,
+			   REG_DIV_CLK_CAM0_200, 8, 2,
+			   REG_CLK_BYP_0, 16,
+			   CLK_IS_CRITICAL),
+	CV1800B_BYPASS_MUX(CLK_AXI_VIP, "clk_axi_vip", clk_vip_sys_parents,
+			   REG_CLK_EN_2, 4,
+			   REG_DIV_CLK_AXI_VIP, 16, 4, 3,
+			   REG_DIV_CLK_AXI_VIP, 8, 2,
+			   REG_CLK_BYP_0, 22,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SRC_VIP_SYS_0, "clk_src_vip_sys_0", clk_vip_sys_parents,
+			   REG_CLK_EN_2, 5,
+			   REG_DIV_CLK_SRC_VIP_SYS_0, 16, 4, 6,
+			   REG_DIV_CLK_SRC_VIP_SYS_0, 8, 2,
+			   REG_CLK_BYP_0, 23,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SRC_VIP_SYS_1, "clk_src_vip_sys_1", clk_vip_sys_parents,
+			   REG_CLK_EN_2, 6,
+			   REG_DIV_CLK_SRC_VIP_SYS_1, 16, 4, 6,
+			   REG_DIV_CLK_SRC_VIP_SYS_1, 8, 2,
+			   REG_CLK_BYP_0, 24,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SRC_VIP_SYS_2, "clk_src_vip_sys_2", clk_vip_sys_parents,
+			   REG_CLK_EN_3, 29,
+			   REG_DIV_CLK_SRC_VIP_SYS_2, 16, 4, 2,
+			   REG_DIV_CLK_SRC_VIP_SYS_2, 8, 2,
+			   REG_CLK_BYP_1, 1,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SRC_VIP_SYS_3, "clk_src_vip_sys_3", clk_vip_sys_parents,
+			   REG_CLK_EN_4, 15,
+			   REG_DIV_CLK_SRC_VIP_SYS_3, 16, 4, 2,
+			   REG_DIV_CLK_SRC_VIP_SYS_3, 8, 2,
+			   REG_CLK_BYP_1, 8,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_SRC_VIP_SYS_4, "clk_src_vip_sys_4", clk_vip_sys_parents,
+			   REG_CLK_EN_4, 16,
+			   REG_DIV_CLK_SRC_VIP_SYS_4, 16, 4, 3,
+			   REG_DIV_CLK_SRC_VIP_SYS_4, 8, 2,
+			   REG_CLK_BYP_1, 9,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_AXI_VIDEO_CODEC, "clk_axi_video_codec", clk_axi_video_codec_parents,
+			   REG_CLK_EN_2, 8,
+			   REG_DIV_CLK_AXI_VIDEO_CODEC, 16, 4, 2,
+			   REG_DIV_CLK_AXI_VIDEO_CODEC, 8, 2,
+			   REG_CLK_BYP_0, 26,
+			   0),
+	CV1800B_BYPASS_MUX(CLK_VC_SRC0, "clk_vc_src0", clk_vc_src0_parents,
+			   REG_CLK_EN_2, 9,
+			   REG_DIV_CLK_VC_SRC0, 16, 4, 2,
+			   REG_DIV_CLK_VC_SRC0, 8, 2,
+			   REG_CLK_BYP_0, 27,
+			   0),
+};
+
+struct cv1800b_clk_mmux cv1800b_mmux_info[] = {
+	CV1800B_MMUX(CLK_C906_0, "clk_c906_0", clk_c906_0_parents,
+		     REG_CLK_EN_4, 13,
+		     REG_DIV_CLK_C906_0_0, 16, 4, 1,
+		     REG_DIV_CLK_C906_0_1, 16, 4, 2,
+		     REG_DIV_CLK_C906_0_0, 8, 2,
+		     REG_DIV_CLK_C906_0_1, 8, 2,
+		     REG_CLK_BYP_1, 6,
+		     REG_CLK_SEL_0, 23,
+		     CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE),
+	CV1800B_MMUX(CLK_C906_1, "clk_c906_1", clk_c906_1_parents,
+		     REG_CLK_EN_4, 14,
+		     REG_DIV_CLK_C906_1_0, 16, 4, 2,
+		     REG_DIV_CLK_C906_1_1, 16, 4, 3,
+		     REG_DIV_CLK_C906_1_0, 8, 2,
+		     REG_DIV_CLK_C906_1_1, 8, 2,
+		     REG_CLK_BYP_1, 7,
+		     REG_CLK_SEL_0, 24,
+		     CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE),
+	CV1800B_MMUX(CLK_A53, "clk_a53", clk_a53_parents,
+		     REG_CLK_EN_0, 0,
+		     REG_DIV_CLK_A53_0, 16, 4, 1,
+		     REG_DIV_CLK_A53_1, 16, 4, 2,
+		     REG_DIV_CLK_A53_0, 8, 2,
+		     REG_DIV_CLK_A53_1, 8, 2,
+		     REG_CLK_BYP_0, 0,
+		     REG_CLK_SEL_0, 0,
+		     CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE),
+};
+
+static struct cv1800b_clk_audio cv1800b_audio_info[] = {
+	CV1800B_AUDIO(CLK_A24M, "clk_a24m", "clk_mipimpll",
+		      REG_APLL_FRAC_DIV_CTRL, 0,
+		      REG_APLL_FRAC_DIV_CTRL, 3,
+		      REG_APLL_FRAC_DIV_CTRL, 1,
+		      REG_APLL_FRAC_DIV_CTRL, 2,
+		      REG_APLL_FRAC_DIV_M, 0, 22,
+		      REG_APLL_FRAC_DIV_N, 0, 22,
+		      0),
+};
+
+static struct cv1800b_clk_ipll cv1800b_ipll_info[] = {
+	CV1800B_IPLL(CLK_FPLL, "clk_fpll", "osc", REG_FPLL_CSR,
+		     REG_PLL_G6_CTRL, 8,
+		     REG_PLL_G6_STATUS, 2,
+		     CLK_IS_CRITICAL),
+	CV1800B_IPLL(CLK_MIPIMPLL, "clk_mipimpll", "osc", REG_MIPIMPLL_CSR,
+		     REG_PLL_G2_CTRL, 0,
+		     REG_PLL_G2_STATUS, 0,
+		     CLK_IS_CRITICAL),
+};
+
+static struct cv1800b_clk_fpll cv1800b_fpll_info[] = {
+	CV1800B_FPLL(CLK_MPLL, "clk_mpll", "osc", REG_MPLL_CSR,
+		     REG_PLL_G6_CTRL, 0,
+		     REG_PLL_G6_STATUS, 0,
+		     REG_PLL_G6_SSC_SYN_CTRL, 2,
+		     REG_PLL_G6_SSC_SYN_CTRL, 0,
+		     REG_MPLL_SSC_SYN_CTRL, REG_MPLL_SSC_SYN_SET,
+		     CLK_IS_CRITICAL),
+	CV1800B_FPLL(CLK_TPLL, "clk_tpll", "osc", REG_TPLL_CSR,
+		     REG_PLL_G6_CTRL, 4,
+		     REG_PLL_G6_STATUS, 1,
+		     REG_PLL_G6_SSC_SYN_CTRL, 3,
+		     REG_PLL_G6_SSC_SYN_CTRL, 0,
+		     REG_TPLL_SSC_SYN_CTRL, REG_TPLL_SSC_SYN_SET,
+		     CLK_IS_CRITICAL),
+	CV1800B_FPLL(CLK_A0PLL, "clk_a0pll", "clk_mipimpll", REG_A0PLL_CSR,
+		     REG_PLL_G2_CTRL, 4,
+		     REG_PLL_G2_STATUS, 1,
+		     REG_PLL_G2_SSC_SYN_CTRL, 2,
+		     REG_PLL_G2_SSC_SYN_CTRL, 0,
+		     REG_A0PLL_SSC_SYN_CTRL, REG_A0PLL_SSC_SYN_SET,
+		     CLK_IS_CRITICAL),
+	CV1800B_FPLL(CLK_DISPPLL, "clk_disppll", "clk_mipimpll", REG_DISPPLL_CSR,
+		     REG_PLL_G2_CTRL, 8,
+		     REG_PLL_G2_STATUS, 2,
+		     REG_PLL_G2_SSC_SYN_CTRL, 3,
+		     REG_PLL_G2_SSC_SYN_CTRL, 0,
+		     REG_DISPPLL_SSC_SYN_CTRL, REG_DISPPLL_SSC_SYN_SET,
+		     CLK_IS_CRITICAL),
+	CV1800B_FPLL(CLK_CAM0PLL, "clk_cam0pll", "clk_mipimpll", REG_CAM0PLL_CSR,
+		     REG_PLL_G2_CTRL, 12,
+		     REG_PLL_G2_STATUS, 3,
+		     REG_PLL_G2_SSC_SYN_CTRL, 4,
+		     REG_PLL_G2_SSC_SYN_CTRL, 0,
+		     REG_CAM0PLL_SSC_SYN_CTRL, REG_CAM0PLL_SSC_SYN_SET,
+		     CLK_IGNORE_UNUSED),
+	CV1800B_FPLL(CLK_CAM1PLL, "clk_cam1pll", "clk_mipimpll", REG_CAM1PLL_CSR,
+		     REG_PLL_G2_CTRL, 16,
+		     REG_PLL_G2_STATUS, 4,
+		     REG_PLL_G2_SSC_SYN_CTRL, 5,
+		     REG_PLL_G2_SSC_SYN_CTRL, 0,
+		     REG_CAM1PLL_SSC_SYN_CTRL, REG_CAM1PLL_SSC_SYN_SET,
+		     CLK_IS_CRITICAL),
+};
+
+static int cv1800b_register_clk(struct udevice *dev)
+{
+	struct clk osc;
+	ulong osc_rate;
+	void *base = devfdt_get_addr_ptr(dev);
+	int i, ret;
+
+	ret = clk_get_by_index(dev, 0, &osc);
+	if (ret) {
+		pr_err("Failed to get clock\n");
+		return ret;
+	}
+
+	osc_rate = clk_get_rate(&osc);
+	clk_dm(CV1800B_CLK_OSC, clk_register_fixed_rate(NULL, "osc", osc_rate));
+	clk_dm(CV1800B_CLK_BYPASS, clk_register_fixed_rate(NULL, "bypass", osc_rate));
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_ipll_info); i++) {
+		struct cv1800b_clk_ipll *ipll = &cv1800b_ipll_info[i];
+
+		ipll->base = base;
+		ret = clk_register(&ipll->clk, "cv1800b_clk_ipll", ipll->name,
+				   ipll->parent_name);
+		if (ret) {
+			pr_err("Failed to register ipll %s\n", ipll->name);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_fpll_info); i++) {
+		struct cv1800b_clk_fpll *fpll = &cv1800b_fpll_info[i];
+
+		fpll->ipll.base = base;
+		ret = clk_register(&fpll->ipll.clk, "cv1800b_clk_fpll",
+				   fpll->ipll.name, fpll->ipll.parent_name);
+		if (ret) {
+			pr_err("Failed to register fpll %s\n", fpll->ipll.name);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_div_info); i++) {
+		struct cv1800b_clk_div *div = &cv1800b_div_info[i];
+
+		div->base = base;
+		ret = clk_register(&div->clk, "cv1800b_clk_div", div->name,
+				   div->parent_name);
+		if (ret) {
+			pr_err("Failed to register div %s\n", div->name);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_fixed_div_info); i++) {
+		struct cv1800b_clk_fixed_div *fixed_div =
+			&cv1800b_fixed_div_info[i];
+
+		fixed_div->base = base;
+		ret = clk_register(&fixed_div->clk, "cv1800b_clk_fixed_div",
+				   fixed_div->name, fixed_div->parent_name);
+		if (ret) {
+			pr_err("Failed to register fixed div %s\n",
+			       fixed_div->name);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_bypass_fixed_div_info); i++) {
+		struct cv1800b_clk_bypass_fixed_div *bypass_fixed_div =
+			&cv1800b_bypass_fixed_div_info[i];
+
+		bypass_fixed_div->div.base = base;
+		ret = clk_register(&bypass_fixed_div->div.clk,
+				   "cv1800b_clk_bypass_fixed_div",
+				   bypass_fixed_div->div.name,
+				   bypass_fixed_div->div.parent_name);
+		if (ret) {
+			pr_err("Failed to register bypass fixed div %s\n",
+			       bypass_fixed_div->div.name);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_mux_info); i++) {
+		struct cv1800b_clk_mux *mux = &cv1800b_mux_info[i];
+		int parent;
+
+		mux->base = base;
+		parent = cv1800b_clk_getfield(base, &mux->mux);
+		ret = clk_register(&mux->clk, "cv1800b_clk_mux", mux->name,
+				   mux->parent_names[parent]);
+		if (ret) {
+			pr_err("Failed to register mux %s\n", mux->name);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_mmux_info); i++) {
+		struct cv1800b_clk_mmux *mmux = &cv1800b_mmux_info[i];
+		int clk_sel, parent, idx;
+
+		mmux->base = base;
+		clk_sel = cv1800b_clk_getbit(base, &mmux->clk_sel) ? 0 : 1;
+		parent = cv1800b_clk_getfield(base, &mmux->mux[clk_sel]);
+		for (idx = 0; idx < mmux->num_parents; idx++) {
+			if (clk_sel == mmux->parent_infos[idx].clk_sel &&
+			    parent == mmux->parent_infos[idx].index)
+				break;
+		}
+		ret = clk_register(&mmux->clk, "cv1800b_clk_mmux", mmux->name,
+				   mmux->parent_infos[idx].name);
+		if (ret) {
+			pr_err("Failed to register mmux %s\n", mmux->name);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_audio_info); i++) {
+		struct cv1800b_clk_audio *audio = &cv1800b_audio_info[i];
+
+		audio->base = base;
+		ret = clk_register(&audio->clk, "cv1800b_clk_audio",
+				   audio->name, audio->parent_name);
+		if (ret) {
+			pr_err("Failed to register audio %s\n", audio->name);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_bypass_mux_info); i++) {
+		struct cv1800b_clk_bypass_mux *bypass_mux =
+			&cv1800b_bypass_mux_info[i];
+		int parent;
+
+		bypass_mux->mux.base = base;
+		parent = cv1800b_clk_getfield(base, &bypass_mux->mux.mux);
+		ret = clk_register(&bypass_mux->mux.clk,
+				   "cv1800b_clk_bypass_mux",
+				   bypass_mux->mux.name,
+				   bypass_mux->mux.parent_names[parent]);
+		if (ret) {
+			pr_err("Failed to register bypass mux %s\n",
+			       bypass_mux->mux.name);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_bypass_div_info); i++) {
+		struct cv1800b_clk_bypass_div *bypass_div =
+			&cv1800b_bypass_div_info[i];
+
+		bypass_div->div.base = base;
+		ret = clk_register(&bypass_div->div.clk,
+				   "cv1800b_clk_bypass_div",
+				   bypass_div->div.name,
+				   bypass_div->div.parent_name);
+		if (ret) {
+			pr_err("Failed to register bypass div %s\n",
+			       bypass_div->div.name);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(cv1800b_gate_info); i++) {
+		struct cv1800b_clk_gate *gate = &cv1800b_gate_info[i];
+
+		gate->base = base;
+		ret = clk_register(&gate->clk, "cv1800b_clk_gate", gate->name,
+				   gate->parent_name);
+		if (ret) {
+			pr_err("Failed to register gate %s\n", gate->name);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int cv1800b_clk_probe(struct udevice *dev)
+{
+	return cv1800b_register_clk(dev);
+}
+
+static int cv1800b_clk_enable(struct clk *clk)
+{
+	struct clk *c;
+	int err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(clk->id), &c);
+
+	if (err)
+		return err;
+	return clk_enable(c);
+}
+
+static int cv1800b_clk_disable(struct clk *clk)
+{
+	struct clk *c;
+	int err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(clk->id), &c);
+
+	if (err)
+		return err;
+	return clk_disable(c);
+}
+
+static ulong cv1800b_clk_get_rate(struct clk *clk)
+{
+	struct clk *c;
+	int err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(clk->id), &c);
+
+	if (err)
+		return err;
+	return clk_get_rate(c);
+}
+
+static ulong cv1800b_clk_set_rate(struct clk *clk, ulong rate)
+{
+	struct clk *c;
+	int err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(clk->id), &c);
+
+	if (err)
+		return err;
+	return clk_set_rate(c, rate);
+}
+
+static int cv1800b_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct clk *c, *p;
+	int err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(clk->id), &c);
+
+	if (err)
+		return err;
+	err = clk_get_by_id(CV1800B_CLK_ID_TRANSFORM(parent->id), &p);
+	if (err)
+		return err;
+	return clk_set_parent(c, p);
+}
+
+const struct clk_ops cv1800b_clk_ops = {
+	.enable = cv1800b_clk_enable,
+	.disable = cv1800b_clk_disable,
+	.get_rate = cv1800b_clk_get_rate,
+	.set_rate = cv1800b_clk_set_rate,
+	.set_parent = cv1800b_clk_set_parent,
+};
+
+static const struct udevice_id cv1800b_clk_of_match[] = {
+	{ .compatible = "sophgo,cv1800-clk" },
+	{ },
+};
+
+U_BOOT_DRIVER(sophgo_clk) = {
+	.name      = "cv1800b_clk",
+	.id        = UCLASS_CLK,
+	.of_match  = cv1800b_clk_of_match,
+	.probe     = cv1800b_clk_probe,
+	.ops       = &cv1800b_clk_ops,
+	.flags	   = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/sophgo/clk-cv1800b.h b/drivers/clk/sophgo/clk-cv1800b.h
new file mode 100644
index 0000000000..1e7107b5d0
--- /dev/null
+++ b/drivers/clk/sophgo/clk-cv1800b.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
+ */
+
+#ifndef _CLK_SOPHGO_CV1800_H_
+#define _CLK_SOPHGO_CV1800_H_
+
+#include <dt-bindings/clock/sophgo,cv1800.h>
+
+#define CV1800_CLK_MAX			(CLK_XTAL_AP + 1)
+#define CV1810_CLK_MAX			(CLK_DISP_SRC_VIP + 1)
+
+#define REG_PLL_G2_CTRL			0x800
+#define REG_PLL_G2_STATUS		0x804
+#define REG_MIPIMPLL_CSR		0x808
+#define REG_A0PLL_CSR			0x80C
+#define REG_DISPPLL_CSR			0x810
+#define REG_CAM0PLL_CSR			0x814
+#define REG_CAM1PLL_CSR			0x818
+#define REG_PLL_G2_SSC_SYN_CTRL		0x840
+#define REG_A0PLL_SSC_SYN_CTRL		0x850
+#define REG_A0PLL_SSC_SYN_SET		0x854
+#define REG_A0PLL_SSC_SYN_SPAN		0x858
+#define REG_A0PLL_SSC_SYN_STEP		0x85C
+#define REG_DISPPLL_SSC_SYN_CTRL	0x860
+#define REG_DISPPLL_SSC_SYN_SET		0x864
+#define REG_DISPPLL_SSC_SYN_SPAN	0x868
+#define REG_DISPPLL_SSC_SYN_STEP	0x86C
+#define REG_CAM0PLL_SSC_SYN_CTRL	0x870
+#define REG_CAM0PLL_SSC_SYN_SET		0x874
+#define REG_CAM0PLL_SSC_SYN_SPAN	0x878
+#define REG_CAM0PLL_SSC_SYN_STEP	0x87C
+#define REG_CAM1PLL_SSC_SYN_CTRL	0x880
+#define REG_CAM1PLL_SSC_SYN_SET		0x884
+#define REG_CAM1PLL_SSC_SYN_SPAN	0x888
+#define REG_CAM1PLL_SSC_SYN_STEP	0x88C
+#define REG_APLL_FRAC_DIV_CTRL		0x890
+#define REG_APLL_FRAC_DIV_M		0x894
+#define REG_APLL_FRAC_DIV_N		0x898
+#define REG_MIPIMPLL_CLK_CSR		0x8A0
+#define REG_A0PLL_CLK_CSR		0x8A4
+#define REG_DISPPLL_CLK_CSR		0x8A8
+#define REG_CAM0PLL_CLK_CSR		0x8AC
+#define REG_CAM1PLL_CLK_CSR		0x8B0
+#define REG_CLK_CAM0_SRC_DIV		0x8C0
+#define REG_CLK_CAM1_SRC_DIV		0x8C4
+
+/* top_pll_g6 */
+#define REG_PLL_G6_CTRL			0x900
+#define REG_PLL_G6_STATUS		0x904
+#define REG_MPLL_CSR			0x908
+#define REG_TPLL_CSR			0x90C
+#define REG_FPLL_CSR			0x910
+#define REG_PLL_G6_SSC_SYN_CTRL		0x940
+#define REG_DPLL_SSC_SYN_CTRL		0x950
+#define REG_DPLL_SSC_SYN_SET		0x954
+#define REG_DPLL_SSC_SYN_SPAN		0x958
+#define REG_DPLL_SSC_SYN_STEP		0x95C
+#define REG_MPLL_SSC_SYN_CTRL		0x960
+#define REG_MPLL_SSC_SYN_SET		0x964
+#define REG_MPLL_SSC_SYN_SPAN		0x968
+#define REG_MPLL_SSC_SYN_STEP		0x96C
+#define REG_TPLL_SSC_SYN_CTRL		0x970
+#define REG_TPLL_SSC_SYN_SET		0x974
+#define REG_TPLL_SSC_SYN_SPAN		0x978
+#define REG_TPLL_SSC_SYN_STEP		0x97C
+
+/* clkgen */
+#define REG_CLK_EN_0			0x000
+#define REG_CLK_EN_1			0x004
+#define REG_CLK_EN_2			0x008
+#define REG_CLK_EN_3			0x00C
+#define REG_CLK_EN_4			0x010
+#define REG_CLK_SEL_0			0x020
+#define REG_CLK_BYP_0			0x030
+#define REG_CLK_BYP_1			0x034
+
+#define REG_DIV_CLK_A53_0		0x040
+#define REG_DIV_CLK_A53_1		0x044
+#define REG_DIV_CLK_CPU_AXI0		0x048
+#define REG_DIV_CLK_CPU_GIC		0x050
+#define REG_DIV_CLK_TPU			0x054
+#define REG_DIV_CLK_EMMC		0x064
+#define REG_DIV_CLK_EMMC_100K		0x06C
+#define REG_DIV_CLK_SD0			0x070
+#define REG_DIV_CLK_SD0_100K		0x078
+#define REG_DIV_CLK_SD1			0x07C
+#define REG_DIV_CLK_SD1_100K		0x084
+#define REG_DIV_CLK_SPI_NAND		0x088
+#define REG_DIV_CLK_ETH0_500M		0x08C
+#define REG_DIV_CLK_ETH1_500M		0x090
+#define REG_DIV_CLK_GPIO_DB		0x094
+#define REG_DIV_CLK_SDMA_AUD0		0x098
+#define REG_DIV_CLK_SDMA_AUD1		0x09C
+#define REG_DIV_CLK_SDMA_AUD2		0x0A0
+#define REG_DIV_CLK_SDMA_AUD3		0x0A4
+#define REG_DIV_CLK_CAM0_200		0x0A8
+#define REG_DIV_CLK_AXI4		0x0B8
+#define REG_DIV_CLK_AXI6		0x0BC
+#define REG_DIV_CLK_DSI_ESC		0x0C4
+#define REG_DIV_CLK_AXI_VIP		0x0C8
+#define REG_DIV_CLK_SRC_VIP_SYS_0	0x0D0
+#define REG_DIV_CLK_SRC_VIP_SYS_1	0x0D8
+#define REG_DIV_CLK_DISP_SRC_VIP	0x0E0
+#define REG_DIV_CLK_AXI_VIDEO_CODEC	0x0E4
+#define REG_DIV_CLK_VC_SRC0		0x0EC
+#define REG_DIV_CLK_1M			0x0FC
+#define REG_DIV_CLK_SPI			0x100
+#define REG_DIV_CLK_I2C			0x104
+#define REG_DIV_CLK_SRC_VIP_SYS_2	0x110
+#define REG_DIV_CLK_AUDSRC		0x118
+#define REG_DIV_CLK_PWM_SRC_0		0x120
+#define REG_DIV_CLK_AP_DEBUG		0x128
+#define REG_DIV_CLK_RTCSYS_SRC_0	0x12C
+#define REG_DIV_CLK_C906_0_0		0x130
+#define REG_DIV_CLK_C906_0_1		0x134
+#define REG_DIV_CLK_C906_1_0		0x138
+#define REG_DIV_CLK_C906_1_1		0x13C
+#define REG_DIV_CLK_SRC_VIP_SYS_3	0x140
+#define REG_DIV_CLK_SRC_VIP_SYS_4	0x144
+
+#endif /* _CLK_SOPHGO_CV1800_H_ */
diff --git a/drivers/clk/sophgo/clk-ip.c b/drivers/clk/sophgo/clk-ip.c
new file mode 100644
index 0000000000..d571fa671b
--- /dev/null
+++ b/drivers/clk/sophgo/clk-ip.c
@@ -0,0 +1,594 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
+ */
+
+#include <dm.h>
+#include <div64.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+
+#include "clk-common.h"
+#include "clk-ip.h"
+
+static int get_parent_index(struct clk *clk, const char *const *parent_name,
+			    u8 num_parents)
+{
+	const char *name = clk_hw_get_name(clk);
+	int i;
+
+	for (i = 0; i < num_parents; i++) {
+		if (!strcmp(name, parent_name[i]))
+			return i;
+	}
+
+	return -1;
+}
+
+/* GATE */
+#define to_cv1800b_clk_gate(_clk) \
+	container_of(_clk, struct cv1800b_clk_gate, clk)
+
+static int gate_enable(struct clk *clk)
+{
+	struct cv1800b_clk_gate *gate = to_cv1800b_clk_gate(clk);
+
+	return cv1800b_clk_setbit(gate->base, &gate->gate);
+}
+
+static int gate_disable(struct clk *clk)
+{
+	struct cv1800b_clk_gate *gate = to_cv1800b_clk_gate(clk);
+
+	return cv1800b_clk_clrbit(gate->base, &gate->gate);
+}
+
+static ulong gate_get_rate(struct clk *clk)
+{
+	return clk_get_parent_rate(clk);
+}
+
+const struct clk_ops cv1800b_clk_gate_ops = {
+	.disable = gate_disable,
+	.enable = gate_enable,
+	.get_rate = gate_get_rate,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_gate) = {
+	.name = "cv1800b_clk_gate",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_clk_gate_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+/* DIV */
+#define CLK_DIV_EN_FACTOR BIT(3)
+
+#define to_cv1800b_clk_div(_clk) container_of(_clk, struct cv1800b_clk_div, clk)
+
+static int div_enable(struct clk *clk)
+{
+	struct cv1800b_clk_div *div = to_cv1800b_clk_div(clk);
+
+	return cv1800b_clk_setbit(div->base, &div->gate);
+}
+
+static int div_disable(struct clk *clk)
+{
+	struct cv1800b_clk_div *div = to_cv1800b_clk_div(clk);
+
+	return cv1800b_clk_clrbit(div->base, &div->gate);
+}
+
+static ulong div_get_rate(struct clk *clk)
+{
+	struct cv1800b_clk_div *div = to_cv1800b_clk_div(clk);
+	ulong val;
+
+	if (div->div_init == 0 ||
+	    readl(div->base + div->div.offset) & CLK_DIV_EN_FACTOR)
+		val = cv1800b_clk_getfield(div->base, &div->div);
+	else
+		val = div->div_init;
+
+	return DIV_ROUND_UP_ULL(clk_get_parent_rate(clk), val);
+}
+
+static ulong div_set_rate(struct clk *clk, ulong rate)
+{
+	struct cv1800b_clk_div *div = to_cv1800b_clk_div(clk);
+	ulong parent_rate = clk_get_parent_rate(clk);
+	u32 val;
+
+	val = DIV_ROUND_UP_ULL(parent_rate, rate);
+	val = min_t(u32, val, clk_div_mask(div->div.width));
+
+	cv1800b_clk_setfield(div->base, &div->div, val);
+	if (div->div_init > 0)
+		setbits_le32(div->base + div->div.offset, CLK_DIV_EN_FACTOR);
+
+	return DIV_ROUND_UP_ULL(parent_rate, val);
+}
+
+const struct clk_ops cv1800b_clk_div_ops = {
+	.disable = div_disable,
+	.enable = div_enable,
+	.get_rate = div_get_rate,
+	.set_rate = div_set_rate,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_div) = {
+	.name = "cv1800b_clk_div",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_clk_div_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+#define to_cv1800b_clk_bypass_div(_clk) \
+	container_of(_clk, struct cv1800b_clk_bypass_div, div.clk)
+
+static ulong bypass_div_get_rate(struct clk *clk)
+{
+	struct cv1800b_clk_bypass_div *div = to_cv1800b_clk_bypass_div(clk);
+
+	if (cv1800b_clk_getbit(div->div.base, &div->bypass))
+		return 0;
+
+	return div_get_rate(clk);
+}
+
+static ulong bypass_div_set_rate(struct clk *clk, ulong rate)
+{
+	struct cv1800b_clk_bypass_div *div = to_cv1800b_clk_bypass_div(clk);
+
+	if (cv1800b_clk_getbit(div->div.base, &div->bypass))
+		return 0;
+
+	return div_set_rate(clk, rate);
+}
+
+static int bypass_div_set_parent(struct clk *clk, struct clk *pclk)
+{
+	struct cv1800b_clk_bypass_div *div = to_cv1800b_clk_bypass_div(clk);
+
+	if (pclk->id == CV1800B_CLK_BYPASS) {
+		cv1800b_clk_setbit(div->div.base, &div->bypass);
+		return 0;
+	}
+
+	if (strcmp(clk_hw_get_name(pclk), div->div.parent_name))
+		return -EINVAL;
+
+	cv1800b_clk_clrbit(div->div.base, &div->bypass);
+	return 0;
+}
+
+const struct clk_ops cv1800b_clk_bypass_div_ops = {
+	.disable = div_disable,
+	.enable = div_enable,
+	.get_rate = bypass_div_get_rate,
+	.set_rate = bypass_div_set_rate,
+	.set_parent = bypass_div_set_parent,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_bypass_div) = {
+	.name = "cv1800b_clk_bypass_div",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_clk_bypass_div_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+/* FIXED DIV */
+#define to_cv1800b_clk_fixed_div(_clk) \
+	container_of(_clk, struct cv1800b_clk_fixed_div, clk)
+
+static int fixed_div_enable(struct clk *clk)
+{
+	struct cv1800b_clk_fixed_div *div = to_cv1800b_clk_fixed_div(clk);
+
+	return cv1800b_clk_setbit(div->base, &div->gate);
+}
+
+static int fixed_div_disable(struct clk *clk)
+{
+	struct cv1800b_clk_fixed_div *div = to_cv1800b_clk_fixed_div(clk);
+
+	return cv1800b_clk_clrbit(div->base, &div->gate);
+}
+
+static ulong fixed_div_get_rate(struct clk *clk)
+{
+	struct cv1800b_clk_fixed_div *div = to_cv1800b_clk_fixed_div(clk);
+
+	return DIV_ROUND_UP_ULL(clk_get_parent_rate(clk), div->div);
+}
+
+const struct clk_ops cv1800b_clk_fixed_div_ops = {
+	.disable = fixed_div_disable,
+	.enable = fixed_div_enable,
+	.get_rate = fixed_div_get_rate,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_fixed_div) = {
+	.name = "cv1800b_clk_fixed_div",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_clk_fixed_div_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+#define to_cv1800b_clk_bypass_fixed_div(_clk) \
+	container_of(_clk, struct cv1800b_clk_bypass_fixed_div, div.clk)
+
+static ulong bypass_fixed_div_get_rate(struct clk *clk)
+{
+	struct cv1800b_clk_bypass_fixed_div *div =
+		to_cv1800b_clk_bypass_fixed_div(clk);
+
+	if (cv1800b_clk_getbit(div->div.base, &div->bypass))
+		return 0;
+
+	return fixed_div_get_rate(clk);
+}
+
+static int bypass_fixed_div_set_parent(struct clk *clk, struct clk *pclk)
+{
+	struct cv1800b_clk_bypass_fixed_div *div =
+		to_cv1800b_clk_bypass_fixed_div(clk);
+
+	if (pclk->id == CV1800B_CLK_BYPASS) {
+		cv1800b_clk_setbit(div->div.base, &div->bypass);
+		return 0;
+	}
+
+	if (strcmp(clk_hw_get_name(pclk), div->div.parent_name))
+		return -EINVAL;
+
+	cv1800b_clk_clrbit(div->div.base, &div->bypass);
+	return 0;
+}
+
+const struct clk_ops cv1800b_clk_bypass_fixed_div_ops = {
+	.disable = fixed_div_disable,
+	.enable = fixed_div_enable,
+	.get_rate = bypass_fixed_div_get_rate,
+	.set_parent = bypass_fixed_div_set_parent,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_bypass_fixed_div) = {
+	.name = "cv1800b_clk_bypass_fixed_div",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_clk_bypass_fixed_div_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+/* MUX */
+#define to_cv1800b_clk_mux(_clk) container_of(_clk, struct cv1800b_clk_mux, clk)
+
+static int mux_enable(struct clk *clk)
+{
+	struct cv1800b_clk_mux *mux = to_cv1800b_clk_mux(clk);
+
+	return cv1800b_clk_setbit(mux->base, &mux->gate);
+}
+
+static int mux_disable(struct clk *clk)
+{
+	struct cv1800b_clk_mux *mux = to_cv1800b_clk_mux(clk);
+
+	return cv1800b_clk_clrbit(mux->base, &mux->gate);
+}
+
+static ulong mux_get_rate(struct clk *clk)
+{
+	struct cv1800b_clk_mux *mux = to_cv1800b_clk_mux(clk);
+	ulong val;
+
+	if (mux->div_init == 0 ||
+	    readl(mux->base + mux->div.offset) & CLK_DIV_EN_FACTOR)
+		val = cv1800b_clk_getfield(mux->base, &mux->div);
+	else
+		val = mux->div_init;
+
+	return DIV_ROUND_UP_ULL(clk_get_parent_rate(clk), val);
+}
+
+static ulong mux_set_rate(struct clk *clk, ulong rate)
+{
+	struct cv1800b_clk_mux *mux = to_cv1800b_clk_mux(clk);
+	ulong parent_rate = clk_get_parent_rate(clk);
+	ulong val;
+
+	val = DIV_ROUND_UP_ULL(parent_rate, rate);
+	val = min_t(u32, val, clk_div_mask(mux->div.width));
+
+	cv1800b_clk_setfield(mux->base, &mux->div, val);
+	if (mux->div_init > 0)
+		setbits_le32(mux->base + mux->div.offset, CLK_DIV_EN_FACTOR);
+
+	return DIV_ROUND_UP_ULL(parent_rate, val);
+}
+
+static int mux_set_parent(struct clk *clk, struct clk *pclk)
+{
+	struct cv1800b_clk_mux *mux = to_cv1800b_clk_mux(clk);
+	int index = get_parent_index(pclk, mux->parent_names, mux->num_parents);
+
+	if (index < 0)
+		return -EINVAL;
+
+	cv1800b_clk_setfield(mux->base, &mux->mux, index);
+	return 0;
+}
+
+const struct clk_ops cv1800b_clk_mux_ops = {
+	.disable = mux_disable,
+	.enable = mux_enable,
+	.get_rate = mux_get_rate,
+	.set_rate = mux_set_rate,
+	.set_parent = mux_set_parent,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_mux) = {
+	.name = "cv1800b_clk_mux",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_clk_mux_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+#define to_cv1800b_clk_bypass_mux(_clk) \
+	container_of(_clk, struct cv1800b_clk_bypass_mux, mux.clk)
+
+static ulong bypass_mux_get_rate(struct clk *clk)
+{
+	struct cv1800b_clk_bypass_mux *mux = to_cv1800b_clk_bypass_mux(clk);
+
+	if (cv1800b_clk_getbit(mux->mux.base, &mux->bypass))
+		return 0;
+
+	return mux_get_rate(clk);
+}
+
+static ulong bypass_mux_set_rate(struct clk *clk, ulong rate)
+{
+	struct cv1800b_clk_bypass_mux *mux = to_cv1800b_clk_bypass_mux(clk);
+
+	if (cv1800b_clk_getbit(mux->mux.base, &mux->bypass))
+		return 0;
+
+	return mux_set_rate(clk, rate);
+}
+
+static int bypass_mux_set_parent(struct clk *clk, struct clk *pclk)
+{
+	struct cv1800b_clk_bypass_mux *mux = to_cv1800b_clk_bypass_mux(clk);
+	int index;
+
+	if (pclk->id == CV1800B_CLK_BYPASS) {
+		cv1800b_clk_setbit(mux->mux.base, &mux->bypass);
+		return 0;
+	}
+
+	index = get_parent_index(pclk, mux->mux.parent_names,
+				 mux->mux.num_parents);
+	if (index < 0)
+		return -EINVAL;
+
+	cv1800b_clk_clrbit(mux->mux.base, &mux->bypass);
+	cv1800b_clk_setfield(mux->mux.base, &mux->mux.mux, index);
+	return 0;
+}
+
+const struct clk_ops cv1800b_clk_bypass_mux_ops = {
+	.disable = mux_disable,
+	.enable = mux_enable,
+	.get_rate = bypass_mux_get_rate,
+	.set_rate = bypass_mux_set_rate,
+	.set_parent = bypass_mux_set_parent,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_bypass_mux) = {
+	.name = "cv1800b_clk_bypass_mux",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_clk_bypass_mux_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+/* MMUX */
+#define to_cv1800b_clk_mmux(_clk) \
+	container_of(_clk, struct cv1800b_clk_mmux, clk)
+
+static int mmux_enable(struct clk *clk)
+{
+	struct cv1800b_clk_mmux *mmux = to_cv1800b_clk_mmux(clk);
+
+	return cv1800b_clk_setbit(mmux->base, &mmux->gate);
+}
+
+static int mmux_disable(struct clk *clk)
+{
+	struct cv1800b_clk_mmux *mmux = to_cv1800b_clk_mmux(clk);
+
+	return cv1800b_clk_clrbit(mmux->base, &mmux->gate);
+}
+
+static ulong mmux_get_rate(struct clk *clk)
+{
+	struct cv1800b_clk_mmux *mmux = to_cv1800b_clk_mmux(clk);
+	int clk_sel = 1;
+	ulong reg, val;
+
+	if (cv1800b_clk_getbit(mmux->base, &mmux->bypass))
+		return 0;
+
+	if (cv1800b_clk_getbit(mmux->base, &mmux->clk_sel))
+		clk_sel = 0;
+
+	reg = readl(mmux->base + mmux->div[clk_sel].offset);
+
+	if (mmux->div_init[clk_sel] == 0 || reg & CLK_DIV_EN_FACTOR)
+		val = cv1800b_clk_getfield(mmux->base, &mmux->div[clk_sel]);
+	else
+		val = mmux->div_init[clk_sel];
+
+	return DIV_ROUND_UP_ULL(clk_get_parent_rate(clk), val);
+}
+
+static ulong mmux_set_rate(struct clk *clk, ulong rate)
+{
+	struct cv1800b_clk_mmux *mmux = to_cv1800b_clk_mmux(clk);
+	int clk_sel = 1;
+	ulong parent_rate = clk_get_parent_rate(clk);
+	ulong val;
+
+	if (cv1800b_clk_getbit(mmux->base, &mmux->bypass))
+		return 0;
+
+	if (cv1800b_clk_getbit(mmux->base, &mmux->clk_sel))
+		clk_sel = 0;
+
+	val = DIV_ROUND_UP_ULL(parent_rate, rate);
+	val = min_t(u32, val, clk_div_mask(mmux->div[clk_sel].width));
+
+	cv1800b_clk_setfield(mmux->base, &mmux->div[clk_sel], val);
+	if (mmux->div_init[clk_sel] > 0)
+		setbits_le32(mmux->base + mmux->div[clk_sel].offset,
+			     CLK_DIV_EN_FACTOR);
+
+	return DIV_ROUND_UP_ULL(parent_rate, val);
+}
+
+static int mmux_set_parent(struct clk *clk, struct clk *pclk)
+{
+	struct cv1800b_clk_mmux *mmux = to_cv1800b_clk_mmux(clk);
+	const char *pname = clk_hw_get_name(pclk);
+	int i;
+	u8 clk_sel, index;
+
+	if (pclk->id == CV1800B_CLK_BYPASS) {
+		cv1800b_clk_setbit(mmux->base, &mmux->bypass);
+		return 0;
+	}
+
+	for (i = 0; i < mmux->num_parents; i++) {
+		if (!strcmp(pname, mmux->parent_infos[i].name))
+			break;
+	}
+
+	if (i == mmux->num_parents)
+		return -EINVAL;
+
+	clk_sel = mmux->parent_infos[i].clk_sel;
+	index = mmux->parent_infos[i].index;
+	cv1800b_clk_clrbit(mmux->base, &mmux->bypass);
+	if (clk_sel)
+		cv1800b_clk_clrbit(mmux->base, &mmux->clk_sel);
+	else
+		cv1800b_clk_setbit(mmux->base, &mmux->clk_sel);
+
+	cv1800b_clk_setfield(mmux->base, &mmux->mux[clk_sel], index);
+	return 0;
+}
+
+const struct clk_ops cv1800b_clk_mmux_ops = {
+	.disable = mmux_disable,
+	.enable = mmux_enable,
+	.get_rate = mmux_get_rate,
+	.set_rate = mmux_set_rate,
+	.set_parent = mmux_set_parent,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_mmux) = {
+	.name = "cv1800b_clk_mmux",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_clk_mmux_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+/* AUDIO CLK */
+#define to_cv1800b_clk_audio(_clk) \
+	container_of(_clk, struct cv1800b_clk_audio, clk)
+
+static int aclk_enable(struct clk *clk)
+{
+	struct cv1800b_clk_audio *aclk = to_cv1800b_clk_audio(clk);
+
+	cv1800b_clk_setbit(aclk->base, &aclk->src_en);
+	cv1800b_clk_setbit(aclk->base, &aclk->output_en);
+	return 0;
+}
+
+static int aclk_disable(struct clk *clk)
+{
+	struct cv1800b_clk_audio *aclk = to_cv1800b_clk_audio(clk);
+
+	cv1800b_clk_clrbit(aclk->base, &aclk->src_en);
+	cv1800b_clk_clrbit(aclk->base, &aclk->output_en);
+	return 0;
+}
+
+static ulong aclk_get_rate(struct clk *clk)
+{
+	struct cv1800b_clk_audio *aclk = to_cv1800b_clk_audio(clk);
+	u64 parent_rate = clk_get_parent_rate(clk);
+	u32 m, n;
+
+	if (!cv1800b_clk_getbit(aclk->base, &aclk->div_en))
+		return 0;
+
+	m = cv1800b_clk_getfield(aclk->base, &aclk->m);
+	n = cv1800b_clk_getfield(aclk->base, &aclk->n);
+
+	return DIV_ROUND_UP_ULL(n * parent_rate, m * 2);
+}
+
+static u32 gcd(u32 a, u32 b)
+{
+	u32 t;
+
+	while (b != 0) {
+		t = a % b;
+		a = b;
+		b = t;
+	}
+	return a;
+}
+
+static void aclk_determine_mn(ulong parent_rate, ulong rate, u32 *m, u32 *n)
+{
+	u32 tm = parent_rate / 2;
+	u32 tn = rate;
+	u32 tcommon = gcd(tm, tn);
+	*m = tm / tcommon;
+	*n = tn / tcommon;
+}
+
+static ulong aclk_set_rate(struct clk *clk, ulong rate)
+{
+	struct cv1800b_clk_audio *aclk = to_cv1800b_clk_audio(clk);
+	ulong parent_rate = clk_get_parent_rate(clk);
+	u32 m, n;
+
+	aclk_determine_mn(parent_rate, rate, &m, &n);
+
+	cv1800b_clk_setfield(aclk->base, &aclk->m, m);
+	cv1800b_clk_setfield(aclk->base, &aclk->n, n);
+
+	cv1800b_clk_setbit(aclk->base, &aclk->div_en);
+	cv1800b_clk_setbit(aclk->base, &aclk->div_up);
+
+	return DIV_ROUND_UP_ULL(parent_rate * n, m * 2);
+}
+
+const struct clk_ops cv1800b_clk_audio_ops = {
+	.disable = aclk_disable,
+	.enable = aclk_enable,
+	.get_rate = aclk_get_rate,
+	.set_rate = aclk_set_rate,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_audio) = {
+	.name = "cv1800b_clk_audio",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_clk_audio_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/sophgo/clk-ip.h b/drivers/clk/sophgo/clk-ip.h
new file mode 100644
index 0000000000..09d15d86dc
--- /dev/null
+++ b/drivers/clk/sophgo/clk-ip.h
@@ -0,0 +1,288 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ *
+ */
+
+#ifndef __CLK_SOPHGO_IP_H__
+#define __CLK_SOPHGO_IP_H__
+
+#include <clk.h>
+
+#include "clk-common.h"
+
+struct cv1800b_mmux_parent_info {
+	const char *name;
+	u8 clk_sel;
+	u8 index;
+};
+
+struct cv1800b_clk_gate {
+	struct clk clk;
+	const char *name;
+	const char *parent_name;
+	void __iomem *base;
+	struct cv1800b_clk_regbit gate;
+};
+
+struct cv1800b_clk_div {
+	struct clk clk;
+	const char *name;
+	const char *parent_name;
+	void __iomem *base;
+	struct cv1800b_clk_regbit gate;
+	struct cv1800b_clk_regfield div;
+	int div_init;
+};
+
+struct cv1800b_clk_bypass_div {
+	struct cv1800b_clk_div div;
+	struct cv1800b_clk_regbit bypass;
+};
+
+struct cv1800b_clk_fixed_div {
+	struct clk clk;
+	const char *name;
+	const char *parent_name;
+	void __iomem *base;
+	struct cv1800b_clk_regbit gate;
+	int div;
+};
+
+struct cv1800b_clk_bypass_fixed_div {
+	struct cv1800b_clk_fixed_div div;
+	struct cv1800b_clk_regbit bypass;
+};
+
+struct cv1800b_clk_mux {
+	struct clk clk;
+	const char *name;
+	const char * const *parent_names;
+	u8 num_parents;
+	void __iomem *base;
+	struct cv1800b_clk_regbit gate;
+	struct cv1800b_clk_regfield div;
+	int div_init;
+	struct cv1800b_clk_regfield mux;
+};
+
+struct cv1800b_clk_bypass_mux {
+	struct cv1800b_clk_mux mux;
+	struct cv1800b_clk_regbit bypass;
+};
+
+struct cv1800b_clk_mmux {
+	struct clk clk;
+	const char *name;
+	const struct cv1800b_mmux_parent_info *parent_infos;
+	u8 num_parents;
+	void __iomem *base;
+	struct cv1800b_clk_regbit gate;
+	struct cv1800b_clk_regfield div[2];
+	int div_init[2];
+	struct cv1800b_clk_regfield mux[2];
+	struct cv1800b_clk_regbit bypass;
+	struct cv1800b_clk_regbit clk_sel;
+};
+
+struct cv1800b_clk_audio {
+	struct clk clk;
+	const char *name;
+	const char *parent_name;
+	void __iomem *base;
+	struct cv1800b_clk_regbit src_en;
+	struct cv1800b_clk_regbit output_en;
+	struct cv1800b_clk_regbit div_en;
+	struct cv1800b_clk_regbit div_up;
+	struct cv1800b_clk_regfield m;
+	struct cv1800b_clk_regfield n;
+};
+
+#define CV1800B_GATE(_id, _name, _parent,				\
+		     _gate_offset, _gate_shift,				\
+		     _flags)						\
+	{								\
+		.clk = {						\
+			.id = CV1800B_CLK_ID_TRANSFORM(_id),		\
+			.flags = _flags,				\
+		},							\
+		.name = _name,						\
+		.parent_name = _parent,					\
+		.gate = CV1800B_CLK_REGBIT(_gate_offset, _gate_shift),	\
+	}
+
+#define CV1800B_DIV(_id, _name, _parent,				\
+		    _gate_offset, _gate_shift,				\
+		    _div_offset, _div_shift, _div_width,		\
+		    _div_init, _flags)					\
+	{								\
+		.clk = {						\
+			.id = CV1800B_CLK_ID_TRANSFORM(_id),		\
+			.flags = _flags,				\
+		},							\
+		.name = _name,						\
+		.parent_name = _parent,					\
+		.gate = CV1800B_CLK_REGBIT(_gate_offset, _gate_shift),	\
+		.div = CV1800B_CLK_REGFIELD(_div_offset, _div_shift,	\
+					    _div_width),		\
+		.div_init = _div_init,					\
+	}
+
+#define CV1800B_BYPASS_DIV(_id, _name, _parent,				\
+			   _gate_offset, _gate_shift,			\
+			   _div_offset, _div_shift,			\
+			   _div_width, _div_init,			\
+			   _bypass_offset, _bypass_shift,		\
+			   _flags)					\
+	{								\
+		.div = CV1800B_DIV(_id, _name, _parent,			\
+				   _gate_offset, _gate_shift,		\
+				   _div_offset, _div_shift, _div_width,	\
+				   _div_init, _flags),			\
+		.bypass = CV1800B_CLK_REGBIT(_bypass_offset,		\
+					     _bypass_shift),		\
+	}
+
+#define CV1800B_FIXED_DIV(_id, _name, _parent,				\
+			  _gate_offset, _gate_shift,			\
+			  _div, _flags)					\
+	{								\
+		.clk = {						\
+			.id = CV1800B_CLK_ID_TRANSFORM(_id),		\
+			.flags = _flags,				\
+		},							\
+		.name = _name,						\
+		.parent_name = _parent,					\
+		.gate = CV1800B_CLK_REGBIT(_gate_offset, _gate_shift),	\
+		.div = _div,						\
+	}
+
+#define CV1800B_BYPASS_FIXED_DIV(_id, _name, _parent,			\
+				 _gate_offset, _gate_shift,		\
+				 _div,					\
+				 _bypass_offset, _bypass_shift,		\
+				 _flags)				\
+	{								\
+		.div = CV1800B_FIXED_DIV(_id, _name, _parent,		\
+					 _gate_offset, _gate_shift,	\
+					 _div, _flags),			\
+		.bypass = CV1800B_CLK_REGBIT(_bypass_offset,		\
+					     _bypass_shift)		\
+	}
+
+#define CV1800B_MUX(_id, _name, _parents,				\
+		    _gate_offset, _gate_shift,				\
+		    _div_offset, _div_shift, _div_width, _div_init,	\
+		    _mux_offset, _mux_shift, _mux_width,		\
+		    _flags)						\
+	{								\
+		.clk = {						\
+			.id = CV1800B_CLK_ID_TRANSFORM(_id),		\
+			.flags = _flags,				\
+		},							\
+		.name = _name,						\
+		.parent_names = _parents,				\
+		.num_parents = ARRAY_SIZE(_parents),			\
+		.gate = CV1800B_CLK_REGBIT(_gate_offset, _gate_shift),	\
+		.div = CV1800B_CLK_REGFIELD(_div_offset, _div_shift,	\
+					    _div_width),		\
+		.div_init = _div_init,					\
+		.mux = CV1800B_CLK_REGFIELD(_mux_offset, _mux_shift,	\
+					    _mux_width),		\
+	}
+
+#define CV1800B_BYPASS_MUX(_id, _name, _parents,			\
+			   _gate_offset, _gate_shift,			\
+			   _div_offset, _div_shift,			\
+			   _div_width, _div_init,			\
+			   _mux_offset, _mux_shift, _mux_width,		\
+			   _bypass_offset, _bypass_shift,		\
+			   _flags)					\
+	{								\
+		.mux = CV1800B_MUX(_id, _name, _parents,		\
+				   _gate_offset, _gate_shift,		\
+				   _div_offset, _div_shift,		\
+				   _div_width, _div_init,		\
+				   _mux_offset, _mux_shift, _mux_width,	\
+				   _flags),				\
+		.bypass = CV1800B_CLK_REGBIT(_bypass_offset,		\
+					     _bypass_shift),		\
+	}
+
+#define CV1800B_MMUX(_id, _name, _parents,				\
+		     _gate_offset, _gate_shift,				\
+		     _div0_offset, _div0_shift, _div0_width, _div0_init,\
+		     _div1_offset, _div1_shift, _div1_width, _div1_init,\
+		     _mux0_offset, _mux0_shift, _mux0_width,		\
+		     _mux1_offset, _mux1_shift, _mux1_width,		\
+		     _bypass_offset, _bypass_shift,			\
+		     _clk_sel_offset, _clk_sel_shift,			\
+		     _flags)						\
+	{								\
+		.clk = {						\
+			.id = CV1800B_CLK_ID_TRANSFORM(_id),		\
+			.flags = _flags,				\
+		},							\
+		.name = _name,						\
+		.parent_infos = _parents,				\
+		.num_parents = ARRAY_SIZE(_parents),			\
+		.gate = CV1800B_CLK_REGBIT(_gate_offset, _gate_shift),	\
+		.div = {						\
+			CV1800B_CLK_REGFIELD(_div0_offset, _div0_shift,	\
+					     _div0_width),		\
+			CV1800B_CLK_REGFIELD(_div1_offset, _div1_shift,	\
+					     _div1_width),		\
+		},							\
+		.div_init = { _div0_init, _div1_init },			\
+		.mux = {						\
+			CV1800B_CLK_REGFIELD(_mux0_offset, _mux0_shift,	\
+					     _mux0_width),		\
+			CV1800B_CLK_REGFIELD(_mux1_offset, _mux1_shift,	\
+					     _mux1_width),		\
+		},							\
+		.bypass = CV1800B_CLK_REGBIT(_bypass_offset,		\
+					     _bypass_shift),		\
+		.clk_sel = CV1800B_CLK_REGBIT(_clk_sel_offset,		\
+					      _clk_sel_shift),		\
+	}
+
+#define CV1800B_AUDIO(_id, _name, _parent,				\
+		      _src_en_offset, _src_en_shift,			\
+		      _output_en_offset, _output_en_shift,		\
+		      _div_en_offset, _div_en_shift,			\
+		      _div_up_offset, _div_up_shift,			\
+		      _m_offset, _m_shift, _m_width,			\
+		      _n_offset, _n_shift, _n_width,			\
+		      _flags)						\
+	{								\
+		.clk = {						\
+			.id = CV1800B_CLK_ID_TRANSFORM(_id),		\
+			.flags = _flags,				\
+		},							\
+		.name = _name,						\
+		.parent_name = _parent,					\
+		.src_en = CV1800B_CLK_REGBIT(_src_en_offset,		\
+					     _src_en_shift),		\
+		.output_en = CV1800B_CLK_REGBIT(_output_en_offset,	\
+						_output_en_shift),	\
+		.div_en = CV1800B_CLK_REGBIT(_div_en_offset,		\
+					     _div_en_shift),		\
+		.div_up = CV1800B_CLK_REGBIT(_div_up_offset,		\
+					     _div_up_shift),		\
+		.m = CV1800B_CLK_REGFIELD(_m_offset, _m_shift,		\
+					  _m_width),			\
+		.n = CV1800B_CLK_REGFIELD(_n_offset, _n_shift,		\
+					  _n_width),			\
+	}
+
+extern const struct clk_ops cv1800b_clk_gate_ops;
+extern const struct clk_ops cv1800b_clk_div_ops;
+extern const struct clk_ops cv1800b_clk_bypass_div_ops;
+extern const struct clk_ops cv1800b_clk_fixed_div_ops;
+extern const struct clk_ops cv1800b_clk_bypass_fixed_div_ops;
+extern const struct clk_ops cv1800b_clk_mux_ops;
+extern const struct clk_ops cv1800b_clk_bypass_mux_ops;
+extern const struct clk_ops cv1800b_clk_mmux_ops;
+extern const struct clk_ops cv1800b_clk_audio_ops;
+
+#endif /* __CLK_SOPHGO_IP_H__ */
diff --git a/drivers/clk/sophgo/clk-pll.c b/drivers/clk/sophgo/clk-pll.c
new file mode 100644
index 0000000000..c99aa0b4e4
--- /dev/null
+++ b/drivers/clk/sophgo/clk-pll.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <div64.h>
+#include <linux/bitfield.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+
+#include "clk-common.h"
+#include "clk-pll.h"
+
+#define PLL_PRE_DIV_MIN      1
+#define PLL_PRE_DIV_MAX      127
+#define PLL_POST_DIV_MIN     1
+#define PLL_POST_DIV_MAX     127
+#define PLL_DIV_MIN          6
+#define PLL_DIV_MAX          127
+#define PLL_ICTRL_MIN        0
+#define PLL_ICTRL_MAX        7
+#define PLL_MODE_MIN         0
+#define PLL_MODE_MAX         3
+#define FOR_RANGE(x, RANGE) for (x = RANGE##_MIN; x <= RANGE##_MAX; x++)
+
+#define PLL_ICTRL GENMASK(26, 24)
+#define PLL_DIV_SEL GENMASK(23, 17)
+#define PLL_SEL_MODE GENMASK(16, 15)
+#define PLL_POST_DIV_SEL GENMASK(14, 8)
+#define PLL_PRE_DIV_SEL GENMASK(6, 0)
+#define PLL_MASK_ALL (PLL_ICTRL | PLL_DIV_SEL | PLL_SEL_MODE | PLL_POST_DIV_SEL | PLL_PRE_DIV_SEL)
+
+/* IPLL */
+#define to_clk_ipll(dev) container_of(dev, struct cv1800b_clk_ipll, clk)
+
+static int cv1800b_ipll_enable(struct clk *clk)
+{
+	struct cv1800b_clk_ipll *pll = to_clk_ipll(clk);
+
+	cv1800b_clk_clrbit(pll->base, &pll->pll_pwd);
+	return 0;
+}
+
+static int cv1800b_ipll_disable(struct clk *clk)
+{
+	struct cv1800b_clk_ipll *pll = to_clk_ipll(clk);
+
+	cv1800b_clk_setbit(pll->base, &pll->pll_pwd);
+	return 0;
+}
+
+static ulong cv1800b_ipll_get_rate(struct clk *clk)
+{
+	struct cv1800b_clk_ipll *pll = to_clk_ipll(clk);
+
+	ulong parent_rate = clk_get_parent_rate(clk);
+	u32 reg = readl(pll->base + pll->pll_reg);
+	u32 pre_div = FIELD_GET(PLL_PRE_DIV_SEL, reg);
+	u32 post_div = FIELD_GET(PLL_POST_DIV_SEL, reg);
+	u32 div = FIELD_GET(PLL_DIV_SEL, reg);
+
+	return DIV_ROUND_DOWN_ULL(parent_rate * div, pre_div * post_div);
+}
+
+static ulong cv1800b_ipll_set_rate(struct clk *clk, ulong rate)
+{
+	struct cv1800b_clk_ipll *pll = to_clk_ipll(clk);
+	ulong parent_rate = clk_get_parent_rate(clk);
+	u32 pre_div, post_div, div;
+	u32 pre_div_sel, post_div_sel, div_sel;
+	ulong new_rate, best_rate = 0;
+	u32 mode, ictrl;
+	u32 test, val;
+
+	FOR_RANGE(pre_div, PLL_PRE_DIV)
+	{
+		FOR_RANGE(post_div, PLL_POST_DIV)
+		{
+			FOR_RANGE(div, PLL_DIV)
+			{
+				new_rate =
+					DIV_ROUND_DOWN_ULL(parent_rate * div, pre_div * post_div);
+				if (rate - new_rate < rate - best_rate) {
+					best_rate = new_rate;
+					pre_div_sel = pre_div;
+					post_div_sel = post_div;
+					div_sel = div;
+				}
+			}
+		}
+	}
+
+	FOR_RANGE(mode, PLL_MODE)
+	{
+		FOR_RANGE(ictrl, PLL_ICTRL)
+		{
+			test = 184 * (1 + mode) * (1 + ictrl) / 2;
+			if (test > 20 * div_sel && test < 35 * div_sel) {
+				val = FIELD_PREP(PLL_PRE_DIV_SEL, pre_div_sel) |
+				      FIELD_PREP(PLL_POST_DIV_SEL, post_div_sel) |
+				      FIELD_PREP(PLL_DIV_SEL, div_sel) |
+				      FIELD_PREP(PLL_ICTRL, ictrl) |
+				      FIELD_PREP(PLL_SEL_MODE, mode);
+				clrsetbits_le32(pll->base + pll->pll_reg, PLL_MASK_ALL, val);
+				return best_rate;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+const struct clk_ops cv1800b_ipll_ops = {
+	.enable = cv1800b_ipll_enable,
+	.disable = cv1800b_ipll_disable,
+	.get_rate = cv1800b_ipll_get_rate,
+	.set_rate = cv1800b_ipll_set_rate,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_ipll) = {
+	.name = "cv1800b_clk_ipll",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_ipll_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+/* FPLL */
+#define to_clk_fpll(dev) container_of(dev, struct cv1800b_clk_fpll, ipll.clk)
+
+static ulong cv1800b_fpll_get_rate(struct clk *clk)
+{
+	struct cv1800b_clk_fpll *pll = to_clk_fpll(clk);
+	u32 val, syn_set;
+	u32 pre_div, post_div, div;
+	u8 mult = 1;
+	ulong divisor, remainder, rate;
+
+	if (!cv1800b_clk_getbit(pll->ipll.base, &pll->syn.en))
+		return cv1800b_ipll_get_rate(clk);
+
+	syn_set = readl(pll->ipll.base + pll->syn.set);
+	if (syn_set == 0)
+		return 0;
+
+	val = readl(pll->ipll.base + pll->ipll.pll_reg);
+	pre_div = FIELD_GET(PLL_PRE_DIV_SEL, val);
+	post_div = FIELD_GET(PLL_POST_DIV_SEL, val);
+	div = FIELD_GET(PLL_DIV_SEL, val);
+
+	if (cv1800b_clk_getbit(pll->ipll.base, &pll->syn.clk_half))
+		mult = 2;
+
+	divisor = (ulong)pre_div * post_div * syn_set;
+	rate = (clk_get_parent_rate(clk) * div) << 25;
+	remainder = rate % divisor;
+	rate /= divisor;
+	return rate * mult + DIV_ROUND_CLOSEST_ULL(remainder * mult, divisor);
+}
+
+static ulong cv1800b_find_syn(ulong rate, ulong parent_rate, ulong pre_div, ulong post_div,
+			      ulong div, u32 *syn)
+{
+	u32 syn_min = (4 << 26) + 1;
+	u32 syn_max = U32_MAX;
+	u32 mid;
+	ulong new_rate;
+	u32 mult = 1;
+	ulong divisor, remainder;
+
+	while (syn_min < syn_max) {
+		mid = ((ulong)syn_min + syn_max) / 2;
+		divisor = pre_div * post_div * mid;
+		new_rate = (parent_rate * div) << 25;
+		remainder = do_div(new_rate, divisor);
+		new_rate = new_rate * mult + DIV_ROUND_CLOSEST_ULL(remainder * mult, divisor);
+		if (new_rate > rate) {
+			syn_max = mid + 1;
+		} else if (new_rate < rate) {
+			syn_min = mid - 1;
+		} else {
+			syn_min = mid;
+			break;
+		}
+	}
+	*syn = syn_min;
+	return new_rate;
+}
+
+static ulong cv1800b_fpll_set_rate(struct clk *clk, ulong rate)
+{
+	struct cv1800b_clk_fpll *pll = to_clk_fpll(clk);
+	ulong parent_rate = clk_get_parent_rate(clk);
+	u32 pre_div, post_div, div;
+	u32 pre_div_sel, post_div_sel, div_sel;
+	u32 syn, syn_sel;
+	ulong new_rate, best_rate = 0;
+	u32 mult = 1;
+	u32 mode, ictrl;
+
+	if (!cv1800b_clk_getbit(pll->ipll.base, &pll->syn.en))
+		return cv1800b_ipll_set_rate(clk, rate);
+
+	if (cv1800b_clk_getbit(pll->ipll.base, &pll->syn.clk_half))
+		mult = 2;
+
+	FOR_RANGE(pre_div, PLL_PRE_DIV)
+	{
+		FOR_RANGE(post_div, PLL_POST_DIV)
+		{
+			FOR_RANGE(div, PLL_DIV)
+			{
+				new_rate = cv1800b_find_syn(rate, parent_rate, pre_div, post_div,
+							    div, &syn);
+				if (rate - new_rate < rate - best_rate) {
+					best_rate = new_rate;
+					pre_div_sel = pre_div;
+					post_div_sel = post_div;
+					div_sel = div;
+					syn_sel = syn;
+				}
+			}
+		}
+	}
+
+	FOR_RANGE(mode, PLL_MODE)
+	{
+		FOR_RANGE(ictrl, PLL_ICTRL)
+		{
+			u32 test = 184 * (1 + mode) * (1 + ictrl) / 2;
+
+			if (test > 10 * div_sel && test <= 24 * div_sel) {
+				u32 val = FIELD_PREP(PLL_PRE_DIV_SEL, pre_div_sel) |
+					  FIELD_PREP(PLL_POST_DIV_SEL, post_div_sel) |
+					  FIELD_PREP(PLL_DIV_SEL, div_sel) |
+					  FIELD_PREP(PLL_ICTRL, ictrl) |
+					  FIELD_PREP(PLL_SEL_MODE, mode);
+				clrsetbits_le32(pll->ipll.base + pll->ipll.pll_reg, PLL_MASK_ALL,
+						val);
+				writel(syn_sel, pll->ipll.base + pll->syn.set);
+				return best_rate;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int cv1800b_fpll_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct cv1800b_clk_fpll *pll = to_clk_fpll(clk);
+
+	if (parent->id == CV1800B_CLK_BYPASS)
+		cv1800b_clk_setbit(pll->ipll.base, &pll->syn.en);
+	else
+		cv1800b_clk_clrbit(pll->ipll.base, &pll->syn.en);
+
+	return 0;
+}
+
+const struct clk_ops cv1800b_fpll_ops = {
+	.enable = cv1800b_ipll_enable,
+	.disable = cv1800b_ipll_disable,
+	.get_rate = cv1800b_fpll_get_rate,
+	.set_rate = cv1800b_fpll_set_rate,
+	.set_parent = cv1800b_fpll_set_parent,
+};
+
+U_BOOT_DRIVER(cv1800b_clk_fpll) = {
+	.name = "cv1800b_clk_fpll",
+	.id = UCLASS_CLK,
+	.ops = &cv1800b_fpll_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/sophgo/clk-pll.h b/drivers/clk/sophgo/clk-pll.h
new file mode 100644
index 0000000000..bea9bd8a43
--- /dev/null
+++ b/drivers/clk/sophgo/clk-pll.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ *
+ */
+
+#ifndef __clk_SOPHGO_PLL_H__
+#define __clk_SOPHGO_PLL_H__
+
+#include <clk.h>
+
+#include "clk-common.h"
+
+struct cv1800b_clk_synthesizer {
+	struct cv1800b_clk_regbit en;
+	struct cv1800b_clk_regbit clk_half;
+	u32 ctrl;
+	u32 set;
+};
+
+struct cv1800b_clk_ipll {
+	struct clk clk;
+	const char *name;
+	const char *parent_name;
+	void __iomem *base;
+	u32 pll_reg;
+	struct cv1800b_clk_regbit pll_pwd;
+	struct cv1800b_clk_regbit pll_status;
+};
+
+struct cv1800b_clk_fpll {
+	struct cv1800b_clk_ipll ipll;
+	struct cv1800b_clk_synthesizer syn;
+};
+
+#define CV1800B_IPLL(_id, _name, _parent_name, _pll_reg, _pll_pwd_offset,	\
+		     _pll_pwd_shift, _pll_status_offset, _pll_status_shift,	\
+		     _flags)							\
+	{									\
+		.clk = {							\
+			.id = CV1800B_CLK_ID_TRANSFORM(_id),			\
+			.flags = _flags,					\
+		},								\
+		.name = _name,							\
+		.parent_name = _parent_name,					\
+		.pll_reg = _pll_reg,						\
+		.pll_pwd = CV1800B_CLK_REGBIT(_pll_pwd_offset, _pll_pwd_shift),	\
+		.pll_status = CV1800B_CLK_REGBIT(_pll_status_offset,		\
+						 _pll_status_shift),		\
+	}
+
+#define CV1800B_FPLL(_id, _name, _parent_name, _pll_reg, _pll_pwd_offset,	\
+		     _pll_pwd_shift, _pll_status_offset, _pll_status_shift,	\
+		     _syn_en_offset, _syn_en_shift, _syn_clk_half_offset,	\
+		     _syn_clk_half_shift, _syn_ctrl_offset, _syn_set_offset,	\
+		     _flags)							\
+	{									\
+		.ipll = CV1800B_IPLL(_id, _name, _parent_name, _pll_reg,	\
+				     _pll_pwd_offset, _pll_pwd_shift,		\
+				     _pll_status_offset, _pll_status_shift,	\
+				     _flags),					\
+		.syn = {							\
+			.en = CV1800B_CLK_REGBIT(_syn_en_offset, _syn_en_shift),\
+			.clk_half = CV1800B_CLK_REGBIT(_syn_clk_half_offset,	\
+						       _syn_clk_half_shift),	\
+			.ctrl = _syn_ctrl_offset,				\
+			.set = _syn_set_offset,					\
+		},								\
+	}
+
+extern const struct clk_ops cv1800b_ipll_ops;
+extern const struct clk_ops cv1800b_fpll_ops;
+
+#endif /* __clk_SOPHGO_PLL_H__ */
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 3/4] configs: milkv_duo: Enable clock controller
  2024-06-11  9:41 [PATCH v2 0/4] clk: sophgo: milkv_duo: Add and enable clock controller driver Kongyang Liu
  2024-06-11  9:41 ` [PATCH v2 1/4] dt-bindings: clk: import header for clock controller of sophgo CV1800B Kongyang Liu
  2024-06-11  9:41 ` [PATCH v2 2/4] clk: sophgo: cv1800b: Add clock controller driver for cv1800b SoC Kongyang Liu
@ 2024-06-11  9:41 ` Kongyang Liu
  2024-09-09  6:02   ` Leo Liang
  2024-06-11  9:41 ` [PATCH v2 4/4] riscv: dts: sophgo: Replace device clocks with real clocks Kongyang Liu
  3 siblings, 1 reply; 9+ messages in thread
From: Kongyang Liu @ 2024-06-11  9:41 UTC (permalink / raw)
  To: u-boot; +Cc: Leo Yu-Chi Liang, Tom Rini

Add configs to enable clock controller for Sophgo Milk-V Duo board

Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>
---

(no changes since v1)

 configs/milkv_duo_defconfig | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/configs/milkv_duo_defconfig b/configs/milkv_duo_defconfig
index 0cb2922de4..1186763a73 100644
--- a/configs/milkv_duo_defconfig
+++ b/configs/milkv_duo_defconfig
@@ -1,6 +1,6 @@
 CONFIG_RISCV=y
 CONFIG_SYS_MALLOC_LEN=0x820000
-CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SYS_MALLOC_F_LEN=0x8000
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
 CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x82300000
@@ -26,17 +26,18 @@ CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_ENV_OVERWRITE=y
 CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_CLK_SOPHGO_CV1800B=y
 CONFIG_MMC=y
 CONFIG_MMC_IO_VOLTAGE=y
 CONFIG_MMC_UHS_SUPPORT=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_ADMA=y
 CONFIG_MMC_SDHCI_CV1800B=y
+CONFIG_SPI_FLASH_MACRONIX=y
 CONFIG_ETH_DESIGNWARE=y
 CONFIG_SYS_NS16550=y
 CONFIG_SYS_NS16550_MEM32=y
-CONFIG_SYSRESET=y
-CONFIG_SYSRESET_CV1800B=y
-CONFIG_SPI_FLASH_MACRONIX=y
 CONFIG_SPI=y
 CONFIG_CV1800B_SPIF=y
+CONFIG_SYSRESET=y
+CONFIG_SYSRESET_CV1800B=y
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 4/4] riscv: dts: sophgo: Replace device clocks with real clocks.
  2024-06-11  9:41 [PATCH v2 0/4] clk: sophgo: milkv_duo: Add and enable clock controller driver Kongyang Liu
                   ` (2 preceding siblings ...)
  2024-06-11  9:41 ` [PATCH v2 3/4] configs: milkv_duo: Enable clock controller Kongyang Liu
@ 2024-06-11  9:41 ` Kongyang Liu
  2024-09-09  6:03   ` Leo Liang
  3 siblings, 1 reply; 9+ messages in thread
From: Kongyang Liu @ 2024-06-11  9:41 UTC (permalink / raw)
  To: u-boot; +Cc: Leo, Rick Chen, Tom Rini

Replace device clocks with real clocks from the clock controller, and
remove dummy clocks.

Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>
---

(no changes since v1)

 arch/riscv/dts/cv18xx.dtsi | 40 +++++++++++++++-----------------------
 1 file changed, 16 insertions(+), 24 deletions(-)

diff --git a/arch/riscv/dts/cv18xx.dtsi b/arch/riscv/dts/cv18xx.dtsi
index 4b0143450e..8a7386b76e 100644
--- a/arch/riscv/dts/cv18xx.dtsi
+++ b/arch/riscv/dts/cv18xx.dtsi
@@ -5,6 +5,7 @@
  */
 
 #include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/sophgo,cv1800.h>
 
 / {
 	#address-cells = <1>;
@@ -45,13 +46,6 @@
 		#clock-cells = <0>;
 	};
 
-	sdhci_clk: sdhci-clock {
-		compatible = "fixed-clock";
-		clock-frequency = <375000000>;
-		clock-output-names = "sdhci_clk";
-		#clock-cells = <0>;
-	};
-
 	eth_csrclk: eth-csrclk {
 		compatible = "fixed-clock";
 		clock-frequency = <250000000>;
@@ -66,13 +60,6 @@
 		#clock-cells = <0x0>;
 	};
 
-	spif_clk: spi-flash-clock {
-		compatible = "fixed-clock";
-		clock-frequency = <300000000>;
-		clock-output-names = "spif_clk";
-		#clock-cells = <0>;
-	};
-
 	soc {
 		compatible = "simple-bus";
 		interrupt-parent = <&plic>;
@@ -163,8 +150,8 @@
 			compatible = "sophgo,cv1800b-dwmac";
 			reg = <0x04070000 0x10000>;
 			interrupts = <31 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&eth_csrclk>, <&eth_ptpclk>;
-			clock-names = "stmmaceth", "ptp_ref";
+			clocks = <&clk CLK_ETH0_500M>, <&clk CLK_AXI4_ETH0>;
+			clock-names = "stmmaceth", "pclk";
 			status = "disabled";
 		};
 
@@ -172,7 +159,8 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x04140000 0x100>;
 			interrupts = <44 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&osc>;
+			clocks = <&clk CLK_UART0>, <&clk CLK_APB_UART0>;
+			clock-names = "baudclk", "apb_pclk";
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			status = "disabled";
@@ -182,7 +170,8 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x04150000 0x100>;
 			interrupts = <45 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&osc>;
+			clocks = <&clk CLK_UART4>, <&clk CLK_APB_UART4>;
+			clock-names = "baudclk", "apb_pclk";
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			status = "disabled";
@@ -192,7 +181,8 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x04160000 0x100>;
 			interrupts = <46 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&osc>;
+			clocks = <&clk CLK_UART2>, <&clk CLK_APB_UART2>;
+			clock-names = "baudclk", "apb_pclk";
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			status = "disabled";
@@ -202,7 +192,8 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x04170000 0x100>;
 			interrupts = <47 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&osc>;
+			clocks = <&clk CLK_UART3>, <&clk CLK_APB_UART3>;
+			clock-names = "baudclk", "apb_pclk";
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			status = "disabled";
@@ -212,7 +203,8 @@
 			compatible = "snps,dw-apb-uart";
 			reg = <0x041c0000 0x100>;
 			interrupts = <48 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&osc>;
+			clocks = <&clk CLK_UART4>, <&clk CLK_APB_UART4>;
+			clock-names = "baudclk", "apb_pclk";
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			status = "disabled";
@@ -222,8 +214,8 @@
 			compatible = "sophgo,cv1800b-dwcmshc";
 			reg = <0x4310000 0x1000>;
 			interrupts = <36 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&sdhci_clk>;
-			clock-names = "core";
+			clocks = <&clk CLK_AXI4_SD0>, <&clk CLK_SD0>;
+			clock-names = "core", "bus";
 			status = "disabled";
 		};
 
@@ -232,7 +224,7 @@
 			reg = <0x10000000 0x10000000>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			clocks = <&spif_clk>;
+			clocks = <&clk CLK_AHB_SF>;
 			interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 1/4] dt-bindings: clk: import header for clock controller of sophgo CV1800B
  2024-06-11  9:41 ` [PATCH v2 1/4] dt-bindings: clk: import header for clock controller of sophgo CV1800B Kongyang Liu
@ 2024-09-09  6:00   ` Leo Liang
  0 siblings, 0 replies; 9+ messages in thread
From: Leo Liang @ 2024-09-09  6:00 UTC (permalink / raw)
  To: Kongyang Liu; +Cc: u-boot, Tom Rini

On Tue, Jun 11, 2024 at 05:41:13PM +0800, Kongyang Liu wrote:
> Import header file of sophgo cv1800b clock controller from kernel
> 
> Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>
> Link: https://lore.kernel.org/all/IA1PR20MB4953637E7A6C121D7A700F1CBB8BA@IA1PR20MB4953.namprd20.prod.outlook.com/
> ---
> 
> (no changes since v1)
> 
>  include/dt-bindings/clock/sophgo,cv1800.h | 176 ++++++++++++++++++++++
>  1 file changed, 176 insertions(+)
>  create mode 100644 include/dt-bindings/clock/sophgo,cv1800.h

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 2/4] clk: sophgo: cv1800b: Add clock controller driver for cv1800b SoC
  2024-06-11  9:41 ` [PATCH v2 2/4] clk: sophgo: cv1800b: Add clock controller driver for cv1800b SoC Kongyang Liu
@ 2024-09-09  6:02   ` Leo Liang
  0 siblings, 0 replies; 9+ messages in thread
From: Leo Liang @ 2024-09-09  6:02 UTC (permalink / raw)
  To: Kongyang Liu
  Cc: u-boot, Andre Przywara, Arturs Artamonovs, Caleb Connolly,
	Greg Malysa, Lukasz Majewski, Marek Vasut, Michal Simek,
	Nathan Barrett-Morrison, Samuel Holland, Sean Anderson,
	Sumit Garg, Tom Rini, Utsav Agarwal, Vasileios Bimpikas

On Tue, Jun 11, 2024 at 05:41:14PM +0800, Kongyang Liu wrote:
> Add clock controller driver for sophgo cv1800b SoC
> 
> Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>
> ---
> 
> Changes in v2:
> - Fix compilation error
> - Remove unused code
> 
>  drivers/clk/Kconfig              |   1 +
>  drivers/clk/Makefile             |   1 +
>  drivers/clk/sophgo/Kconfig       |  14 +
>  drivers/clk/sophgo/Makefile      |   6 +
>  drivers/clk/sophgo/clk-common.h  |  74 +++
>  drivers/clk/sophgo/clk-cv1800b.c | 754 +++++++++++++++++++++++++++++++
>  drivers/clk/sophgo/clk-cv1800b.h | 123 +++++
>  drivers/clk/sophgo/clk-ip.c      | 594 ++++++++++++++++++++++++
>  drivers/clk/sophgo/clk-ip.h      | 288 ++++++++++++
>  drivers/clk/sophgo/clk-pll.c     | 275 +++++++++++
>  drivers/clk/sophgo/clk-pll.h     |  74 +++
>  11 files changed, 2204 insertions(+)
>  create mode 100644 drivers/clk/sophgo/Kconfig
>  create mode 100644 drivers/clk/sophgo/Makefile
>  create mode 100644 drivers/clk/sophgo/clk-common.h
>  create mode 100644 drivers/clk/sophgo/clk-cv1800b.c
>  create mode 100644 drivers/clk/sophgo/clk-cv1800b.h
>  create mode 100644 drivers/clk/sophgo/clk-ip.c
>  create mode 100644 drivers/clk/sophgo/clk-ip.h
>  create mode 100644 drivers/clk/sophgo/clk-pll.c
>  create mode 100644 drivers/clk/sophgo/clk-pll.h

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 3/4] configs: milkv_duo: Enable clock controller
  2024-06-11  9:41 ` [PATCH v2 3/4] configs: milkv_duo: Enable clock controller Kongyang Liu
@ 2024-09-09  6:02   ` Leo Liang
  0 siblings, 0 replies; 9+ messages in thread
From: Leo Liang @ 2024-09-09  6:02 UTC (permalink / raw)
  To: Kongyang Liu; +Cc: u-boot, Tom Rini

On Tue, Jun 11, 2024 at 05:41:15PM +0800, Kongyang Liu wrote:
> Add configs to enable clock controller for Sophgo Milk-V Duo board
> 
> Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>
> ---
> 
> (no changes since v1)
> 
>  configs/milkv_duo_defconfig | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 4/4] riscv: dts: sophgo: Replace device clocks with real clocks.
  2024-06-11  9:41 ` [PATCH v2 4/4] riscv: dts: sophgo: Replace device clocks with real clocks Kongyang Liu
@ 2024-09-09  6:03   ` Leo Liang
  0 siblings, 0 replies; 9+ messages in thread
From: Leo Liang @ 2024-09-09  6:03 UTC (permalink / raw)
  To: Kongyang Liu; +Cc: u-boot, Rick Chen, Tom Rini

On Tue, Jun 11, 2024 at 05:41:16PM +0800, Kongyang Liu wrote:
> Replace device clocks with real clocks from the clock controller, and
> remove dummy clocks.
> 
> Signed-off-by: Kongyang Liu <seashell11234455@gmail.com>
> ---
> 
> (no changes since v1)
> 
>  arch/riscv/dts/cv18xx.dtsi | 40 +++++++++++++++-----------------------
>  1 file changed, 16 insertions(+), 24 deletions(-)

Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2024-09-09  6:03 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-11  9:41 [PATCH v2 0/4] clk: sophgo: milkv_duo: Add and enable clock controller driver Kongyang Liu
2024-06-11  9:41 ` [PATCH v2 1/4] dt-bindings: clk: import header for clock controller of sophgo CV1800B Kongyang Liu
2024-09-09  6:00   ` Leo Liang
2024-06-11  9:41 ` [PATCH v2 2/4] clk: sophgo: cv1800b: Add clock controller driver for cv1800b SoC Kongyang Liu
2024-09-09  6:02   ` Leo Liang
2024-06-11  9:41 ` [PATCH v2 3/4] configs: milkv_duo: Enable clock controller Kongyang Liu
2024-09-09  6:02   ` Leo Liang
2024-06-11  9:41 ` [PATCH v2 4/4] riscv: dts: sophgo: Replace device clocks with real clocks Kongyang Liu
2024-09-09  6:03   ` Leo Liang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox