clk: Add SpacemiT K1-X clock drivers 35/316535/1
authorMichal Wilczynski <m.wilczynski@samsung.com>
Thu, 22 Aug 2024 07:31:00 +0000 (09:31 +0200)
committerMichal Wilczynski <m.wilczynski@samsung.com>
Thu, 22 Aug 2024 11:53:35 +0000 (13:53 +0200)
Clock drivers are critical for correct operation of the other hardware on
the SoC. Port them from the vendor kernel [1].

[1] - https://github.com/BPI-SINOVOIP/pi-linux.git

Change-Id: Ib72ab69e6634166b37fe513f11a5fb89666ee5db
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
13 files changed:
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/spacemit/Kconfig [new file with mode: 0755]
drivers/clk/spacemit/Makefile [new file with mode: 0755]
drivers/clk/spacemit/ccu-spacemit-k1x.c [new file with mode: 0755]
drivers/clk/spacemit/ccu-spacemit-k1x.h [new file with mode: 0755]
drivers/clk/spacemit/ccu_ddn.c [new file with mode: 0644]
drivers/clk/spacemit/ccu_ddn.h [new file with mode: 0644]
drivers/clk/spacemit/ccu_mix.c [new file with mode: 0755]
drivers/clk/spacemit/ccu_mix.h [new file with mode: 0755]
drivers/clk/spacemit/ccu_pll.c [new file with mode: 0644]
drivers/clk/spacemit/ccu_pll.h [new file with mode: 0644]
include/dt-bindings/clock/spacemit-k1x-clock.h [new file with mode: 0755]

index c30099866174d3d9e20f425726180f9f49ea746f..aabb3bb063bbbff165fc41ec68f3875cde429757 100644 (file)
@@ -501,6 +501,7 @@ source "drivers/clk/visconti/Kconfig"
 source "drivers/clk/x86/Kconfig"
 source "drivers/clk/xilinx/Kconfig"
 source "drivers/clk/zynqmp/Kconfig"
+source "drivers/clk/spacemit/Kconfig"
 
 # Kunit test cases
 config CLK_KUNIT_TEST
index 18969cbd4bb1e862d352eda0012f9d5f86e2d0d6..583d5fc93c1443ac8e681020cb54510a0a10c6eb 100644 (file)
@@ -136,3 +136,4 @@ endif
 obj-y                                  += xilinx/
 obj-$(CONFIG_ARCH_ZYNQ)                        += zynq/
 obj-$(CONFIG_COMMON_CLK_ZYNQMP)         += zynqmp/
+obj-y                                  += spacemit/
diff --git a/drivers/clk/spacemit/Kconfig b/drivers/clk/spacemit/Kconfig
new file mode 100755 (executable)
index 0000000..94442a6
--- /dev/null
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+# common clock support for SPACEMIT SoC family.
+
+config SPACEMIT_K1PRO_CCU
+       tristate "Clock support for Spacemit k1pro SoCs"
+       depends on SOC_SPACEMIT_K1PRO
+       help
+         Build the driver for K1pro Clock Driver.
+
+config SPACEMIT_K1X_CCU
+        tristate "Clock support for Spacemit k1x SoCs"
+        depends on ARCH_SPACEMIT_K1X
+        help
+          Build the driver for Spacemit K1x Clock Driver.
+
diff --git a/drivers/clk/spacemit/Makefile b/drivers/clk/spacemit/Makefile
new file mode 100755 (executable)
index 0000000..02efb5f
--- /dev/null
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Spacemit Clock specific Makefile
+#
+
+#SoC support
+obj-$(CONFIG_SPACEMIT_K1X_CCU)     += ccu-spacemit-k1x.o ccu_mix.o ccu_pll.o ccu_ddn.o
+obj-$(CONFIG_SPACEMIT_K1PRO_CCU)   += ccu-spacemit-k1pro.o
diff --git a/drivers/clk/spacemit/ccu-spacemit-k1x.c b/drivers/clk/spacemit/ccu-spacemit-k1x.c
new file mode 100755 (executable)
index 0000000..f385788
--- /dev/null
@@ -0,0 +1,1514 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit k1x clock controller driver
+ *
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/clock/spacemit-k1x-clock.h>
+#include "ccu-spacemit-k1x.h"
+#include "ccu_mix.h"
+#include "ccu_pll.h"
+#include "ccu_ddn.h"
+
+#define LOG_INFO(fmt, arg...)    pr_info("[K1X-CLK][%s][%d]:" fmt "\n", __func__, __LINE__, ##arg)
+
+DEFINE_SPINLOCK(g_cru_lock);
+
+/* APBS register offset */
+//pll1
+#define APB_SPARE1_REG          0x100
+#define APB_SPARE2_REG          0x104
+#define APB_SPARE3_REG          0x108
+//pll2
+#define APB_SPARE7_REG          0x118
+#define APB_SPARE8_REG          0x11c
+#define APB_SPARE9_REG          0x120
+//pll3
+#define APB_SPARE10_REG         0x124
+#define APB_SPARE11_REG         0x128
+#define APB_SPARE12_REG         0x12c
+/* end of APBS register offset */
+
+/* APBC register offset */
+#define APBC_UART1_CLK_RST      0x0
+#define APBC_UART2_CLK_RST      0x4
+#define APBC_GPIO_CLK_RST       0x8
+#define APBC_PWM0_CLK_RST       0xc
+#define APBC_PWM1_CLK_RST       0x10
+#define APBC_PWM2_CLK_RST       0x14
+#define APBC_PWM3_CLK_RST       0x18
+#define APBC_TWSI8_CLK_RST      0x20
+#define APBC_UART3_CLK_RST      0x24
+#define APBC_RTC_CLK_RST        0x28 //reserved
+#define APBC_TWSI0_CLK_RST      0x2c
+#define APBC_TWSI1_CLK_RST      0x30
+#define APBC_TIMERS1_CLK_RST    0x34
+#define APBC_TWSI2_CLK_RST      0x38
+#define APBC_AIB_CLK_RST        0x3c
+#define APBC_TWSI4_CLK_RST      0x40
+#define APBC_TIMERS2_CLK_RST    0x44
+#define APBC_ONEWIRE_CLK_RST    0x48
+#define APBC_TWSI5_CLK_RST      0x4c
+#define APBC_DRO_CLK_RST        0x58
+#define APBC_IR_CLK_RST         0x5c
+#define APBC_TWSI6_CLK_RST      0x60
+#define APBC_COUNTER_CLK_SEL    0x64
+
+#define APBC_TWSI7_CLK_RST      0x68
+#define APBC_TSEN_CLK_RST       0x6c
+
+#define APBC_UART4_CLK_RST      0x70
+#define APBC_UART5_CLK_RST      0x74
+#define APBC_UART6_CLK_RST      0x78
+#define APBC_SSP3_CLK_RST       0x7c
+
+#define APBC_SSPA0_CLK_RST      0x80
+#define APBC_SSPA1_CLK_RST      0x84
+
+#define APBC_IPC_AP2AUD_CLK_RST 0x90
+#define APBC_UART7_CLK_RST      0x94
+#define APBC_UART8_CLK_RST      0x98
+#define APBC_UART9_CLK_RST      0x9c
+
+#define APBC_CAN0_CLK_RST       0xa0
+#define APBC_PWM4_CLK_RST       0xa8
+#define APBC_PWM5_CLK_RST       0xac
+#define APBC_PWM6_CLK_RST       0xb0
+#define APBC_PWM7_CLK_RST       0xb4
+#define APBC_PWM8_CLK_RST       0xb8
+#define APBC_PWM9_CLK_RST       0xbc
+#define APBC_PWM10_CLK_RST      0xc0
+#define APBC_PWM11_CLK_RST      0xc4
+#define APBC_PWM12_CLK_RST      0xc8
+#define APBC_PWM13_CLK_RST      0xcc
+#define APBC_PWM14_CLK_RST      0xd0
+#define APBC_PWM15_CLK_RST      0xd4
+#define APBC_PWM16_CLK_RST      0xd8
+#define APBC_PWM17_CLK_RST      0xdc
+#define APBC_PWM18_CLK_RST      0xe0
+#define APBC_PWM19_CLK_RST      0xe4
+/* end of APBC register offset */
+
+/* MPMU register offset */
+#define MPMU_POSR                      0x10 //no define
+#define POSR_PLL1_LOCK                 BIT(27)
+#define POSR_PLL2_LOCK                 BIT(28)
+#define POSR_PLL3_LOCK                 BIT(29)
+
+#define MPMU_VRCR                      0x18 //no define
+#define MPMU_VRCR_REQ_EN0              BIT(0)
+#define MPMU_VRCR_REQ_EN2              BIT(2)
+#define MPMU_VRCR_REQ_POL2             BIT(6)
+#define MPMU_VRCR_VCXO_OUT_REQ_EN2     BIT(14)
+
+#define MPMU_WDTPCR     0x200
+#define MPMU_RIPCCR     0x210 //no define
+#define MPMU_ACGR       0x1024
+#define MPMU_SUCCR      0x14
+#define MPMU_ISCCR      0x44
+#define MPMU_SUCCR_1    0x10b0
+#define MPMU_APBCSCR    0x1050
+
+/* end of MPMU register offset */
+
+/* APMU register offset */
+#define APMU_JPG_CLK_RES_CTRL       0x20
+#define APMU_CSI_CCIC2_CLK_RES_CTRL 0x24
+#define APMU_ISP_CLK_RES_CTRL       0x38
+#define APMU_LCD_CLK_RES_CTRL1      0x44
+#define APMU_LCD_SPI_CLK_RES_CTRL   0x48
+#define APMU_LCD_CLK_RES_CTRL2      0x4c
+#define APMU_CCIC_CLK_RES_CTRL      0x50
+#define APMU_SDH0_CLK_RES_CTRL      0x54
+#define APMU_SDH1_CLK_RES_CTRL      0x58
+#define APMU_USB_CLK_RES_CTRL       0x5c
+#define APMU_QSPI_CLK_RES_CTRL      0x60
+#define APMU_USB_CLK_RES_CTRL       0x5c
+#define APMU_DMA_CLK_RES_CTRL       0x64
+#define APMU_AES_CLK_RES_CTRL       0x68
+#define APMU_VPU_CLK_RES_CTRL       0xa4
+#define APMU_GPU_CLK_RES_CTRL       0xcc
+#define APMU_SDH2_CLK_RES_CTRL      0xe0
+#define APMU_PMUA_MC_CTRL           0xe8
+#define APMU_PMU_CC2_AP             0x100
+#define APMU_PMUA_EM_CLK_RES_CTRL   0x104
+
+#define APMU_AUDIO_CLK_RES_CTRL     0x14c
+#define APMU_HDMI_CLK_RES_CTRL      0x1B8
+#define APMU_CCI550_CLK_CTRL        0x300
+#define APMU_ACLK_CLK_CTRL          0x388
+#define APMU_CPU_C0_CLK_CTRL        0x38C
+#define APMU_CPU_C1_CLK_CTRL        0x390
+
+#define APMU_PCIE_CLK_RES_CTRL_0    0x3cc
+#define APMU_PCIE_CLK_RES_CTRL_1    0x3d4
+#define APMU_PCIE_CLK_RES_CTRL_2    0x3dc
+
+#define APMU_EMAC0_CLK_RES_CTRL     0x3e4
+#define APMU_EMAC1_CLK_RES_CTRL     0x3ec
+/* end of APMU register offset */
+
+/* APBC2 register offset */
+#define APBC2_UART1_CLK_RST            0x00
+#define APBC2_SSP2_CLK_RST             0x04
+#define APBC2_TWSI3_CLK_RST            0x08
+#define APBC2_RTC_CLK_RST              0x0c
+#define APBC2_TIMERS0_CLK_RST          0x10
+#define APBC2_KPC_CLK_RST              0x14
+#define APBC2_GPIO_CLK_RST             0x1c
+/* end of APBC2 register offset */
+
+/* RCPU register offset */
+#define RCPU_HDMI_CLK_RST              0x2044
+#define RCPU_CAN_CLK_RST               0x4c
+/* end of RCPU register offset */
+
+struct spacemit_k1x_clk k1x_clock_controller;
+
+//apbs
+static const struct ccu_pll_rate_tbl pll2_rate_tbl[] = {
+       PLL_RATE(3000000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3f, 0xe00000),
+       PLL_RATE(3200000000UL, 0x67, 0xdd, 0x50, 0x00, 0x43, 0xeaaaab),
+       PLL_RATE(2457600000UL, 0x64, 0xdd, 0x50, 0x00, 0x33, 0x0ccccd),
+       PLL_RATE(2800000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3a, 0x155555),
+};
+
+static const struct ccu_pll_rate_tbl pll3_rate_tbl[] = {
+       PLL_RATE(3000000000UL, 0x66, 0xdd, 0x50, 0x00, 0x3f, 0xe00000),
+       PLL_RATE(3200000000UL, 0x67, 0xdd, 0x50, 0x00, 0x43, 0xeaaaab),
+       PLL_RATE(2457600000UL, 0x64, 0xdd, 0x50, 0x00, 0x33, 0x0ccccd),
+};
+
+static SPACEMIT_CCU_PLL(pll2, "pll2", &pll2_rate_tbl, ARRAY_SIZE(pll2_rate_tbl),
+       BASE_TYPE_APBS, APB_SPARE7_REG, APB_SPARE8_REG, APB_SPARE9_REG,
+       MPMU_POSR, POSR_PLL2_LOCK, 1,
+       CLK_IGNORE_UNUSED);
+
+static SPACEMIT_CCU_PLL(pll3, "pll3", &pll3_rate_tbl, ARRAY_SIZE(pll3_rate_tbl),
+       BASE_TYPE_APBS, APB_SPARE10_REG, APB_SPARE11_REG, APB_SPARE12_REG,
+       MPMU_POSR, POSR_PLL3_LOCK, 1,
+       CLK_IGNORE_UNUSED);
+
+//pll1
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d2, "pll1_d2", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(1), BIT(1), 0x0,
+       2, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d3, "pll1_d3", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(2), BIT(2), 0x0,
+       3, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d4, "pll1_d4", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(3), BIT(3), 0x0,
+       4, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d5, "pll1_d5", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(4), BIT(4), 0x0,
+       5, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d6, "pll1_d6", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(5), BIT(5), 0x0,
+       6, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d7, "pll1_d7", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(6), BIT(6), 0x0,
+       7, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d8, "pll1_d8", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(7), BIT(7), 0x0,
+       8, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d11_223p4, "pll1_d11_223p4", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(15), BIT(15), 0x0,
+       11, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d13_189, "pll1_d13_189", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(16), BIT(16), 0x0,
+       13, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d23_106p8, "pll1_d23_106p8", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(20), BIT(20), 0x0,
+       23, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d64_38p4, "pll1_d64_38p4", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(0), BIT(0), 0x0,
+       64, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_aud_245p7, "pll1_aud_245p7", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(10), BIT(10), 0x0,
+       10, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_aud_24p5, "pll1_aud_24p5", "pll1_2457p6_vco",
+       BASE_TYPE_APBS, APB_SPARE2_REG,
+       BIT(11), BIT(11), 0x0,
+       100, 1, CLK_IGNORE_UNUSED);
+
+//pll2
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d1, "pll2_d1", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(0), BIT(0), 0x0,
+       1, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d2, "pll2_d2", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(1), BIT(1), 0x0,
+       2, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d3, "pll2_d3", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(2), BIT(2), 0x0,
+       3, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d4, "pll2_d4", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(3), BIT(3), 0x0,
+       4, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d5, "pll2_d5", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(4), BIT(4), 0x0,
+       5, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d6, "pll2_d6", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(5), BIT(5), 0x0,
+       6, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d7, "pll2_d7", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(6), BIT(6), 0x0,
+       7, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll2_d8, "pll2_d8", "pll2",
+       BASE_TYPE_APBS, APB_SPARE8_REG,
+       BIT(7), BIT(7), 0x0,
+       8, 1, CLK_IGNORE_UNUSED);
+
+//pll3
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d1, "pll3_d1", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(0), BIT(0), 0x0,
+       1, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d2, "pll3_d2", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(1), BIT(1), 0x0,
+       2, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d3, "pll3_d3", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(2), BIT(2), 0x0,
+       3, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d4, "pll3_d4", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(3), BIT(3), 0x0,
+       4, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d5, "pll3_d5", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(4), BIT(4), 0x0,
+       5, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d6, "pll3_d6", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(5), BIT(5), 0x0,
+       6, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d7, "pll3_d7", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(6), BIT(6), 0x0,
+       7, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll3_d8, "pll3_d8", "pll3",
+       BASE_TYPE_APBS, APB_SPARE11_REG,
+       BIT(7), BIT(7), 0x0,
+       8, 1, CLK_IGNORE_UNUSED);
+
+//pll3_div
+static SPACEMIT_CCU_FACTOR(pll3_80, "pll3_80", "pll3_d8",
+       5, 1);
+static SPACEMIT_CCU_FACTOR(pll3_40, "pll3_40", "pll3_d8",
+       10, 1);
+static SPACEMIT_CCU_FACTOR(pll3_20, "pll3_20", "pll3_d8",
+       20, 1);
+
+//pll1_d8
+static SPACEMIT_CCU_GATE(pll1_d8_307p2, "pll1_d8_307p2", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(13), BIT(13), 0x0,
+       CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_FACTOR(pll1_d32_76p8, "pll1_d32_76p8", "pll1_d8_307p2",
+       4, 1);
+static SPACEMIT_CCU_FACTOR(pll1_d40_61p44, "pll1_d40_61p44", "pll1_d8_307p2",
+       5, 1);
+static SPACEMIT_CCU_FACTOR(pll1_d16_153p6, "pll1_d16_153p6", "pll1_d8",
+       2, 1);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d24_102p4, "pll1_d24_102p4", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(12), BIT(12), 0x0,
+       3, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d48_51p2, "pll1_d48_51p2", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(7), BIT(7), 0x0,
+       6, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d48_51p2_ap, "pll1_d48_51p2_ap", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(11), BIT(11), 0x0,
+       6, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_m3d128_57p6, "pll1_m3d128_57p6", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(8), BIT(8), 0x0,
+       16, 3, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d96_25p6, "pll1_d96_25p6", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(4), BIT(4), 0x0,
+       12, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d192_12p8, "pll1_d192_12p8", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(3), BIT(3), 0x0,
+       24, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d192_12p8_wdt, "pll1_d192_12p8_wdt", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(19), BIT(19), 0x0,
+       24, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d384_6p4, "pll1_d384_6p4", "pll1_d8",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(2), BIT(2), 0x0,
+       48, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_FACTOR(pll1_d768_3p2, "pll1_d768_3p2", "pll1_d384_6p4",
+       2, 1);
+static SPACEMIT_CCU_FACTOR(pll1_d1536_1p6, "pll1_d1536_1p6", "pll1_d384_6p4",
+       4, 1);
+static SPACEMIT_CCU_FACTOR(pll1_d3072_0p8, "pll1_d3072_0p8", "pll1_d384_6p4",
+       8, 1);
+//pll1_d7
+static SPACEMIT_CCU_FACTOR(pll1_d7_351p08, "pll1_d7_351p08", "pll1_d7",
+       1, 1);
+//pll1_d6
+static SPACEMIT_CCU_GATE(pll1_d6_409p6, "pll1_d6_409p6", "pll1_d6",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(0), BIT(0), 0x0,
+       CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d12_204p8, "pll1_d12_204p8", "pll1_d6",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(5), BIT(5), 0x0,
+       2, 1, CLK_IGNORE_UNUSED);
+//pll1_d5
+static SPACEMIT_CCU_GATE(pll1_d5_491p52, "pll1_d5_491p52", "pll1_d5",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(21), BIT(21), 0x0,
+       CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d10_245p76, "pll1_d10_245p76", "pll1_d5",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(18), BIT(18), 0x0,
+       2, 1, CLK_IGNORE_UNUSED);
+//pll1_d4
+static SPACEMIT_CCU_GATE(pll1_d4_614p4, "pll1_d4_614p4", "pll1_d4",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(15), BIT(15), 0x0,
+       CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d52_47p26, "pll1_d52_47p26", "pll1_d4",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(10), BIT(10), 0x0,
+       13, 1, CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_GATE_FACTOR(pll1_d78_31p5, "pll1_d78_31p5", "pll1_d4",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(6), BIT(6), 0x0,
+       39, 2, CLK_IGNORE_UNUSED);
+//pll1_d3
+static SPACEMIT_CCU_GATE(pll1_d3_819p2, "pll1_d3_819p2", "pll1_d3",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(14), BIT(14), 0x0,
+       CLK_IGNORE_UNUSED);
+//pll1_d2
+static SPACEMIT_CCU_GATE(pll1_d2_1228p8, "pll1_d2_1228p8", "pll1_d2",
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(16), BIT(16), 0x0,
+       CLK_IGNORE_UNUSED);
+
+//mpmu
+static struct ccu_ddn_info uart_ddn_mask_info = {
+       .factor = 2,
+       .num_mask = 0x1fff,
+       .den_mask = 0x1fff,
+       .num_shift = 16,
+       .den_shift = 0,
+};
+static struct ccu_ddn_tbl slow_uart1_tbl[] = {
+       {.num = 125, .den = 24}, /*rate = parent_rate*24/125/2) */
+};
+static struct ccu_ddn_tbl slow_uart2_tbl[] = {
+       {.num = 6144, .den = 960},/*rate = parent_rate*960/6144/2) */
+};
+
+static SPACEMIT_CCU_GATE_NO_PARENT(slow_uart, "slow_uart", NULL,
+       BASE_TYPE_MPMU, MPMU_ACGR,
+       BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_DDN(slow_uart1_14p74, "slow_uart1_14p74", "pll1_d16_153p6",
+       &uart_ddn_mask_info, &slow_uart1_tbl, ARRAY_SIZE(slow_uart1_tbl),
+       BASE_TYPE_MPMU, MPMU_SUCCR,
+       CLK_IGNORE_UNUSED);
+static SPACEMIT_CCU_DDN(slow_uart2_48, "slow_uart2_48", "pll1_d4_614p4",
+       &uart_ddn_mask_info, &slow_uart2_tbl, ARRAY_SIZE(slow_uart2_tbl),
+       BASE_TYPE_MPMU, MPMU_SUCCR_1,
+       CLK_IGNORE_UNUSED);
+
+//apbc
+static const char * const uart_parent_names[] = {
+       "pll1_m3d128_57p6", "slow_uart1_14p74", "slow_uart2_48"
+};
+static SPACEMIT_CCU_MUX_GATE(uart1_clk, "uart1_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart2_clk, "uart2_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART2_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart3_clk, "uart3_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART3_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart4_clk, "uart4_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART4_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart5_clk, "uart5_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART5_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart6_clk, "uart6_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART6_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart7_clk, "uart7_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART7_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart8_clk, "uart8_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART8_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(uart9_clk, "uart9_clk", uart_parent_names,
+       BASE_TYPE_APBC, APBC_UART9_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE(gpio_clk, "gpio_clk", "vctcxo_24",
+       BASE_TYPE_APBC, APBC_GPIO_CLK_RST,
+       0x3, 0x3, 0x0,
+       0);
+static const char *pwm_parent_names[] = {
+       "pll1_d192_12p8", "clk_32k"
+};
+static SPACEMIT_CCU_MUX_GATE(pwm0_clk, "pwm0_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM0_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm1_clk, "pwm1_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM1_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm2_clk, "pwm2_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM2_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm3_clk, "pwm3_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM3_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm4_clk, "pwm4_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM4_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm5_clk, "pwm5_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM5_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm6_clk, "pwm6_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM6_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm7_clk, "pwm7_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM7_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm8_clk, "pwm8_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM8_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm9_clk, "pwm9_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM9_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm10_clk, "pwm10_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM10_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm11_clk, "pwm11_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM11_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm12_clk, "pwm12_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM12_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm13_clk, "pwm13_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM13_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm14_clk, "pwm14_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM14_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm15_clk, "pwm15_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM15_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm16_clk, "pwm16_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM16_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm17_clk, "pwm17_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM17_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm18_clk, "pwm18_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM18_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(pwm19_clk, "pwm19_clk", pwm_parent_names,
+       BASE_TYPE_APBC, APBC_PWM19_CLK_RST,
+       4, 3, 0x2, 0x2, 0x0,
+       0);
+static const char *ssp_parent_names[] = { "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6",
+       "pll1_d48_51p2", "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8"
+};
+static SPACEMIT_CCU_MUX_GATE(ssp3_clk, "ssp3_clk", ssp_parent_names,
+       BASE_TYPE_APBC, APBC_SSP3_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE(rtc_clk, "rtc_clk", "clk_32k",
+       BASE_TYPE_APBC, APBC_RTC_CLK_RST,
+       0x83, 0x83, 0x0, 0);
+static const char *twsi_parent_names[] = {
+       "pll1_d78_31p5", "pll1_d48_51p2", "pll1_d40_61p44"
+};
+static SPACEMIT_CCU_MUX_GATE(twsi0_clk, "twsi0_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI0_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi1_clk, "twsi1_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi2_clk, "twsi2_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI2_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi4_clk, "twsi4_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI4_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi5_clk, "twsi5_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI5_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi6_clk, "twsi6_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI6_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi7_clk, "twsi7_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI7_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(twsi8_clk, "twsi8_clk", twsi_parent_names,
+       BASE_TYPE_APBC, APBC_TWSI8_CLK_RST,
+       4, 3, 0x7, 0x3, 0x4,
+       0);
+static const char *timer_parent_names[] = {
+       "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1"
+};
+static SPACEMIT_CCU_MUX_GATE(timers1_clk, "timers1_clk", timer_parent_names,
+       BASE_TYPE_APBC, APBC_TIMERS1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(timers2_clk, "timers2_clk", timer_parent_names,
+       BASE_TYPE_APBC, APBC_TIMERS2_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE(aib_clk, "aib_clk", "vctcxo_24",
+       BASE_TYPE_APBC, APBC_AIB_CLK_RST,
+       0x3, 0x3, 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(onewire_clk, "onewire_clk", NULL,
+       BASE_TYPE_APBC, APBC_ONEWIRE_CLK_RST,
+       0x3, 0x3, 0x0, 0);
+
+static SPACEMIT_CCU_GATE_FACTOR(i2s_sysclk, "i2s_sysclk", "pll1_d16_153p6",
+       BASE_TYPE_MPMU, MPMU_ISCCR,
+       BIT(31), BIT(31), 0x0,
+       50, 1, 0);
+static SPACEMIT_CCU_GATE_FACTOR(i2s_bclk, "i2s_bclk", "i2s_sysclk",
+       BASE_TYPE_MPMU, MPMU_ISCCR,
+       BIT(29), BIT(29), 0x0,
+       1, 1, 0);
+static const char *sspa_parent_names[] = { "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6",
+       "pll1_d48_51p2", "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8", "i2s_bclk"
+};
+static SPACEMIT_CCU_MUX_GATE(sspa0_clk, "sspa0_clk", sspa_parent_names,
+       BASE_TYPE_APBC, APBC_SSPA0_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_MUX_GATE(sspa1_clk, "sspa1_clk", sspa_parent_names,
+       BASE_TYPE_APBC, APBC_SSPA1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dro_clk, "dro_clk", NULL,
+       BASE_TYPE_APBC, APBC_DRO_CLK_RST,
+       0x1, 0x1, 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(ir_clk, "ir_clk", NULL,
+       BASE_TYPE_APBC, APBC_IR_CLK_RST,
+       0x1, 0x1, 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(tsen_clk, "tsen_clk", NULL,
+       BASE_TYPE_APBC, APBC_TSEN_CLK_RST,
+       0x3, 0x3, 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(ipc_ap2aud_clk, "ipc_ap2aud_clk", NULL,
+       BASE_TYPE_APBC, APBC_IPC_AP2AUD_CLK_RST,
+       0x3, 0x3, 0x0, 0);
+static const char *can_parent_names[] = {
+       "pll3_20", "pll3_40", "pll3_80"
+};
+static SPACEMIT_CCU_MUX_GATE(can0_clk, "can0_clk", can_parent_names,
+       BASE_TYPE_APBC, APBC_CAN0_CLK_RST,
+       4, 3, BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(can0_bus_clk, "can0_bus_clk", NULL,
+       BASE_TYPE_APBC, APBC_CAN0_CLK_RST,
+       BIT(0), BIT(0), 0x0, 0);
+
+//mpmu
+static SPACEMIT_CCU_GATE(wdt_clk, "wdt_clk", "pll1_d96_25p6",
+       BASE_TYPE_MPMU, MPMU_WDTPCR,
+       0x3, 0x3, 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(ripc_clk, "ripc_clk", NULL,
+       BASE_TYPE_MPMU, MPMU_RIPCCR,
+       0x3, 0x3, 0x0, 0);
+
+//apmu
+static const char * const jpg_parent_names[] = {
+        "pll1_d4_614p4", "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d3_819p2",
+        "pll1_d2_1228p8", "pll2_d4", "pll2_d3"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(jpg_clk, "jpg_clk", jpg_parent_names,
+       BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL,
+       5, 3, BIT(15),
+       2, 3, BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(jpg_4kafbc_clk, "jpg_4kafbc_clk", NULL,
+       BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL,
+       BIT(16), BIT(16), 0x0, 0);
+static SPACEMIT_CCU_GATE_NO_PARENT(jpg_2kafbc_clk, "jpg_2kafbc_clk", NULL,
+       BASE_TYPE_APMU, APMU_JPG_CLK_RES_CTRL,
+       BIT(17), BIT(17), 0x0, 0);
+static const char * const ccic2phy_parent_names[] = {
+       "pll1_d24_102p4", "pll1_d48_51p2_ap"
+};
+static SPACEMIT_CCU_MUX_GATE(ccic2phy_clk, "ccic2phy_clk", ccic2phy_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       7, 1, BIT(5), BIT(5), 0x0,
+       0);
+static const char * const ccic3phy_parent_names[] = {
+       "pll1_d24_102p4", "pll1_d48_51p2_ap"
+};
+static SPACEMIT_CCU_MUX_GATE(ccic3phy_clk, "ccic3phy_clk", ccic3phy_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       31, 1, BIT(30), BIT(30), 0x0, 0);
+static const char * const csi_parent_names[] = {
+        "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d3_819p2",
+        "pll2_d2", "pll2_d3", "pll2_d4", "pll1_d2_1228p8"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(csi_clk, "csi_clk", csi_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       20, 3, BIT(15),
+       16, 3, BIT(4), BIT(4), 0x0,
+       0);
+static const char * const camm_parent_names[] = {
+       "pll1_d8_307p2", "pll2_d5", "pll1_d6_409p6", "vctcxo_24"
+};
+static SPACEMIT_CCU_DIV_MUX_GATE(camm0_clk, "camm0_clk", camm_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       23, 4, 8, 2,
+       BIT(28), BIT(28), 0x0,
+       0);
+static SPACEMIT_CCU_DIV_MUX_GATE(camm1_clk, "camm1_clk", camm_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       23, 4, 8, 2,
+       BIT(6), BIT(6), 0x0,
+       0);
+static SPACEMIT_CCU_DIV_MUX_GATE(camm2_clk, "camm2_clk", camm_parent_names,
+       BASE_TYPE_APMU, APMU_CSI_CCIC2_CLK_RES_CTRL,
+       23, 4, 8, 2,
+       BIT(3), BIT(3), 0x0,
+       0);
+static const char * const isp_cpp_parent_names[] = {
+        "pll1_d8_307p2", "pll1_d6_409p6"
+};
+static SPACEMIT_CCU_DIV_MUX_GATE(isp_cpp_clk, "isp_cpp_clk", isp_cpp_parent_names,
+       BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL,
+       24, 2, 26, 1,
+       BIT(28), BIT(28), 0x0,
+       0);
+static const char * const isp_bus_parent_names[] = {
+        "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d8_307p2", "pll1_d10_245p76"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(isp_bus_clk, "isp_bus_clk", isp_bus_parent_names,
+       BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL,
+       18, 3, BIT(23),
+       21, 2, BIT(17), BIT(17), 0x0,
+       0);
+static const char * const isp_parent_names[] = {
+        "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(isp_clk, "isp_clk", isp_parent_names,
+       BASE_TYPE_APMU, APMU_ISP_CLK_RES_CTRL,
+       4, 3, BIT(7),
+       8, 2, BIT(1), BIT(1), 0x0,
+       0);
+static const char * const dpumclk_parent_names[] = {
+       "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2"
+};
+static SPACEMIT_CCU_DIV2_FC_MUX_GATE(dpu_mclk, "dpu_mclk", dpumclk_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, APMU_LCD_CLK_RES_CTRL2,
+       1, 4, BIT(29),
+       5, 3, BIT(0), BIT(0), 0x0,
+       0);
+static const char * const dpuesc_parent_names[] = {
+       "pll1_d48_51p2_ap", "pll1_d52_47p26", "pll1_d96_25p6", "pll1_d32_76p8"
+};
+static SPACEMIT_CCU_MUX_GATE(dpu_esc_clk, "dpu_esc_clk", dpuesc_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1,
+       0, 2, BIT(2), BIT(2), 0x0,
+       0);
+static const char * const dpubit_parent_names[] = { "pll1_d3_819p2", "pll2_d2", "pll2_d3",
+       "pll1_d2_1228p8", "pll2_d4", "pll2_d5", "pll2_d8", "pll2_d8" //6 should be 429M?
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(dpu_bit_clk, "dpu_bit_clk", dpubit_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1,
+       17, 3, BIT(31),
+       20, 3, BIT(16), BIT(16), 0x0,
+       0);
+static const char * const dpupx_parent_names[] = {
+       "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2", "pll2_d7", "pll2_d8"
+};
+static SPACEMIT_CCU_DIV2_FC_MUX_GATE(dpu_pxclk, "dpu_pxclk", dpupx_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1, APMU_LCD_CLK_RES_CTRL2,
+       17, 4, BIT(30),
+       21, 3, BIT(16), BIT(16), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dpu_hclk, "dpu_hclk", NULL,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1,
+       BIT(5), BIT(5), 0x0,
+       0);
+static const char * const dpu_spi_parent_names[] = {
+        "pll1_d8_307p2", "pll1_d6_409p6", "pll1_d10_245p76", "pll1_d11_223p4",
+        "pll1_d13_189", "pll1_d23_106p8", "pll2_d3", "pll2_d5"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(dpu_spi_clk, "dpu_spi_clk", dpu_spi_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL,
+       8, 3, BIT(7),
+       12, 3, BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_hbus_clk, "dpu_spi_hbus_clk", NULL,
+       BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL,
+       BIT(3), BIT(3), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_bus_clk, "dpu_spi_bus_clk", NULL,
+       BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL,
+       BIT(5), BIT(5), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dpu_spi_aclk, "dpu_spi_aclk", NULL,
+       BASE_TYPE_APMU, APMU_LCD_SPI_CLK_RES_CTRL,
+       BIT(6), BIT(6), 0x0,
+       0);
+static const char * const v2d_parent_names[] = {
+       "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d8_307p2", "pll1_d4_614p4",
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(v2d_clk, "v2d_clk", v2d_parent_names,
+       BASE_TYPE_APMU, APMU_LCD_CLK_RES_CTRL1,
+       9, 3, BIT(28),
+       12, 2, BIT(8), BIT(8), 0x0,
+       0);
+static const char * const ccic_4x_parent_names[] = {
+        "pll1_d5_491p52", "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d3_819p2",
+        "pll2_d2", "pll2_d3", "pll2_d4", "pll1_d2_1228p8"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(ccic_4x_clk, "ccic_4x_clk", ccic_4x_parent_names,
+       BASE_TYPE_APMU, APMU_CCIC_CLK_RES_CTRL,
+       18, 3, BIT(15),
+       23, 2, BIT(4), BIT(4), 0x0,
+       0);
+static const char * const ccic1phy_parent_names[] = {
+       "pll1_d24_102p4", "pll1_d48_51p2_ap"
+};
+static SPACEMIT_CCU_MUX_GATE(ccic1phy_clk, "ccic1phy_clk", ccic1phy_parent_names,
+       BASE_TYPE_APMU, APMU_CCIC_CLK_RES_CTRL,
+       7, 1, BIT(5), BIT(5), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(sdh_axi_aclk, "sdh_axi_aclk", NULL,
+       BASE_TYPE_APMU, APMU_SDH0_CLK_RES_CTRL,
+       BIT(3), BIT(3), 0x0,
+       0);
+static const char * const sdh01_parent_names[] = {"pll1_d6_409p6",
+       "pll1_d4_614p4", "pll2_d8", "pll2_d5", "pll1_d11_223p4", "pll1_d13_189", "pll1_d23_106p8" };
+
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh0_clk, "sdh0_clk", sdh01_parent_names,
+       BASE_TYPE_APMU, APMU_SDH0_CLK_RES_CTRL,
+       8, 3, BIT(11),
+       5, 3, BIT(4), BIT(4), 0x0,
+       0);
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh1_clk, "sdh1_clk", sdh01_parent_names,
+       BASE_TYPE_APMU, APMU_SDH1_CLK_RES_CTRL,
+       8, 3, BIT(11),
+       5, 3, BIT(4), BIT(4), 0x0,
+       0);
+static const char * const sdh2_parent_names[] = {"pll1_d6_409p6",
+       "pll1_d4_614p4", "pll2_d8", "pll1_d3_819p2", "pll1_d11_223p4", "pll1_d13_189", "pll1_d23_106p8" };
+
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(sdh2_clk, "sdh2_clk", sdh2_parent_names,
+       BASE_TYPE_APMU, APMU_SDH2_CLK_RES_CTRL,
+       8, 3, BIT(11),
+       5, 3, BIT(4), BIT(4), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(usb_axi_clk, "usb_axi_clk", NULL,
+       BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL,
+       BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(usb_p1_aclk, "usb_p1_aclk", NULL,
+       BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL,
+       BIT(5), BIT(5), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(usb30_clk, "usb30_clk", NULL,
+       BASE_TYPE_APMU, APMU_USB_CLK_RES_CTRL,
+       BIT(8), BIT(8), 0x0,
+       0);
+static const char * const qspi_parent_names[] = {"pll1_d6_409p6", "pll2_d8", "pll1_d8_307p2",
+               "pll1_d10_245p76", "pll1_d11_223p4", "pll1_d23_106p8", "pll1_d5_491p52", "pll1_d13_189"};
+static SPACEMIT_CCU_DIV_MFC_MUX_GATE(qspi_clk, "qspi_clk", qspi_parent_names,
+       BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL,
+       9, 3, BIT(12),
+       6, 3, BIT(4), BIT(4), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(qspi_bus_clk, "qspi_bus_clk", NULL,
+       BASE_TYPE_APMU, APMU_QSPI_CLK_RES_CTRL,
+       BIT(3), BIT(3), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(dma_clk, "dma_clk", NULL,
+       BASE_TYPE_APMU, APMU_DMA_CLK_RES_CTRL,
+       BIT(3), BIT(3), 0x0,
+       0);
+static const char * const aes_parent_names[] = {
+       "pll1_d12_204p8", "pll1_d24_102p4"
+};
+static SPACEMIT_CCU_MUX_GATE(aes_clk, "aes_clk", aes_parent_names,
+       BASE_TYPE_APMU, APMU_AES_CLK_RES_CTRL,
+       6, 1, BIT(5), BIT(5), 0x0,
+       0);
+static const char * const vpu_parent_names[] = {
+       "pll1_d4_614p4", "pll1_d5_491p52", "pll1_d3_819p2", "pll1_d6_409p6",
+       "pll3_d6", "pll2_d3", "pll2_d4", "pll2_d5"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(vpu_clk, "vpu_clk", vpu_parent_names,
+       BASE_TYPE_APMU, APMU_VPU_CLK_RES_CTRL,
+       13, 3, BIT(21),
+       10, 3,
+       BIT(3), BIT(3), 0x0,
+       0);
+static const char * const gpu_parent_names[] = {
+       "pll1_d4_614p4", "pll1_d5_491p52", "pll1_d3_819p2", "pll1_d6_409p6",
+       "pll3_d6", "pll2_d3", "pll2_d4", "pll2_d5"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(gpu_clk, "gpu_clk", gpu_parent_names,
+       BASE_TYPE_APMU, APMU_GPU_CLK_RES_CTRL,
+       12, 3, BIT(15),
+       18, 3,
+       BIT(4), BIT(4), 0x0,
+       0);
+static const char * const emmc_parent_names[] = {
+       "pll1_d6_409p6", "pll1_d4_614p4", "pll1_d52_47p26", "pll1_d3_819p2"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(emmc_clk, "emmc_clk", emmc_parent_names,
+       BASE_TYPE_APMU, APMU_PMUA_EM_CLK_RES_CTRL,
+       8, 3, BIT(11),
+       6, 2,
+       0x18, 0x18, 0x0,
+       0);
+static SPACEMIT_CCU_DIV_GATE(emmc_x_clk, "emmc_x_clk", "pll1_d2_1228p8",
+       BASE_TYPE_APMU, APMU_PMUA_EM_CLK_RES_CTRL,
+       12, 3, BIT(15), BIT(15), 0x0,
+       0);
+static const char * const audio_parent_names[] = {
+        "pll1_aud_245p7", "pll1_d8_307p2", "pll1_d6_409p6"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(audio_clk, "audio_clk", audio_parent_names,
+       BASE_TYPE_APMU, APMU_AUDIO_CLK_RES_CTRL,
+       4, 3, BIT(15),
+       7, 3,
+       BIT(12), BIT(12), 0x0,
+       0);
+static const char * const hdmi_parent_names[] = {
+        "pll1_d6_409p6", "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d8_307p2"
+};
+static SPACEMIT_CCU_DIV_FC_MUX_GATE(hdmi_mclk, "hdmi_mclk", hdmi_parent_names,
+       BASE_TYPE_APMU, APMU_HDMI_CLK_RES_CTRL,
+       1, 4, BIT(29),
+       5, 3,
+       BIT(0), BIT(0), 0x0,
+       0);
+static const char * const cci550_parent_names[] = {
+        "pll1_d5_491p52", "pll1_d4_614p4", "pll1_d3_819p2", "pll2_d3"
+};
+static SPACEMIT_CCU_DIV_FC_MUX(cci550_clk, "cci550_clk", cci550_parent_names,
+       BASE_TYPE_APMU, APMU_CCI550_CLK_CTRL,
+       8, 3, BIT(12),
+       0, 2,
+       0);
+static const char * const pmua_aclk_parent_names[] = {
+        "pll1_d10_245p76", "pll1_d8_307p2"
+};
+static SPACEMIT_CCU_DIV_FC_MUX(pmua_aclk, "pmua_aclk", pmua_aclk_parent_names,
+       BASE_TYPE_APMU, APMU_ACLK_CLK_CTRL,
+       1, 2, BIT(4),
+       0, 1,
+       0);
+static const char * const cpu_c0_hi_parent_names[] = {
+        "pll3_d2", "pll3_d1"
+};
+static SPACEMIT_CCU_MUX(cpu_c0_hi_clk, "cpu_c0_hi_clk", cpu_c0_hi_parent_names,
+       BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL,
+       13, 1,
+       0);
+static const char * const cpu_c0_parent_names[] = { "pll1_d4_614p4", "pll1_d3_819p2", "pll1_d6_409p6",
+       "pll1_d5_491p52", "pll1_d2_1228p8", "pll3_d3", "pll2_d3", "cpu_c0_hi_clk"
+};
+static SPACEMIT_CCU_MUX_FC(cpu_c0_core_clk, "cpu_c0_core_clk", cpu_c0_parent_names,
+       BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL,
+       BIT(12),
+       0, 3,
+       0);
+static SPACEMIT_CCU_DIV(cpu_c0_ace_clk, "cpu_c0_ace_clk", "cpu_c0_core_clk",
+       BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL,
+       6, 3,
+       0);
+static SPACEMIT_CCU_DIV(cpu_c0_tcm_clk, "cpu_c0_tcm_clk", "cpu_c0_core_clk",
+       BASE_TYPE_APMU, APMU_CPU_C0_CLK_CTRL,
+       9, 3,
+       0);
+static const char * const cpu_c1_hi_parent_names[] = {
+        "pll3_d2", "pll3_d1"
+};
+static SPACEMIT_CCU_MUX(cpu_c1_hi_clk, "cpu_c1_hi_clk", cpu_c1_hi_parent_names,
+       BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL,
+       13, 1,
+       0);
+static const char * const cpu_c1_parent_names[] = { "pll1_d4_614p4", "pll1_d3_819p2", "pll1_d6_409p6",
+       "pll1_d5_491p52", "pll1_d2_1228p8", "pll3_d3", "pll2_d3", "cpu_c1_hi_clk"
+};
+static SPACEMIT_CCU_MUX_FC(cpu_c1_pclk, "cpu_c1_pclk", cpu_c1_parent_names,
+       BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL,
+       BIT(12),
+       0, 3,
+       0);
+static SPACEMIT_CCU_DIV(cpu_c1_ace_clk, "cpu_c1_ace_clk", "cpu_c1_pclk",
+       BASE_TYPE_APMU, APMU_CPU_C1_CLK_CTRL,
+       6, 3,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(pcie0_clk, "pcie0_clk", NULL,
+       BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_0,
+       0x7, 0x7, 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(pcie1_clk, "pcie1_clk", NULL,
+       BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_1,
+       0x7, 0x7, 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(pcie2_clk, "pcie2_clk", NULL,
+       BASE_TYPE_APMU, APMU_PCIE_CLK_RES_CTRL_2,
+       0x7, 0x7, 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(emac0_bus_clk, "emac0_bus_clk", NULL,
+       BASE_TYPE_APMU, APMU_EMAC0_CLK_RES_CTRL,
+       BIT(0), BIT(0), 0x0,
+       0);
+static SPACEMIT_CCU_GATE(emac0_ptp_clk, "emac0_ptp_clk", "pll2_d6",
+       BASE_TYPE_APMU, APMU_EMAC0_CLK_RES_CTRL,
+       BIT(15), BIT(15), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(emac1_bus_clk, "emac1_bus_clk", NULL,
+       BASE_TYPE_APMU, APMU_EMAC1_CLK_RES_CTRL,
+       BIT(0), BIT(0), 0x0,
+       0);
+static SPACEMIT_CCU_GATE(emac1_ptp_clk, "emac1_ptp_clk", "pll2_d6",
+       BASE_TYPE_APMU, APMU_EMAC1_CLK_RES_CTRL,
+       BIT(15), BIT(15), 0x0,
+       0);
+
+//apbc2
+static const char * const uart1_sec_parent_names[] = {
+       "pll1_m3d128_57p6", "slow_uart1_14p74", "slow_uart2_48"
+};
+static SPACEMIT_CCU_MUX_GATE(uart1_sec_clk, "uart1_sec_clk", uart1_sec_parent_names,
+       BASE_TYPE_APBC2, APBC2_UART1_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+
+static const char *ssp2_sec_parent_names[] = { "pll1_d384_6p4", "pll1_d192_12p8", "pll1_d96_25p6",
+       "pll1_d48_51p2", "pll1_d768_3p2", "pll1_d1536_1p6", "pll1_d3072_0p8"
+};
+static SPACEMIT_CCU_MUX_GATE(ssp2_sec_clk, "ssp2_sec_clk", ssp2_sec_parent_names,
+       BASE_TYPE_APBC2, APBC2_SSP2_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static const char *twsi3_sec_parent_names[] = {
+       "pll1_d78_31p5", "pll1_d48_51p2", "pll1_d40_61p44"
+};
+static SPACEMIT_CCU_MUX_GATE(twsi3_sec_clk, "twsi3_sec_clk", twsi3_sec_parent_names,
+       BASE_TYPE_APBC2, APBC2_TWSI3_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE(rtc_sec_clk, "rtc_sec_clk", "clk_32k",
+       BASE_TYPE_APBC2, APBC2_RTC_CLK_RST,
+       0x83, 0x83, 0x0, 0);
+static const char *timer_sec_parent_names[] = {
+       "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1"
+};
+static SPACEMIT_CCU_MUX_GATE(timers0_sec_clk, "timers0_sec_clk", timer_sec_parent_names,
+       BASE_TYPE_APBC2, APBC2_TIMERS0_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static const char *kpc_sec_parent_names[] = {
+       "pll1_d192_12p8", "clk_32k", "pll1_d384_6p4", "vctcxo_3", "vctcxo_1"
+};
+static SPACEMIT_CCU_MUX_GATE(kpc_sec_clk, "kpc_sec_clk", kpc_sec_parent_names,
+       BASE_TYPE_APBC2, APBC2_KPC_CLK_RST,
+       4, 3, 0x3, 0x3, 0x0,
+       0);
+static SPACEMIT_CCU_GATE(gpio_sec_clk, "gpio_sec_clk", "vctcxo_24",
+       BASE_TYPE_APBC2, APBC2_GPIO_CLK_RST,
+       0x3, 0x3, 0x0,
+       0);
+
+static const char * const apb_parent_names[] = {
+       "pll1_d96_25p6", "pll1_d48_51p2", "pll1_d96_25p6", "pll1_d24_102p4"
+};
+static SPACEMIT_CCU_MUX(apb_clk, "apb_clk", apb_parent_names,
+       BASE_TYPE_MPMU, MPMU_APBCSCR,
+       0, 2, 0);
+//rcpu
+static const char *rhdmi_audio_parent_names[] = {
+       "pll1_aud_24p5", "pll1_aud_245p7"
+};
+static SPACEMIT_CCU_DIV_MUX_GATE(rhdmi_audio_clk, "rhdmi_audio_clk", rhdmi_audio_parent_names,
+       BASE_TYPE_RCPU, RCPU_HDMI_CLK_RST,
+       4, 11, 16, 2,
+       0x6, 0x6, 0x0,
+       0);
+
+static const char *rcan_parent_names[] = {
+       "pll3_20", "pll3_40", "pll3_80"
+};
+static SPACEMIT_CCU_DIV_MUX_GATE(rcan_clk, "rcan_clk", rcan_parent_names,
+       BASE_TYPE_RCPU, RCPU_CAN_CLK_RST,
+       8, 11, 4, 2,
+       BIT(1), BIT(1), 0x0,
+       0);
+static SPACEMIT_CCU_GATE_NO_PARENT(rcan_bus_clk, "rcan_bus_clk", NULL,
+       BASE_TYPE_RCPU, RCPU_CAN_CLK_RST,
+       BIT(2), BIT(2), 0x0, 0);
+
+static struct clk_hw_onecell_data spacemit_k1x_hw_clks = {
+       .hws    = {
+               [CLK_PLL2]              = &pll2.common.hw,
+               [CLK_PLL3]              = &pll3.common.hw,
+               [CLK_PLL1_D2]           = &pll1_d2.common.hw,
+               [CLK_PLL1_D3]           = &pll1_d3.common.hw,
+               [CLK_PLL1_D4]           = &pll1_d4.common.hw,
+               [CLK_PLL1_D5]           = &pll1_d5.common.hw,
+               [CLK_PLL1_D6]           = &pll1_d6.common.hw,
+               [CLK_PLL1_D7]           = &pll1_d7.common.hw,
+               [CLK_PLL1_D8]           = &pll1_d8.common.hw,
+               [CLK_PLL1_D11]          = &pll1_d11_223p4.common.hw,
+               [CLK_PLL1_D13]          = &pll1_d13_189.common.hw,
+               [CLK_PLL1_D23]          = &pll1_d23_106p8.common.hw,
+               [CLK_PLL1_D64]          = &pll1_d64_38p4.common.hw,
+               [CLK_PLL1_D10_AUD]      = &pll1_aud_245p7.common.hw,
+               [CLK_PLL1_D100_AUD]     = &pll1_aud_24p5.common.hw,
+               [CLK_PLL2_D1]           = &pll2_d1.common.hw,
+               [CLK_PLL2_D2]           = &pll2_d2.common.hw,
+               [CLK_PLL2_D3]           = &pll2_d3.common.hw,
+               [CLK_PLL2_D4]           = &pll2_d4.common.hw,
+               [CLK_PLL2_D5]           = &pll2_d5.common.hw,
+               [CLK_PLL2_D6]           = &pll2_d6.common.hw,
+               [CLK_PLL2_D7]           = &pll2_d7.common.hw,
+               [CLK_PLL2_D8]           = &pll2_d8.common.hw,
+               [CLK_PLL3_D1]           = &pll3_d1.common.hw,
+               [CLK_PLL3_D2]           = &pll3_d2.common.hw,
+               [CLK_PLL3_D3]           = &pll3_d3.common.hw,
+               [CLK_PLL3_D4]           = &pll3_d4.common.hw,
+               [CLK_PLL3_D5]           = &pll3_d5.common.hw,
+               [CLK_PLL3_D6]           = &pll3_d6.common.hw,
+               [CLK_PLL3_D7]           = &pll3_d7.common.hw,
+               [CLK_PLL3_D8]           = &pll3_d8.common.hw,
+               [CLK_PLL3_80]           = &pll3_80.common.hw,
+               [CLK_PLL3_40]           = &pll3_40.common.hw,
+               [CLK_PLL3_20]           = &pll3_20.common.hw,
+               [CLK_PLL1_307P2]        = &pll1_d8_307p2.common.hw,
+               [CLK_PLL1_76P8]         = &pll1_d32_76p8.common.hw,
+               [CLK_PLL1_61P44]        = &pll1_d40_61p44.common.hw,
+               [CLK_PLL1_153P6]        = &pll1_d16_153p6.common.hw,
+               [CLK_PLL1_102P4]        = &pll1_d24_102p4.common.hw,
+               [CLK_PLL1_51P2]         = &pll1_d48_51p2.common.hw,
+               [CLK_PLL1_51P2_AP]      = &pll1_d48_51p2_ap.common.hw,
+               [CLK_PLL1_57P6]         = &pll1_m3d128_57p6.common.hw,
+               [CLK_PLL1_25P6]         = &pll1_d96_25p6.common.hw,
+               [CLK_PLL1_12P8]         = &pll1_d192_12p8.common.hw,
+               [CLK_PLL1_12P8_WDT]     = &pll1_d192_12p8_wdt.common.hw,
+               [CLK_PLL1_6P4]          = &pll1_d384_6p4.common.hw,
+               [CLK_PLL1_3P2]          = &pll1_d768_3p2.common.hw,
+               [CLK_PLL1_1P6]          = &pll1_d1536_1p6.common.hw,
+               [CLK_PLL1_0P8]          = &pll1_d3072_0p8.common.hw,
+               [CLK_PLL1_351]          = &pll1_d7_351p08.common.hw,
+               [CLK_PLL1_409P6]        = &pll1_d6_409p6.common.hw,
+               [CLK_PLL1_204P8]        = &pll1_d12_204p8.common.hw,
+               [CLK_PLL1_491]          = &pll1_d5_491p52.common.hw,
+               [CLK_PLL1_245P76]       = &pll1_d10_245p76.common.hw,
+               [CLK_PLL1_614]          = &pll1_d4_614p4.common.hw,
+               [CLK_PLL1_47P26]        = &pll1_d52_47p26.common.hw,
+               [CLK_PLL1_31P5]         = &pll1_d78_31p5.common.hw,
+               [CLK_PLL1_819]          = &pll1_d3_819p2.common.hw,
+               [CLK_PLL1_1228]         = &pll1_d2_1228p8.common.hw,
+               [CLK_SLOW_UART1]        = &slow_uart1_14p74.common.hw,
+               [CLK_SLOW_UART2]        = &slow_uart2_48.common.hw,
+               [CLK_UART1]             = &uart1_clk.common.hw,
+               [CLK_UART2]             = &uart2_clk.common.hw,
+               [CLK_UART3]             = &uart3_clk.common.hw,
+               [CLK_UART4]             = &uart4_clk.common.hw,
+               [CLK_UART5]             = &uart5_clk.common.hw,
+               [CLK_UART6]             = &uart6_clk.common.hw,
+               [CLK_UART7]             = &uart7_clk.common.hw,
+               [CLK_UART8]             = &uart8_clk.common.hw,
+               [CLK_UART9]             = &uart9_clk.common.hw,
+               [CLK_GPIO]              = &gpio_clk.common.hw,
+               [CLK_PWM0]              = &pwm0_clk.common.hw,
+               [CLK_PWM1]              = &pwm1_clk.common.hw,
+               [CLK_PWM2]              = &pwm2_clk.common.hw,
+               [CLK_PWM3]              = &pwm3_clk.common.hw,
+               [CLK_PWM4]              = &pwm4_clk.common.hw,
+               [CLK_PWM5]              = &pwm5_clk.common.hw,
+               [CLK_PWM6]              = &pwm6_clk.common.hw,
+               [CLK_PWM7]              = &pwm7_clk.common.hw,
+               [CLK_PWM8]              = &pwm8_clk.common.hw,
+               [CLK_PWM9]              = &pwm9_clk.common.hw,
+               [CLK_PWM10]             = &pwm10_clk.common.hw,
+               [CLK_PWM11]             = &pwm11_clk.common.hw,
+               [CLK_PWM12]             = &pwm12_clk.common.hw,
+               [CLK_PWM13]             = &pwm13_clk.common.hw,
+               [CLK_PWM14]             = &pwm14_clk.common.hw,
+               [CLK_PWM15]             = &pwm15_clk.common.hw,
+               [CLK_PWM16]             = &pwm16_clk.common.hw,
+               [CLK_PWM17]             = &pwm17_clk.common.hw,
+               [CLK_PWM18]             = &pwm18_clk.common.hw,
+               [CLK_PWM19]             = &pwm19_clk.common.hw,
+               [CLK_SSP3]              = &ssp3_clk.common.hw,
+               [CLK_RTC]               = &rtc_clk.common.hw,
+               [CLK_TWSI0]             = &twsi0_clk.common.hw,
+               [CLK_TWSI1]             = &twsi1_clk.common.hw,
+               [CLK_TWSI2]             = &twsi2_clk.common.hw,
+               [CLK_TWSI4]             = &twsi4_clk.common.hw,
+               [CLK_TWSI5]             = &twsi5_clk.common.hw,
+               [CLK_TWSI6]             = &twsi6_clk.common.hw,
+               [CLK_TWSI7]             = &twsi7_clk.common.hw,
+               [CLK_TWSI8]             = &twsi8_clk.common.hw,
+               [CLK_TIMERS1]           = &timers1_clk.common.hw,
+               [CLK_TIMERS2]           = &timers2_clk.common.hw,
+               [CLK_AIB]               = &aib_clk.common.hw,
+               [CLK_ONEWIRE]           = &onewire_clk.common.hw,
+               [CLK_SSPA0]             = &sspa0_clk.common.hw,
+               [CLK_SSPA1]             = &sspa1_clk.common.hw,
+               [CLK_DRO]               = &dro_clk.common.hw,
+               [CLK_IR]                = &ir_clk.common.hw,
+               [CLK_TSEN]              = &tsen_clk.common.hw,
+               [CLK_IPC_AP2AUD]        = &ipc_ap2aud_clk.common.hw,
+               [CLK_CAN0]              = &can0_clk.common.hw,
+               [CLK_CAN0_BUS]          = &can0_bus_clk.common.hw,
+               [CLK_WDT]               = &wdt_clk.common.hw,
+               [CLK_RIPC]              = &ripc_clk.common.hw,
+               [CLK_JPG]               = &jpg_clk.common.hw,
+               [CLK_JPF_4KAFBC]        = &jpg_4kafbc_clk.common.hw,
+               [CLK_JPF_2KAFBC]        = &jpg_2kafbc_clk.common.hw,
+               [CLK_CCIC2PHY]          = &ccic2phy_clk.common.hw,
+               [CLK_CCIC3PHY]          = &ccic3phy_clk.common.hw,
+               [CLK_CSI]               = &csi_clk.common.hw,
+               [CLK_CAMM0]             = &camm0_clk.common.hw,
+               [CLK_CAMM1]             = &camm1_clk.common.hw,
+               [CLK_CAMM2]             = &camm2_clk.common.hw,
+               [CLK_ISP_CPP]           = &isp_cpp_clk.common.hw,
+               [CLK_ISP_BUS]           = &isp_bus_clk.common.hw,
+               [CLK_ISP]               = &isp_clk.common.hw,
+               [CLK_DPU_MCLK]          = &dpu_mclk.common.hw,
+               [CLK_DPU_ESC]           = &dpu_esc_clk.common.hw,
+               [CLK_DPU_BIT]           = &dpu_bit_clk.common.hw,
+               [CLK_DPU_PXCLK]         = &dpu_pxclk.common.hw,
+               [CLK_DPU_HCLK]          = &dpu_hclk.common.hw,
+               [CLK_DPU_SPI]           = &dpu_spi_clk.common.hw,
+               [CLK_DPU_SPI_HBUS]      = &dpu_spi_hbus_clk.common.hw,
+               [CLK_DPU_SPIBUS]        = &dpu_spi_bus_clk.common.hw,
+               [CLK_SPU_SPI_ACLK]      = &dpu_spi_aclk.common.hw,
+               [CLK_V2D]               = &v2d_clk.common.hw,
+               [CLK_CCIC_4X]           = &ccic_4x_clk.common.hw,
+               [CLK_CCIC1PHY]          = &ccic1phy_clk.common.hw,
+               [CLK_SDH_AXI]           = &sdh_axi_aclk.common.hw,
+               [CLK_SDH0]              = &sdh0_clk.common.hw,
+               [CLK_SDH1]              = &sdh1_clk.common.hw,
+               [CLK_SDH2]              = &sdh2_clk.common.hw,
+               [CLK_USB_P1]            = &usb_p1_aclk.common.hw,
+               [CLK_USB_AXI]           = &usb_axi_clk.common.hw,
+               [CLK_USB30]             = &usb30_clk.common.hw,
+               [CLK_QSPI]              = &qspi_clk.common.hw,
+               [CLK_QSPI_BUS]          = &qspi_bus_clk.common.hw,
+               [CLK_DMA]               = &dma_clk.common.hw,
+               [CLK_AES]               = &aes_clk.common.hw,
+               [CLK_VPU]               = &vpu_clk.common.hw,
+               [CLK_GPU]               = &gpu_clk.common.hw,
+               [CLK_EMMC]              = &emmc_clk.common.hw,
+               [CLK_EMMC_X]            = &emmc_x_clk.common.hw,
+               [CLK_AUDIO]             = &audio_clk.common.hw,
+               [CLK_HDMI]              = &hdmi_mclk.common.hw,
+               [CLK_CCI550]            = &cci550_clk.common.hw,
+               [CLK_PMUA_ACLK]         = &pmua_aclk.common.hw,
+               [CLK_CPU_C0_HI]         = &cpu_c0_hi_clk.common.hw,
+               [CLK_CPU_C0_CORE]       = &cpu_c0_core_clk.common.hw,
+               [CLK_CPU_C0_ACE]        = &cpu_c0_ace_clk.common.hw,
+               [CLK_CPU_C0_TCM]        = &cpu_c0_tcm_clk.common.hw,
+               [CLK_CPU_C1_HI]         = &cpu_c1_hi_clk.common.hw,
+               [CLK_CPU_C1_CORE]       = &cpu_c1_pclk.common.hw,
+               [CLK_CPU_C1_ACE]        = &cpu_c1_ace_clk.common.hw,
+               [CLK_PCIE0]             = &pcie0_clk.common.hw,
+               [CLK_PCIE1]             = &pcie1_clk.common.hw,
+               [CLK_PCIE2]             = &pcie2_clk.common.hw,
+               [CLK_EMAC0_BUS]         = &emac0_bus_clk.common.hw,
+               [CLK_EMAC0_PTP]         = &emac0_ptp_clk.common.hw,
+               [CLK_EMAC1_BUS]         = &emac1_bus_clk.common.hw,
+               [CLK_EMAC1_PTP]         = &emac1_ptp_clk.common.hw,
+               [CLK_SEC_UART1]         = &uart1_sec_clk.common.hw,
+               [CLK_SEC_SSP2]          = &ssp2_sec_clk.common.hw,
+               [CLK_SEC_TWSI3]         = &twsi3_sec_clk.common.hw,
+               [CLK_SEC_RTC]           = &rtc_sec_clk.common.hw,
+               [CLK_SEC_TIMERS0]       = &timers0_sec_clk.common.hw,
+               [CLK_SEC_KPC]           = &kpc_sec_clk.common.hw,
+               [CLK_SEC_GPIO]          = &gpio_sec_clk.common.hw,
+               [CLK_APB]               = &apb_clk.common.hw,
+               [CLK_SLOW_UART]         = &slow_uart.common.hw,
+               [CLK_I2S_SYSCLK]        = &i2s_sysclk.common.hw,
+               [CLK_I2S_BCLK]          = &i2s_bclk.common.hw,
+               [CLK_RCPU_HDMIAUDIO]    = &rhdmi_audio_clk.common.hw,
+               [CLK_RCPU_CAN]          = &rcan_clk.common.hw,
+               [CLK_RCPU_CAN_BUS]      = &rcan_bus_clk.common.hw,
+       },
+       .num = CLK_MAX_NO,
+};
+
+static struct clk_hw_table bootup_enable_clk_table[] = {
+       {"pll1_d8_307p2",       CLK_PLL1_307P2},
+       {"pll1_d6_409p6",       CLK_PLL1_409P6},
+       {"pll1_d5_491p52",      CLK_PLL1_491},
+       {"pll1_d4_614p4",       CLK_PLL1_614},
+       {"pll1_d3_819p2",       CLK_PLL1_819},
+       {"pll1_d2_1228p8",      CLK_PLL1_1228},
+       {"pll1_d10_245p76",     CLK_PLL1_245P76},
+       {"pll1_d48_51p2",       CLK_PLL1_51P2},
+       {"pll1_d48_51p2_ap",    CLK_PLL1_51P2_AP},
+       {"pll1_d96_25p6",       CLK_PLL1_25P6},
+       {"pll3_d1",     CLK_PLL3_D1},
+       {"pll3_d2",     CLK_PLL3_D2},
+       {"pll3_d3",     CLK_PLL3_D3},
+       {"pll2_d3",     CLK_PLL2_D3},
+       {"apb_clk",     CLK_APB},
+       {"pmua_aclk",   CLK_PMUA_ACLK},
+};
+
+void spacemit_clocks_enable(struct clk_hw_table *tbl, int tbl_size)
+{
+       int i;
+       struct clk *clk;
+
+       for (i = 0; i < tbl_size; i++) {
+               clk = clk_hw_get_clk(spacemit_k1x_hw_clks.hws[tbl[i].clk_hw_id], tbl[i].name);
+               if (!IS_ERR_OR_NULL(clk))
+                       clk_prepare_enable(clk);
+               else
+                       pr_err("%s : can't find clk %s\n", __func__, tbl[i].name);
+       }
+}
+
+int ccu_common_init(struct clk_hw * hw, struct spacemit_k1x_clk *clk_info)
+{
+       struct ccu_common *common = hw_to_ccu_common(hw);
+       struct ccu_pll *pll = hw_to_ccu_pll(hw);
+
+       if (!common)
+               return -1;
+
+       common->lock = &g_cru_lock;
+
+       switch(common->base_type){
+       case BASE_TYPE_MPMU:
+               common->base = clk_info->mpmu_base;
+               break;
+       case BASE_TYPE_APMU:
+               common->base = clk_info->apmu_base;
+               break;
+       case BASE_TYPE_APBC:
+               common->base = clk_info->apbc_base;
+               break;
+       case BASE_TYPE_APBS:
+               common->base = clk_info->apbs_base;
+               break;
+       case BASE_TYPE_CIU:
+               common->base = clk_info->ciu_base;
+               break;
+       case BASE_TYPE_DCIU:
+               common->base = clk_info->dciu_base;
+               break;
+       case BASE_TYPE_DDRC:
+               common->base = clk_info->ddrc_base;
+               break;
+       case BASE_TYPE_AUDC:
+               common->base = clk_info->audio_ctrl_base;
+               break;
+       case BASE_TYPE_APBC2:
+               common->base = clk_info->apbc2_base;
+               break;
+       case BASE_TYPE_RCPU:
+               common->base = clk_info->rcpu_base;
+               break;
+       default:
+               common->base = clk_info->apbc_base;
+               break;
+
+       }
+       if(common->is_pll)
+               pll->pll.lock_base = clk_info->mpmu_base;
+
+       return 0;
+}
+
+int spacemit_ccu_probe(struct device_node *node, struct spacemit_k1x_clk *clk_info,
+                   struct clk_hw_onecell_data *hw_clks)
+{
+       int i, ret;
+       for (i = 0; i < hw_clks->num ; i++) {
+               struct clk_hw *hw = hw_clks->hws[i];
+               const char *name;
+               if (!hw)
+                       continue;
+               if (!hw->init)
+                       continue;
+
+               ccu_common_init(hw, clk_info);
+               name = hw->init->name;
+
+               ret = of_clk_hw_register(node, hw);
+               if (ret) {
+                       pr_err("Couldn't register clock %d - %s\n", i, name);
+                       goto err_clk_unreg;
+               }
+       }
+       ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
+                                    hw_clks);
+       if (ret)
+               goto err_clk_unreg;
+
+       //enable some clocks
+       spacemit_clocks_enable(bootup_enable_clk_table, ARRAY_SIZE(bootup_enable_clk_table));
+
+       return 0;
+
+err_clk_unreg:
+       while (--i >= 0) {
+               struct clk_hw *hw = hw_clks->hws[i];
+               if (!hw)
+                       continue;
+               clk_hw_unregister(hw);
+       }
+       LOG_INFO("clock init fail");
+       return ret;
+}
+
+static void spacemit_k1x_ccu_probe(struct device_node *np)
+{
+       int ret;
+       struct spacemit_k1x_clk *clk_info;
+       struct clk_hw_onecell_data *hw_clks = &spacemit_k1x_hw_clks;
+
+       //LOG_INFO("init clock");
+       if (of_device_is_compatible(np, "spacemit,k1x-clock")){
+               clk_info = &k1x_clock_controller;
+
+               clk_info->mpmu_base = of_iomap(np, 0);
+               if (!clk_info->mpmu_base) {
+                       pr_err("failed to map mpmu registers\n");
+                       goto out;
+               }
+
+               clk_info->apmu_base = of_iomap(np, 1);
+               if (!clk_info->apmu_base) {
+                       pr_err("failed to map apmu registers\n");
+                       goto out;
+               }
+
+               clk_info->apbc_base = of_iomap(np, 2);
+               if (!clk_info->apbc_base) {
+                       pr_err("failed to map apbc registers\n");
+                       goto out;
+               }
+
+               clk_info->apbs_base = of_iomap(np, 3);
+               if (!clk_info->apbs_base) {
+                       pr_err("failed to map apbs registers\n");
+                       goto out;
+               }
+
+               clk_info->ciu_base = of_iomap(np, 4);
+               if (!clk_info->ciu_base) {
+                       pr_err("failed to map ciu registers\n");
+                       goto out;
+               }
+
+               clk_info->dciu_base = of_iomap(np, 5);
+               if (!clk_info->dciu_base) {
+                       pr_err("failed to map dragon ciu registers\n");
+                       goto out;
+               }
+
+               clk_info->ddrc_base = of_iomap(np, 6);
+               if (!clk_info->ddrc_base) {
+                       pr_err("failed to map ddrc registers\n");
+                       goto out;
+               }
+
+               clk_info->apbc2_base = of_iomap(np, 7);
+               if (!clk_info->apbc2_base) {
+                       pr_err("failed to map apbc2 registers\n");
+                       goto out;
+               }
+
+               clk_info->rcpu_base = of_iomap(np, 8);
+               if (!clk_info->rcpu_base) {
+                       pr_err("failed to map rcpu registers\n");
+                       goto out;
+               }
+       }
+       ret = spacemit_ccu_probe(np, clk_info, hw_clks);
+       //LOG_INFO("init clock finish");
+       if (ret)
+               return;
+out:
+       return;
+}
+
+CLK_OF_DECLARE(k1x_clock, "spacemit,k1x-clock", spacemit_k1x_ccu_probe);
+
diff --git a/drivers/clk/spacemit/ccu-spacemit-k1x.h b/drivers/clk/spacemit/ccu-spacemit-k1x.h
new file mode 100755 (executable)
index 0000000..44b81cb
--- /dev/null
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#ifndef _CCU_SPACEMIT_K1X_H_
+#define _CCU_SPACEMIT_K1X_H_
+
+#include <linux/compiler.h>
+#include <linux/clk-provider.h>
+
+enum ccu_base_type{
+       BASE_TYPE_MPMU       = 0,
+       BASE_TYPE_APMU       = 1,
+       BASE_TYPE_APBC       = 2,
+       BASE_TYPE_APBS       = 3,
+       BASE_TYPE_CIU        = 4,
+       BASE_TYPE_DCIU       = 5,
+       BASE_TYPE_DDRC       = 6,
+       BASE_TYPE_AUDC       = 7,
+       BASE_TYPE_APBC2      = 8,
+       BASE_TYPE_RCPU       = 9,
+};
+
+enum {
+       CLK_DIV_TYPE_1REG_NOFC_V1 = 0,
+       CLK_DIV_TYPE_1REG_FC_V2,
+       CLK_DIV_TYPE_2REG_NOFC_V3,
+       CLK_DIV_TYPE_2REG_FC_V4,
+       CLK_DIV_TYPE_1REG_FC_DIV_V5,
+       CLK_DIV_TYPE_1REG_FC_MUX_V6,
+};
+
+struct ccu_common {
+       void __iomem    *base;
+       enum ccu_base_type base_type;
+       u32     reg_type;
+       u32     reg_ctrl;
+       u32     reg_sel;
+       u32     reg_xtc;
+       u32     fc;
+       bool    is_pll;
+       const char              *name;
+       const struct clk_ops    *ops;
+       const char              * const *parent_names;
+       u8      num_parents;
+       unsigned long   flags;
+       spinlock_t      *lock;
+       struct clk_hw   hw;
+};
+
+struct spacemit_k1x_clk {
+       void __iomem *mpmu_base;
+       void __iomem *apmu_base;
+       void __iomem *apbc_base;
+       void __iomem *apbs_base;
+       void __iomem *ciu_base;
+       void __iomem *dciu_base;
+       void __iomem *ddrc_base;
+       void __iomem *audio_ctrl_base;
+       void __iomem *apbc2_base;
+       void __iomem *rcpu_base;
+};
+
+struct clk_hw_table {
+       char    *name;
+       u32 clk_hw_id;
+};
+
+extern spinlock_t g_cru_lock;
+
+static inline struct ccu_common *hw_to_ccu_common(struct clk_hw *hw)
+{
+       return container_of(hw, struct ccu_common, hw);
+}
+
+int spacemit_ccu_probe(struct device_node *node, struct spacemit_k1x_clk *clk_info,
+                   struct clk_hw_onecell_data *desc);
+
+#endif /* _CCU_SPACEMIT_K1X_H_ */
diff --git a/drivers/clk/spacemit/ccu_ddn.c b/drivers/clk/spacemit/ccu_ddn.c
new file mode 100644 (file)
index 0000000..5afbd46
--- /dev/null
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit clock type ddn
+ *
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+
+#include "ccu_ddn.h"
+/*
+ * It is M/N clock
+ *
+ * Fout from synthesizer can be given from two equations:
+ * numerator/denominator = Fin / (Fout * factor)
+ */
+
+static void ccu_ddn_disable(struct clk_hw *hw)
+{
+       struct ccu_ddn *ddn = hw_to_ccu_ddn(hw);
+       struct ccu_common * common = &ddn->common;
+       unsigned long flags;
+       u32 reg;
+
+       if (!ddn->gate)
+               return;
+
+       spin_lock_irqsave(common->lock, flags);
+
+       reg = readl(common->base + common->reg_sel);
+
+       writel(reg & ~ddn->gate, common->base + common->reg_sel);
+
+       spin_unlock_irqrestore(common->lock, flags);
+}
+
+static int ccu_ddn_enable(struct clk_hw *hw)
+{
+       struct ccu_ddn *ddn = hw_to_ccu_ddn(hw);
+       struct ccu_common * common = &ddn->common;
+       unsigned long flags;
+       u32 reg;
+
+       if (!ddn->gate)
+               return 0;
+
+       spin_lock_irqsave(common->lock, flags);
+
+       reg = readl(common->base + common->reg_sel);
+
+       writel(reg | ddn->gate, common->base + common->reg_sel);
+
+       spin_unlock_irqrestore(common->lock, flags);
+
+       return 0;
+}
+
+static int ccu_ddn_is_enabled(struct clk_hw *hw)
+{
+       struct ccu_ddn *ddn = hw_to_ccu_ddn(hw);
+       struct ccu_common * common = &ddn->common;
+
+       if (!ddn->gate)
+               return 1;
+
+       return readl(common->base + common->reg_sel) & ddn->gate;
+}
+
+static long clk_ddn_round_rate(struct clk_hw *hw, unsigned long drate,
+               unsigned long *prate)
+{
+       struct ccu_ddn *ddn = hw_to_ccu_ddn(hw);
+       struct ccu_ddn_config *params = &ddn->ddn;
+       unsigned long rate = 0, prev_rate;
+       unsigned long result;
+       int i;
+
+       for (i = 0; i < params->tbl_size; i++) {
+               prev_rate = rate;
+               rate = (((*prate / 10000) * params->tbl[i].den) /
+                       (params->tbl[i].num * params->info->factor)) * 10000;
+               if (rate > drate)
+                       break;
+       }
+       if ((i == 0) || (i == params->tbl_size)) {
+               result = rate;
+       } else {
+               if ((drate - prev_rate) > (rate - drate))
+                       result = rate;
+               else
+                       result = prev_rate;
+       }
+       return result;
+}
+
+static unsigned long clk_ddn_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct ccu_ddn *ddn = hw_to_ccu_ddn(hw);
+       struct ccu_ddn_config *params = &ddn->ddn;
+       unsigned int val, num, den;
+       unsigned long rate;
+
+       val = readl(ddn->common.base + ddn->common.reg_ctrl);
+
+       /* calculate numerator */
+       num = (val >> params->info->num_shift) & params->info->num_mask;
+
+       /* calculate denominator */
+       den = (val >> params->info->den_shift) & params->info->den_mask;
+
+       if (!den)
+               return 0;
+       rate = (((parent_rate / 10000)  * den) /
+                       (num * params->info->factor)) * 10000;
+       return rate;
+}
+
+/* Configures new clock rate*/
+static int clk_ddn_set_rate(struct clk_hw *hw, unsigned long drate,
+                               unsigned long prate)
+{
+       struct ccu_ddn *ddn = hw_to_ccu_ddn(hw);
+       struct ccu_ddn_config *params = &ddn->ddn;
+       int i;
+       unsigned long val;
+       unsigned long prev_rate, rate = 0;
+       unsigned long flags = 0;
+
+       for (i = 0; i < params->tbl_size; i++) {
+               prev_rate = rate;
+               rate = (((prate / 10000) * params->tbl[i].den) /
+                       (params->tbl[i].num * params->info->factor)) * 10000;
+               if (rate > drate)
+                       break;
+       }
+
+       if (i > 0)
+               i--;
+
+       if (ddn->common.lock)
+               spin_lock_irqsave(ddn->common.lock, flags);
+
+       val = readl(ddn->common.base + ddn->common.reg_ctrl);
+
+       val &= ~(params->info->num_mask << params->info->num_shift);
+       val |= (params->tbl[i].num & params->info->num_mask) << params->info->num_shift;
+
+       val &= ~(params->info->den_mask << params->info->den_shift);
+       val |= (params->tbl[i].den & params->info->den_mask) << params->info->den_shift;
+
+       writel(val, ddn->common.base + ddn->common.reg_ctrl);
+
+       if (ddn->common.lock)
+               spin_unlock_irqrestore(ddn->common.lock, flags);
+
+       return 0;
+}
+
+const struct clk_ops ccu_ddn_ops = {
+    .disable    = ccu_ddn_disable,
+       .enable          = ccu_ddn_enable,
+       .is_enabled      = ccu_ddn_is_enabled,
+       .recalc_rate = clk_ddn_recalc_rate,
+       .round_rate = clk_ddn_round_rate,
+       .set_rate = clk_ddn_set_rate,
+};
+
diff --git a/drivers/clk/spacemit/ccu_ddn.h b/drivers/clk/spacemit/ccu_ddn.h
new file mode 100644 (file)
index 0000000..b2a0ccc
--- /dev/null
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#ifndef _CCU_DDN_H_
+#define _CCU_DDN_H_
+
+
+#include <linux/spinlock_types.h>
+#include <linux/clk-provider.h>
+
+#include "ccu-spacemit-k1x.h"
+
+struct ccu_ddn_tbl {
+       unsigned int num;
+       unsigned int den;
+};
+
+struct ccu_ddn_info {
+       unsigned int factor;
+       unsigned int num_mask;
+       unsigned int den_mask;
+       unsigned int num_shift;
+       unsigned int den_shift;
+};
+
+struct ccu_ddn_config {
+       struct ccu_ddn_info * info;
+       struct ccu_ddn_tbl * tbl;
+       u32 tbl_size;
+};
+
+#define PLL_DDN_TBL(_num, _den)                \
+       {                                               \
+               .num    =       (_num),         \
+               .den    =       (_den),                 \
+       }
+
+struct ccu_ddn {
+       u32 gate;
+       struct ccu_ddn_config  ddn;
+       struct ccu_common       common;
+};
+
+#define _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size) \
+       {                                               \
+               .info   = (struct ccu_ddn_info *)_info,                 \
+               .tbl    = (struct ccu_ddn_tbl *)_table,                 \
+               .tbl_size       = _size,                        \
+       }
+
+#define SPACEMIT_CCU_DDN(_struct, _name, _parent, _info, _table, _size,        \
+                                                _base_type, _reg_ctrl,         \
+                                                _flags)                                \
+       struct ccu_ddn _struct = {                                      \
+               .ddn    = _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size),       \
+               .common = {                                     \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .base_type              = _base_type,      \
+                       .hw.init        = CLK_HW_INIT(_name,    \
+                                                                 _parent, \
+                                                                 &ccu_ddn_ops, \
+                                                                 _flags),      \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_DDN_GATE(_struct, _name, _parent, _info, _table, _size,   \
+                                                        _base_type, _reg_ddn, __reg_gate, _gate_mask, \
+                                                        _flags)                                \
+       struct ccu_ddn _struct = {                                      \
+               .gate   = _gate_mask,    \
+               .ddn    = _SPACEMIT_CCU_DDN_CONFIG(_info, _table, _size),       \
+               .common = {                                     \
+                       .reg_ctrl               = _reg_ddn,                     \
+                       .reg_sel                = __reg_gate,                   \
+                       .base_type              = _base_type,      \
+                       .hw.init        = CLK_HW_INIT(_name,    \
+                                                                 _parent, \
+                                                                 &ccu_ddn_ops, \
+                                                                 _flags),      \
+               }                                                       \
+       }
+
+
+static inline struct ccu_ddn *hw_to_ccu_ddn(struct clk_hw *hw)
+{
+       struct ccu_common *common = hw_to_ccu_common(hw);
+
+       return container_of(common, struct ccu_ddn, common);
+}
+
+extern const struct clk_ops ccu_ddn_ops;
+
+
+#endif
diff --git a/drivers/clk/spacemit/ccu_mix.c b/drivers/clk/spacemit/ccu_mix.c
new file mode 100755 (executable)
index 0000000..844b2a2
--- /dev/null
@@ -0,0 +1,498 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit clock type mix(div/mux/gate/factor)
+ *
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include "ccu_mix.h"
+
+#define TIMEOUT_LIMIT (20000) /* max timeout 10000us */
+static int twsi8_reg_val = 0x04;
+const char * tswi8_clk_name = "twsi8_clk";
+static void ccu_mix_disable(struct clk_hw *hw)
+{
+       struct ccu_mix *mix = hw_to_ccu_mix(hw);
+       struct ccu_common * common = &mix->common;
+       struct ccu_gate_config *gate = mix->gate;
+       unsigned long flags = 0;
+       unsigned long rate;
+       u32 tmp;
+
+       if (!gate)
+               return;
+
+       if (!strcmp(common->name, tswi8_clk_name)){
+               twsi8_reg_val &= ~gate->gate_mask;;
+               twsi8_reg_val |= gate->val_disable;
+               tmp = twsi8_reg_val;
+               if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+                       || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+                       writel(tmp, common->base + common->reg_sel);
+               else
+                       writel(tmp, common->base + common->reg_ctrl);
+               return;
+       }
+
+       if (common->lock)
+               spin_lock_irqsave(common->lock, flags);
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               tmp = readl(common->base + common->reg_sel);
+       else
+               tmp = readl(common->base + common->reg_ctrl);
+
+       tmp &= ~gate->gate_mask;
+       tmp |= gate->val_disable;
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               writel(tmp, common->base + common->reg_sel);
+       else
+               writel(tmp, common->base + common->reg_ctrl);
+
+       if (common->lock)
+               spin_unlock_irqrestore(common->lock, flags);
+
+       if (gate->flags & SPACEMIT_CLK_GATE_NEED_DELAY) {
+               rate = clk_hw_get_rate(&common->hw);
+
+               if (rate == 0)
+                       pr_err("clock rate of %s is 0.\n", clk_hw_get_name(&common->hw));
+               else
+                       /* Need delay 2M cycles. */
+                       udelay(DIV_ROUND_UP(2000000, rate));
+       }
+
+       return;
+}
+
+static int ccu_mix_enable(struct clk_hw *hw)
+{
+       struct ccu_mix *mix = hw_to_ccu_mix(hw);
+       struct ccu_common * common = &mix->common;
+       struct ccu_gate_config *gate = mix->gate;
+       unsigned long flags = 0;
+       unsigned long rate;
+       u32 tmp;
+       u32 val = 0;
+       int timeout_power = 1;
+
+    if (!gate)
+               return 0;
+
+       if (!strcmp(common->name, tswi8_clk_name)){
+               twsi8_reg_val &= ~gate->gate_mask;;
+               twsi8_reg_val |= gate->val_enable;
+               tmp = twsi8_reg_val;
+               if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+                       || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+                       writel(tmp, common->base + common->reg_sel);
+               else
+                       writel(tmp, common->base + common->reg_ctrl);
+               return 0;
+       }
+
+       if (common->lock)
+               spin_lock_irqsave(common->lock, flags);
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               tmp = readl(common->base + common->reg_sel);
+       else
+               tmp = readl(common->base + common->reg_ctrl);
+
+       tmp &= ~gate->gate_mask;
+       tmp |= gate->val_enable;
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               writel(tmp, common->base + common->reg_sel);
+       else
+               writel(tmp, common->base + common->reg_ctrl);
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               val = readl(common->base + common->reg_sel);
+       else
+               val = readl(common->base + common->reg_ctrl);
+
+       if (common->lock)
+               spin_unlock_irqrestore(common->lock, flags);
+
+       while ((val & gate->gate_mask) != gate->val_enable && (timeout_power < TIMEOUT_LIMIT)) {
+               udelay(timeout_power);
+               if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+                       val = readl(common->base + common->reg_sel);
+               else
+                       val = readl(common->base + common->reg_ctrl);
+               timeout_power *= 10;
+       }
+
+       if (timeout_power > 1) {
+               if (val == tmp)
+                       pr_err("write clk_gate %s timeout occur, read pass after %d us delay\n",
+                       clk_hw_get_name(&common->hw), timeout_power);
+               else
+                       pr_err("write clk_gate  %s timeout after %d us!\n", clk_hw_get_name(&common->hw), timeout_power);
+       }
+
+       if (gate->flags & SPACEMIT_CLK_GATE_NEED_DELAY) {
+               rate = clk_hw_get_rate(&common->hw);
+
+               if (rate == 0)
+                       pr_err("clock rate of %s is 0.\n", clk_hw_get_name(&common->hw));
+               else
+                       /* Need delay 2M cycles. */
+                       udelay(DIV_ROUND_UP(2000000, rate));
+       }
+
+       return 0;
+}
+
+static int ccu_mix_is_enabled(struct clk_hw *hw)
+{
+       struct ccu_mix *mix = hw_to_ccu_mix(hw);
+       struct ccu_common * common = &mix->common;
+       struct ccu_gate_config *gate = mix->gate;
+       unsigned long flags = 0;
+       u32 tmp;
+
+       if (!gate)
+               return 1;
+
+       if (!strcmp(common->name, tswi8_clk_name)){
+               return (twsi8_reg_val & gate->gate_mask) == gate->val_enable;
+       }
+
+       if (common->lock)
+               spin_lock_irqsave(common->lock, flags);
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               tmp = readl(common->base + common->reg_sel);
+       else
+               tmp = readl(common->base + common->reg_ctrl);
+
+       if (common->lock)
+               spin_unlock_irqrestore(common->lock, flags);
+
+       return (tmp & gate->gate_mask) == gate->val_enable;
+}
+
+static unsigned long ccu_mix_recalc_rate(struct clk_hw *hw,
+                                       unsigned long parent_rate)
+{
+       struct ccu_mix *mix = hw_to_ccu_mix(hw);
+       struct ccu_common * common = &mix->common;
+       struct ccu_div_config *div = mix->div;
+       unsigned long val;
+       u32 reg;
+
+       if (!div){
+               if (mix->factor)
+                       return parent_rate * mix->factor->mul / mix->factor->div;
+               else
+                   return parent_rate;
+       }
+    if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               reg = readl(common->base + common->reg_sel);
+       else
+               reg = readl(common->base + common->reg_ctrl);
+
+       val = reg >> div->shift;
+       val &= (1 << div->width) - 1;
+
+       val = divider_recalc_rate(hw, parent_rate, val, div->table,
+                                 div->flags, div->width);
+
+       return val;
+}
+
+
+static int ccu_mix_trigger_fc(struct clk_hw *hw)
+{
+       struct ccu_mix *mix = hw_to_ccu_mix(hw);
+       struct ccu_common * common = &mix->common;
+       unsigned long val = 0;
+
+       int ret = 0, timeout = 50;
+
+       if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4
+               || common->reg_type == CLK_DIV_TYPE_1REG_FC_DIV_V5
+               || common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) {
+
+               timeout = 50;
+               val = readl(common->base + common->reg_ctrl);
+               val |= common->fc;
+               writel(val, common->base + common->reg_ctrl);
+
+               do {
+                       val = readl(common->base + common->reg_ctrl);
+                       timeout--;
+                       if (!(val & (common->fc)))
+                               break;
+               } while (timeout);
+
+               if (timeout == 0) {
+                       timeout = 5000;
+                       do {
+                               val = readl(common->base + common->reg_ctrl);
+                               timeout--;
+                               if (!(val & (common->fc)))
+                                       break;
+                       } while (timeout);
+                       if (timeout != 0) {
+                               ret = 0;
+
+                       } else {
+                               ret = -1;
+                       }
+               }
+       }
+
+       return ret;
+
+}
+
+static long ccu_mix_round_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long *prate)
+{
+       return rate;
+}
+
+unsigned long ccu_mix_calc_best_rate(struct clk_hw *hw, unsigned long rate, u32 *mux_val, u32 *div_val)
+{
+       struct ccu_mix *mix = hw_to_ccu_mix(hw);
+       struct ccu_common * common = &mix->common;
+       struct ccu_div_config *div = mix->div? mix->div: NULL;
+       struct clk_hw *parent;
+       unsigned long parent_rate = 0, best_rate = 0;
+       u32 i, j, div_max;
+
+       for (i = 0; i < common->num_parents; i++) {
+
+               parent = clk_hw_get_parent_by_index(hw, i);
+               if (!parent)
+                       continue;
+               parent_rate = clk_hw_get_rate(parent);
+
+               if(div)
+                       div_max = 1 << div->width;
+               else
+                       div_max = 1;
+
+               for(j = 1; j <= div_max; j++){
+                       if(abs(parent_rate/j - rate) < abs(best_rate - rate)){
+                               best_rate = DIV_ROUND_UP_ULL(parent_rate, j);
+                               *mux_val = i;
+                               *div_val = j - 1;
+                       }
+               }
+       }
+
+       return best_rate;
+}
+
+static int ccu_mix_set_rate(struct clk_hw *hw, unsigned long rate,
+                          unsigned long parent_rate)
+{
+       struct ccu_mix *mix = hw_to_ccu_mix(hw);
+       struct ccu_common * common = &mix->common;
+       struct ccu_div_config *div = mix->div? mix->div: NULL;
+       struct ccu_mux_config *mux = mix->mux? mix->mux: NULL;
+       unsigned long best_rate = 0;
+       unsigned long flags;
+       u32 cur_mux, cur_div, mux_val = 0, div_val = 0;
+       u32 reg = 0;
+       int ret = 0;
+
+       if(!div && !mux){
+               return 0;
+       }
+
+       best_rate = ccu_mix_calc_best_rate(hw, rate, &mux_val, &div_val);
+       if (!strcmp(common->name, tswi8_clk_name)){
+               if(mux){
+               cur_mux = twsi8_reg_val >> mux->shift;
+               cur_mux &= (1 << mux->width) - 1;
+               if(cur_mux != mux_val)
+                       clk_hw_set_parent(hw, clk_hw_get_parent_by_index(hw, mux_val));
+               }
+               return 0;
+       }
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               reg = readl(common->base + common->reg_sel);
+       else
+               reg = readl(common->base + common->reg_ctrl);
+
+       if(mux){
+               cur_mux = reg >> mux->shift;
+               cur_mux &= (1 << mux->width) - 1;
+               if(cur_mux != mux_val)
+                       clk_hw_set_parent(hw, clk_hw_get_parent_by_index(hw, mux_val));
+       }
+       if(div){
+               cur_div = reg >> div->shift;
+               cur_div &= (1 << div->width) - 1;
+               if(cur_div == div_val)
+                       return 0;
+       }else{
+               return 0;
+       }
+
+       spin_lock_irqsave(common->lock, flags);
+    if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               reg = readl(common->base + common->reg_sel);
+       else
+               reg = readl(common->base + common->reg_ctrl);
+
+       reg &= ~GENMASK(div->width + div->shift - 1, div->shift);
+
+    if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               writel(reg | (div_val << div->shift),
+              common->base + common->reg_sel);
+       else
+               writel(reg | (div_val << div->shift),
+              common->base + common->reg_ctrl);
+
+       if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4
+               || common->reg_type == CLK_DIV_TYPE_1REG_FC_DIV_V5) {
+
+               ret = ccu_mix_trigger_fc(hw);
+       }
+       spin_unlock_irqrestore(common->lock, flags);
+
+       if(ret)
+               pr_err("%s of %s timeout\n", __func__, clk_hw_get_name(&common->hw));
+       return 0;
+}
+
+static u8 ccu_mix_get_parent(struct clk_hw *hw)
+{
+       struct ccu_mix *mix = hw_to_ccu_mix(hw);
+       struct ccu_common * common = &mix->common;
+       struct ccu_mux_config *mux = mix->mux;
+       u32 reg;
+       u8 parent;
+
+       if(!mux)
+               return 0;
+
+       if (!strcmp(common->name, tswi8_clk_name)){
+               parent = twsi8_reg_val >> mux->shift;
+               parent &= (1 << mux->width) - 1;
+               return parent;
+       }
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               reg = readl(common->base + common->reg_sel);
+       else
+               reg = readl(common->base + common->reg_ctrl);
+
+       parent = reg >> mux->shift;
+       parent &= (1 << mux->width) - 1;
+
+       if (mux->table) {
+               int num_parents = clk_hw_get_num_parents(&common->hw);
+               int i;
+
+               for (i = 0; i < num_parents; i++)
+                       if (mux->table[i] == parent)
+                               return i;
+       }
+       return parent;
+}
+
+static int ccu_mix_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct ccu_mix *mix = hw_to_ccu_mix(hw);
+       struct ccu_common * common = &mix->common;
+       struct ccu_mux_config *mux = mix->mux;
+       unsigned long flags;
+       u32 reg = 0;
+       int ret = 0;
+
+       if(!mux)
+               return 0;
+
+       if (mux->table)
+               index = mux->table[index];
+
+       if (!strcmp(common->name, tswi8_clk_name)){
+               twsi8_reg_val &= ~GENMASK(mux->width + mux->shift - 1, mux->shift);
+               twsi8_reg_val |= (index << mux->shift);
+               reg = twsi8_reg_val;
+               if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+                       || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+                       writel(reg, common->base + common->reg_sel);
+               else
+                       writel(reg, common->base + common->reg_ctrl);
+               return 0;
+       }
+
+       spin_lock_irqsave(common->lock, flags);
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               reg = readl(common->base + common->reg_sel);
+       else
+               reg = readl(common->base + common->reg_ctrl);
+
+       reg &= ~GENMASK(mux->width + mux->shift - 1, mux->shift);
+
+       if (common->reg_type == CLK_DIV_TYPE_2REG_NOFC_V3
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4)
+               writel(reg | (index << mux->shift), common->base + common->reg_sel);
+       else
+               writel(reg | (index << mux->shift), common->base + common->reg_ctrl);
+
+       if (common->reg_type == CLK_DIV_TYPE_1REG_FC_V2
+               || common->reg_type == CLK_DIV_TYPE_2REG_FC_V4
+               || common->reg_type == CLK_DIV_TYPE_1REG_FC_MUX_V6) {
+
+               ret = ccu_mix_trigger_fc(hw);
+       }
+       spin_unlock_irqrestore(common->lock, flags);
+
+       if(ret)
+               pr_err("%s of %s timeout\n", __func__, clk_hw_get_name(&common->hw));
+
+       return 0;
+}
+
+static int ccu_mix_determine_rate(struct clk_hw *hw,
+                                 struct clk_rate_request *req)
+{
+       /* Just return the same rate without modifying it */
+       return 0;
+}
+
+
+const struct clk_ops ccu_mix_ops = {
+       .disable         = ccu_mix_disable,
+       .enable          = ccu_mix_enable,
+       .is_enabled      = ccu_mix_is_enabled,
+       .get_parent      = ccu_mix_get_parent,
+       .set_parent      = ccu_mix_set_parent,
+       .determine_rate  = ccu_mix_determine_rate,
+       .round_rate  = ccu_mix_round_rate,
+       .recalc_rate = ccu_mix_recalc_rate,
+       .set_rate        = ccu_mix_set_rate,
+};
+
diff --git a/drivers/clk/spacemit/ccu_mix.h b/drivers/clk/spacemit/ccu_mix.h
new file mode 100755 (executable)
index 0000000..f0dfeb9
--- /dev/null
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#ifndef _CCU_MIX_H_
+#define _CCU_MIX_H_
+
+#include <linux/clk-provider.h>
+#include "ccu-spacemit-k1x.h"
+
+
+#define SPACEMIT_CLK_GATE_NEED_DELAY BIT(0)
+
+struct ccu_gate_config {
+       u32             gate_mask;
+       u32             val_enable;
+       u32             val_disable;
+       u32             flags;
+};
+
+struct ccu_factor_config {
+       u32             div;
+       u32             mul;
+};
+
+struct ccu_mux_config {
+       u8              shift;
+       u8              width;
+       const u8        *table;
+       u32             flags;
+};
+
+struct ccu_div_config {
+       u8                      shift;
+       u8                      width;
+       u32                     max;
+       u32                     offset;
+       u32                     flags;
+       struct clk_div_table    *table;
+};
+
+struct ccu_mix {
+       struct ccu_gate_config  *gate;
+       struct ccu_factor_config  *factor;
+       struct ccu_div_config   *div;
+       struct ccu_mux_config   *mux;
+       struct ccu_common       common;
+};
+
+#define CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, _flags)           \
+       (&(struct ccu_gate_config) {                            \
+               .gate_mask   = _gate_mask,                      \
+               .val_enable  = _val_enable,                     \
+               .val_disable = _val_disable,    \
+               .flags  = _flags,                               \
+       })
+
+#define CCU_FACTOR_INIT(_div, _mul)            \
+       (&(struct ccu_factor_config) {                          \
+               .div = _div,                    \
+               .mul = _mul,                    \
+       })
+
+
+#define CCU_MUX_INIT(_shift, _width, _table, _flags)           \
+       (&(struct ccu_mux_config) {                             \
+               .shift  = _shift,                       \
+               .width  = _width,                       \
+               .table  = _table,                       \
+               .flags  = _flags,                               \
+       })
+
+#define CCU_DIV_INIT(_shift, _width, _table, _flags)           \
+       (&(struct ccu_div_config) {                             \
+               .shift  = _shift,                                       \
+               .width  = _width,                                       \
+               .flags  = _flags,                                       \
+               .table  = _table,                                       \
+       })
+
+#define SPACEMIT_CCU_GATE(_struct, _name, _parent, _base_type, _reg,   \
+                                     _gate_mask, _val_enable, _val_disable, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),       \
+               .common = {                                             \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,       \
+                       .name                   = _name,       \
+                       .num_parents    = 1,            \
+                       .hw.init        = CLK_HW_INIT(_name,    \
+                                                     _parent,          \
+                                                     &ccu_mix_ops,     \
+                                                     _flags),          \
+               }                                                       \
+       }
+#define SPACEMIT_CCU_GATE_NO_PARENT(_struct, _name, _parent, _base_type, _reg, \
+                                                 _gate_mask, _val_enable, _val_disable, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),       \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .num_parents    = 0,            \
+                       .hw.init        = CLK_HW_INIT_NO_PARENT(_name,  \
+                                                         &ccu_mix_ops, \
+                                                         _flags),              \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_FACTOR(_struct, _name, _parent,   \
+                                                 _div, _mul) \
+       struct ccu_mix _struct = {                                      \
+               .factor = CCU_FACTOR_INIT(_div, _mul),   \
+               .common = {                                     \
+                       .name                   = _name,    \
+                       .num_parents    = 1,            \
+                       .hw.init        = CLK_HW_INIT(_name,    \
+                                                         _parent,              \
+                                                         &ccu_mix_ops, \
+                                                         0),           \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_MUX(_struct, _name, _parents, _base_type, _reg,   \
+                                                 _shift, _width, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .mux    = CCU_MUX_INIT(_shift, _width, NULL, 0),         \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .parent_names   = _parents,         \
+                       .num_parents    = ARRAY_SIZE(_parents),         \
+                       .hw.init        = CLK_HW_INIT_PARENTS(_name,    \
+                                                         _parents,             \
+                                                         &ccu_mix_ops, \
+                                                         _flags|CLK_GET_RATE_NOCACHE),         \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_DIV(_struct, _name, _parent, _base_type, _reg,    \
+                                                         _shift, _width, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .div    = CCU_DIV_INIT(_shift, _width, NULL, 0),         \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .num_parents    = 1,            \
+                       .hw.init        = CLK_HW_INIT(_name,    \
+                                                         _parent,              \
+                                                         &ccu_mix_ops, \
+                                                         _flags|CLK_GET_RATE_NOCACHE),         \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_GATE_FACTOR(_struct, _name, _parent, _base_type, _reg,    \
+                                                 _gate_mask, _val_enable, _val_disable,  \
+                                                 _div, _mul, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),       \
+               .factor = CCU_FACTOR_INIT(_div, _mul),   \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .num_parents    = 1,            \
+                       .hw.init        = CLK_HW_INIT(_name,    \
+                                                         _parent,              \
+                                                         &ccu_mix_ops, \
+                                                         _flags),              \
+               }                                                       \
+       }
+
+
+#define SPACEMIT_CCU_MUX_GATE(_struct, _name, _parents, _base_type, _reg,      \
+                                                         _shift, _width, _gate_mask, _val_enable, _val_disable, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),       \
+               .mux    = CCU_MUX_INIT(_shift, _width, NULL, 0),         \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .parent_names   = _parents,         \
+                       .num_parents    = ARRAY_SIZE(_parents),         \
+                       .hw.init        = CLK_HW_INIT_PARENTS(_name,    \
+                                                         _parents,             \
+                                                         &ccu_mix_ops, \
+                                                         _flags|CLK_GET_RATE_NOCACHE),         \
+               }                                                       \
+       }
+
+#define SPACEMIT_CCU_DIV_GATE(_struct, _name, _parent, _base_type, _reg,       \
+                                                                _shift, _width, _gate_mask, _val_enable, _val_disable, _flags) \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),       \
+               .div    = CCU_DIV_INIT(_shift, _width, NULL, 0),         \
+               .common = {                                     \
+                       .reg_ctrl               = _reg,                         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .num_parents    = 1,            \
+                       .hw.init        = CLK_HW_INIT(_name,    \
+                                                         _parent,              \
+                                                         &ccu_mix_ops, \
+                                                         _flags|CLK_GET_RATE_NOCACHE),         \
+               }                                                       \
+       }
+
+
+#define SPACEMIT_CCU_DIV_MUX_GATE(_struct, _name, _parents,            \
+                                       _base_type, _reg_ctrl,                          \
+                                       _mshift, _mwidth,               \
+                                       _muxshift, _muxwidth,           \
+                                       _gate_mask, _val_enable, _val_disable, _flags)                  \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),                              \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                             \
+                       .reg_ctrl               = _reg_ctrl,                            \
+                       .base_type              = _base_type,       \
+                       .name                   = _name,       \
+                       .parent_names   = _parents,         \
+                       .num_parents    = ARRAY_SIZE(_parents),         \
+                       .hw.init        = CLK_HW_INIT_PARENTS(_name,    \
+                                                             _parents, \
+                                                             &ccu_mix_ops, \
+                                                             _flags|CLK_GET_RATE_NOCACHE),     \
+               },                                                      \
+       }
+
+#define SPACEMIT_CCU_DIV2_FC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, _reg_sel,       \
+                                                 _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, _val_enable, _val_disable,           \
+                                                 _flags)                                       \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),      \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                     \
+                   .reg_type = CLK_DIV_TYPE_2REG_FC_V4,   \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .reg_sel                = _reg_sel,      \
+                       .fc                     = _fc,             \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .parent_names   = _parents,         \
+                       .num_parents    = ARRAY_SIZE(_parents),         \
+                       .hw.init        = CLK_HW_INIT_PARENTS(_name,            \
+                                                         _parents,             \
+                                                         &ccu_mix_ops, \
+                                                         _flags|CLK_GET_RATE_NOCACHE),         \
+               },                                                      \
+       }
+
+
+#define SPACEMIT_CCU_DIV_FC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl,  \
+                                                 _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, _val_enable, _val_disable,           \
+                                                 _flags)                                       \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),      \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                     \
+                   .reg_type = CLK_DIV_TYPE_1REG_FC_V2,    \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .fc                     = _fc,             \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .parent_names   = _parents,         \
+                       .num_parents    = ARRAY_SIZE(_parents),         \
+                       .hw.init        = CLK_HW_INIT_PARENTS(_name,            \
+                                                         _parents,             \
+                                                         &ccu_mix_ops, \
+                                                         _flags|CLK_GET_RATE_NOCACHE),         \
+               },                                                      \
+       }
+
+#define SPACEMIT_CCU_DIV_MFC_MUX_GATE(_struct, _name, _parents, _base_type, _reg_ctrl, \
+                                                         _mshift, _mwidth, _fc, _muxshift, _muxwidth, _gate_mask, _val_enable, _val_disable,           \
+                                                         _flags)                                       \
+               struct ccu_mix _struct = {                                      \
+                       .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),      \
+                       .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+                       .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+                       .common = {                                     \
+                               .reg_type = CLK_DIV_TYPE_1REG_FC_MUX_V6,        \
+                               .reg_ctrl               = _reg_ctrl,                    \
+                               .fc                     = _fc,             \
+                               .base_type              = _base_type,           \
+                               .name                   = _name,       \
+                               .parent_names   = _parents,             \
+                               .num_parents    = ARRAY_SIZE(_parents),         \
+                               .hw.init        = CLK_HW_INIT_PARENTS(_name,            \
+                                                                 _parents,     \
+                                                                 &ccu_mix_ops, \
+                                                                 _flags|CLK_GET_RATE_NOCACHE),         \
+                       },                                                      \
+               }
+
+
+#define SPACEMIT_CCU_DIV_FC_WITH_GATE(_struct, _name, _parent, _base_type, _reg_ctrl,          \
+                                         _mshift, _mwidth, _fc, _gate_mask, _val_enable, _val_disable,                 \
+                                         _flags)                                       \
+       struct ccu_mix _struct = {                                      \
+               .gate   = CCU_GATE_INIT(_gate_mask, _val_enable, _val_disable, 0),      \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .common = {                                     \
+                       .reg_type = CLK_DIV_TYPE_1REG_FC_V2,    \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .fc                     = _fc,         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .num_parents    = 1,            \
+                       .hw.init        = CLK_HW_INIT(_name,            \
+                                                         _parent,              \
+                                                         &ccu_mix_ops, \
+                                                         _flags|CLK_GET_RATE_NOCACHE),         \
+               },                                                      \
+       }
+
+#define SPACEMIT_CCU_DIV_FC_MUX(_struct, _name, _parents, _base_type, _reg_ctrl,               \
+                                         _mshift, _mwidth, _fc, _muxshift, _muxwidth, _flags)                                  \
+       struct ccu_mix _struct = {                                      \
+               .div    = CCU_DIV_INIT(_mshift, _mwidth, NULL, 0),              \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                     \
+                       .reg_type = CLK_DIV_TYPE_1REG_FC_V2,    \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .fc                     = _fc,         \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .parent_names   = _parents,         \
+                       .num_parents    = ARRAY_SIZE(_parents),         \
+                       .hw.init        = CLK_HW_INIT_PARENTS(_name,            \
+                                                         _parents,             \
+                                                         &ccu_mix_ops, \
+                                                         _flags|CLK_GET_RATE_NOCACHE),         \
+               },                                                      \
+       }
+
+#define SPACEMIT_CCU_MUX_FC(_struct, _name, _parents, _base_type, _reg_ctrl,           \
+                                                 _fc, _muxshift, _muxwidth, _flags)                                    \
+       struct ccu_mix _struct = {                                      \
+               .mux    = CCU_MUX_INIT(_muxshift, _muxwidth, NULL, 0), \
+               .common = {                                     \
+                       .reg_type = CLK_DIV_TYPE_1REG_FC_V2,    \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .fc                     = _fc,             \
+                       .base_type              = _base_type,           \
+                       .name                   = _name,       \
+                       .parent_names   = _parents,             \
+                       .num_parents    = ARRAY_SIZE(_parents),         \
+                       .hw.init        = CLK_HW_INIT_PARENTS(_name,            \
+                                                         _parents,     \
+                                                         &ccu_mix_ops, \
+                                                         _flags|CLK_GET_RATE_NOCACHE),         \
+               },                                                      \
+       }
+
+static inline struct ccu_mix *hw_to_ccu_mix(struct clk_hw *hw)
+{
+       struct ccu_common *common = hw_to_ccu_common(hw);
+
+       return container_of(common, struct ccu_mix, common);
+}
+
+extern const struct clk_ops ccu_mix_ops;
+
+#endif /* _CCU_DIV_H_ */
diff --git a/drivers/clk/spacemit/ccu_pll.c b/drivers/clk/spacemit/ccu_pll.c
new file mode 100644 (file)
index 0000000..391498a
--- /dev/null
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit clock type pll
+ *
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+
+#include "ccu_pll.h"
+
+#define PLL_MIN_FREQ 600000000
+#define PLL_MAX_FREQ 3400000000
+#define PLL_DELAYTIME 590 //(590*5)us
+
+#define pll_readl(reg)         readl(reg)
+#define pll_readl_pll_swcr1(p) pll_readl(p.base + p.reg_ctrl)
+#define pll_readl_pll_swcr2(p) pll_readl(p.base + p.reg_sel)
+#define pll_readl_pll_swcr3(p) pll_readl(p.base + p.reg_xtc)
+
+#define pll_writel(val, reg)           writel(val, reg)
+#define pll_writel_pll_swcr1(val, p)   pll_writel(val, p.base + p.reg_ctrl)
+#define pll_writel_pll_swcr2(val, p)   pll_writel(val, p.base + p.reg_sel)
+#define pll_writel_pll_swcr3(val, p)   pll_writel(val, p.base + p.reg_xtc)
+
+/* unified pllx_swcr1 for pll1~3 */
+union pllx_swcr1 {
+       struct {
+               unsigned int reg5:8;
+               unsigned int reg6:8;
+               unsigned int reg7:8;
+               unsigned int reg8:8;
+       } b;
+       unsigned int v;
+};
+
+/* unified pllx_swcr2 for pll1~3 */
+union pllx_swcr2 {
+       struct {
+               unsigned int div1_en:1;
+               unsigned int div2_en:1;
+               unsigned int div3_en:1;
+               unsigned int div4_en:1;
+               unsigned int div5_en:1;
+               unsigned int div6_en:1;
+               unsigned int div7_en:1;
+               unsigned int div8_en:1;
+               unsigned int reserved1:4;
+               unsigned int atest_en:1;
+               unsigned int cktest_en:1;
+               unsigned int dtest_en:1;
+               unsigned int rdo:2;
+               unsigned int mon_cfg:4;
+               unsigned int reserved2:11;
+       } b;
+       unsigned int v;
+};
+
+/* unified pllx_swcr3 for pll1~3 */
+union pllx_swcr3{
+       struct {
+               unsigned int div_frc:24;
+               unsigned int div_int:7;
+               unsigned int pll_en:1;
+       } b;
+
+       unsigned int v;
+};
+
+static int ccu_pll_is_enabled(struct clk_hw *hw)
+{
+       struct ccu_pll *p = hw_to_ccu_pll(hw);
+       union pllx_swcr3 swcr3;
+       unsigned int enabled;
+
+       swcr3.v = pll_readl_pll_swcr3(p->common);
+       enabled = swcr3.b.pll_en;
+
+       return enabled;
+}
+
+/* frequency unit Mhz, return pll vco freq */
+static unsigned long __get_vco_freq(struct clk_hw *hw)
+{
+       unsigned int reg5, reg6, reg7, reg8, size, i;
+       unsigned int div_int, div_frc;
+       struct ccu_pll_rate_tbl *freq_pll_regs_table;
+       struct ccu_pll *p = hw_to_ccu_pll(hw);
+       union pllx_swcr1 swcr1;
+       union pllx_swcr3 swcr3;
+
+       swcr1.v = pll_readl_pll_swcr1(p->common);
+       swcr3.v = pll_readl_pll_swcr3(p->common);
+
+    reg5 = swcr1.b.reg5;
+    reg6 = swcr1.b.reg6;
+    reg7 = swcr1.b.reg7;
+    reg8 = swcr1.b.reg8;
+
+    div_int = swcr3.b.div_int;
+    div_frc = swcr3.b.div_frc;
+
+    freq_pll_regs_table = p->pll.rate_tbl;
+    size = p->pll.tbl_size;
+
+    for (i = 0; i < size; i++) {
+              if ((freq_pll_regs_table[i].reg5 == reg5)
+              && (freq_pll_regs_table[i].reg6 == reg6)
+              && (freq_pll_regs_table[i].reg7 == reg7)
+              && (freq_pll_regs_table[i].reg8 == reg8)
+         && (freq_pll_regs_table[i].div_int == div_int)
+         && (freq_pll_regs_table[i].div_frac == div_frc))
+                    return freq_pll_regs_table[i].rate;
+
+    }
+
+    pr_err("Unknown rate for clock %s\n", __clk_get_name(hw->clk));
+
+    return 0;
+}
+
+static int ccu_pll_enable(struct clk_hw *hw)
+{
+       unsigned int delaytime = PLL_DELAYTIME;
+       unsigned long flags;
+       struct ccu_pll *p = hw_to_ccu_pll(hw);
+       union pllx_swcr3 swcr3;
+
+       if (ccu_pll_is_enabled(hw))
+               return 0;
+
+       spin_lock_irqsave(p->common.lock, flags);
+       swcr3.v = pll_readl_pll_swcr3(p->common);
+       swcr3.b.pll_en = 1;
+       pll_writel_pll_swcr3(swcr3.v, p->common);
+       spin_unlock_irqrestore(p->common.lock, flags);
+
+       /* check lock status */
+       udelay(50);
+
+       while ((!(readl(p->pll.lock_base + p->pll.reg_lock) & p->pll.lock_enable_bit))
+              && delaytime) {
+               udelay(5);
+               delaytime--;
+       }
+       if (unlikely(!delaytime)) {
+               pr_err("%s enabling didn't get stable within 3000us!!!\n", __clk_get_name(hw->clk));
+               //panic("pllx_r/w timeout!\n");
+       }
+
+       return 0;
+}
+
+static void ccu_pll_disable(struct clk_hw *hw)
+{
+       unsigned long flags;
+       struct ccu_pll *p = hw_to_ccu_pll(hw);
+       union pllx_swcr3 swcr3;
+
+       spin_lock_irqsave(p->common.lock, flags);
+       swcr3.v = pll_readl_pll_swcr3(p->common);
+       swcr3.b.pll_en = 0;
+       pll_writel_pll_swcr3(swcr3.v, p->common);
+       spin_unlock_irqrestore(p->common.lock, flags);
+}
+
+/*
+ * pll rate change requires sequence:
+ * clock off -> change rate setting -> clock on
+ * This function doesn't really change rate, but cache the config
+ */
+static int ccu_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long parent_rate)
+{
+       unsigned int i, reg5 = 0, reg6 = 0, reg7 = 0, reg8 = 0;
+       unsigned int div_int, div_frc;
+       unsigned long flags;
+       unsigned long new_rate = rate, old_rate;
+       struct ccu_pll *p = hw_to_ccu_pll(hw);
+       struct ccu_pll_config *params = &p->pll;
+       union pllx_swcr1 swcr1;
+       union pllx_swcr3 swcr3;
+       bool found = false;
+
+       if (ccu_pll_is_enabled(hw)) {
+               pr_err("%s %s is enabled, ignore the setrate!\n",
+                      __func__, __clk_get_name(hw->clk));
+               return 0;
+       }
+
+       old_rate = __get_vco_freq(hw);
+       /* setp 1: calculate fbd frcd kvco and band */
+       if (params->rate_tbl) {
+               for (i = 0; i < params->tbl_size; i++) {
+                       if (rate == params->rate_tbl[i].rate) {
+                               found = true;
+
+                               reg5 = params->rate_tbl[i].reg5;
+                               reg6 = params->rate_tbl[i].reg6;
+                               reg7 = params->rate_tbl[i].reg7;
+                               reg8 = params->rate_tbl[i].reg8;
+                               div_int = params->rate_tbl[i].div_int;
+                               div_frc = params->rate_tbl[i].div_frac;
+                               break;
+                       }
+               }
+
+               BUG_ON(!found);
+       } else {
+               pr_err("don't find freq table for pll\n");
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(p->common.lock, flags);
+       /* setp 2: set pll kvco/band and fbd/frcd setting */
+       swcr1.v = pll_readl_pll_swcr1(p->common);
+       swcr1.b.reg5 = reg5;
+       swcr1.b.reg6 = reg6;
+       swcr1.b.reg7 = reg7;
+       swcr1.b.reg8 = reg8;
+       pll_writel_pll_swcr1(swcr1.v, p->common);
+
+       swcr3.v = pll_readl_pll_swcr3(p->common);
+       swcr3.b.div_int = div_int;
+       swcr3.b.div_frc = div_frc;
+       pll_writel_pll_swcr3(swcr3.v, p->common);
+
+       spin_unlock_irqrestore(p->common.lock, flags);
+
+       pr_debug("%s %s rate %lu->%lu!\n", __func__,
+                __clk_get_name(hw->clk), old_rate, new_rate);
+       return 0;
+}
+
+static unsigned long ccu_pll_recalc_rate(struct clk_hw *hw,
+                                        unsigned long parent_rate)
+{
+       return __get_vco_freq(hw);
+}
+
+static long ccu_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long *prate)
+{
+       struct ccu_pll *p = hw_to_ccu_pll(hw);
+       unsigned long max_rate = 0;
+       unsigned int i;
+       struct ccu_pll_config *params = &p->pll;
+
+       if (rate > PLL_MAX_FREQ || rate < PLL_MIN_FREQ) {
+               pr_err("%lu rate out of range!\n", rate);
+               return -EINVAL;
+       }
+
+       if (params->rate_tbl) {
+               for (i = 0; i < params->tbl_size; i++) {
+                       if (params->rate_tbl[i].rate <= rate) {
+                               if (max_rate < params->rate_tbl[i].rate)
+                                       max_rate = params->rate_tbl[i].rate;
+                       }
+               }
+       } else {
+               pr_err("don't find freq table for pll\n");
+       }
+       return max_rate;
+}
+
+const struct clk_ops ccu_pll_ops = {
+       .enable = ccu_pll_enable,
+       .disable = ccu_pll_disable,
+       .set_rate = ccu_pll_set_rate,
+       .recalc_rate = ccu_pll_recalc_rate,
+       .round_rate = ccu_pll_round_rate,
+       .is_enabled = ccu_pll_is_enabled,
+};
+
diff --git a/drivers/clk/spacemit/ccu_pll.h b/drivers/clk/spacemit/ccu_pll.h
new file mode 100644 (file)
index 0000000..95df620
--- /dev/null
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, spacemit Corporation.
+ *
+ */
+
+#ifndef _CCU_PLL_H_
+#define _CCU_PLL_H_
+
+#include <linux/spinlock_types.h>
+#include <linux/clk-provider.h>
+#include "ccu-spacemit-k1x.h"
+
+struct ccu_pll_rate_tbl {
+       unsigned long long rate;
+       u32 reg5;
+       u32 reg6;
+       u32 reg7;
+       u32 reg8;
+       unsigned int div_int;
+       unsigned int div_frac;
+};
+
+struct ccu_pll_config {
+       struct ccu_pll_rate_tbl * rate_tbl;
+       u32 tbl_size;
+       void __iomem    *lock_base;
+       u32             reg_lock;
+       u32 lock_enable_bit;
+};
+
+#define PLL_RATE(_rate, _reg5, _reg6, _reg7, _reg8, _div_int, _div_frac)               \
+       {                                               \
+               .rate   =       (_rate),                \
+               .reg5   =       (_reg5),                        \
+               .reg6   =       (_reg6),                        \
+               .reg7   =       (_reg7),                        \
+               .reg8   =       (_reg8),                        \
+               .div_int        =       (_div_int),                     \
+               .div_frac       =       (_div_frac),                    \
+       }
+
+struct ccu_pll {
+       struct ccu_pll_config   pll;
+       struct ccu_common       common;
+};
+
+#define _SPACEMIT_CCU_PLL_CONFIG(_table, _size, _reg_lock, _lock_enable_bit)   \
+       {                                               \
+               .rate_tbl       = (struct ccu_pll_rate_tbl *)_table,                    \
+               .tbl_size       = _size,                        \
+               .reg_lock       = _reg_lock,        \
+               .lock_enable_bit        = _lock_enable_bit,                     \
+       }
+
+#define SPACEMIT_CCU_PLL(_struct, _name, _table, _size,        \
+                                                _base_type, _reg_ctrl, _reg_sel, _reg_xtc,\
+                                                _reg_lock, _lock_enable_bit, _is_pll,  \
+                                                _flags)                                \
+       struct ccu_pll _struct = {                                      \
+               .pll    = _SPACEMIT_CCU_PLL_CONFIG(_table, _size, _reg_lock, _lock_enable_bit), \
+               .common = {                                     \
+                       .reg_ctrl               = _reg_ctrl,                    \
+                       .reg_sel                = _reg_sel,                     \
+                       .reg_xtc                = _reg_xtc,                     \
+                       .base_type              = _base_type,      \
+                       .is_pll                 = _is_pll,       \
+                       .hw.init        = CLK_HW_INIT_NO_PARENT(_name,  \
+                                                                 &ccu_pll_ops, \
+                                                                 _flags),      \
+               }                                                       \
+       }
+
+
+static inline struct ccu_pll *hw_to_ccu_pll(struct clk_hw *hw)
+{
+       struct ccu_common *common = hw_to_ccu_common(hw);
+
+       return container_of(common, struct ccu_pll, common);
+}
+
+extern const struct clk_ops ccu_pll_ops;
+
+#endif
diff --git a/include/dt-bindings/clock/spacemit-k1x-clock.h b/include/dt-bindings/clock/spacemit-k1x-clock.h
new file mode 100755 (executable)
index 0000000..391f830
--- /dev/null
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: (GPL-2.0+ or MIT)
+
+#ifndef _DT_BINDINGS_CLK_SPACEMIT_K1X_H_
+#define _DT_BINDINGS_CLK_SPACEMIT_K1X_H_
+
+#define CLK_PLL2     0
+#define CLK_PLL3     1
+#define CLK_PLL1_D2  2
+#define CLK_PLL1_D3  3
+#define CLK_PLL1_D4  4
+#define CLK_PLL1_D5  5
+#define CLK_PLL1_D6  6
+#define CLK_PLL1_D7  7
+#define CLK_PLL1_D8  8
+#define CLK_PLL1_D11 9
+#define CLK_PLL1_D13 10
+#define CLK_PLL1_D23 11
+#define CLK_PLL1_D64 12
+#define CLK_PLL1_D10_AUD  13
+#define CLK_PLL1_D100_AUD 14
+#define CLK_PLL2_D1  15
+#define CLK_PLL2_D2  16
+#define CLK_PLL2_D3  17
+#define CLK_PLL2_D4  18
+#define CLK_PLL2_D5  19
+#define CLK_PLL2_D6  20
+#define CLK_PLL2_D7  21
+#define CLK_PLL2_D8  22
+#define CLK_PLL3_D1  23
+#define CLK_PLL3_D2  24
+#define CLK_PLL3_D3  25
+#define CLK_PLL3_D4  26
+#define CLK_PLL3_D5  27
+#define CLK_PLL3_D6  28
+#define CLK_PLL3_D7  29
+#define CLK_PLL3_D8  30
+#define CLK_PLL1_307P2 31
+#define CLK_PLL1_76P8  32
+#define CLK_PLL1_61P44 33
+#define CLK_PLL1_153P6 34
+#define CLK_PLL1_102P4 35
+#define CLK_PLL1_51P2  36
+#define CLK_PLL1_51P2_AP 37
+#define CLK_PLL1_57P6 38
+#define CLK_PLL1_25P6 39
+#define CLK_PLL1_12P8 40
+#define CLK_PLL1_12P8_WDT 41
+#define CLK_PLL1_6P4  42
+#define CLK_PLL1_3P2  43
+#define CLK_PLL1_1P6  44
+#define CLK_PLL1_0P8  45
+#define CLK_PLL1_351  46
+#define CLK_PLL1_409P6 47
+#define CLK_PLL1_204P8 48
+#define CLK_PLL1_491   49
+#define CLK_PLL1_245P76 50
+#define CLK_PLL1_614    51
+#define CLK_PLL1_47P26  52
+#define CLK_PLL1_31P5   53
+#define CLK_PLL1_819    54
+#define CLK_PLL1_1228   55
+#define CLK_SLOW_UART1  56
+#define CLK_SLOW_UART2  57
+#define CLK_UART1  58
+#define CLK_UART2  59
+#define CLK_UART3  60
+#define CLK_UART4  61
+#define CLK_UART5  62
+#define CLK_UART6  63
+#define CLK_UART7  64
+#define CLK_UART8  65
+#define CLK_UART9  66
+#define CLK_GPIO  67
+#define CLK_PWM0  68
+#define CLK_PWM1  69
+#define CLK_PWM2  70
+#define CLK_PWM3  71
+#define CLK_PWM4  72
+#define CLK_PWM5  73
+#define CLK_PWM6  74
+#define CLK_PWM7  75
+#define CLK_PWM8  76
+#define CLK_PWM9  77
+#define CLK_PWM10 78
+#define CLK_PWM11 79
+#define CLK_PWM12 80
+#define CLK_PWM13 81
+#define CLK_PWM14 82
+#define CLK_PWM15 83
+#define CLK_PWM16 84
+#define CLK_PWM17 85
+#define CLK_PWM18 86
+#define CLK_PWM19 87
+#define CLK_SSP3  88
+#define CLK_RTC   89
+#define CLK_TWSI0 90
+#define CLK_TWSI1 91
+#define CLK_TWSI2 92
+#define CLK_TWSI4 93
+#define CLK_TWSI5 94
+#define CLK_TWSI6 95
+#define CLK_TWSI7 96
+#define CLK_TWSI8 97
+#define CLK_TIMERS1 98
+#define CLK_TIMERS2 99
+#define CLK_AIB     100
+#define CLK_ONEWIRE 101
+#define CLK_SSPA0   102
+#define CLK_SSPA1   103
+#define CLK_DRO     104
+#define CLK_IR      105
+#define CLK_TSEN    106
+#define CLK_IPC_AP2AUD  107
+#define CLK_CAN0     108
+#define CLK_CAN0_BUS 109
+#define CLK_WDT      110
+#define CLK_RIPC     111
+#define CLK_JPG      112
+#define CLK_JPF_4KAFBC 113
+#define CLK_JPF_2KAFBC 114
+#define CLK_CCIC2PHY   115
+#define CLK_CCIC3PHY   116
+#define CLK_CSI      117
+#define CLK_CAMM0    118
+#define CLK_CAMM1    119
+#define CLK_CAMM2    120
+#define CLK_ISP_CPP  121
+#define CLK_ISP_BUS  122
+#define CLK_ISP      123
+#define CLK_DPU_MCLK 124
+#define CLK_DPU_ESC  125
+#define CLK_DPU_BIT  126
+#define CLK_DPU_PXCLK  127
+#define CLK_DPU_HCLK   128
+#define CLK_DPU_SPI    129
+#define CLK_DPU_SPI_HBUS  130
+#define CLK_DPU_SPIBUS   131
+#define CLK_SPU_SPI_ACLK  132
+#define CLK_V2D      133
+#define CLK_CCIC_4X  134
+#define CLK_CCIC1PHY 135
+#define CLK_SDH_AXI  136
+#define CLK_SDH0     137
+#define CLK_SDH1     138
+#define CLK_SDH2     139
+#define CLK_USB_P1   140
+#define CLK_USB_AXI  141
+#define CLK_USB30    142
+#define CLK_QSPI     143
+#define CLK_QSPI_BUS 144
+#define CLK_DMA      145
+#define CLK_AES      146
+#define CLK_VPU      147
+#define CLK_GPU      148
+#define CLK_EMMC     149
+#define CLK_EMMC_X   150
+#define CLK_AUDIO    151
+#define CLK_HDMI     152
+#define CLK_CCI550   153
+#define CLK_PMUA_ACLK  154
+#define CLK_CPU_C0_HI  155
+#define CLK_CPU_C0_CORE 156
+#define CLK_CPU_C0_ACE  157
+#define CLK_CPU_C0_TCM  158
+#define CLK_CPU_C1_HI   159
+#define CLK_CPU_C1_CORE 160
+#define CLK_CPU_C1_ACE  161
+#define CLK_PCIE0   162
+#define CLK_PCIE1   163
+#define CLK_PCIE2   164
+#define CLK_EMAC0_BUS  165
+#define CLK_EMAC0_PTP  166
+#define CLK_EMAC1_BUS  167
+#define CLK_EMAC1_PTP  168
+
+#define CLK_SEC_UART1   169
+#define CLK_SEC_SSP2    170
+#define CLK_SEC_TWSI3   171
+#define CLK_SEC_RTC     172
+#define CLK_SEC_TIMERS0 173
+#define CLK_SEC_KPC     174
+#define CLK_SEC_GPIO    175
+
+#define CLK_APB         176
+
+#define CLK_PLL3_80     177
+#define CLK_PLL3_40     178
+#define CLK_PLL3_20     179
+
+#define CLK_SLOW_UART   180
+
+#define CLK_I2S_SYSCLK  181
+#define CLK_I2S_BCLK    182
+#define CLK_RCPU_HDMIAUDIO  183
+#define CLK_RCPU_CAN        184
+#define CLK_RCPU_CAN_BUS    185
+
+#define CLK_MAX_NO      186
+#endif /* _DT_BINDINGS_CLK_SPACEMIT_K1X_H_ */