--- /dev/null
+From ad6de25748213578dc88100b0a7bf7bec4f44dff Mon Sep 17 00:00:00 2001
+From: Chen Wang <unicornxw@gmail.com>
+Date: Wed, 20 Sep 2023 14:40:32 +0800
+Subject: [PATCH 03/18] riscv: dts: add initial SOPHGO SG2042 SoC device tree
+
+Milk-V Pioneer motherboard is powered by SOPHON's SG2042.
+
+SG2042 is server grade chip with high performance, low power
+consumption and high data throughput.
+Key features:
+- 64 RISC-V cpu cores which implements IMAFDC
+- 4 cores per cluster, 16 clusters on chip
+- ......
+
+More info is available at [1].
+
+[1]: https://en.sophgo.com/product/introduce/sg2042.html
+
+Currently only support booting into console with only uart,
+other features will be added soon later.
+
+Acked-by: Xiaoguang Xing <xiaoguang.xing@sophgo.com>
+Signed-off-by: Xiaoguang Xing <xiaoguang.xing@sophgo.com>
+Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
+Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
+Signed-off-by: Chen Wang <wangchen20@iscas.ac.cn>
+Reviewed-by: Guo Ren <guoren@kernel.org>
+---
+ arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi | 1744 +++++++++++++++++++
+ arch/riscv/boot/dts/sophgo/sg2042.dtsi | 439 +++++
+ 2 files changed, 2183 insertions(+)
+ create mode 100644 arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/sg2042.dtsi
+
+diff --git a/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi b/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi
+new file mode 100644
+index 000000000000..9fc79b1cf3bf
+--- /dev/null
++++ b/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi
+@@ -0,0 +1,1744 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved.
++ */
++
++/ {
++ cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ timebase-frequency = <50000000>;
++
++ cpu-map {
++ socket0 {
++ cluster0 {
++ core0 {
++ cpu = <&cpu0>;
++ };
++ core1 {
++ cpu = <&cpu1>;
++ };
++ core2 {
++ cpu = <&cpu2>;
++ };
++ core3 {
++ cpu = <&cpu3>;
++ };
++ };
++
++ cluster1 {
++ core0 {
++ cpu = <&cpu4>;
++ };
++ core1 {
++ cpu = <&cpu5>;
++ };
++ core2 {
++ cpu = <&cpu6>;
++ };
++ core3 {
++ cpu = <&cpu7>;
++ };
++ };
++
++ cluster2 {
++ core0 {
++ cpu = <&cpu16>;
++ };
++ core1 {
++ cpu = <&cpu17>;
++ };
++ core2 {
++ cpu = <&cpu18>;
++ };
++ core3 {
++ cpu = <&cpu19>;
++ };
++ };
++
++ cluster3 {
++ core0 {
++ cpu = <&cpu20>;
++ };
++ core1 {
++ cpu = <&cpu21>;
++ };
++ core2 {
++ cpu = <&cpu22>;
++ };
++ core3 {
++ cpu = <&cpu23>;
++ };
++ };
++
++ cluster4 {
++ core0 {
++ cpu = <&cpu8>;
++ };
++ core1 {
++ cpu = <&cpu9>;
++ };
++ core2 {
++ cpu = <&cpu10>;
++ };
++ core3 {
++ cpu = <&cpu11>;
++ };
++ };
++
++ cluster5 {
++ core0 {
++ cpu = <&cpu12>;
++ };
++ core1 {
++ cpu = <&cpu13>;
++ };
++ core2 {
++ cpu = <&cpu14>;
++ };
++ core3 {
++ cpu = <&cpu15>;
++ };
++ };
++
++ cluster6 {
++ core0 {
++ cpu = <&cpu24>;
++ };
++ core1 {
++ cpu = <&cpu25>;
++ };
++ core2 {
++ cpu = <&cpu26>;
++ };
++ core3 {
++ cpu = <&cpu27>;
++ };
++ };
++
++ cluster7 {
++ core0 {
++ cpu = <&cpu28>;
++ };
++ core1 {
++ cpu = <&cpu29>;
++ };
++ core2 {
++ cpu = <&cpu30>;
++ };
++ core3 {
++ cpu = <&cpu31>;
++ };
++ };
++
++ cluster8 {
++ core0 {
++ cpu = <&cpu32>;
++ };
++ core1 {
++ cpu = <&cpu33>;
++ };
++ core2 {
++ cpu = <&cpu34>;
++ };
++ core3 {
++ cpu = <&cpu35>;
++ };
++ };
++
++ cluster9 {
++ core0 {
++ cpu = <&cpu36>;
++ };
++ core1 {
++ cpu = <&cpu37>;
++ };
++ core2 {
++ cpu = <&cpu38>;
++ };
++ core3 {
++ cpu = <&cpu39>;
++ };
++ };
++
++ cluster10 {
++ core0 {
++ cpu = <&cpu48>;
++ };
++ core1 {
++ cpu = <&cpu49>;
++ };
++ core2 {
++ cpu = <&cpu50>;
++ };
++ core3 {
++ cpu = <&cpu51>;
++ };
++ };
++
++ cluster11 {
++ core0 {
++ cpu = <&cpu52>;
++ };
++ core1 {
++ cpu = <&cpu53>;
++ };
++ core2 {
++ cpu = <&cpu54>;
++ };
++ core3 {
++ cpu = <&cpu55>;
++ };
++ };
++
++ cluster12 {
++ core0 {
++ cpu = <&cpu40>;
++ };
++ core1 {
++ cpu = <&cpu41>;
++ };
++ core2 {
++ cpu = <&cpu42>;
++ };
++ core3 {
++ cpu = <&cpu43>;
++ };
++ };
++
++ cluster13 {
++ core0 {
++ cpu = <&cpu44>;
++ };
++ core1 {
++ cpu = <&cpu45>;
++ };
++ core2 {
++ cpu = <&cpu46>;
++ };
++ core3 {
++ cpu = <&cpu47>;
++ };
++ };
++
++ cluster14 {
++ core0 {
++ cpu = <&cpu56>;
++ };
++ core1 {
++ cpu = <&cpu57>;
++ };
++ core2 {
++ cpu = <&cpu58>;
++ };
++ core3 {
++ cpu = <&cpu59>;
++ };
++ };
++
++ cluster15 {
++ core0 {
++ cpu = <&cpu60>;
++ };
++ core1 {
++ cpu = <&cpu61>;
++ };
++ core2 {
++ cpu = <&cpu62>;
++ };
++ core3 {
++ cpu = <&cpu63>;
++ };
++ };
++ };
++ };
++
++ cpu0: cpu@0 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <0>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache0>;
++ mmu-type = "riscv,sv39";
++
++ cpu0_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu1: cpu@1 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <1>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache0>;
++ mmu-type = "riscv,sv39";
++
++ cpu1_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu2: cpu@2 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <2>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache0>;
++ mmu-type = "riscv,sv39";
++
++ cpu2_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu3: cpu@3 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <3>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache0>;
++ mmu-type = "riscv,sv39";
++
++ cpu3_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu4: cpu@4 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <4>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache1>;
++ mmu-type = "riscv,sv39";
++
++ cpu4_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu5: cpu@5 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <5>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache1>;
++ mmu-type = "riscv,sv39";
++
++ cpu5_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu6: cpu@6 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <6>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache1>;
++ mmu-type = "riscv,sv39";
++
++ cpu6_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu7: cpu@7 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <7>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache1>;
++ mmu-type = "riscv,sv39";
++
++ cpu7_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu8: cpu@8 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <8>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache4>;
++ mmu-type = "riscv,sv39";
++
++ cpu8_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu9: cpu@9 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <9>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache4>;
++ mmu-type = "riscv,sv39";
++
++ cpu9_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu10: cpu@10 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <10>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache4>;
++ mmu-type = "riscv,sv39";
++
++ cpu10_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu11: cpu@11 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <11>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache4>;
++ mmu-type = "riscv,sv39";
++
++ cpu11_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu12: cpu@12 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <12>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache5>;
++ mmu-type = "riscv,sv39";
++
++ cpu12_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu13: cpu@13 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <13>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache5>;
++ mmu-type = "riscv,sv39";
++
++ cpu13_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu14: cpu@14 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <14>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache5>;
++ mmu-type = "riscv,sv39";
++
++ cpu14_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu15: cpu@15 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <15>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache5>;
++ mmu-type = "riscv,sv39";
++
++ cpu15_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu16: cpu@16 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <16>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache2>;
++ mmu-type = "riscv,sv39";
++
++ cpu16_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu17: cpu@17 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <17>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache2>;
++ mmu-type = "riscv,sv39";
++
++ cpu17_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu18: cpu@18 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <18>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache2>;
++ mmu-type = "riscv,sv39";
++
++ cpu18_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu19: cpu@19 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <19>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache2>;
++ mmu-type = "riscv,sv39";
++
++ cpu19_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu20: cpu@20 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <20>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache3>;
++ mmu-type = "riscv,sv39";
++
++ cpu20_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu21: cpu@21 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <21>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache3>;
++ mmu-type = "riscv,sv39";
++
++ cpu21_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu22: cpu@22 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <22>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache3>;
++ mmu-type = "riscv,sv39";
++
++ cpu22_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu23: cpu@23 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <23>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache3>;
++ mmu-type = "riscv,sv39";
++
++ cpu23_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu24: cpu@24 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <24>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache6>;
++ mmu-type = "riscv,sv39";
++
++ cpu24_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu25: cpu@25 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <25>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache6>;
++ mmu-type = "riscv,sv39";
++
++ cpu25_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu26: cpu@26 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <26>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache6>;
++ mmu-type = "riscv,sv39";
++
++ cpu26_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu27: cpu@27 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <27>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache6>;
++ mmu-type = "riscv,sv39";
++
++ cpu27_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu28: cpu@28 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <28>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache7>;
++ mmu-type = "riscv,sv39";
++
++ cpu28_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu29: cpu@29 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <29>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache7>;
++ mmu-type = "riscv,sv39";
++
++ cpu29_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu30: cpu@30 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <30>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache7>;
++ mmu-type = "riscv,sv39";
++
++ cpu30_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu31: cpu@31 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <31>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache7>;
++ mmu-type = "riscv,sv39";
++
++ cpu31_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu32: cpu@32 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <32>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache8>;
++ mmu-type = "riscv,sv39";
++
++ cpu32_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu33: cpu@33 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <33>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache8>;
++ mmu-type = "riscv,sv39";
++
++ cpu33_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu34: cpu@34 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <34>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache8>;
++ mmu-type = "riscv,sv39";
++
++ cpu34_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu35: cpu@35 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <35>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache8>;
++ mmu-type = "riscv,sv39";
++
++ cpu35_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu36: cpu@36 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <36>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache9>;
++ mmu-type = "riscv,sv39";
++
++ cpu36_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu37: cpu@37 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <37>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache9>;
++ mmu-type = "riscv,sv39";
++
++ cpu37_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu38: cpu@38 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <38>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache9>;
++ mmu-type = "riscv,sv39";
++
++ cpu38_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu39: cpu@39 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <39>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache9>;
++ mmu-type = "riscv,sv39";
++
++ cpu39_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu40: cpu@40 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <40>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache12>;
++ mmu-type = "riscv,sv39";
++
++ cpu40_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu41: cpu@41 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <41>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache12>;
++ mmu-type = "riscv,sv39";
++
++ cpu41_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu42: cpu@42 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <42>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache12>;
++ mmu-type = "riscv,sv39";
++
++ cpu42_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu43: cpu@43 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <43>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache12>;
++ mmu-type = "riscv,sv39";
++
++ cpu43_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu44: cpu@44 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <44>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache13>;
++ mmu-type = "riscv,sv39";
++
++ cpu44_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu45: cpu@45 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <45>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache13>;
++ mmu-type = "riscv,sv39";
++
++ cpu45_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu46: cpu@46 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <46>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache13>;
++ mmu-type = "riscv,sv39";
++
++ cpu46_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu47: cpu@47 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <47>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache13>;
++ mmu-type = "riscv,sv39";
++
++ cpu47_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu48: cpu@48 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <48>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache10>;
++ mmu-type = "riscv,sv39";
++
++ cpu48_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu49: cpu@49 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <49>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache10>;
++ mmu-type = "riscv,sv39";
++
++ cpu49_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu50: cpu@50 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <50>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache10>;
++ mmu-type = "riscv,sv39";
++
++ cpu50_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu51: cpu@51 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <51>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache10>;
++ mmu-type = "riscv,sv39";
++
++ cpu51_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu52: cpu@52 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <52>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache11>;
++ mmu-type = "riscv,sv39";
++
++ cpu52_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu53: cpu@53 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <53>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache11>;
++ mmu-type = "riscv,sv39";
++
++ cpu53_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu54: cpu@54 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <54>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache11>;
++ mmu-type = "riscv,sv39";
++
++ cpu54_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu55: cpu@55 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <55>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache11>;
++ mmu-type = "riscv,sv39";
++
++ cpu55_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu56: cpu@56 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <56>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache14>;
++ mmu-type = "riscv,sv39";
++
++ cpu56_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu57: cpu@57 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <57>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache14>;
++ mmu-type = "riscv,sv39";
++
++ cpu57_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu58: cpu@58 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <58>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache14>;
++ mmu-type = "riscv,sv39";
++
++ cpu58_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu59: cpu@59 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <59>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache14>;
++ mmu-type = "riscv,sv39";
++
++ cpu59_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu60: cpu@60 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <60>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache15>;
++ mmu-type = "riscv,sv39";
++
++ cpu60_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu61: cpu@61 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <61>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache15>;
++ mmu-type = "riscv,sv39";
++
++ cpu61_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu62: cpu@62 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <62>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache15>;
++ mmu-type = "riscv,sv39";
++
++ cpu62_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ cpu63: cpu@63 {
++ compatible = "thead,c920", "riscv";
++ device_type = "cpu";
++ riscv,isa = "rv64imafdc";
++ reg = <63>;
++ i-cache-block-size = <64>;
++ i-cache-size = <65536>;
++ i-cache-sets = <512>;
++ d-cache-block-size = <64>;
++ d-cache-size = <65536>;
++ d-cache-sets = <512>;
++ next-level-cache = <&l2_cache15>;
++ mmu-type = "riscv,sv39";
++
++ cpu63_intc: interrupt-controller {
++ compatible = "riscv,cpu-intc";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ l2_cache0: l2-cache@0 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache1: l2-cache@1 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache2: l2-cache@2 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache3: l2-cache@3 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache4: l2-cache@4 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache5: l2-cache@5 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache6: l2-cache@6 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache7: l2-cache@7 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache8: l2-cache@8 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache9: l2-cache@9 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache10: l2-cache@10 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache11: l2-cache@11 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache12: l2-cache@12 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache13: l2-cache@13 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache14: l2-cache@14 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++
++ l2_cache15: l2-cache@15 {
++ compatible = "cache";
++ cache-block-size = <64>;
++ cache-level = <2>;
++ cache-size = <1048576>;
++ cache-sets = <1024>;
++ cache-unified;
++ };
++ };
++};
+diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi
+new file mode 100644
+index 000000000000..747fd9764c95
+--- /dev/null
++++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi
+@@ -0,0 +1,439 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved.
++ */
++
++/dts-v1/;
++#include <dt-bindings/interrupt-controller/irq.h>
++
++#include "sg2042-cpus.dtsi"
++
++#define SOC_PERIPHERAL_IRQ(nr) (nr)
++
++/ {
++ compatible = "sophgo,sg2042";
++ #address-cells = <2>;
++ #size-cells = <2>;
++ dma-noncoherent;
++
++ aliases {
++ serial0 = &uart0;
++ };
++
++ /* the mem node will be updated by ZSBL. */
++ memory@0 {
++ device_type = "memory";
++ reg = <0x00000000 0x00000000 0x00000000 0x00000000>;
++ };
++
++ memory@1 {
++ device_type = "memory";
++ reg = <0x00000000 0x00000001 0x00000000 0x00000000>;
++ };
++
++ memory@2 {
++ device_type = "memory";
++ reg = <0x00000000 0x00000002 0x00000000 0x00000000>;
++ };
++
++ memory@3 {
++ device_type = "memory";
++ reg = <0x00000000 0x00000003 0x00000000 0x00000000>;
++ };
++
++ pmu {
++ compatible = "riscv,pmu";
++ riscv,event-to-mhpmevent =
++ <0x00003 0x00000000 0x00000010>,
++ <0x00004 0x00000000 0x00000011>,
++ <0x00005 0x00000000 0x00000007>,
++ <0x00006 0x00000000 0x00000006>,
++ <0x00008 0x00000000 0x00000027>,
++ <0x00009 0x00000000 0x00000028>,
++ <0x10000 0x00000000 0x0000000c>,
++ <0x10001 0x00000000 0x0000000d>,
++ <0x10002 0x00000000 0x0000000e>,
++ <0x10003 0x00000000 0x0000000f>,
++ <0x10008 0x00000000 0x00000001>,
++ <0x10009 0x00000000 0x00000002>,
++ <0x10010 0x00000000 0x00000010>,
++ <0x10011 0x00000000 0x00000011>,
++ <0x10012 0x00000000 0x00000012>,
++ <0x10013 0x00000000 0x00000013>,
++ <0x10019 0x00000000 0x00000004>,
++ <0x10021 0x00000000 0x00000003>,
++ <0x10030 0x00000000 0x0000001c>,
++ <0x10031 0x00000000 0x0000001b>;
++ riscv,event-to-mhpmcounters =
++ <0x00003 0x00003 0xfffffff8>,
++ <0x00004 0x00004 0xfffffff8>,
++ <0x00005 0x00005 0xfffffff8>,
++ <0x00006 0x00006 0xfffffff8>,
++ <0x00007 0x00007 0xfffffff8>,
++ <0x00008 0x00008 0xfffffff8>,
++ <0x00009 0x00009 0xfffffff8>,
++ <0x0000a 0x0000a 0xfffffff8>,
++ <0x10000 0x10000 0xfffffff8>,
++ <0x10001 0x10001 0xfffffff8>,
++ <0x10002 0x10002 0xfffffff8>,
++ <0x10003 0x10003 0xfffffff8>,
++ <0x10008 0x10008 0xfffffff8>,
++ <0x10009 0x10009 0xfffffff8>,
++ <0x10010 0x10010 0xfffffff8>,
++ <0x10011 0x10011 0xfffffff8>,
++ <0x10012 0x10012 0xfffffff8>,
++ <0x10013 0x10013 0xfffffff8>,
++ <0x10019 0x10019 0xfffffff8>,
++ <0x10021 0x10021 0xfffffff8>,
++ <0x10030 0x10030 0xfffffff8>,
++ <0x10031 0x10031 0xfffffff8>;
++ riscv,raw-event-to-mhpmcounters =
++ <0x00000000 0x00000001 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000002 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000003 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000004 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000005 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000006 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000007 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000008 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000009 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000000a 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000000b 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000000c 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000000d 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000000e 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000000f 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000010 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000011 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000012 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000013 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000014 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000015 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000016 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000017 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000018 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000019 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000001a 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000001b 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000001c 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000001d 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000001e 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000001f 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000020 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000021 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000022 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000023 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000024 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000025 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000026 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000027 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000028 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x00000029 0xffffffff 0xffffffff 0xfffffff8>,
++ <0x00000000 0x0000002a 0xffffffff 0xffffffff 0xfffffff8>;
++ };
++
++ soc: soc {
++ compatible = "simple-bus";
++ #address-cells = <2>;
++ #size-cells = <2>;
++ ranges;
++
++ clint_mswi: interrupt-controller@7094000000 {
++ compatible = "sophgo,sg2042-clint-mswi", "thead,c900-clint-mswi";
++ reg = <0x00000070 0x94000000 0x00000000 0x00004000>;
++ interrupts-extended = <&cpu0_intc 3>,
++ <&cpu1_intc 3>,
++ <&cpu2_intc 3>,
++ <&cpu3_intc 3>,
++ <&cpu4_intc 3>,
++ <&cpu5_intc 3>,
++ <&cpu6_intc 3>,
++ <&cpu7_intc 3>,
++ <&cpu8_intc 3>,
++ <&cpu9_intc 3>,
++ <&cpu10_intc 3>,
++ <&cpu11_intc 3>,
++ <&cpu12_intc 3>,
++ <&cpu13_intc 3>,
++ <&cpu14_intc 3>,
++ <&cpu15_intc 3>,
++ <&cpu16_intc 3>,
++ <&cpu17_intc 3>,
++ <&cpu18_intc 3>,
++ <&cpu19_intc 3>,
++ <&cpu20_intc 3>,
++ <&cpu21_intc 3>,
++ <&cpu22_intc 3>,
++ <&cpu23_intc 3>,
++ <&cpu24_intc 3>,
++ <&cpu25_intc 3>,
++ <&cpu26_intc 3>,
++ <&cpu27_intc 3>,
++ <&cpu28_intc 3>,
++ <&cpu29_intc 3>,
++ <&cpu30_intc 3>,
++ <&cpu31_intc 3>,
++ <&cpu32_intc 3>,
++ <&cpu33_intc 3>,
++ <&cpu34_intc 3>,
++ <&cpu35_intc 3>,
++ <&cpu36_intc 3>,
++ <&cpu37_intc 3>,
++ <&cpu38_intc 3>,
++ <&cpu39_intc 3>,
++ <&cpu40_intc 3>,
++ <&cpu41_intc 3>,
++ <&cpu42_intc 3>,
++ <&cpu43_intc 3>,
++ <&cpu44_intc 3>,
++ <&cpu45_intc 3>,
++ <&cpu46_intc 3>,
++ <&cpu47_intc 3>,
++ <&cpu48_intc 3>,
++ <&cpu49_intc 3>,
++ <&cpu50_intc 3>,
++ <&cpu51_intc 3>,
++ <&cpu52_intc 3>,
++ <&cpu53_intc 3>,
++ <&cpu54_intc 3>,
++ <&cpu55_intc 3>,
++ <&cpu56_intc 3>,
++ <&cpu57_intc 3>,
++ <&cpu58_intc 3>,
++ <&cpu59_intc 3>,
++ <&cpu60_intc 3>,
++ <&cpu61_intc 3>,
++ <&cpu62_intc 3>,
++ <&cpu63_intc 3>;
++ };
++
++ clint_mtimer0: timer@70ac000000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac000000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu0_intc 7>,
++ <&cpu1_intc 7>,
++ <&cpu2_intc 7>,
++ <&cpu3_intc 7>;
++ };
++
++ clint_mtimer1: timer@70ac010000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac010000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu4_intc 7>,
++ <&cpu5_intc 7>,
++ <&cpu6_intc 7>,
++ <&cpu7_intc 7>;
++ };
++
++ clint_mtimer2: timer@70ac020000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac020000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu8_intc 7>,
++ <&cpu9_intc 7>,
++ <&cpu10_intc 7>,
++ <&cpu11_intc 7>;
++ };
++
++ clint_mtimer3: timer@70ac030000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac030000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu12_intc 7>,
++ <&cpu13_intc 7>,
++ <&cpu14_intc 7>,
++ <&cpu15_intc 7>;
++ };
++
++ clint_mtimer4: timer@70ac040000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac040000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu16_intc 7>,
++ <&cpu17_intc 7>,
++ <&cpu18_intc 7>,
++ <&cpu19_intc 7>;
++ };
++
++ clint_mtimer5: timer@70ac050000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac050000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu20_intc 7>,
++ <&cpu21_intc 7>,
++ <&cpu22_intc 7>,
++ <&cpu23_intc 7>;
++ };
++
++ clint_mtimer6: timer@70ac060000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac060000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu24_intc 7>,
++ <&cpu25_intc 7>,
++ <&cpu26_intc 7>,
++ <&cpu27_intc 7>;
++ };
++
++ clint_mtimer7: timer@70ac070000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac070000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu28_intc 7>,
++ <&cpu29_intc 7>,
++ <&cpu30_intc 7>,
++ <&cpu31_intc 7>;
++ };
++
++ clint_mtimer8: timer@70ac080000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac080000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu32_intc 7>,
++ <&cpu33_intc 7>,
++ <&cpu34_intc 7>,
++ <&cpu35_intc 7>;
++ };
++
++ clint_mtimer9: timer@70ac090000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac090000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu36_intc 7>,
++ <&cpu37_intc 7>,
++ <&cpu38_intc 7>,
++ <&cpu39_intc 7>;
++ };
++
++ clint_mtimer10: timer@70ac0a0000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac0a0000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu40_intc 7>,
++ <&cpu41_intc 7>,
++ <&cpu42_intc 7>,
++ <&cpu43_intc 7>;
++ };
++
++ clint_mtimer11: timer@70ac0b0000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac0b0000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu44_intc 7>,
++ <&cpu45_intc 7>,
++ <&cpu46_intc 7>,
++ <&cpu47_intc 7>;
++ };
++
++ clint_mtimer12: timer@70ac0c0000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac0c0000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu48_intc 7>,
++ <&cpu49_intc 7>,
++ <&cpu50_intc 7>,
++ <&cpu51_intc 7>;
++ };
++
++ clint_mtimer13: timer@70ac0d0000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac0d0000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu52_intc 7>,
++ <&cpu53_intc 7>,
++ <&cpu54_intc 7>,
++ <&cpu55_intc 7>;
++ };
++
++ clint_mtimer14: timer@70ac0e0000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac0e0000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu56_intc 7>,
++ <&cpu57_intc 7>,
++ <&cpu58_intc 7>,
++ <&cpu59_intc 7>;
++ };
++
++ clint_mtimer15: timer@70ac0f0000 {
++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer";
++ reg = <0x00000070 0xac0f0000 0x00000000 0x00007ff8>;
++ interrupts-extended = <&cpu60_intc 7>,
++ <&cpu61_intc 7>,
++ <&cpu62_intc 7>,
++ <&cpu63_intc 7>;
++ };
++
++ intc: interrupt-controller@7090000000 {
++ compatible = "sophgo,sg2042-plic", "thead,c900-plic";
++ #address-cells = <0>;
++ #interrupt-cells = <2>;
++ reg = <0x00000070 0x90000000 0x00000000 0x04000000>;
++ interrupt-controller;
++ interrupts-extended =
++ <&cpu0_intc 0xffffffff>, <&cpu0_intc 9>,
++ <&cpu1_intc 0xffffffff>, <&cpu1_intc 9>,
++ <&cpu2_intc 0xffffffff>, <&cpu2_intc 9>,
++ <&cpu3_intc 0xffffffff>, <&cpu3_intc 9>,
++ <&cpu4_intc 0xffffffff>, <&cpu4_intc 9>,
++ <&cpu5_intc 0xffffffff>, <&cpu5_intc 9>,
++ <&cpu6_intc 0xffffffff>, <&cpu6_intc 9>,
++ <&cpu7_intc 0xffffffff>, <&cpu7_intc 9>,
++ <&cpu8_intc 0xffffffff>, <&cpu8_intc 9>,
++ <&cpu9_intc 0xffffffff>, <&cpu9_intc 9>,
++ <&cpu10_intc 0xffffffff>, <&cpu10_intc 9>,
++ <&cpu11_intc 0xffffffff>, <&cpu11_intc 9>,
++ <&cpu12_intc 0xffffffff>, <&cpu12_intc 9>,
++ <&cpu13_intc 0xffffffff>, <&cpu13_intc 9>,
++ <&cpu14_intc 0xffffffff>, <&cpu14_intc 9>,
++ <&cpu15_intc 0xffffffff>, <&cpu15_intc 9>,
++ <&cpu16_intc 0xffffffff>, <&cpu16_intc 9>,
++ <&cpu17_intc 0xffffffff>, <&cpu17_intc 9>,
++ <&cpu18_intc 0xffffffff>, <&cpu18_intc 9>,
++ <&cpu19_intc 0xffffffff>, <&cpu19_intc 9>,
++ <&cpu20_intc 0xffffffff>, <&cpu20_intc 9>,
++ <&cpu21_intc 0xffffffff>, <&cpu21_intc 9>,
++ <&cpu22_intc 0xffffffff>, <&cpu22_intc 9>,
++ <&cpu23_intc 0xffffffff>, <&cpu23_intc 9>,
++ <&cpu24_intc 0xffffffff>, <&cpu24_intc 9>,
++ <&cpu25_intc 0xffffffff>, <&cpu25_intc 9>,
++ <&cpu26_intc 0xffffffff>, <&cpu26_intc 9>,
++ <&cpu27_intc 0xffffffff>, <&cpu27_intc 9>,
++ <&cpu28_intc 0xffffffff>, <&cpu28_intc 9>,
++ <&cpu29_intc 0xffffffff>, <&cpu29_intc 9>,
++ <&cpu30_intc 0xffffffff>, <&cpu30_intc 9>,
++ <&cpu31_intc 0xffffffff>, <&cpu31_intc 9>,
++ <&cpu32_intc 0xffffffff>, <&cpu32_intc 9>,
++ <&cpu33_intc 0xffffffff>, <&cpu33_intc 9>,
++ <&cpu34_intc 0xffffffff>, <&cpu34_intc 9>,
++ <&cpu35_intc 0xffffffff>, <&cpu35_intc 9>,
++ <&cpu36_intc 0xffffffff>, <&cpu36_intc 9>,
++ <&cpu37_intc 0xffffffff>, <&cpu37_intc 9>,
++ <&cpu38_intc 0xffffffff>, <&cpu38_intc 9>,
++ <&cpu39_intc 0xffffffff>, <&cpu39_intc 9>,
++ <&cpu40_intc 0xffffffff>, <&cpu40_intc 9>,
++ <&cpu41_intc 0xffffffff>, <&cpu41_intc 9>,
++ <&cpu42_intc 0xffffffff>, <&cpu42_intc 9>,
++ <&cpu43_intc 0xffffffff>, <&cpu43_intc 9>,
++ <&cpu44_intc 0xffffffff>, <&cpu44_intc 9>,
++ <&cpu45_intc 0xffffffff>, <&cpu45_intc 9>,
++ <&cpu46_intc 0xffffffff>, <&cpu46_intc 9>,
++ <&cpu47_intc 0xffffffff>, <&cpu47_intc 9>,
++ <&cpu48_intc 0xffffffff>, <&cpu48_intc 9>,
++ <&cpu49_intc 0xffffffff>, <&cpu49_intc 9>,
++ <&cpu50_intc 0xffffffff>, <&cpu50_intc 9>,
++ <&cpu51_intc 0xffffffff>, <&cpu51_intc 9>,
++ <&cpu52_intc 0xffffffff>, <&cpu52_intc 9>,
++ <&cpu53_intc 0xffffffff>, <&cpu53_intc 9>,
++ <&cpu54_intc 0xffffffff>, <&cpu54_intc 9>,
++ <&cpu55_intc 0xffffffff>, <&cpu55_intc 9>,
++ <&cpu56_intc 0xffffffff>, <&cpu56_intc 9>,
++ <&cpu57_intc 0xffffffff>, <&cpu57_intc 9>,
++ <&cpu58_intc 0xffffffff>, <&cpu58_intc 9>,
++ <&cpu59_intc 0xffffffff>, <&cpu59_intc 9>,
++ <&cpu60_intc 0xffffffff>, <&cpu60_intc 9>,
++ <&cpu61_intc 0xffffffff>, <&cpu61_intc 9>,
++ <&cpu62_intc 0xffffffff>, <&cpu62_intc 9>,
++ <&cpu63_intc 0xffffffff>, <&cpu63_intc 9>;
++ riscv,ndev = <224>;
++ };
++
++ uart0: serial@7040000000 {
++ compatible = "sophgo,sg2042-uart", "snps,dw-apb-uart";
++ reg = <0x00000070 0x40000000 0x00000000 0x00001000>;
++ interrupt-parent = <&intc>;
++ interrupts = <SOC_PERIPHERAL_IRQ(112) IRQ_TYPE_LEVEL_HIGH>;
++ clock-frequency = <500000000>;
++ reg-shift = <2>;
++ reg-io-width = <4>;
++ status = "disabled";
++ };
++ };
++};
+--
+2.20.1
+
--- /dev/null
+From ff1199b26c397a8dfd94a72565c515c20474f468 Mon Sep 17 00:00:00 2001
+From: Inochi Amaoto <inochiama@outlook.com>
+Date: Tue, 13 Feb 2024 16:22:34 +0800
+Subject: [PATCH 12/18] clk: sophgo: Add CV1800/SG2000 series clock controller
+ driver skeleton
+
+Add driver skeleton for CV1800/SG2000 series clock controller.
+The skeleton code includes:
+1. common utility code for clk_ops implementation
+2. basic probe code of the whole driver
+3. helper structure for clk definition
+
+Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
+---
+ arch/riscv/boot/dts/sophgo/cv1800b.dtsi | 4 +
+ arch/riscv/boot/dts/sophgo/cv1812h.dtsi | 4 +
+ arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 22 +-
+ drivers/clk/Kconfig | 1 +
+ drivers/clk/Makefile | 1 +
+ drivers/clk/sophgo/Kconfig | 12 +
+ drivers/clk/sophgo/Makefile | 7 +
+ drivers/clk/sophgo/clk-cv1800.c | 1541 +++++++++++++++++++++++
+ drivers/clk/sophgo/clk-cv1800.h | 123 ++
+ drivers/clk/sophgo/clk-cv18xx-common.c | 66 +
+ drivers/clk/sophgo/clk-cv18xx-common.h | 81 ++
+ drivers/clk/sophgo/clk-cv18xx-ip.c | 887 +++++++++++++
+ drivers/clk/sophgo/clk-cv18xx-ip.h | 261 ++++
+ drivers/clk/sophgo/clk-cv18xx-pll.c | 420 ++++++
+ drivers/clk/sophgo/clk-cv18xx-pll.h | 118 ++
+ 15 files changed, 3543 insertions(+), 5 deletions(-)
+ create mode 100644 drivers/clk/sophgo/Kconfig
+ create mode 100644 drivers/clk/sophgo/Makefile
+ create mode 100644 drivers/clk/sophgo/clk-cv1800.c
+ create mode 100644 drivers/clk/sophgo/clk-cv1800.h
+ create mode 100644 drivers/clk/sophgo/clk-cv18xx-common.c
+ create mode 100644 drivers/clk/sophgo/clk-cv18xx-common.h
+ create mode 100644 drivers/clk/sophgo/clk-cv18xx-ip.c
+ create mode 100644 drivers/clk/sophgo/clk-cv18xx-ip.h
+ create mode 100644 drivers/clk/sophgo/clk-cv18xx-pll.c
+ create mode 100644 drivers/clk/sophgo/clk-cv18xx-pll.h
+
+diff --git a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi
+index 165e9e320a8c..baf641829e72 100644
+--- a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi
++++ b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi
+@@ -16,3 +16,7 @@
+ &clint {
+ compatible = "sophgo,cv1800b-clint", "thead,c900-clint";
+ };
++
++&clk {
++ compatible = "sophgo,cv1800-clk";
++};
+diff --git a/arch/riscv/boot/dts/sophgo/cv1812h.dtsi b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi
+index 3e7a942f5c1a..7fa4c1e2d1da 100644
+--- a/arch/riscv/boot/dts/sophgo/cv1812h.dtsi
++++ b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi
+@@ -22,3 +22,7 @@
+ &clint {
+ compatible = "sophgo,cv1812h-clint", "thead,c900-clint";
+ };
++
++&clk {
++ compatible = "sophgo,cv1810-clk";
++};
+diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi
+index d415cc758def..e375e9d9516e 100644
+--- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi
++++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi
+@@ -5,6 +5,7 @@
+ */
+
+ #include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/clock/sophgo,cv1800.h>
+
+ / {
+ #address-cells = <1>;
+@@ -54,6 +55,12 @@
+ dma-noncoherent;
+ ranges;
+
++ clk: clock-controller@3002000 {
++ reg = <0x03002000 0x1000>;
++ clocks = <&osc>;
++ #clock-cells = <1>;
++ };
++
+ gpio0: gpio@3020000 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x3020000 0x1000>;
+@@ -130,7 +137,8 @@
+ compatible = "snps,dw-apb-uart";
+ reg = <0x04140000 0x100>;
+ interrupts = <44 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&osc>;
++ clocks = <&clk CLK_UART0>, <&clk CLK_APB_UART0>;
++ clock-names = "baudclk", "apb_pclk";
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+@@ -140,7 +148,8 @@
+ compatible = "snps,dw-apb-uart";
+ reg = <0x04150000 0x100>;
+ interrupts = <45 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&osc>;
++ clocks = <&clk CLK_UART1>, <&clk CLK_APB_UART1>;
++ clock-names = "baudclk", "apb_pclk";
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+@@ -150,7 +159,8 @@
+ compatible = "snps,dw-apb-uart";
+ reg = <0x04160000 0x100>;
+ interrupts = <46 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&osc>;
++ clocks = <&clk CLK_UART2>, <&clk CLK_APB_UART2>;
++ clock-names = "baudclk", "apb_pclk";
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+@@ -160,7 +170,8 @@
+ compatible = "snps,dw-apb-uart";
+ reg = <0x04170000 0x100>;
+ interrupts = <47 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&osc>;
++ clocks = <&clk CLK_UART3>, <&clk CLK_APB_UART3>;
++ clock-names = "baudclk", "apb_pclk";
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+@@ -170,7 +181,8 @@
+ compatible = "snps,dw-apb-uart";
+ reg = <0x041c0000 0x100>;
+ interrupts = <48 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&osc>;
++ clocks = <&clk CLK_UART4>, <&clk CLK_APB_UART4>;
++ clock-names = "baudclk", "apb_pclk";
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
+index c30099866174..f3ec23f22e3e 100644
+--- a/drivers/clk/Kconfig
++++ b/drivers/clk/Kconfig
+@@ -490,6 +490,7 @@ source "drivers/clk/rockchip/Kconfig"
+ source "drivers/clk/samsung/Kconfig"
+ source "drivers/clk/sifive/Kconfig"
+ source "drivers/clk/socfpga/Kconfig"
++source "drivers/clk/sophgo/Kconfig"
+ source "drivers/clk/sprd/Kconfig"
+ source "drivers/clk/starfive/Kconfig"
+ source "drivers/clk/sunxi/Kconfig"
+diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
+index 18969cbd4bb1..acac827d906a 100644
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -117,6 +117,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
+ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
+ obj-$(CONFIG_CLK_SIFIVE) += sifive/
+ obj-y += socfpga/
++obj-y += sophgo/
+ obj-$(CONFIG_PLAT_SPEAR) += spear/
+ obj-y += sprd/
+ obj-$(CONFIG_ARCH_STI) += st/
+diff --git a/drivers/clk/sophgo/Kconfig b/drivers/clk/sophgo/Kconfig
+new file mode 100644
+index 000000000000..d67009fa749f
+--- /dev/null
++++ b/drivers/clk/sophgo/Kconfig
+@@ -0,0 +1,12 @@
++# SPDX-License-Identifier: GPL-2.0
++# common clock support for SOPHGO SoC family.
++
++config CLK_SOPHGO_CV1800
++ tristate "Support for the Sophgo CV1800 series SoCs clock controller"
++ default m
++ depends on ARCH_SOPHGO || COMPILE_TEST
++ help
++ This driver supports clock controller of Sophgo CV18XX series SoC.
++ The driver require a 25MHz Oscillator to function generate clock.
++ It includes PLLs, common clock function and some vendor clock for
++ IPs of CV18XX series SoC
+diff --git a/drivers/clk/sophgo/Makefile b/drivers/clk/sophgo/Makefile
+new file mode 100644
+index 000000000000..a50320764200
+--- /dev/null
++++ b/drivers/clk/sophgo/Makefile
+@@ -0,0 +1,7 @@
++# SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_CLK_SOPHGO_CV1800) += clk-sophgo-cv1800.o
++
++clk-sophgo-cv1800-y += clk-cv1800.o
++clk-sophgo-cv1800-y += clk-cv18xx-common.o
++clk-sophgo-cv1800-y += clk-cv18xx-ip.o
++clk-sophgo-cv1800-y += clk-cv18xx-pll.o
+diff --git a/drivers/clk/sophgo/clk-cv1800.c b/drivers/clk/sophgo/clk-cv1800.c
+new file mode 100644
+index 000000000000..1aedf2df242c
+--- /dev/null
++++ b/drivers/clk/sophgo/clk-cv1800.c
+@@ -0,0 +1,1541 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
++ */
++
++#include <linux/module.h>
++#include <linux/clk-provider.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/spinlock.h>
++
++#include "clk-cv1800.h"
++
++#include "clk-cv18xx-common.h"
++#include "clk-cv18xx-ip.h"
++#include "clk-cv18xx-pll.h"
++
++struct cv1800_clk_ctrl;
++
++struct cv1800_clk_desc {
++ struct clk_hw_onecell_data *clks_data;
++
++ int (*pre_init)(struct device *dev, void __iomem *base,
++ struct cv1800_clk_ctrl *ctrl,
++ const struct cv1800_clk_desc *desc);
++};
++
++struct cv1800_clk_ctrl {
++ const struct cv1800_clk_desc *desc;
++ spinlock_t lock;
++};
++
++#define CV1800_DIV_FLAG \
++ (CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ROUND_CLOSEST)
++static const struct clk_parent_data osc_parents[] = {
++ { .index = 0 },
++};
++
++static const struct cv1800_clk_pll_limit pll_limits[] = {
++ {
++ .pre_div = _CV1800_PLL_LIMIT(1, 127),
++ .div = _CV1800_PLL_LIMIT(6, 127),
++ .post_div = _CV1800_PLL_LIMIT(1, 127),
++ .ictrl = _CV1800_PLL_LIMIT(0, 7),
++ .mode = _CV1800_PLL_LIMIT(0, 3),
++ },
++ {
++ .pre_div = _CV1800_PLL_LIMIT(1, 127),
++ .div = _CV1800_PLL_LIMIT(6, 127),
++ .post_div = _CV1800_PLL_LIMIT(1, 127),
++ .ictrl = _CV1800_PLL_LIMIT(0, 7),
++ .mode = _CV1800_PLL_LIMIT(0, 3),
++ },
++};
++
++static CV1800_INTEGRAL_PLL(clk_fpll, osc_parents,
++ REG_FPLL_CSR,
++ REG_PLL_G6_CTRL, 8,
++ REG_PLL_G6_STATUS, 2,
++ pll_limits,
++ CLK_IS_CRITICAL);
++
++static CV1800_INTEGRAL_PLL(clk_mipimpll, osc_parents,
++ REG_MIPIMPLL_CSR,
++ REG_PLL_G2_CTRL, 0,
++ REG_PLL_G2_STATUS, 0,
++ pll_limits,
++ CLK_IS_CRITICAL);
++
++static const struct clk_parent_data clk_mipimpll_parents[] = {
++ { .hw = &clk_mipimpll.common.hw },
++};
++static const struct clk_parent_data clk_bypass_mipimpll_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_mipimpll.common.hw },
++};
++static const struct clk_parent_data clk_bypass_fpll_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_fpll.common.hw },
++};
++
++struct cv1800_clk_pll_synthesizer clk_mpll_synthesizer = {
++ .en = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 2),
++ .clk_half = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 0),
++ .ctrl = REG_MPLL_SSC_SYN_CTRL,
++ .set = REG_MPLL_SSC_SYN_SET,
++};
++static CV1800_FACTIONAL_PLL(clk_mpll, clk_bypass_mipimpll_parents,
++ REG_MPLL_CSR,
++ REG_PLL_G6_CTRL, 0,
++ REG_PLL_G6_STATUS, 0,
++ pll_limits,
++ &clk_mpll_synthesizer,
++ CLK_IS_CRITICAL);
++
++struct cv1800_clk_pll_synthesizer clk_tpll_synthesizer = {
++ .en = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 3),
++ .clk_half = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 0),
++ .ctrl = REG_TPLL_SSC_SYN_CTRL,
++ .set = REG_TPLL_SSC_SYN_SET,
++};
++static CV1800_FACTIONAL_PLL(clk_tpll, clk_bypass_mipimpll_parents,
++ REG_TPLL_CSR,
++ REG_PLL_G6_CTRL, 4,
++ REG_PLL_G6_STATUS, 1,
++ pll_limits,
++ &clk_tpll_synthesizer,
++ CLK_IS_CRITICAL);
++
++struct cv1800_clk_pll_synthesizer clk_a0pll_synthesizer = {
++ .en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 2),
++ .clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0),
++ .ctrl = REG_A0PLL_SSC_SYN_CTRL,
++ .set = REG_A0PLL_SSC_SYN_SET,
++};
++static CV1800_FACTIONAL_PLL(clk_a0pll, clk_bypass_mipimpll_parents,
++ REG_A0PLL_CSR,
++ REG_PLL_G2_CTRL, 4,
++ REG_PLL_G2_STATUS, 1,
++ pll_limits,
++ &clk_a0pll_synthesizer,
++ CLK_IS_CRITICAL);
++
++struct cv1800_clk_pll_synthesizer clk_disppll_synthesizer = {
++ .en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 3),
++ .clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0),
++ .ctrl = REG_DISPPLL_SSC_SYN_CTRL,
++ .set = REG_DISPPLL_SSC_SYN_SET,
++};
++static CV1800_FACTIONAL_PLL(clk_disppll, clk_bypass_mipimpll_parents,
++ REG_DISPPLL_CSR,
++ REG_PLL_G2_CTRL, 8,
++ REG_PLL_G2_STATUS, 2,
++ pll_limits,
++ &clk_disppll_synthesizer,
++ CLK_IS_CRITICAL);
++
++struct cv1800_clk_pll_synthesizer clk_cam0pll_synthesizer = {
++ .en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 4),
++ .clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0),
++ .ctrl = REG_CAM0PLL_SSC_SYN_CTRL,
++ .set = REG_CAM0PLL_SSC_SYN_SET,
++};
++static CV1800_FACTIONAL_PLL(clk_cam0pll, clk_bypass_mipimpll_parents,
++ REG_CAM0PLL_CSR,
++ REG_PLL_G2_CTRL, 12,
++ REG_PLL_G2_STATUS, 3,
++ pll_limits,
++ &clk_cam0pll_synthesizer,
++ CLK_IGNORE_UNUSED);
++
++struct cv1800_clk_pll_synthesizer clk_cam1pll_synthesizer = {
++ .en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 5),
++ .clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0),
++ .ctrl = REG_CAM1PLL_SSC_SYN_CTRL,
++ .set = REG_CAM1PLL_SSC_SYN_SET,
++};
++static CV1800_FACTIONAL_PLL(clk_cam1pll, clk_bypass_mipimpll_parents,
++ REG_CAM1PLL_CSR,
++ REG_PLL_G2_CTRL, 16,
++ REG_PLL_G2_STATUS, 4,
++ pll_limits,
++ &clk_cam1pll_synthesizer,
++ CLK_IS_CRITICAL);
++
++static const struct clk_parent_data clk_cam0pll_parents[] = {
++ { .hw = &clk_cam0pll.common.hw },
++};
++
++/* G2D */
++static CV1800_FIXED_DIV(clk_cam0pll_d2, clk_cam0pll_parents,
++ REG_CAM0PLL_CLK_CSR, 1,
++ 2,
++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
++static CV1800_FIXED_DIV(clk_cam0pll_d3, clk_cam0pll_parents,
++ REG_CAM0PLL_CLK_CSR, 2,
++ 3,
++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
++static CV1800_FIXED_DIV(clk_mipimpll_d3, clk_mipimpll_parents,
++ REG_MIPIMPLL_CLK_CSR, 2,
++ 3,
++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
++
++/* TPU */
++static const struct clk_parent_data clk_tpu_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_tpll.common.hw },
++ { .hw = &clk_a0pll.common.hw },
++ { .hw = &clk_mipimpll.common.hw },
++ { .hw = &clk_fpll.common.hw },
++};
++
++static CV1800_BYPASS_MUX(clk_tpu, clk_tpu_parents,
++ REG_CLK_EN_0, 4,
++ REG_DIV_CLK_TPU, 16, 4, 3, CV1800_DIV_FLAG,
++ REG_DIV_CLK_TPU, 8, 2,
++ REG_CLK_BYP_0, 3,
++ 0);
++static CV1800_GATE(clk_tpu_fab, clk_mipimpll_parents,
++ REG_CLK_EN_0, 5,
++ 0);
++
++/* FABRIC_AXI6 */
++static CV1800_BYPASS_DIV(clk_axi6, clk_bypass_fpll_parents,
++ REG_CLK_EN_2, 2,
++ REG_DIV_CLK_AXI6, 16, 4, 15, CV1800_DIV_FLAG,
++ REG_CLK_BYP_0, 20,
++ CLK_IS_CRITICAL);
++
++static const struct clk_parent_data clk_axi6_bus_parents[] = {
++ { .hw = &clk_axi6.div.common.hw },
++};
++static const struct clk_parent_data clk_bypass_axi6_bus_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_axi6.div.common.hw },
++};
++
++/* FABRIC_AXI4 */
++static const struct clk_parent_data clk_axi4_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_fpll.common.hw },
++ { .hw = &clk_disppll.common.hw },
++};
++
++static CV1800_BYPASS_MUX(clk_axi4, clk_axi4_parents,
++ REG_CLK_EN_2, 1,
++ REG_DIV_CLK_AXI4, 16, 4, 5, CV1800_DIV_FLAG,
++ REG_DIV_CLK_AXI4, 8, 2,
++ REG_CLK_BYP_0, 19,
++ CLK_IS_CRITICAL);
++
++static const struct clk_parent_data clk_axi4_bus_parents[] = {
++ { .hw = &clk_axi4.mux.common.hw },
++};
++
++/* XTAL_MISC */
++static CV1800_GATE(clk_xtal_misc, osc_parents,
++ REG_CLK_EN_0, 14,
++ CLK_IS_CRITICAL);
++
++static const struct clk_parent_data clk_timer_parents[] = {
++ { .hw = &clk_xtal_misc.common.hw },
++};
++
++/* TOP */
++static const struct clk_parent_data clk_cam0_200_parents[] = {
++ { .index = 0 },
++ { .index = 0 },
++ { .hw = &clk_disppll.common.hw },
++};
++
++static CV1800_BYPASS_MUX(clk_cam0_200, clk_cam0_200_parents,
++ REG_CLK_EN_1, 13,
++ REG_DIV_CLK_CAM0_200, 16, 4, 1, CV1800_DIV_FLAG,
++ REG_DIV_CLK_CAM0_200, 8, 2,
++ REG_CLK_BYP_0, 16,
++ CLK_IS_CRITICAL);
++static CV1800_DIV(clk_1m, osc_parents,
++ REG_CLK_EN_3, 5,
++ REG_DIV_CLK_1M, 16, 6, 25, CV1800_DIV_FLAG,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_pm, clk_axi6_bus_parents,
++ REG_CLK_EN_3, 8,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_timer0, clk_timer_parents,
++ REG_CLK_EN_3, 9,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_timer1, clk_timer_parents,
++ REG_CLK_EN_3, 10,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_timer2, clk_timer_parents,
++ REG_CLK_EN_3, 11,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_timer3, clk_timer_parents,
++ REG_CLK_EN_3, 12,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_timer4, clk_timer_parents,
++ REG_CLK_EN_3, 13,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_timer5, clk_timer_parents,
++ REG_CLK_EN_3, 14,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_timer6, clk_timer_parents,
++ REG_CLK_EN_3, 15,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_timer7, clk_timer_parents,
++ REG_CLK_EN_3, 16,
++ CLK_IS_CRITICAL);
++
++static const struct clk_parent_data clk_parents_1m[] = {
++ { .hw = &clk_1m.common.hw },
++};
++static const struct clk_parent_data clk_uart_parents[] = {
++ { .hw = &clk_cam0_200.mux.common.hw },
++};
++
++/* AHB ROM */
++static CV1800_GATE(clk_ahb_rom, clk_axi4_bus_parents,
++ REG_CLK_EN_0, 6,
++ 0);
++
++/* RTC */
++static CV1800_GATE(clk_rtc_25m, osc_parents,
++ REG_CLK_EN_0, 8,
++ CLK_IS_CRITICAL);
++static CV1800_BYPASS_DIV(clk_src_rtc_sys_0, clk_bypass_fpll_parents,
++ REG_CLK_EN_4, 6,
++ REG_DIV_CLK_RTCSYS_SRC_0, 16, 4, 5, CV1800_DIV_FLAG,
++ REG_CLK_BYP_1, 5,
++ CLK_IS_CRITICAL);
++
++/* TEMPSEN */
++static CV1800_GATE(clk_tempsen, osc_parents,
++ REG_CLK_EN_0, 9,
++ 0);
++
++/* SARADC */
++static CV1800_GATE(clk_saradc, osc_parents,
++ REG_CLK_EN_0, 10,
++ 0);
++
++/* EFUSE */
++static CV1800_GATE(clk_efuse, osc_parents,
++ REG_CLK_EN_0, 11,
++ 0);
++static CV1800_GATE(clk_apb_efuse, osc_parents,
++ REG_CLK_EN_0, 12,
++ 0);
++
++/* WDT */
++static CV1800_GATE(clk_apb_wdt, osc_parents,
++ REG_CLK_EN_1, 7,
++ CLK_IS_CRITICAL);
++
++/* WGN */
++static CV1800_GATE(clk_wgn, osc_parents,
++ REG_CLK_EN_3, 22,
++ 0);
++static CV1800_GATE(clk_wgn0, osc_parents,
++ REG_CLK_EN_3, 23,
++ 0);
++static CV1800_GATE(clk_wgn1, osc_parents,
++ REG_CLK_EN_3, 24,
++ 0);
++static CV1800_GATE(clk_wgn2, osc_parents,
++ REG_CLK_EN_3, 25,
++ 0);
++
++/* KEYSCAN */
++static CV1800_GATE(clk_keyscan, osc_parents,
++ REG_CLK_EN_3, 26,
++ 0);
++
++/* EMMC */
++static CV1800_GATE(clk_axi4_emmc, clk_axi4_bus_parents,
++ REG_CLK_EN_0, 15,
++ 0);
++static CV1800_BYPASS_MUX(clk_emmc, clk_axi4_parents,
++ REG_CLK_EN_0, 16,
++ REG_DIV_CLK_EMMC, 16, 5, 15, CV1800_DIV_FLAG,
++ REG_DIV_CLK_EMMC, 8, 2,
++ REG_CLK_BYP_0, 5,
++ 0);
++static CV1800_DIV(clk_emmc_100k, clk_parents_1m,
++ REG_CLK_EN_0, 17,
++ REG_DIV_CLK_EMMC_100K, 16, 8, 10, CV1800_DIV_FLAG,
++ 0);
++
++/* SD */
++static CV1800_GATE(clk_axi4_sd0, clk_axi4_bus_parents,
++ REG_CLK_EN_0, 18,
++ 0);
++static CV1800_BYPASS_MUX(clk_sd0, clk_axi4_parents,
++ REG_CLK_EN_0, 19,
++ REG_DIV_CLK_SD0, 16, 5, 15, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SD0, 8, 2,
++ REG_CLK_BYP_0, 6,
++ 0);
++static CV1800_DIV(clk_sd0_100k, clk_parents_1m,
++ REG_CLK_EN_0, 20,
++ REG_DIV_CLK_SD0_100K, 16, 8, 10, CV1800_DIV_FLAG,
++ 0);
++static CV1800_GATE(clk_axi4_sd1, clk_axi4_bus_parents,
++ REG_CLK_EN_0, 21,
++ 0);
++static CV1800_BYPASS_MUX(clk_sd1, clk_axi4_parents,
++ REG_CLK_EN_0, 22,
++ REG_DIV_CLK_SD1, 16, 5, 15, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SD1, 8, 2,
++ REG_CLK_BYP_0, 7,
++ 0);
++static CV1800_DIV(clk_sd1_100k, clk_parents_1m,
++ REG_CLK_EN_0, 23,
++ REG_DIV_CLK_SD1_100K, 16, 8, 10, CV1800_DIV_FLAG,
++ 0);
++
++/* SPI NAND */
++static CV1800_BYPASS_MUX(clk_spi_nand, clk_axi4_parents,
++ REG_CLK_EN_0, 24,
++ REG_DIV_CLK_SPI_NAND, 16, 5, 8, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SPI_NAND, 8, 2,
++ REG_CLK_BYP_0, 8,
++ 0);
++
++/* GPIO */
++static CV1800_DIV(clk_gpio_db, clk_parents_1m,
++ REG_CLK_EN_0, 31,
++ REG_DIV_CLK_GPIO_DB, 16, 16, 10, CV1800_DIV_FLAG,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_apb_gpio, clk_axi6_bus_parents,
++ REG_CLK_EN_0, 29,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_apb_gpio_intr, clk_axi6_bus_parents,
++ REG_CLK_EN_0, 30,
++ CLK_IS_CRITICAL);
++
++/* ETH */
++static CV1800_BYPASS_DIV(clk_eth0_500m, clk_bypass_fpll_parents,
++ REG_CLK_EN_0, 25,
++ REG_DIV_CLK_GPIO_DB, 16, 4, 3, CV1800_DIV_FLAG,
++ REG_CLK_BYP_0, 9,
++ 0);
++static CV1800_GATE(clk_axi4_eth0, clk_axi4_bus_parents,
++ REG_CLK_EN_0, 26,
++ 0);
++static CV1800_BYPASS_DIV(clk_eth1_500m, clk_bypass_fpll_parents,
++ REG_CLK_EN_0, 27,
++ REG_DIV_CLK_GPIO_DB, 16, 4, 3, CV1800_DIV_FLAG,
++ REG_CLK_BYP_0, 10,
++ 0);
++static CV1800_GATE(clk_axi4_eth1, clk_axi4_bus_parents,
++ REG_CLK_EN_0, 28,
++ 0);
++
++/* SF */
++static CV1800_GATE(clk_ahb_sf, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 0,
++ 0);
++static CV1800_GATE(clk_ahb_sf1, clk_axi4_bus_parents,
++ REG_CLK_EN_3, 27,
++ 0);
++
++/* AUDSRC */
++static CV1800_ACLK(clk_a24m, clk_mipimpll_parents,
++ REG_APLL_FRAC_DIV_CTRL, 0,
++ REG_APLL_FRAC_DIV_CTRL, 3,
++ REG_APLL_FRAC_DIV_CTRL, 1,
++ REG_APLL_FRAC_DIV_CTRL, 2,
++ REG_APLL_FRAC_DIV_M, 0, 22, CV1800_DIV_FLAG,
++ REG_APLL_FRAC_DIV_N, 0, 22, CV1800_DIV_FLAG,
++ 24576000,
++ 0);
++
++static const struct clk_parent_data clk_aud_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_a0pll.common.hw },
++ { .hw = &clk_a24m.common.hw },
++};
++
++static CV1800_BYPASS_MUX(clk_audsrc, clk_aud_parents,
++ REG_CLK_EN_4, 1,
++ REG_DIV_CLK_AUDSRC, 16, 8, 18, CV1800_DIV_FLAG,
++ REG_DIV_CLK_AUDSRC, 8, 2,
++ REG_CLK_BYP_1, 2,
++ 0);
++static CV1800_GATE(clk_apb_audsrc, clk_axi4_bus_parents,
++ REG_CLK_EN_4, 2,
++ 0);
++
++/* SDMA */
++static CV1800_GATE(clk_sdma_axi, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 1,
++ 0);
++static CV1800_BYPASS_MUX(clk_sdma_aud0, clk_aud_parents,
++ REG_CLK_EN_1, 2,
++ REG_DIV_CLK_SDMA_AUD0, 16, 8, 18, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SDMA_AUD0, 8, 2,
++ REG_CLK_BYP_0, 11,
++ 0);
++static CV1800_BYPASS_MUX(clk_sdma_aud1, clk_aud_parents,
++ REG_CLK_EN_1, 3,
++ REG_DIV_CLK_SDMA_AUD1, 16, 8, 18, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SDMA_AUD1, 8, 2,
++ REG_CLK_BYP_0, 12,
++ 0);
++static CV1800_BYPASS_MUX(clk_sdma_aud2, clk_aud_parents,
++ REG_CLK_EN_1, 3,
++ REG_DIV_CLK_SDMA_AUD2, 16, 8, 18, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SDMA_AUD2, 8, 2,
++ REG_CLK_BYP_0, 13,
++ 0);
++static CV1800_BYPASS_MUX(clk_sdma_aud3, clk_aud_parents,
++ REG_CLK_EN_1, 3,
++ REG_DIV_CLK_SDMA_AUD3, 16, 8, 18, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SDMA_AUD3, 8, 2,
++ REG_CLK_BYP_0, 14,
++ 0);
++
++/* SPI */
++static CV1800_GATE(clk_apb_spi0, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 9,
++ 0);
++static CV1800_GATE(clk_apb_spi1, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 10,
++ 0);
++static CV1800_GATE(clk_apb_spi2, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 11,
++ 0);
++static CV1800_GATE(clk_apb_spi3, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 12,
++ 0);
++static CV1800_BYPASS_DIV(clk_spi, clk_bypass_fpll_parents,
++ REG_CLK_EN_3, 6,
++ REG_DIV_CLK_SPI, 16, 6, 8, CV1800_DIV_FLAG,
++ REG_CLK_BYP_0, 30,
++ 0);
++
++/* UART */
++static CV1800_GATE(clk_uart0, clk_uart_parents,
++ REG_CLK_EN_1, 14,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_apb_uart0, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 15,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_uart1, clk_uart_parents,
++ REG_CLK_EN_1, 16,
++ 0);
++static CV1800_GATE(clk_apb_uart1, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 17,
++ 0);
++static CV1800_GATE(clk_uart2, clk_uart_parents,
++ REG_CLK_EN_1, 18,
++ 0);
++static CV1800_GATE(clk_apb_uart2, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 19,
++ 0);
++static CV1800_GATE(clk_uart3, clk_uart_parents,
++ REG_CLK_EN_1, 20,
++ 0);
++static CV1800_GATE(clk_apb_uart3, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 21,
++ 0);
++static CV1800_GATE(clk_uart4, clk_uart_parents,
++ REG_CLK_EN_1, 22,
++ 0);
++static CV1800_GATE(clk_apb_uart4, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 23,
++ 0);
++
++/* I2S */
++static CV1800_GATE(clk_apb_i2s0, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 24,
++ 0);
++static CV1800_GATE(clk_apb_i2s1, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 25,
++ 0);
++static CV1800_GATE(clk_apb_i2s2, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 26,
++ 0);
++static CV1800_GATE(clk_apb_i2s3, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 27,
++ 0);
++
++/* DEBUG */
++static CV1800_GATE(clk_debug, osc_parents,
++ REG_CLK_EN_0, 13,
++ CLK_IS_CRITICAL);
++static CV1800_BYPASS_DIV(clk_ap_debug, clk_bypass_fpll_parents,
++ REG_CLK_EN_4, 5,
++ REG_DIV_CLK_AP_DEBUG, 16, 4, 5, CV1800_DIV_FLAG,
++ REG_CLK_BYP_1, 4,
++ CLK_IS_CRITICAL);
++
++/* DDR */
++static CV1800_GATE(clk_ddr_axi_reg, clk_axi6_bus_parents,
++ REG_CLK_EN_0, 7,
++ CLK_IS_CRITICAL);
++
++/* I2C */
++static CV1800_GATE(clk_apb_i2c, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 6,
++ 0);
++static CV1800_BYPASS_DIV(clk_i2c, clk_bypass_axi6_bus_parents,
++ REG_CLK_EN_3, 7,
++ REG_DIV_CLK_I2C, 16, 4, 1, CV1800_DIV_FLAG,
++ REG_CLK_BYP_0, 31,
++ 0);
++static CV1800_GATE(clk_apb_i2c0, clk_axi4_bus_parents,
++ REG_CLK_EN_3, 17,
++ 0);
++static CV1800_GATE(clk_apb_i2c1, clk_axi4_bus_parents,
++ REG_CLK_EN_3, 18,
++ 0);
++static CV1800_GATE(clk_apb_i2c2, clk_axi4_bus_parents,
++ REG_CLK_EN_3, 19,
++ 0);
++static CV1800_GATE(clk_apb_i2c3, clk_axi4_bus_parents,
++ REG_CLK_EN_3, 20,
++ 0);
++static CV1800_GATE(clk_apb_i2c4, clk_axi4_bus_parents,
++ REG_CLK_EN_3, 21,
++ 0);
++
++/* USB */
++static CV1800_GATE(clk_axi4_usb, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 28,
++ 0);
++static CV1800_GATE(clk_apb_usb, clk_axi4_bus_parents,
++ REG_CLK_EN_1, 29,
++ 0);
++static CV1800_BYPASS_FIXED_DIV(clk_usb_125m, clk_bypass_fpll_parents,
++ REG_CLK_EN_1, 30,
++ 12,
++ REG_CLK_BYP_0, 17,
++ CLK_SET_RATE_PARENT);
++static CV1800_FIXED_DIV(clk_usb_33k, clk_parents_1m,
++ REG_CLK_EN_1, 31,
++ 3,
++ 0);
++static CV1800_BYPASS_FIXED_DIV(clk_usb_12m, clk_bypass_fpll_parents,
++ REG_CLK_EN_2, 0,
++ 125,
++ REG_CLK_BYP_0, 18,
++ CLK_SET_RATE_PARENT);
++
++/* VIP SYS */
++static const struct clk_parent_data clk_vip_sys_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_mipimpll.common.hw },
++ { .hw = &clk_cam0pll.common.hw },
++ { .hw = &clk_disppll.common.hw },
++ { .hw = &clk_fpll.common.hw },
++};
++static const struct clk_parent_data clk_disp_vip_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_disppll.common.hw },
++};
++
++static CV1800_BYPASS_DIV(clk_dsi_esc, clk_bypass_axi6_bus_parents,
++ REG_CLK_EN_2, 3,
++ REG_DIV_CLK_DSI_ESC, 16, 4, 5, CV1800_DIV_FLAG,
++ REG_CLK_BYP_0, 21,
++ 0);
++static CV1800_BYPASS_MUX(clk_axi_vip, clk_vip_sys_parents,
++ REG_CLK_EN_2, 4,
++ REG_DIV_CLK_AXI_VIP, 16, 4, 3, CV1800_DIV_FLAG,
++ REG_DIV_CLK_AXI_VIP, 8, 2,
++ REG_CLK_BYP_0, 22,
++ 0);
++
++static const struct clk_parent_data clk_axi_vip_bus_parents[] = {
++ { .hw = &clk_axi_vip.mux.common.hw },
++};
++
++static CV1800_BYPASS_MUX(clk_src_vip_sys_0, clk_vip_sys_parents,
++ REG_CLK_EN_2, 5,
++ REG_DIV_CLK_SRC_VIP_SYS_0, 16, 4, 6, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SRC_VIP_SYS_0, 8, 2,
++ REG_CLK_BYP_0, 23,
++ 0);
++static CV1800_BYPASS_MUX(clk_src_vip_sys_1, clk_vip_sys_parents,
++ REG_CLK_EN_2, 6,
++ REG_DIV_CLK_SRC_VIP_SYS_1, 16, 4, 6, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SRC_VIP_SYS_1, 8, 2,
++ REG_CLK_BYP_0, 24,
++ 0);
++static CV1800_BYPASS_DIV(clk_disp_src_vip, clk_disp_vip_parents,
++ REG_CLK_EN_2, 7,
++ REG_DIV_CLK_DISP_SRC_VIP, 16, 4, 8, CV1800_DIV_FLAG,
++ REG_CLK_BYP_0, 25,
++ 0);
++static CV1800_BYPASS_MUX(clk_src_vip_sys_2, clk_vip_sys_parents,
++ REG_CLK_EN_3, 29,
++ REG_DIV_CLK_SRC_VIP_SYS_2, 16, 4, 2, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SRC_VIP_SYS_2, 8, 2,
++ REG_CLK_BYP_1, 1,
++ 0);
++static CV1800_GATE(clk_csi_mac0_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 18,
++ 0);
++static CV1800_GATE(clk_csi_mac1_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 19,
++ 0);
++static CV1800_GATE(clk_isp_top_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 20,
++ 0);
++static CV1800_GATE(clk_img_d_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 21,
++ 0);
++static CV1800_GATE(clk_img_v_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 22,
++ 0);
++static CV1800_GATE(clk_sc_top_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 23,
++ 0);
++static CV1800_GATE(clk_sc_d_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 24,
++ 0);
++static CV1800_GATE(clk_sc_v1_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 25,
++ 0);
++static CV1800_GATE(clk_sc_v2_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 26,
++ 0);
++static CV1800_GATE(clk_sc_v3_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 27,
++ 0);
++static CV1800_GATE(clk_dwa_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 28,
++ 0);
++static CV1800_GATE(clk_bt_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 29,
++ 0);
++static CV1800_GATE(clk_disp_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 30,
++ 0);
++static CV1800_GATE(clk_dsi_mac_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_2, 31,
++ 0);
++static CV1800_GATE(clk_lvds0_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_3, 0,
++ 0);
++static CV1800_GATE(clk_lvds1_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_3, 1,
++ 0);
++static CV1800_GATE(clk_csi0_rx_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_3, 2,
++ 0);
++static CV1800_GATE(clk_csi1_rx_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_3, 3,
++ 0);
++static CV1800_GATE(clk_pad_vi_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_3, 4,
++ 0);
++static CV1800_GATE(clk_pad_vi1_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_3, 30,
++ 0);
++static CV1800_GATE(clk_cfg_reg_vip, clk_axi6_bus_parents,
++ REG_CLK_EN_3, 31,
++ 0);
++static CV1800_GATE(clk_pad_vi2_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 7,
++ 0);
++static CV1800_GATE(clk_csi_be_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 8,
++ 0);
++static CV1800_GATE(clk_vip_ip0, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 9,
++ 0);
++static CV1800_GATE(clk_vip_ip1, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 10,
++ 0);
++static CV1800_GATE(clk_vip_ip2, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 11,
++ 0);
++static CV1800_GATE(clk_vip_ip3, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 12,
++ 0);
++static CV1800_BYPASS_MUX(clk_src_vip_sys_3, clk_vip_sys_parents,
++ REG_CLK_EN_4, 15,
++ REG_DIV_CLK_SRC_VIP_SYS_3, 16, 4, 2, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SRC_VIP_SYS_3, 8, 2,
++ REG_CLK_BYP_1, 8,
++ 0);
++static CV1800_BYPASS_MUX(clk_src_vip_sys_4, clk_vip_sys_parents,
++ REG_CLK_EN_4, 16,
++ REG_DIV_CLK_SRC_VIP_SYS_4, 16, 4, 3, CV1800_DIV_FLAG,
++ REG_DIV_CLK_SRC_VIP_SYS_4, 8, 2,
++ REG_CLK_BYP_1, 9,
++ 0);
++static CV1800_GATE(clk_ive_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 17,
++ 0);
++static CV1800_GATE(clk_raw_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 18,
++ 0);
++static CV1800_GATE(clk_osdc_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 19,
++ 0);
++static CV1800_GATE(clk_csi_mac2_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 20,
++ 0);
++static CV1800_GATE(clk_cam0_vip, clk_axi_vip_bus_parents,
++ REG_CLK_EN_4, 21,
++ 0);
++
++/* CAM OUT */
++static const struct clk_parent_data clk_cam_parents[] = {
++ { .hw = &clk_cam0pll.common.hw },
++ { .hw = &clk_cam0pll_d2.common.hw },
++ { .hw = &clk_cam0pll_d3.common.hw },
++ { .hw = &clk_mipimpll_d3.common.hw },
++};
++
++static CV1800_MUX(clk_cam0, clk_cam_parents,
++ REG_CLK_EN_2, 16,
++ REG_CLK_CAM0_SRC_DIV, 16, 6, 0, CV1800_DIV_FLAG,
++ REG_CLK_CAM0_SRC_DIV, 8, 2,
++ CLK_IGNORE_UNUSED);
++static CV1800_MUX(clk_cam1, clk_cam_parents,
++ REG_CLK_EN_2, 17,
++ REG_CLK_CAM1_SRC_DIV, 16, 6, 0, CV1800_DIV_FLAG,
++ REG_CLK_CAM1_SRC_DIV, 8, 2,
++ CLK_IGNORE_UNUSED);
++
++/* VIDEO SUBSYS */
++static const struct clk_parent_data clk_axi_video_codec_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_a0pll.common.hw },
++ { .hw = &clk_mipimpll.common.hw },
++ { .hw = &clk_cam1pll.common.hw },
++ { .hw = &clk_fpll.common.hw },
++};
++static const struct clk_parent_data clk_vc_src0_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_disppll.common.hw },
++ { .hw = &clk_mipimpll.common.hw },
++ { .hw = &clk_cam1pll.common.hw },
++ { .hw = &clk_fpll.common.hw },
++};
++static const struct clk_parent_data clk_vc_src1_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_cam1pll.common.hw },
++};
++
++static CV1800_BYPASS_MUX(clk_axi_video_codec, clk_axi_video_codec_parents,
++ REG_CLK_EN_2, 8,
++ REG_DIV_CLK_AXI_VIDEO_CODEC, 16, 4, 2, CV1800_DIV_FLAG,
++ REG_DIV_CLK_AXI_VIDEO_CODEC, 8, 2,
++ REG_CLK_BYP_0, 26,
++ 0);
++
++static const struct clk_parent_data clk_axi_video_codec_bus_parents[] = {
++ { .hw = &clk_axi_video_codec.mux.common.hw },
++};
++
++static CV1800_BYPASS_MUX(clk_vc_src0, clk_vc_src0_parents,
++ REG_CLK_EN_2, 9,
++ REG_DIV_CLK_VC_SRC0, 16, 4, 2, CV1800_DIV_FLAG,
++ REG_DIV_CLK_VC_SRC0, 8, 2,
++ REG_CLK_BYP_0, 27,
++ 0);
++
++static CV1800_GATE(clk_h264c, clk_axi_video_codec_bus_parents,
++ REG_CLK_EN_2, 10,
++ 0);
++static CV1800_GATE(clk_h265c, clk_axi_video_codec_bus_parents,
++ REG_CLK_EN_2, 11,
++ 0);
++static CV1800_GATE(clk_jpeg, clk_axi_video_codec_bus_parents,
++ REG_CLK_EN_2, 12,
++ CLK_IGNORE_UNUSED);
++static CV1800_GATE(clk_apb_jpeg, clk_axi6_bus_parents,
++ REG_CLK_EN_2, 13,
++ CLK_IGNORE_UNUSED);
++static CV1800_GATE(clk_apb_h264c, clk_axi6_bus_parents,
++ REG_CLK_EN_2, 14,
++ 0);
++static CV1800_GATE(clk_apb_h265c, clk_axi6_bus_parents,
++ REG_CLK_EN_2, 15,
++ 0);
++static CV1800_BYPASS_FIXED_DIV(clk_vc_src1, clk_vc_src1_parents,
++ REG_CLK_EN_3, 28,
++ 2,
++ REG_CLK_BYP_1, 0,
++ CLK_SET_RATE_PARENT);
++static CV1800_BYPASS_FIXED_DIV(clk_vc_src2, clk_bypass_fpll_parents,
++ REG_CLK_EN_4, 3,
++ 3,
++ REG_CLK_BYP_1, 3,
++ CLK_SET_RATE_PARENT);
++
++/* VC SYS */
++static CV1800_GATE(clk_cfg_reg_vc, clk_axi6_bus_parents,
++ REG_CLK_EN_4, 0,
++ CLK_IGNORE_UNUSED);
++
++/* PWM */
++static CV1800_BYPASS_MUX(clk_pwm_src, clk_axi4_parents,
++ REG_CLK_EN_4, 4,
++ REG_DIV_CLK_PWM_SRC_0, 16, 6, 10, CV1800_DIV_FLAG,
++ REG_DIV_CLK_PWM_SRC_0, 8, 2,
++ REG_CLK_BYP_0, 15,
++ CLK_IS_CRITICAL);
++
++static const struct clk_parent_data clk_pwm_parents[] = {
++ { .hw = &clk_pwm_src.mux.common.hw },
++};
++
++static CV1800_GATE(clk_pwm, clk_pwm_parents,
++ REG_CLK_EN_1, 8,
++ CLK_IS_CRITICAL);
++
++/* C906 */
++static const struct clk_parent_data clk_c906_0_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_tpll.common.hw },
++ { .hw = &clk_a0pll.common.hw },
++ { .hw = &clk_mipimpll.common.hw },
++ { .hw = &clk_mpll.common.hw },
++ { .hw = &clk_fpll.common.hw },
++};
++static const struct clk_parent_data clk_c906_1_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_tpll.common.hw },
++ { .hw = &clk_a0pll.common.hw },
++ { .hw = &clk_disppll.common.hw },
++ { .hw = &clk_mpll.common.hw },
++ { .hw = &clk_fpll.common.hw },
++};
++
++static const s8 clk_c906_parent2sel[] = {
++ -1, /* osc */
++ 0, /* mux 0: clk_tpll(c906_0), clk_tpll(c906_1) */
++ 0, /* mux 0: clk_a0pll(c906_0), clk_a0pll(c906_1) */
++ 0, /* mux 0: clk_mipimpll(c906_0), clk_disppll(c906_1) */
++ 0, /* mux 0: clk_mpll(c906_0), clk_mpll(c906_1) */
++ 1 /* mux 1: clk_fpll(c906_0), clk_fpll(c906_1) */
++};
++
++static const u8 clk_c906_sel2parent[2][4] = {
++ [0] = {
++ 1,
++ 2,
++ 3,
++ 4
++ },
++ [1] = {
++ 5,
++ 5,
++ 5,
++ 5
++ },
++};
++
++static CV1800_MMUX(clk_c906_0, clk_c906_0_parents,
++ REG_CLK_EN_4, 13,
++ REG_DIV_CLK_C906_0_0, 16, 4, 1, CV1800_DIV_FLAG,
++ REG_DIV_CLK_C906_0_1, 16, 4, 2, CV1800_DIV_FLAG,
++ REG_DIV_CLK_C906_0_0, 8, 2,
++ REG_DIV_CLK_C906_0_1, 8, 2,
++ REG_CLK_BYP_1, 6,
++ REG_CLK_SEL_0, 23,
++ clk_c906_parent2sel,
++ clk_c906_sel2parent[0], clk_c906_sel2parent[1],
++ CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
++static CV1800_MMUX(clk_c906_1, clk_c906_1_parents,
++ REG_CLK_EN_4, 14,
++ REG_DIV_CLK_C906_1_0, 16, 4, 2, CV1800_DIV_FLAG,
++ REG_DIV_CLK_C906_1_1, 16, 4, 3, CV1800_DIV_FLAG,
++ REG_DIV_CLK_C906_1_0, 8, 2,
++ REG_DIV_CLK_C906_1_1, 8, 2,
++ REG_CLK_BYP_1, 7,
++ REG_CLK_SEL_0, 24,
++ clk_c906_parent2sel,
++ clk_c906_sel2parent[0], clk_c906_sel2parent[1],
++ CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
++
++/* A53 */
++static CV1800_BYPASS_DIV(clk_cpu_axi0, clk_axi4_parents,
++ REG_CLK_EN_0, 1,
++ REG_DIV_CLK_CPU_AXI0, 16, 4, 3, CV1800_DIV_FLAG,
++ REG_CLK_BYP_0, 1,
++ CLK_IS_CRITICAL);
++static CV1800_BYPASS_DIV(clk_cpu_gic, clk_bypass_fpll_parents,
++ REG_CLK_EN_0, 2,
++ REG_DIV_CLK_CPU_GIC, 16, 4, 5, CV1800_DIV_FLAG,
++ REG_CLK_BYP_0, 2,
++ CLK_IS_CRITICAL);
++static CV1800_GATE(clk_xtal_ap, osc_parents,
++ REG_CLK_EN_0, 3,
++ CLK_IS_CRITICAL);
++
++static const struct clk_parent_data clk_a53_parents[] = {
++ { .index = 0 },
++ { .hw = &clk_tpll.common.hw },
++ { .hw = &clk_a0pll.common.hw },
++ { .hw = &clk_mipimpll.common.hw },
++ { .hw = &clk_mpll.common.hw },
++ { .hw = &clk_fpll.common.hw },
++};
++
++static const s8 clk_a53_parent2sel[] = {
++ -1, /* osc */
++ 0, /* mux 0: clk_tpll */
++ 0, /* mux 0: clk_a0pll */
++ 0, /* mux 0: clk_mipimpll */
++ 0, /* mux 0: clk_mpll */
++ 1 /* mux 1: clk_fpll */
++};
++
++static const u8 clk_a53_sel2parent[2][4] = {
++ [0] = {
++ 1,
++ 2,
++ 3,
++ 4
++ },
++ [1] = {
++ 5,
++ 5,
++ 5,
++ 5
++ },
++};
++
++/*
++ * Clock for A53 cpu in the CV18XX/SG200X series.
++ * For CV180X and CV181X series, this clock is not used, but can not
++ * be set to bypass mode, or the SoC will hang.
++ */
++static CV1800_MMUX(clk_a53, clk_a53_parents,
++ REG_CLK_EN_0, 0,
++ REG_DIV_CLK_A53_0, 16, 4, 1, CV1800_DIV_FLAG,
++ REG_DIV_CLK_A53_1, 16, 4, 2, CV1800_DIV_FLAG,
++ REG_DIV_CLK_A53_0, 8, 2,
++ REG_DIV_CLK_A53_1, 8, 2,
++ REG_CLK_BYP_0, 0,
++ REG_CLK_SEL_0, 0,
++ clk_a53_parent2sel,
++ clk_a53_sel2parent[0], clk_a53_sel2parent[1],
++ CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE);
++
++static struct clk_hw_onecell_data cv1800_hw_clks = {
++ .num = CV1800_CLK_MAX,
++ .hws = {
++ [CLK_MPLL] = &clk_mpll.common.hw,
++ [CLK_TPLL] = &clk_tpll.common.hw,
++ [CLK_FPLL] = &clk_fpll.common.hw,
++ [CLK_MIPIMPLL] = &clk_mipimpll.common.hw,
++ [CLK_A0PLL] = &clk_a0pll.common.hw,
++ [CLK_DISPPLL] = &clk_disppll.common.hw,
++ [CLK_CAM0PLL] = &clk_cam0pll.common.hw,
++ [CLK_CAM1PLL] = &clk_cam1pll.common.hw,
++
++ [CLK_MIPIMPLL_D3] = &clk_mipimpll_d3.common.hw,
++ [CLK_CAM0PLL_D2] = &clk_cam0pll_d2.common.hw,
++ [CLK_CAM0PLL_D3] = &clk_cam0pll_d3.common.hw,
++
++ [CLK_TPU] = &clk_tpu.mux.common.hw,
++ [CLK_TPU_FAB] = &clk_tpu_fab.common.hw,
++ [CLK_AHB_ROM] = &clk_ahb_rom.common.hw,
++ [CLK_DDR_AXI_REG] = &clk_ddr_axi_reg.common.hw,
++ [CLK_RTC_25M] = &clk_rtc_25m.common.hw,
++ [CLK_SRC_RTC_SYS_0] = &clk_src_rtc_sys_0.div.common.hw,
++ [CLK_TEMPSEN] = &clk_tempsen.common.hw,
++ [CLK_SARADC] = &clk_saradc.common.hw,
++ [CLK_EFUSE] = &clk_efuse.common.hw,
++ [CLK_APB_EFUSE] = &clk_apb_efuse.common.hw,
++ [CLK_DEBUG] = &clk_debug.common.hw,
++ [CLK_AP_DEBUG] = &clk_ap_debug.div.common.hw,
++ [CLK_XTAL_MISC] = &clk_xtal_misc.common.hw,
++ [CLK_AXI4_EMMC] = &clk_axi4_emmc.common.hw,
++ [CLK_EMMC] = &clk_emmc.mux.common.hw,
++ [CLK_EMMC_100K] = &clk_emmc_100k.common.hw,
++ [CLK_AXI4_SD0] = &clk_axi4_sd0.common.hw,
++ [CLK_SD0] = &clk_sd0.mux.common.hw,
++ [CLK_SD0_100K] = &clk_sd0_100k.common.hw,
++ [CLK_AXI4_SD1] = &clk_axi4_sd1.common.hw,
++ [CLK_SD1] = &clk_sd1.mux.common.hw,
++ [CLK_SD1_100K] = &clk_sd1_100k.common.hw,
++ [CLK_SPI_NAND] = &clk_spi_nand.mux.common.hw,
++ [CLK_ETH0_500M] = &clk_eth0_500m.div.common.hw,
++ [CLK_AXI4_ETH0] = &clk_axi4_eth0.common.hw,
++ [CLK_ETH1_500M] = &clk_eth1_500m.div.common.hw,
++ [CLK_AXI4_ETH1] = &clk_axi4_eth1.common.hw,
++ [CLK_APB_GPIO] = &clk_apb_gpio.common.hw,
++ [CLK_APB_GPIO_INTR] = &clk_apb_gpio_intr.common.hw,
++ [CLK_GPIO_DB] = &clk_gpio_db.common.hw,
++ [CLK_AHB_SF] = &clk_ahb_sf.common.hw,
++ [CLK_AHB_SF1] = &clk_ahb_sf1.common.hw,
++ [CLK_A24M] = &clk_a24m.common.hw,
++ [CLK_AUDSRC] = &clk_audsrc.mux.common.hw,
++ [CLK_APB_AUDSRC] = &clk_apb_audsrc.common.hw,
++ [CLK_SDMA_AXI] = &clk_sdma_axi.common.hw,
++ [CLK_SDMA_AUD0] = &clk_sdma_aud0.mux.common.hw,
++ [CLK_SDMA_AUD1] = &clk_sdma_aud1.mux.common.hw,
++ [CLK_SDMA_AUD2] = &clk_sdma_aud2.mux.common.hw,
++ [CLK_SDMA_AUD3] = &clk_sdma_aud3.mux.common.hw,
++ [CLK_I2C] = &clk_i2c.div.common.hw,
++ [CLK_APB_I2C] = &clk_apb_i2c.common.hw,
++ [CLK_APB_I2C0] = &clk_apb_i2c0.common.hw,
++ [CLK_APB_I2C1] = &clk_apb_i2c1.common.hw,
++ [CLK_APB_I2C2] = &clk_apb_i2c2.common.hw,
++ [CLK_APB_I2C3] = &clk_apb_i2c3.common.hw,
++ [CLK_APB_I2C4] = &clk_apb_i2c4.common.hw,
++ [CLK_APB_WDT] = &clk_apb_wdt.common.hw,
++ [CLK_PWM_SRC] = &clk_pwm_src.mux.common.hw,
++ [CLK_PWM] = &clk_pwm.common.hw,
++ [CLK_SPI] = &clk_spi.div.common.hw,
++ [CLK_APB_SPI0] = &clk_apb_spi0.common.hw,
++ [CLK_APB_SPI1] = &clk_apb_spi1.common.hw,
++ [CLK_APB_SPI2] = &clk_apb_spi2.common.hw,
++ [CLK_APB_SPI3] = &clk_apb_spi3.common.hw,
++ [CLK_1M] = &clk_1m.common.hw,
++ [CLK_CAM0_200] = &clk_cam0_200.mux.common.hw,
++ [CLK_PM] = &clk_pm.common.hw,
++ [CLK_TIMER0] = &clk_timer0.common.hw,
++ [CLK_TIMER1] = &clk_timer1.common.hw,
++ [CLK_TIMER2] = &clk_timer2.common.hw,
++ [CLK_TIMER3] = &clk_timer3.common.hw,
++ [CLK_TIMER4] = &clk_timer4.common.hw,
++ [CLK_TIMER5] = &clk_timer5.common.hw,
++ [CLK_TIMER6] = &clk_timer6.common.hw,
++ [CLK_TIMER7] = &clk_timer7.common.hw,
++ [CLK_UART0] = &clk_uart0.common.hw,
++ [CLK_APB_UART0] = &clk_apb_uart0.common.hw,
++ [CLK_UART1] = &clk_uart1.common.hw,
++ [CLK_APB_UART1] = &clk_apb_uart1.common.hw,
++ [CLK_UART2] = &clk_uart2.common.hw,
++ [CLK_APB_UART2] = &clk_apb_uart2.common.hw,
++ [CLK_UART3] = &clk_uart3.common.hw,
++ [CLK_APB_UART3] = &clk_apb_uart3.common.hw,
++ [CLK_UART4] = &clk_uart4.common.hw,
++ [CLK_APB_UART4] = &clk_apb_uart4.common.hw,
++ [CLK_APB_I2S0] = &clk_apb_i2s0.common.hw,
++ [CLK_APB_I2S1] = &clk_apb_i2s1.common.hw,
++ [CLK_APB_I2S2] = &clk_apb_i2s2.common.hw,
++ [CLK_APB_I2S3] = &clk_apb_i2s3.common.hw,
++ [CLK_AXI4_USB] = &clk_axi4_usb.common.hw,
++ [CLK_APB_USB] = &clk_apb_usb.common.hw,
++ [CLK_USB_125M] = &clk_usb_125m.div.common.hw,
++ [CLK_USB_33K] = &clk_usb_33k.common.hw,
++ [CLK_USB_12M] = &clk_usb_12m.div.common.hw,
++ [CLK_AXI4] = &clk_axi4.mux.common.hw,
++ [CLK_AXI6] = &clk_axi6.div.common.hw,
++ [CLK_DSI_ESC] = &clk_dsi_esc.div.common.hw,
++ [CLK_AXI_VIP] = &clk_axi_vip.mux.common.hw,
++ [CLK_SRC_VIP_SYS_0] = &clk_src_vip_sys_0.mux.common.hw,
++ [CLK_SRC_VIP_SYS_1] = &clk_src_vip_sys_1.mux.common.hw,
++ [CLK_SRC_VIP_SYS_2] = &clk_src_vip_sys_2.mux.common.hw,
++ [CLK_SRC_VIP_SYS_3] = &clk_src_vip_sys_3.mux.common.hw,
++ [CLK_SRC_VIP_SYS_4] = &clk_src_vip_sys_4.mux.common.hw,
++ [CLK_CSI_BE_VIP] = &clk_csi_be_vip.common.hw,
++ [CLK_CSI_MAC0_VIP] = &clk_csi_mac0_vip.common.hw,
++ [CLK_CSI_MAC1_VIP] = &clk_csi_mac1_vip.common.hw,
++ [CLK_CSI_MAC2_VIP] = &clk_csi_mac2_vip.common.hw,
++ [CLK_CSI0_RX_VIP] = &clk_csi0_rx_vip.common.hw,
++ [CLK_CSI1_RX_VIP] = &clk_csi1_rx_vip.common.hw,
++ [CLK_ISP_TOP_VIP] = &clk_isp_top_vip.common.hw,
++ [CLK_IMG_D_VIP] = &clk_img_d_vip.common.hw,
++ [CLK_IMG_V_VIP] = &clk_img_v_vip.common.hw,
++ [CLK_SC_TOP_VIP] = &clk_sc_top_vip.common.hw,
++ [CLK_SC_D_VIP] = &clk_sc_d_vip.common.hw,
++ [CLK_SC_V1_VIP] = &clk_sc_v1_vip.common.hw,
++ [CLK_SC_V2_VIP] = &clk_sc_v2_vip.common.hw,
++ [CLK_SC_V3_VIP] = &clk_sc_v3_vip.common.hw,
++ [CLK_DWA_VIP] = &clk_dwa_vip.common.hw,
++ [CLK_BT_VIP] = &clk_bt_vip.common.hw,
++ [CLK_DISP_VIP] = &clk_disp_vip.common.hw,
++ [CLK_DSI_MAC_VIP] = &clk_dsi_mac_vip.common.hw,
++ [CLK_LVDS0_VIP] = &clk_lvds0_vip.common.hw,
++ [CLK_LVDS1_VIP] = &clk_lvds1_vip.common.hw,
++ [CLK_PAD_VI_VIP] = &clk_pad_vi_vip.common.hw,
++ [CLK_PAD_VI1_VIP] = &clk_pad_vi1_vip.common.hw,
++ [CLK_PAD_VI2_VIP] = &clk_pad_vi2_vip.common.hw,
++ [CLK_CFG_REG_VIP] = &clk_cfg_reg_vip.common.hw,
++ [CLK_VIP_IP0] = &clk_vip_ip0.common.hw,
++ [CLK_VIP_IP1] = &clk_vip_ip1.common.hw,
++ [CLK_VIP_IP2] = &clk_vip_ip2.common.hw,
++ [CLK_VIP_IP3] = &clk_vip_ip3.common.hw,
++ [CLK_IVE_VIP] = &clk_ive_vip.common.hw,
++ [CLK_RAW_VIP] = &clk_raw_vip.common.hw,
++ [CLK_OSDC_VIP] = &clk_osdc_vip.common.hw,
++ [CLK_CAM0_VIP] = &clk_cam0_vip.common.hw,
++ [CLK_AXI_VIDEO_CODEC] = &clk_axi_video_codec.mux.common.hw,
++ [CLK_VC_SRC0] = &clk_vc_src0.mux.common.hw,
++ [CLK_VC_SRC1] = &clk_vc_src1.div.common.hw,
++ [CLK_VC_SRC2] = &clk_vc_src2.div.common.hw,
++ [CLK_H264C] = &clk_h264c.common.hw,
++ [CLK_APB_H264C] = &clk_apb_h264c.common.hw,
++ [CLK_H265C] = &clk_h265c.common.hw,
++ [CLK_APB_H265C] = &clk_apb_h265c.common.hw,
++ [CLK_JPEG] = &clk_jpeg.common.hw,
++ [CLK_APB_JPEG] = &clk_apb_jpeg.common.hw,
++ [CLK_CAM0] = &clk_cam0.common.hw,
++ [CLK_CAM1] = &clk_cam1.common.hw,
++ [CLK_WGN] = &clk_wgn.common.hw,
++ [CLK_WGN0] = &clk_wgn0.common.hw,
++ [CLK_WGN1] = &clk_wgn1.common.hw,
++ [CLK_WGN2] = &clk_wgn2.common.hw,
++ [CLK_KEYSCAN] = &clk_keyscan.common.hw,
++ [CLK_CFG_REG_VC] = &clk_cfg_reg_vc.common.hw,
++ [CLK_C906_0] = &clk_c906_0.common.hw,
++ [CLK_C906_1] = &clk_c906_1.common.hw,
++ [CLK_A53] = &clk_a53.common.hw,
++ [CLK_CPU_AXI0] = &clk_cpu_axi0.div.common.hw,
++ [CLK_CPU_GIC] = &clk_cpu_gic.div.common.hw,
++ [CLK_XTAL_AP] = &clk_xtal_ap.common.hw,
++ },
++};
++
++static void cv18xx_clk_disable_auto_pd(void __iomem *base)
++{
++ static const u16 CV1800_PD_CLK[] = {
++ REG_MIPIMPLL_CLK_CSR,
++ REG_A0PLL_CLK_CSR,
++ REG_DISPPLL_CLK_CSR,
++ REG_CAM0PLL_CLK_CSR,
++ REG_CAM1PLL_CLK_CSR,
++ };
++
++ u32 val;
++ int i;
++
++ /* disable auto power down */
++ for (i = 0; i < ARRAY_SIZE(CV1800_PD_CLK); i++) {
++ u32 reg = CV1800_PD_CLK[i];
++
++ val = readl(base + reg);
++ val |= GENMASK(12, 9);
++ val &= ~BIT(8);
++ writel(val, base + reg);
++ }
++}
++
++static void cv18xx_clk_disable_a53(void __iomem *base)
++{
++ u32 val = readl(base + REG_CLK_BYP_0);
++
++ /* Set bypass clock for clk_a53 */
++ val |= BIT(0);
++
++ /* Set bypass clock for clk_cpu_axi0 */
++ val |= BIT(1);
++
++ /* Set bypass clock for clk_cpu_gic */
++ val |= BIT(2);
++
++ writel(val, base + REG_CLK_BYP_0);
++}
++
++static int cv1800_pre_init(struct device *dev, void __iomem *base,
++ struct cv1800_clk_ctrl *ctrl,
++ const struct cv1800_clk_desc *desc)
++{
++ u32 val = readl(base + REG_CLK_EN_2);
++
++ /* disable unsupported clk_disp_src_vip */
++ val &= ~BIT(7);
++
++ writel(val, base + REG_CLK_EN_2);
++
++ cv18xx_clk_disable_a53(base);
++ cv18xx_clk_disable_auto_pd(base);
++
++ return 0;
++}
++
++static const struct cv1800_clk_desc cv1800_desc = {
++ .clks_data = &cv1800_hw_clks,
++ .pre_init = cv1800_pre_init,
++};
++
++static struct clk_hw_onecell_data cv1810_hw_clks = {
++ .num = CV1810_CLK_MAX,
++ .hws = {
++ [CLK_MPLL] = &clk_mpll.common.hw,
++ [CLK_TPLL] = &clk_tpll.common.hw,
++ [CLK_FPLL] = &clk_fpll.common.hw,
++ [CLK_MIPIMPLL] = &clk_mipimpll.common.hw,
++ [CLK_A0PLL] = &clk_a0pll.common.hw,
++ [CLK_DISPPLL] = &clk_disppll.common.hw,
++ [CLK_CAM0PLL] = &clk_cam0pll.common.hw,
++ [CLK_CAM1PLL] = &clk_cam1pll.common.hw,
++
++ [CLK_MIPIMPLL_D3] = &clk_mipimpll_d3.common.hw,
++ [CLK_CAM0PLL_D2] = &clk_cam0pll_d2.common.hw,
++ [CLK_CAM0PLL_D3] = &clk_cam0pll_d3.common.hw,
++
++ [CLK_TPU] = &clk_tpu.mux.common.hw,
++ [CLK_TPU_FAB] = &clk_tpu_fab.common.hw,
++ [CLK_AHB_ROM] = &clk_ahb_rom.common.hw,
++ [CLK_DDR_AXI_REG] = &clk_ddr_axi_reg.common.hw,
++ [CLK_RTC_25M] = &clk_rtc_25m.common.hw,
++ [CLK_SRC_RTC_SYS_0] = &clk_src_rtc_sys_0.div.common.hw,
++ [CLK_TEMPSEN] = &clk_tempsen.common.hw,
++ [CLK_SARADC] = &clk_saradc.common.hw,
++ [CLK_EFUSE] = &clk_efuse.common.hw,
++ [CLK_APB_EFUSE] = &clk_apb_efuse.common.hw,
++ [CLK_DEBUG] = &clk_debug.common.hw,
++ [CLK_AP_DEBUG] = &clk_ap_debug.div.common.hw,
++ [CLK_XTAL_MISC] = &clk_xtal_misc.common.hw,
++ [CLK_AXI4_EMMC] = &clk_axi4_emmc.common.hw,
++ [CLK_EMMC] = &clk_emmc.mux.common.hw,
++ [CLK_EMMC_100K] = &clk_emmc_100k.common.hw,
++ [CLK_AXI4_SD0] = &clk_axi4_sd0.common.hw,
++ [CLK_SD0] = &clk_sd0.mux.common.hw,
++ [CLK_SD0_100K] = &clk_sd0_100k.common.hw,
++ [CLK_AXI4_SD1] = &clk_axi4_sd1.common.hw,
++ [CLK_SD1] = &clk_sd1.mux.common.hw,
++ [CLK_SD1_100K] = &clk_sd1_100k.common.hw,
++ [CLK_SPI_NAND] = &clk_spi_nand.mux.common.hw,
++ [CLK_ETH0_500M] = &clk_eth0_500m.div.common.hw,
++ [CLK_AXI4_ETH0] = &clk_axi4_eth0.common.hw,
++ [CLK_ETH1_500M] = &clk_eth1_500m.div.common.hw,
++ [CLK_AXI4_ETH1] = &clk_axi4_eth1.common.hw,
++ [CLK_APB_GPIO] = &clk_apb_gpio.common.hw,
++ [CLK_APB_GPIO_INTR] = &clk_apb_gpio_intr.common.hw,
++ [CLK_GPIO_DB] = &clk_gpio_db.common.hw,
++ [CLK_AHB_SF] = &clk_ahb_sf.common.hw,
++ [CLK_AHB_SF1] = &clk_ahb_sf1.common.hw,
++ [CLK_A24M] = &clk_a24m.common.hw,
++ [CLK_AUDSRC] = &clk_audsrc.mux.common.hw,
++ [CLK_APB_AUDSRC] = &clk_apb_audsrc.common.hw,
++ [CLK_SDMA_AXI] = &clk_sdma_axi.common.hw,
++ [CLK_SDMA_AUD0] = &clk_sdma_aud0.mux.common.hw,
++ [CLK_SDMA_AUD1] = &clk_sdma_aud1.mux.common.hw,
++ [CLK_SDMA_AUD2] = &clk_sdma_aud2.mux.common.hw,
++ [CLK_SDMA_AUD3] = &clk_sdma_aud3.mux.common.hw,
++ [CLK_I2C] = &clk_i2c.div.common.hw,
++ [CLK_APB_I2C] = &clk_apb_i2c.common.hw,
++ [CLK_APB_I2C0] = &clk_apb_i2c0.common.hw,
++ [CLK_APB_I2C1] = &clk_apb_i2c1.common.hw,
++ [CLK_APB_I2C2] = &clk_apb_i2c2.common.hw,
++ [CLK_APB_I2C3] = &clk_apb_i2c3.common.hw,
++ [CLK_APB_I2C4] = &clk_apb_i2c4.common.hw,
++ [CLK_APB_WDT] = &clk_apb_wdt.common.hw,
++ [CLK_PWM_SRC] = &clk_pwm_src.mux.common.hw,
++ [CLK_PWM] = &clk_pwm.common.hw,
++ [CLK_SPI] = &clk_spi.div.common.hw,
++ [CLK_APB_SPI0] = &clk_apb_spi0.common.hw,
++ [CLK_APB_SPI1] = &clk_apb_spi1.common.hw,
++ [CLK_APB_SPI2] = &clk_apb_spi2.common.hw,
++ [CLK_APB_SPI3] = &clk_apb_spi3.common.hw,
++ [CLK_1M] = &clk_1m.common.hw,
++ [CLK_CAM0_200] = &clk_cam0_200.mux.common.hw,
++ [CLK_PM] = &clk_pm.common.hw,
++ [CLK_TIMER0] = &clk_timer0.common.hw,
++ [CLK_TIMER1] = &clk_timer1.common.hw,
++ [CLK_TIMER2] = &clk_timer2.common.hw,
++ [CLK_TIMER3] = &clk_timer3.common.hw,
++ [CLK_TIMER4] = &clk_timer4.common.hw,
++ [CLK_TIMER5] = &clk_timer5.common.hw,
++ [CLK_TIMER6] = &clk_timer6.common.hw,
++ [CLK_TIMER7] = &clk_timer7.common.hw,
++ [CLK_UART0] = &clk_uart0.common.hw,
++ [CLK_APB_UART0] = &clk_apb_uart0.common.hw,
++ [CLK_UART1] = &clk_uart1.common.hw,
++ [CLK_APB_UART1] = &clk_apb_uart1.common.hw,
++ [CLK_UART2] = &clk_uart2.common.hw,
++ [CLK_APB_UART2] = &clk_apb_uart2.common.hw,
++ [CLK_UART3] = &clk_uart3.common.hw,
++ [CLK_APB_UART3] = &clk_apb_uart3.common.hw,
++ [CLK_UART4] = &clk_uart4.common.hw,
++ [CLK_APB_UART4] = &clk_apb_uart4.common.hw,
++ [CLK_APB_I2S0] = &clk_apb_i2s0.common.hw,
++ [CLK_APB_I2S1] = &clk_apb_i2s1.common.hw,
++ [CLK_APB_I2S2] = &clk_apb_i2s2.common.hw,
++ [CLK_APB_I2S3] = &clk_apb_i2s3.common.hw,
++ [CLK_AXI4_USB] = &clk_axi4_usb.common.hw,
++ [CLK_APB_USB] = &clk_apb_usb.common.hw,
++ [CLK_USB_125M] = &clk_usb_125m.div.common.hw,
++ [CLK_USB_33K] = &clk_usb_33k.common.hw,
++ [CLK_USB_12M] = &clk_usb_12m.div.common.hw,
++ [CLK_AXI4] = &clk_axi4.mux.common.hw,
++ [CLK_AXI6] = &clk_axi6.div.common.hw,
++ [CLK_DSI_ESC] = &clk_dsi_esc.div.common.hw,
++ [CLK_AXI_VIP] = &clk_axi_vip.mux.common.hw,
++ [CLK_SRC_VIP_SYS_0] = &clk_src_vip_sys_0.mux.common.hw,
++ [CLK_SRC_VIP_SYS_1] = &clk_src_vip_sys_1.mux.common.hw,
++ [CLK_SRC_VIP_SYS_2] = &clk_src_vip_sys_2.mux.common.hw,
++ [CLK_SRC_VIP_SYS_3] = &clk_src_vip_sys_3.mux.common.hw,
++ [CLK_SRC_VIP_SYS_4] = &clk_src_vip_sys_4.mux.common.hw,
++ [CLK_CSI_BE_VIP] = &clk_csi_be_vip.common.hw,
++ [CLK_CSI_MAC0_VIP] = &clk_csi_mac0_vip.common.hw,
++ [CLK_CSI_MAC1_VIP] = &clk_csi_mac1_vip.common.hw,
++ [CLK_CSI_MAC2_VIP] = &clk_csi_mac2_vip.common.hw,
++ [CLK_CSI0_RX_VIP] = &clk_csi0_rx_vip.common.hw,
++ [CLK_CSI1_RX_VIP] = &clk_csi1_rx_vip.common.hw,
++ [CLK_ISP_TOP_VIP] = &clk_isp_top_vip.common.hw,
++ [CLK_IMG_D_VIP] = &clk_img_d_vip.common.hw,
++ [CLK_IMG_V_VIP] = &clk_img_v_vip.common.hw,
++ [CLK_SC_TOP_VIP] = &clk_sc_top_vip.common.hw,
++ [CLK_SC_D_VIP] = &clk_sc_d_vip.common.hw,
++ [CLK_SC_V1_VIP] = &clk_sc_v1_vip.common.hw,
++ [CLK_SC_V2_VIP] = &clk_sc_v2_vip.common.hw,
++ [CLK_SC_V3_VIP] = &clk_sc_v3_vip.common.hw,
++ [CLK_DWA_VIP] = &clk_dwa_vip.common.hw,
++ [CLK_BT_VIP] = &clk_bt_vip.common.hw,
++ [CLK_DISP_VIP] = &clk_disp_vip.common.hw,
++ [CLK_DSI_MAC_VIP] = &clk_dsi_mac_vip.common.hw,
++ [CLK_LVDS0_VIP] = &clk_lvds0_vip.common.hw,
++ [CLK_LVDS1_VIP] = &clk_lvds1_vip.common.hw,
++ [CLK_PAD_VI_VIP] = &clk_pad_vi_vip.common.hw,
++ [CLK_PAD_VI1_VIP] = &clk_pad_vi1_vip.common.hw,
++ [CLK_PAD_VI2_VIP] = &clk_pad_vi2_vip.common.hw,
++ [CLK_CFG_REG_VIP] = &clk_cfg_reg_vip.common.hw,
++ [CLK_VIP_IP0] = &clk_vip_ip0.common.hw,
++ [CLK_VIP_IP1] = &clk_vip_ip1.common.hw,
++ [CLK_VIP_IP2] = &clk_vip_ip2.common.hw,
++ [CLK_VIP_IP3] = &clk_vip_ip3.common.hw,
++ [CLK_IVE_VIP] = &clk_ive_vip.common.hw,
++ [CLK_RAW_VIP] = &clk_raw_vip.common.hw,
++ [CLK_OSDC_VIP] = &clk_osdc_vip.common.hw,
++ [CLK_CAM0_VIP] = &clk_cam0_vip.common.hw,
++ [CLK_AXI_VIDEO_CODEC] = &clk_axi_video_codec.mux.common.hw,
++ [CLK_VC_SRC0] = &clk_vc_src0.mux.common.hw,
++ [CLK_VC_SRC1] = &clk_vc_src1.div.common.hw,
++ [CLK_VC_SRC2] = &clk_vc_src2.div.common.hw,
++ [CLK_H264C] = &clk_h264c.common.hw,
++ [CLK_APB_H264C] = &clk_apb_h264c.common.hw,
++ [CLK_H265C] = &clk_h265c.common.hw,
++ [CLK_APB_H265C] = &clk_apb_h265c.common.hw,
++ [CLK_JPEG] = &clk_jpeg.common.hw,
++ [CLK_APB_JPEG] = &clk_apb_jpeg.common.hw,
++ [CLK_CAM0] = &clk_cam0.common.hw,
++ [CLK_CAM1] = &clk_cam1.common.hw,
++ [CLK_WGN] = &clk_wgn.common.hw,
++ [CLK_WGN0] = &clk_wgn0.common.hw,
++ [CLK_WGN1] = &clk_wgn1.common.hw,
++ [CLK_WGN2] = &clk_wgn2.common.hw,
++ [CLK_KEYSCAN] = &clk_keyscan.common.hw,
++ [CLK_CFG_REG_VC] = &clk_cfg_reg_vc.common.hw,
++ [CLK_C906_0] = &clk_c906_0.common.hw,
++ [CLK_C906_1] = &clk_c906_1.common.hw,
++ [CLK_A53] = &clk_a53.common.hw,
++ [CLK_CPU_AXI0] = &clk_cpu_axi0.div.common.hw,
++ [CLK_CPU_GIC] = &clk_cpu_gic.div.common.hw,
++ [CLK_XTAL_AP] = &clk_xtal_ap.common.hw,
++ [CLK_DISP_SRC_VIP] = &clk_disp_src_vip.div.common.hw,
++ },
++};
++
++static int cv1810_pre_init(struct device *dev, void __iomem *base,
++ struct cv1800_clk_ctrl *ctrl,
++ const struct cv1800_clk_desc *desc)
++{
++ cv18xx_clk_disable_a53(base);
++ cv18xx_clk_disable_auto_pd(base);
++
++ return 0;
++}
++
++static const struct cv1800_clk_desc cv1810_desc = {
++ .clks_data = &cv1810_hw_clks,
++ .pre_init = cv1810_pre_init,
++};
++
++static int sg2000_pre_init(struct device *dev, void __iomem *base,
++ struct cv1800_clk_ctrl *ctrl,
++ const struct cv1800_clk_desc *desc)
++{
++ cv18xx_clk_disable_auto_pd(base);
++
++ return 0;
++}
++
++static const struct cv1800_clk_desc sg2000_desc = {
++ .clks_data = &cv1810_hw_clks,
++ .pre_init = sg2000_pre_init,
++};
++
++static int cv1800_clk_init_ctrl(struct device *dev, void __iomem *reg,
++ struct cv1800_clk_ctrl *ctrl,
++ const struct cv1800_clk_desc *desc)
++{
++ int i, ret;
++
++ ctrl->desc = desc;
++ spin_lock_init(&ctrl->lock);
++
++ for (i = 0; i < desc->clks_data->num; i++) {
++ struct clk_hw *hw = desc->clks_data->hws[i];
++ struct cv1800_clk_common *common;
++ const char *name;
++
++ if (!hw)
++ continue;
++
++ name = hw->init->name;
++
++ common = hw_to_cv1800_clk_common(hw);
++ common->base = reg;
++ common->lock = &ctrl->lock;
++
++ ret = devm_clk_hw_register(dev, hw);
++ if (ret) {
++ dev_err(dev, "Couldn't register clock %d - %s\n",
++ i, name);
++ return ret;
++ }
++ }
++
++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
++ desc->clks_data);
++
++ return ret;
++}
++
++static int cv1800_clk_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ void __iomem *reg;
++ int ret;
++ const struct cv1800_clk_desc *desc;
++ struct cv1800_clk_ctrl *ctrl;
++
++ reg = devm_platform_ioremap_resource(pdev, 0);
++ if (IS_ERR(reg))
++ return PTR_ERR(reg);
++
++ desc = device_get_match_data(dev);
++ if (!desc) {
++ dev_err(dev, "no match data for platform\n");
++ return -EINVAL;
++ }
++
++ ctrl = devm_kmalloc(dev, sizeof(*ctrl), GFP_KERNEL);
++ if (!ctrl)
++ return -ENOMEM;
++
++ if (desc->pre_init) {
++ ret = desc->pre_init(dev, reg, ctrl, desc);
++ if (ret)
++ return ret;
++ }
++
++ ret = cv1800_clk_init_ctrl(dev, reg, ctrl, desc);
++
++ return ret;
++}
++
++static const struct of_device_id cv1800_clk_ids[] = {
++ { .compatible = "sophgo,cv1800-clk", .data = &cv1800_desc },
++ { .compatible = "sophgo,cv1810-clk", .data = &cv1810_desc },
++ { .compatible = "sophgo,sg2000-clk", .data = &sg2000_desc },
++ { }
++};
++MODULE_DEVICE_TABLE(of, cv1800_clk_ids);
++
++static struct platform_driver cv1800_clk_driver = {
++ .probe = cv1800_clk_probe,
++ .driver = {
++ .name = "cv1800-clk",
++ .suppress_bind_attrs = true,
++ .of_match_table = cv1800_clk_ids,
++ },
++};
++module_platform_driver(cv1800_clk_driver);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/clk/sophgo/clk-cv1800.h b/drivers/clk/sophgo/clk-cv1800.h
+new file mode 100644
+index 000000000000..1e7107b5d05e
+--- /dev/null
++++ b/drivers/clk/sophgo/clk-cv1800.h
+@@ -0,0 +1,123 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
++ */
++
++#ifndef _CLK_SOPHGO_CV1800_H_
++#define _CLK_SOPHGO_CV1800_H_
++
++#include <dt-bindings/clock/sophgo,cv1800.h>
++
++#define CV1800_CLK_MAX (CLK_XTAL_AP + 1)
++#define CV1810_CLK_MAX (CLK_DISP_SRC_VIP + 1)
++
++#define REG_PLL_G2_CTRL 0x800
++#define REG_PLL_G2_STATUS 0x804
++#define REG_MIPIMPLL_CSR 0x808
++#define REG_A0PLL_CSR 0x80C
++#define REG_DISPPLL_CSR 0x810
++#define REG_CAM0PLL_CSR 0x814
++#define REG_CAM1PLL_CSR 0x818
++#define REG_PLL_G2_SSC_SYN_CTRL 0x840
++#define REG_A0PLL_SSC_SYN_CTRL 0x850
++#define REG_A0PLL_SSC_SYN_SET 0x854
++#define REG_A0PLL_SSC_SYN_SPAN 0x858
++#define REG_A0PLL_SSC_SYN_STEP 0x85C
++#define REG_DISPPLL_SSC_SYN_CTRL 0x860
++#define REG_DISPPLL_SSC_SYN_SET 0x864
++#define REG_DISPPLL_SSC_SYN_SPAN 0x868
++#define REG_DISPPLL_SSC_SYN_STEP 0x86C
++#define REG_CAM0PLL_SSC_SYN_CTRL 0x870
++#define REG_CAM0PLL_SSC_SYN_SET 0x874
++#define REG_CAM0PLL_SSC_SYN_SPAN 0x878
++#define REG_CAM0PLL_SSC_SYN_STEP 0x87C
++#define REG_CAM1PLL_SSC_SYN_CTRL 0x880
++#define REG_CAM1PLL_SSC_SYN_SET 0x884
++#define REG_CAM1PLL_SSC_SYN_SPAN 0x888
++#define REG_CAM1PLL_SSC_SYN_STEP 0x88C
++#define REG_APLL_FRAC_DIV_CTRL 0x890
++#define REG_APLL_FRAC_DIV_M 0x894
++#define REG_APLL_FRAC_DIV_N 0x898
++#define REG_MIPIMPLL_CLK_CSR 0x8A0
++#define REG_A0PLL_CLK_CSR 0x8A4
++#define REG_DISPPLL_CLK_CSR 0x8A8
++#define REG_CAM0PLL_CLK_CSR 0x8AC
++#define REG_CAM1PLL_CLK_CSR 0x8B0
++#define REG_CLK_CAM0_SRC_DIV 0x8C0
++#define REG_CLK_CAM1_SRC_DIV 0x8C4
++
++/* top_pll_g6 */
++#define REG_PLL_G6_CTRL 0x900
++#define REG_PLL_G6_STATUS 0x904
++#define REG_MPLL_CSR 0x908
++#define REG_TPLL_CSR 0x90C
++#define REG_FPLL_CSR 0x910
++#define REG_PLL_G6_SSC_SYN_CTRL 0x940
++#define REG_DPLL_SSC_SYN_CTRL 0x950
++#define REG_DPLL_SSC_SYN_SET 0x954
++#define REG_DPLL_SSC_SYN_SPAN 0x958
++#define REG_DPLL_SSC_SYN_STEP 0x95C
++#define REG_MPLL_SSC_SYN_CTRL 0x960
++#define REG_MPLL_SSC_SYN_SET 0x964
++#define REG_MPLL_SSC_SYN_SPAN 0x968
++#define REG_MPLL_SSC_SYN_STEP 0x96C
++#define REG_TPLL_SSC_SYN_CTRL 0x970
++#define REG_TPLL_SSC_SYN_SET 0x974
++#define REG_TPLL_SSC_SYN_SPAN 0x978
++#define REG_TPLL_SSC_SYN_STEP 0x97C
++
++/* clkgen */
++#define REG_CLK_EN_0 0x000
++#define REG_CLK_EN_1 0x004
++#define REG_CLK_EN_2 0x008
++#define REG_CLK_EN_3 0x00C
++#define REG_CLK_EN_4 0x010
++#define REG_CLK_SEL_0 0x020
++#define REG_CLK_BYP_0 0x030
++#define REG_CLK_BYP_1 0x034
++
++#define REG_DIV_CLK_A53_0 0x040
++#define REG_DIV_CLK_A53_1 0x044
++#define REG_DIV_CLK_CPU_AXI0 0x048
++#define REG_DIV_CLK_CPU_GIC 0x050
++#define REG_DIV_CLK_TPU 0x054
++#define REG_DIV_CLK_EMMC 0x064
++#define REG_DIV_CLK_EMMC_100K 0x06C
++#define REG_DIV_CLK_SD0 0x070
++#define REG_DIV_CLK_SD0_100K 0x078
++#define REG_DIV_CLK_SD1 0x07C
++#define REG_DIV_CLK_SD1_100K 0x084
++#define REG_DIV_CLK_SPI_NAND 0x088
++#define REG_DIV_CLK_ETH0_500M 0x08C
++#define REG_DIV_CLK_ETH1_500M 0x090
++#define REG_DIV_CLK_GPIO_DB 0x094
++#define REG_DIV_CLK_SDMA_AUD0 0x098
++#define REG_DIV_CLK_SDMA_AUD1 0x09C
++#define REG_DIV_CLK_SDMA_AUD2 0x0A0
++#define REG_DIV_CLK_SDMA_AUD3 0x0A4
++#define REG_DIV_CLK_CAM0_200 0x0A8
++#define REG_DIV_CLK_AXI4 0x0B8
++#define REG_DIV_CLK_AXI6 0x0BC
++#define REG_DIV_CLK_DSI_ESC 0x0C4
++#define REG_DIV_CLK_AXI_VIP 0x0C8
++#define REG_DIV_CLK_SRC_VIP_SYS_0 0x0D0
++#define REG_DIV_CLK_SRC_VIP_SYS_1 0x0D8
++#define REG_DIV_CLK_DISP_SRC_VIP 0x0E0
++#define REG_DIV_CLK_AXI_VIDEO_CODEC 0x0E4
++#define REG_DIV_CLK_VC_SRC0 0x0EC
++#define REG_DIV_CLK_1M 0x0FC
++#define REG_DIV_CLK_SPI 0x100
++#define REG_DIV_CLK_I2C 0x104
++#define REG_DIV_CLK_SRC_VIP_SYS_2 0x110
++#define REG_DIV_CLK_AUDSRC 0x118
++#define REG_DIV_CLK_PWM_SRC_0 0x120
++#define REG_DIV_CLK_AP_DEBUG 0x128
++#define REG_DIV_CLK_RTCSYS_SRC_0 0x12C
++#define REG_DIV_CLK_C906_0_0 0x130
++#define REG_DIV_CLK_C906_0_1 0x134
++#define REG_DIV_CLK_C906_1_0 0x138
++#define REG_DIV_CLK_C906_1_1 0x13C
++#define REG_DIV_CLK_SRC_VIP_SYS_3 0x140
++#define REG_DIV_CLK_SRC_VIP_SYS_4 0x144
++
++#endif /* _CLK_SOPHGO_CV1800_H_ */
+diff --git a/drivers/clk/sophgo/clk-cv18xx-common.c b/drivers/clk/sophgo/clk-cv18xx-common.c
+new file mode 100644
+index 000000000000..cbcdd88f0e23
+--- /dev/null
++++ b/drivers/clk/sophgo/clk-cv18xx-common.c
+@@ -0,0 +1,66 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
++ */
++
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/spinlock.h>
++#include <linux/bug.h>
++
++#include "clk-cv18xx-common.h"
++
++int cv1800_clk_setbit(struct cv1800_clk_common *common,
++ struct cv1800_clk_regbit *field)
++{
++ u32 mask = BIT(field->shift);
++ u32 value;
++ unsigned long flags;
++
++ spin_lock_irqsave(common->lock, flags);
++
++ value = readl(common->base + field->reg);
++ writel(value | mask, common->base + field->reg);
++
++ spin_unlock_irqrestore(common->lock, flags);
++
++ return 0;
++}
++
++int cv1800_clk_clearbit(struct cv1800_clk_common *common,
++ struct cv1800_clk_regbit *field)
++{
++ u32 mask = BIT(field->shift);
++ u32 value;
++ unsigned long flags;
++
++ spin_lock_irqsave(common->lock, flags);
++
++ value = readl(common->base + field->reg);
++ writel(value & ~mask, common->base + field->reg);
++
++ spin_unlock_irqrestore(common->lock, flags);
++
++ return 0;
++}
++
++int cv1800_clk_checkbit(struct cv1800_clk_common *common,
++ struct cv1800_clk_regbit *field)
++{
++ return readl(common->base + field->reg) & BIT(field->shift);
++}
++
++#define PLL_LOCK_TIMEOUT_US (200 * 1000)
++
++void cv1800_clk_wait_for_lock(struct cv1800_clk_common *common,
++ u32 reg, u32 lock)
++{
++ void __iomem *addr = common->base + reg;
++ u32 regval;
++
++ if (!lock)
++ return;
++
++ WARN_ON(readl_relaxed_poll_timeout(addr, regval, regval & lock,
++ 100, PLL_LOCK_TIMEOUT_US));
++}
+diff --git a/drivers/clk/sophgo/clk-cv18xx-common.h b/drivers/clk/sophgo/clk-cv18xx-common.h
+new file mode 100644
+index 000000000000..2bfda02b2064
+--- /dev/null
++++ b/drivers/clk/sophgo/clk-cv18xx-common.h
+@@ -0,0 +1,81 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
++ */
++
++#ifndef _CLK_SOPHGO_CV18XX_IP_H_
++#define _CLK_SOPHGO_CV18XX_IP_H_
++
++#include <linux/compiler.h>
++#include <linux/clk-provider.h>
++#include <linux/bitfield.h>
++
++struct cv1800_clk_common {
++ void __iomem *base;
++ spinlock_t *lock;
++ struct clk_hw hw;
++ unsigned long features;
++};
++
++#define CV1800_CLK_COMMON(_name, _parents, _op, _flags) \
++ { \
++ .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parents, \
++ _op, _flags), \
++ }
++
++static inline struct cv1800_clk_common *
++hw_to_cv1800_clk_common(struct clk_hw *hw)
++{
++ return container_of(hw, struct cv1800_clk_common, hw);
++}
++
++struct cv1800_clk_regbit {
++ u16 reg;
++ s8 shift;
++};
++
++struct cv1800_clk_regfield {
++ u16 reg;
++ u8 shift;
++ u8 width;
++ s16 initval;
++ unsigned long flags;
++};
++
++#define CV1800_CLK_BIT(_reg, _shift) \
++ { \
++ .reg = _reg, \
++ .shift = _shift, \
++ }
++
++#define CV1800_CLK_REG(_reg, _shift, _width, _initval, _flags) \
++ { \
++ .reg = _reg, \
++ .shift = _shift, \
++ .width = _width, \
++ .initval = _initval, \
++ .flags = _flags, \
++ }
++
++#define cv1800_clk_regfield_genmask(_reg) \
++ GENMASK((_reg)->shift + (_reg)->width - 1, (_reg)->shift)
++#define cv1800_clk_regfield_get(_val, _reg) \
++ (((_val) >> (_reg)->shift) & GENMASK((_reg)->width - 1, 0))
++#define cv1800_clk_regfield_set(_val, _new, _reg) \
++ (((_val) & ~cv1800_clk_regfield_genmask((_reg))) | \
++ (((_new) & GENMASK((_reg)->width - 1, 0)) << (_reg)->shift))
++
++#define _CV1800_SET_FIELD(_reg, _val, _field) \
++ (((_reg) & ~(_field)) | FIELD_PREP((_field), (_val)))
++
++int cv1800_clk_setbit(struct cv1800_clk_common *common,
++ struct cv1800_clk_regbit *field);
++int cv1800_clk_clearbit(struct cv1800_clk_common *common,
++ struct cv1800_clk_regbit *field);
++int cv1800_clk_checkbit(struct cv1800_clk_common *common,
++ struct cv1800_clk_regbit *field);
++
++void cv1800_clk_wait_for_lock(struct cv1800_clk_common *common,
++ u32 reg, u32 lock);
++
++#endif // _CLK_SOPHGO_CV18XX_IP_H_
+diff --git a/drivers/clk/sophgo/clk-cv18xx-ip.c b/drivers/clk/sophgo/clk-cv18xx-ip.c
+new file mode 100644
+index 000000000000..805f561725ae
+--- /dev/null
++++ b/drivers/clk/sophgo/clk-cv18xx-ip.c
+@@ -0,0 +1,887 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/io.h>
++#include <linux/gcd.h>
++#include <linux/spinlock.h>
++
++#include "clk-cv18xx-ip.h"
++
++/* GATE */
++static inline struct cv1800_clk_gate *hw_to_cv1800_clk_gate(struct clk_hw *hw)
++{
++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw);
++
++ return container_of(common, struct cv1800_clk_gate, common);
++}
++
++static int gate_enable(struct clk_hw *hw)
++{
++ struct cv1800_clk_gate *gate = hw_to_cv1800_clk_gate(hw);
++
++ return cv1800_clk_setbit(&gate->common, &gate->gate);
++}
++
++static void gate_disable(struct clk_hw *hw)
++{
++ struct cv1800_clk_gate *gate = hw_to_cv1800_clk_gate(hw);
++
++ cv1800_clk_clearbit(&gate->common, &gate->gate);
++}
++
++static int gate_is_enabled(struct clk_hw *hw)
++{
++ struct cv1800_clk_gate *gate = hw_to_cv1800_clk_gate(hw);
++
++ return cv1800_clk_checkbit(&gate->common, &gate->gate);
++}
++
++static unsigned long gate_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ return parent_rate;
++}
++
++static long gate_round_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long *parent_rate)
++{
++ return *parent_rate;
++}
++
++static int gate_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ return 0;
++}
++
++const struct clk_ops cv1800_clk_gate_ops = {
++ .disable = gate_disable,
++ .enable = gate_enable,
++ .is_enabled = gate_is_enabled,
++
++ .recalc_rate = gate_recalc_rate,
++ .round_rate = gate_round_rate,
++ .set_rate = gate_set_rate,
++};
++
++/* DIV */
++#define _DIV_EN_CLK_DIV_FACTOR_FIELD BIT(3)
++
++#define DIV_GET_EN_CLK_DIV_FACTOR(_reg) \
++ FIELD_GET(_DIV_EN_CLK_DIV_FACTOR_FIELD, _reg)
++
++#define DIV_SET_EN_DIV_FACTOR(_reg) \
++ _CV1800_SET_FIELD(_reg, 1, _DIV_EN_CLK_DIV_FACTOR_FIELD)
++
++static inline struct cv1800_clk_div *hw_to_cv1800_clk_div(struct clk_hw *hw)
++{
++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw);
++
++ return container_of(common, struct cv1800_clk_div, common);
++}
++
++static int div_enable(struct clk_hw *hw)
++{
++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw);
++
++ return cv1800_clk_setbit(&div->common, &div->gate);
++}
++
++static void div_disable(struct clk_hw *hw)
++{
++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw);
++
++ cv1800_clk_clearbit(&div->common, &div->gate);
++}
++
++static int div_is_enabled(struct clk_hw *hw)
++{
++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw);
++
++ return cv1800_clk_checkbit(&div->common, &div->gate);
++}
++
++static int div_helper_set_rate(struct cv1800_clk_common *common,
++ struct cv1800_clk_regfield *div,
++ unsigned long val)
++{
++ unsigned long flags;
++ u32 reg;
++
++ if (div->width == 0)
++ return 0;
++
++ spin_lock_irqsave(common->lock, flags);
++
++ reg = readl(common->base + div->reg);
++ reg = cv1800_clk_regfield_set(reg, val, div);
++ if (div->initval > 0)
++ reg = DIV_SET_EN_DIV_FACTOR(reg);
++
++ writel(reg, common->base + div->reg);
++
++ spin_unlock_irqrestore(common->lock, flags);
++
++ return 0;
++}
++
++static u32 div_helper_get_clockdiv(struct cv1800_clk_common *common,
++ struct cv1800_clk_regfield *div)
++{
++ u32 clockdiv = 1;
++ u32 reg;
++
++ if (!div || div->initval < 0 || (div->width == 0 && div->initval <= 0))
++ return 1;
++
++ if (div->width == 0 && div->initval > 0)
++ return div->initval;
++
++ reg = readl(common->base + div->reg);
++
++ if (div->initval == 0 || DIV_GET_EN_CLK_DIV_FACTOR(reg))
++ clockdiv = cv1800_clk_regfield_get(reg, div);
++ else if (div->initval > 0)
++ clockdiv = div->initval;
++
++ return clockdiv;
++}
++
++static u32 div_helper_round_rate(struct cv1800_clk_regfield *div,
++ struct clk_hw *hw, struct clk_hw *parent,
++ unsigned long rate, unsigned long *prate)
++{
++ if (div->width == 0) {
++ if (div->initval <= 0)
++ return DIV_ROUND_UP_ULL(*prate, 1);
++ else
++ return DIV_ROUND_UP_ULL(*prate, div->initval);
++ }
++
++ return divider_round_rate_parent(hw, parent, rate, prate, NULL,
++ div->width, div->flags);
++}
++
++static long div_round_rate(struct clk_hw *parent, unsigned long *parent_rate,
++ unsigned long rate, int id, void *data)
++{
++ struct cv1800_clk_div *div = data;
++
++ return div_helper_round_rate(&div->div, &div->common.hw, parent,
++ rate, parent_rate);
++}
++
++static bool div_is_better_rate(struct cv1800_clk_common *common,
++ unsigned long target, unsigned long now,
++ unsigned long best)
++{
++ if (common->features & CLK_DIVIDER_ROUND_CLOSEST)
++ return abs_diff(target, now) < abs_diff(target, best);
++
++ return now <= target && now > best;
++}
++
++static int mux_helper_determine_rate(struct cv1800_clk_common *common,
++ struct clk_rate_request *req,
++ long (*round)(struct clk_hw *,
++ unsigned long *,
++ unsigned long,
++ int,
++ void *),
++ void *data)
++{
++ unsigned long best_parent_rate = 0, best_rate = 0;
++ struct clk_hw *best_parent, *hw = &common->hw;
++ unsigned int i;
++
++ if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
++ unsigned long adj_parent_rate;
++
++ best_parent = clk_hw_get_parent(hw);
++ best_parent_rate = clk_hw_get_rate(best_parent);
++
++ best_rate = round(best_parent, &adj_parent_rate,
++ req->rate, -1, data);
++
++ goto find;
++ }
++
++ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
++ unsigned long tmp_rate, parent_rate;
++ struct clk_hw *parent;
++
++ parent = clk_hw_get_parent_by_index(hw, i);
++ if (!parent)
++ continue;
++
++ parent_rate = clk_hw_get_rate(parent);
++
++ tmp_rate = round(parent, &parent_rate, req->rate, i, data);
++
++ if (tmp_rate == req->rate) {
++ best_parent = parent;
++ best_parent_rate = parent_rate;
++ best_rate = tmp_rate;
++ goto find;
++ }
++
++ if (div_is_better_rate(common, req->rate,
++ tmp_rate, best_rate)) {
++ best_parent = parent;
++ best_parent_rate = parent_rate;
++ best_rate = tmp_rate;
++ }
++ }
++
++ if (best_rate == 0)
++ return -EINVAL;
++
++find:
++ req->best_parent_hw = best_parent;
++ req->best_parent_rate = best_parent_rate;
++ req->rate = best_rate;
++ return 0;
++}
++
++static int div_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw);
++
++ return mux_helper_determine_rate(&div->common, req,
++ div_round_rate, div);
++}
++
++static unsigned long div_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw);
++ unsigned long val;
++
++ val = div_helper_get_clockdiv(&div->common, &div->div);
++ if (val == 0)
++ return 0;
++
++ return divider_recalc_rate(hw, parent_rate, val, NULL,
++ div->div.flags, div->div.width);
++}
++
++static int div_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw);
++ unsigned long val;
++
++ val = divider_get_val(rate, parent_rate, NULL,
++ div->div.width, div->div.flags);
++
++ return div_helper_set_rate(&div->common, &div->div, val);
++}
++
++const struct clk_ops cv1800_clk_div_ops = {
++ .disable = div_disable,
++ .enable = div_enable,
++ .is_enabled = div_is_enabled,
++
++ .determine_rate = div_determine_rate,
++ .recalc_rate = div_recalc_rate,
++ .set_rate = div_set_rate,
++};
++
++static inline struct cv1800_clk_bypass_div *
++hw_to_cv1800_clk_bypass_div(struct clk_hw *hw)
++{
++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw);
++
++ return container_of(div, struct cv1800_clk_bypass_div, div);
++}
++
++static long bypass_div_round_rate(struct clk_hw *parent,
++ unsigned long *parent_rate,
++ unsigned long rate, int id, void *data)
++{
++ struct cv1800_clk_bypass_div *div = data;
++
++ if (id == -1) {
++ if (cv1800_clk_checkbit(&div->div.common, &div->bypass))
++ return *parent_rate;
++ else
++ return div_round_rate(parent, parent_rate, rate,
++ -1, &div->div);
++ }
++
++ if (id == 0)
++ return *parent_rate;
++
++ return div_round_rate(parent, parent_rate, rate, id - 1, &div->div);
++}
++
++static int bypass_div_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw);
++
++ return mux_helper_determine_rate(&div->div.common, req,
++ bypass_div_round_rate, div);
++}
++
++static unsigned long bypass_div_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw);
++
++ if (cv1800_clk_checkbit(&div->div.common, &div->bypass))
++ return parent_rate;
++
++ return div_recalc_rate(hw, parent_rate);
++}
++
++static int bypass_div_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw);
++
++ if (cv1800_clk_checkbit(&div->div.common, &div->bypass))
++ return 0;
++
++ return div_set_rate(hw, rate, parent_rate);
++}
++
++static u8 bypass_div_get_parent(struct clk_hw *hw)
++{
++ struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw);
++
++ if (cv1800_clk_checkbit(&div->div.common, &div->bypass))
++ return 0;
++
++ return 1;
++}
++
++static int bypass_div_set_parent(struct clk_hw *hw, u8 index)
++{
++ struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw);
++
++ if (index)
++ return cv1800_clk_clearbit(&div->div.common, &div->bypass);
++
++ return cv1800_clk_setbit(&div->div.common, &div->bypass);
++}
++
++const struct clk_ops cv1800_clk_bypass_div_ops = {
++ .disable = div_disable,
++ .enable = div_enable,
++ .is_enabled = div_is_enabled,
++
++ .determine_rate = bypass_div_determine_rate,
++ .recalc_rate = bypass_div_recalc_rate,
++ .set_rate = bypass_div_set_rate,
++
++ .set_parent = bypass_div_set_parent,
++ .get_parent = bypass_div_get_parent,
++};
++
++/* MUX */
++static inline struct cv1800_clk_mux *hw_to_cv1800_clk_mux(struct clk_hw *hw)
++{
++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw);
++
++ return container_of(common, struct cv1800_clk_mux, common);
++}
++
++static int mux_enable(struct clk_hw *hw)
++{
++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw);
++
++ return cv1800_clk_setbit(&mux->common, &mux->gate);
++}
++
++static void mux_disable(struct clk_hw *hw)
++{
++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw);
++
++ cv1800_clk_clearbit(&mux->common, &mux->gate);
++}
++
++static int mux_is_enabled(struct clk_hw *hw)
++{
++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw);
++
++ return cv1800_clk_checkbit(&mux->common, &mux->gate);
++}
++
++static long mux_round_rate(struct clk_hw *parent, unsigned long *parent_rate,
++ unsigned long rate, int id, void *data)
++{
++ struct cv1800_clk_mux *mux = data;
++
++ return div_helper_round_rate(&mux->div, &mux->common.hw, parent,
++ rate, parent_rate);
++}
++
++static int mux_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw);
++
++ return mux_helper_determine_rate(&mux->common, req,
++ mux_round_rate, mux);
++}
++
++static unsigned long mux_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw);
++ unsigned long val;
++
++ val = div_helper_get_clockdiv(&mux->common, &mux->div);
++ if (val == 0)
++ return 0;
++
++ return divider_recalc_rate(hw, parent_rate, val, NULL,
++ mux->div.flags, mux->div.width);
++}
++
++static int mux_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw);
++ unsigned long val;
++
++ val = divider_get_val(rate, parent_rate, NULL,
++ mux->div.width, mux->div.flags);
++
++ return div_helper_set_rate(&mux->common, &mux->div, val);
++}
++
++static u8 mux_get_parent(struct clk_hw *hw)
++{
++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw);
++ u32 reg = readl(mux->common.base + mux->mux.reg);
++
++ return cv1800_clk_regfield_get(reg, &mux->mux);
++}
++
++static int _mux_set_parent(struct cv1800_clk_mux *mux, u8 index)
++{
++ u32 reg;
++
++ reg = readl(mux->common.base + mux->mux.reg);
++ reg = cv1800_clk_regfield_set(reg, index, &mux->mux);
++ writel(reg, mux->common.base + mux->mux.reg);
++
++ return 0;
++}
++
++static int mux_set_parent(struct clk_hw *hw, u8 index)
++{
++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw);
++ unsigned long flags;
++
++ spin_lock_irqsave(mux->common.lock, flags);
++
++ _mux_set_parent(mux, index);
++
++ spin_unlock_irqrestore(mux->common.lock, flags);
++
++ return 0;
++}
++
++const struct clk_ops cv1800_clk_mux_ops = {
++ .disable = mux_disable,
++ .enable = mux_enable,
++ .is_enabled = mux_is_enabled,
++
++ .determine_rate = mux_determine_rate,
++ .recalc_rate = mux_recalc_rate,
++ .set_rate = mux_set_rate,
++
++ .set_parent = mux_set_parent,
++ .get_parent = mux_get_parent,
++};
++
++static inline struct cv1800_clk_bypass_mux *
++hw_to_cv1800_clk_bypass_mux(struct clk_hw *hw)
++{
++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw);
++
++ return container_of(mux, struct cv1800_clk_bypass_mux, mux);
++}
++
++static long bypass_mux_round_rate(struct clk_hw *parent,
++ unsigned long *parent_rate,
++ unsigned long rate, int id, void *data)
++{
++ struct cv1800_clk_bypass_mux *mux = data;
++
++ if (id == -1) {
++ if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass))
++ return *parent_rate;
++ else
++ return mux_round_rate(parent, parent_rate, rate,
++ -1, &mux->mux);
++ }
++
++ if (id == 0)
++ return *parent_rate;
++
++ return mux_round_rate(parent, parent_rate, rate, id - 1, &mux->mux);
++}
++
++static int bypass_mux_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw);
++
++ return mux_helper_determine_rate(&mux->mux.common, req,
++ bypass_mux_round_rate, mux);
++}
++
++static unsigned long bypass_mux_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw);
++
++ if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass))
++ return parent_rate;
++
++ return mux_recalc_rate(hw, parent_rate);
++}
++
++static int bypass_mux_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw);
++
++ if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass))
++ return 0;
++
++ return mux_set_rate(hw, rate, parent_rate);
++}
++
++static u8 bypass_mux_get_parent(struct clk_hw *hw)
++{
++ struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw);
++
++ if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass))
++ return 0;
++
++ return mux_get_parent(hw) + 1;
++}
++
++static int bypass_mux_set_parent(struct clk_hw *hw, u8 index)
++{
++ struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw);
++
++ if (index == 0)
++ return cv1800_clk_setbit(&mux->mux.common, &mux->bypass);
++
++ return cv1800_clk_clearbit(&mux->mux.common, &mux->bypass);
++}
++
++const struct clk_ops cv1800_clk_bypass_mux_ops = {
++ .disable = mux_disable,
++ .enable = mux_enable,
++ .is_enabled = mux_is_enabled,
++
++ .determine_rate = bypass_mux_determine_rate,
++ .recalc_rate = bypass_mux_recalc_rate,
++ .set_rate = bypass_mux_set_rate,
++
++ .set_parent = bypass_mux_set_parent,
++ .get_parent = bypass_mux_get_parent,
++};
++
++/* MMUX */
++static inline struct cv1800_clk_mmux *hw_to_cv1800_clk_mmux(struct clk_hw *hw)
++{
++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw);
++
++ return container_of(common, struct cv1800_clk_mmux, common);
++}
++
++static u8 mmux_get_parent_id(struct cv1800_clk_mmux *mmux)
++{
++ struct clk_hw *hw = &mmux->common.hw;
++ struct clk_hw *parent = clk_hw_get_parent(hw);
++ unsigned int i;
++
++ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
++ if (parent == clk_hw_get_parent_by_index(hw, i))
++ return i;
++ }
++
++ unreachable();
++}
++
++static int mmux_enable(struct clk_hw *hw)
++{
++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw);
++
++ return cv1800_clk_setbit(&mmux->common, &mmux->gate);
++}
++
++static void mmux_disable(struct clk_hw *hw)
++{
++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw);
++
++ cv1800_clk_clearbit(&mmux->common, &mmux->gate);
++}
++
++static int mmux_is_enabled(struct clk_hw *hw)
++{
++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw);
++
++ return cv1800_clk_checkbit(&mmux->common, &mmux->gate);
++}
++
++static long mmux_round_rate(struct clk_hw *parent, unsigned long *parent_rate,
++ unsigned long rate, int id, void *data)
++{
++ struct cv1800_clk_mmux *mmux = data;
++ s8 div_id;
++
++ if (id == -1) {
++ if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass))
++ return *parent_rate;
++
++ id = mmux_get_parent_id(mmux);
++ }
++
++ div_id = mmux->parent2sel[id];
++
++ if (div_id < 0)
++ return *parent_rate;
++
++ return div_helper_round_rate(&mmux->div[div_id],
++ &mmux->common.hw, parent,
++ rate, parent_rate);
++}
++
++static int mmux_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw);
++
++ return mux_helper_determine_rate(&mmux->common, req,
++ mmux_round_rate, mmux);
++}
++
++static unsigned long mmux_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw);
++ unsigned long val;
++ struct cv1800_clk_regfield *div;
++
++ if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass))
++ return parent_rate;
++
++ if (cv1800_clk_checkbit(&mmux->common, &mmux->clk_sel))
++ div = &mmux->div[0];
++ else
++ div = &mmux->div[1];
++
++ val = div_helper_get_clockdiv(&mmux->common, div);
++ if (val == 0)
++ return 0;
++
++ return divider_recalc_rate(hw, parent_rate, val, NULL,
++ div->flags, div->width);
++}
++
++static int mmux_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw);
++ struct cv1800_clk_regfield *div;
++ unsigned long val;
++
++ if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass))
++ return parent_rate;
++
++ if (cv1800_clk_checkbit(&mmux->common, &mmux->clk_sel))
++ div = &mmux->div[0];
++ else
++ div = &mmux->div[1];
++
++ val = divider_get_val(rate, parent_rate, NULL,
++ div->width, div->flags);
++
++ return div_helper_set_rate(&mmux->common, div, val);
++}
++
++static u8 mmux_get_parent(struct clk_hw *hw)
++{
++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw);
++ struct cv1800_clk_regfield *mux;
++ u32 reg;
++ s8 clk_sel;
++
++ if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass))
++ return 0;
++
++ if (cv1800_clk_checkbit(&mmux->common, &mmux->clk_sel))
++ clk_sel = 0;
++ else
++ clk_sel = 1;
++ mux = &mmux->mux[clk_sel];
++
++ reg = readl(mmux->common.base + mux->reg);
++
++ return mmux->sel2parent[clk_sel][cv1800_clk_regfield_get(reg, mux)];
++}
++
++static int mmux_set_parent(struct clk_hw *hw, u8 index)
++{
++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw);
++ struct cv1800_clk_regfield *mux;
++ unsigned long flags;
++ u32 reg;
++ s8 clk_sel = mmux->parent2sel[index];
++
++ if (index == 0 || clk_sel == -1) {
++ cv1800_clk_setbit(&mmux->common, &mmux->bypass);
++ goto release;
++ }
++
++ cv1800_clk_clearbit(&mmux->common, &mmux->bypass);
++
++ if (clk_sel)
++ cv1800_clk_clearbit(&mmux->common, &mmux->clk_sel);
++ else
++ cv1800_clk_setbit(&mmux->common, &mmux->clk_sel);
++
++ spin_lock_irqsave(mmux->common.lock, flags);
++
++ mux = &mmux->mux[clk_sel];
++ reg = readl(mmux->common.base + mux->reg);
++ reg = cv1800_clk_regfield_set(reg, index, mux);
++
++ writel(reg, mmux->common.base + mux->reg);
++
++ spin_unlock_irqrestore(mmux->common.lock, flags);
++
++release:
++ return 0;
++}
++
++const struct clk_ops cv1800_clk_mmux_ops = {
++ .disable = mmux_disable,
++ .enable = mmux_enable,
++ .is_enabled = mmux_is_enabled,
++
++ .determine_rate = mmux_determine_rate,
++ .recalc_rate = mmux_recalc_rate,
++ .set_rate = mmux_set_rate,
++
++ .set_parent = mmux_set_parent,
++ .get_parent = mmux_get_parent,
++};
++
++/* AUDIO CLK */
++static inline struct cv1800_clk_audio *
++hw_to_cv1800_clk_audio(struct clk_hw *hw)
++{
++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw);
++
++ return container_of(common, struct cv1800_clk_audio, common);
++}
++
++static int aclk_enable(struct clk_hw *hw)
++{
++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw);
++
++ cv1800_clk_setbit(&aclk->common, &aclk->src_en);
++ return cv1800_clk_setbit(&aclk->common, &aclk->output_en);
++}
++
++static void aclk_disable(struct clk_hw *hw)
++{
++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw);
++
++ cv1800_clk_clearbit(&aclk->common, &aclk->output_en);
++ cv1800_clk_clearbit(&aclk->common, &aclk->src_en);
++}
++
++static int aclk_is_enabled(struct clk_hw *hw)
++{
++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw);
++
++ return cv1800_clk_checkbit(&aclk->common, &aclk->output_en);
++}
++
++static int aclk_determine_rate(struct clk_hw *hw,
++ struct clk_rate_request *req)
++{
++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw);
++
++ req->rate = aclk->target_rate;
++
++ return 0;
++}
++
++static unsigned long aclk_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw);
++ u64 rate = parent_rate;
++ u64 factor = 2;
++ u32 regval;
++
++ if (!cv1800_clk_checkbit(&aclk->common, &aclk->div_en))
++ return 0;
++
++ regval = readl(aclk->common.base + aclk->m.reg);
++ factor *= cv1800_clk_regfield_get(regval, &aclk->m);
++
++ regval = readl(aclk->common.base + aclk->n.reg);
++ rate *= cv1800_clk_regfield_get(regval, &aclk->n);
++
++ return DIV64_U64_ROUND_UP(rate, factor);
++}
++
++static void aclk_determine_mn(unsigned long parent_rate, unsigned long rate,
++ u32 *m, u32 *n)
++{
++ u32 tm = parent_rate / 2;
++ u32 tn = rate;
++ u32 tcommon = gcd(tm, tn);
++ *m = tm / tcommon;
++ *n = tn / tcommon;
++}
++
++static int aclk_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw);
++ unsigned long flags;
++ u32 m, n;
++
++ aclk_determine_mn(parent_rate, rate,
++ &m, &n);
++
++ spin_lock_irqsave(aclk->common.lock, flags);
++
++ writel(m, aclk->common.base + aclk->m.reg);
++ writel(n, aclk->common.base + aclk->n.reg);
++
++ cv1800_clk_setbit(&aclk->common, &aclk->div_en);
++ cv1800_clk_setbit(&aclk->common, &aclk->div_up);
++
++ spin_unlock_irqrestore(aclk->common.lock, flags);
++
++ return 0;
++}
++
++const struct clk_ops cv1800_clk_audio_ops = {
++ .disable = aclk_disable,
++ .enable = aclk_enable,
++ .is_enabled = aclk_is_enabled,
++
++ .determine_rate = aclk_determine_rate,
++ .recalc_rate = aclk_recalc_rate,
++ .set_rate = aclk_set_rate,
++};
+diff --git a/drivers/clk/sophgo/clk-cv18xx-ip.h b/drivers/clk/sophgo/clk-cv18xx-ip.h
+new file mode 100644
+index 000000000000..b37ba42bfde3
+--- /dev/null
++++ b/drivers/clk/sophgo/clk-cv18xx-ip.h
+@@ -0,0 +1,261 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
++ */
++
++#ifndef _CLK_SOPHGO_CV1800_IP_H_
++#define _CLK_SOPHGO_CV1800_IP_H_
++
++#include "clk-cv18xx-common.h"
++
++struct cv1800_clk_gate {
++ struct cv1800_clk_common common;
++ struct cv1800_clk_regbit gate;
++};
++
++struct cv1800_clk_div_data {
++ u32 reg;
++ u32 mask;
++ u32 width;
++ u32 init;
++ u32 flags;
++};
++
++struct cv1800_clk_div {
++ struct cv1800_clk_common common;
++ struct cv1800_clk_regbit gate;
++ struct cv1800_clk_regfield div;
++};
++
++struct cv1800_clk_bypass_div {
++ struct cv1800_clk_div div;
++ struct cv1800_clk_regbit bypass;
++};
++
++struct cv1800_clk_mux {
++ struct cv1800_clk_common common;
++ struct cv1800_clk_regbit gate;
++ struct cv1800_clk_regfield div;
++ struct cv1800_clk_regfield mux;
++};
++
++struct cv1800_clk_bypass_mux {
++ struct cv1800_clk_mux mux;
++ struct cv1800_clk_regbit bypass;
++};
++
++struct cv1800_clk_mmux {
++ struct cv1800_clk_common common;
++ struct cv1800_clk_regbit gate;
++ struct cv1800_clk_regfield div[2];
++ struct cv1800_clk_regfield mux[2];
++ struct cv1800_clk_regbit bypass;
++ struct cv1800_clk_regbit clk_sel;
++ const s8 *parent2sel;
++ const u8 *sel2parent[2];
++};
++
++struct cv1800_clk_audio {
++ struct cv1800_clk_common common;
++ struct cv1800_clk_regbit src_en;
++ struct cv1800_clk_regbit output_en;
++ struct cv1800_clk_regbit div_en;
++ struct cv1800_clk_regbit div_up;
++ struct cv1800_clk_regfield m;
++ struct cv1800_clk_regfield n;
++ u32 target_rate;
++};
++
++#define CV1800_GATE(_name, _parent, _gate_reg, _gate_shift, _flags) \
++ struct cv1800_clk_gate _name = { \
++ .common = CV1800_CLK_COMMON(#_name, _parent, \
++ &cv1800_clk_gate_ops, \
++ _flags), \
++ .gate = CV1800_CLK_BIT(_gate_reg, _gate_shift), \
++ }
++
++#define _CV1800_DIV(_name, _parent, _gate_reg, _gate_shift, \
++ _div_reg, _div_shift, _div_width, _div_init, \
++ _div_flag, _ops, _flags) \
++ { \
++ .common = CV1800_CLK_COMMON(#_name, _parent, \
++ _ops, _flags), \
++ .gate = CV1800_CLK_BIT(_gate_reg, \
++ _gate_shift), \
++ .div = CV1800_CLK_REG(_div_reg, _div_shift, \
++ _div_width, _div_init, \
++ _div_flag), \
++ }
++
++#define _CV1800_FIXED_DIV_FLAG \
++ (CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ROUND_CLOSEST)
++
++#define _CV1800_FIXED_DIV(_name, _parent, _gate_reg, _gate_shift, \
++ _fix_div, _ops, _flags) \
++ { \
++ .common = CV1800_CLK_COMMON(#_name, _parent, \
++ _ops, _flags), \
++ .gate = CV1800_CLK_BIT(_gate_reg, \
++ _gate_shift), \
++ .div = CV1800_CLK_REG(0, 0, 0, \
++ _fix_div, \
++ _CV1800_FIXED_DIV_FLAG),\
++ }
++
++#define CV1800_DIV(_name, _parent, _gate_reg, _gate_shift, \
++ _div_reg, _div_shift, _div_width, _div_init, \
++ _div_flag, _flags) \
++ struct cv1800_clk_div _name = \
++ _CV1800_DIV(_name, _parent, _gate_reg, _gate_shift, \
++ _div_reg, _div_shift, _div_width, _div_init,\
++ _div_flag, &cv1800_clk_div_ops, _flags)
++
++#define CV1800_BYPASS_DIV(_name, _parent, _gate_reg, _gate_shift, \
++ _div_reg, _div_shift, _div_width, _div_init, \
++ _div_flag, _bypass_reg, _bypass_shift, _flags)\
++ struct cv1800_clk_bypass_div _name = { \
++ .div = _CV1800_DIV(_name, _parent, \
++ _gate_reg, _gate_shift, \
++ _div_reg, _div_shift, \
++ _div_width, _div_init, _div_flag, \
++ &cv1800_clk_bypass_div_ops, \
++ _flags), \
++ .bypass = CV1800_CLK_BIT(_bypass_reg, _bypass_shift), \
++ }
++
++#define CV1800_FIXED_DIV(_name, _parent, _gate_reg, _gate_shift, \
++ _fix_div, _flags) \
++ struct cv1800_clk_div _name = \
++ _CV1800_FIXED_DIV(_name, _parent, \
++ _gate_reg, _gate_shift, \
++ _fix_div, \
++ &cv1800_clk_div_ops, _flags) \
++
++#define CV1800_BYPASS_FIXED_DIV(_name, _parent, _gate_reg, _gate_shift, \
++ _fix_div, _bypass_reg, _bypass_shift, \
++ _flags) \
++ struct cv1800_clk_bypass_div _name = { \
++ .div = _CV1800_FIXED_DIV(_name, _parent, \
++ _gate_reg, _gate_shift, \
++ _fix_div, \
++ &cv1800_clk_bypass_div_ops, \
++ _flags), \
++ .bypass = CV1800_CLK_BIT(_bypass_reg, _bypass_shift), \
++ }
++
++#define _CV1800_MUX(_name, _parent, _gate_reg, _gate_shift, \
++ _div_reg, _div_shift, _div_width, _div_init, \
++ _div_flag, \
++ _mux_reg, _mux_shift, _mux_width, \
++ _ops, _flags) \
++ { \
++ .common = CV1800_CLK_COMMON(#_name, _parent, \
++ _ops, _flags), \
++ .gate = CV1800_CLK_BIT(_gate_reg, \
++ _gate_shift), \
++ .div = CV1800_CLK_REG(_div_reg, _div_shift, \
++ _div_width, _div_init, \
++ _div_flag), \
++ .mux = CV1800_CLK_REG(_mux_reg, _mux_shift, \
++ _mux_width, 0, 0), \
++ }
++
++#define CV1800_MUX(_name, _parent, _gate_reg, _gate_shift, \
++ _div_reg, _div_shift, _div_width, _div_init, \
++ _div_flag, \
++ _mux_reg, _mux_shift, _mux_width, _flags) \
++ struct cv1800_clk_mux _name = \
++ _CV1800_MUX(_name, _parent, _gate_reg, _gate_shift, \
++ _div_reg, _div_shift, _div_width, _div_init,\
++ _div_flag, _mux_reg, _mux_shift, _mux_width,\
++ &cv1800_clk_mux_ops, _flags)
++
++#define CV1800_BYPASS_MUX(_name, _parent, _gate_reg, _gate_shift, \
++ _div_reg, _div_shift, _div_width, _div_init, \
++ _div_flag, \
++ _mux_reg, _mux_shift, _mux_width, \
++ _bypass_reg, _bypass_shift, _flags) \
++ struct cv1800_clk_bypass_mux _name = { \
++ .mux = _CV1800_MUX(_name, _parent, \
++ _gate_reg, _gate_shift, \
++ _div_reg, _div_shift, _div_width, \
++ _div_init, _div_flag, \
++ _mux_reg, _mux_shift, _mux_width, \
++ &cv1800_clk_bypass_mux_ops, \
++ _flags), \
++ .bypass = CV1800_CLK_BIT(_bypass_reg, _bypass_shift), \
++ }
++
++#define CV1800_MMUX(_name, _parent, _gate_reg, _gate_shift, \
++ _div0_reg, _div0_shift, _div0_width, _div0_init, \
++ _div0_flag, \
++ _div1_reg, _div1_shift, _div1_width, _div1_init, \
++ _div1_flag, \
++ _mux0_reg, _mux0_shift, _mux0_width, \
++ _mux1_reg, _mux1_shift, _mux1_width, \
++ _bypass_reg, _bypass_shift, \
++ _clk_sel_reg, _clk_sel_shift, \
++ _parent2sel, _sel2parent0, _sel2parent1, _flags) \
++ struct cv1800_clk_mmux _name = { \
++ .common = CV1800_CLK_COMMON(#_name, _parent, \
++ &cv1800_clk_mmux_ops,\
++ _flags), \
++ .gate = CV1800_CLK_BIT(_gate_reg, _gate_shift),\
++ .div = { \
++ CV1800_CLK_REG(_div0_reg, _div0_shift, \
++ _div0_width, _div0_init, \
++ _div0_flag), \
++ CV1800_CLK_REG(_div1_reg, _div1_shift, \
++ _div1_width, _div1_init, \
++ _div1_flag), \
++ }, \
++ .mux = { \
++ CV1800_CLK_REG(_mux0_reg, _mux0_shift, \
++ _mux0_width, 0, 0), \
++ CV1800_CLK_REG(_mux1_reg, _mux1_shift, \
++ _mux1_width, 0, 0), \
++ }, \
++ .bypass = CV1800_CLK_BIT(_bypass_reg, \
++ _bypass_shift), \
++ .clk_sel = CV1800_CLK_BIT(_clk_sel_reg, \
++ _clk_sel_shift), \
++ .parent2sel = _parent2sel, \
++ .sel2parent = { _sel2parent0, _sel2parent1 }, \
++ }
++
++#define CV1800_ACLK(_name, _parent, \
++ _src_en_reg, _src_en_reg_shift, \
++ _output_en_reg, _output_en_shift, \
++ _div_en_reg, _div_en_reg_shift, \
++ _div_up_reg, _div_up_reg_shift, \
++ _m_reg, _m_shift, _m_width, _m_flag, \
++ _n_reg, _n_shift, _n_width, _n_flag, \
++ _target_rate, _flags) \
++ struct cv1800_clk_audio _name = { \
++ .common = CV1800_CLK_COMMON(#_name, _parent, \
++ &cv1800_clk_audio_ops,\
++ _flags), \
++ .src_en = CV1800_CLK_BIT(_src_en_reg, \
++ _src_en_reg_shift), \
++ .output_en = CV1800_CLK_BIT(_output_en_reg, \
++ _output_en_shift), \
++ .div_en = CV1800_CLK_BIT(_div_en_reg, \
++ _div_en_reg_shift), \
++ .div_up = CV1800_CLK_BIT(_div_up_reg, \
++ _div_up_reg_shift), \
++ .m = CV1800_CLK_REG(_m_reg, _m_shift, \
++ _m_width, 0, _m_flag), \
++ .n = CV1800_CLK_REG(_n_reg, _n_shift, \
++ _n_width, 0, _n_flag), \
++ .target_rate = _target_rate, \
++ }
++
++extern const struct clk_ops cv1800_clk_gate_ops;
++extern const struct clk_ops cv1800_clk_div_ops;
++extern const struct clk_ops cv1800_clk_bypass_div_ops;
++extern const struct clk_ops cv1800_clk_mux_ops;
++extern const struct clk_ops cv1800_clk_bypass_mux_ops;
++extern const struct clk_ops cv1800_clk_mmux_ops;
++extern const struct clk_ops cv1800_clk_audio_ops;
++
++#endif // _CLK_SOPHGO_CV1800_IP_H_
+diff --git a/drivers/clk/sophgo/clk-cv18xx-pll.c b/drivers/clk/sophgo/clk-cv18xx-pll.c
+new file mode 100644
+index 000000000000..c546dad1791c
+--- /dev/null
++++ b/drivers/clk/sophgo/clk-cv18xx-pll.c
+@@ -0,0 +1,420 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/io.h>
++#include <linux/limits.h>
++#include <linux/spinlock.h>
++
++#include "clk-cv18xx-pll.h"
++
++static inline struct cv1800_clk_pll *hw_to_cv1800_clk_pll(struct clk_hw *hw)
++{
++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw);
++
++ return container_of(common, struct cv1800_clk_pll, common);
++}
++
++static unsigned long ipll_calc_rate(unsigned long parent_rate,
++ unsigned long pre_div_sel,
++ unsigned long div_sel,
++ unsigned long post_div_sel)
++{
++ uint64_t rate = parent_rate;
++
++ rate *= div_sel;
++ do_div(rate, pre_div_sel * post_div_sel);
++
++ return rate;
++}
++
++static unsigned long ipll_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++ u32 value;
++
++ value = readl(pll->common.base + pll->pll_reg);
++
++ return ipll_calc_rate(parent_rate,
++ PLL_GET_PRE_DIV_SEL(value),
++ PLL_GET_DIV_SEL(value),
++ PLL_GET_POST_DIV_SEL(value));
++}
++
++static int ipll_find_rate(const struct cv1800_clk_pll_limit *limit,
++ unsigned long prate, unsigned long *rate,
++ u32 *value)
++{
++ unsigned long best_rate = 0;
++ unsigned long trate = *rate;
++ unsigned long pre_div_sel = 0, div_sel = 0, post_div_sel = 0;
++ unsigned long pre, div, post;
++ u32 detected = *value;
++ unsigned long tmp;
++
++ for_each_pll_limit_range(pre, &limit->pre_div) {
++ for_each_pll_limit_range(div, &limit->div) {
++ for_each_pll_limit_range(post, &limit->post_div) {
++ tmp = ipll_calc_rate(prate, pre, div, post);
++
++ if (tmp > trate)
++ continue;
++
++ if ((trate - tmp) < (trate - best_rate)) {
++ best_rate = tmp;
++ pre_div_sel = pre;
++ div_sel = div;
++ post_div_sel = post;
++ }
++ }
++ }
++ }
++
++ if (best_rate) {
++ detected = PLL_SET_PRE_DIV_SEL(detected, pre_div_sel);
++ detected = PLL_SET_POST_DIV_SEL(detected, post_div_sel);
++ detected = PLL_SET_DIV_SEL(detected, div_sel);
++ *value = detected;
++ *rate = best_rate;
++ return 0;
++ }
++
++ return -EINVAL;
++}
++
++static int ipll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
++{
++ u32 val;
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++
++ return ipll_find_rate(pll->pll_limit, req->best_parent_rate,
++ &req->rate, &val);
++}
++
++static void pll_get_mode_ctrl(unsigned long div_sel,
++ bool (*mode_ctrl_check)(unsigned long,
++ unsigned long,
++ unsigned long),
++ const struct cv1800_clk_pll_limit *limit,
++ u32 *value)
++{
++ unsigned long ictrl = 0, mode = 0;
++ u32 detected = *value;
++
++ for_each_pll_limit_range(mode, &limit->mode) {
++ for_each_pll_limit_range(ictrl, &limit->ictrl) {
++ if (mode_ctrl_check(div_sel, ictrl, mode)) {
++ detected = PLL_SET_SEL_MODE(detected, mode);
++ detected = PLL_SET_ICTRL(detected, ictrl);
++ *value = detected;
++ return;
++ }
++ }
++ }
++}
++
++static bool ipll_check_mode_ctrl_restrict(unsigned long div_sel,
++ unsigned long ictrl,
++ unsigned long mode)
++{
++ unsigned long left_rest = 20 * div_sel;
++ unsigned long right_rest = 35 * div_sel;
++ unsigned long test = 184 * (1 + mode) * (1 + ictrl) / 2;
++
++ return test > left_rest && test <= right_rest;
++}
++
++static int ipll_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ u32 regval, detected = 0;
++ unsigned long flags;
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++
++ ipll_find_rate(pll->pll_limit, parent_rate, &rate, &detected);
++ pll_get_mode_ctrl(PLL_GET_DIV_SEL(detected),
++ ipll_check_mode_ctrl_restrict,
++ pll->pll_limit, &detected);
++
++ spin_lock_irqsave(pll->common.lock, flags);
++
++ regval = readl(pll->common.base + pll->pll_reg);
++ regval = PLL_COPY_REG(regval, detected);
++
++ writel(regval, pll->common.base + pll->pll_reg);
++
++ spin_unlock_irqrestore(pll->common.lock, flags);
++
++ cv1800_clk_wait_for_lock(&pll->common, pll->pll_status.reg,
++ BIT(pll->pll_status.shift));
++
++ return 0;
++}
++
++static int pll_enable(struct clk_hw *hw)
++{
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++
++ return cv1800_clk_clearbit(&pll->common, &pll->pll_pwd);
++}
++
++static void pll_disable(struct clk_hw *hw)
++{
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++
++ cv1800_clk_setbit(&pll->common, &pll->pll_pwd);
++}
++
++static int pll_is_enable(struct clk_hw *hw)
++{
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++
++ return cv1800_clk_checkbit(&pll->common, &pll->pll_pwd) == 0;
++}
++
++const struct clk_ops cv1800_clk_ipll_ops = {
++ .disable = pll_disable,
++ .enable = pll_enable,
++ .is_enabled = pll_is_enable,
++
++ .recalc_rate = ipll_recalc_rate,
++ .determine_rate = ipll_determine_rate,
++ .set_rate = ipll_set_rate,
++};
++
++#define PLL_SYN_FACTOR_DOT_POS 26
++#define PLL_SYN_FACTOR_MINIMUM ((4 << PLL_SYN_FACTOR_DOT_POS) + 1)
++
++static bool fpll_is_factional_mode(struct cv1800_clk_pll *pll)
++{
++ return cv1800_clk_checkbit(&pll->common, &pll->pll_syn->en);
++}
++
++static unsigned long fpll_calc_rate(unsigned long parent_rate,
++ unsigned long pre_div_sel,
++ unsigned long div_sel,
++ unsigned long post_div_sel,
++ unsigned long ssc_syn_set,
++ bool is_full_parent)
++{
++ u64 dividend = parent_rate * div_sel;
++ u64 factor = ssc_syn_set * pre_div_sel * post_div_sel;
++ unsigned long rate;
++
++ dividend <<= PLL_SYN_FACTOR_DOT_POS - 1;
++ rate = dividend / factor;
++ dividend %= factor;
++
++ if (is_full_parent) {
++ dividend <<= 1;
++ rate <<= 1;
++ }
++
++ rate += DIV64_U64_ROUND_CLOSEST(dividend, factor);
++
++ return rate;
++}
++
++static unsigned long fpll_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++ u32 value;
++ bool clk_full;
++ u32 syn_set;
++
++ if (!fpll_is_factional_mode(pll))
++ return ipll_recalc_rate(hw, parent_rate);
++
++ syn_set = readl(pll->common.base + pll->pll_syn->set);
++
++ if (syn_set == 0)
++ return 0;
++
++ clk_full = cv1800_clk_checkbit(&pll->common,
++ &pll->pll_syn->clk_half);
++
++ value = readl(pll->common.base + pll->pll_reg);
++
++ return fpll_calc_rate(parent_rate,
++ PLL_GET_PRE_DIV_SEL(value),
++ PLL_GET_DIV_SEL(value),
++ PLL_GET_POST_DIV_SEL(value),
++ syn_set, clk_full);
++}
++
++static unsigned long fpll_find_synthesizer(unsigned long parent,
++ unsigned long rate,
++ unsigned long pre_div,
++ unsigned long div,
++ unsigned long post_div,
++ bool is_full_parent,
++ u32 *ssc_syn_set)
++{
++ u32 test_max = U32_MAX, test_min = PLL_SYN_FACTOR_MINIMUM;
++ unsigned long trate;
++
++ while (test_min < test_max) {
++ u32 tssc = (test_max + test_min) / 2;
++
++ trate = fpll_calc_rate(parent, pre_div, div, post_div,
++ tssc, is_full_parent);
++
++ if (trate == rate) {
++ test_min = tssc;
++ break;
++ }
++
++ if (trate > rate)
++ test_min = tssc + 1;
++ else
++ test_max = tssc - 1;
++ }
++
++ if (trate != 0)
++ *ssc_syn_set = test_min;
++
++ return trate;
++}
++
++static int fpll_find_rate(struct cv1800_clk_pll *pll,
++ const struct cv1800_clk_pll_limit *limit,
++ unsigned long prate,
++ unsigned long *rate,
++ u32 *value, u32 *ssc_syn_set)
++{
++ unsigned long best_rate = 0;
++ unsigned long pre_div_sel = 0, div_sel = 0, post_div_sel = 0;
++ unsigned long pre, div, post;
++ unsigned long trate = *rate;
++ u32 detected = *value;
++ unsigned long tmp;
++ bool clk_full = cv1800_clk_checkbit(&pll->common,
++ &pll->pll_syn->clk_half);
++
++ for_each_pll_limit_range(pre, &limit->pre_div) {
++ for_each_pll_limit_range(post, &limit->post_div) {
++ for_each_pll_limit_range(div, &limit->div) {
++ tmp = fpll_find_synthesizer(prate, trate,
++ pre, div, post,
++ clk_full,
++ ssc_syn_set);
++
++ if ((trate - tmp) < (trate - best_rate)) {
++ best_rate = tmp;
++ pre_div_sel = pre;
++ div_sel = div;
++ post_div_sel = post;
++ }
++ }
++ }
++ }
++
++ if (best_rate) {
++ detected = PLL_SET_PRE_DIV_SEL(detected, pre_div_sel);
++ detected = PLL_SET_POST_DIV_SEL(detected, post_div_sel);
++ detected = PLL_SET_DIV_SEL(detected, div_sel);
++ *value = detected;
++ *rate = best_rate;
++ return 0;
++ }
++
++ return -EINVAL;
++}
++
++static int fpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
++{
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++ u32 val, ssc_syn_set;
++
++ if (!fpll_is_factional_mode(pll))
++ return ipll_determine_rate(hw, req);
++
++ fpll_find_rate(pll, &pll->pll_limit[2], req->best_parent_rate,
++ &req->rate, &val, &ssc_syn_set);
++
++ return 0;
++}
++
++static bool fpll_check_mode_ctrl_restrict(unsigned long div_sel,
++ unsigned long ictrl,
++ unsigned long mode)
++{
++ unsigned long left_rest = 10 * div_sel;
++ unsigned long right_rest = 24 * div_sel;
++ unsigned long test = 184 * (1 + mode) * (1 + ictrl) / 2;
++
++ return test > left_rest && test <= right_rest;
++}
++
++static int fpll_set_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long parent_rate)
++{
++ u32 regval;
++ u32 detected = 0, detected_ssc = 0;
++ unsigned long flags;
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++
++ if (!fpll_is_factional_mode(pll))
++ return ipll_set_rate(hw, rate, parent_rate);
++
++ fpll_find_rate(pll, &pll->pll_limit[2], parent_rate,
++ &rate, &detected, &detected_ssc);
++ pll_get_mode_ctrl(PLL_GET_DIV_SEL(detected),
++ fpll_check_mode_ctrl_restrict,
++ pll->pll_limit, &detected);
++
++ spin_lock_irqsave(pll->common.lock, flags);
++
++ writel(detected_ssc, pll->common.base + pll->pll_syn->set);
++
++ regval = readl(pll->common.base + pll->pll_reg);
++ regval = PLL_COPY_REG(regval, detected);
++
++ writel(regval, pll->common.base + pll->pll_reg);
++
++ spin_unlock_irqrestore(pll->common.lock, flags);
++
++ cv1800_clk_wait_for_lock(&pll->common, pll->pll_status.reg,
++ BIT(pll->pll_status.shift));
++
++ return 0;
++}
++
++static u8 fpll_get_parent(struct clk_hw *hw)
++{
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++
++ if (fpll_is_factional_mode(pll))
++ return 1;
++
++ return 0;
++}
++
++static int fpll_set_parent(struct clk_hw *hw, u8 index)
++{
++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
++
++ if (index)
++ cv1800_clk_setbit(&pll->common, &pll->pll_syn->en);
++ else
++ cv1800_clk_clearbit(&pll->common, &pll->pll_syn->en);
++
++ return 0;
++}
++
++const struct clk_ops cv1800_clk_fpll_ops = {
++ .disable = pll_disable,
++ .enable = pll_enable,
++ .is_enabled = pll_is_enable,
++
++ .recalc_rate = fpll_recalc_rate,
++ .determine_rate = fpll_determine_rate,
++ .set_rate = fpll_set_rate,
++
++ .set_parent = fpll_set_parent,
++ .get_parent = fpll_get_parent,
++};
+diff --git a/drivers/clk/sophgo/clk-cv18xx-pll.h b/drivers/clk/sophgo/clk-cv18xx-pll.h
+new file mode 100644
+index 000000000000..7a33f3da2d64
+--- /dev/null
++++ b/drivers/clk/sophgo/clk-cv18xx-pll.h
+@@ -0,0 +1,118 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
++ */
++
++#ifndef _CLK_SOPHGO_CV1800_PLL_H_
++#define _CLK_SOPHGO_CV1800_PLL_H_
++
++#include "clk-cv18xx-common.h"
++
++struct cv1800_clk_pll_limit {
++ struct {
++ u8 min;
++ u8 max;
++ } pre_div, div, post_div, ictrl, mode;
++};
++
++#define _CV1800_PLL_LIMIT(_min, _max) \
++ { \
++ .min = _min, \
++ .max = _max, \
++ } \
++
++#define for_each_pll_limit_range(_var, _restrict) \
++ for (_var = (_restrict)->min; _var <= (_restrict)->max; _var++)
++
++struct cv1800_clk_pll_synthesizer {
++ struct cv1800_clk_regbit en;
++ struct cv1800_clk_regbit clk_half;
++ u32 ctrl;
++ u32 set;
++};
++
++#define _PLL_PRE_DIV_SEL_FIELD GENMASK(6, 0)
++#define _PLL_POST_DIV_SEL_FIELD GENMASK(14, 8)
++#define _PLL_SEL_MODE_FIELD GENMASK(16, 15)
++#define _PLL_DIV_SEL_FIELD GENMASK(23, 17)
++#define _PLL_ICTRL_FIELD GENMASK(26, 24)
++
++#define _PLL_ALL_FIELD_MASK \
++ (_PLL_PRE_DIV_SEL_FIELD | \
++ _PLL_POST_DIV_SEL_FIELD | \
++ _PLL_SEL_MODE_FIELD | \
++ _PLL_DIV_SEL_FIELD | \
++ _PLL_ICTRL_FIELD)
++
++#define PLL_COPY_REG(_dest, _src) \
++ (((_dest) & (~_PLL_ALL_FIELD_MASK)) | ((_src) & _PLL_ALL_FIELD_MASK))
++
++#define PLL_GET_PRE_DIV_SEL(_reg) \
++ FIELD_GET(_PLL_PRE_DIV_SEL_FIELD, (_reg))
++#define PLL_GET_POST_DIV_SEL(_reg) \
++ FIELD_GET(_PLL_POST_DIV_SEL_FIELD, (_reg))
++#define PLL_GET_SEL_MODE(_reg) \
++ FIELD_GET(_PLL_SEL_MODE_FIELD, (_reg))
++#define PLL_GET_DIV_SEL(_reg) \
++ FIELD_GET(_PLL_DIV_SEL_FIELD, (_reg))
++#define PLL_GET_ICTRL(_reg) \
++ FIELD_GET(_PLL_ICTRL_FIELD, (_reg))
++
++#define PLL_SET_PRE_DIV_SEL(_reg, _val) \
++ _CV1800_SET_FIELD((_reg), (_val), _PLL_PRE_DIV_SEL_FIELD)
++#define PLL_SET_POST_DIV_SEL(_reg, _val) \
++ _CV1800_SET_FIELD((_reg), (_val), _PLL_POST_DIV_SEL_FIELD)
++#define PLL_SET_SEL_MODE(_reg, _val) \
++ _CV1800_SET_FIELD((_reg), (_val), _PLL_SEL_MODE_FIELD)
++#define PLL_SET_DIV_SEL(_reg, _val) \
++ _CV1800_SET_FIELD((_reg), (_val), _PLL_DIV_SEL_FIELD)
++#define PLL_SET_ICTRL(_reg, _val) \
++ _CV1800_SET_FIELD((_reg), (_val), _PLL_ICTRL_FIELD)
++
++struct cv1800_clk_pll {
++ struct cv1800_clk_common common;
++ u32 pll_reg;
++ struct cv1800_clk_regbit pll_pwd;
++ struct cv1800_clk_regbit pll_status;
++ const struct cv1800_clk_pll_limit *pll_limit;
++ struct cv1800_clk_pll_synthesizer *pll_syn;
++};
++
++#define CV1800_INTEGRAL_PLL(_name, _parent, _pll_reg, \
++ _pll_pwd_reg, _pll_pwd_shift, \
++ _pll_status_reg, _pll_status_shift, \
++ _pll_limit, _flags) \
++ struct cv1800_clk_pll _name = { \
++ .common = CV1800_CLK_COMMON(#_name, _parent, \
++ &cv1800_clk_ipll_ops,\
++ _flags), \
++ .pll_reg = _pll_reg, \
++ .pll_pwd = CV1800_CLK_BIT(_pll_pwd_reg, \
++ _pll_pwd_shift), \
++ .pll_status = CV1800_CLK_BIT(_pll_status_reg, \
++ _pll_status_shift), \
++ .pll_limit = _pll_limit, \
++ .pll_syn = NULL, \
++ }
++
++#define CV1800_FACTIONAL_PLL(_name, _parent, _pll_reg, \
++ _pll_pwd_reg, _pll_pwd_shift, \
++ _pll_status_reg, _pll_status_shift, \
++ _pll_limit, _pll_syn, _flags) \
++ struct cv1800_clk_pll _name = { \
++ .common = CV1800_CLK_COMMON(#_name, _parent, \
++ &cv1800_clk_fpll_ops,\
++ _flags), \
++ .pll_reg = _pll_reg, \
++ .pll_pwd = CV1800_CLK_BIT(_pll_pwd_reg, \
++ _pll_pwd_shift), \
++ .pll_status = CV1800_CLK_BIT(_pll_status_reg, \
++ _pll_status_shift), \
++ .pll_limit = _pll_limit, \
++ .pll_syn = _pll_syn, \
++ }
++
++extern const struct clk_ops cv1800_clk_ipll_ops;
++extern const struct clk_ops cv1800_clk_fpll_ops;
++
++#endif // _CLK_SOPHGO_CV1800_PLL_H_
+--
+2.20.1
+