2024-01-16 07:20:58

by Chen Wang

[permalink] [raw]
Subject: [PATCH v8 0/5] riscv: sophgo: add clock support for sg2042

From: Chen Wang <[email protected]>

This series adds clock controller support for sophgo sg2042.

Thanks,
Chen

---

Changes in v8:
The patch series is based on v6.7. You can simply review or test the
patches at the link [9].

In this version, the main change is to split one clock provider into two.
Strictly follow the hardware instructions, in the memoymap, the control
registers of some clocks are defined in the SYS_CTRL segment, and the
control registers of other clocks are defined in the CLOCK segment.
Therefore, the new design defines two clock controllers, one as a child
node of the system control and the other as an independent clock controller
node.

This modification involves a major modification to the binding files, so
the reviewed-by tags has been deleted.

Changes in v7:
The patch series is based on v6.7. You can simply review or test the
patches at the link [8].
- fixed initval issue.
- fixed pll clk crash issue.
- fixed warning reported by <[email protected]>
- code optimization as per review comments.
- code cleanup and style improvements as per review comments and checkpatch
with "--strict"

Changes in v6:
The patch series is based on v6.7-rc1. You can simply review or test the
patches at the link [7].
- fixed some warnings/errors reported by kernel test robot <[email protected]>.

Changes in v5:
The patch series is based on v6.7-rc1. You can simply review or test the
patches at the link [6].
- dt-bindings: improved yaml, such as:
- add vendor prefix for system-ctrl property for clock generator.
- Add explanation for system-ctrl property.
- move sophgo,sg2042-clkgen.yaml to directly under clock folder.
- fixed bugs for driver Makefile/Kconfig
- continue cleaning-up debug print for driver code.

Changes in v4:
The patch series is based on v6.7-rc1. You can simply review or test the
patches at the link [5].
- dt-bindings: fixed a dt_binding_check error.

Changes in v3:
The patch series is based on v6.7-rc1. You can simply review or test the
patches at the link [3].
- DTS: don't use syscon but define sg2042 specific system control node. More
background info can read [4].
- Updating minor issues in dt-bindings as per input from reviews.

Changes in v2:
The patch series is based on v6.7-rc1. You can simply review or test the
patches at the link [2].
- Squashed the patch adding clock definitions with the patch adding the
binding for the clock controller.
- Updating dt-binding for syscon, remove oneOf for property compatible;
define clock controller as child of syscon.
- DTS changes: merge sg2042-clock.dtsi into sg2042.dtsi; move clock-frequency
property of osc to board devicethree due to the oscillator is outside the
SoC.
- Fixed some bugs in driver code during testing, including removing warnings
for rv32_defconfig.
- Updated MAINTAINERS info.

Changes in v1:
The patch series is based on v6.7-rc1. You can simply review or test the
patches at the link [1].

Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v1 [1]
Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v2 [2]
Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v3 [3]
Link: https://lore.kernel.org/linux-riscv/MA0P287MB03329AE180378E1A2E034374FE82A@MA0P287MB0332.INDP287.PROD.OUTLOOK.COM/ [4]
Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v4 [5]
Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v5 [6]
Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v6 [7]
Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v7 [8]
Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v8 [9]

---

Chen Wang (5):
dt-bindings: clock: sophgo: add sysclk for SG2042
dt-bindings: soc: sophgo: Add Sophgo system control module
dt-bindings: clock: sophgo: add clkgen for SG2042
clk: sophgo: Add SG2042 clock generator driver
riscv: dts: add clock generator for Sophgo SG2042 SoC

.../bindings/clock/sophgo,sg2042-clkgen.yaml | 40 +
.../bindings/clock/sophgo,sg2042-sysclk.yaml | 44 +
.../soc/sophgo/sophgo,sg2042-sysctrl.yaml | 46 +
MAINTAINERS | 7 +
.../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 12 +
arch/riscv/boot/dts/sophgo/sg2042.dtsi | 39 +
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/sophgo/Kconfig | 8 +
drivers/clk/sophgo/Makefile | 2 +
drivers/clk/sophgo/clk-sophgo-sg2042.c | 1387 +++++++++++++++++
drivers/clk/sophgo/clk-sophgo-sg2042.h | 233 +++
.../dt-bindings/clock/sophgo,sg2042-clkgen.h | 111 ++
.../dt-bindings/clock/sophgo,sg2042-sysclk.h | 63 +
14 files changed, 1994 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/sophgo,sg2042-clkgen.yaml
create mode 100644 Documentation/devicetree/bindings/clock/sophgo,sg2042-sysclk.yaml
create mode 100644 Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
create mode 100644 drivers/clk/sophgo/Kconfig
create mode 100644 drivers/clk/sophgo/Makefile
create mode 100644 drivers/clk/sophgo/clk-sophgo-sg2042.c
create mode 100644 drivers/clk/sophgo/clk-sophgo-sg2042.h
create mode 100644 include/dt-bindings/clock/sophgo,sg2042-clkgen.h
create mode 100644 include/dt-bindings/clock/sophgo,sg2042-sysclk.h


base-commit: 0dd3ee31125508cd67f7e7172247f05b7fd1753a
--
2.25.1



2024-01-16 07:21:17

by Chen Wang

[permalink] [raw]
Subject: [PATCH v8 1/5] dt-bindings: clock: sophgo: add sysclk for SG2042

From: Chen Wang <[email protected]>

Add bindings for the clocks of which configuration registers are in the
range of SYS_CTRL in the memory-map.

Signed-off-by: Chen Wang <[email protected]>

.
---
.../bindings/clock/sophgo,sg2042-sysclk.yaml | 44 +++++++++++++
.../dt-bindings/clock/sophgo,sg2042-sysclk.h | 63 +++++++++++++++++++
2 files changed, 107 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/sophgo,sg2042-sysclk.yaml
create mode 100644 include/dt-bindings/clock/sophgo,sg2042-sysclk.h

diff --git a/Documentation/devicetree/bindings/clock/sophgo,sg2042-sysclk.yaml b/Documentation/devicetree/bindings/clock/sophgo,sg2042-sysclk.yaml
new file mode 100644
index 000000000000..93b0631dcd0d
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sophgo,sg2042-sysclk.yaml
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/sophgo,sg2042-sysclk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sophgo SG2042 Clock Generator in System-Control
+
+description:
+ These clocks have configuration registers in the SYS_CTRL range of memory-map.
+ So the node should be a child of system-control node.
+
+maintainers:
+ - Chen Wang <[email protected]>
+
+properties:
+ compatible:
+ const: sophgo,sg2042-sysclk
+
+ clocks:
+ items:
+ - description: Oscillator(Clock Generation IC) for Main/Fixed PLL (25 MHz)
+ - description: Oscillator(Clock Generation IC) for DDR PLL 0 (25 MHz)
+ - description: Oscillator(Clock Generation IC) for DDR PLL 1 (25 MHz)
+
+ '#clock-cells':
+ const: 1
+ description:
+ See <dt-bindings/clock/sophgo,sg2042-sysclk.h> for valid indices.
+
+required:
+ - compatible
+ - clocks
+ - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ clock-controller {
+ compatible = "sophgo,sg2042-sysclk";
+ clocks = <&cgi_main>, <&cgi_dpll0>, <&cgi_dpll1>;
+ #clock-cells = <1>;
+ };
diff --git a/include/dt-bindings/clock/sophgo,sg2042-sysclk.h b/include/dt-bindings/clock/sophgo,sg2042-sysclk.h
new file mode 100644
index 000000000000..f7a9fbce16f8
--- /dev/null
+++ b/include/dt-bindings/clock/sophgo,sg2042-sysclk.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * Copyright (C) 2023 Sophgo Technology Inc. All rights reserved.
+ */
+
+#ifndef __DT_BINDINGS_SOPHGO_SG2042_SYSCLK_H__
+#define __DT_BINDINGS_SOPHGO_SG2042_SYSCLK_H__
+
+#define MPLL_CLK 0
+#define FPLL_CLK 1
+#define DPLL0_CLK 2
+#define DPLL1_CLK 3
+
+#define GATE_CLK_RXU0 4
+#define GATE_CLK_RXU1 5
+#define GATE_CLK_RXU2 6
+#define GATE_CLK_RXU3 7
+#define GATE_CLK_RXU4 8
+#define GATE_CLK_RXU5 9
+#define GATE_CLK_RXU6 10
+#define GATE_CLK_RXU7 11
+#define GATE_CLK_RXU8 12
+#define GATE_CLK_RXU9 13
+#define GATE_CLK_RXU10 14
+#define GATE_CLK_RXU11 15
+#define GATE_CLK_RXU12 16
+#define GATE_CLK_RXU13 17
+#define GATE_CLK_RXU14 18
+#define GATE_CLK_RXU15 19
+#define GATE_CLK_RXU16 20
+#define GATE_CLK_RXU17 21
+#define GATE_CLK_RXU18 22
+#define GATE_CLK_RXU19 23
+#define GATE_CLK_RXU20 24
+#define GATE_CLK_RXU21 25
+#define GATE_CLK_RXU22 26
+#define GATE_CLK_RXU23 27
+#define GATE_CLK_RXU24 28
+#define GATE_CLK_RXU25 29
+#define GATE_CLK_RXU26 30
+#define GATE_CLK_RXU27 31
+#define GATE_CLK_RXU28 32
+#define GATE_CLK_RXU29 33
+#define GATE_CLK_RXU30 34
+#define GATE_CLK_RXU31 35
+#define GATE_CLK_MP0 36
+#define GATE_CLK_MP1 37
+#define GATE_CLK_MP2 38
+#define GATE_CLK_MP3 39
+#define GATE_CLK_MP4 40
+#define GATE_CLK_MP5 41
+#define GATE_CLK_MP6 42
+#define GATE_CLK_MP7 43
+#define GATE_CLK_MP8 44
+#define GATE_CLK_MP9 45
+#define GATE_CLK_MP10 46
+#define GATE_CLK_MP11 47
+#define GATE_CLK_MP12 48
+#define GATE_CLK_MP13 49
+#define GATE_CLK_MP14 50
+#define GATE_CLK_MP15 51
+
+#endif /* __DT_BINDINGS_SOPHGO_SG2042_SYSCLK_H__ */
--
2.25.1


2024-01-16 07:21:31

by Chen Wang

[permalink] [raw]
Subject: [PATCH v8 2/5] dt-bindings: soc: sophgo: Add Sophgo system control module

From: Chen Wang <[email protected]>

Add documentation to describe Sophgo System Control for SG2042.

Signed-off-by: Chen Wang <[email protected]>
---
.../soc/sophgo/sophgo,sg2042-sysctrl.yaml | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml

diff --git a/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
new file mode 100644
index 000000000000..7b50bb56b4cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/sophgo/sophgo,sg2042-sysctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sophgo SG2042 SoC system control
+
+maintainers:
+ - Chen Wang <[email protected]>
+
+description:
+ The Sophgo system control is a registers block (SYS_CTRL), providing multiple
+ low level platform functions like chip configuration, clock control, etc.
+
+properties:
+ compatible:
+ const: sophgo,sg2042-sysctrl
+
+ reg:
+ maxItems: 1
+
+ clock-controller:
+ # Child node
+ $ref: /schemas/clock/sophgo,sg2042-sysclk.yaml#
+ type: object
+
+required:
+ - compatible
+ - reg
+ - clock-controller
+
+additionalProperties: false
+
+examples:
+ - |
+ system-control@30010000 {
+ compatible = "sophgo,sg2042-sysctrl";
+ reg = <0x30010000 0x1000>;
+
+ clock-controller {
+ compatible = "sophgo,sg2042-sysclk";
+ clocks = <&cgi_main>, <&cgi_dpll0>, <&cgi_dpll1>;
+ #clock-cells = <1>;
+ };
+ };
--
2.25.1


2024-01-16 07:21:58

by Chen Wang

[permalink] [raw]
Subject: [PATCH v8 3/5] dt-bindings: clock: sophgo: add clkgen for SG2042

From: Chen Wang <[email protected]>

Add bindings for the clocks of which configuration registers are in the
range of CLOCK in the memory-map.

Signed-off-by: Chen Wang <[email protected]>
---
.../bindings/clock/sophgo,sg2042-clkgen.yaml | 40 +++++++
.../dt-bindings/clock/sophgo,sg2042-clkgen.h | 111 ++++++++++++++++++
2 files changed, 151 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/sophgo,sg2042-clkgen.yaml
create mode 100644 include/dt-bindings/clock/sophgo,sg2042-clkgen.h

diff --git a/Documentation/devicetree/bindings/clock/sophgo,sg2042-clkgen.yaml b/Documentation/devicetree/bindings/clock/sophgo,sg2042-clkgen.yaml
new file mode 100644
index 000000000000..4291889cd550
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sophgo,sg2042-clkgen.yaml
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/sophgo,sg2042-clkgen.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sophgo SG2042 Clock Generator
+
+description:
+ These clocks have configuration registers in the CLOCK range of memory-map.
+
+maintainers:
+ - Chen Wang <[email protected]>
+
+properties:
+ compatible:
+ const: sophgo,sg2042-clkgen
+
+ reg:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+ description:
+ See <dt-bindings/clock/sophgo,sg2042-clkgen.h> for valid indices.
+
+required:
+ - compatible
+ - reg
+ - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ clock-controller@30012000 {
+ compatible = "sophgo,sg2042-clkgen";
+ reg = <0x30012000 0x1000>;
+ #clock-cells = <1>;
+ };
diff --git a/include/dt-bindings/clock/sophgo,sg2042-clkgen.h b/include/dt-bindings/clock/sophgo,sg2042-clkgen.h
new file mode 100644
index 000000000000..84f7857317a2
--- /dev/null
+++ b/include/dt-bindings/clock/sophgo,sg2042-clkgen.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * Copyright (C) 2023 Sophgo Technology Inc. All rights reserved.
+ */
+
+#ifndef __DT_BINDINGS_SOPHGO_SG2042_CLKGEN_H__
+#define __DT_BINDINGS_SOPHGO_SG2042_CLKGEN_H__
+
+#define DIV_CLK_MPLL_RP_CPU_NORMAL_0 0
+#define DIV_CLK_MPLL_AXI_DDR_0 1
+#define DIV_CLK_FPLL_DDR01_1 2
+#define DIV_CLK_FPLL_DDR23_1 3
+#define DIV_CLK_FPLL_RP_CPU_NORMAL_1 4
+#define DIV_CLK_FPLL_50M_A53 5
+#define DIV_CLK_FPLL_TOP_RP_CMN_DIV2 6
+#define DIV_CLK_FPLL_UART_500M 7
+#define DIV_CLK_FPLL_AHB_LPC 8
+#define DIV_CLK_FPLL_EFUSE 9
+#define DIV_CLK_FPLL_TX_ETH0 10
+#define DIV_CLK_FPLL_PTP_REF_I_ETH0 11
+#define DIV_CLK_FPLL_REF_ETH0 12
+#define DIV_CLK_FPLL_EMMC 13
+#define DIV_CLK_FPLL_SD 14
+#define DIV_CLK_FPLL_TOP_AXI0 15
+#define DIV_CLK_FPLL_TOP_AXI_HSPERI 16
+#define DIV_CLK_FPLL_AXI_DDR_1 17
+#define DIV_CLK_FPLL_DIV_TIMER1 18
+#define DIV_CLK_FPLL_DIV_TIMER2 19
+#define DIV_CLK_FPLL_DIV_TIMER3 20
+#define DIV_CLK_FPLL_DIV_TIMER4 21
+#define DIV_CLK_FPLL_DIV_TIMER5 22
+#define DIV_CLK_FPLL_DIV_TIMER6 23
+#define DIV_CLK_FPLL_DIV_TIMER7 24
+#define DIV_CLK_FPLL_DIV_TIMER8 25
+#define DIV_CLK_FPLL_100K_EMMC 26
+#define DIV_CLK_FPLL_100K_SD 27
+#define DIV_CLK_FPLL_GPIO_DB 28
+#define DIV_CLK_DPLL0_DDR01_0 29
+#define DIV_CLK_DPLL1_DDR23_0 30
+
+#define GATE_CLK_RP_CPU_NORMAL_DIV0 31
+#define GATE_CLK_AXI_DDR_DIV0 32
+
+#define GATE_CLK_RP_CPU_NORMAL_DIV1 33
+#define GATE_CLK_A53_50M 34
+#define GATE_CLK_TOP_RP_CMN_DIV2 35
+#define GATE_CLK_HSDMA 36
+#define GATE_CLK_EMMC_100M 37
+#define GATE_CLK_SD_100M 38
+#define GATE_CLK_TX_ETH0 39
+#define GATE_CLK_PTP_REF_I_ETH0 40
+#define GATE_CLK_REF_ETH0 41
+#define GATE_CLK_UART_500M 42
+#define GATE_CLK_EFUSE 43
+
+#define GATE_CLK_AHB_LPC 44
+#define GATE_CLK_AHB_ROM 45
+#define GATE_CLK_AHB_SF 46
+
+#define GATE_CLK_APB_UART 47
+#define GATE_CLK_APB_TIMER 48
+#define GATE_CLK_APB_EFUSE 49
+#define GATE_CLK_APB_GPIO 50
+#define GATE_CLK_APB_GPIO_INTR 51
+#define GATE_CLK_APB_SPI 52
+#define GATE_CLK_APB_I2C 53
+#define GATE_CLK_APB_WDT 54
+#define GATE_CLK_APB_PWM 55
+#define GATE_CLK_APB_RTC 56
+
+#define GATE_CLK_AXI_PCIE0 57
+#define GATE_CLK_AXI_PCIE1 58
+#define GATE_CLK_SYSDMA_AXI 59
+#define GATE_CLK_AXI_DBG_I2C 60
+#define GATE_CLK_AXI_SRAM 61
+#define GATE_CLK_AXI_ETH0 62
+#define GATE_CLK_AXI_EMMC 63
+#define GATE_CLK_AXI_SD 64
+#define GATE_CLK_TOP_AXI0 65
+#define GATE_CLK_TOP_AXI_HSPERI 66
+
+#define GATE_CLK_TIMER1 67
+#define GATE_CLK_TIMER2 68
+#define GATE_CLK_TIMER3 69
+#define GATE_CLK_TIMER4 70
+#define GATE_CLK_TIMER5 71
+#define GATE_CLK_TIMER6 72
+#define GATE_CLK_TIMER7 73
+#define GATE_CLK_TIMER8 74
+#define GATE_CLK_100K_EMMC 75
+#define GATE_CLK_100K_SD 76
+#define GATE_CLK_GPIO_DB 77
+
+#define GATE_CLK_AXI_DDR_DIV1 78
+#define GATE_CLK_DDR01_DIV1 79
+#define GATE_CLK_DDR23_DIV1 80
+
+#define GATE_CLK_DDR01_DIV0 81
+#define GATE_CLK_DDR23_DIV0 82
+
+#define GATE_CLK_DDR01 83
+#define GATE_CLK_DDR23 84
+#define GATE_CLK_RP_CPU_NORMAL 85
+#define GATE_CLK_AXI_DDR 86
+
+#define MUX_CLK_DDR01 87
+#define MUX_CLK_DDR23 88
+#define MUX_CLK_RP_CPU_NORMAL 89
+#define MUX_CLK_AXI_DDR 90
+
+#endif /* __DT_BINDINGS_SOPHGO_SG2042_CLKGEN_H__ */
--
2.25.1


2024-01-16 07:22:25

by Chen Wang

[permalink] [raw]
Subject: [PATCH v8 4/5] clk: sophgo: Add SG2042 clock generator driver

From: Chen Wang <[email protected]>

Add a driver for the SOPHGO SG2042 clock generator.

Signed-off-by: Chen Wang <[email protected]>
---
MAINTAINERS | 7 +
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/sophgo/Kconfig | 8 +
drivers/clk/sophgo/Makefile | 2 +
drivers/clk/sophgo/clk-sophgo-sg2042.c | 1387 ++++++++++++++++++++++++
drivers/clk/sophgo/clk-sophgo-sg2042.h | 233 ++++
7 files changed, 1639 insertions(+)
create mode 100644 drivers/clk/sophgo/Kconfig
create mode 100644 drivers/clk/sophgo/Makefile
create mode 100644 drivers/clk/sophgo/clk-sophgo-sg2042.c
create mode 100644 drivers/clk/sophgo/clk-sophgo-sg2042.h

diff --git a/MAINTAINERS b/MAINTAINERS
index a7c4cf8201e0..6b5019ba0794 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20197,6 +20197,13 @@ S: Maintained
F: arch/riscv/boot/dts/sophgo/
F: Documentation/devicetree/bindings/riscv/sophgo.yaml

+SOPHGO CLOCK DRIVER
+M: Chen Wang <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/clock/sophgo/
+F: drivers/clk/sophgo/
+F: include/dt-bindings/clock/sophgo,sg2042-clkgen.h
+
SOUND
M: Jaroslav Kysela <[email protected]>
M: Takashi Iwai <[email protected]>
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c30d0d396f7a..514343934fda 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -499,6 +499,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 ed71f2e0ee36..eeae7ae93f89 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -119,6 +119,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..feab0b805a29
--- /dev/null
+++ b/drivers/clk/sophgo/Kconfig
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config CLK_SOPHGO_SG2042
+ bool "Sophgo SG2042 clock support"
+ depends on ARCH_SOPHGO || COMPILE_TEST
+ default y
+ help
+ Say yes here to support the clock controller on the Sophgo SG2042 SoC.
diff --git a/drivers/clk/sophgo/Makefile b/drivers/clk/sophgo/Makefile
new file mode 100644
index 000000000000..13834cce260c
--- /dev/null
+++ b/drivers/clk/sophgo/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_CLK_SOPHGO_SG2042) += clk-sophgo-sg2042.o
diff --git a/drivers/clk/sophgo/clk-sophgo-sg2042.c b/drivers/clk/sophgo/clk-sophgo-sg2042.c
new file mode 100644
index 000000000000..22de9848eb15
--- /dev/null
+++ b/drivers/clk/sophgo/clk-sophgo-sg2042.c
@@ -0,0 +1,1387 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sophgo SG2042 Clock Generator Driver
+ *
+ * Copyright (C) 2023 Sophgo Technology Inc. All rights reserved.
+ */
+
+#include <linux/bits.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/sophgo,sg2042-sysclk.h>
+#include <dt-bindings/clock/sophgo,sg2042-clkgen.h>
+
+#include "clk-sophgo-sg2042.h"
+
+#define KHZ 1000UL
+#define MHZ (KHZ * KHZ)
+
+#define REFDIV_MIN 1
+#define REFDIV_MAX 63
+#define FBDIV_MIN 16
+#define FBDIV_MAX 320
+
+#define PLL_FREF_SG2042 (25 * MHZ)
+
+#define PLL_FOUTPOSTDIV_MIN (16 * MHZ)
+#define PLL_FOUTPOSTDIV_MAX (3200 * MHZ)
+
+#define PLL_FOUTVCO_MIN (800 * MHZ)
+#define PLL_FOUTVCO_MAX (3200 * MHZ)
+
+struct sg2042_pll_ctrl {
+ unsigned long freq;
+ unsigned int fbdiv;
+ unsigned int postdiv1;
+ unsigned int postdiv2;
+ unsigned int refdiv;
+};
+
+#define PLLCTRL_FBDIV_SHIFT 16
+#define PLLCTRL_FBDIV_MASK (GENMASK(27, 16) >> PLLCTRL_FBDIV_SHIFT)
+#define PLLCTRL_POSTDIV2_SHIFT 12
+#define PLLCTRL_POSTDIV2_MASK (GENMASK(14, 12) >> PLLCTRL_POSTDIV2_SHIFT)
+#define PLLCTRL_POSTDIV1_SHIFT 8
+#define PLLCTRL_POSTDIV1_MASK (GENMASK(10, 8) >> PLLCTRL_POSTDIV1_SHIFT)
+#define PLLCTRL_REFDIV_SHIFT 0
+#define PLLCTRL_REFDIV_MASK (GENMASK(5, 0) >> PLLCTRL_REFDIV_SHIFT)
+
+static inline u32 sg2042_pll_ctrl_encode(struct sg2042_pll_ctrl *ctrl)
+{
+ return (((ctrl->fbdiv & PLLCTRL_FBDIV_MASK) << PLLCTRL_FBDIV_SHIFT) |
+ ((ctrl->postdiv2 & PLLCTRL_POSTDIV2_MASK) << PLLCTRL_POSTDIV2_SHIFT) |
+ ((ctrl->postdiv1 & PLLCTRL_POSTDIV1_MASK) << PLLCTRL_POSTDIV1_SHIFT) |
+ ((ctrl->refdiv & PLLCTRL_REFDIV_MASK) << PLLCTRL_REFDIV_SHIFT));
+}
+
+static inline void sg2042_pll_ctrl_decode(unsigned int reg_value,
+ struct sg2042_pll_ctrl *ctrl)
+{
+ ctrl->fbdiv = (reg_value >> PLLCTRL_FBDIV_SHIFT) & PLLCTRL_FBDIV_MASK;
+ ctrl->refdiv = (reg_value >> PLLCTRL_REFDIV_SHIFT) & PLLCTRL_REFDIV_MASK;
+ ctrl->postdiv1 = (reg_value >> PLLCTRL_POSTDIV1_SHIFT) & PLLCTRL_POSTDIV1_MASK;
+ ctrl->postdiv2 = (reg_value >> PLLCTRL_POSTDIV2_SHIFT) & PLLCTRL_POSTDIV2_MASK;
+}
+
+static inline int sg2042_pll_enable(struct sg2042_pll_clock *pll, bool en)
+{
+ unsigned int value = 0;
+ struct regmap *map = pll->map;
+
+ if (en) {
+ /* wait pll lock */
+ if (regmap_read_poll_timeout_atomic(map,
+ pll->offset_status,
+ value,
+ ((value >> pll->shift_status_lock) & 0x1),
+ 0,
+ 100000))
+ pr_warn("%s not locked\n", pll->name);
+
+ /* wait pll updating */
+ if (regmap_read_poll_timeout_atomic(map,
+ pll->offset_status,
+ value,
+ !((value >> pll->shift_status_updating) & 0x1),
+ 0,
+ 100000))
+ pr_warn("%s still updating\n", pll->name);
+
+ /* enable pll */
+ regmap_read(map, pll->offset_enable, &value);
+ regmap_write(map, pll->offset_enable, value | (1 << pll->shift_enable));
+ } else {
+ /* disable pll */
+ regmap_read(map, pll->offset_enable, &value);
+ regmap_write(map, pll->offset_enable, value & (~(1 << pll->shift_enable)));
+ }
+
+ return 0;
+}
+
+/*
+ * @reg_value: current register value
+ * @parent_rate: parent frequency
+ *
+ * This function is used to calculate below "rate" in equation
+ * rate = (parent_rate/REFDIV) x FBDIV/POSTDIV1/POSTDIV2
+ * = (parent_rate x FBDIV) / (REFDIV x POSTDIV1 x POSTDIV2)
+ */
+static unsigned long sg2042_pll_recalc_rate(unsigned int reg_value,
+ unsigned long parent_rate)
+{
+ struct sg2042_pll_ctrl ctrl_table;
+ u64 rate, numerator, denominator;
+
+ sg2042_pll_ctrl_decode(reg_value, &ctrl_table);
+
+ numerator = parent_rate * ctrl_table.fbdiv;
+ denominator = ctrl_table.refdiv * ctrl_table.postdiv1 * ctrl_table.postdiv2;
+ do_div(numerator, denominator);
+ rate = numerator;
+
+ return rate;
+}
+
+/*
+ * Below array is the total combination lists of POSTDIV1 and POSTDIV2
+ * for example:
+ * postdiv1_2[0] = {2, 4, 8}
+ * ==> div1 = 2, div2 = 4 , div1 * div2 = 8
+ * And POSTDIV_RESULT_INDEX point to 3rd element in the array
+ */
+#define POSTDIV_RESULT_INDEX 2
+static int postdiv1_2[][3] = {
+ {2, 4, 8}, {3, 3, 9}, {2, 5, 10}, {2, 6, 12},
+ {2, 7, 14}, {3, 5, 15}, {4, 4, 16}, {3, 6, 18},
+ {4, 5, 20}, {3, 7, 21}, {4, 6, 24}, {5, 5, 25},
+ {4, 7, 28}, {5, 6, 30}, {5, 7, 35}, {6, 6, 36},
+ {6, 7, 42}, {7, 7, 49}
+};
+
+/*
+ * Based on input rate/prate/fbdiv/refdiv, look up the postdiv1_2 table
+ * to get the closest postdiiv combination.
+ * @rate: FOUTPOSTDIV
+ * @prate: parent rate, i.e. FREF
+ * @fbdiv: FBDIV
+ * @refdiv: REFDIV
+ * @postdiv1: POSTDIV1, output
+ * @postdiv2: POSTDIV2, output
+ * See TRM:
+ * FOUTPOSTDIV = FREF * FBDIV / REFDIV / (POSTDIV1 * POSTDIV2)
+ * So we get following formula to get POSTDIV1 and POSTDIV2:
+ * POSTDIV = (prate/REFDIV) x FBDIV/rate
+ * above POSTDIV = POSTDIV1*POSTDIV2
+ */
+static int sg2042_pll_get_postdiv_1_2(unsigned long rate,
+ unsigned long prate,
+ unsigned int fbdiv,
+ unsigned int refdiv,
+ unsigned int *postdiv1,
+ unsigned int *postdiv2)
+{
+ int index = 0;
+ u64 tmp0;
+
+ /* prate/REFDIV and result save to tmp0 */
+ tmp0 = prate;
+ do_div(tmp0, refdiv);
+
+ /* ((prate/REFDIV) x FBDIV) and result save to tmp0 */
+ tmp0 *= fbdiv;
+
+ /* ((prate/REFDIV) x FBDIV)/rate and result save to tmp0 */
+ do_div(tmp0, rate);
+
+ /* tmp0 is POSTDIV1*POSTDIV2, now we calculate div1 and div2 value */
+ if (tmp0 <= 7) {
+ /* (div1 * div2) <= 7, no need to use array search */
+ *postdiv1 = tmp0;
+ *postdiv2 = 1;
+ return 0;
+ }
+
+ /* (div1 * div2) > 7, use array search */
+ for (index = 0; index < ARRAY_SIZE(postdiv1_2); index++) {
+ if (tmp0 > postdiv1_2[index][POSTDIV_RESULT_INDEX]) {
+ continue;
+ } else {
+ /* found it */
+ *postdiv1 = postdiv1_2[index][1];
+ *postdiv2 = postdiv1_2[index][0];
+ return 0;
+ }
+ }
+ pr_warn("%s can not find in postdiv array!\n", __func__);
+ return -EINVAL;
+}
+
+/*
+ * Based on the given FOUTPISTDIV and the input FREF to calculate
+ * the REFDIV/FBDIV/PSTDIV1/POSTDIV2 combination for pllctrl register.
+ * @req_rate: expected output clock rate, i.e. FOUTPISTDIV
+ * @parent_rate: input parent clock rate, i.e. FREF
+ * @best: output to hold calculated combination of REFDIV/FBDIV/PSTDIV1/POSTDIV2
+ */
+static int sg2042_get_pll_ctl_setting(struct sg2042_pll_ctrl *best,
+ unsigned long req_rate,
+ unsigned long parent_rate)
+{
+ int ret;
+ unsigned int fbdiv, refdiv, postdiv1, postdiv2;
+ unsigned long foutpostdiv;
+ u64 tmp;
+ u64 foutvco;
+
+ if (parent_rate != PLL_FREF_SG2042) {
+ pr_alert("INVALID FREF: %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ if (req_rate < PLL_FOUTPOSTDIV_MIN || req_rate > PLL_FOUTPOSTDIV_MAX) {
+ pr_alert("INVALID FOUTPOSTDIV: %ld\n", req_rate);
+ return -EINVAL;
+ }
+
+ memset(best, 0, sizeof(struct sg2042_pll_ctrl));
+
+ for (refdiv = REFDIV_MIN; refdiv < REFDIV_MAX + 1; refdiv++) {
+ /* required by hardware: FREF/REFDIV must > 10 */
+ tmp = parent_rate;
+ do_div(tmp, refdiv);
+ if (tmp <= 10)
+ continue;
+
+ for (fbdiv = FBDIV_MIN; fbdiv < FBDIV_MAX + 1; fbdiv++) {
+ /*
+ * FOUTVCO = FREF*FBDIV/REFDIV validation
+ * required by hardware, FOUTVCO must [800MHz, 3200MHz]
+ */
+ foutvco = parent_rate * fbdiv;
+ do_div(foutvco, refdiv);
+ if (foutvco < PLL_FOUTVCO_MIN || foutvco > PLL_FOUTVCO_MAX)
+ continue;
+
+ ret = sg2042_pll_get_postdiv_1_2(req_rate, parent_rate,
+ fbdiv, refdiv,
+ &postdiv1, &postdiv2);
+ if (ret)
+ continue;
+
+ /*
+ * FOUTPOSTDIV = FREF*FBDIV/REFDIV/(POSTDIV1*POSTDIV2)
+ * = FOUTVCO/(POSTDIV1*POSTDIV2)
+ */
+ tmp = foutvco;
+ do_div(tmp, (postdiv1 * postdiv2));
+ foutpostdiv = (unsigned long)tmp;
+ /* Iterative to approach the expected value */
+ if (abs_diff(foutpostdiv, req_rate) <
+ abs_diff(best->freq, req_rate)) {
+ best->freq = foutpostdiv;
+ best->refdiv = refdiv;
+ best->fbdiv = fbdiv;
+ best->postdiv1 = postdiv1;
+ best->postdiv2 = postdiv2;
+ if (foutpostdiv == req_rate)
+ return 0;
+ }
+ continue;
+ }
+ }
+
+ if (best->freq == 0)
+ return -EINVAL;
+ else
+ return 0;
+}
+
+/*
+ * @hw: ccf use to hook get sg2042_pll_clock
+ * @parent_rate: parent rate
+ *
+ * The is function will be called through clk_get_rate
+ * and return current rate after decoding reg value
+ */
+static unsigned long sg2042_clk_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned int value;
+ unsigned long rate;
+ struct sg2042_pll_clock *pll = to_sg2042_pll_clk(hw);
+
+ regmap_read(pll->map, pll->offset_ctrl, &value);
+ rate = sg2042_pll_recalc_rate(value, parent_rate);
+
+ pr_debug("--> %s: pll_recalc_rate: val = %ld\n",
+ clk_hw_get_name(hw), rate);
+ return rate;
+}
+
+static long sg2042_clk_pll_round_rate(struct clk_hw *hw,
+ unsigned long req_rate,
+ unsigned long *prate)
+{
+ unsigned int value;
+ struct sg2042_pll_ctrl pctrl_table;
+ long proper_rate;
+ int ret;
+
+ ret = sg2042_get_pll_ctl_setting(&pctrl_table, req_rate, *prate);
+ if (ret) {
+ proper_rate = 0;
+ goto out;
+ }
+
+ value = sg2042_pll_ctrl_encode(&pctrl_table);
+ proper_rate = (long)sg2042_pll_recalc_rate(value, *prate);
+
+out:
+ pr_debug("--> %s: pll_round_rate: val = %ld\n",
+ clk_hw_get_name(hw), proper_rate);
+ return proper_rate;
+}
+
+static int sg2042_clk_pll_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ req->rate = sg2042_clk_pll_round_rate(hw, min(req->rate, req->max_rate),
+ &req->best_parent_rate);
+ pr_debug("--> %s: pll_determine_rate: val = %ld\n",
+ clk_hw_get_name(hw), req->rate);
+ return 0;
+}
+
+static int sg2042_clk_pll_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ unsigned long flags;
+ unsigned int value;
+ int ret = 0;
+ struct sg2042_pll_ctrl pctrl_table;
+ struct sg2042_pll_clock *pll = to_sg2042_pll_clk(hw);
+
+ spin_lock_irqsave(pll->lock, flags);
+ if (sg2042_pll_enable(pll, 0)) {
+ pr_warn("Can't disable pll(%s), status error\n", pll->name);
+ goto out;
+ }
+ ret = sg2042_get_pll_ctl_setting(&pctrl_table, rate, parent_rate);
+ if (ret) {
+ pr_warn("%s: Can't find a proper pll setting\n", pll->name);
+ goto out2;
+ }
+
+ value = sg2042_pll_ctrl_encode(&pctrl_table);
+
+ /* write the value to top register */
+ regmap_write(pll->map, pll->offset_ctrl, value);
+
+out2:
+ sg2042_pll_enable(pll, 1);
+out:
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ pr_debug("--> %s: pll_set_rate: val = 0x%x\n",
+ clk_hw_get_name(hw), value);
+ return ret;
+}
+
+static const struct clk_ops sg2042_clk_pll_ops = {
+ .recalc_rate = sg2042_clk_pll_recalc_rate,
+ .round_rate = sg2042_clk_pll_round_rate,
+ .determine_rate = sg2042_clk_pll_determine_rate,
+ .set_rate = sg2042_clk_pll_set_rate,
+};
+
+static const struct clk_ops sg2042_clk_pll_ro_ops = {
+ .recalc_rate = sg2042_clk_pll_recalc_rate,
+ .round_rate = sg2042_clk_pll_round_rate,
+};
+
+#define DIV_MASK(width) GENMASK(((width) - 1), 0)
+
+static unsigned long sg2042_clk_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
+ unsigned int val;
+ unsigned long ret_rate;
+
+ if (!(readl(divider->reg) & BIT(3))) {
+ val = (int)(divider->initval);
+ } else {
+ val = readl(divider->reg) >> divider->shift;
+ val &= DIV_MASK(divider->width);
+ }
+
+ ret_rate = divider_recalc_rate(hw, parent_rate, val, NULL,
+ divider->div_flags, divider->width);
+
+ pr_debug("--> %s: divider_recalc_rate: ret_rate = %ld\n",
+ clk_hw_get_name(hw), ret_rate);
+ return ret_rate;
+}
+
+static long sg2042_clk_divider_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *prate)
+{
+ int bestdiv;
+ unsigned long ret_rate;
+ struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
+
+ /* if read only, just return current value */
+ if (divider->div_flags & CLK_DIVIDER_READ_ONLY) {
+ if (!(readl(divider->reg) & BIT(3))) {
+ bestdiv = (int)(divider->initval);
+ } else {
+ bestdiv = readl(divider->reg) >> divider->shift;
+ bestdiv &= DIV_MASK(divider->width);
+ }
+ ret_rate = DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
+ } else {
+ ret_rate = divider_round_rate(hw, rate, prate, NULL,
+ divider->width, divider->div_flags);
+ }
+
+ pr_debug("--> %s: divider_round_rate: val = %ld\n",
+ clk_hw_get_name(hw), ret_rate);
+ return ret_rate;
+}
+
+static int sg2042_clk_divider_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ unsigned int value;
+ unsigned int val, val2;
+ unsigned long flags = 0;
+ struct sg2042_divider_clock *divider = to_sg2042_clk_divider(hw);
+
+ value = divider_get_val(rate, parent_rate, NULL,
+ divider->width, divider->div_flags);
+
+ if (divider->lock)
+ spin_lock_irqsave(divider->lock, flags);
+ else
+ __acquire(divider->lock);
+
+ /*
+ * The sequence of clock frequency modification is:
+ * Assert to reset divider.
+ * Modify the value of Clock Divide Factor (and High Wide if needed).
+ * De-assert to restore divided clock with new frequency.
+ */
+ val = readl(divider->reg);
+
+ /* assert */
+ val &= ~0x1;
+ writel(val, divider->reg);
+
+ if (divider->div_flags & CLK_DIVIDER_HIWORD_MASK) {
+ val = DIV_MASK(divider->width) << (divider->shift + 16);
+ } else {
+ val = readl(divider->reg);
+ val &= ~(DIV_MASK(divider->width) << divider->shift);
+ }
+ val |= value << divider->shift;
+ val |= 1 << 3;
+ writel(val, divider->reg);
+ val2 = val;
+
+ /* de-assert */
+ val |= 1;
+ writel(val, divider->reg);
+
+ if (divider->lock)
+ spin_unlock_irqrestore(divider->lock, flags);
+ else
+ __release(divider->lock);
+
+ pr_debug("--> %s: divider_set_rate: register val = 0x%x\n",
+ clk_hw_get_name(hw), val2);
+ return 0;
+}
+
+static const struct clk_ops sg2042_clk_divider_ops = {
+ .recalc_rate = sg2042_clk_divider_recalc_rate,
+ .round_rate = sg2042_clk_divider_round_rate,
+ .set_rate = sg2042_clk_divider_set_rate,
+};
+
+static const struct clk_ops sg2042_clk_divider_ro_ops = {
+ .recalc_rate = sg2042_clk_divider_recalc_rate,
+ .round_rate = sg2042_clk_divider_round_rate,
+};
+
+#define SG2042_PLL(_id, _name, _parent_name, _r_stat, _r_enable, _r_ctrl, _shift) \
+ { \
+ .hw.init = CLK_HW_INIT_PARENTS( \
+ _name, \
+ (const char *[]){_parent_name}, \
+ &sg2042_clk_pll_ops, \
+ CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE),\
+ .id = _id, \
+ .name = _name, \
+ .offset_ctrl = _r_ctrl, \
+ .offset_status = _r_stat, \
+ .offset_enable = _r_enable, \
+ .shift_status_lock = 8 + (_shift), \
+ .shift_status_updating = _shift, \
+ .shift_enable = _shift, \
+ }
+
+#define SG2042_PLL_RO(_id, _name, _parent_name, _r_stat, _r_enable, _r_ctrl, _shift) \
+ { \
+ .hw.init = CLK_HW_INIT_PARENTS( \
+ _name, \
+ (const char *[]){_parent_name}, \
+ &sg2042_clk_pll_ro_ops, \
+ CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE),\
+ .id = _id, \
+ .name = _name, \
+ .offset_ctrl = _r_ctrl, \
+ .offset_status = _r_stat, \
+ .offset_enable = _r_enable, \
+ .shift_status_lock = 8 + (_shift), \
+ .shift_status_updating = _shift, \
+ .shift_enable = _shift, \
+ }
+
+static struct sg2042_pll_clock sg2042_pll_clks[] = {
+ SG2042_PLL(MPLL_CLK, "mpll_clock", "cgi_main",
+ R_PLL_STAT, R_PLL_CLKEN_CONTROL, R_MPLL_CONTROL, 0),
+ SG2042_PLL_RO(FPLL_CLK, "fpll_clock", "cgi_main",
+ R_PLL_STAT, R_PLL_CLKEN_CONTROL, R_FPLL_CONTROL, 3),
+ SG2042_PLL_RO(DPLL0_CLK, "dpll0_clock", "cgi_dpll0",
+ R_PLL_STAT, R_PLL_CLKEN_CONTROL, R_DPLL0_CONTROL, 4),
+ SG2042_PLL_RO(DPLL1_CLK, "dpll1_clock", "cgi_dpll1",
+ R_PLL_STAT, R_PLL_CLKEN_CONTROL, R_DPLL1_CONTROL, 5),
+};
+
+#define SG2042_DIV(_id, _name, _parent_name, \
+ _r_ctrl, _shift, _width, \
+ _div_flag, _initval) { \
+ .hw.init = CLK_HW_INIT_PARENTS( \
+ _name, \
+ (const char *[]){_parent_name}, \
+ &sg2042_clk_divider_ops, \
+ 0), \
+ .id = _id, \
+ .name = _name, \
+ .offset_ctrl = _r_ctrl, \
+ .shift = _shift, \
+ .width = _width, \
+ .div_flags = _div_flag, \
+ .initval = _initval, \
+ }
+
+#define SG2042_DIV_RO(_id, _name, _parent_name, \
+ _r_ctrl, _shift, _width, \
+ _div_flag, _initval) { \
+ .hw.init = CLK_HW_INIT_PARENTS( \
+ _name, \
+ (const char *[]){_parent_name}, \
+ &sg2042_clk_divider_ro_ops, \
+ 0), \
+ .id = _id, \
+ .name = _name, \
+ .offset_ctrl = _r_ctrl, \
+ .shift = _shift, \
+ .width = _width, \
+ .div_flags = (_div_flag) | CLK_DIVIDER_READ_ONLY, \
+ .initval = _initval, \
+ }
+
+/*
+ * DIV items in the array are sorted according to the clock-tree diagram,
+ * from top to bottom, from upstream to downstream. Read TRM for details.
+ */
+#define DEF_DIVFLAG (CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO)
+static struct sg2042_divider_clock sg2042_div_clks[] = {
+ SG2042_DIV_RO(DIV_CLK_DPLL0_DDR01_0,
+ "clk_div_ddr01_0", "clk_gate_ddr01_div0",
+ R_CLKDIVREG27, 16, 5, DEF_DIVFLAG, 1),
+ SG2042_DIV_RO(DIV_CLK_FPLL_DDR01_1,
+ "clk_div_ddr01_1", "clk_gate_ddr01_div1",
+ R_CLKDIVREG28, 16, 5, DEF_DIVFLAG, 1),
+
+ SG2042_DIV_RO(DIV_CLK_DPLL1_DDR23_0,
+ "clk_div_ddr23_0", "clk_gate_ddr23_div0",
+ R_CLKDIVREG29, 16, 5, DEF_DIVFLAG, 1),
+ SG2042_DIV_RO(DIV_CLK_FPLL_DDR23_1,
+ "clk_div_ddr23_1", "clk_gate_ddr23_div1",
+ R_CLKDIVREG30, 16, 5, DEF_DIVFLAG, 1),
+
+ SG2042_DIV(DIV_CLK_MPLL_RP_CPU_NORMAL_0,
+ "clk_div_rp_cpu_normal_0", "clk_gate_rp_cpu_normal_div0",
+ R_CLKDIVREG0, 16, 5, DEF_DIVFLAG, 1),
+ SG2042_DIV(DIV_CLK_FPLL_RP_CPU_NORMAL_1,
+ "clk_div_rp_cpu_normal_1", "clk_gate_rp_cpu_normal_div1",
+ R_CLKDIVREG1, 16, 5, DEF_DIVFLAG, 1),
+
+ SG2042_DIV(DIV_CLK_MPLL_AXI_DDR_0,
+ "clk_div_axi_ddr_0", "clk_gate_axi_ddr_div0",
+ R_CLKDIVREG25, 16, 5, DEF_DIVFLAG, 2),
+ SG2042_DIV(DIV_CLK_FPLL_AXI_DDR_1,
+ "clk_div_axi_ddr_1", "clk_gate_axi_ddr_div1",
+ R_CLKDIVREG26, 16, 5, DEF_DIVFLAG, 1),
+
+ SG2042_DIV(DIV_CLK_FPLL_TOP_RP_CMN_DIV2,
+ "clk_div_top_rp_cmn_div2", "clk_mux_rp_cpu_normal",
+ R_CLKDIVREG3, 16, 16, DEF_DIVFLAG, 2),
+
+ SG2042_DIV(DIV_CLK_FPLL_50M_A53, "clk_div_50m_a53", "fpll_clock",
+ R_CLKDIVREG2, 16, 8, DEF_DIVFLAG, 20),
+ /* downstream of div_50m_a53 */
+ SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER1, "clk_div_timer1", "clk_div_50m_a53",
+ R_CLKDIVREG6, 16, 16, DEF_DIVFLAG, 1),
+ SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER2, "clk_div_timer2", "clk_div_50m_a53",
+ R_CLKDIVREG7, 16, 16, DEF_DIVFLAG, 1),
+ SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER3, "clk_div_timer3", "clk_div_50m_a53",
+ R_CLKDIVREG8, 16, 16, DEF_DIVFLAG, 1),
+ SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER4, "clk_div_timer4", "clk_div_50m_a53",
+ R_CLKDIVREG9, 16, 16, DEF_DIVFLAG, 1),
+ SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER5, "clk_div_timer5", "clk_div_50m_a53",
+ R_CLKDIVREG10, 16, 16, DEF_DIVFLAG, 1),
+ SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER6, "clk_div_timer6", "clk_div_50m_a53",
+ R_CLKDIVREG11, 16, 16, DEF_DIVFLAG, 1),
+ SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER7, "clk_div_timer7", "clk_div_50m_a53",
+ R_CLKDIVREG12, 16, 16, DEF_DIVFLAG, 1),
+ SG2042_DIV(DIV_CLK_FPLL_DIV_TIMER8, "clk_div_timer8", "clk_div_50m_a53",
+ R_CLKDIVREG13, 16, 16, DEF_DIVFLAG, 1),
+
+ /*
+ * Set clk_div_uart_500m as RO, because the width of CLKDIVREG4 is too
+ * narrow for us to produce 115200. Use UART internal divider directly.
+ */
+ SG2042_DIV_RO(DIV_CLK_FPLL_UART_500M, "clk_div_uart_500m", "fpll_clock",
+ R_CLKDIVREG4, 16, 7, DEF_DIVFLAG, 2),
+ SG2042_DIV(DIV_CLK_FPLL_AHB_LPC, "clk_div_ahb_lpc", "fpll_clock",
+ R_CLKDIVREG5, 16, 16, DEF_DIVFLAG, 5),
+ SG2042_DIV(DIV_CLK_FPLL_EFUSE, "clk_div_efuse", "fpll_clock",
+ R_CLKDIVREG14, 16, 7, DEF_DIVFLAG, 40),
+ SG2042_DIV(DIV_CLK_FPLL_TX_ETH0, "clk_div_tx_eth0", "fpll_clock",
+ R_CLKDIVREG16, 16, 11, DEF_DIVFLAG, 8),
+ SG2042_DIV(DIV_CLK_FPLL_PTP_REF_I_ETH0,
+ "clk_div_ptp_ref_i_eth0", "fpll_clock",
+ R_CLKDIVREG17, 16, 8, DEF_DIVFLAG, 20),
+ SG2042_DIV(DIV_CLK_FPLL_REF_ETH0, "clk_div_ref_eth0", "fpll_clock",
+ R_CLKDIVREG18, 16, 8, DEF_DIVFLAG, 40),
+ SG2042_DIV(DIV_CLK_FPLL_EMMC, "clk_div_emmc", "fpll_clock",
+ R_CLKDIVREG19, 16, 5, DEF_DIVFLAG, 10),
+ SG2042_DIV(DIV_CLK_FPLL_SD, "clk_div_sd", "fpll_clock",
+ R_CLKDIVREG21, 16, 5, DEF_DIVFLAG, 10),
+
+ SG2042_DIV(DIV_CLK_FPLL_TOP_AXI0, "clk_div_top_axi0", "fpll_clock",
+ R_CLKDIVREG23, 16, 5, DEF_DIVFLAG, 10),
+ /* downstream of div_top_axi0 */
+ SG2042_DIV(DIV_CLK_FPLL_100K_EMMC, "clk_div_100k_emmc", "clk_div_top_axi0",
+ R_CLKDIVREG20, 16, 16, DEF_DIVFLAG, 1000),
+ SG2042_DIV(DIV_CLK_FPLL_100K_SD, "clk_div_100k_sd", "clk_div_top_axi0",
+ R_CLKDIVREG22, 16, 16, DEF_DIVFLAG, 1000),
+ SG2042_DIV(DIV_CLK_FPLL_GPIO_DB, "clk_div_gpio_db", "clk_div_top_axi0",
+ R_CLKDIVREG15, 16, 16, DEF_DIVFLAG, 1000),
+
+ SG2042_DIV(DIV_CLK_FPLL_TOP_AXI_HSPERI,
+ "clk_div_top_axi_hsperi", "fpll_clock",
+ R_CLKDIVREG24, 16, 5, DEF_DIVFLAG, 4),
+};
+
+#define SG2042_GATE(_id, _name, _parent_name, _flags, \
+ _r_enable, _bit_idx) { \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent_name, \
+ .flags = _flags, \
+ .offset_enable = _r_enable, \
+ .bit_idx = _bit_idx, \
+ }
+
+/*
+ * GATE items in the array are sorted according to the clock-tree diagram,
+ * from top to bottom, from upstream to downstream. Read TRM for details.
+ */
+
+/* Gate clocks which control registers are defined in CLOCK. */
+static const struct sg2042_gate_clock sg2042_gate_clks[] = {
+ SG2042_GATE(GATE_CLK_DDR01_DIV0, "clk_gate_ddr01_div0", "dpll0_clock",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ R_CLKDIVREG27, 4),
+ SG2042_GATE(GATE_CLK_DDR01_DIV1, "clk_gate_ddr01_div1", "fpll_clock",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKDIVREG28, 4),
+
+ SG2042_GATE(GATE_CLK_DDR23_DIV0, "clk_gate_ddr23_div0", "dpll1_clock",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ R_CLKDIVREG29, 4),
+ SG2042_GATE(GATE_CLK_DDR23_DIV1, "clk_gate_ddr23_div1", "fpll_clock",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKDIVREG30, 4),
+
+ SG2042_GATE(GATE_CLK_RP_CPU_NORMAL_DIV0, "clk_gate_rp_cpu_normal_div0", "mpll_clock",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKDIVREG0, 4),
+ SG2042_GATE(GATE_CLK_RP_CPU_NORMAL_DIV1,
+ "clk_gate_rp_cpu_normal_div1", "fpll_clock",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKDIVREG1, 4),
+
+ SG2042_GATE(GATE_CLK_AXI_DDR_DIV0, "clk_gate_axi_ddr_div0", "mpll_clock",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKDIVREG25, 4),
+ SG2042_GATE(GATE_CLK_AXI_DDR_DIV1, "clk_gate_axi_ddr_div1", "fpll_clock",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKDIVREG26, 4),
+
+ /* upon are gate clocks as input source for the muxes */
+
+ SG2042_GATE(GATE_CLK_DDR01, "clk_gate_ddr01", "clk_mux_ddr01",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKENREG1, 14),
+
+ SG2042_GATE(GATE_CLK_DDR23, "clk_gate_ddr23", "clk_mux_ddr23",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKENREG1, 15),
+
+ SG2042_GATE(GATE_CLK_RP_CPU_NORMAL,
+ "clk_gate_rp_cpu_normal", "clk_mux_rp_cpu_normal",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKENREG0, 0),
+
+ SG2042_GATE(GATE_CLK_AXI_DDR, "clk_gate_axi_ddr", "clk_mux_axi_ddr",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKENREG1, 13),
+
+ /* upon are gate clocks directly downstream of muxes */
+
+ /* downstream of clk_div_top_rp_cmn_div2 */
+ SG2042_GATE(GATE_CLK_TOP_RP_CMN_DIV2,
+ "clk_gate_top_rp_cmn_div2", "clk_div_top_rp_cmn_div2",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG0, 2),
+ SG2042_GATE(GATE_CLK_HSDMA, "clk_gate_hsdma", "clk_gate_top_rp_cmn_div2",
+ CLK_SET_RATE_PARENT, R_CLKENREG1, 10),
+
+ /*
+ * downstream of clk_gate_rp_cpu_normal
+ *
+ * FIXME: there should be one 1/2 DIV between clk_gate_rp_cpu_normal
+ * and clk_gate_axi_pcie0/clk_gate_axi_pcie1.
+ * But the 1/2 DIV is fixed and no configurable register exported, so
+ * when reading from these two clocks, the rate value are still the
+ * same as that of clk_gate_rp_cpu_normal, it's not correct.
+ * This just affects the value read.
+ */
+ SG2042_GATE(GATE_CLK_AXI_PCIE0,
+ "clk_gate_axi_pcie0", "clk_gate_rp_cpu_normal",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG1, 8),
+ SG2042_GATE(GATE_CLK_AXI_PCIE1,
+ "clk_gate_axi_pcie1", "clk_gate_rp_cpu_normal",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG1, 9),
+
+ /* downstream of div_50m_a53 */
+ SG2042_GATE(GATE_CLK_A53_50M, "clk_gate_a53_50m", "clk_div_50m_a53",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG0, 1),
+ SG2042_GATE(GATE_CLK_TIMER1, "clk_gate_timer1", "clk_div_timer1",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 12),
+ SG2042_GATE(GATE_CLK_TIMER2, "clk_gate_timer2", "clk_div_timer2",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 13),
+ SG2042_GATE(GATE_CLK_TIMER3, "clk_gate_timer3", "clk_div_timer3",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 14),
+ SG2042_GATE(GATE_CLK_TIMER4, "clk_gate_timer4", "clk_div_timer4",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 15),
+ SG2042_GATE(GATE_CLK_TIMER5, "clk_gate_timer5", "clk_div_timer5",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 16),
+ SG2042_GATE(GATE_CLK_TIMER6, "clk_gate_timer6", "clk_div_timer6",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 17),
+ SG2042_GATE(GATE_CLK_TIMER7, "clk_gate_timer7", "clk_div_timer7",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 18),
+ SG2042_GATE(GATE_CLK_TIMER8, "clk_gate_timer8", "clk_div_timer8",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 19),
+
+ /* gate clocks downstream from div clocks one-to-one */
+ SG2042_GATE(GATE_CLK_UART_500M, "clk_gate_uart_500m", "clk_div_uart_500m",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, R_CLKENREG0, 4),
+ SG2042_GATE(GATE_CLK_AHB_LPC, "clk_gate_ahb_lpc", "clk_div_ahb_lpc",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 7),
+ SG2042_GATE(GATE_CLK_EFUSE, "clk_gate_efuse", "clk_div_efuse",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 20),
+ SG2042_GATE(GATE_CLK_TX_ETH0, "clk_gate_tx_eth0", "clk_div_tx_eth0",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 30),
+ SG2042_GATE(GATE_CLK_PTP_REF_I_ETH0,
+ "clk_gate_ptp_ref_i_eth0", "clk_div_ptp_ref_i_eth0",
+ CLK_SET_RATE_PARENT, R_CLKENREG1, 0),
+ SG2042_GATE(GATE_CLK_REF_ETH0, "clk_gate_ref_eth0", "clk_div_ref_eth0",
+ CLK_SET_RATE_PARENT, R_CLKENREG1, 1),
+ SG2042_GATE(GATE_CLK_EMMC_100M, "clk_gate_emmc", "clk_div_emmc",
+ CLK_SET_RATE_PARENT, R_CLKENREG1, 3),
+ SG2042_GATE(GATE_CLK_SD_100M, "clk_gate_sd", "clk_div_sd",
+ CLK_SET_RATE_PARENT, R_CLKENREG1, 6),
+
+ /* downstream of clk_div_top_axi0 */
+ SG2042_GATE(GATE_CLK_AHB_ROM, "clk_gate_ahb_rom", "clk_div_top_axi0",
+ 0, R_CLKENREG0, 8),
+ SG2042_GATE(GATE_CLK_AHB_SF, "clk_gate_ahb_sf", "clk_div_top_axi0",
+ 0, R_CLKENREG0, 9),
+ SG2042_GATE(GATE_CLK_AXI_SRAM, "clk_gate_axi_sram", "clk_div_top_axi0",
+ CLK_IGNORE_UNUSED, R_CLKENREG0, 10),
+ SG2042_GATE(GATE_CLK_APB_TIMER, "clk_gate_apb_timer", "clk_div_top_axi0",
+ CLK_IGNORE_UNUSED, R_CLKENREG0, 11),
+ SG2042_GATE(GATE_CLK_APB_EFUSE, "clk_gate_apb_efuse", "clk_div_top_axi0",
+ 0, R_CLKENREG0, 21),
+ SG2042_GATE(GATE_CLK_APB_GPIO, "clk_gate_apb_gpio", "clk_div_top_axi0",
+ 0, R_CLKENREG0, 22),
+ SG2042_GATE(GATE_CLK_APB_GPIO_INTR,
+ "clk_gate_apb_gpio_intr", "clk_div_top_axi0",
+ 0, R_CLKENREG0, 23),
+ SG2042_GATE(GATE_CLK_APB_I2C, "clk_gate_apb_i2c", "clk_div_top_axi0",
+ 0, R_CLKENREG0, 26),
+ SG2042_GATE(GATE_CLK_APB_WDT, "clk_gate_apb_wdt", "clk_div_top_axi0",
+ 0, R_CLKENREG0, 27),
+ SG2042_GATE(GATE_CLK_APB_PWM, "clk_gate_apb_pwm", "clk_div_top_axi0",
+ 0, R_CLKENREG0, 28),
+ SG2042_GATE(GATE_CLK_APB_RTC, "clk_gate_apb_rtc", "clk_div_top_axi0",
+ 0, R_CLKENREG0, 29),
+ SG2042_GATE(GATE_CLK_TOP_AXI0, "clk_gate_top_axi0", "clk_div_top_axi0",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKENREG1, 11),
+ /* downstream of DIV clocks which are sourced from clk_div_top_axi0 */
+ SG2042_GATE(GATE_CLK_GPIO_DB, "clk_gate_gpio_db", "clk_div_gpio_db",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 24),
+ SG2042_GATE(GATE_CLK_100K_EMMC, "clk_gate_100k_emmc", "clk_div_100k_emmc",
+ CLK_SET_RATE_PARENT, R_CLKENREG1, 4),
+ SG2042_GATE(GATE_CLK_100K_SD, "clk_gate_100k_sd", "clk_div_100k_sd",
+ CLK_SET_RATE_PARENT, R_CLKENREG1, 7),
+
+ /* downstream of clk_div_top_axi_hsperi */
+ SG2042_GATE(GATE_CLK_SYSDMA_AXI,
+ "clk_gate_sysdma_axi", "clk_div_top_axi_hsperi",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 3),
+ SG2042_GATE(GATE_CLK_APB_UART,
+ "clk_gate_apb_uart", "clk_div_top_axi_hsperi",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 5),
+ SG2042_GATE(GATE_CLK_AXI_DBG_I2C,
+ "clk_gate_axi_dbg_i2c", "clk_div_top_axi_hsperi",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 6),
+ SG2042_GATE(GATE_CLK_APB_SPI,
+ "clk_gate_apb_spi", "clk_div_top_axi_hsperi",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 25),
+ SG2042_GATE(GATE_CLK_AXI_ETH0,
+ "clk_gate_axi_eth0", "clk_div_top_axi_hsperi",
+ CLK_SET_RATE_PARENT, R_CLKENREG0, 31),
+ SG2042_GATE(GATE_CLK_AXI_EMMC,
+ "clk_gate_axi_emmc", "clk_div_top_axi_hsperi",
+ CLK_SET_RATE_PARENT, R_CLKENREG1, 2),
+ SG2042_GATE(GATE_CLK_AXI_SD,
+ "clk_gate_axi_sd", "clk_div_top_axi_hsperi",
+ CLK_SET_RATE_PARENT, R_CLKENREG1, 5),
+ SG2042_GATE(GATE_CLK_TOP_AXI_HSPERI,
+ "clk_gate_top_axi_hsperi", "clk_div_top_axi_hsperi",
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
+ R_CLKENREG1, 12),
+};
+
+/* Gate clocks which control registers are defined in SYS_CTRL. */
+static const struct sg2042_gate_clock sg2042_gate_sysclks[] = {
+ /* downstream of clk_gate_rp_cpu_normal about rxu */
+ SG2042_GATE(GATE_CLK_RXU0, "clk_gate_rxu0", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 0),
+ SG2042_GATE(GATE_CLK_RXU1, "clk_gate_rxu1", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 1),
+ SG2042_GATE(GATE_CLK_RXU2, "clk_gate_rxu2", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 2),
+ SG2042_GATE(GATE_CLK_RXU3, "clk_gate_rxu3", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 3),
+ SG2042_GATE(GATE_CLK_RXU4, "clk_gate_rxu4", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 4),
+ SG2042_GATE(GATE_CLK_RXU5, "clk_gate_rxu5", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 5),
+ SG2042_GATE(GATE_CLK_RXU6, "clk_gate_rxu6", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 6),
+ SG2042_GATE(GATE_CLK_RXU7, "clk_gate_rxu7", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 7),
+ SG2042_GATE(GATE_CLK_RXU8, "clk_gate_rxu8", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 8),
+ SG2042_GATE(GATE_CLK_RXU9, "clk_gate_rxu9", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 9),
+ SG2042_GATE(GATE_CLK_RXU10, "clk_gate_rxu10", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 10),
+ SG2042_GATE(GATE_CLK_RXU11, "clk_gate_rxu11", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 11),
+ SG2042_GATE(GATE_CLK_RXU12, "clk_gate_rxu12", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 12),
+ SG2042_GATE(GATE_CLK_RXU13, "clk_gate_rxu13", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 13),
+ SG2042_GATE(GATE_CLK_RXU14, "clk_gate_rxu14", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 14),
+ SG2042_GATE(GATE_CLK_RXU15, "clk_gate_rxu15", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 15),
+ SG2042_GATE(GATE_CLK_RXU16, "clk_gate_rxu16", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 16),
+ SG2042_GATE(GATE_CLK_RXU17, "clk_gate_rxu17", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 17),
+ SG2042_GATE(GATE_CLK_RXU18, "clk_gate_rxu18", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 18),
+ SG2042_GATE(GATE_CLK_RXU19, "clk_gate_rxu19", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 19),
+ SG2042_GATE(GATE_CLK_RXU20, "clk_gate_rxu20", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 20),
+ SG2042_GATE(GATE_CLK_RXU21, "clk_gate_rxu21", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 21),
+ SG2042_GATE(GATE_CLK_RXU22, "clk_gate_rxu22", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 22),
+ SG2042_GATE(GATE_CLK_RXU23, "clk_gate_rxu23", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 23),
+ SG2042_GATE(GATE_CLK_RXU24, "clk_gate_rxu24", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 24),
+ SG2042_GATE(GATE_CLK_RXU25, "clk_gate_rxu25", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 25),
+ SG2042_GATE(GATE_CLK_RXU26, "clk_gate_rxu26", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 26),
+ SG2042_GATE(GATE_CLK_RXU27, "clk_gate_rxu27", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 27),
+ SG2042_GATE(GATE_CLK_RXU28, "clk_gate_rxu28", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 28),
+ SG2042_GATE(GATE_CLK_RXU29, "clk_gate_rxu29", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 29),
+ SG2042_GATE(GATE_CLK_RXU30, "clk_gate_rxu30", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 30),
+ SG2042_GATE(GATE_CLK_RXU31, "clk_gate_rxu31", "clk_gate_rp_cpu_normal",
+ 0, R_RP_RXU_CLK_ENABLE, 31),
+
+ /* downstream of clk_gate_rp_cpu_normal about mp */
+ SG2042_GATE(GATE_CLK_MP0, "clk_gate_mp0", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP0_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP1, "clk_gate_mp1", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP1_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP2, "clk_gate_mp2", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP2_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP3, "clk_gate_mp3", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP3_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP4, "clk_gate_mp4", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP4_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP5, "clk_gate_mp5", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP5_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP6, "clk_gate_mp6", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP6_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP7, "clk_gate_mp7", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP7_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP8, "clk_gate_mp8", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP8_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP9, "clk_gate_mp9", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP9_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP10, "clk_gate_mp10", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP10_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP11, "clk_gate_mp11", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP11_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP12, "clk_gate_mp12", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP12_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP13, "clk_gate_mp13", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP13_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP14, "clk_gate_mp14", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP14_CONTROL_REG, 0),
+ SG2042_GATE(GATE_CLK_MP15, "clk_gate_mp15", "clk_gate_rp_cpu_normal",
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, R_MP15_CONTROL_REG, 0),
+};
+
+#define SG2042_MUX(_id, _name, _parent_names, _flags, _r_select, _shift, _width) { \
+ .id = _id, \
+ .name = _name, \
+ .parent_names = _parent_names, \
+ .num_parents = ARRAY_SIZE(_parent_names), \
+ .flags = _flags, \
+ .offset_select = _r_select, \
+ .shift = _shift, \
+ .width = _width, \
+ }
+
+/*
+ * Note: regarding names for mux clock, "0/1" or "div0/div1" means the
+ * first/second parent input source, not the register value.
+ * For example:
+ * "clk_div_ddr01_0" is the name of Clock divider 0 control of DDR01, and
+ * "clk_gate_ddr01_div0" is the gate clock in front of the "clk_div_ddr01_0",
+ * they are both controlled by register CLKDIVREG27;
+ * "clk_div_ddr01_1" is the name of Clock divider 1 control of DDR01, and
+ * "clk_gate_ddr01_div1" is the gate clock in front of the "clk_div_ddr01_1",
+ * they are both controlled by register CLKDIVREG28;
+ * While for register value of mux selection, use Clock Select for DDR01’s clock
+ * as example, see CLKSELREG0, bit[2].
+ * 1: Select in_dpll0_clk as clock source, correspondng to the parent input
+ * source from "clk_div_ddr01_0".
+ * 0: Select in_fpll_clk as clock source, corresponding to the parent input
+ * source from "clk_div_ddr01_1".
+ * So we need a table to define the array of register values corresponding to
+ * the parent index and tell CCF about this when registering mux clock.
+ */
+static const u32 sg2042_mux_table[] = {1, 0};
+
+static const char *const clk_mux_ddr01_p[] = {
+ "clk_div_ddr01_0", "clk_div_ddr01_1"};
+static const char *const clk_mux_ddr23_p[] = {
+ "clk_div_ddr23_0", "clk_div_ddr23_1"};
+static const char *const clk_mux_rp_cpu_normal_p[] = {
+ "clk_div_rp_cpu_normal_0", "clk_div_rp_cpu_normal_1"};
+static const char *const clk_mux_axi_ddr_p[] = {
+ "clk_div_axi_ddr_0", "clk_div_axi_ddr_1"};
+
+static struct sg2042_mux_clock sg2042_mux_clks[] = {
+ SG2042_MUX(MUX_CLK_DDR01, "clk_mux_ddr01", clk_mux_ddr01_p,
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_MUX_READ_ONLY,
+ R_CLKSELREG0, 2, 1),
+ SG2042_MUX(MUX_CLK_DDR23, "clk_mux_ddr23", clk_mux_ddr23_p,
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_MUX_READ_ONLY,
+ R_CLKSELREG0, 3, 1),
+ SG2042_MUX(MUX_CLK_RP_CPU_NORMAL, "clk_mux_rp_cpu_normal", clk_mux_rp_cpu_normal_p,
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+ R_CLKSELREG0, 0, 1),
+ SG2042_MUX(MUX_CLK_AXI_DDR, "clk_mux_axi_ddr", clk_mux_axi_ddr_p,
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+ R_CLKSELREG0, 1, 1),
+};
+
+static DEFINE_SPINLOCK(sg2042_clk_lock);
+
+static int sg2042_clk_register_plls(struct sg2042_clk_data *clk_data,
+ struct sg2042_pll_clock pll_clks[],
+ int num_pll_clks)
+{
+ struct clk_hw *hw;
+ struct sg2042_pll_clock *pll;
+ int i, ret = 0;
+
+ for (i = 0; i < num_pll_clks; i++) {
+ pll = &pll_clks[i];
+ /* assign these for ops usage during registration */
+ pll->map = clk_data->regmap_syscon;
+ pll->lock = &sg2042_clk_lock;
+
+ hw = &pll->hw;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ pr_err("failed to register clock %s\n", pll->name);
+ break;
+ }
+
+ clk_data->onecell_data.hws[pll->id] = hw;
+ }
+
+ /* leave unregister to outside if failed */
+ return ret;
+}
+
+static int sg2042_clk_register_divs(struct sg2042_clk_data *clk_data,
+ struct sg2042_divider_clock div_clks[],
+ int num_div_clks)
+{
+ struct clk_hw *hw;
+ struct sg2042_divider_clock *div;
+ int i, ret = 0;
+
+ for (i = 0; i < num_div_clks; i++) {
+ div = &div_clks[i];
+
+ if (div->div_flags & CLK_DIVIDER_HIWORD_MASK) {
+ if (div->width + div->shift > 16) {
+ pr_warn("divider value exceeds LOWORD field\n");
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ div->reg = clk_data->iobase + div->offset_ctrl;
+ div->lock = &sg2042_clk_lock;
+
+ hw = &div->hw;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ pr_err("failed to register clock %s\n", div->name);
+ break;
+ }
+
+ clk_data->onecell_data.hws[div->id] = hw;
+ }
+
+ /* leave unregister to outside if failed */
+ return ret;
+}
+
+/*
+ * NOTE: Gate registers are scattered in SYS_CTRL and CLOCK!
+ * @sysctrl: flag if this clock is controlled by registers defined
+ * in SYS_CTRL, 1: yes, 0: no, it's in CLOCK.
+ */
+static int sg2042_clk_register_gates(struct sg2042_clk_data *clk_data,
+ const struct sg2042_gate_clock gate_clks[],
+ int num_gate_clks,
+ bool sysctrl)
+{
+ struct clk_hw *hw;
+ const struct sg2042_gate_clock *gate;
+ int i, ret = 0;
+ void __iomem *reg;
+
+ for (i = 0; i < num_gate_clks; i++) {
+ gate = &gate_clks[i];
+ if (sysctrl)
+ reg = clk_data->iobase_syscon + gate->offset_enable;
+ else
+ reg = clk_data->iobase + gate->offset_enable;
+ hw = clk_hw_register_gate(NULL,
+ gate->name,
+ gate->parent_name,
+ gate->flags,
+ reg,
+ gate->bit_idx,
+ 0,
+ &sg2042_clk_lock);
+ if (IS_ERR(hw)) {
+ pr_err("failed to register clock %s\n", gate->name);
+ ret = PTR_ERR(hw);
+ break;
+ }
+
+ clk_data->onecell_data.hws[gate->id] = hw;
+ }
+
+ /* leave unregister to outside if failed */
+ return ret;
+}
+
+static int sg2042_mux_notifier_cb(struct notifier_block *nb,
+ unsigned long event,
+ void *data)
+{
+ int ret = 0;
+ struct clk_notifier_data *ndata = data;
+ struct clk_hw *hw = __clk_get_hw(ndata->clk);
+ const struct clk_ops *ops = &clk_mux_ops;
+ struct sg2042_mux_clock *mux = to_sg2042_mux_nb(nb);
+
+ /* To switch to fpll before changing rate and restore after that */
+ if (event == PRE_RATE_CHANGE) {
+ mux->original_index = ops->get_parent(hw);
+
+ /*
+ * "1" is the array index of the second parent input source of
+ * mux. For SG2042, it's fpll for all mux clocks.
+ * "0" is the array index of the frist parent input source of
+ * mux, For SG2042, it's mpll.
+ * FIXME, any good idea to avoid magic number?
+ */
+ if (mux->original_index == 0)
+ ret = ops->set_parent(hw, 1);
+ } else if (event == POST_RATE_CHANGE) {
+ ret = ops->set_parent(hw, mux->original_index);
+ }
+
+ return notifier_from_errno(ret);
+}
+
+static int sg2042_clk_register_muxs(struct sg2042_clk_data *clk_data,
+ struct sg2042_mux_clock mux_clks[],
+ int num_mux_clks)
+{
+ struct clk_hw *hw;
+ struct sg2042_mux_clock *mux;
+ int i, ret = 0;
+
+ for (i = 0; i < num_mux_clks; i++) {
+ mux = &mux_clks[i];
+
+ hw = clk_hw_register_mux_table(NULL,
+ mux->name,
+ mux->parent_names,
+ mux->num_parents,
+ mux->flags,
+ clk_data->iobase + mux->offset_select,
+ mux->shift,
+ BIT(mux->width) - 1,
+ 0,
+ sg2042_mux_table,
+ &sg2042_clk_lock);
+ if (IS_ERR(hw)) {
+ pr_err("failed to register clock %s\n", mux->name);
+ ret = PTR_ERR(hw);
+ break;
+ }
+
+ clk_data->onecell_data.hws[mux->id] = hw;
+
+ /*
+ * FIXME: Theoretically, we should set parent for the
+ * mux, but seems hardware has done this for us with
+ * default value, so we don't set parent again here.
+ */
+
+ if (!(mux->flags & CLK_MUX_READ_ONLY)) {
+ mux->clk_nb.notifier_call = sg2042_mux_notifier_cb;
+ ret = clk_notifier_register(hw->clk, &mux->clk_nb);
+ if (ret) {
+ pr_err("failed to register clock notifier for %s\n",
+ mux->name);
+ goto error_cleanup;
+ }
+ }
+ }
+
+ return 0;
+
+error_cleanup:
+ /* unregister notifier and release the memory allocated */
+ for (i = 0; i < num_mux_clks; i++) {
+ mux = &mux_clks[i];
+
+ hw = clk_data->onecell_data.hws[mux->id];
+
+ if (hw)
+ clk_notifier_unregister(hw->clk, &mux->clk_nb);
+ }
+
+ /* leave clk unregister to outside if failed */
+ return ret;
+}
+
+static int __init sg2042_init_clkdata_clkgen(struct device_node *node,
+ int num_clks,
+ struct sg2042_clk_data **pp_clk_data)
+{
+ int ret = 0;
+ struct sg2042_clk_data *clk_data = NULL;
+
+ clk_data = kzalloc(struct_size(clk_data, onecell_data.hws, num_clks), GFP_KERNEL);
+ if (!clk_data) {
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ clk_data->iobase = of_iomap(node, 0);
+ clk_data->onecell_data.num = num_clks;
+
+ *pp_clk_data = clk_data;
+
+ return ret;
+}
+
+static int __init sg2042_init_clkdata_sysclk(struct device_node *node,
+ int num_clks,
+ struct sg2042_clk_data **pp_clk_data)
+{
+ int ret = 0;
+ struct sg2042_clk_data *clk_data = NULL;
+ struct device_node *np_syscon;
+
+ np_syscon = of_get_parent(node);
+ if (!np_syscon) {
+ pr_err("failed to get system-control node\n");
+ ret = -EINVAL;
+ goto error_out;
+ }
+
+ clk_data = kzalloc(struct_size(clk_data, onecell_data.hws, num_clks), GFP_KERNEL);
+ if (!clk_data) {
+ ret = -ENOMEM;
+ goto error_out;
+ }
+
+ clk_data->regmap_syscon = device_node_to_regmap(np_syscon);
+ if (IS_ERR(clk_data->regmap_syscon)) {
+ ret = PTR_ERR(clk_data->regmap_syscon);
+ goto cleanup;
+ }
+ clk_data->iobase_syscon = of_iomap(np_syscon, 0);
+ clk_data->onecell_data.num = num_clks;
+
+ *pp_clk_data = clk_data;
+
+ return ret;
+
+cleanup:
+ kfree(clk_data);
+
+error_out:
+ return ret;
+}
+
+static void __init sg2042_clkgen_init(struct device_node *node)
+{
+ struct sg2042_clk_data *clk_data = NULL;
+ int i, ret = 0;
+ int num_clks = 0;
+
+ num_clks = ARRAY_SIZE(sg2042_div_clks) +
+ ARRAY_SIZE(sg2042_gate_clks) +
+ ARRAY_SIZE(sg2042_mux_clks);
+ if (num_clks == 0) {
+ ret = -EINVAL;
+ goto error_out;
+ }
+
+ ret = sg2042_init_clkdata_clkgen(node, num_clks, &clk_data);
+ if (ret < 0)
+ goto error_out;
+
+ ret = sg2042_clk_register_divs(clk_data, sg2042_div_clks,
+ ARRAY_SIZE(sg2042_div_clks));
+ if (ret)
+ goto cleanup;
+
+ ret = sg2042_clk_register_gates(clk_data, sg2042_gate_clks,
+ ARRAY_SIZE(sg2042_gate_clks), 0);
+ if (ret)
+ goto cleanup;
+
+ ret = sg2042_clk_register_muxs(clk_data, sg2042_mux_clks,
+ ARRAY_SIZE(sg2042_mux_clks));
+ if (ret)
+ goto cleanup;
+
+ ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, &clk_data->onecell_data);
+ if (ret)
+ goto cleanup;
+
+ return;
+
+cleanup:
+ for (i = 0; i < num_clks; i++) {
+ if (clk_data->onecell_data.hws[i])
+ clk_hw_unregister(clk_data->onecell_data.hws[i]);
+ }
+ kfree(clk_data);
+
+error_out:
+ pr_err("%s failed error number %d\n", __func__, ret);
+}
+
+static void __init sg2042_sysclk_init(struct device_node *node)
+{
+ struct sg2042_clk_data *clk_data = NULL;
+ int i, ret = 0;
+ int num_clks = 0;
+
+ num_clks = ARRAY_SIZE(sg2042_pll_clks) +
+ ARRAY_SIZE(sg2042_gate_sysclks);
+ if (num_clks == 0) {
+ ret = -EINVAL;
+ goto error_out;
+ }
+
+ ret = sg2042_init_clkdata_sysclk(node, num_clks, &clk_data);
+ if (ret < 0)
+ goto error_out;
+
+ ret = sg2042_clk_register_plls(clk_data, sg2042_pll_clks,
+ ARRAY_SIZE(sg2042_pll_clks));
+ if (ret)
+ goto cleanup;
+
+ ret = sg2042_clk_register_gates(clk_data, sg2042_gate_sysclks,
+ ARRAY_SIZE(sg2042_gate_sysclks), 1);
+ if (ret)
+ goto cleanup;
+
+ ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, &clk_data->onecell_data);
+ if (ret)
+ goto cleanup;
+
+ return;
+
+cleanup:
+ for (i = 0; i < num_clks; i++) {
+ if (clk_data->onecell_data.hws[i])
+ clk_hw_unregister(clk_data->onecell_data.hws[i]);
+ }
+ kfree(clk_data);
+
+error_out:
+ pr_err("%s failed error number %d\n", __func__, ret);
+}
+
+CLK_OF_DECLARE(sg2042_clkgen, "sophgo,sg2042-clkgen", sg2042_clkgen_init);
+CLK_OF_DECLARE(sg2042_sysclk, "sophgo,sg2042-sysclk", sg2042_sysclk_init);
diff --git a/drivers/clk/sophgo/clk-sophgo-sg2042.h b/drivers/clk/sophgo/clk-sophgo-sg2042.h
new file mode 100644
index 000000000000..ac60702a719d
--- /dev/null
+++ b/drivers/clk/sophgo/clk-sophgo-sg2042.h
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __CLK_SOPHGO_SG2042_H
+#define __CLK_SOPHGO_SG2042_H
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+/* Registers defined in SYS_CTRL */
+#define R_PLL_STAT 0xC0
+#define R_PLL_CLKEN_CONTROL 0xC4
+#define R_MPLL_CONTROL 0xE8
+#define R_FPLL_CONTROL 0xF4
+#define R_DPLL0_CONTROL 0xF8
+#define R_DPLL1_CONTROL 0xFC
+
+#define R_RP_RXU_CLK_ENABLE 0x0368
+#define R_MP0_STATUS_REG 0x0380
+#define R_MP0_CONTROL_REG 0x0384
+#define R_MP1_STATUS_REG 0x0388
+#define R_MP1_CONTROL_REG 0x038C
+#define R_MP2_STATUS_REG 0x0390
+#define R_MP2_CONTROL_REG 0x0394
+#define R_MP3_STATUS_REG 0x0398
+#define R_MP3_CONTROL_REG 0x039C
+#define R_MP4_STATUS_REG 0x03A0
+#define R_MP4_CONTROL_REG 0x03A4
+#define R_MP5_STATUS_REG 0x03A8
+#define R_MP5_CONTROL_REG 0x03AC
+#define R_MP6_STATUS_REG 0x03B0
+#define R_MP6_CONTROL_REG 0x03B4
+#define R_MP7_STATUS_REG 0x03B8
+#define R_MP7_CONTROL_REG 0x03BC
+#define R_MP8_STATUS_REG 0x03C0
+#define R_MP8_CONTROL_REG 0x03C4
+#define R_MP9_STATUS_REG 0x03C8
+#define R_MP9_CONTROL_REG 0x03CC
+#define R_MP10_STATUS_REG 0x03D0
+#define R_MP10_CONTROL_REG 0x03D4
+#define R_MP11_STATUS_REG 0x03D8
+#define R_MP11_CONTROL_REG 0x03DC
+#define R_MP12_STATUS_REG 0x03E0
+#define R_MP12_CONTROL_REG 0x03E4
+#define R_MP13_STATUS_REG 0x03E8
+#define R_MP13_CONTROL_REG 0x03EC
+#define R_MP14_STATUS_REG 0x03F0
+#define R_MP14_CONTROL_REG 0x03F4
+#define R_MP15_STATUS_REG 0x03F8
+#define R_MP15_CONTROL_REG 0x03FC
+
+/* Registers defined in CLOCK */
+#define R_CLKENREG0 0x00
+#define R_CLKENREG1 0x04
+#define R_CLKSELREG0 0x20
+#define R_CLKDIVREG0 0x40
+#define R_CLKDIVREG1 0x44
+#define R_CLKDIVREG2 0x48
+#define R_CLKDIVREG3 0x4C
+#define R_CLKDIVREG4 0x50
+#define R_CLKDIVREG5 0x54
+#define R_CLKDIVREG6 0x58
+#define R_CLKDIVREG7 0x5C
+#define R_CLKDIVREG8 0x60
+#define R_CLKDIVREG9 0x64
+#define R_CLKDIVREG10 0x68
+#define R_CLKDIVREG11 0x6C
+#define R_CLKDIVREG12 0x70
+#define R_CLKDIVREG13 0x74
+#define R_CLKDIVREG14 0x78
+#define R_CLKDIVREG15 0x7C
+#define R_CLKDIVREG16 0x80
+#define R_CLKDIVREG17 0x84
+#define R_CLKDIVREG18 0x88
+#define R_CLKDIVREG19 0x8C
+#define R_CLKDIVREG20 0x90
+#define R_CLKDIVREG21 0x94
+#define R_CLKDIVREG22 0x98
+#define R_CLKDIVREG23 0x9C
+#define R_CLKDIVREG24 0xA0
+#define R_CLKDIVREG25 0xA4
+#define R_CLKDIVREG26 0xA8
+#define R_CLKDIVREG27 0xAC
+#define R_CLKDIVREG28 0xB0
+#define R_CLKDIVREG29 0xB4
+#define R_CLKDIVREG30 0xB8
+
+/*
+ * Common data of clock-controller
+ * Note: this structure will be used both by clkgen & sysclk.
+ * @iobase: base address of clock-controller for clkgen
+ * @iobase_syscon & @regmap_syscon: base address of clock-controller for sysclk.
+ * The reason we use two different type of pointer just due to PLL uses
+ * regmap while others use iomem.
+ * @lock: clock register access lock
+ * @onecell_data: used for adding providers.
+ */
+struct sg2042_clk_data {
+ void __iomem *iobase;
+ void __iomem *iobase_syscon;
+ struct regmap *regmap_syscon;
+ struct clk_hw_onecell_data onecell_data;
+};
+
+/*
+ * PLL clock
+ * @id: used to map clk_onecell_data
+ * @name: used for print even when clk registration failed
+ * @map: used for regmap read/write, regmap is more useful
+ * then iomem address when we have multiple offsets
+ * for different registers.
+ * NOTE: PLL registers are all in SYS_CTRL!
+ * @lock: spinlock to protect register access
+ * @offset_status: offset of pll status registers
+ * @offset_enable: offset of pll enable registers
+ * @offset_ctrl: offset of pll control registers
+ * @shift_status_lock: shift of XXX_LOCK in pll status register
+ * @shift_status_updating: shift of UPDATING_XXX in pll status register
+ * @shift_enable: shift of XXX_CLK_EN in pll enable register
+ */
+struct sg2042_pll_clock {
+ struct clk_hw hw;
+
+ /* private data */
+ unsigned int id;
+ const char *name;
+
+ struct regmap *map;
+ /* modification of frequency can only be served one at the time */
+ spinlock_t *lock;
+
+ u32 offset_status;
+ u32 offset_enable;
+ u32 offset_ctrl;
+ u8 shift_status_lock;
+ u8 shift_status_updating;
+ u8 shift_enable;
+};
+
+#define to_sg2042_pll_clk(_hw) container_of(_hw, struct sg2042_pll_clock, hw)
+
+/*
+ * Divider clock
+ * @id: used to map clk_onecell_data
+ * @name: used for print even when clk registration failed
+ * @reg: used for readl/writel.
+ * NOTE: DIV registers are ALL in CLOCK!
+ * @lock: spinlock to protect register access
+ * @offset_ctrl: offset of divider control registers
+ * @shift: shift of "Clock Divider Factor" in divider control register
+ * @width: width of "Clock Divider Factor" in divider control register
+ * @div_flags: private flags for this clock, not for framework-specific
+ * @initval: In the divider control register, we can configure whether
+ * to use the value of "Clock Divider Factor" or just use
+ * the initial value pre-configured by IC. BIT[3] controls
+ * this and by default (value is 0), means initial value
+ * is used.
+ * **NOTE** that we cannot read the initial value (default
+ * value when poweron) and default value of "Clock Divider
+ * Factor" is zero, which I think is a hardware design flaw
+ * and should be sync-ed with the initial value. So in
+ * software we have to add a configuration item (initval)
+ * to manually configure this value and use it when BIT[3]
+ * is zero.
+ */
+struct sg2042_divider_clock {
+ struct clk_hw hw;
+
+ /* private data */
+ unsigned int id;
+ const char *name;
+
+ void __iomem *reg;
+ /* modification of frequency can only be served one at the time */
+ spinlock_t *lock;
+
+ unsigned long offset_ctrl;
+ u8 shift;
+ u8 width;
+ u8 div_flags;
+ u32 initval;
+};
+
+#define to_sg2042_clk_divider(_hw) \
+ container_of(_hw, struct sg2042_divider_clock, hw)
+
+/*
+ * Gate clock
+ * @id: used to map clk_onecell_data
+ * @name: string of this clock name
+ * @parent_name: string of parent clock name
+ * @flags: framework-specific flags for this clock
+ * @offset_enable: offset of gate enable registers
+ * @bit_idx: which bit in the register controls gating of this clock
+ */
+struct sg2042_gate_clock {
+ unsigned int id;
+ const char *name;
+ const char *parent_name;
+ unsigned long flags;
+ unsigned long offset_enable;
+ u8 bit_idx;
+};
+
+/*
+ * Mux clock
+ * @id: used to map clk_onecell_data
+ * @name: string of this clock name
+ * @parent_name: string array of parents' clock name
+ * @flags: framework-specific flags for this clock
+ * @offset_select: offset of mux selection registers
+ * NOTE: MUX registers are ALL in CLOCK!
+ * @shift: shift of "Clock Select" in mux selection register
+ * @width: width of "Clock Select" in mux selection register
+ * @clk_nb: used for notification
+ * @original_index: set by notifier callback
+ */
+struct sg2042_mux_clock {
+ unsigned int id;
+ const char *name;
+ const char * const *parent_names;
+ u8 num_parents;
+ unsigned long flags;
+ unsigned long offset_select;
+ u8 shift;
+ u8 width;
+ struct notifier_block clk_nb;
+ u8 original_index;
+};
+
+#define to_sg2042_mux_nb(_nb) container_of(_nb, struct sg2042_mux_clock, clk_nb)
+
+#endif /* __CLK_SOPHGO_SG2042_H */
--
2.25.1


2024-01-16 07:22:42

by Chen Wang

[permalink] [raw]
Subject: [PATCH v8 5/5] riscv: dts: add clock generator for Sophgo SG2042 SoC

From: Chen Wang <[email protected]>

Add clock generator node to device tree for SG2042, and enable clock for
uart.

Signed-off-by: Chen Wang <[email protected]>
---
.../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 12 ++++++
arch/riscv/boot/dts/sophgo/sg2042.dtsi | 39 +++++++++++++++++++
2 files changed, 51 insertions(+)

diff --git a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts
index 49b4b9c2c101..80cb017974d8 100644
--- a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts
+++ b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts
@@ -14,6 +14,18 @@ chosen {
};
};

+&cgi_main {
+ clock-frequency = <25000000>;
+};
+
+&cgi_dpll0 {
+ clock-frequency = <25000000>;
+};
+
+&cgi_dpll1 {
+ clock-frequency = <25000000>;
+};
+
&uart0 {
status = "okay";
};
diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi
index 93256540d078..6dd8d89d4833 100644
--- a/arch/riscv/boot/dts/sophgo/sg2042.dtsi
+++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi
@@ -5,6 +5,7 @@

/dts-v1/;
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/sophgo,sg2042-clkgen.h>

#include "sg2042-cpus.dtsi"

@@ -18,6 +19,24 @@ aliases {
serial0 = &uart0;
};

+ cgi_main: oscillator0 {
+ compatible = "fixed-clock";
+ clock-output-names = "cgi_main";
+ #clock-cells = <0>;
+ };
+
+ cgi_dpll0: oscillator1 {
+ compatible = "fixed-clock";
+ clock-output-names = "cgi_dpll0";
+ #clock-cells = <0>;
+ };
+
+ cgi_dpll1: oscillator2 {
+ compatible = "fixed-clock";
+ clock-output-names = "cgi_dpll1";
+ #clock-cells = <0>;
+ };
+
soc: soc {
compatible = "simple-bus";
#address-cells = <2>;
@@ -311,12 +330,32 @@ intc: interrupt-controller@7090000000 {
riscv,ndev = <224>;
};

+ system-control@7030010000 {
+ compatible = "sophgo,sg2042-sysctrl";
+ reg = <0x70 0x30010000 0x0 0x1000>;
+
+ sysclk: clock-controller {
+ compatible = "sophgo,sg2042-sysclk";
+ clocks = <&cgi_main>, <&cgi_dpll0>, <&cgi_dpll1>;
+ #clock-cells = <1>;
+ };
+ };
+
+ clkgen: clock-controller@7030012000 {
+ compatible = "sophgo,sg2042-clkgen";
+ reg = <0x70 0x30012000 0x0 0x1000>;
+ #clock-cells = <1>;
+ };
+
uart0: serial@7040000000 {
compatible = "snps,dw-apb-uart";
reg = <0x00000070 0x40000000 0x00000000 0x00001000>;
interrupt-parent = <&intc>;
interrupts = <112 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <500000000>;
+ clocks = <&clkgen GATE_CLK_UART_500M>,
+ <&clkgen GATE_CLK_APB_UART>;
+ clock-names = "baudclk", "apb_pclk";
reg-shift = <2>;
reg-io-width = <4>;
status = "disabled";
--
2.25.1


2024-01-16 09:48:17

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v8 0/5] riscv: sophgo: add clock support for sg2042

On 16/01/2024 08:20, Chen Wang wrote:
> From: Chen Wang <[email protected]>
>
> This series adds clock controller support for sophgo sg2042.
>
> Thanks,
> Chen
>
> ---
>
> Changes in v8:
> The patch series is based on v6.7. You can simply review or test the
> patches at the link [9].
>

..

> Changes in v1:
> The patch series is based on v6.7-rc1. You can simply review or test the
> patches at the link [1].
>
> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v1 [1]
> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v2 [2]
> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v3 [3]
> Link: https://lore.kernel.org/linux-riscv/MA0P287MB03329AE180378E1A2E034374FE82A@MA0P287MB0332.INDP287.PROD.OUTLOOK.COM/ [4]
> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v4 [5]
> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v5 [6]
> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v6 [7]
> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v7 [8]
> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v8 [9]

lore links are useful to previous discussions. This shows what was at
v7, but I cannot see my comments and compare whether you applied them.

Best regards,
Krzysztof


2024-01-16 10:06:16

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v8 2/5] dt-bindings: soc: sophgo: Add Sophgo system control module

On 16/01/2024 08:21, Chen Wang wrote:
> From: Chen Wang <[email protected]>
>
> Add documentation to describe Sophgo System Control for SG2042.
>
> Signed-off-by: Chen Wang <[email protected]>
> ---
> .../soc/sophgo/sophgo,sg2042-sysctrl.yaml | 46 +++++++++++++++++++
> 1 file changed, 46 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>
> diff --git a/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
> new file mode 100644
> index 000000000000..7b50bb56b4cf
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
> @@ -0,0 +1,46 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/sophgo/sophgo,sg2042-sysctrl.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Sophgo SG2042 SoC system control
> +
> +maintainers:
> + - Chen Wang <[email protected]>
> +
> +description:
> + The Sophgo system control is a registers block (SYS_CTRL), providing multiple
> + low level platform functions like chip configuration, clock control, etc.
> +
> +properties:
> + compatible:
> + const: sophgo,sg2042-sysctrl
> +
> + reg:
> + maxItems: 1
> +
> + clock-controller:
> + # Child node

Drop the comment, it is obvious. It cannot be anything else.

> + $ref: /schemas/clock/sophgo,sg2042-sysclk.yaml#
> + type: object

Why isn't this merged here? You do not need the child node really...
unless the clock inputs are specific to that clock controller and you
will have here more devices? But where are they in such case?

> +
> +required:
> + - compatible
> + - reg
> + - clock-controller
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + system-control@30010000 {

Why did you change the name? Please provide detailed changelog with
explanation of such changes.


> + compatible = "sophgo,sg2042-sysctrl";
> + reg = <0x30010000 0x1000>;
> +

Best regards,
Krzysztof


2024-01-16 10:09:15

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v8 1/5] dt-bindings: clock: sophgo: add sysclk for SG2042

On 16/01/2024 08:20, Chen Wang wrote:
> From: Chen Wang <[email protected]>
>
> Add bindings for the clocks of which configuration registers are in the
> range of SYS_CTRL in the memory-map.

This means it is not a separate device and should be just merged with
parent node. Otherwise please give us some arguments why this should be
a separate device node.


>
> Signed-off-by: Chen Wang <[email protected]>
>
> .

Some stray characters above ^^^. Clean your commit msg. Also, I have
doubts it passes checkpatch.


Best regards,
Krzysztof


2024-01-16 11:37:56

by Chen Wang

[permalink] [raw]
Subject: Re: [PATCH v8 2/5] dt-bindings: soc: sophgo: Add Sophgo system control module


On 2024/1/16 18:06, Krzysztof Kozlowski wrote:
> On 16/01/2024 08:21, Chen Wang wrote:
>> From: Chen Wang <[email protected]>
>>
>> Add documentation to describe Sophgo System Control for SG2042.
>>
>> Signed-off-by: Chen Wang <[email protected]>
>> ---
>> .../soc/sophgo/sophgo,sg2042-sysctrl.yaml | 46 +++++++++++++++++++
>> 1 file changed, 46 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>> new file mode 100644
>> index 000000000000..7b50bb56b4cf
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>> @@ -0,0 +1,46 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/soc/sophgo/sophgo,sg2042-sysctrl.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Sophgo SG2042 SoC system control
>> +
>> +maintainers:
>> + - Chen Wang <[email protected]>
>> +
>> +description:
>> + The Sophgo system control is a registers block (SYS_CTRL), providing multiple
>> + low level platform functions like chip configuration, clock control, etc.
>> +
>> +properties:
>> + compatible:
>> + const: sophgo,sg2042-sysctrl
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + clock-controller:
>> + # Child node
> Drop the comment, it is obvious. It cannot be anything else.
>
>> + $ref: /schemas/clock/sophgo,sg2042-sysclk.yaml#
>> + type: object
> Why isn't this merged here? You do not need the child node really...
> unless the clock inputs are specific to that clock controller and you
> will have here more devices? But where are they in such case?
I don't see more devices will be included later. It should be ok to
merge them into one.
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - clock-controller
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + system-control@30010000 {
> Why did you change the name? Please provide detailed changelog with
> explanation of such changes.

I changed the name due to I find the
TRM(https://github.com/sophgo/sophgo-doc/blob/main/SG2042/TRM/source/system-control.rst)
call it "system control",  so I changed it in v8.

Which one do you prefer? I'm not sure if there are any requirements for
this?

>> + compatible = "sophgo,sg2042-sysctrl";
>> + reg = <0x30010000 0x1000>;
>> +
> Best regards,
> Krzysztof
>

2024-01-16 11:40:58

by Chen Wang

[permalink] [raw]
Subject: Re: [PATCH v8 0/5] riscv: sophgo: add clock support for sg2042


On 2024/1/16 17:47, Krzysztof Kozlowski wrote:
> On 16/01/2024 08:20, Chen Wang wrote:
>> From: Chen Wang <[email protected]>
>>
>> This series adds clock controller support for sophgo sg2042.
>>
>> Thanks,
>> Chen
>>
>> ---
>>
>> Changes in v8:
>> The patch series is based on v6.7. You can simply review or test the
>> patches at the link [9].
>>
> ...
>
>> Changes in v1:
>> The patch series is based on v6.7-rc1. You can simply review or test the
>> patches at the link [1].
>>
>> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v1 [1]
>> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v2 [2]
>> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v3 [3]
>> Link: https://lore.kernel.org/linux-riscv/MA0P287MB03329AE180378E1A2E034374FE82A@MA0P287MB0332.INDP287.PROD.OUTLOOK.COM/ [4]
>> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v4 [5]
>> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v5 [6]
>> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v6 [7]
>> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v7 [8]
>> Link: https://github.com/unicornx/linux-riscv/commits/upstream-sg2042-clock-v8 [9]
> lore links are useful to previous discussions. This shows what was at
> v7, but I cannot see my comments and compare whether you applied them.
Ok, I will replace them with lore links in next revision.
>
> Best regards,
> Krzysztof
>

2024-01-16 12:15:42

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v8 2/5] dt-bindings: soc: sophgo: Add Sophgo system control module

On 16/01/2024 12:37, Chen Wang wrote:
>
> On 2024/1/16 18:06, Krzysztof Kozlowski wrote:
>> On 16/01/2024 08:21, Chen Wang wrote:
>>> From: Chen Wang <[email protected]>
>>>
>>> Add documentation to describe Sophgo System Control for SG2042.
>>>
>>> Signed-off-by: Chen Wang <[email protected]>
>>> ---
>>> .../soc/sophgo/sophgo,sg2042-sysctrl.yaml | 46 +++++++++++++++++++
>>> 1 file changed, 46 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>> new file mode 100644
>>> index 000000000000..7b50bb56b4cf
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>> @@ -0,0 +1,46 @@
>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/soc/sophgo/sophgo,sg2042-sysctrl.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Sophgo SG2042 SoC system control
>>> +
>>> +maintainers:
>>> + - Chen Wang <[email protected]>
>>> +
>>> +description:
>>> + The Sophgo system control is a registers block (SYS_CTRL), providing multiple
>>> + low level platform functions like chip configuration, clock control, etc.
>>> +
>>> +properties:
>>> + compatible:
>>> + const: sophgo,sg2042-sysctrl
>>> +
>>> + reg:
>>> + maxItems: 1
>>> +
>>> + clock-controller:
>>> + # Child node
>> Drop the comment, it is obvious. It cannot be anything else.
>>
>>> + $ref: /schemas/clock/sophgo,sg2042-sysclk.yaml#
>>> + type: object
>> Why isn't this merged here? You do not need the child node really...
>> unless the clock inputs are specific to that clock controller and you
>> will have here more devices? But where are they in such case?
> I don't see more devices will be included later. It should be ok to
> merge them into one.
>>> +
>>> +required:
>>> + - compatible
>>> + - reg
>>> + - clock-controller
>>> +
>>> +additionalProperties: false
>>> +
>>> +examples:
>>> + - |
>>> + system-control@30010000 {
>> Why did you change the name? Please provide detailed changelog with
>> explanation of such changes.
>
> I changed the name due to I find the
> TRM(https://github.com/sophgo/sophgo-doc/blob/main/SG2042/TRM/source/system-control.rst)
> call it "system control",  so I changed it in v8.
>
> Which one do you prefer? I'm not sure if there are any requirements for
> this?

Node names should be generic and follow common guidelines, not match
your TRM. Please use the same name all other devices use for the same class.

Best regards,
Krzysztof


2024-01-18 05:30:32

by Chen Wang

[permalink] [raw]
Subject: Re: [PATCH v8 2/5] dt-bindings: soc: sophgo: Add Sophgo system control module


On 2024/1/16 19:37, Chen Wang wrote:
>
> On 2024/1/16 18:06, Krzysztof Kozlowski wrote:
>> On 16/01/2024 08:21, Chen Wang wrote:
>>> From: Chen Wang <[email protected]>
>>>
>>> Add documentation to describe Sophgo System Control for SG2042.
>>>
>>> Signed-off-by: Chen Wang <[email protected]>
>>> ---
>>>   .../soc/sophgo/sophgo,sg2042-sysctrl.yaml     | 46
>>> +++++++++++++++++++
>>>   1 file changed, 46 insertions(+)
>>>   create mode 100644
>>> Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>> b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>
>>> new file mode 100644
>>> index 000000000000..7b50bb56b4cf
>>> --- /dev/null
>>> +++
>>> b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>> @@ -0,0 +1,46 @@
>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id:
>>> http://devicetree.org/schemas/soc/sophgo/sophgo,sg2042-sysctrl.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Sophgo SG2042 SoC system control
>>> +
>>> +maintainers:
>>> +  - Chen Wang <[email protected]>
>>> +
>>> +description:
>>> +  The Sophgo system control is a registers block (SYS_CTRL),
>>> providing multiple
>>> +  low level platform functions like chip configuration, clock
>>> control, etc.
>>> +
>>> +properties:
>>> +  compatible:
>>> +    const: sophgo,sg2042-sysctrl
>>> +
>>> +  reg:
>>> +    maxItems: 1
>>> +
>>> +  clock-controller:
>>> +    # Child node
>> Drop the comment, it is obvious. It cannot be anything else.
>>
>>> +    $ref: /schemas/clock/sophgo,sg2042-sysclk.yaml#
>>> +    type: object
>> Why isn't this merged here? You do not need the child node really...
>> unless the clock inputs are specific to that clock controller and you
>> will have here more devices? But where are they in such case?
> I don't see more devices will be included later. It should be ok to
> merge them into one.

hi, Krzysztof,

After some double check, I find we will have more devices in
system-control. For example, in the SYS_CTRL area, there is also a
section of registers used to control the "General Purpose Interrupt".
The pcie controller of sg2042 will use this interrupt controller which
is defined in SYS_CTRL, we will add it in later work.

Specifically, the distribution (offset) of registers in SYS_CTRL is as
follows:

- 0x0C0 ~ 0x0FC: for some PLL clocks :

- ......

- 0x2E0 ~ 0x30C: for General Purpose Interrupt:

- ......

- 0x368 ~ 0x3FC: For some gate clocks

So it seems that it is still necessary to keep the current child node
method, and it will also facilitate future expansion.

What do you think, please feel free let me know.

Thanks,

Chen


2024-01-22 03:43:22

by Chen Wang

[permalink] [raw]
Subject: Re: [PATCH v8 2/5] dt-bindings: soc: sophgo: Add Sophgo system control module


On 2024/1/18 13:29, Chen Wang wrote:
>
> On 2024/1/16 19:37, Chen Wang wrote:
>>
>> On 2024/1/16 18:06, Krzysztof Kozlowski wrote:
>>> On 16/01/2024 08:21, Chen Wang wrote:
>>>> From: Chen Wang <[email protected]>
>>>>
>>>> Add documentation to describe Sophgo System Control for SG2042.
>>>>
>>>> Signed-off-by: Chen Wang <[email protected]>
>>>> ---
>>>>   .../soc/sophgo/sophgo,sg2042-sysctrl.yaml     | 46
>>>> +++++++++++++++++++
>>>>   1 file changed, 46 insertions(+)
>>>>   create mode 100644
>>>> Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>>
>>>>
>>>> diff --git
>>>> a/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>> b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>>
>>>> new file mode 100644
>>>> index 000000000000..7b50bb56b4cf
>>>> --- /dev/null
>>>> +++
>>>> b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>> @@ -0,0 +1,46 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>>> +%YAML 1.2
>>>> +---
>>>> +$id:
>>>> http://devicetree.org/schemas/soc/sophgo/sophgo,sg2042-sysctrl.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Sophgo SG2042 SoC system control
>>>> +
>>>> +maintainers:
>>>> +  - Chen Wang <[email protected]>
>>>> +
>>>> +description:
>>>> +  The Sophgo system control is a registers block (SYS_CTRL),
>>>> providing multiple
>>>> +  low level platform functions like chip configuration, clock
>>>> control, etc.
>>>> +
>>>> +properties:
>>>> +  compatible:
>>>> +    const: sophgo,sg2042-sysctrl
>>>> +
>>>> +  reg:
>>>> +    maxItems: 1
>>>> +
>>>> +  clock-controller:
>>>> +    # Child node
>>> Drop the comment, it is obvious. It cannot be anything else.
>>>
>>>> +    $ref: /schemas/clock/sophgo,sg2042-sysclk.yaml#
>>>> +    type: object
>>> Why isn't this merged here? You do not need the child node really...
>>> unless the clock inputs are specific to that clock controller and you
>>> will have here more devices? But where are they in such case?
>> I don't see more devices will be included later. It should be ok to
>> merge them into one.
>
> hi, Krzysztof,
>
> After some double check, I find we will have more devices in
> system-control. For example, in the SYS_CTRL area, there is also a
> section of registers used to control the "General Purpose Interrupt".
> The pcie controller of sg2042 will use this interrupt controller which
> is defined in SYS_CTRL, we will add it in later work.
>
> Specifically, the distribution (offset) of registers in SYS_CTRL is as
> follows:
>
> - 0x0C0 ~ 0x0FC: for some PLL clocks :
>
> - ......
>
> - 0x2E0 ~ 0x30C: for General Purpose Interrupt:
>
> - ......
>
> - 0x368 ~ 0x3FC: For some gate clocks
>
> So it seems that it is still necessary to keep the current child node
> method, and it will also facilitate future expansion.
>
> What do you think, please feel free let me know.
>
> Thanks,
>
> Chen

hi, Krzysztof,

Can you please take a look if you have time, looking forward to your reply.

Thanks,

Chen


>
>
> _______________________________________________
> linux-riscv mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-riscv

2024-01-22 08:10:47

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v8 2/5] dt-bindings: soc: sophgo: Add Sophgo system control module

On 18/01/2024 06:29, Chen Wang wrote:
>
> On 2024/1/16 19:37, Chen Wang wrote:
>>
>> On 2024/1/16 18:06, Krzysztof Kozlowski wrote:
>>> On 16/01/2024 08:21, Chen Wang wrote:
>>>> From: Chen Wang <[email protected]>
>>>>
>>>> Add documentation to describe Sophgo System Control for SG2042.
>>>>
>>>> Signed-off-by: Chen Wang <[email protected]>
>>>> ---
>>>>   .../soc/sophgo/sophgo,sg2042-sysctrl.yaml     | 46
>>>> +++++++++++++++++++
>>>>   1 file changed, 46 insertions(+)
>>>>   create mode 100644
>>>> Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>>
>>>> diff --git
>>>> a/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>> b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>>
>>>> new file mode 100644
>>>> index 000000000000..7b50bb56b4cf
>>>> --- /dev/null
>>>> +++
>>>> b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>> @@ -0,0 +1,46 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>>> +%YAML 1.2
>>>> +---
>>>> +$id:
>>>> http://devicetree.org/schemas/soc/sophgo/sophgo,sg2042-sysctrl.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Sophgo SG2042 SoC system control
>>>> +
>>>> +maintainers:
>>>> +  - Chen Wang <[email protected]>
>>>> +
>>>> +description:
>>>> +  The Sophgo system control is a registers block (SYS_CTRL),
>>>> providing multiple
>>>> +  low level platform functions like chip configuration, clock
>>>> control, etc.
>>>> +
>>>> +properties:
>>>> +  compatible:
>>>> +    const: sophgo,sg2042-sysctrl
>>>> +
>>>> +  reg:
>>>> +    maxItems: 1
>>>> +
>>>> +  clock-controller:
>>>> +    # Child node
>>> Drop the comment, it is obvious. It cannot be anything else.
>>>
>>>> +    $ref: /schemas/clock/sophgo,sg2042-sysclk.yaml#
>>>> +    type: object
>>> Why isn't this merged here? You do not need the child node really...
>>> unless the clock inputs are specific to that clock controller and you
>>> will have here more devices? But where are they in such case?
>> I don't see more devices will be included later. It should be ok to
>> merge them into one.
>
> hi, Krzysztof,
>
> After some double check, I find we will have more devices in
> system-control. For example, in the SYS_CTRL area, there is also a
> section of registers used to control the "General Purpose Interrupt".
> The pcie controller of sg2042 will use this interrupt controller which
> is defined in SYS_CTRL, we will add it in later work.
>

I expect then all devices to be documented.

Best regards,
Krzysztof


2024-01-22 10:12:44

by Chen Wang

[permalink] [raw]
Subject: Re: [PATCH v8 2/5] dt-bindings: soc: sophgo: Add Sophgo system control module


On 2024/1/22 16:10, Krzysztof Kozlowski wrote:
> On 18/01/2024 06:29, Chen Wang wrote:
>> On 2024/1/16 19:37, Chen Wang wrote:
>>> On 2024/1/16 18:06, Krzysztof Kozlowski wrote:
>>>> On 16/01/2024 08:21, Chen Wang wrote:
>>>>> From: Chen Wang <[email protected]>
>>>>>
>>>>> Add documentation to describe Sophgo System Control for SG2042.
>>>>>
>>>>> Signed-off-by: Chen Wang <[email protected]>
>>>>> ---
>>>>>   .../soc/sophgo/sophgo,sg2042-sysctrl.yaml     | 46
>>>>> +++++++++++++++++++
>>>>>   1 file changed, 46 insertions(+)
>>>>>   create mode 100644
>>>>> Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>>>
>>>>> diff --git
>>>>> a/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>>> b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>>>
>>>>> new file mode 100644
>>>>> index 000000000000..7b50bb56b4cf
>>>>> --- /dev/null
>>>>> +++
>>>>> b/Documentation/devicetree/bindings/soc/sophgo/sophgo,sg2042-sysctrl.yaml
>>>>> @@ -0,0 +1,46 @@
>>>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>>>> +%YAML 1.2
>>>>> +---
>>>>> +$id:
>>>>> http://devicetree.org/schemas/soc/sophgo/sophgo,sg2042-sysctrl.yaml#
>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>> +
>>>>> +title: Sophgo SG2042 SoC system control
>>>>> +
>>>>> +maintainers:
>>>>> +  - Chen Wang <[email protected]>
>>>>> +
>>>>> +description:
>>>>> +  The Sophgo system control is a registers block (SYS_CTRL),
>>>>> providing multiple
>>>>> +  low level platform functions like chip configuration, clock
>>>>> control, etc.
>>>>> +
>>>>> +properties:
>>>>> +  compatible:
>>>>> +    const: sophgo,sg2042-sysctrl
>>>>> +
>>>>> +  reg:
>>>>> +    maxItems: 1
>>>>> +
>>>>> +  clock-controller:
>>>>> +    # Child node
>>>> Drop the comment, it is obvious. It cannot be anything else.
>>>>
>>>>> +    $ref: /schemas/clock/sophgo,sg2042-sysclk.yaml#
>>>>> +    type: object
>>>> Why isn't this merged here? You do not need the child node really...
>>>> unless the clock inputs are specific to that clock controller and you
>>>> will have here more devices? But where are they in such case?
>>> I don't see more devices will be included later. It should be ok to
>>> merge them into one.
>> hi, Krzysztof,
>>
>> After some double check, I find we will have more devices in
>> system-control. For example, in the SYS_CTRL area, there is also a
>> section of registers used to control the "General Purpose Interrupt".
>> The pcie controller of sg2042 will use this interrupt controller which
>> is defined in SYS_CTRL, we will add it in later work.
>>
> I expect then all devices to be documented.

hi, Krzysztof.

First, I'm very sorry for having double-checked with you for this system
controller and child node issue, but this time I'm sure there should be
no more child nodes except the clock and interrupt controllers, though
there are some other registers in SYS_CTRL section, but we will not use
them till now.

One question, when you say "to be documented", do you mean I need write
binding/yaml files for other child node? But they exceed the scope of
this patchset (this patchset is for clock support only). That's why I
suggest just add clock-controller in this patchset and to add the
interrupt controller in another patchset for pcie support. This
mechanism should be suitable for our expansion.

Thanks,

Chen

>
> Best regards,
> Krzysztof
>

2024-01-22 12:57:41

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v8 2/5] dt-bindings: soc: sophgo: Add Sophgo system control module

On 22/01/2024 11:11, Chen Wang wrote:
>>>>>> +    $ref: /schemas/clock/sophgo,sg2042-sysclk.yaml#
>>>>>> +    type: object
>>>>> Why isn't this merged here? You do not need the child node really...
>>>>> unless the clock inputs are specific to that clock controller and you
>>>>> will have here more devices? But where are they in such case?
>>>> I don't see more devices will be included later. It should be ok to
>>>> merge them into one.
>>> hi, Krzysztof,
>>>
>>> After some double check, I find we will have more devices in
>>> system-control. For example, in the SYS_CTRL area, there is also a
>>> section of registers used to control the "General Purpose Interrupt".
>>> The pcie controller of sg2042 will use this interrupt controller which
>>> is defined in SYS_CTRL, we will add it in later work.
>>>
>> I expect then all devices to be documented.
>
> hi, Krzysztof.
>
> First, I'm very sorry for having double-checked with you for this system
> controller and child node issue, but this time I'm sure there should be
> no more child nodes except the clock and interrupt controllers, though
> there are some other registers in SYS_CTRL section, but we will not use
> them till now.
>
> One question, when you say "to be documented", do you mean I need write
> binding/yaml files for other child node? But they exceed the scope of
> this patchset (this patchset is for clock support only). That's why I

That's not true. The scope of this patch is to add DT binding
description for your device. If you choose any other scope, I don't
agree and I am not going to provide positive review.

> suggest just add clock-controller in this patchset and to add the
> interrupt controller in another patchset for pcie support. This
> mechanism should be suitable for our expansion.

How then are you going to solve the requirement: "DO attempt to make
bindings complete even"?

https://elixir.bootlin.com/linux/v6.1-rc1/source/Documentation/devicetree/bindings/writing-bindings.rst#L17

Best regards,
Krzysztof


2024-01-23 09:29:39

by Chen Wang

[permalink] [raw]
Subject: Re: [PATCH v8 2/5] dt-bindings: soc: sophgo: Add Sophgo system control module


On 2024/1/22 20:56, Krzysztof Kozlowski wrote:
> On 22/01/2024 11:11, Chen Wang wrote:
>>>>>>> +    $ref: /schemas/clock/sophgo,sg2042-sysclk.yaml#
>>>>>>> +    type: object
>>>>>> Why isn't this merged here? You do not need the child node really...
>>>>>> unless the clock inputs are specific to that clock controller and you
>>>>>> will have here more devices? But where are they in such case?
>>>>> I don't see more devices will be included later. It should be ok to
>>>>> merge them into one.
>>>> hi, Krzysztof,
>>>>
>>>> After some double check, I find we will have more devices in
>>>> system-control. For example, in the SYS_CTRL area, there is also a
>>>> section of registers used to control the "General Purpose Interrupt".
>>>> The pcie controller of sg2042 will use this interrupt controller which
>>>> is defined in SYS_CTRL, we will add it in later work.
>>>>
>>> I expect then all devices to be documented.
>> hi, Krzysztof.
>>
>> First, I'm very sorry for having double-checked with you for this system
>> controller and child node issue, but this time I'm sure there should be
>> no more child nodes except the clock and interrupt controllers, though
>> there are some other registers in SYS_CTRL section, but we will not use
>> them till now.
>>
>> One question, when you say "to be documented", do you mean I need write
>> binding/yaml files for other child node? But they exceed the scope of
>> this patchset (this patchset is for clock support only). That's why I
> That's not true. The scope of this patch is to add DT binding
> description for your device. If you choose any other scope, I don't
> agree and I am not going to provide positive review.
>
>> suggest just add clock-controller in this patchset and to add the
>> interrupt controller in another patchset for pcie support. This
>> mechanism should be suitable for our expansion.
> How then are you going to solve the requirement: "DO attempt to make
> bindings complete even"?
>
> https://elixir.bootlin.com/linux/v6.1-rc1/source/Documentation/devicetree/bindings/writing-bindings.rst#L17
Learned and I will try to make bindings for system-controller device
complete, thanks.
>
> Best regards,
> Krzysztof
>