2023-05-12 02:24:16

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v4 0/7] Add PLL clocks driver and syscon for StarFive JH7110 SoC

This patch serises are to add PLL clocks driver and providers by writing
and reading syscon registers for the StarFive JH7110 RISC-V SoC. And add
documentation and nodes to describe StarFive System Controller(syscon)
Registers. This patch serises are based on Linux 6.4-rc1.

PLL are high speed, low jitter frequency synthesizers in JH7110.
Each PLL clocks work in integer mode or fraction mode by some dividers,
and the dividers are set in several syscon registers.
The formula for calculating frequency is:
Fvco = Fref * (NI + NF) / M / Q1

The first patch adds docunmentation to describe PLL clock bindings,
and the second patch adds driver to support PLL clocks for JH7110.
The patch 3 modifies the SYSCRG dibindings and adds PLL clock inputs.
The patch 4 modifies the system clock driver and changes PLL clock source
from PLL clock controller instead of the fixed factor clocks. The patch 5
adds documentation to decribe syscon registers. And the patch 6 adds the
stg/sys/aon syscon nodes for JH7110 SoC. The last patch adds PLL
clock node and modifies the syscrg node in JH7110 dts file.

Changes since v3:
- Rebased on Linux 6.4-rc1.
- Dropped the 'power-controller' property and used 'power-domain-cells'
instead in syscon binding.
- Used the data by of_device_id to get the syscon registers'
configuration include offset, mask and shift.

v3: https://lore.kernel.org/all/[email protected]/

Changes since v2:
- Rebased on latest JH7110 basic clock drivers.
- Added the complete documentation to describe syscon register.
- Added syscon node in JH7110 dts file.
- Modified the clock rate selection to match the closest rate in
PLL driver when setting rate.

v2: https://lore.kernel.org/all/[email protected]/

Changes since v1:
- Changed PLL clock node to be child of syscon node in dts.
- Modifed the definitions and names of function in PLL clock driver.
- Added commit to update syscon and syscrg dt-bindings.

v1: https://lore.kernel.org/all/[email protected]/

William Qiu (2):
dt-bindings: soc: starfive: Add StarFive syscon module
riscv: dts: starfive: jh7110: Add syscon nodes

Xingyu Wu (5):
dt-bindings: clock: Add StarFive JH7110 PLL clock generator
clk: starfive: Add StarFive JH7110 PLL clock driver
dt-bindings: clock: jh7110-syscrg: Add PLL clock inputs
clk: starfive: jh7110-sys: Modify PLL clocks source
riscv: dts: starfive: jh7110: Add PLL clock node and modify syscrg
node

.../bindings/clock/starfive,jh7110-pll.yaml | 46 +++
.../clock/starfive,jh7110-syscrg.yaml | 20 +-
.../soc/starfive/starfive,jh7110-syscon.yaml | 67 ++++
MAINTAINERS | 13 +
arch/riscv/boot/dts/starfive/jh7110.dtsi | 30 +-
drivers/clk/starfive/Kconfig | 9 +
drivers/clk/starfive/Makefile | 1 +
.../clk/starfive/clk-starfive-jh7110-pll.c | 309 ++++++++++++++++
.../clk/starfive/clk-starfive-jh7110-pll.h | 331 ++++++++++++++++++
.../clk/starfive/clk-starfive-jh7110-sys.c | 31 +-
.../dt-bindings/clock/starfive,jh7110-crg.h | 6 +
11 files changed, 834 insertions(+), 29 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml
create mode 100644 Documentation/devicetree/bindings/soc/starfive/starfive,jh7110-syscon.yaml
create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.c
create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.h


base-commit: ac9a78681b921877518763ba0e89202254349d1b
--
2.25.1



2023-05-12 02:24:26

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

Add bindings for the PLL clock generator on the JH7110 RISC-V SoC.

Reviewed-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Xingyu Wu <[email protected]>
---
.../bindings/clock/starfive,jh7110-pll.yaml | 46 +++++++++++++++++++
.../dt-bindings/clock/starfive,jh7110-crg.h | 6 +++
2 files changed, 52 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml

diff --git a/Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml b/Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml
new file mode 100644
index 000000000000..8aa8c7b8e42f
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/starfive,jh7110-pll.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JH7110 PLL Clock Generator
+
+description:
+ This PLL are high speed, low jitter frequency synthesizers in JH7110.
+ Each PLL clocks work in integer mode or fraction mode by some dividers,
+ and the configuration registers and dividers are set in several syscon
+ registers. So pll node should be a child of SYS-SYSCON node.
+ The formula for calculating frequency is that,
+ Fvco = Fref * (NI + NF) / M / Q1
+
+maintainers:
+ - Xingyu Wu <[email protected]>
+
+properties:
+ compatible:
+ const: starfive,jh7110-pll
+
+ clocks:
+ maxItems: 1
+ description: Main Oscillator (24 MHz)
+
+ '#clock-cells':
+ const: 1
+ description:
+ See <dt-bindings/clock/starfive,jh7110-crg.h> for valid indices.
+
+required:
+ - compatible
+ - clocks
+ - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ pll-clock-controller {
+ compatible = "starfive,jh7110-pll";
+ clocks = <&osc>;
+ #clock-cells = <1>;
+ };
diff --git a/include/dt-bindings/clock/starfive,jh7110-crg.h b/include/dt-bindings/clock/starfive,jh7110-crg.h
index 06257bfd9ac1..086a6ddcf380 100644
--- a/include/dt-bindings/clock/starfive,jh7110-crg.h
+++ b/include/dt-bindings/clock/starfive,jh7110-crg.h
@@ -6,6 +6,12 @@
#ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
#define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__

+/* PLL clocks */
+#define JH7110_CLK_PLL0_OUT 0
+#define JH7110_CLK_PLL1_OUT 1
+#define JH7110_CLK_PLL2_OUT 2
+#define JH7110_PLLCLK_END 3
+
/* SYSCRG clocks */
#define JH7110_SYSCLK_CPU_ROOT 0
#define JH7110_SYSCLK_CPU_CORE 1
--
2.25.1


2023-05-12 02:24:35

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v4 7/7] riscv: dts: starfive: jh7110: Add PLL clock node and modify syscrg node

Add the PLL clock node for the Starfive JH7110 SoC and
modify the SYSCRG node to add PLL clocks input.

Signed-off-by: Xingyu Wu <[email protected]>
---
arch/riscv/boot/dts/starfive/jh7110.dtsi | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
index fa27fd4169a8..cdfd036a0e6c 100644
--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
@@ -452,12 +452,16 @@ syscrg: clock-controller@13020000 {
<&gmac1_rgmii_rxin>,
<&i2stx_bclk_ext>, <&i2stx_lrck_ext>,
<&i2srx_bclk_ext>, <&i2srx_lrck_ext>,
- <&tdm_ext>, <&mclk_ext>;
+ <&tdm_ext>, <&mclk_ext>,
+ <&pllclk JH7110_CLK_PLL0_OUT>,
+ <&pllclk JH7110_CLK_PLL1_OUT>,
+ <&pllclk JH7110_CLK_PLL2_OUT>;
clock-names = "osc", "gmac1_rmii_refin",
"gmac1_rgmii_rxin",
"i2stx_bclk_ext", "i2stx_lrck_ext",
"i2srx_bclk_ext", "i2srx_lrck_ext",
- "tdm_ext", "mclk_ext";
+ "tdm_ext", "mclk_ext",
+ "pll0_out", "pll1_out", "pll2_out";
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -465,6 +469,12 @@ syscrg: clock-controller@13020000 {
sys_syscon: syscon@13030000 {
compatible = "starfive,jh7110-sys-syscon", "syscon", "simple-mfd";
reg = <0x0 0x13030000 0x0 0x1000>;
+
+ pllclk: clock-controller {
+ compatible = "starfive,jh7110-pll";
+ clocks = <&osc>;
+ #clock-cells = <1>;
+ };
};

sysgpio: pinctrl@13040000 {
--
2.25.1


2023-05-12 02:24:44

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v4 3/7] dt-bindings: clock: jh7110-syscrg: Add PLL clock inputs

Add PLL clock inputs from PLL clock generator.

Acked-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Xingyu Wu <[email protected]>
---
.../clock/starfive,jh7110-syscrg.yaml | 20 +++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml b/Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
index 84373ae31644..fcb363353050 100644
--- a/Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
+++ b/Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
@@ -27,6 +27,9 @@ properties:
- description: External I2S RX left/right channel clock
- description: External TDM clock
- description: External audio master clock
+ - description: PLL0
+ - description: PLL1
+ - description: PLL2

- items:
- description: Main Oscillator (24 MHz)
@@ -38,6 +41,9 @@ properties:
- description: External I2S RX left/right channel clock
- description: External TDM clock
- description: External audio master clock
+ - description: PLL0
+ - description: PLL1
+ - description: PLL2

clock-names:
oneOf:
@@ -52,6 +58,9 @@ properties:
- const: i2srx_lrck_ext
- const: tdm_ext
- const: mclk_ext
+ - const: pll0_out
+ - const: pll1_out
+ - const: pll2_out

- items:
- const: osc
@@ -63,6 +72,9 @@ properties:
- const: i2srx_lrck_ext
- const: tdm_ext
- const: mclk_ext
+ - const: pll0_out
+ - const: pll1_out
+ - const: pll2_out

'#clock-cells':
const: 1
@@ -93,12 +105,16 @@ examples:
<&gmac1_rgmii_rxin>,
<&i2stx_bclk_ext>, <&i2stx_lrck_ext>,
<&i2srx_bclk_ext>, <&i2srx_lrck_ext>,
- <&tdm_ext>, <&mclk_ext>;
+ <&tdm_ext>, <&mclk_ext>,
+ <&pllclk 0>,
+ <&pllclk 1>,
+ <&pllclk 2>;
clock-names = "osc", "gmac1_rmii_refin",
"gmac1_rgmii_rxin",
"i2stx_bclk_ext", "i2stx_lrck_ext",
"i2srx_bclk_ext", "i2srx_lrck_ext",
- "tdm_ext", "mclk_ext";
+ "tdm_ext", "mclk_ext",
+ "pll0_out", "pll1_out", "pll2_out";
#clock-cells = <1>;
#reset-cells = <1>;
};
--
2.25.1


2023-05-12 02:24:50

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v4 6/7] riscv: dts: starfive: jh7110: Add syscon nodes

From: William Qiu <[email protected]>

Add stg_syscon/sys_syscon/aon_syscon nodes for JH7110 Soc.

Co-developed-by: Xingyu Wu <[email protected]>
Signed-off-by: Xingyu Wu <[email protected]>
Reviewed-by: Conor Dooley <[email protected]>
Reviewed-by: Emil Renner Berthing <[email protected]>
Signed-off-by: William Qiu <[email protected]>
---
arch/riscv/boot/dts/starfive/jh7110.dtsi | 16 ++++++++++++++++
1 file changed, 16 insertions(+)

diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
index 4c5fdb905da8..fa27fd4169a8 100644
--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
@@ -353,6 +353,11 @@ i2c2: i2c@10050000 {
status = "disabled";
};

+ stg_syscon: syscon@10240000 {
+ compatible = "starfive,jh7110-stg-syscon", "syscon";
+ reg = <0x0 0x10240000 0x0 0x1000>;
+ };
+
uart3: serial@12000000 {
compatible = "snps,dw-apb-uart";
reg = <0x0 0x12000000 0x0 0x10000>;
@@ -457,6 +462,11 @@ syscrg: clock-controller@13020000 {
#reset-cells = <1>;
};

+ sys_syscon: syscon@13030000 {
+ compatible = "starfive,jh7110-sys-syscon", "syscon", "simple-mfd";
+ reg = <0x0 0x13030000 0x0 0x1000>;
+ };
+
sysgpio: pinctrl@13040000 {
compatible = "starfive,jh7110-sys-pinctrl";
reg = <0x0 0x13040000 0x0 0x10000>;
@@ -486,6 +496,12 @@ aoncrg: clock-controller@17000000 {
#reset-cells = <1>;
};

+ aon_syscon: syscon@17010000 {
+ compatible = "starfive,jh7110-aon-syscon", "syscon";
+ reg = <0x0 0x17010000 0x0 0x1000>;
+ #power-domain-cells = <1>;
+ };
+
aongpio: pinctrl@17020000 {
compatible = "starfive,jh7110-aon-pinctrl";
reg = <0x0 0x17020000 0x0 0x10000>;
--
2.25.1


2023-05-12 02:24:53

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v4 2/7] clk: starfive: Add StarFive JH7110 PLL clock driver

Add driver for the StarFive JH7110 PLL clock controller
and they work by reading and setting syscon registers.

Signed-off-by: Xingyu Wu <[email protected]>
---
MAINTAINERS | 6 +
drivers/clk/starfive/Kconfig | 8 +
drivers/clk/starfive/Makefile | 1 +
.../clk/starfive/clk-starfive-jh7110-pll.c | 309 ++++++++++++++++
.../clk/starfive/clk-starfive-jh7110-pll.h | 331 ++++++++++++++++++
5 files changed, 655 insertions(+)
create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.c
create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 7e0b87d5aa2e..0fb4a703f66f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20087,6 +20087,12 @@ S: Supported
F: Documentation/devicetree/bindings/mmc/starfive*
F: drivers/mmc/host/dw_mmc-starfive.c

+STARFIVE JH7110 PLL CLOCK DRIVER
+M: Xingyu Wu <[email protected]>
+S: Supported
+F: Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml
+F: drivers/clk/starfive/clk-starfive-jh7110-pll.*
+
STARFIVE JH71X0 CLOCK DRIVERS
M: Emil Renner Berthing <[email protected]>
M: Hal Feng <[email protected]>
diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
index 5d2333106f13..5195f7be5213 100644
--- a/drivers/clk/starfive/Kconfig
+++ b/drivers/clk/starfive/Kconfig
@@ -21,6 +21,14 @@ config CLK_STARFIVE_JH7100_AUDIO
Say Y or M here to support the audio clocks on the StarFive JH7100
SoC.

+config CLK_STARFIVE_JH7110_PLL
+ bool "StarFive JH7110 PLL clock support"
+ depends on ARCH_STARFIVE || COMPILE_TEST
+ default ARCH_STARFIVE
+ help
+ Say yes here to support the PLL clock controller on the
+ StarFive JH7110 SoC.
+
config CLK_STARFIVE_JH7110_SYS
bool "StarFive JH7110 system clock support"
depends on ARCH_STARFIVE || COMPILE_TEST
diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
index f3df7d957b1e..b48e539e52b0 100644
--- a/drivers/clk/starfive/Makefile
+++ b/drivers/clk/starfive/Makefile
@@ -4,5 +4,6 @@ obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk-starfive-jh71x0.o
obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o
obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o

+obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += clk-starfive-jh7110-pll.o
obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
diff --git a/drivers/clk/starfive/clk-starfive-jh7110-pll.c b/drivers/clk/starfive/clk-starfive-jh7110-pll.c
new file mode 100644
index 000000000000..f86deddd4bef
--- /dev/null
+++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * StarFive JH7110 PLL Clock Generator Driver
+ *
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ *
+ * This driver is about to register JH7110 PLL clock generator and support ops.
+ * The JH7110 have three PLL clock, PLL0, PLL1 and PLL2.
+ * Each PLL clocks work in integer mode or fraction mode by some dividers,
+ * and the configuration registers and dividers are set in several syscon registers.
+ * The formula for calculating frequency is:
+ * Fvco = Fref * (NI + NF) / M / Q1
+ * Fref: OSC source clock rate
+ * NI: integer frequency dividing ratio of feedback divider, set by fbdiv[11:0].
+ * NF: fractional frequency dividing ratio, set by frac[23:0]. NF = frac[23:0] / 2^24 = 0 ~ 0.999.
+ * M: frequency dividing ratio of pre-divider, set by prediv[5:0].
+ * Q1: frequency dividing ratio of post divider, set by postdiv1[1:0], Q1= 1,2,4,8.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/starfive,jh7110-crg.h>
+
+#include "clk-starfive-jh7110-pll.h"
+
+struct jh7110_pll_conf_variant {
+ unsigned int pll_nums;
+ struct jh7110_pll_syscon_conf conf[];
+};
+
+static const struct jh7110_pll_conf_variant jh7110_pll_variant = {
+ .pll_nums = JH7110_PLLCLK_END,
+ .conf = {
+ JH7110_PLL(JH7110_CLK_PLL0_OUT, "pll0_out",
+ JH7110_PLL0_FREQ_MAX, jh7110_pll0_syscon_val_preset),
+ JH7110_PLL(JH7110_CLK_PLL1_OUT, "pll1_out",
+ JH7110_PLL1_FREQ_MAX, jh7110_pll1_syscon_val_preset),
+ JH7110_PLL(JH7110_CLK_PLL2_OUT, "pll2_out",
+ JH7110_PLL2_FREQ_MAX, jh7110_pll2_syscon_val_preset),
+ },
+};
+
+static struct jh7110_clk_pll_data *jh7110_pll_data_from(struct clk_hw *hw)
+{
+ return container_of(hw, struct jh7110_clk_pll_data, hw);
+}
+
+static struct jh7110_clk_pll_priv *jh7110_pll_priv_from(struct jh7110_clk_pll_data *data)
+{
+ return container_of(data, struct jh7110_clk_pll_priv, data[data->idx]);
+}
+
+/* Read register value from syscon and calculate PLL(x) frequency */
+static unsigned long jh7110_pll_get_freq(struct jh7110_clk_pll_data *data,
+ unsigned long parent_rate)
+{
+ struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
+ struct jh7110_pll_syscon_offset *offset = &data->conf.offsets;
+ struct jh7110_pll_syscon_mask *mask = &data->conf.masks;
+ struct jh7110_pll_syscon_shift *shift = &data->conf.shifts;
+ unsigned long frac_cal;
+ u32 dacpd;
+ u32 dsmpd;
+ u32 fbdiv;
+ u32 prediv;
+ u32 postdiv1;
+ u32 frac;
+ u32 reg_val;
+
+ regmap_read(priv->syscon_regmap, offset->dacpd, &reg_val);
+ dacpd = (reg_val & mask->dacpd) >> shift->dacpd;
+
+ regmap_read(priv->syscon_regmap, offset->dsmpd, &reg_val);
+ dsmpd = (reg_val & mask->dsmpd) >> shift->dsmpd;
+
+ regmap_read(priv->syscon_regmap, offset->fbdiv, &reg_val);
+ fbdiv = (reg_val & mask->fbdiv) >> shift->fbdiv;
+
+ regmap_read(priv->syscon_regmap, offset->prediv, &reg_val);
+ prediv = (reg_val & mask->prediv) >> shift->prediv;
+
+ regmap_read(priv->syscon_regmap, offset->postdiv1, &reg_val);
+ /* postdiv1 = 2 ^ reg_val */
+ postdiv1 = 1 << ((reg_val & mask->postdiv1) >> shift->postdiv1);
+
+ regmap_read(priv->syscon_regmap, offset->frac, &reg_val);
+ frac = (reg_val & mask->frac) >> shift->frac;
+
+ /*
+ * Integer Mode (Both 1) or Fraction Mode (Both 0).
+ * And the decimal places are counted by expanding them by
+ * a factor of STARFIVE_PLL_FRAC_PATR_SIZE.
+ */
+ if (dacpd == 1 && dsmpd == 1)
+ frac_cal = 0;
+ else if (dacpd == 0 && dsmpd == 0)
+ frac_cal = (unsigned long)frac * STARFIVE_PLL_FRAC_PATR_SIZE / (1 << 24);
+ else
+ return 0;
+
+ /* Fvco = Fref * (NI + NF) / M / Q1 */
+ return (parent_rate / STARFIVE_PLL_FRAC_PATR_SIZE *
+ (fbdiv * STARFIVE_PLL_FRAC_PATR_SIZE + frac_cal) / prediv / postdiv1);
+}
+
+static unsigned long jh7110_pll_rate_sub_fabs(unsigned long rate1, unsigned long rate2)
+{
+ return rate1 > rate2 ? (rate1 - rate2) : (rate2 - rate1);
+}
+
+/* Select the appropriate frequency from the already configured registers value */
+static void jh7110_pll_select_near_freq_id(struct jh7110_clk_pll_data *data,
+ unsigned long rate)
+{
+ const struct jh7110_pll_syscon_val *val;
+ unsigned int id;
+ unsigned long rate_diff;
+
+ /* compare the frequency one by one from small to large in order */
+ for (id = 0; id < data->conf.preset_val_nums; id++) {
+ val = &data->conf.preset_val[id];
+
+ if (rate == val->freq)
+ goto match_end;
+
+ /* select near frequency */
+ if (rate < val->freq) {
+ /* The last frequency is closer to the target rate than this time. */
+ if (id > 0)
+ if (rate_diff < jh7110_pll_rate_sub_fabs(rate, val->freq))
+ id--;
+
+ goto match_end;
+ } else {
+ rate_diff = jh7110_pll_rate_sub_fabs(rate, val->freq);
+ }
+ }
+
+match_end:
+ data->freq_select_idx = id;
+}
+
+static int jh7110_pll_set_freq_syscon(struct jh7110_clk_pll_data *data)
+{
+ struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
+ struct jh7110_pll_syscon_offset *offset = &data->conf.offsets;
+ struct jh7110_pll_syscon_mask *mask = &data->conf.masks;
+ struct jh7110_pll_syscon_shift *shift = &data->conf.shifts;
+ const struct jh7110_pll_syscon_val *val = &data->conf.preset_val[data->freq_select_idx];
+
+ /* frac: Integer Mode (Both 1) or Fraction Mode (Both 0) */
+ if (val->dacpd == 0 && val->dsmpd == 0)
+ regmap_update_bits(priv->syscon_regmap, offset->frac, mask->frac,
+ (val->frac << shift->frac));
+ else if (val->dacpd != val->dsmpd)
+ return -EINVAL;
+
+ /* fbdiv value should be 8 to 4095 */
+ if (val->fbdiv < 8)
+ return -EINVAL;
+
+ regmap_update_bits(priv->syscon_regmap, offset->dacpd, mask->dacpd,
+ (val->dacpd << shift->dacpd));
+ regmap_update_bits(priv->syscon_regmap, offset->dsmpd, mask->dsmpd,
+ (val->dsmpd << shift->dsmpd));
+ regmap_update_bits(priv->syscon_regmap, offset->prediv, mask->prediv,
+ (val->prediv << shift->prediv));
+ regmap_update_bits(priv->syscon_regmap, offset->fbdiv, mask->fbdiv,
+ (val->fbdiv << shift->fbdiv));
+ regmap_update_bits(priv->syscon_regmap, offset->postdiv1, mask->postdiv1,
+ ((val->postdiv1 >> 1) << shift->postdiv1));
+
+ return 0;
+}
+
+static unsigned long jh7110_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
+
+ return jh7110_pll_get_freq(data, parent_rate);
+}
+
+static int jh7110_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
+
+ jh7110_pll_select_near_freq_id(data, req->rate);
+ req->rate = data->conf.preset_val[data->freq_select_idx].freq;
+
+ return 0;
+}
+
+static int jh7110_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
+
+ return jh7110_pll_set_freq_syscon(data);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void jh7110_pll_debug_init(struct clk_hw *hw, struct dentry *dentry)
+{
+ static const struct debugfs_reg32 jh7110_clk_pll_reg = {
+ .name = "CTRL",
+ .offset = 0,
+ };
+ struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
+ struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
+ struct debugfs_regset32 *regset;
+
+ regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL);
+ if (!regset)
+ return;
+
+ regset->regs = &jh7110_clk_pll_reg;
+ regset->nregs = 1;
+
+ debugfs_create_regset32("registers", 0400, dentry, regset);
+}
+#else
+#define jh7110_pll_debug_init NULL
+#endif
+
+static const struct clk_ops jh7110_pll_ops = {
+ .recalc_rate = jh7110_pll_recalc_rate,
+ .determine_rate = jh7110_pll_determine_rate,
+ .set_rate = jh7110_pll_set_rate,
+ .debug_init = jh7110_pll_debug_init,
+};
+
+static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data)
+{
+ struct jh7110_clk_pll_priv *priv = data;
+ unsigned int idx = clkspec->args[0];
+
+ if (idx < priv->pll_nums)
+ return &priv->data[idx].hw;
+
+ return ERR_PTR(-EINVAL);
+}
+
+static int jh7110_pll_probe(struct platform_device *pdev)
+{
+ const struct jh7110_pll_conf_variant *variant;
+ struct jh7110_clk_pll_priv *priv;
+ struct jh7110_clk_pll_data *data;
+ int ret;
+ unsigned int idx;
+
+ variant = of_device_get_match_data(&pdev->dev);
+ if (!variant)
+ return -ENOMEM;
+
+ priv = devm_kzalloc(&pdev->dev, struct_size(priv, data, variant->pll_nums),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+ priv->syscon_regmap = syscon_node_to_regmap(priv->dev->of_node->parent);
+ if (IS_ERR(priv->syscon_regmap))
+ return PTR_ERR(priv->syscon_regmap);
+
+ priv->pll_nums = variant->pll_nums;
+ for (idx = 0; idx < priv->pll_nums; idx++) {
+ struct clk_parent_data parents = {
+ .index = 0,
+ };
+ struct clk_init_data init = {
+ .name = variant->conf[idx].name,
+ .ops = &jh7110_pll_ops,
+ .parent_data = &parents,
+ .num_parents = 1,
+ .flags = 0,
+ };
+
+ data = &priv->data[idx];
+ data->conf = variant->conf[idx];
+ data->hw.init = &init;
+ data->idx = idx;
+
+ ret = devm_clk_hw_register(&pdev->dev, &data->hw);
+ if (ret)
+ return ret;
+ }
+
+ return devm_of_clk_add_hw_provider(&pdev->dev, jh7110_pll_get, priv);
+}
+
+static const struct of_device_id jh7110_pll_match[] = {
+ { .compatible = "starfive,jh7110-pll", .data = &jh7110_pll_variant },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jh7110_pll_match);
+
+static struct platform_driver jh7110_pll_driver = {
+ .driver = {
+ .name = "clk-starfive-jh7110-pll",
+ .of_match_table = jh7110_pll_match,
+ },
+};
+builtin_platform_driver_probe(jh7110_pll_driver, jh7110_pll_probe);
diff --git a/drivers/clk/starfive/clk-starfive-jh7110-pll.h b/drivers/clk/starfive/clk-starfive-jh7110-pll.h
new file mode 100644
index 000000000000..526f21670fe3
--- /dev/null
+++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.h
@@ -0,0 +1,331 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * StarFive JH7110 PLL Clock Generator Driver
+ *
+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
+ */
+
+#ifndef _CLK_STARFIVE_JH7110_PLL_H_
+#define _CLK_STARFIVE_JH7110_PLL_H_
+
+#include <linux/bits.h>
+
+/* The decimal places are counted by expanding them by a factor of STARFIVE_PLL_FRAC_PATR_SIZE */
+#define STARFIVE_PLL_FRAC_PATR_SIZE 1000
+
+#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_OFFSET 0x18
+#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_SHIFT 24
+#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_MASK BIT(24)
+#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_OFFSET 0x18
+#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_SHIFT 25
+#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_MASK BIT(25)
+#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_OFFSET 0x1c
+#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_SHIFT 0
+#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_MASK GENMASK(11, 0)
+#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_OFFSET 0x20
+#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_SHIFT 0
+#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_MASK GENMASK(23, 0)
+#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_OFFSET 0x20
+#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_SHIFT 28
+#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_MASK GENMASK(29, 28)
+#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_OFFSET 0x24
+#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_SHIFT 0
+#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_MASK GENMASK(5, 0)
+
+#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_OFFSET 0x24
+#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_SHIFT 15
+#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_MASK BIT(15)
+#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_OFFSET 0x24
+#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_SHIFT 16
+#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_MASK BIT(16)
+#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_OFFSET 0x24
+#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_SHIFT 17
+#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_MASK GENMASK(28, 17)
+#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_OFFSET 0x28
+#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_SHIFT 0
+#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_MASK GENMASK(23, 0)
+#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_OFFSET 0x28
+#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_SHIFT 28
+#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_MASK GENMASK(29, 28)
+#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_OFFSET 0x2c
+#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_SHIFT 0
+#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_MASK GENMASK(5, 0)
+
+#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_OFFSET 0x2c
+#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_SHIFT 15
+#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_MASK BIT(15)
+#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_OFFSET 0x2c
+#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_SHIFT 16
+#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_MASK BIT(16)
+#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_OFFSET 0x2c
+#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_SHIFT 17
+#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_MASK GENMASK(28, 17)
+#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_OFFSET 0x30
+#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_SHIFT 0
+#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_MASK GENMASK(23, 0)
+#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_OFFSET 0x30
+#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_SHIFT 28
+#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_MASK GENMASK(29, 28)
+#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_OFFSET 0x34
+#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_SHIFT 0
+#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_MASK GENMASK(5, 0)
+
+#define JH7110_PLL(_idx, _name, _nums, _val) \
+[_idx] = { \
+ .name = _name, \
+ .offsets = { \
+ .dacpd = STARFIVE_##_idx##_DACPD_OFFSET, \
+ .dsmpd = STARFIVE_##_idx##_DSMPD_OFFSET, \
+ .fbdiv = STARFIVE_##_idx##_FBDIV_OFFSET, \
+ .frac = STARFIVE_##_idx##_FRAC_OFFSET, \
+ .prediv = STARFIVE_##_idx##_PREDIV_OFFSET, \
+ .postdiv1 = STARFIVE_##_idx##_POSTDIV1_OFFSET, \
+ }, \
+ .masks = { \
+ .dacpd = STARFIVE_##_idx##_DACPD_MASK, \
+ .dsmpd = STARFIVE_##_idx##_DSMPD_MASK, \
+ .fbdiv = STARFIVE_##_idx##_FBDIV_MASK, \
+ .frac = STARFIVE_##_idx##_FRAC_MASK, \
+ .prediv = STARFIVE_##_idx##_PREDIV_MASK, \
+ .postdiv1 = STARFIVE_##_idx##_POSTDIV1_MASK, \
+ }, \
+ .shifts = { \
+ .dacpd = STARFIVE_##_idx##_DACPD_SHIFT, \
+ .dsmpd = STARFIVE_##_idx##_DSMPD_SHIFT, \
+ .fbdiv = STARFIVE_##_idx##_FBDIV_SHIFT, \
+ .frac = STARFIVE_##_idx##_FRAC_SHIFT, \
+ .prediv = STARFIVE_##_idx##_PREDIV_SHIFT, \
+ .postdiv1 = STARFIVE_##_idx##_POSTDIV1_SHIFT, \
+ }, \
+ .preset_val_nums = _nums, \
+ .preset_val = _val, \
+}
+
+struct jh7110_pll_syscon_offset {
+ unsigned int dacpd;
+ unsigned int dsmpd;
+ unsigned int fbdiv;
+ unsigned int frac;
+ unsigned int prediv;
+ unsigned int postdiv1;
+};
+
+struct jh7110_pll_syscon_mask {
+ u32 dacpd;
+ u32 dsmpd;
+ u32 fbdiv;
+ u32 frac;
+ u32 prediv;
+ u32 postdiv1;
+};
+
+struct jh7110_pll_syscon_shift {
+ char dacpd;
+ char dsmpd;
+ char fbdiv;
+ char frac;
+ char prediv;
+ char postdiv1;
+};
+
+struct jh7110_pll_syscon_val {
+ unsigned long freq;
+ u32 prediv;
+ u32 fbdiv;
+ u32 postdiv1;
+/* Both daxpd and dsmpd set 1 while integer mode */
+/* Both daxpd and dsmpd set 0 while fraction mode */
+ u32 dacpd;
+ u32 dsmpd;
+/* frac value should be decimals multiplied by 2^24 */
+ u32 frac;
+};
+
+struct jh7110_pll_syscon_conf {
+ char *name;
+ struct jh7110_pll_syscon_offset offsets;
+ struct jh7110_pll_syscon_mask masks;
+ struct jh7110_pll_syscon_shift shifts;
+ unsigned int preset_val_nums;
+ const struct jh7110_pll_syscon_val *preset_val;
+};
+
+struct jh7110_clk_pll_data {
+ struct clk_hw hw;
+ unsigned int idx;
+ unsigned int freq_select_idx;
+ struct jh7110_pll_syscon_conf conf;
+};
+
+struct jh7110_clk_pll_priv {
+ unsigned int pll_nums;
+ struct device *dev;
+ struct regmap *syscon_regmap;
+ struct jh7110_clk_pll_data data[];
+};
+
+enum jh7110_pll0_freq_index {
+ JH7110_PLL0_FREQ_375 = 0,
+ JH7110_PLL0_FREQ_500,
+ JH7110_PLL0_FREQ_625,
+ JH7110_PLL0_FREQ_750,
+ JH7110_PLL0_FREQ_875,
+ JH7110_PLL0_FREQ_1000,
+ JH7110_PLL0_FREQ_1250,
+ JH7110_PLL0_FREQ_1375,
+ JH7110_PLL0_FREQ_1500,
+ JH7110_PLL0_FREQ_MAX
+};
+
+enum jh7110_pll1_freq_index {
+ JH7110_PLL1_FREQ_1066 = 0,
+ JH7110_PLL1_FREQ_1200,
+ JH7110_PLL1_FREQ_1400,
+ JH7110_PLL1_FREQ_1600,
+ JH7110_PLL1_FREQ_MAX
+};
+
+enum jh7110_pll2_freq_index {
+ JH7110_PLL2_FREQ_1188 = 0,
+ JH7110_PLL2_FREQ_12288,
+ JH7110_PLL2_FREQ_MAX
+};
+
+/*
+ * Because the pll frequency is relatively fixed,
+ * it cannot be set arbitrarily, so it needs a specific configuration.
+ * PLL0 frequency should be multiple of 125MHz (USB frequency).
+ */
+static const struct jh7110_pll_syscon_val
+ jh7110_pll0_syscon_val_preset[] = {
+ [JH7110_PLL0_FREQ_375] = {
+ .freq = 375000000,
+ .prediv = 8,
+ .fbdiv = 125,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL0_FREQ_500] = {
+ .freq = 500000000,
+ .prediv = 6,
+ .fbdiv = 125,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL0_FREQ_625] = {
+ .freq = 625000000,
+ .prediv = 24,
+ .fbdiv = 625,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL0_FREQ_750] = {
+ .freq = 750000000,
+ .prediv = 4,
+ .fbdiv = 125,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL0_FREQ_875] = {
+ .freq = 875000000,
+ .prediv = 24,
+ .fbdiv = 875,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL0_FREQ_1000] = {
+ .freq = 1000000000,
+ .prediv = 3,
+ .fbdiv = 125,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL0_FREQ_1250] = {
+ .freq = 1250000000,
+ .prediv = 12,
+ .fbdiv = 625,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL0_FREQ_1375] = {
+ .freq = 1375000000,
+ .prediv = 24,
+ .fbdiv = 1375,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL0_FREQ_1500] = {
+ .freq = 1500000000,
+ .prediv = 2,
+ .fbdiv = 125,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+};
+
+static const struct jh7110_pll_syscon_val
+ jh7110_pll1_syscon_val_preset[] = {
+ [JH7110_PLL1_FREQ_1066] = {
+ .freq = 1066000000,
+ .prediv = 12,
+ .fbdiv = 533,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL1_FREQ_1200] = {
+ .freq = 1200000000,
+ .prediv = 1,
+ .fbdiv = 50,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL1_FREQ_1400] = {
+ .freq = 1400000000,
+ .prediv = 6,
+ .fbdiv = 350,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL1_FREQ_1600] = {
+ .freq = 1600000000,
+ .prediv = 3,
+ .fbdiv = 200,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+};
+
+static const struct jh7110_pll_syscon_val
+ jh7110_pll2_syscon_val_preset[] = {
+ [JH7110_PLL2_FREQ_1188] = {
+ .freq = 1188000000,
+ .prediv = 2,
+ .fbdiv = 99,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+ [JH7110_PLL2_FREQ_12288] = {
+ .freq = 1228800000,
+ .prediv = 5,
+ .fbdiv = 256,
+ .postdiv1 = 1,
+ .dacpd = 1,
+ .dsmpd = 1,
+ },
+};
+
+#endif
--
2.25.1


2023-05-12 06:41:03

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v4 7/7] riscv: dts: starfive: jh7110: Add PLL clock node and modify syscrg node

On 12/05/2023 04:20, Xingyu Wu wrote:
> Add the PLL clock node for the Starfive JH7110 SoC and
> modify the SYSCRG node to add PLL clocks input.


> @@ -465,6 +469,12 @@ syscrg: clock-controller@13020000 {
> sys_syscon: syscon@13030000 {
> compatible = "starfive,jh7110-sys-syscon", "syscon", "simple-mfd";
> reg = <0x0 0x13030000 0x0 0x1000>;
> +
> + pllclk: clock-controller {
> + compatible = "starfive,jh7110-pll";
> + clocks = <&osc>;
> + #clock-cells = <1>;

This should be part of previous patch. You just added that node. Don't
add half of devices but entire device.

Best regards,
Krzysztof


2023-05-12 06:41:30

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v4 6/7] riscv: dts: starfive: jh7110: Add syscon nodes

On 12/05/2023 04:20, Xingyu Wu wrote:
> From: William Qiu <[email protected]>
>
> Add stg_syscon/sys_syscon/aon_syscon nodes for JH7110 Soc.
>
> Co-developed-by: Xingyu Wu <[email protected]>
> Signed-off-by: Xingyu Wu <[email protected]>
> Reviewed-by: Conor Dooley <[email protected]>
> Reviewed-by: Emil Renner Berthing <[email protected]>
> Signed-off-by: William Qiu <[email protected]>
> ---
> arch/riscv/boot/dts/starfive/jh7110.dtsi | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
> index 4c5fdb905da8..fa27fd4169a8 100644
> --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
> +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
> @@ -353,6 +353,11 @@ i2c2: i2c@10050000 {
> status = "disabled";
> };
>
> + stg_syscon: syscon@10240000 {
> + compatible = "starfive,jh7110-stg-syscon", "syscon";
> + reg = <0x0 0x10240000 0x0 0x1000>;
> + };
> +
> uart3: serial@12000000 {
> compatible = "snps,dw-apb-uart";
> reg = <0x0 0x12000000 0x0 0x10000>;
> @@ -457,6 +462,11 @@ syscrg: clock-controller@13020000 {
> #reset-cells = <1>;
> };
>
> + sys_syscon: syscon@13030000 {
> + compatible = "starfive,jh7110-sys-syscon", "syscon", "simple-mfd";
> + reg = <0x0 0x13030000 0x0 0x1000>;

No children, drop the simple-mfd. Or your binding is incorrect or your
DTS is incomplete (you mentioned clock-controller). DTS should be complete.

Best regards,
Krzysztof


2023-05-12 06:56:28

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 3/7] dt-bindings: clock: jh7110-syscrg: Add PLL clock inputs

On Fri, May 12, 2023 at 10:20:32AM +0800, Xingyu Wu wrote:
> Add PLL clock inputs from PLL clock generator.
>
> Acked-by: Krzysztof Kozlowski <[email protected]>
> Signed-off-by: Xingyu Wu <[email protected]>
> ---
> .../clock/starfive,jh7110-syscrg.yaml | 20 +++++++++++++++++--
> 1 file changed, 18 insertions(+), 2 deletions(-)

/tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
[[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
/tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
'i2stx_bclk_ext' was expected
'i2stx_lrck_ext' was expected
'i2srx_bclk_ext' was expected
'i2srx_lrck_ext' was expected
'tdm_ext' was expected
'mclk_ext' was expected
'pll0_out' was expected
From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
/tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
[[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
From schema: Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
/tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
'i2stx_bclk_ext' was expected
'i2stx_lrck_ext' was expected
'i2srx_bclk_ext' was expected
'i2srx_lrck_ext' was expected
'tdm_ext' was expected
'mclk_ext' was expected
'pll0_out' was expected
Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml

This binding change is incompatible with the existing devicetrees for
the visionfive 2.


Attachments:
(No filename) (2.30 kB)
signature.asc (235.00 B)
Download all attachments

2023-05-12 07:22:55

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 7/7] riscv: dts: starfive: jh7110: Add PLL clock node and modify syscrg node

On 2023/5/12 14:37, Krzysztof Kozlowski wrote:
> On 12/05/2023 04:20, Xingyu Wu wrote:
>> Add the PLL clock node for the Starfive JH7110 SoC and
>> modify the SYSCRG node to add PLL clocks input.
>
>
>> @@ -465,6 +469,12 @@ syscrg: clock-controller@13020000 {
>> sys_syscon: syscon@13030000 {
>> compatible = "starfive,jh7110-sys-syscon", "syscon", "simple-mfd";
>> reg = <0x0 0x13030000 0x0 0x1000>;
>> +
>> + pllclk: clock-controller {
>> + compatible = "starfive,jh7110-pll";
>> + clocks = <&osc>;
>> + #clock-cells = <1>;
>
> This should be part of previous patch. You just added that node. Don't
> add half of devices but entire device.
>

So do I merge the patch 6 and patch 7 into one patch and add syscon and
clock-controller together?

Best regards,
Xingyu Wu

2023-05-12 07:30:24

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v4 7/7] riscv: dts: starfive: jh7110: Add PLL clock node and modify syscrg node

On 12/05/2023 09:15, Xingyu Wu wrote:
> On 2023/5/12 14:37, Krzysztof Kozlowski wrote:
>> On 12/05/2023 04:20, Xingyu Wu wrote:
>>> Add the PLL clock node for the Starfive JH7110 SoC and
>>> modify the SYSCRG node to add PLL clocks input.
>>
>>
>>> @@ -465,6 +469,12 @@ syscrg: clock-controller@13020000 {
>>> sys_syscon: syscon@13030000 {
>>> compatible = "starfive,jh7110-sys-syscon", "syscon", "simple-mfd";
>>> reg = <0x0 0x13030000 0x0 0x1000>;
>>> +
>>> + pllclk: clock-controller {
>>> + compatible = "starfive,jh7110-pll";
>>> + clocks = <&osc>;
>>> + #clock-cells = <1>;
>>
>> This should be part of previous patch. You just added that node. Don't
>> add half of devices but entire device.
>>
>
> So do I merge the patch 6 and patch 7 into one patch and add syscon and
> clock-controller together?

I am okay with adding users of clocks in separate patch, but the clock
controller - so part of SYS - should be added when adding SYS.

Best regards,
Krzysztof


2023-05-12 07:54:17

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 7/7] riscv: dts: starfive: jh7110: Add PLL clock node and modify syscrg node

On 2023/5/12 15:22, Krzysztof Kozlowski wrote:
> On 12/05/2023 09:15, Xingyu Wu wrote:
>> On 2023/5/12 14:37, Krzysztof Kozlowski wrote:
>>> On 12/05/2023 04:20, Xingyu Wu wrote:
>>>> Add the PLL clock node for the Starfive JH7110 SoC and
>>>> modify the SYSCRG node to add PLL clocks input.
>>>
>>>
>>>> @@ -465,6 +469,12 @@ syscrg: clock-controller@13020000 {
>>>> sys_syscon: syscon@13030000 {
>>>> compatible = "starfive,jh7110-sys-syscon", "syscon", "simple-mfd";
>>>> reg = <0x0 0x13030000 0x0 0x1000>;
>>>> +
>>>> + pllclk: clock-controller {
>>>> + compatible = "starfive,jh7110-pll";
>>>> + clocks = <&osc>;
>>>> + #clock-cells = <1>;
>>>
>>> This should be part of previous patch. You just added that node. Don't
>>> add half of devices but entire device.
>>>
>>
>> So do I merge the patch 6 and patch 7 into one patch and add syscon and
>> clock-controller together?
>
> I am okay with adding users of clocks in separate patch, but the clock
> controller - so part of SYS - should be added when adding SYS.
>

Got it. Thanks.

Best regards,
Xingyu Wu


2023-05-12 08:20:19

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 3/7] dt-bindings: clock: jh7110-syscrg: Add PLL clock inputs

On 2023/5/12 14:47, Conor Dooley wrote:
> On Fri, May 12, 2023 at 10:20:32AM +0800, Xingyu Wu wrote:
>> Add PLL clock inputs from PLL clock generator.
>>
>> Acked-by: Krzysztof Kozlowski <[email protected]>
>> Signed-off-by: Xingyu Wu <[email protected]>
>> ---
>> .../clock/starfive,jh7110-syscrg.yaml | 20 +++++++++++++++++--
>> 1 file changed, 18 insertions(+), 2 deletions(-)
>
> /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
> [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
> From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
> ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
> 'i2stx_bclk_ext' was expected
> 'i2stx_lrck_ext' was expected
> 'i2srx_bclk_ext' was expected
> 'i2srx_lrck_ext' was expected
> 'tdm_ext' was expected
> 'mclk_ext' was expected
> 'pll0_out' was expected
> From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
> [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
> From schema: Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
> ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
> 'i2stx_bclk_ext' was expected
> 'i2stx_lrck_ext' was expected
> 'i2srx_bclk_ext' was expected
> 'i2srx_lrck_ext' was expected
> 'tdm_ext' was expected
> 'mclk_ext' was expected
> 'pll0_out' was expected
> Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>
> This binding change is incompatible with the existing devicetrees for
> the visionfive 2.

This looks like less clocks about PLL in SYSCRG node. And I add this in patch 7.

Best regards,
Xingyu Wu

2023-05-12 09:42:46

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 3/7] dt-bindings: clock: jh7110-syscrg: Add PLL clock inputs

On Fri, May 12, 2023 at 04:07:47PM +0800, Xingyu Wu wrote:
> On 2023/5/12 14:47, Conor Dooley wrote:
> > On Fri, May 12, 2023 at 10:20:32AM +0800, Xingyu Wu wrote:
> >> Add PLL clock inputs from PLL clock generator.
> >>
> >> Acked-by: Krzysztof Kozlowski <[email protected]>
> >> Signed-off-by: Xingyu Wu <[email protected]>
> >> ---
> >> .../clock/starfive,jh7110-syscrg.yaml | 20 +++++++++++++++++--
> >> 1 file changed, 18 insertions(+), 2 deletions(-)
> >
> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
> > 'i2stx_bclk_ext' was expected
> > 'i2stx_lrck_ext' was expected
> > 'i2srx_bclk_ext' was expected
> > 'i2srx_lrck_ext' was expected
> > 'tdm_ext' was expected
> > 'mclk_ext' was expected
> > 'pll0_out' was expected
> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
> > From schema: Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
> > 'i2stx_bclk_ext' was expected
> > 'i2stx_lrck_ext' was expected
> > 'i2srx_bclk_ext' was expected
> > 'i2srx_lrck_ext' was expected
> > 'tdm_ext' was expected
> > 'mclk_ext' was expected
> > 'pll0_out' was expected
> > Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> >
> > This binding change is incompatible with the existing devicetrees for
> > the visionfive 2.
>
> This looks like less clocks about PLL in SYSCRG node. And I add this in patch 7.

The existing devicetree is a valid, albeit limited, description of the
hardware.
After your changes to the clock driver in this series, but *without* the
changes to the devicetrees, does the system still function?
From a quick check of 4/7, it looks like it will not?


Attachments:
(No filename) (2.89 kB)
signature.asc (235.00 B)
Download all attachments

2023-05-12 10:00:34

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 3/7] dt-bindings: clock: jh7110-syscrg: Add PLL clock inputs

On 2023/5/12 17:35, Conor Dooley wrote:
> On Fri, May 12, 2023 at 04:07:47PM +0800, Xingyu Wu wrote:
>> On 2023/5/12 14:47, Conor Dooley wrote:
>> > On Fri, May 12, 2023 at 10:20:32AM +0800, Xingyu Wu wrote:
>> >> Add PLL clock inputs from PLL clock generator.
>> >>
>> >> Acked-by: Krzysztof Kozlowski <[email protected]>
>> >> Signed-off-by: Xingyu Wu <[email protected]>
>> >> ---
>> >> .../clock/starfive,jh7110-syscrg.yaml | 20 +++++++++++++++++--
>> >> 1 file changed, 18 insertions(+), 2 deletions(-)
>> >
>> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
>> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
>> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
>> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
>> > 'i2stx_bclk_ext' was expected
>> > 'i2stx_lrck_ext' was expected
>> > 'i2srx_bclk_ext' was expected
>> > 'i2srx_lrck_ext' was expected
>> > 'tdm_ext' was expected
>> > 'mclk_ext' was expected
>> > 'pll0_out' was expected
>> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
>> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
>> > From schema: Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
>> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
>> > 'i2stx_bclk_ext' was expected
>> > 'i2stx_lrck_ext' was expected
>> > 'i2srx_bclk_ext' was expected
>> > 'i2srx_lrck_ext' was expected
>> > 'tdm_ext' was expected
>> > 'mclk_ext' was expected
>> > 'pll0_out' was expected
>> > Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> >
>> > This binding change is incompatible with the existing devicetrees for
>> > the visionfive 2.
>>
>> This looks like less clocks about PLL in SYSCRG node. And I add this in patch 7.
>
> The existing devicetree is a valid, albeit limited, description of the
> hardware.
> After your changes to the clock driver in this series, but *without* the
> changes to the devicetrees, does the system still function?
> From a quick check of 4/7, it looks like it will not?

I just tested it on the board and the system still worked without the changes
about devicetree. But these clocks' rate were 0 because these could not get
the PLL clocks from devicetree.

Best regards,
Xingyu Wu

2023-05-12 14:15:53

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 3/7] dt-bindings: clock: jh7110-syscrg: Add PLL clock inputs

On Fri, May 12, 2023 at 05:56:16PM +0800, Xingyu Wu wrote:
> On 2023/5/12 17:35, Conor Dooley wrote:
> > On Fri, May 12, 2023 at 04:07:47PM +0800, Xingyu Wu wrote:
> >> On 2023/5/12 14:47, Conor Dooley wrote:
> >> > On Fri, May 12, 2023 at 10:20:32AM +0800, Xingyu Wu wrote:
> >> >> Add PLL clock inputs from PLL clock generator.
> >> >>
> >> >> Acked-by: Krzysztof Kozlowski <[email protected]>
> >> >> Signed-off-by: Xingyu Wu <[email protected]>
> >> >> ---
> >> >> .../clock/starfive,jh7110-syscrg.yaml | 20 +++++++++++++++++--
> >> >> 1 file changed, 18 insertions(+), 2 deletions(-)
> >> >
> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
> >> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
> >> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
> >> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
> >> > 'i2stx_bclk_ext' was expected
> >> > 'i2stx_lrck_ext' was expected
> >> > 'i2srx_bclk_ext' was expected
> >> > 'i2srx_lrck_ext' was expected
> >> > 'tdm_ext' was expected
> >> > 'mclk_ext' was expected
> >> > 'pll0_out' was expected
> >> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
> >> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
> >> > From schema: Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
> >> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
> >> > 'i2stx_bclk_ext' was expected
> >> > 'i2stx_lrck_ext' was expected
> >> > 'i2srx_bclk_ext' was expected
> >> > 'i2srx_lrck_ext' was expected
> >> > 'tdm_ext' was expected
> >> > 'mclk_ext' was expected
> >> > 'pll0_out' was expected
> >> > Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> >> >
> >> > This binding change is incompatible with the existing devicetrees for
> >> > the visionfive 2.
> >>
> >> This looks like less clocks about PLL in SYSCRG node. And I add this in patch 7.
> >
> > The existing devicetree is a valid, albeit limited, description of the
> > hardware.
> > After your changes to the clock driver in this series, but *without* the
> > changes to the devicetrees, does the system still function?
> > From a quick check of 4/7, it looks like it will not?
>
> I just tested it on the board and the system still worked without the changes
> about devicetree. But these clocks' rate were 0 because these could not get
> the PLL clocks from devicetree.

Hmm, that sounds like an issue to me. If all of the clock rates are
computed based off of parents that incorrectly report 0, are we not in
for trouble?
Should the fixed-factor clocks be retained as a fallback for the sake of
compatibility?
Emil, Stephen?


Attachments:
(No filename) (3.59 kB)
signature.asc (235.00 B)
Download all attachments

2023-05-19 08:05:54

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 3/7] dt-bindings: clock: jh7110-syscrg: Add PLL clock inputs

On 2023/5/12 21:49, Conor Dooley wrote:
> On Fri, May 12, 2023 at 05:56:16PM +0800, Xingyu Wu wrote:
>> On 2023/5/12 17:35, Conor Dooley wrote:
>> > On Fri, May 12, 2023 at 04:07:47PM +0800, Xingyu Wu wrote:
>> >> On 2023/5/12 14:47, Conor Dooley wrote:
>> >> > On Fri, May 12, 2023 at 10:20:32AM +0800, Xingyu Wu wrote:
>> >> >> Add PLL clock inputs from PLL clock generator.
>> >> >>
>> >> >> Acked-by: Krzysztof Kozlowski <[email protected]>
>> >> >> Signed-off-by: Xingyu Wu <[email protected]>
>> >> >> ---
>> >> >> .../clock/starfive,jh7110-syscrg.yaml | 20 +++++++++++++++++--
>> >> >> 1 file changed, 18 insertions(+), 2 deletions(-)
>> >> >
>> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
>> >> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
>> >> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
>> >> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
>> >> > 'i2stx_bclk_ext' was expected
>> >> > 'i2stx_lrck_ext' was expected
>> >> > 'i2srx_bclk_ext' was expected
>> >> > 'i2srx_lrck_ext' was expected
>> >> > 'tdm_ext' was expected
>> >> > 'mclk_ext' was expected
>> >> > 'pll0_out' was expected
>> >> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
>> >> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
>> >> > From schema: Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
>> >> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
>> >> > 'i2stx_bclk_ext' was expected
>> >> > 'i2stx_lrck_ext' was expected
>> >> > 'i2srx_bclk_ext' was expected
>> >> > 'i2srx_lrck_ext' was expected
>> >> > 'tdm_ext' was expected
>> >> > 'mclk_ext' was expected
>> >> > 'pll0_out' was expected
>> >> > Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> >> >
>> >> > This binding change is incompatible with the existing devicetrees for
>> >> > the visionfive 2.
>> >>
>> >> This looks like less clocks about PLL in SYSCRG node. And I add this in patch 7.
>> >
>> > The existing devicetree is a valid, albeit limited, description of the
>> > hardware.
>> > After your changes to the clock driver in this series, but *without* the
>> > changes to the devicetrees, does the system still function?
>> > From a quick check of 4/7, it looks like it will not?
>>
>> I just tested it on the board and the system still worked without the changes
>> about devicetree. But these clocks' rate were 0 because these could not get
>> the PLL clocks from devicetree.
>
> Hmm, that sounds like an issue to me. If all of the clock rates are
> computed based off of parents that incorrectly report 0, are we not in
> for trouble?
> Should the fixed-factor clocks be retained as a fallback for the sake of
> compatibility?
> Emil, Stephen?

I got your concern. Actually, I can add a check in driver to see if the dts
has pll clocks and then decide whether to use fixed-factor clocks or pll clocks
from syscon. But eventually we have to use pll clocks and dts has to add it.
Then the binding should add it synchronously, right?

Best regards,
Xingyu Wu

2023-05-19 08:23:11

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 3/7] dt-bindings: clock: jh7110-syscrg: Add PLL clock inputs

On Fri, May 19, 2023 at 03:59:19PM +0800, Xingyu Wu wrote:
> On 2023/5/12 21:49, Conor Dooley wrote:
> > On Fri, May 12, 2023 at 05:56:16PM +0800, Xingyu Wu wrote:
> >> On 2023/5/12 17:35, Conor Dooley wrote:
> >> > On Fri, May 12, 2023 at 04:07:47PM +0800, Xingyu Wu wrote:
> >> >> On 2023/5/12 14:47, Conor Dooley wrote:
> >> >> > On Fri, May 12, 2023 at 10:20:32AM +0800, Xingyu Wu wrote:
> >> >> >> Add PLL clock inputs from PLL clock generator.
> >> >> >>
> >> >> >> Acked-by: Krzysztof Kozlowski <[email protected]>
> >> >> >> Signed-off-by: Xingyu Wu <[email protected]>
> >> >> >> ---
> >> >> >> .../clock/starfive,jh7110-syscrg.yaml | 20 +++++++++++++++++--
> >> >> >> 1 file changed, 18 insertions(+), 2 deletions(-)
> >> >> >
> >> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
> >> >> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
> >> >> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> >> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
> >> >> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
> >> >> > 'i2stx_bclk_ext' was expected
> >> >> > 'i2stx_lrck_ext' was expected
> >> >> > 'i2srx_bclk_ext' was expected
> >> >> > 'i2srx_lrck_ext' was expected
> >> >> > 'tdm_ext' was expected
> >> >> > 'mclk_ext' was expected
> >> >> > 'pll0_out' was expected
> >> >> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> >> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
> >> >> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
> >> >> > From schema: Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> >> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
> >> >> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
> >> >> > 'i2stx_bclk_ext' was expected
> >> >> > 'i2stx_lrck_ext' was expected
> >> >> > 'i2srx_bclk_ext' was expected
> >> >> > 'i2srx_lrck_ext' was expected
> >> >> > 'tdm_ext' was expected
> >> >> > 'mclk_ext' was expected
> >> >> > 'pll0_out' was expected
> >> >> > Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
> >> >> >
> >> >> > This binding change is incompatible with the existing devicetrees for
> >> >> > the visionfive 2.
> >> >>
> >> >> This looks like less clocks about PLL in SYSCRG node. And I add this in patch 7.
> >> >
> >> > The existing devicetree is a valid, albeit limited, description of the
> >> > hardware.
> >> > After your changes to the clock driver in this series, but *without* the
> >> > changes to the devicetrees, does the system still function?
> >> > From a quick check of 4/7, it looks like it will not?
> >>
> >> I just tested it on the board and the system still worked without the changes
> >> about devicetree. But these clocks' rate were 0 because these could not get
> >> the PLL clocks from devicetree.
> >
> > Hmm, that sounds like an issue to me. If all of the clock rates are
> > computed based off of parents that incorrectly report 0, are we not in
> > for trouble?
> > Should the fixed-factor clocks be retained as a fallback for the sake of
> > compatibility?
> > Emil, Stephen?
>
> I got your concern. Actually, I can add a check in driver to see if the dts
> has pll clocks and then decide whether to use fixed-factor clocks or pll clocks
> from syscon. But eventually we have to use pll clocks and dts has to add it.
> Then the binding should add it synchronously, right?

IMO, it is okay to change the bindings to only allow the "correct"
representation of the clock tree, but the driver should fall back to the
fixed factor clocks if it detects the old/limited configuration.

Cheers,
Conor.


Attachments:
(No filename) (4.40 kB)
signature.asc (235.00 B)
Download all attachments

2023-05-19 08:39:49

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 3/7] dt-bindings: clock: jh7110-syscrg: Add PLL clock inputs

On 2023/5/19 16:12, Conor Dooley wrote:
> On Fri, May 19, 2023 at 03:59:19PM +0800, Xingyu Wu wrote:
>> On 2023/5/12 21:49, Conor Dooley wrote:
>> > On Fri, May 12, 2023 at 05:56:16PM +0800, Xingyu Wu wrote:
>> >> On 2023/5/12 17:35, Conor Dooley wrote:
>> >> > On Fri, May 12, 2023 at 04:07:47PM +0800, Xingyu Wu wrote:
>> >> >> On 2023/5/12 14:47, Conor Dooley wrote:
>> >> >> > On Fri, May 12, 2023 at 10:20:32AM +0800, Xingyu Wu wrote:
>> >> >> >> Add PLL clock inputs from PLL clock generator.
>> >> >> >>
>> >> >> >> Acked-by: Krzysztof Kozlowski <[email protected]>
>> >> >> >> Signed-off-by: Xingyu Wu <[email protected]>
>> >> >> >> ---
>> >> >> >> .../clock/starfive,jh7110-syscrg.yaml | 20 +++++++++++++++++--
>> >> >> >> 1 file changed, 18 insertions(+), 2 deletions(-)
>> >> >> >
>> >> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
>> >> >> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
>> >> >> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> >> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
>> >> >> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
>> >> >> > 'i2stx_bclk_ext' was expected
>> >> >> > 'i2stx_lrck_ext' was expected
>> >> >> > 'i2srx_bclk_ext' was expected
>> >> >> > 'i2srx_lrck_ext' was expected
>> >> >> > 'tdm_ext' was expected
>> >> >> > 'mclk_ext' was expected
>> >> >> > 'pll0_out' was expected
>> >> >> > From schema: /Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> >> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clocks: 'oneOf' conditional failed, one must be fixed:
>> >> >> > [[19], [20], [21], [22], [23], [24], [25], [26], [27]] is too short
>> >> >> > From schema: Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> >> >> > /tmp/tmp.KDlzwQM5ma/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.2a.dtb: clock-controller@13020000: clock-names: 'oneOf' conditional failed, one must be fixed:
>> >> >> > ['osc', 'gmac1_rmii_refin', 'gmac1_rgmii_rxin', 'i2stx_bclk_ext', 'i2stx_lrck_ext', 'i2srx_bclk_ext', 'i2srx_lrck_ext', 'tdm_ext', 'mclk_ext'] is too short
>> >> >> > 'i2stx_bclk_ext' was expected
>> >> >> > 'i2stx_lrck_ext' was expected
>> >> >> > 'i2srx_bclk_ext' was expected
>> >> >> > 'i2srx_lrck_ext' was expected
>> >> >> > 'tdm_ext' was expected
>> >> >> > 'mclk_ext' was expected
>> >> >> > 'pll0_out' was expected
>> >> >> > Documentation/devicetree/bindings/clock/starfive,jh7110-syscrg.yaml
>> >> >> >
>> >> >> > This binding change is incompatible with the existing devicetrees for
>> >> >> > the visionfive 2.
>> >> >>
>> >> >> This looks like less clocks about PLL in SYSCRG node. And I add this in patch 7.
>> >> >
>> >> > The existing devicetree is a valid, albeit limited, description of the
>> >> > hardware.
>> >> > After your changes to the clock driver in this series, but *without* the
>> >> > changes to the devicetrees, does the system still function?
>> >> > From a quick check of 4/7, it looks like it will not?
>> >>
>> >> I just tested it on the board and the system still worked without the changes
>> >> about devicetree. But these clocks' rate were 0 because these could not get
>> >> the PLL clocks from devicetree.
>> >
>> > Hmm, that sounds like an issue to me. If all of the clock rates are
>> > computed based off of parents that incorrectly report 0, are we not in
>> > for trouble?
>> > Should the fixed-factor clocks be retained as a fallback for the sake of
>> > compatibility?
>> > Emil, Stephen?
>>
>> I got your concern. Actually, I can add a check in driver to see if the dts
>> has pll clocks and then decide whether to use fixed-factor clocks or pll clocks
>> from syscon. But eventually we have to use pll clocks and dts has to add it.
>> Then the binding should add it synchronously, right?
>
> IMO, it is okay to change the bindings to only allow the "correct"
> representation of the clock tree, but the driver should fall back to the
> fixed factor clocks if it detects the old/limited configuration.
>

Great, I will follow it.

Best regards,
Xingyu Wu


2023-05-19 14:05:35

by Torsten Duwe

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
[...]
> #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
> #define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
>
> +/* PLL clocks */
> +#define JH7110_CLK_PLL0_OUT 0
> +#define JH7110_CLK_PLL1_OUT 1
> +#define JH7110_CLK_PLL2_OUT 2

In U-Boot commit 58c9c60b Yanhong Wang added:

+
+#define JH7110_SYSCLK_PLL0_OUT 190
+#define JH7110_SYSCLK_PLL1_OUT 191
+#define JH7110_SYSCLK_PLL2_OUT 192
+
+#define JH7110_SYSCLK_END 193

in that respective file.

> +#define JH7110_PLLCLK_END 3
> +
> /* SYSCRG clocks */
> #define JH7110_SYSCLK_CPU_ROOT 0

If the symbolic names referred to the same items, would it be possible
to keep the two files in sync somehow?

Torsten

2023-05-19 14:20:23

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
> [...]
> > #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
> > #define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
> >
> > +/* PLL clocks */
> > +#define JH7110_CLK_PLL0_OUT 0
> > +#define JH7110_CLK_PLL1_OUT 1
> > +#define JH7110_CLK_PLL2_OUT 2
>
> In U-Boot commit 58c9c60b Yanhong Wang added:
>
> +
> +#define JH7110_SYSCLK_PLL0_OUT 190
> +#define JH7110_SYSCLK_PLL1_OUT 191
> +#define JH7110_SYSCLK_PLL2_OUT 192
> +
> +#define JH7110_SYSCLK_END 193
>
> in that respective file.
>
> > +#define JH7110_PLLCLK_END 3
> > +
> > /* SYSCRG clocks */
> > #define JH7110_SYSCLK_CPU_ROOT 0
>
> If the symbolic names referred to the same items, would it be possible
> to keep the two files in sync somehow?

Ohh, that's not good.. If you pass the U-Boot dtb to Linux it won't
understand the numbering. The headers are part of the dt-binding :/


Attachments:
(No filename) (1.08 kB)
signature.asc (235.00 B)
Download all attachments

2023-05-23 02:55:03

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On 2023/5/19 22:16, Conor Dooley wrote:
> On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
>> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
>> [...]
>> > #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
>> > #define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
>> >
>> > +/* PLL clocks */
>> > +#define JH7110_CLK_PLL0_OUT 0
>> > +#define JH7110_CLK_PLL1_OUT 1
>> > +#define JH7110_CLK_PLL2_OUT 2
>>
>> In U-Boot commit 58c9c60b Yanhong Wang added:
>>
>> +
>> +#define JH7110_SYSCLK_PLL0_OUT 190
>> +#define JH7110_SYSCLK_PLL1_OUT 191
>> +#define JH7110_SYSCLK_PLL2_OUT 192
>> +
>> +#define JH7110_SYSCLK_END 193
>>
>> in that respective file.
>>
>> > +#define JH7110_PLLCLK_END 3
>> > +
>> > /* SYSCRG clocks */
>> > #define JH7110_SYSCLK_CPU_ROOT 0
>>
>> If the symbolic names referred to the same items, would it be possible
>> to keep the two files in sync somehow?
>
> Ohh, that's not good.. If you pass the U-Boot dtb to Linux it won't
> understand the numbering. The headers are part of the dt-binding :/

Because PLL driver is separated from SYSCRG driver in Linux,
the numbering starts from 0. But in Uboot, the PLL driver is
included in the SYSCRG driver, and the number follows the SYSCRG.

Best regards,
Xingyu Wu

2023-05-23 03:00:23

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On 2023/5/19 22:16, Conor Dooley wrote:
> On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
>> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
>> [...]
>> > #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
>> > #define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
>> >
>> > +/* PLL clocks */
>> > +#define JH7110_CLK_PLL0_OUT 0
>> > +#define JH7110_CLK_PLL1_OUT 1
>> > +#define JH7110_CLK_PLL2_OUT 2
>>
>> In U-Boot commit 58c9c60b Yanhong Wang added:
>>
>> +
>> +#define JH7110_SYSCLK_PLL0_OUT 190
>> +#define JH7110_SYSCLK_PLL1_OUT 191
>> +#define JH7110_SYSCLK_PLL2_OUT 192
>> +
>> +#define JH7110_SYSCLK_END 193
>>
>> in that respective file.
>>
>> > +#define JH7110_PLLCLK_END 3
>> > +
>> > /* SYSCRG clocks */
>> > #define JH7110_SYSCLK_CPU_ROOT 0
>>
>> If the symbolic names referred to the same items, would it be possible
>> to keep the two files in sync somehow?
>
> Ohh, that's not good.. If you pass the U-Boot dtb to Linux it won't
> understand the numbering. The headers are part of the dt-binding :/

Because in Linux, the PLL driver is separate from SYSCRG driver and the
numbering starts from 0. But in Uboot, the PLL driver is included in
the SYSCRG driver and the numbering follows the SYSCRG.

Best regards,
Xingyu Wu

2023-05-23 03:07:23

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On 2023/5/19 22:16, Conor Dooley wrote:
> On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
>> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
>> [...]
>> > #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
>> > #define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
>> >
>> > +/* PLL clocks */
>> > +#define JH7110_CLK_PLL0_OUT 0
>> > +#define JH7110_CLK_PLL1_OUT 1
>> > +#define JH7110_CLK_PLL2_OUT 2
>>
>> In U-Boot commit 58c9c60b Yanhong Wang added:
>>
>> +
>> +#define JH7110_SYSCLK_PLL0_OUT 190
>> +#define JH7110_SYSCLK_PLL1_OUT 191
>> +#define JH7110_SYSCLK_PLL2_OUT 192
>> +
>> +#define JH7110_SYSCLK_END 193
>>
>> in that respective file.
>>
>> > +#define JH7110_PLLCLK_END 3
>> > +
>> > /* SYSCRG clocks */
>> > #define JH7110_SYSCLK_CPU_ROOT 0
>>
>> If the symbolic names referred to the same items, would it be possible
>> to keep the two files in sync somehow?
>
> Ohh, that's not good.. If you pass the U-Boot dtb to Linux it won't
> understand the numbering. The headers are part of the dt-binding :/

Because PLL driver is separated from SYSCRG drivers in Linux, the numbering
starts from 0. But in Uboot, the PLL driver is included in the SYSCRG driver,
and the number follows the SYSCRG.

Best regards,
Xingyu Wu

2023-05-23 08:51:52

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Tue, May 23, 2023 at 10:56:43AM +0800, Xingyu Wu wrote:
> On 2023/5/19 22:16, Conor Dooley wrote:
> > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
> >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
> >> [...]
> >> > #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
> >> > #define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
> >> >
> >> > +/* PLL clocks */
> >> > +#define JH7110_CLK_PLL0_OUT 0
> >> > +#define JH7110_CLK_PLL1_OUT 1
> >> > +#define JH7110_CLK_PLL2_OUT 2
> >>
> >> In U-Boot commit 58c9c60b Yanhong Wang added:
> >>
> >> +
> >> +#define JH7110_SYSCLK_PLL0_OUT 190
> >> +#define JH7110_SYSCLK_PLL1_OUT 191
> >> +#define JH7110_SYSCLK_PLL2_OUT 192
> >> +
> >> +#define JH7110_SYSCLK_END 193
> >>
> >> in that respective file.
> >>
> >> > +#define JH7110_PLLCLK_END 3
> >> > +
> >> > /* SYSCRG clocks */
> >> > #define JH7110_SYSCLK_CPU_ROOT 0
> >>
> >> If the symbolic names referred to the same items, would it be possible
> >> to keep the two files in sync somehow?
> >
> > Ohh, that's not good.. If you pass the U-Boot dtb to Linux it won't
> > understand the numbering. The headers are part of the dt-binding :/
>
> Because PLL driver is separated from SYSCRG drivers in Linux, the numbering
> starts from 0. But in Uboot, the PLL driver is included in the SYSCRG driver,
> and the number follows the SYSCRG.

Unfortunately, how you choose to construct your drivers has nothing to
do with this.
These defines/numbers appear in the dts and are part of the DT ABI.
The same dts is supposed to work for Linux & U-Boot.


Attachments:
(No filename) (1.68 kB)
signature.asc (235.00 B)
Download all attachments

2023-05-23 11:35:35

by Torsten Duwe

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Tue, 23 May 2023 09:28:39 +0100
Conor Dooley <[email protected]> wrote:

> On Tue, May 23, 2023 at 10:56:43AM +0800, Xingyu Wu wrote:
> > On 2023/5/19 22:16, Conor Dooley wrote:
> > > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
> > >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
> > >> [...]

> > >> > +/* PLL clocks */
> > >> > +#define JH7110_CLK_PLL0_OUT 0
> > >> > +#define JH7110_CLK_PLL1_OUT 1
> > >> > +#define JH7110_CLK_PLL2_OUT 2
> > >>
> > >> In U-Boot commit 58c9c60b Yanhong Wang added:
> > >>
> > >> +
> > >> +#define JH7110_SYSCLK_PLL0_OUT 190
> > >> +#define JH7110_SYSCLK_PLL1_OUT 191
> > >> +#define JH7110_SYSCLK_PLL2_OUT 192
> > >> +
> > >> +#define JH7110_SYSCLK_END 193
[...]
> > > Ohh, that's not good.. If you pass the U-Boot dtb to Linux it
> > > won't understand the numbering. The headers are part of the
> > > dt-binding :/

In fact, the clock index >= 190 makes linux hang on boot, waiting with
EPROBE_DEFER for every device's clock, because the sysclk driver errors
out with EINVAL (jh7110_sysclk_get()).

> > Because PLL driver is separated from SYSCRG drivers in Linux, the
> > numbering starts from 0. But in Uboot, the PLL driver is included
> > in the SYSCRG driver, and the number follows the SYSCRG.
>
> Unfortunately, how you choose to construct your drivers has nothing to
> do with this.
> These defines/numbers appear in the dts and are part of the DT ABI.
> The same dts is supposed to work for Linux & U-Boot.

The JH7110 has 6 blocks of 64k iomem in that functional area:
{SYS,STG,AON} x {CRG,SYSCON}. None of these has 190 clocks.
The good news: the current DTS, as proposed here and in U-Boot master,
provides nodes for all 6 entities. The bad news is that the clock
assignments to those nodes and their numbering is messed up.

AFAICT PLL{0,1,2} _are_ generated in SYS_SYSCON and thus U-Boot gets it
wrong, in addition to the erroneous DTS.

Torsten

2023-05-23 11:46:03

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Tue, May 23, 2023 at 01:10:06PM +0200, Torsten Duwe wrote:
> On Tue, 23 May 2023 09:28:39 +0100
> Conor Dooley <[email protected]> wrote:
>
> > On Tue, May 23, 2023 at 10:56:43AM +0800, Xingyu Wu wrote:
> > > On 2023/5/19 22:16, Conor Dooley wrote:
> > > > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
> > > >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
> > > >> [...]
>
> > > >> > +/* PLL clocks */
> > > >> > +#define JH7110_CLK_PLL0_OUT 0
> > > >> > +#define JH7110_CLK_PLL1_OUT 1
> > > >> > +#define JH7110_CLK_PLL2_OUT 2
> > > >>
> > > >> In U-Boot commit 58c9c60b Yanhong Wang added:
> > > >>
> > > >> +
> > > >> +#define JH7110_SYSCLK_PLL0_OUT 190
> > > >> +#define JH7110_SYSCLK_PLL1_OUT 191
> > > >> +#define JH7110_SYSCLK_PLL2_OUT 192
> > > >> +
> > > >> +#define JH7110_SYSCLK_END 193
> [...]
> > > > Ohh, that's not good.. If you pass the U-Boot dtb to Linux it
> > > > won't understand the numbering. The headers are part of the
> > > > dt-binding :/
>
> In fact, the clock index >= 190 makes linux hang on boot, waiting with
> EPROBE_DEFER for every device's clock, because the sysclk driver errors
> out with EINVAL (jh7110_sysclk_get()).

Yup, that's about what I expected to happen.

> > > Because PLL driver is separated from SYSCRG drivers in Linux, the
> > > numbering starts from 0. But in Uboot, the PLL driver is included
> > > in the SYSCRG driver, and the number follows the SYSCRG.
> >
> > Unfortunately, how you choose to construct your drivers has nothing to
> > do with this.
> > These defines/numbers appear in the dts and are part of the DT ABI.
> > The same dts is supposed to work for Linux & U-Boot.
>
> The JH7110 has 6 blocks of 64k iomem in that functional area:
> {SYS,STG,AON} x {CRG,SYSCON}. None of these has 190 clocks.
> The good news: the current DTS, as proposed here and in U-Boot master,
> provides nodes for all 6 entities. The bad news is that the clock
> assignments to those nodes and their numbering is messed up.
>
> AFAICT PLL{0,1,2} _are_ generated in SYS_SYSCON and thus U-Boot gets it
> wrong, in addition to the erroneous DTS.

The numbers are kinda hocus-pocus anyway, they are just made up since the
clock numbering usually isn't something with a nice TRM to go and
reference (unlike interrupts which usually are documented in that way).
It is very helpful to make them aligned some register/bit positions or,
but that is not required.
IOW U-Boot is not wrong per se to use 190 instead of 0, but it is wrong
to have different numbers in both places.

It sounds like you're saying that (and I have not looked) the U-Boot dts
actually has structural difference w.r.t. what provides which clock?
If so, that'll need to be fixed independently of the numbering problem.

Otherwise Xingyu & Yanhong should coordinate on which is the "correct"
way of doing things & do it in both places.

Thanks,
Conor.


Attachments:
(No filename) (3.00 kB)
signature.asc (235.00 B)
Download all attachments

2023-05-24 09:34:47

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On 2023/5/23 19:28, Conor Dooley wrote:
> On Tue, May 23, 2023 at 01:10:06PM +0200, Torsten Duwe wrote:
>> On Tue, 23 May 2023 09:28:39 +0100
>> Conor Dooley <[email protected]> wrote:
>>
>> > On Tue, May 23, 2023 at 10:56:43AM +0800, Xingyu Wu wrote:
>> > > On 2023/5/19 22:16, Conor Dooley wrote:
>> > > > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
>> > > >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
>> > > >> [...]
>>
>> > > >> > +/* PLL clocks */
>> > > >> > +#define JH7110_CLK_PLL0_OUT 0
>> > > >> > +#define JH7110_CLK_PLL1_OUT 1
>> > > >> > +#define JH7110_CLK_PLL2_OUT 2
>> > > >>
>> > > >> In U-Boot commit 58c9c60b Yanhong Wang added:
>> > > >>
>> > > >> +
>> > > >> +#define JH7110_SYSCLK_PLL0_OUT 190
>> > > >> +#define JH7110_SYSCLK_PLL1_OUT 191
>> > > >> +#define JH7110_SYSCLK_PLL2_OUT 192
>> > > >> +
>> > > >> +#define JH7110_SYSCLK_END 193
>> [...]
>> > > > Ohh, that's not good.. If you pass the U-Boot dtb to Linux it
>> > > > won't understand the numbering. The headers are part of the
>> > > > dt-binding :/
>>
>> In fact, the clock index >= 190 makes linux hang on boot, waiting with
>> EPROBE_DEFER for every device's clock, because the sysclk driver errors
>> out with EINVAL (jh7110_sysclk_get()).
>
> Yup, that's about what I expected to happen.
>
>> > > Because PLL driver is separated from SYSCRG drivers in Linux, the
>> > > numbering starts from 0. But in Uboot, the PLL driver is included
>> > > in the SYSCRG driver, and the number follows the SYSCRG.
>> >
>> > Unfortunately, how you choose to construct your drivers has nothing to
>> > do with this.
>> > These defines/numbers appear in the dts and are part of the DT ABI.
>> > The same dts is supposed to work for Linux & U-Boot.
>>
>> The JH7110 has 6 blocks of 64k iomem in that functional area:
>> {SYS,STG,AON} x {CRG,SYSCON}. None of these has 190 clocks.
>> The good news: the current DTS, as proposed here and in U-Boot master,
>> provides nodes for all 6 entities. The bad news is that the clock
>> assignments to those nodes and their numbering is messed up.
>>
>> AFAICT PLL{0,1,2} _are_ generated in SYS_SYSCON and thus U-Boot gets it
>> wrong, in addition to the erroneous DTS.
>
> The numbers are kinda hocus-pocus anyway, they are just made up since the
> clock numbering usually isn't something with a nice TRM to go and
> reference (unlike interrupts which usually are documented in that way).
> It is very helpful to make them aligned some register/bit positions or,
> but that is not required.
> IOW U-Boot is not wrong per se to use 190 instead of 0, but it is wrong
> to have different numbers in both places.
>
> It sounds like you're saying that (and I have not looked) the U-Boot dts
> actually has structural difference w.r.t. what provides which clock?
> If so, that'll need to be fixed independently of the numbering problem.
>
> Otherwise Xingyu & Yanhong should coordinate on which is the "correct"
> way of doing things & do it in both places.
>

Oh, unfortunately, the 7110 can not support to mix the uboot dtb and linux dtb up.
If boot the Linux and should use the linux dtb instead of the uboot dtb.
Because all clock ids and reset ids in Linux and Uboot are different include
PLL, and some modules can work in Linux but not in uboot.
I suggest to boot Linux with its own linux dtb.

Best regards,
Xingyu Wu



2023-05-24 10:33:09

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Wed, May 24, 2023 at 05:00:02PM +0800, Xingyu Wu wrote:
> On 2023/5/23 19:28, Conor Dooley wrote:
> > On Tue, May 23, 2023 at 01:10:06PM +0200, Torsten Duwe wrote:
> >> On Tue, 23 May 2023 09:28:39 +0100
> >> Conor Dooley <[email protected]> wrote:
> >>
> >> > On Tue, May 23, 2023 at 10:56:43AM +0800, Xingyu Wu wrote:
> >> > > On 2023/5/19 22:16, Conor Dooley wrote:
> >> > > > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
> >> > > >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
> >> > > >> [...]
> >>
> >> > > >> > +/* PLL clocks */
> >> > > >> > +#define JH7110_CLK_PLL0_OUT 0
> >> > > >> > +#define JH7110_CLK_PLL1_OUT 1
> >> > > >> > +#define JH7110_CLK_PLL2_OUT 2
> >> > > >>
> >> > > >> In U-Boot commit 58c9c60b Yanhong Wang added:
> >> > > >>
> >> > > >> +
> >> > > >> +#define JH7110_SYSCLK_PLL0_OUT 190
> >> > > >> +#define JH7110_SYSCLK_PLL1_OUT 191
> >> > > >> +#define JH7110_SYSCLK_PLL2_OUT 192
> >> > > >> +
> >> > > >> +#define JH7110_SYSCLK_END 193
> >> [...]
> >> > > > Ohh, that's not good.. If you pass the U-Boot dtb to Linux it
> >> > > > won't understand the numbering. The headers are part of the
> >> > > > dt-binding :/
> >>
> >> In fact, the clock index >= 190 makes linux hang on boot, waiting with
> >> EPROBE_DEFER for every device's clock, because the sysclk driver errors
> >> out with EINVAL (jh7110_sysclk_get()).
> >
> > Yup, that's about what I expected to happen.
> >
> >> > > Because PLL driver is separated from SYSCRG drivers in Linux, the
> >> > > numbering starts from 0. But in Uboot, the PLL driver is included
> >> > > in the SYSCRG driver, and the number follows the SYSCRG.
> >> >
> >> > Unfortunately, how you choose to construct your drivers has nothing to
> >> > do with this.
> >> > These defines/numbers appear in the dts and are part of the DT ABI.
> >> > The same dts is supposed to work for Linux & U-Boot.
> >>
> >> The JH7110 has 6 blocks of 64k iomem in that functional area:
> >> {SYS,STG,AON} x {CRG,SYSCON}. None of these has 190 clocks.
> >> The good news: the current DTS, as proposed here and in U-Boot master,
> >> provides nodes for all 6 entities. The bad news is that the clock
> >> assignments to those nodes and their numbering is messed up.
> >>
> >> AFAICT PLL{0,1,2} _are_ generated in SYS_SYSCON and thus U-Boot gets it
> >> wrong, in addition to the erroneous DTS.
> >
> > The numbers are kinda hocus-pocus anyway, they are just made up since the
> > clock numbering usually isn't something with a nice TRM to go and
> > reference (unlike interrupts which usually are documented in that way).
> > It is very helpful to make them aligned some register/bit positions or,
> > but that is not required.
> > IOW U-Boot is not wrong per se to use 190 instead of 0, but it is wrong
> > to have different numbers in both places.
> >
> > It sounds like you're saying that (and I have not looked) the U-Boot dts
> > actually has structural difference w.r.t. what provides which clock?
> > If so, that'll need to be fixed independently of the numbering problem.
> >
> > Otherwise Xingyu & Yanhong should coordinate on which is the "correct"
> > way of doing things & do it in both places.
> >
>
> Oh, unfortunately, the 7110 can not support to mix the uboot dtb and linux dtb up.

What does "cannot support" mean? It's normal and desirable for the same
dtb to be usable for both. The Linux kernel's dt-bindings are used for
multiple projects, not just Linux - it'd be silly for U-Boot, FreeBSD
etc etc to go off and each have their open set of (incompatible) bindings.

> If boot the Linux and should use the linux dtb instead of the uboot dtb.
> Because all clock ids and reset ids in Linux and Uboot are different include
> PLL, and some modules can work in Linux but not in uboot.

What do you mean by "modules"? It is fine for either Linux or U-Boot to
not have drivers for particular peripherals - for example, there might
be no driver for your camera related bits in U-Boot, or for controlling
DRAM in Linux.

The description of the hardware should not change though, as the
hardware has not.

> I suggest to boot Linux with its own linux dtb.

I suggest to make sure that you can use the same dtb for both.

Thanks,
Conor.


Attachments:
(No filename) (4.34 kB)
signature.asc (235.00 B)
Download all attachments

2023-05-26 07:45:34

by Torsten Duwe

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Wed, 24 May 2023 11:19:48 +0100
Conor Dooley <[email protected]> wrote:

> On Wed, May 24, 2023 at 05:00:02PM +0800, Xingyu Wu wrote:
> > On 2023/5/23 19:28, Conor Dooley wrote:
> > > On Tue, May 23, 2023 at 01:10:06PM +0200, Torsten Duwe wrote:
> > >> On Tue, 23 May 2023 09:28:39 +0100
> > >> Conor Dooley <[email protected]> wrote:
> > >>
> > >> > On Tue, May 23, 2023 at 10:56:43AM +0800, Xingyu Wu wrote:
> > >> > > On 2023/5/19 22:16, Conor Dooley wrote:
> > >> > > > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe
> > >> > > > wrote:
> > >> > > >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
[...]

> > >> > > Because PLL driver is separated from SYSCRG drivers in
> > >> > > Linux, the numbering starts from 0. But in Uboot, the PLL
> > >> > > driver is included in the SYSCRG driver, and the number
> > >> > > follows the SYSCRG.
> > >> >
> > >> > Unfortunately, how you choose to construct your drivers has
> > >> > nothing to do with this.

Exactly. As I wrote (quote below), the PLLx frequencies are controlled
by the I/O block SYS_SYSCON (starting there at offset 0x18), according
to the public datasheets. All(?) other clocks are derived from those in
the *_CRG units. That *is* the hardware to be described, in *the* (one
and only!) DT. U-Boot, and any OS, are free to reorganise their driver
framework around that, but the hardware description is quite clear.

> > >> > These defines/numbers appear in the dts and are part of the DT
> > >> > ABI. The same dts is supposed to work for Linux & U-Boot.
> > >>
> > >> The JH7110 has 6 blocks of 64k iomem in that functional area:
> > >> {SYS,STG,AON} x {CRG,SYSCON}. None of these has 190 clocks.
> > >> The good news: the current DTS, as proposed here and in U-Boot
> > >> master, provides nodes for all 6 entities. The bad news is that
> > >> the clock assignments to those nodes and their numbering is
> > >> messed up.
> > >>
> > >> AFAICT PLL{0,1,2} _are_ generated in SYS_SYSCON and thus U-Boot
> > >> gets it wrong, in addition to the erroneous DTS.
> > >
> > > The numbers are kinda hocus-pocus anyway, they are just made up
> > > since the clock numbering usually isn't something with a nice TRM
> > > to go and reference (unlike interrupts which usually are
> > > documented in that way). It is very helpful to make them aligned
> > > some register/bit positions or, but that is not required.
> > > IOW U-Boot is not wrong per se to use 190 instead of 0, but it is
> > > wrong to have different numbers in both places.

U-Boot reuses the Common Clock Framework from Linux, and I'm not sure
whether the clock IDs need to be unique in order for the appropriate
clock to be found. But that would be the only restriction, if it
applies. Even then, each driver could register a clock with its own,
arbitrarily chosen base offset with the CCF, so each CRG unit could
still have its own clocks enumerated starting with 0 in the DTB.

> > > It sounds like you're saying that (and I have not looked) the
> > > U-Boot dts actually has structural difference w.r.t. what
> > > provides which clock? If so, that'll need to be fixed
> > > independently of the numbering problem.

> >
> > Oh, unfortunately, the 7110 can not support to mix the uboot dtb
> > and linux dtb up.
>
> What does "cannot support" mean? It's normal and desirable for the

IMHO "desirable" is too weak.

> same dtb to be usable for both. The Linux kernel's dt-bindings are
> used for multiple projects, not just Linux - it'd be silly for
> U-Boot, FreeBSD etc etc to go off and each have their open set of
> (incompatible) bindings.
>
> > If boot the Linux and should use the linux dtb instead of the uboot
> > dtb. Because all clock ids and reset ids in Linux and Uboot are
> > different include PLL, and some modules can work in Linux but not
> > in uboot.
[...]
>
> > I suggest to boot Linux with its own linux dtb.

This is a fragile band-aid, to be used only as a last resort. It
creates more problems than it solves. Your DTB will then match your
kernel, but whether it describes the actual hardware is a game of
chance. Doesn't the VisionFive2 have an RPi connector... ?

One of the IMO few valid use cases of adding a DTB to the kernel
at boot is OpenWRT, when you build an OS Image for a particular piece
of hardware you have at hand.

> I suggest to make sure that you can use the same dtb for both.

Interestingly enough, U-Boot already has the PLL driver in a separate
file. I have a half-baked patch here that moves the sys_syscon DT
matching into that file...

Torsten


2023-05-26 12:26:13

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Fri, May 26, 2023 at 09:34:32AM +0200, Torsten Duwe wrote:
> On Wed, 24 May 2023 11:19:48 +0100
> Conor Dooley <[email protected]> wrote:
>
> > On Wed, May 24, 2023 at 05:00:02PM +0800, Xingyu Wu wrote:
> > > On 2023/5/23 19:28, Conor Dooley wrote:
> > > > On Tue, May 23, 2023 at 01:10:06PM +0200, Torsten Duwe wrote:
> > > >> On Tue, 23 May 2023 09:28:39 +0100
> > > >> Conor Dooley <[email protected]> wrote:
> > > >>
> > > >> > On Tue, May 23, 2023 at 10:56:43AM +0800, Xingyu Wu wrote:
> > > >> > > On 2023/5/19 22:16, Conor Dooley wrote:
> > > >> > > > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe
> > > >> > > > wrote:
> > > >> > > >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
> [...]
>
> > > >> > > Because PLL driver is separated from SYSCRG drivers in
> > > >> > > Linux, the numbering starts from 0. But in Uboot, the PLL
> > > >> > > driver is included in the SYSCRG driver, and the number
> > > >> > > follows the SYSCRG.
> > > >> >
> > > >> > Unfortunately, how you choose to construct your drivers has
> > > >> > nothing to do with this.
>
> Exactly. As I wrote (quote below), the PLLx frequencies are controlled
> by the I/O block SYS_SYSCON (starting there at offset 0x18), according
> to the public datasheets. All(?) other clocks are derived from those in
> the *_CRG units. That *is* the hardware to be described, in *the* (one
> and only!) DT. U-Boot, and any OS, are free to reorganise their driver
> framework around that, but the hardware description is quite clear.

The dt-binding that is in this series specifies that the pll clock
controller is a child of the syscon:
https://lore.kernel.org/linux-riscv/[email protected]/T/#Z2e.:..:20230512022036.97987-6-xingyu.wu::40starfivetech.com:1soc:starfive:starfive::2cjh7110-syscon.yaml

That seems correct to me & U-Boot's devicetree is not compliant.

> > > >> > These defines/numbers appear in the dts and are part of the DT
> > > >> > ABI. The same dts is supposed to work for Linux & U-Boot.
> > > >>
> > > >> The JH7110 has 6 blocks of 64k iomem in that functional area:
> > > >> {SYS,STG,AON} x {CRG,SYSCON}. None of these has 190 clocks.
> > > >> The good news: the current DTS, as proposed here and in U-Boot
> > > >> master, provides nodes for all 6 entities. The bad news is that
> > > >> the clock assignments to those nodes and their numbering is
> > > >> messed up.
> > > >>
> > > >> AFAICT PLL{0,1,2} _are_ generated in SYS_SYSCON and thus U-Boot
> > > >> gets it wrong, in addition to the erroneous DTS.
> > > >
> > > > The numbers are kinda hocus-pocus anyway, they are just made up
> > > > since the clock numbering usually isn't something with a nice TRM
> > > > to go and reference (unlike interrupts which usually are
> > > > documented in that way). It is very helpful to make them aligned
> > > > some register/bit positions or, but that is not required.
> > > > IOW U-Boot is not wrong per se to use 190 instead of 0, but it is
> > > > wrong to have different numbers in both places.
>
> U-Boot reuses the Common Clock Framework from Linux, and I'm not sure
> whether the clock IDs need to be unique in order for the appropriate
> clock to be found.

Unique within the clock controller, otherwise it is impossible to tell
the difference between <&cctrl 1> and <&cctrl 1> apart! (The same
follows even with increased #clock-cells, something must be unique).
That's besides the point of this particular issue though.

> But that would be the only restriction, if it
> applies. Even then, each driver could register a clock with its own,
> arbitrarily chosen base offset with the CCF, so each CRG unit could
> still have its own clocks enumerated starting with 0 in the DTB.
>
> > > > It sounds like you're saying that (and I have not looked) the
> > > > U-Boot dts actually has structural difference w.r.t. what
> > > > provides which clock? If so, that'll need to be fixed
> > > > independently of the numbering problem.
>
> > >
> > > Oh, unfortunately, the 7110 can not support to mix the uboot dtb
> > > and linux dtb up.
> >
> > What does "cannot support" mean? It's normal and desirable for the
>
> IMHO "desirable" is too weak.

Yeah, agreed. I just don't like being prescriptive about what happens in
projects that I do not maintain things for I guess.

> > same dtb to be usable for both. The Linux kernel's dt-bindings are
> > used for multiple projects, not just Linux - it'd be silly for
> > U-Boot, FreeBSD etc etc to go off and each have their open set of
> > (incompatible) bindings.
> >
> > > If boot the Linux and should use the linux dtb instead of the uboot
> > > dtb. Because all clock ids and reset ids in Linux and Uboot are
> > > different include PLL, and some modules can work in Linux but not
> > > in uboot.
> [...]
> >
> > > I suggest to boot Linux with its own linux dtb.
>
> This is a fragile band-aid, to be used only as a last resort. It
> creates more problems than it solves. Your DTB will then match your
> kernel, but whether it describes the actual hardware is a game of
> chance. Doesn't the VisionFive2 have an RPi connector... ?
>
> One of the IMO few valid use cases of adding a DTB to the kernel
> at boot is OpenWRT, when you build an OS Image for a particular piece
> of hardware you have at hand.
>
> > I suggest to make sure that you can use the same dtb for both.
>
> Interestingly enough, U-Boot already has the PLL driver in a separate
> file. I have a half-baked patch here that moves the sys_syscon DT
> matching into that file...

If you have patches that fix the devicetree & drivers in U-Boot, please
post them. I don't really care at all which set of arbitrary numbers are
chosen (as long as there is one and one only) but it looks like U-Boot's
devicetree has an incorrect description of the clock controllers.

Thanks,
Conor.


Attachments:
(No filename) (5.86 kB)
signature.asc (235.00 B)
Download all attachments

2023-06-01 11:08:52

by Emil Renner Berthing

[permalink] [raw]
Subject: Re: [PATCH v4 2/7] clk: starfive: Add StarFive JH7110 PLL clock driver

Hi Xingyu,

Thanks for working on this.

On Fri, 12 May 2023 at 04:24, Xingyu Wu <[email protected]> wrote:
>
> Add driver for the StarFive JH7110 PLL clock controller
> and they work by reading and setting syscon registers.
>
> Signed-off-by: Xingyu Wu <[email protected]>
> ---
> MAINTAINERS | 6 +
> drivers/clk/starfive/Kconfig | 8 +
> drivers/clk/starfive/Makefile | 1 +
> .../clk/starfive/clk-starfive-jh7110-pll.c | 309 ++++++++++++++++
> .../clk/starfive/clk-starfive-jh7110-pll.h | 331 ++++++++++++++++++
> 5 files changed, 655 insertions(+)
> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.c
> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7e0b87d5aa2e..0fb4a703f66f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -20087,6 +20087,12 @@ S: Supported
> F: Documentation/devicetree/bindings/mmc/starfive*
> F: drivers/mmc/host/dw_mmc-starfive.c
>
> +STARFIVE JH7110 PLL CLOCK DRIVER
> +M: Xingyu Wu <[email protected]>
> +S: Supported
> +F: Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml
> +F: drivers/clk/starfive/clk-starfive-jh7110-pll.*
> +
> STARFIVE JH71X0 CLOCK DRIVERS
> M: Emil Renner Berthing <[email protected]>
> M: Hal Feng <[email protected]>
> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
> index 5d2333106f13..5195f7be5213 100644
> --- a/drivers/clk/starfive/Kconfig
> +++ b/drivers/clk/starfive/Kconfig
> @@ -21,6 +21,14 @@ config CLK_STARFIVE_JH7100_AUDIO
> Say Y or M here to support the audio clocks on the StarFive JH7100
> SoC.
>
> +config CLK_STARFIVE_JH7110_PLL
> + bool "StarFive JH7110 PLL clock support"
> + depends on ARCH_STARFIVE || COMPILE_TEST
> + default ARCH_STARFIVE
> + help
> + Say yes here to support the PLL clock controller on the
> + StarFive JH7110 SoC.
> +
> config CLK_STARFIVE_JH7110_SYS
> bool "StarFive JH7110 system clock support"
> depends on ARCH_STARFIVE || COMPILE_TEST
> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
> index f3df7d957b1e..b48e539e52b0 100644
> --- a/drivers/clk/starfive/Makefile
> +++ b/drivers/clk/starfive/Makefile
> @@ -4,5 +4,6 @@ obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk-starfive-jh71x0.o
> obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o
> obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
>
> +obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += clk-starfive-jh7110-pll.o
> obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-pll.c b/drivers/clk/starfive/clk-starfive-jh7110-pll.c
> new file mode 100644
> index 000000000000..f86deddd4bef
> --- /dev/null
> +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.c
> @@ -0,0 +1,309 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * StarFive JH7110 PLL Clock Generator Driver
> + *
> + * Copyright (C) 2023 StarFive Technology Co., Ltd.
> + *
> + * This driver is about to register JH7110 PLL clock generator and support ops.
> + * The JH7110 have three PLL clock, PLL0, PLL1 and PLL2.
> + * Each PLL clocks work in integer mode or fraction mode by some dividers,
> + * and the configuration registers and dividers are set in several syscon registers.
> + * The formula for calculating frequency is:
> + * Fvco = Fref * (NI + NF) / M / Q1
> + * Fref: OSC source clock rate
> + * NI: integer frequency dividing ratio of feedback divider, set by fbdiv[11:0].
> + * NF: fractional frequency dividing ratio, set by frac[23:0]. NF = frac[23:0] / 2^24 = 0 ~ 0.999.
> + * M: frequency dividing ratio of pre-divider, set by prediv[5:0].
> + * Q1: frequency dividing ratio of post divider, set by postdiv1[1:0], Q1= 1,2,4,8.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/debugfs.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
> +
> +#include "clk-starfive-jh7110-pll.h"
> +
> +struct jh7110_pll_conf_variant {
> + unsigned int pll_nums;
> + struct jh7110_pll_syscon_conf conf[];
> +};
> +
> +static const struct jh7110_pll_conf_variant jh7110_pll_variant = {
> + .pll_nums = JH7110_PLLCLK_END,
> + .conf = {
> + JH7110_PLL(JH7110_CLK_PLL0_OUT, "pll0_out",
> + JH7110_PLL0_FREQ_MAX, jh7110_pll0_syscon_val_preset),
> + JH7110_PLL(JH7110_CLK_PLL1_OUT, "pll1_out",
> + JH7110_PLL1_FREQ_MAX, jh7110_pll1_syscon_val_preset),
> + JH7110_PLL(JH7110_CLK_PLL2_OUT, "pll2_out",
> + JH7110_PLL2_FREQ_MAX, jh7110_pll2_syscon_val_preset),
> + },
> +};
> +
> +static struct jh7110_clk_pll_data *jh7110_pll_data_from(struct clk_hw *hw)
> +{
> + return container_of(hw, struct jh7110_clk_pll_data, hw);
> +}
> +
> +static struct jh7110_clk_pll_priv *jh7110_pll_priv_from(struct jh7110_clk_pll_data *data)
> +{
> + return container_of(data, struct jh7110_clk_pll_priv, data[data->idx]);
> +}
> +
> +/* Read register value from syscon and calculate PLL(x) frequency */
> +static unsigned long jh7110_pll_get_freq(struct jh7110_clk_pll_data *data,
> + unsigned long parent_rate)
> +{
> + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
> + struct jh7110_pll_syscon_offset *offset = &data->conf.offsets;
> + struct jh7110_pll_syscon_mask *mask = &data->conf.masks;
> + struct jh7110_pll_syscon_shift *shift = &data->conf.shifts;
> + unsigned long frac_cal;
> + u32 dacpd;
> + u32 dsmpd;
> + u32 fbdiv;
> + u32 prediv;
> + u32 postdiv1;
> + u32 frac;
> + u32 reg_val;
> +
> + regmap_read(priv->syscon_regmap, offset->dacpd, &reg_val);
> + dacpd = (reg_val & mask->dacpd) >> shift->dacpd;
> +
> + regmap_read(priv->syscon_regmap, offset->dsmpd, &reg_val);
> + dsmpd = (reg_val & mask->dsmpd) >> shift->dsmpd;
> +
> + regmap_read(priv->syscon_regmap, offset->fbdiv, &reg_val);
> + fbdiv = (reg_val & mask->fbdiv) >> shift->fbdiv;
> +
> + regmap_read(priv->syscon_regmap, offset->prediv, &reg_val);
> + prediv = (reg_val & mask->prediv) >> shift->prediv;
> +
> + regmap_read(priv->syscon_regmap, offset->postdiv1, &reg_val);
> + /* postdiv1 = 2 ^ reg_val */
> + postdiv1 = 1 << ((reg_val & mask->postdiv1) >> shift->postdiv1);
> +
> + regmap_read(priv->syscon_regmap, offset->frac, &reg_val);
> + frac = (reg_val & mask->frac) >> shift->frac;
> +
> + /*
> + * Integer Mode (Both 1) or Fraction Mode (Both 0).
> + * And the decimal places are counted by expanding them by
> + * a factor of STARFIVE_PLL_FRAC_PATR_SIZE.
> + */
> + if (dacpd == 1 && dsmpd == 1)
> + frac_cal = 0;
> + else if (dacpd == 0 && dsmpd == 0)
> + frac_cal = (unsigned long)frac * STARFIVE_PLL_FRAC_PATR_SIZE / (1 << 24);
> + else
> + return 0;
> +
> + /* Fvco = Fref * (NI + NF) / M / Q1 */
> + return (parent_rate / STARFIVE_PLL_FRAC_PATR_SIZE *
> + (fbdiv * STARFIVE_PLL_FRAC_PATR_SIZE + frac_cal) / prediv / postdiv1);

You have

rate = parent * (fbdiv + frac/2^24) / prediv / 2^postdiv1regval

Where postdiv1regval is the raw postdiv1 register value. This can also
be written

rate = (parent * fbdiv + parent * frac / 2^24) / (prediv * 2^postdiv1regval)

so how about

if (dacpd == 1 && dsmpd == 1)
rate = 0;
else if (dacpd == 0 && dsmpd == 0)
rate = parent * frac / (1UL << 24);
else
return 0;

rate += parent * fbdiv;
rate /= prediv << postdiv1regval;
return rate;

> +}
> +
> +static unsigned long jh7110_pll_rate_sub_fabs(unsigned long rate1, unsigned long rate2)
> +{
> + return rate1 > rate2 ? (rate1 - rate2) : (rate2 - rate1);
> +}
> +
> +/* Select the appropriate frequency from the already configured registers value */
> +static void jh7110_pll_select_near_freq_id(struct jh7110_clk_pll_data *data,
> + unsigned long rate)
> +{
> + const struct jh7110_pll_syscon_val *val;
> + unsigned int id;
> + unsigned long rate_diff;
> +
> + /* compare the frequency one by one from small to large in order */
> + for (id = 0; id < data->conf.preset_val_nums; id++) {
> + val = &data->conf.preset_val[id];
> +
> + if (rate == val->freq)
> + goto match_end;
> +
> + /* select near frequency */

Is there any reason we can't just pick the highest rate <= the
requested rate, just like we do for the regular clock dividers?

> + if (rate < val->freq) {
> + /* The last frequency is closer to the target rate than this time. */
> + if (id > 0)
> + if (rate_diff < jh7110_pll_rate_sub_fabs(rate, val->freq))
> + id--;
> +
> + goto match_end;
> + } else {
> + rate_diff = jh7110_pll_rate_sub_fabs(rate, val->freq);
> + }
> + }
> +
> +match_end:
> + data->freq_select_idx = id;
> +}
> +
> +static int jh7110_pll_set_freq_syscon(struct jh7110_clk_pll_data *data)
> +{
> + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
> + struct jh7110_pll_syscon_offset *offset = &data->conf.offsets;
> + struct jh7110_pll_syscon_mask *mask = &data->conf.masks;
> + struct jh7110_pll_syscon_shift *shift = &data->conf.shifts;
> + const struct jh7110_pll_syscon_val *val = &data->conf.preset_val[data->freq_select_idx];
> +
> + /* frac: Integer Mode (Both 1) or Fraction Mode (Both 0) */
> + if (val->dacpd == 0 && val->dsmpd == 0)
> + regmap_update_bits(priv->syscon_regmap, offset->frac, mask->frac,
> + (val->frac << shift->frac));
> + else if (val->dacpd != val->dsmpd)
> + return -EINVAL;
> +
> + /* fbdiv value should be 8 to 4095 */
> + if (val->fbdiv < 8)
> + return -EINVAL;
> +
> + regmap_update_bits(priv->syscon_regmap, offset->dacpd, mask->dacpd,
> + (val->dacpd << shift->dacpd));
> + regmap_update_bits(priv->syscon_regmap, offset->dsmpd, mask->dsmpd,
> + (val->dsmpd << shift->dsmpd));
> + regmap_update_bits(priv->syscon_regmap, offset->prediv, mask->prediv,
> + (val->prediv << shift->prediv));
> + regmap_update_bits(priv->syscon_regmap, offset->fbdiv, mask->fbdiv,
> + (val->fbdiv << shift->fbdiv));
> + regmap_update_bits(priv->syscon_regmap, offset->postdiv1, mask->postdiv1,
> + ((val->postdiv1 >> 1) << shift->postdiv1));

It seems like you're storing the divider and not the register value in
the presets. Since the divider is 2^regval it means you need to write
log2 (divider) into the register, but here you store divider >> 1 aka
divider / 2.

I'd strongly suggest you just store the register value, and just use
2^regval when you need the divider. This way you won't need to ever
calculate log2 of anything.

> +
> + return 0;
> +}
> +
> +static unsigned long jh7110_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
> +
> + return jh7110_pll_get_freq(data, parent_rate);
> +}
> +
> +static int jh7110_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
> +{
> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);

What happens if the parent rate != 24MHz? Then all your presets will
be wrong. We probably want to guard against that.

> + jh7110_pll_select_near_freq_id(data, req->rate);
> + req->rate = data->conf.preset_val[data->freq_select_idx].freq;
> +
> + return 0;
> +}
> +
> +static int jh7110_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
> +
> + return jh7110_pll_set_freq_syscon(data);
> +}
> +
> +#ifdef CONFIG_DEBUG_FS
> +static void jh7110_pll_debug_init(struct clk_hw *hw, struct dentry *dentry)
> +{
> + static const struct debugfs_reg32 jh7110_clk_pll_reg = {
> + .name = "CTRL",
> + .offset = 0,
> + };
> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
> + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
> + struct debugfs_regset32 *regset;
> +
> + regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL);
> + if (!regset)
> + return;
> +
> + regset->regs = &jh7110_clk_pll_reg;
> + regset->nregs = 1;

You never set regset->base, so this function creates a registers file
that just shows the contents of address 0. I don't think you tested
this.

> +
> + debugfs_create_regset32("registers", 0400, dentry, regset);
> +}
> +#else
> +#define jh7110_pll_debug_init NULL
> +#endif
> +
> +static const struct clk_ops jh7110_pll_ops = {
> + .recalc_rate = jh7110_pll_recalc_rate,
> + .determine_rate = jh7110_pll_determine_rate,
> + .set_rate = jh7110_pll_set_rate,
> + .debug_init = jh7110_pll_debug_init,
> +};
> +
> +static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data)
> +{
> + struct jh7110_clk_pll_priv *priv = data;
> + unsigned int idx = clkspec->args[0];
> +
> + if (idx < priv->pll_nums)
> + return &priv->data[idx].hw;
> +
> + return ERR_PTR(-EINVAL);
> +}
> +
> +static int jh7110_pll_probe(struct platform_device *pdev)
> +{
> + const struct jh7110_pll_conf_variant *variant;
> + struct jh7110_clk_pll_priv *priv;
> + struct jh7110_clk_pll_data *data;
> + int ret;
> + unsigned int idx;
> +
> + variant = of_device_get_match_data(&pdev->dev);
> + if (!variant)
> + return -ENOMEM;
> +
> + priv = devm_kzalloc(&pdev->dev, struct_size(priv, data, variant->pll_nums),
> + GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->dev = &pdev->dev;
> + priv->syscon_regmap = syscon_node_to_regmap(priv->dev->of_node->parent);
> + if (IS_ERR(priv->syscon_regmap))
> + return PTR_ERR(priv->syscon_regmap);
> +
> + priv->pll_nums = variant->pll_nums;
> + for (idx = 0; idx < priv->pll_nums; idx++) {
> + struct clk_parent_data parents = {
> + .index = 0,
> + };
> + struct clk_init_data init = {
> + .name = variant->conf[idx].name,
> + .ops = &jh7110_pll_ops,
> + .parent_data = &parents,
> + .num_parents = 1,
> + .flags = 0,
> + };
> +
> + data = &priv->data[idx];
> + data->conf = variant->conf[idx];

Why do you need to copy all this static data? Can't you just reference
the static const version you already have?

> + data->hw.init = &init;
> + data->idx = idx;
> +
> + ret = devm_clk_hw_register(&pdev->dev, &data->hw);
> + if (ret)
> + return ret;
> + }
> +
> + return devm_of_clk_add_hw_provider(&pdev->dev, jh7110_pll_get, priv);
> +}
> +
> +static const struct of_device_id jh7110_pll_match[] = {
> + { .compatible = "starfive,jh7110-pll", .data = &jh7110_pll_variant },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, jh7110_pll_match);
> +
> +static struct platform_driver jh7110_pll_driver = {
> + .driver = {
> + .name = "clk-starfive-jh7110-pll",
> + .of_match_table = jh7110_pll_match,
> + },
> +};
> +builtin_platform_driver_probe(jh7110_pll_driver, jh7110_pll_probe);
> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-pll.h b/drivers/clk/starfive/clk-starfive-jh7110-pll.h
> new file mode 100644
> index 000000000000..526f21670fe3
> --- /dev/null
> +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.h

This header is never used outside of clk-starfive-jh7110-pll.c. Please
just merge it into that file.

> @@ -0,0 +1,331 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR MIT */
> +/*
> + * StarFive JH7110 PLL Clock Generator Driver
> + *
> + * Copyright (C) 2023 StarFive Technology Co., Ltd.
> + */
> +
> +#ifndef _CLK_STARFIVE_JH7110_PLL_H_
> +#define _CLK_STARFIVE_JH7110_PLL_H_
> +
> +#include <linux/bits.h>
> +
> +/* The decimal places are counted by expanding them by a factor of STARFIVE_PLL_FRAC_PATR_SIZE */
> +#define STARFIVE_PLL_FRAC_PATR_SIZE 1000
> +
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_OFFSET 0x18
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_SHIFT 24
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_MASK BIT(24)
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_OFFSET 0x18
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_SHIFT 25
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_MASK BIT(25)
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_OFFSET 0x1c
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_SHIFT 0
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_MASK GENMASK(11, 0)
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_OFFSET 0x20
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_SHIFT 0
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_MASK GENMASK(23, 0)
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_OFFSET 0x20
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_SHIFT 28
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_MASK GENMASK(29, 28)
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_OFFSET 0x24
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_SHIFT 0
> +#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_MASK GENMASK(5, 0)
> +
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_OFFSET 0x24
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_SHIFT 15
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_MASK BIT(15)
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_OFFSET 0x24
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_SHIFT 16
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_MASK BIT(16)
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_OFFSET 0x24
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_SHIFT 17
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_MASK GENMASK(28, 17)
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_OFFSET 0x28
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_SHIFT 0
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_MASK GENMASK(23, 0)
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_OFFSET 0x28
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_SHIFT 28
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_MASK GENMASK(29, 28)
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_OFFSET 0x2c
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_SHIFT 0
> +#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_MASK GENMASK(5, 0)
> +
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_OFFSET 0x2c
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_SHIFT 15
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_MASK BIT(15)
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_OFFSET 0x2c
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_SHIFT 16
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_MASK BIT(16)
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_OFFSET 0x2c
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_SHIFT 17
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_MASK GENMASK(28, 17)
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_OFFSET 0x30
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_SHIFT 0
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_MASK GENMASK(23, 0)
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_OFFSET 0x30
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_SHIFT 28
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_MASK GENMASK(29, 28)
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_OFFSET 0x34
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_SHIFT 0
> +#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_MASK GENMASK(5, 0)
> +
> +#define JH7110_PLL(_idx, _name, _nums, _val) \
> +[_idx] = { \
> + .name = _name, \
> + .offsets = { \
> + .dacpd = STARFIVE_##_idx##_DACPD_OFFSET, \
> + .dsmpd = STARFIVE_##_idx##_DSMPD_OFFSET, \
> + .fbdiv = STARFIVE_##_idx##_FBDIV_OFFSET, \
> + .frac = STARFIVE_##_idx##_FRAC_OFFSET, \
> + .prediv = STARFIVE_##_idx##_PREDIV_OFFSET, \
> + .postdiv1 = STARFIVE_##_idx##_POSTDIV1_OFFSET, \
> + }, \
> + .masks = { \
> + .dacpd = STARFIVE_##_idx##_DACPD_MASK, \
> + .dsmpd = STARFIVE_##_idx##_DSMPD_MASK, \
> + .fbdiv = STARFIVE_##_idx##_FBDIV_MASK, \
> + .frac = STARFIVE_##_idx##_FRAC_MASK, \
> + .prediv = STARFIVE_##_idx##_PREDIV_MASK, \
> + .postdiv1 = STARFIVE_##_idx##_POSTDIV1_MASK, \
> + }, \
> + .shifts = { \
> + .dacpd = STARFIVE_##_idx##_DACPD_SHIFT, \
> + .dsmpd = STARFIVE_##_idx##_DSMPD_SHIFT, \
> + .fbdiv = STARFIVE_##_idx##_FBDIV_SHIFT, \
> + .frac = STARFIVE_##_idx##_FRAC_SHIFT, \
> + .prediv = STARFIVE_##_idx##_PREDIV_SHIFT, \
> + .postdiv1 = STARFIVE_##_idx##_POSTDIV1_SHIFT, \
> + }, \
> + .preset_val_nums = _nums, \
> + .preset_val = _val, \
> +}
> +
> +struct jh7110_pll_syscon_offset {
> + unsigned int dacpd;
> + unsigned int dsmpd;
> + unsigned int fbdiv;
> + unsigned int frac;
> + unsigned int prediv;
> + unsigned int postdiv1;
> +};
> +
> +struct jh7110_pll_syscon_mask {
> + u32 dacpd;
> + u32 dsmpd;
> + u32 fbdiv;
> + u32 frac;
> + u32 prediv;
> + u32 postdiv1;
> +};
> +
> +struct jh7110_pll_syscon_shift {
> + char dacpd;
> + char dsmpd;
> + char fbdiv;
> + char frac;
> + char prediv;
> + char postdiv1;
> +};
> +
> +struct jh7110_pll_syscon_val {
> + unsigned long freq;
> + u32 prediv;
> + u32 fbdiv;
> + u32 postdiv1;
> +/* Both daxpd and dsmpd set 1 while integer mode */
> +/* Both daxpd and dsmpd set 0 while fraction mode */
> + u32 dacpd;
> + u32 dsmpd;
> +/* frac value should be decimals multiplied by 2^24 */
> + u32 frac;
> +};
> +
> +struct jh7110_pll_syscon_conf {
> + char *name;
> + struct jh7110_pll_syscon_offset offsets;
> + struct jh7110_pll_syscon_mask masks;
> + struct jh7110_pll_syscon_shift shifts;
> + unsigned int preset_val_nums;
> + const struct jh7110_pll_syscon_val *preset_val;
> +};
> +
> +struct jh7110_clk_pll_data {
> + struct clk_hw hw;
> + unsigned int idx;
> + unsigned int freq_select_idx;
> + struct jh7110_pll_syscon_conf conf;
> +};
> +
> +struct jh7110_clk_pll_priv {
> + unsigned int pll_nums;
> + struct device *dev;
> + struct regmap *syscon_regmap;
> + struct jh7110_clk_pll_data data[];
> +};
> +
> +enum jh7110_pll0_freq_index {
> + JH7110_PLL0_FREQ_375 = 0,
> + JH7110_PLL0_FREQ_500,
> + JH7110_PLL0_FREQ_625,
> + JH7110_PLL0_FREQ_750,
> + JH7110_PLL0_FREQ_875,
> + JH7110_PLL0_FREQ_1000,
> + JH7110_PLL0_FREQ_1250,
> + JH7110_PLL0_FREQ_1375,
> + JH7110_PLL0_FREQ_1500,
> + JH7110_PLL0_FREQ_MAX
> +};
> +
> +enum jh7110_pll1_freq_index {
> + JH7110_PLL1_FREQ_1066 = 0,
> + JH7110_PLL1_FREQ_1200,
> + JH7110_PLL1_FREQ_1400,
> + JH7110_PLL1_FREQ_1600,
> + JH7110_PLL1_FREQ_MAX
> +};
> +
> +enum jh7110_pll2_freq_index {
> + JH7110_PLL2_FREQ_1188 = 0,
> + JH7110_PLL2_FREQ_12288,
> + JH7110_PLL2_FREQ_MAX
> +};
> +
> +/*
> + * Because the pll frequency is relatively fixed,
> + * it cannot be set arbitrarily, so it needs a specific configuration.
> + * PLL0 frequency should be multiple of 125MHz (USB frequency).
> + */
> +static const struct jh7110_pll_syscon_val
> + jh7110_pll0_syscon_val_preset[] = {
> + [JH7110_PLL0_FREQ_375] = {
> + .freq = 375000000,
> + .prediv = 8,
> + .fbdiv = 125,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL0_FREQ_500] = {
> + .freq = 500000000,
> + .prediv = 6,
> + .fbdiv = 125,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL0_FREQ_625] = {
> + .freq = 625000000,
> + .prediv = 24,
> + .fbdiv = 625,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL0_FREQ_750] = {
> + .freq = 750000000,
> + .prediv = 4,
> + .fbdiv = 125,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL0_FREQ_875] = {
> + .freq = 875000000,
> + .prediv = 24,
> + .fbdiv = 875,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL0_FREQ_1000] = {
> + .freq = 1000000000,
> + .prediv = 3,
> + .fbdiv = 125,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL0_FREQ_1250] = {
> + .freq = 1250000000,
> + .prediv = 12,
> + .fbdiv = 625,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL0_FREQ_1375] = {
> + .freq = 1375000000,
> + .prediv = 24,
> + .fbdiv = 1375,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL0_FREQ_1500] = {
> + .freq = 1500000000,
> + .prediv = 2,
> + .fbdiv = 125,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> +};
> +
> +static const struct jh7110_pll_syscon_val
> + jh7110_pll1_syscon_val_preset[] = {
> + [JH7110_PLL1_FREQ_1066] = {
> + .freq = 1066000000,
> + .prediv = 12,
> + .fbdiv = 533,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL1_FREQ_1200] = {
> + .freq = 1200000000,
> + .prediv = 1,
> + .fbdiv = 50,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL1_FREQ_1400] = {
> + .freq = 1400000000,
> + .prediv = 6,
> + .fbdiv = 350,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL1_FREQ_1600] = {
> + .freq = 1600000000,
> + .prediv = 3,
> + .fbdiv = 200,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> +};
> +
> +static const struct jh7110_pll_syscon_val
> + jh7110_pll2_syscon_val_preset[] = {
> + [JH7110_PLL2_FREQ_1188] = {
> + .freq = 1188000000,
> + .prediv = 2,
> + .fbdiv = 99,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> + [JH7110_PLL2_FREQ_12288] = {
> + .freq = 1228800000,
> + .prediv = 5,
> + .fbdiv = 256,
> + .postdiv1 = 1,
> + .dacpd = 1,
> + .dsmpd = 1,
> + },
> +};
> +
> +#endif
> --
> 2.25.1

In general this driver is overly generic even though it is a driver
specific to the JH7110 SoC. Rather than try to explain all the ways
you can simplify it, I decided it would be easier to show you:

https://github.com/esmil/linux/commit/9b7f325267c9a760eda6612c7ffbf22366790878

It has all the same functionality, fixes all of the above and saves
more than 100 lines of code, so please use that for your next
revision.

/Emil

2023-06-02 10:03:22

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On 2023/5/26 20:23, Conor Dooley wrote:
> On Fri, May 26, 2023 at 09:34:32AM +0200, Torsten Duwe wrote:
>> On Wed, 24 May 2023 11:19:48 +0100
>> Conor Dooley <[email protected]> wrote:
>>
>> > On Wed, May 24, 2023 at 05:00:02PM +0800, Xingyu Wu wrote:
>> > > On 2023/5/23 19:28, Conor Dooley wrote:
>> > > > On Tue, May 23, 2023 at 01:10:06PM +0200, Torsten Duwe wrote:
>> > > >> On Tue, 23 May 2023 09:28:39 +0100
>> > > >> Conor Dooley <[email protected]> wrote:
>> > > >>
>> > > >> > On Tue, May 23, 2023 at 10:56:43AM +0800, Xingyu Wu wrote:
>> > > >> > > On 2023/5/19 22:16, Conor Dooley wrote:
>> > > >> > > > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe
>> > > >> > > > wrote:
>> > > >> > > >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
>> [...]
>>
>> > > >> > > Because PLL driver is separated from SYSCRG drivers in
>> > > >> > > Linux, the numbering starts from 0. But in Uboot, the PLL
>> > > >> > > driver is included in the SYSCRG driver, and the number
>> > > >> > > follows the SYSCRG.
>> > > >> >
>> > > >> > Unfortunately, how you choose to construct your drivers has
>> > > >> > nothing to do with this.
>>
>> Exactly. As I wrote (quote below), the PLLx frequencies are controlled
>> by the I/O block SYS_SYSCON (starting there at offset 0x18), according
>> to the public datasheets. All(?) other clocks are derived from those in
>> the *_CRG units. That *is* the hardware to be described, in *the* (one
>> and only!) DT. U-Boot, and any OS, are free to reorganise their driver
>> framework around that, but the hardware description is quite clear.
>
> The dt-binding that is in this series specifies that the pll clock
> controller is a child of the syscon:
> https://lore.kernel.org/linux-riscv/[email protected]/T/#Z2e.:..:20230512022036.97987-6-xingyu.wu::40starfivetech.com:1soc:starfive:starfive::2cjh7110-syscon.yaml
>
> That seems correct to me & U-Boot's devicetree is not compliant.
>
>> > > >> > These defines/numbers appear in the dts and are part of the DT
>> > > >> > ABI. The same dts is supposed to work for Linux & U-Boot.
>> > > >>
>> > > >> The JH7110 has 6 blocks of 64k iomem in that functional area:
>> > > >> {SYS,STG,AON} x {CRG,SYSCON}. None of these has 190 clocks.
>> > > >> The good news: the current DTS, as proposed here and in U-Boot
>> > > >> master, provides nodes for all 6 entities. The bad news is that
>> > > >> the clock assignments to those nodes and their numbering is
>> > > >> messed up.
>> > > >>
>> > > >> AFAICT PLL{0,1,2} _are_ generated in SYS_SYSCON and thus U-Boot
>> > > >> gets it wrong, in addition to the erroneous DTS.
>> > > >
>> > > > The numbers are kinda hocus-pocus anyway, they are just made up
>> > > > since the clock numbering usually isn't something with a nice TRM
>> > > > to go and reference (unlike interrupts which usually are
>> > > > documented in that way). It is very helpful to make them aligned
>> > > > some register/bit positions or, but that is not required.
>> > > > IOW U-Boot is not wrong per se to use 190 instead of 0, but it is
>> > > > wrong to have different numbers in both places.
>>
>> U-Boot reuses the Common Clock Framework from Linux, and I'm not sure
>> whether the clock IDs need to be unique in order for the appropriate
>> clock to be found.
>
> Unique within the clock controller, otherwise it is impossible to tell
> the difference between <&cctrl 1> and <&cctrl 1> apart! (The same
> follows even with increased #clock-cells, something must be unique).
> That's besides the point of this particular issue though.
>
>> But that would be the only restriction, if it
>> applies. Even then, each driver could register a clock with its own,
>> arbitrarily chosen base offset with the CCF, so each CRG unit could
>> still have its own clocks enumerated starting with 0 in the DTB.
>>
>> > > > It sounds like you're saying that (and I have not looked) the
>> > > > U-Boot dts actually has structural difference w.r.t. what
>> > > > provides which clock? If so, that'll need to be fixed
>> > > > independently of the numbering problem.
>>
>> > >
>> > > Oh, unfortunately, the 7110 can not support to mix the uboot dtb
>> > > and linux dtb up.
>> >
>> > What does "cannot support" mean? It's normal and desirable for the
>>
>> IMHO "desirable" is too weak.
>
> Yeah, agreed. I just don't like being prescriptive about what happens in
> projects that I do not maintain things for I guess.
>
>> > same dtb to be usable for both. The Linux kernel's dt-bindings are
>> > used for multiple projects, not just Linux - it'd be silly for
>> > U-Boot, FreeBSD etc etc to go off and each have their open set of
>> > (incompatible) bindings.
>> >
>> > > If boot the Linux and should use the linux dtb instead of the uboot
>> > > dtb. Because all clock ids and reset ids in Linux and Uboot are
>> > > different include PLL, and some modules can work in Linux but not
>> > > in uboot.
>> [...]
>> >
>> > > I suggest to boot Linux with its own linux dtb.
>>
>> This is a fragile band-aid, to be used only as a last resort. It
>> creates more problems than it solves. Your DTB will then match your
>> kernel, but whether it describes the actual hardware is a game of
>> chance. Doesn't the VisionFive2 have an RPi connector... ?
>>
>> One of the IMO few valid use cases of adding a DTB to the kernel
>> at boot is OpenWRT, when you build an OS Image for a particular piece
>> of hardware you have at hand.
>>
>> > I suggest to make sure that you can use the same dtb for both.
>>
>> Interestingly enough, U-Boot already has the PLL driver in a separate
>> file. I have a half-baked patch here that moves the sys_syscon DT
>> matching into that file...
>
> If you have patches that fix the devicetree & drivers in U-Boot, please
> post them. I don't really care at all which set of arbitrary numbers are
> chosen (as long as there is one and one only) but it looks like U-Boot's
> devicetree has an incorrect description of the clock controllers.
>

Thank you for your suggestions. I will discuss with my partners how to solve this problem.

Best regards,
Xingyu Wu


2023-06-02 10:06:01

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 2/7] clk: starfive: Add StarFive JH7110 PLL clock driver

On 2023/6/1 19:02, Emil Renner Berthing wrote:
> Hi Xingyu,
>
> Thanks for working on this.
>
> On Fri, 12 May 2023 at 04:24, Xingyu Wu <[email protected]> wrote:
>>
>> Add driver for the StarFive JH7110 PLL clock controller
>> and they work by reading and setting syscon registers.
>>
>> Signed-off-by: Xingyu Wu <[email protected]>
>> ---
>> MAINTAINERS | 6 +
>> drivers/clk/starfive/Kconfig | 8 +
>> drivers/clk/starfive/Makefile | 1 +
>> .../clk/starfive/clk-starfive-jh7110-pll.c | 309 ++++++++++++++++
>> .../clk/starfive/clk-starfive-jh7110-pll.h | 331 ++++++++++++++++++
>> 5 files changed, 655 insertions(+)
>> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.c
>> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 7e0b87d5aa2e..0fb4a703f66f 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -20087,6 +20087,12 @@ S: Supported
>> F: Documentation/devicetree/bindings/mmc/starfive*
>> F: drivers/mmc/host/dw_mmc-starfive.c
>>
>> +STARFIVE JH7110 PLL CLOCK DRIVER
>> +M: Xingyu Wu <[email protected]>
>> +S: Supported
>> +F: Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml
>> +F: drivers/clk/starfive/clk-starfive-jh7110-pll.*
>> +
>> STARFIVE JH71X0 CLOCK DRIVERS
>> M: Emil Renner Berthing <[email protected]>
>> M: Hal Feng <[email protected]>
>> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
>> index 5d2333106f13..5195f7be5213 100644
>> --- a/drivers/clk/starfive/Kconfig
>> +++ b/drivers/clk/starfive/Kconfig
>> @@ -21,6 +21,14 @@ config CLK_STARFIVE_JH7100_AUDIO
>> Say Y or M here to support the audio clocks on the StarFive JH7100
>> SoC.
>>
>> +config CLK_STARFIVE_JH7110_PLL
>> + bool "StarFive JH7110 PLL clock support"
>> + depends on ARCH_STARFIVE || COMPILE_TEST
>> + default ARCH_STARFIVE
>> + help
>> + Say yes here to support the PLL clock controller on the
>> + StarFive JH7110 SoC.
>> +
>> config CLK_STARFIVE_JH7110_SYS
>> bool "StarFive JH7110 system clock support"
>> depends on ARCH_STARFIVE || COMPILE_TEST
>> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
>> index f3df7d957b1e..b48e539e52b0 100644
>> --- a/drivers/clk/starfive/Makefile
>> +++ b/drivers/clk/starfive/Makefile
>> @@ -4,5 +4,6 @@ obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk-starfive-jh71x0.o
>> obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o
>> obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
>>
>> +obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += clk-starfive-jh7110-pll.o
>> obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
>> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
>> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-pll.c b/drivers/clk/starfive/clk-starfive-jh7110-pll.c
>> new file mode 100644
>> index 000000000000..f86deddd4bef
>> --- /dev/null
>> +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.c
>> @@ -0,0 +1,309 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * StarFive JH7110 PLL Clock Generator Driver
>> + *
>> + * Copyright (C) 2023 StarFive Technology Co., Ltd.
>> + *
>> + * This driver is about to register JH7110 PLL clock generator and support ops.
>> + * The JH7110 have three PLL clock, PLL0, PLL1 and PLL2.
>> + * Each PLL clocks work in integer mode or fraction mode by some dividers,
>> + * and the configuration registers and dividers are set in several syscon registers.
>> + * The formula for calculating frequency is:
>> + * Fvco = Fref * (NI + NF) / M / Q1
>> + * Fref: OSC source clock rate
>> + * NI: integer frequency dividing ratio of feedback divider, set by fbdiv[11:0].
>> + * NF: fractional frequency dividing ratio, set by frac[23:0]. NF = frac[23:0] / 2^24 = 0 ~ 0.999.
>> + * M: frequency dividing ratio of pre-divider, set by prediv[5:0].
>> + * Q1: frequency dividing ratio of post divider, set by postdiv1[1:0], Q1= 1,2,4,8.
>> + */
>> +
>> +#include <linux/clk-provider.h>
>> +#include <linux/debugfs.h>
>> +#include <linux/device.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regmap.h>
>> +
>> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
>> +
>> +#include "clk-starfive-jh7110-pll.h"
>> +
>> +struct jh7110_pll_conf_variant {
>> + unsigned int pll_nums;
>> + struct jh7110_pll_syscon_conf conf[];
>> +};
>> +
>> +static const struct jh7110_pll_conf_variant jh7110_pll_variant = {
>> + .pll_nums = JH7110_PLLCLK_END,
>> + .conf = {
>> + JH7110_PLL(JH7110_CLK_PLL0_OUT, "pll0_out",
>> + JH7110_PLL0_FREQ_MAX, jh7110_pll0_syscon_val_preset),
>> + JH7110_PLL(JH7110_CLK_PLL1_OUT, "pll1_out",
>> + JH7110_PLL1_FREQ_MAX, jh7110_pll1_syscon_val_preset),
>> + JH7110_PLL(JH7110_CLK_PLL2_OUT, "pll2_out",
>> + JH7110_PLL2_FREQ_MAX, jh7110_pll2_syscon_val_preset),
>> + },
>> +};
>> +
>> +static struct jh7110_clk_pll_data *jh7110_pll_data_from(struct clk_hw *hw)
>> +{
>> + return container_of(hw, struct jh7110_clk_pll_data, hw);
>> +}
>> +
>> +static struct jh7110_clk_pll_priv *jh7110_pll_priv_from(struct jh7110_clk_pll_data *data)
>> +{
>> + return container_of(data, struct jh7110_clk_pll_priv, data[data->idx]);
>> +}
>> +
>> +/* Read register value from syscon and calculate PLL(x) frequency */
>> +static unsigned long jh7110_pll_get_freq(struct jh7110_clk_pll_data *data,
>> + unsigned long parent_rate)
>> +{
>> + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
>> + struct jh7110_pll_syscon_offset *offset = &data->conf.offsets;
>> + struct jh7110_pll_syscon_mask *mask = &data->conf.masks;
>> + struct jh7110_pll_syscon_shift *shift = &data->conf.shifts;
>> + unsigned long frac_cal;
>> + u32 dacpd;
>> + u32 dsmpd;
>> + u32 fbdiv;
>> + u32 prediv;
>> + u32 postdiv1;
>> + u32 frac;
>> + u32 reg_val;
>> +
>> + regmap_read(priv->syscon_regmap, offset->dacpd, &reg_val);
>> + dacpd = (reg_val & mask->dacpd) >> shift->dacpd;
>> +
>> + regmap_read(priv->syscon_regmap, offset->dsmpd, &reg_val);
>> + dsmpd = (reg_val & mask->dsmpd) >> shift->dsmpd;
>> +
>> + regmap_read(priv->syscon_regmap, offset->fbdiv, &reg_val);
>> + fbdiv = (reg_val & mask->fbdiv) >> shift->fbdiv;
>> +
>> + regmap_read(priv->syscon_regmap, offset->prediv, &reg_val);
>> + prediv = (reg_val & mask->prediv) >> shift->prediv;
>> +
>> + regmap_read(priv->syscon_regmap, offset->postdiv1, &reg_val);
>> + /* postdiv1 = 2 ^ reg_val */
>> + postdiv1 = 1 << ((reg_val & mask->postdiv1) >> shift->postdiv1);
>> +
>> + regmap_read(priv->syscon_regmap, offset->frac, &reg_val);
>> + frac = (reg_val & mask->frac) >> shift->frac;
>> +
>> + /*
>> + * Integer Mode (Both 1) or Fraction Mode (Both 0).
>> + * And the decimal places are counted by expanding them by
>> + * a factor of STARFIVE_PLL_FRAC_PATR_SIZE.
>> + */
>> + if (dacpd == 1 && dsmpd == 1)
>> + frac_cal = 0;
>> + else if (dacpd == 0 && dsmpd == 0)
>> + frac_cal = (unsigned long)frac * STARFIVE_PLL_FRAC_PATR_SIZE / (1 << 24);
>> + else
>> + return 0;
>> +
>> + /* Fvco = Fref * (NI + NF) / M / Q1 */
>> + return (parent_rate / STARFIVE_PLL_FRAC_PATR_SIZE *
>> + (fbdiv * STARFIVE_PLL_FRAC_PATR_SIZE + frac_cal) / prediv / postdiv1);
>
> You have
>
> rate = parent * (fbdiv + frac/2^24) / prediv / 2^postdiv1regval
>
> Where postdiv1regval is the raw postdiv1 register value. This can also
> be written
>
> rate = (parent * fbdiv + parent * frac / 2^24) / (prediv * 2^postdiv1regval)
>
> so how about
>
> if (dacpd == 1 && dsmpd == 1)
> rate = 0;
> else if (dacpd == 0 && dsmpd == 0)
> rate = parent * frac / (1UL << 24);
> else
> return 0;
>
> rate += parent * fbdiv;
> rate /= prediv << postdiv1regval;
> return rate;
>
Thanks for you suggestions. I will modify this.
And I have a question, should I keep the 'STARFIVE_PLL_FRAC_PATR_SIZE ' as integer to calculate the fractional part of 'frac'?

>> +}
>> +
>> +static unsigned long jh7110_pll_rate_sub_fabs(unsigned long rate1, unsigned long rate2)
>> +{
>> + return rate1 > rate2 ? (rate1 - rate2) : (rate2 - rate1);
>> +}
>> +
>> +/* Select the appropriate frequency from the already configured registers value */
>> +static void jh7110_pll_select_near_freq_id(struct jh7110_clk_pll_data *data,
>> + unsigned long rate)
>> +{
>> + const struct jh7110_pll_syscon_val *val;
>> + unsigned int id;
>> + unsigned long rate_diff;
>> +
>> + /* compare the frequency one by one from small to large in order */
>> + for (id = 0; id < data->conf.preset_val_nums; id++) {
>> + val = &data->conf.preset_val[id];
>> +
>> + if (rate == val->freq)
>> + goto match_end;
>> +
>> + /* select near frequency */
>
> Is there any reason we can't just pick the highest rate <= the
> requested rate, just like we do for the regular clock dividers?

It sounds like rounding down. This is a good idea and I will fix it.

>
>> + if (rate < val->freq) {
>> + /* The last frequency is closer to the target rate than this time. */
>> + if (id > 0)
>> + if (rate_diff < jh7110_pll_rate_sub_fabs(rate, val->freq))
>> + id--;
>> +
>> + goto match_end;
>> + } else {
>> + rate_diff = jh7110_pll_rate_sub_fabs(rate, val->freq);
>> + }
>> + }
>> +
>> +match_end:
>> + data->freq_select_idx = id;
>> +}
>> +
>> +static int jh7110_pll_set_freq_syscon(struct jh7110_clk_pll_data *data)
>> +{
>> + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
>> + struct jh7110_pll_syscon_offset *offset = &data->conf.offsets;
>> + struct jh7110_pll_syscon_mask *mask = &data->conf.masks;
>> + struct jh7110_pll_syscon_shift *shift = &data->conf.shifts;
>> + const struct jh7110_pll_syscon_val *val = &data->conf.preset_val[data->freq_select_idx];
>> +
>> + /* frac: Integer Mode (Both 1) or Fraction Mode (Both 0) */
>> + if (val->dacpd == 0 && val->dsmpd == 0)
>> + regmap_update_bits(priv->syscon_regmap, offset->frac, mask->frac,
>> + (val->frac << shift->frac));
>> + else if (val->dacpd != val->dsmpd)
>> + return -EINVAL;
>> +
>> + /* fbdiv value should be 8 to 4095 */
>> + if (val->fbdiv < 8)
>> + return -EINVAL;
>> +
>> + regmap_update_bits(priv->syscon_regmap, offset->dacpd, mask->dacpd,
>> + (val->dacpd << shift->dacpd));
>> + regmap_update_bits(priv->syscon_regmap, offset->dsmpd, mask->dsmpd,
>> + (val->dsmpd << shift->dsmpd));
>> + regmap_update_bits(priv->syscon_regmap, offset->prediv, mask->prediv,
>> + (val->prediv << shift->prediv));
>> + regmap_update_bits(priv->syscon_regmap, offset->fbdiv, mask->fbdiv,
>> + (val->fbdiv << shift->fbdiv));
>> + regmap_update_bits(priv->syscon_regmap, offset->postdiv1, mask->postdiv1,
>> + ((val->postdiv1 >> 1) << shift->postdiv1));
>
> It seems like you're storing the divider and not the register value in
> the presets. Since the divider is 2^regval it means you need to write
> log2 (divider) into the register, but here you store divider >> 1 aka
> divider / 2.

Oh, It's my mistake. The values of post divider are 1,2,4, and 8, which pass when it equals 1, 2, and 4, but is failed when it equals 8.

>
> I'd strongly suggest you just store the register value, and just use
> 2^regval when you need the divider. This way you won't need to ever
> calculate log2 of anything.

Great. Using the register value directly avoid some calculations.

>
>> +
>> + return 0;
>> +}
>> +
>> +static unsigned long jh7110_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
>> +{
>> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
>> +
>> + return jh7110_pll_get_freq(data, parent_rate);
>> +}
>> +
>> +static int jh7110_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
>> +{
>> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
>
> What happens if the parent rate != 24MHz? Then all your presets will
> be wrong. We probably want to guard against that.

Will fix and add a check for parent rate.

>
>> + jh7110_pll_select_near_freq_id(data, req->rate);
>> + req->rate = data->conf.preset_val[data->freq_select_idx].freq;
>> +
>> + return 0;
>> +}
>> +
>> +static int jh7110_pll_set_rate(struct clk_hw *hw, unsigned long rate,
>> + unsigned long parent_rate)
>> +{
>> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
>> +
>> + return jh7110_pll_set_freq_syscon(data);
>> +}
>> +
>> +#ifdef CONFIG_DEBUG_FS
>> +static void jh7110_pll_debug_init(struct clk_hw *hw, struct dentry *dentry)
>> +{
>> + static const struct debugfs_reg32 jh7110_clk_pll_reg = {
>> + .name = "CTRL",
>> + .offset = 0,
>> + };
>> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
>> + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
>> + struct debugfs_regset32 *regset;
>> +
>> + regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL);
>> + if (!regset)
>> + return;
>> +
>> + regset->regs = &jh7110_clk_pll_reg;
>> + regset->nregs = 1;
>
> You never set regset->base, so this function creates a registers file
> that just shows the contents of address 0. I don't think you tested
> this.

Will add the regset->base.

>
>> +
>> + debugfs_create_regset32("registers", 0400, dentry, regset);
>> +}
>> +#else
>> +#define jh7110_pll_debug_init NULL
>> +#endif
>> +
>> +static const struct clk_ops jh7110_pll_ops = {
>> + .recalc_rate = jh7110_pll_recalc_rate,
>> + .determine_rate = jh7110_pll_determine_rate,
>> + .set_rate = jh7110_pll_set_rate,
>> + .debug_init = jh7110_pll_debug_init,
>> +};
>> +
>> +static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data)
>> +{
>> + struct jh7110_clk_pll_priv *priv = data;
>> + unsigned int idx = clkspec->args[0];
>> +
>> + if (idx < priv->pll_nums)
>> + return &priv->data[idx].hw;
>> +
>> + return ERR_PTR(-EINVAL);
>> +}
>> +
>> +static int jh7110_pll_probe(struct platform_device *pdev)
>> +{
>> + const struct jh7110_pll_conf_variant *variant;
>> + struct jh7110_clk_pll_priv *priv;
>> + struct jh7110_clk_pll_data *data;
>> + int ret;
>> + unsigned int idx;
>> +
>> + variant = of_device_get_match_data(&pdev->dev);
>> + if (!variant)
>> + return -ENOMEM;
>> +
>> + priv = devm_kzalloc(&pdev->dev, struct_size(priv, data, variant->pll_nums),
>> + GFP_KERNEL);
>> + if (!priv)
>> + return -ENOMEM;
>> +
>> + priv->dev = &pdev->dev;
>> + priv->syscon_regmap = syscon_node_to_regmap(priv->dev->of_node->parent);
>> + if (IS_ERR(priv->syscon_regmap))
>> + return PTR_ERR(priv->syscon_regmap);
>> +
>> + priv->pll_nums = variant->pll_nums;
>> + for (idx = 0; idx < priv->pll_nums; idx++) {
>> + struct clk_parent_data parents = {
>> + .index = 0,
>> + };
>> + struct clk_init_data init = {
>> + .name = variant->conf[idx].name,
>> + .ops = &jh7110_pll_ops,
>> + .parent_data = &parents,
>> + .num_parents = 1,
>> + .flags = 0,
>> + };
>> +
>> + data = &priv->data[idx];
>> + data->conf = variant->conf[idx];
>
> Why do you need to copy all this static data? Can't you just reference
> the static const version you already have?

Will use the address variable to reference it.

>
>> + data->hw.init = &init;
>> + data->idx = idx;
>> +
>> + ret = devm_clk_hw_register(&pdev->dev, &data->hw);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + return devm_of_clk_add_hw_provider(&pdev->dev, jh7110_pll_get, priv);
>> +}
>> +
>> +static const struct of_device_id jh7110_pll_match[] = {
>> + { .compatible = "starfive,jh7110-pll", .data = &jh7110_pll_variant },
>> + { /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, jh7110_pll_match);
>> +
>> +static struct platform_driver jh7110_pll_driver = {
>> + .driver = {
>> + .name = "clk-starfive-jh7110-pll",
>> + .of_match_table = jh7110_pll_match,
>> + },
>> +};
>> +builtin_platform_driver_probe(jh7110_pll_driver, jh7110_pll_probe);
>> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-pll.h b/drivers/clk/starfive/clk-starfive-jh7110-pll.h
>> new file mode 100644
>> index 000000000000..526f21670fe3
>> --- /dev/null
>> +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.h
>
> This header is never used outside of clk-starfive-jh7110-pll.c. Please
> just merge it into that file.

Will fix.

>
>> @@ -0,0 +1,331 @@
>> +/* SPDX-License-Identifier: GPL-2.0 OR MIT */
>> +/*
>> + * StarFive JH7110 PLL Clock Generator Driver
>> + *
>> + * Copyright (C) 2023 StarFive Technology Co., Ltd.
>> + */
>> +
>> +#ifndef _CLK_STARFIVE_JH7110_PLL_H_
>> +#define _CLK_STARFIVE_JH7110_PLL_H_
>> +
>> +#include <linux/bits.h>
>> +
>> +/* The decimal places are counted by expanding them by a factor of STARFIVE_PLL_FRAC_PATR_SIZE */
>> +#define STARFIVE_PLL_FRAC_PATR_SIZE 1000
>> +
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_OFFSET 0x18
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_SHIFT 24
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_MASK BIT(24)
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_OFFSET 0x18
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_SHIFT 25
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_MASK BIT(25)
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_OFFSET 0x1c
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_SHIFT 0
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_MASK GENMASK(11, 0)
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_OFFSET 0x20
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_SHIFT 0
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_MASK GENMASK(23, 0)
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_OFFSET 0x20
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_SHIFT 28
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_MASK GENMASK(29, 28)
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_OFFSET 0x24
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_SHIFT 0
>> +#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_MASK GENMASK(5, 0)
>> +
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_OFFSET 0x24
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_SHIFT 15
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_MASK BIT(15)
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_OFFSET 0x24
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_SHIFT 16
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_MASK BIT(16)
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_OFFSET 0x24
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_SHIFT 17
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_MASK GENMASK(28, 17)
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_OFFSET 0x28
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_SHIFT 0
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_MASK GENMASK(23, 0)
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_OFFSET 0x28
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_SHIFT 28
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_MASK GENMASK(29, 28)
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_OFFSET 0x2c
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_SHIFT 0
>> +#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_MASK GENMASK(5, 0)
>> +
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_OFFSET 0x2c
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_SHIFT 15
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_MASK BIT(15)
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_OFFSET 0x2c
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_SHIFT 16
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_MASK BIT(16)
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_OFFSET 0x2c
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_SHIFT 17
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_MASK GENMASK(28, 17)
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_OFFSET 0x30
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_SHIFT 0
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_MASK GENMASK(23, 0)
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_OFFSET 0x30
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_SHIFT 28
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_MASK GENMASK(29, 28)
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_OFFSET 0x34
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_SHIFT 0
>> +#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_MASK GENMASK(5, 0)
>> +
>> +#define JH7110_PLL(_idx, _name, _nums, _val) \
>> +[_idx] = { \
>> + .name = _name, \
>> + .offsets = { \
>> + .dacpd = STARFIVE_##_idx##_DACPD_OFFSET, \
>> + .dsmpd = STARFIVE_##_idx##_DSMPD_OFFSET, \
>> + .fbdiv = STARFIVE_##_idx##_FBDIV_OFFSET, \
>> + .frac = STARFIVE_##_idx##_FRAC_OFFSET, \
>> + .prediv = STARFIVE_##_idx##_PREDIV_OFFSET, \
>> + .postdiv1 = STARFIVE_##_idx##_POSTDIV1_OFFSET, \
>> + }, \
>> + .masks = { \
>> + .dacpd = STARFIVE_##_idx##_DACPD_MASK, \
>> + .dsmpd = STARFIVE_##_idx##_DSMPD_MASK, \
>> + .fbdiv = STARFIVE_##_idx##_FBDIV_MASK, \
>> + .frac = STARFIVE_##_idx##_FRAC_MASK, \
>> + .prediv = STARFIVE_##_idx##_PREDIV_MASK, \
>> + .postdiv1 = STARFIVE_##_idx##_POSTDIV1_MASK, \
>> + }, \
>> + .shifts = { \
>> + .dacpd = STARFIVE_##_idx##_DACPD_SHIFT, \
>> + .dsmpd = STARFIVE_##_idx##_DSMPD_SHIFT, \
>> + .fbdiv = STARFIVE_##_idx##_FBDIV_SHIFT, \
>> + .frac = STARFIVE_##_idx##_FRAC_SHIFT, \
>> + .prediv = STARFIVE_##_idx##_PREDIV_SHIFT, \
>> + .postdiv1 = STARFIVE_##_idx##_POSTDIV1_SHIFT, \
>> + }, \
>> + .preset_val_nums = _nums, \
>> + .preset_val = _val, \
>> +}
>> +
>> +struct jh7110_pll_syscon_offset {
>> + unsigned int dacpd;
>> + unsigned int dsmpd;
>> + unsigned int fbdiv;
>> + unsigned int frac;
>> + unsigned int prediv;
>> + unsigned int postdiv1;
>> +};
>> +
>> +struct jh7110_pll_syscon_mask {
>> + u32 dacpd;
>> + u32 dsmpd;
>> + u32 fbdiv;
>> + u32 frac;
>> + u32 prediv;
>> + u32 postdiv1;
>> +};
>> +
>> +struct jh7110_pll_syscon_shift {
>> + char dacpd;
>> + char dsmpd;
>> + char fbdiv;
>> + char frac;
>> + char prediv;
>> + char postdiv1;
>> +};
>> +
>> +struct jh7110_pll_syscon_val {
>> + unsigned long freq;
>> + u32 prediv;
>> + u32 fbdiv;
>> + u32 postdiv1;
>> +/* Both daxpd and dsmpd set 1 while integer mode */
>> +/* Both daxpd and dsmpd set 0 while fraction mode */
>> + u32 dacpd;
>> + u32 dsmpd;
>> +/* frac value should be decimals multiplied by 2^24 */
>> + u32 frac;
>> +};
>> +
>> +struct jh7110_pll_syscon_conf {
>> + char *name;
>> + struct jh7110_pll_syscon_offset offsets;
>> + struct jh7110_pll_syscon_mask masks;
>> + struct jh7110_pll_syscon_shift shifts;
>> + unsigned int preset_val_nums;
>> + const struct jh7110_pll_syscon_val *preset_val;
>> +};
>> +
>> +struct jh7110_clk_pll_data {
>> + struct clk_hw hw;
>> + unsigned int idx;
>> + unsigned int freq_select_idx;
>> + struct jh7110_pll_syscon_conf conf;
>> +};
>> +
>> +struct jh7110_clk_pll_priv {
>> + unsigned int pll_nums;
>> + struct device *dev;
>> + struct regmap *syscon_regmap;
>> + struct jh7110_clk_pll_data data[];
>> +};
>> +
>> +enum jh7110_pll0_freq_index {
>> + JH7110_PLL0_FREQ_375 = 0,
>> + JH7110_PLL0_FREQ_500,
>> + JH7110_PLL0_FREQ_625,
>> + JH7110_PLL0_FREQ_750,
>> + JH7110_PLL0_FREQ_875,
>> + JH7110_PLL0_FREQ_1000,
>> + JH7110_PLL0_FREQ_1250,
>> + JH7110_PLL0_FREQ_1375,
>> + JH7110_PLL0_FREQ_1500,
>> + JH7110_PLL0_FREQ_MAX
>> +};
>> +
>> +enum jh7110_pll1_freq_index {
>> + JH7110_PLL1_FREQ_1066 = 0,
>> + JH7110_PLL1_FREQ_1200,
>> + JH7110_PLL1_FREQ_1400,
>> + JH7110_PLL1_FREQ_1600,
>> + JH7110_PLL1_FREQ_MAX
>> +};
>> +
>> +enum jh7110_pll2_freq_index {
>> + JH7110_PLL2_FREQ_1188 = 0,
>> + JH7110_PLL2_FREQ_12288,
>> + JH7110_PLL2_FREQ_MAX
>> +};
>> +
>> +/*
>> + * Because the pll frequency is relatively fixed,
>> + * it cannot be set arbitrarily, so it needs a specific configuration.
>> + * PLL0 frequency should be multiple of 125MHz (USB frequency).
>> + */
>> +static const struct jh7110_pll_syscon_val
>> + jh7110_pll0_syscon_val_preset[] = {
>> + [JH7110_PLL0_FREQ_375] = {
>> + .freq = 375000000,
>> + .prediv = 8,
>> + .fbdiv = 125,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL0_FREQ_500] = {
>> + .freq = 500000000,
>> + .prediv = 6,
>> + .fbdiv = 125,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL0_FREQ_625] = {
>> + .freq = 625000000,
>> + .prediv = 24,
>> + .fbdiv = 625,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL0_FREQ_750] = {
>> + .freq = 750000000,
>> + .prediv = 4,
>> + .fbdiv = 125,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL0_FREQ_875] = {
>> + .freq = 875000000,
>> + .prediv = 24,
>> + .fbdiv = 875,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL0_FREQ_1000] = {
>> + .freq = 1000000000,
>> + .prediv = 3,
>> + .fbdiv = 125,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL0_FREQ_1250] = {
>> + .freq = 1250000000,
>> + .prediv = 12,
>> + .fbdiv = 625,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL0_FREQ_1375] = {
>> + .freq = 1375000000,
>> + .prediv = 24,
>> + .fbdiv = 1375,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL0_FREQ_1500] = {
>> + .freq = 1500000000,
>> + .prediv = 2,
>> + .fbdiv = 125,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> +};
>> +
>> +static const struct jh7110_pll_syscon_val
>> + jh7110_pll1_syscon_val_preset[] = {
>> + [JH7110_PLL1_FREQ_1066] = {
>> + .freq = 1066000000,
>> + .prediv = 12,
>> + .fbdiv = 533,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL1_FREQ_1200] = {
>> + .freq = 1200000000,
>> + .prediv = 1,
>> + .fbdiv = 50,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL1_FREQ_1400] = {
>> + .freq = 1400000000,
>> + .prediv = 6,
>> + .fbdiv = 350,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL1_FREQ_1600] = {
>> + .freq = 1600000000,
>> + .prediv = 3,
>> + .fbdiv = 200,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> +};
>> +
>> +static const struct jh7110_pll_syscon_val
>> + jh7110_pll2_syscon_val_preset[] = {
>> + [JH7110_PLL2_FREQ_1188] = {
>> + .freq = 1188000000,
>> + .prediv = 2,
>> + .fbdiv = 99,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> + [JH7110_PLL2_FREQ_12288] = {
>> + .freq = 1228800000,
>> + .prediv = 5,
>> + .fbdiv = 256,
>> + .postdiv1 = 1,
>> + .dacpd = 1,
>> + .dsmpd = 1,
>> + },
>> +};
>> +
>> +#endif
>> --
>> 2.25.1
>
> In general this driver is overly generic even though it is a driver
> specific to the JH7110 SoC. Rather than try to explain all the ways
> you can simplify it, I decided it would be easier to show you:
>
> https://github.com/esmil/linux/commit/9b7f325267c9a760eda6612c7ffbf22366790878
>
> It has all the same functionality, fixes all of the above and saves
> more than 100 lines of code, so please use that for your next
> revision.
>

Thanks for you suggestions. I will fix it by referring to these.

Best regards,
Xingyu Wu

2023-06-02 15:21:16

by Emil Renner Berthing

[permalink] [raw]
Subject: Re: [PATCH v4 2/7] clk: starfive: Add StarFive JH7110 PLL clock driver

On Fri, 2 Jun 2023 at 11:41, Xingyu Wu <[email protected]> wrote:
>
> On 2023/6/1 19:02, Emil Renner Berthing wrote:
> > Hi Xingyu,
> >
> > Thanks for working on this.
> >
> > On Fri, 12 May 2023 at 04:24, Xingyu Wu <[email protected]> wrote:
> >>
> >> Add driver for the StarFive JH7110 PLL clock controller
> >> and they work by reading and setting syscon registers.
> >>
> >> Signed-off-by: Xingyu Wu <[email protected]>
> >> ---
> >> MAINTAINERS | 6 +
> >> drivers/clk/starfive/Kconfig | 8 +
> >> drivers/clk/starfive/Makefile | 1 +
> >> .../clk/starfive/clk-starfive-jh7110-pll.c | 309 ++++++++++++++++
> >> .../clk/starfive/clk-starfive-jh7110-pll.h | 331 ++++++++++++++++++
> >> 5 files changed, 655 insertions(+)
> >> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.c
> >> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.h
> >>
> >> diff --git a/MAINTAINERS b/MAINTAINERS
> >> index 7e0b87d5aa2e..0fb4a703f66f 100644
> >> --- a/MAINTAINERS
> >> +++ b/MAINTAINERS
> >> @@ -20087,6 +20087,12 @@ S: Supported
> >> F: Documentation/devicetree/bindings/mmc/starfive*
> >> F: drivers/mmc/host/dw_mmc-starfive.c
> >>
> >> +STARFIVE JH7110 PLL CLOCK DRIVER
> >> +M: Xingyu Wu <[email protected]>
> >> +S: Supported
> >> +F: Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml
> >> +F: drivers/clk/starfive/clk-starfive-jh7110-pll.*
> >> +
> >> STARFIVE JH71X0 CLOCK DRIVERS
> >> M: Emil Renner Berthing <[email protected]>
> >> M: Hal Feng <[email protected]>
> >> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
> >> index 5d2333106f13..5195f7be5213 100644
> >> --- a/drivers/clk/starfive/Kconfig
> >> +++ b/drivers/clk/starfive/Kconfig
> >> @@ -21,6 +21,14 @@ config CLK_STARFIVE_JH7100_AUDIO
> >> Say Y or M here to support the audio clocks on the StarFive JH7100
> >> SoC.
> >>
> >> +config CLK_STARFIVE_JH7110_PLL
> >> + bool "StarFive JH7110 PLL clock support"
> >> + depends on ARCH_STARFIVE || COMPILE_TEST
> >> + default ARCH_STARFIVE
> >> + help
> >> + Say yes here to support the PLL clock controller on the
> >> + StarFive JH7110 SoC.
> >> +
> >> config CLK_STARFIVE_JH7110_SYS
> >> bool "StarFive JH7110 system clock support"
> >> depends on ARCH_STARFIVE || COMPILE_TEST
> >> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
> >> index f3df7d957b1e..b48e539e52b0 100644
> >> --- a/drivers/clk/starfive/Makefile
> >> +++ b/drivers/clk/starfive/Makefile
> >> @@ -4,5 +4,6 @@ obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk-starfive-jh71x0.o
> >> obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o
> >> obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
> >>
> >> +obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += clk-starfive-jh7110-pll.o
> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
> >> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-pll.c b/drivers/clk/starfive/clk-starfive-jh7110-pll.c
> >> new file mode 100644
> >> index 000000000000..f86deddd4bef
> >> --- /dev/null
> >> +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.c
> >> @@ -0,0 +1,309 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * StarFive JH7110 PLL Clock Generator Driver
> >> + *
> >> + * Copyright (C) 2023 StarFive Technology Co., Ltd.
> >> + *
> >> + * This driver is about to register JH7110 PLL clock generator and support ops.
> >> + * The JH7110 have three PLL clock, PLL0, PLL1 and PLL2.
> >> + * Each PLL clocks work in integer mode or fraction mode by some dividers,
> >> + * and the configuration registers and dividers are set in several syscon registers.
> >> + * The formula for calculating frequency is:
> >> + * Fvco = Fref * (NI + NF) / M / Q1
> >> + * Fref: OSC source clock rate
> >> + * NI: integer frequency dividing ratio of feedback divider, set by fbdiv[11:0].
> >> + * NF: fractional frequency dividing ratio, set by frac[23:0]. NF = frac[23:0] / 2^24 = 0 ~ 0.999.
> >> + * M: frequency dividing ratio of pre-divider, set by prediv[5:0].
> >> + * Q1: frequency dividing ratio of post divider, set by postdiv1[1:0], Q1= 1,2,4,8.
> >> + */
> >> +
> >> +#include <linux/clk-provider.h>
> >> +#include <linux/debugfs.h>
> >> +#include <linux/device.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/mfd/syscon.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/regmap.h>
> >> +
> >> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
> >> +
> >> +#include "clk-starfive-jh7110-pll.h"
> >> +
> >> +struct jh7110_pll_conf_variant {
> >> + unsigned int pll_nums;
> >> + struct jh7110_pll_syscon_conf conf[];
> >> +};
> >> +
> >> +static const struct jh7110_pll_conf_variant jh7110_pll_variant = {
> >> + .pll_nums = JH7110_PLLCLK_END,
> >> + .conf = {
> >> + JH7110_PLL(JH7110_CLK_PLL0_OUT, "pll0_out",
> >> + JH7110_PLL0_FREQ_MAX, jh7110_pll0_syscon_val_preset),
> >> + JH7110_PLL(JH7110_CLK_PLL1_OUT, "pll1_out",
> >> + JH7110_PLL1_FREQ_MAX, jh7110_pll1_syscon_val_preset),
> >> + JH7110_PLL(JH7110_CLK_PLL2_OUT, "pll2_out",
> >> + JH7110_PLL2_FREQ_MAX, jh7110_pll2_syscon_val_preset),
> >> + },
> >> +};
> >> +
> >> +static struct jh7110_clk_pll_data *jh7110_pll_data_from(struct clk_hw *hw)
> >> +{
> >> + return container_of(hw, struct jh7110_clk_pll_data, hw);
> >> +}
> >> +
> >> +static struct jh7110_clk_pll_priv *jh7110_pll_priv_from(struct jh7110_clk_pll_data *data)
> >> +{
> >> + return container_of(data, struct jh7110_clk_pll_priv, data[data->idx]);
> >> +}
> >> +
> >> +/* Read register value from syscon and calculate PLL(x) frequency */
> >> +static unsigned long jh7110_pll_get_freq(struct jh7110_clk_pll_data *data,
> >> + unsigned long parent_rate)
> >> +{
> >> + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
> >> + struct jh7110_pll_syscon_offset *offset = &data->conf.offsets;
> >> + struct jh7110_pll_syscon_mask *mask = &data->conf.masks;
> >> + struct jh7110_pll_syscon_shift *shift = &data->conf.shifts;
> >> + unsigned long frac_cal;
> >> + u32 dacpd;
> >> + u32 dsmpd;
> >> + u32 fbdiv;
> >> + u32 prediv;
> >> + u32 postdiv1;
> >> + u32 frac;
> >> + u32 reg_val;
> >> +
> >> + regmap_read(priv->syscon_regmap, offset->dacpd, &reg_val);
> >> + dacpd = (reg_val & mask->dacpd) >> shift->dacpd;
> >> +
> >> + regmap_read(priv->syscon_regmap, offset->dsmpd, &reg_val);
> >> + dsmpd = (reg_val & mask->dsmpd) >> shift->dsmpd;
> >> +
> >> + regmap_read(priv->syscon_regmap, offset->fbdiv, &reg_val);
> >> + fbdiv = (reg_val & mask->fbdiv) >> shift->fbdiv;
> >> +
> >> + regmap_read(priv->syscon_regmap, offset->prediv, &reg_val);
> >> + prediv = (reg_val & mask->prediv) >> shift->prediv;
> >> +
> >> + regmap_read(priv->syscon_regmap, offset->postdiv1, &reg_val);
> >> + /* postdiv1 = 2 ^ reg_val */
> >> + postdiv1 = 1 << ((reg_val & mask->postdiv1) >> shift->postdiv1);
> >> +
> >> + regmap_read(priv->syscon_regmap, offset->frac, &reg_val);
> >> + frac = (reg_val & mask->frac) >> shift->frac;
> >> +
> >> + /*
> >> + * Integer Mode (Both 1) or Fraction Mode (Both 0).
> >> + * And the decimal places are counted by expanding them by
> >> + * a factor of STARFIVE_PLL_FRAC_PATR_SIZE.
> >> + */
> >> + if (dacpd == 1 && dsmpd == 1)
> >> + frac_cal = 0;
> >> + else if (dacpd == 0 && dsmpd == 0)
> >> + frac_cal = (unsigned long)frac * STARFIVE_PLL_FRAC_PATR_SIZE / (1 << 24);
> >> + else
> >> + return 0;
> >> +
> >> + /* Fvco = Fref * (NI + NF) / M / Q1 */
> >> + return (parent_rate / STARFIVE_PLL_FRAC_PATR_SIZE *
> >> + (fbdiv * STARFIVE_PLL_FRAC_PATR_SIZE + frac_cal) / prediv / postdiv1);
> >
> > You have
> >
> > rate = parent * (fbdiv + frac/2^24) / prediv / 2^postdiv1regval
> >
> > Where postdiv1regval is the raw postdiv1 register value. This can also
> > be written
> >
> > rate = (parent * fbdiv + parent * frac / 2^24) / (prediv * 2^postdiv1regval)
> >
> > so how about
> >
> > if (dacpd == 1 && dsmpd == 1)
> > rate = 0;
> > else if (dacpd == 0 && dsmpd == 0)
> > rate = parent * frac / (1UL << 24);
> > else
> > return 0;
> >
> > rate += parent * fbdiv;
> > rate /= prediv << postdiv1regval;
> > return rate;
> >
> Thanks for you suggestions. I will modify this.
> And I have a question, should I keep the 'STARFIVE_PLL_FRAC_PATR_SIZE ' as integer to calculate the fractional part of 'frac'?

Again, please just use the version I linked. It has all this taken
care of already:

https://github.com/esmil/linux/commit/9b7f325267c9a760eda6612c7ffbf22366790878

> >> +}
> >> +
> >> +static unsigned long jh7110_pll_rate_sub_fabs(unsigned long rate1, unsigned long rate2)
> >> +{
> >> + return rate1 > rate2 ? (rate1 - rate2) : (rate2 - rate1);
> >> +}
> >> +
> >> +/* Select the appropriate frequency from the already configured registers value */
> >> +static void jh7110_pll_select_near_freq_id(struct jh7110_clk_pll_data *data,
> >> + unsigned long rate)
> >> +{
> >> + const struct jh7110_pll_syscon_val *val;
> >> + unsigned int id;
> >> + unsigned long rate_diff;
> >> +
> >> + /* compare the frequency one by one from small to large in order */
> >> + for (id = 0; id < data->conf.preset_val_nums; id++) {
> >> + val = &data->conf.preset_val[id];
> >> +
> >> + if (rate == val->freq)
> >> + goto match_end;
> >> +
> >> + /* select near frequency */
> >
> > Is there any reason we can't just pick the highest rate <= the
> > requested rate, just like we do for the regular clock dividers?
>
> It sounds like rounding down. This is a good idea and I will fix it.
>
> >
> >> + if (rate < val->freq) {
> >> + /* The last frequency is closer to the target rate than this time. */
> >> + if (id > 0)
> >> + if (rate_diff < jh7110_pll_rate_sub_fabs(rate, val->freq))
> >> + id--;
> >> +
> >> + goto match_end;
> >> + } else {
> >> + rate_diff = jh7110_pll_rate_sub_fabs(rate, val->freq);
> >> + }
> >> + }
> >> +
> >> +match_end:
> >> + data->freq_select_idx = id;
> >> +}
> >> +
> >> +static int jh7110_pll_set_freq_syscon(struct jh7110_clk_pll_data *data)
> >> +{
> >> + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
> >> + struct jh7110_pll_syscon_offset *offset = &data->conf.offsets;
> >> + struct jh7110_pll_syscon_mask *mask = &data->conf.masks;
> >> + struct jh7110_pll_syscon_shift *shift = &data->conf.shifts;
> >> + const struct jh7110_pll_syscon_val *val = &data->conf.preset_val[data->freq_select_idx];
> >> +
> >> + /* frac: Integer Mode (Both 1) or Fraction Mode (Both 0) */
> >> + if (val->dacpd == 0 && val->dsmpd == 0)
> >> + regmap_update_bits(priv->syscon_regmap, offset->frac, mask->frac,
> >> + (val->frac << shift->frac));
> >> + else if (val->dacpd != val->dsmpd)
> >> + return -EINVAL;
> >> +
> >> + /* fbdiv value should be 8 to 4095 */
> >> + if (val->fbdiv < 8)
> >> + return -EINVAL;
> >> +
> >> + regmap_update_bits(priv->syscon_regmap, offset->dacpd, mask->dacpd,
> >> + (val->dacpd << shift->dacpd));
> >> + regmap_update_bits(priv->syscon_regmap, offset->dsmpd, mask->dsmpd,
> >> + (val->dsmpd << shift->dsmpd));
> >> + regmap_update_bits(priv->syscon_regmap, offset->prediv, mask->prediv,
> >> + (val->prediv << shift->prediv));
> >> + regmap_update_bits(priv->syscon_regmap, offset->fbdiv, mask->fbdiv,
> >> + (val->fbdiv << shift->fbdiv));
> >> + regmap_update_bits(priv->syscon_regmap, offset->postdiv1, mask->postdiv1,
> >> + ((val->postdiv1 >> 1) << shift->postdiv1));
> >
> > It seems like you're storing the divider and not the register value in
> > the presets. Since the divider is 2^regval it means you need to write
> > log2 (divider) into the register, but here you store divider >> 1 aka
> > divider / 2.
>
> Oh, It's my mistake. The values of post divider are 1,2,4, and 8, which pass when it equals 1, 2, and 4, but is failed when it equals 8.
>
> >
> > I'd strongly suggest you just store the register value, and just use
> > 2^regval when you need the divider. This way you won't need to ever
> > calculate log2 of anything.
>
> Great. Using the register value directly avoid some calculations.
>
> >
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static unsigned long jh7110_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> >> +{
> >> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
> >> +
> >> + return jh7110_pll_get_freq(data, parent_rate);
> >> +}
> >> +
> >> +static int jh7110_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
> >> +{
> >> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
> >
> > What happens if the parent rate != 24MHz? Then all your presets will
> > be wrong. We probably want to guard against that.
>
> Will fix and add a check for parent rate.
>
> >
> >> + jh7110_pll_select_near_freq_id(data, req->rate);
> >> + req->rate = data->conf.preset_val[data->freq_select_idx].freq;
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int jh7110_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> >> + unsigned long parent_rate)
> >> +{
> >> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
> >> +
> >> + return jh7110_pll_set_freq_syscon(data);
> >> +}
> >> +
> >> +#ifdef CONFIG_DEBUG_FS
> >> +static void jh7110_pll_debug_init(struct clk_hw *hw, struct dentry *dentry)
> >> +{
> >> + static const struct debugfs_reg32 jh7110_clk_pll_reg = {
> >> + .name = "CTRL",
> >> + .offset = 0,
> >> + };
> >> + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
> >> + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
> >> + struct debugfs_regset32 *regset;
> >> +
> >> + regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL);
> >> + if (!regset)
> >> + return;
> >> +
> >> + regset->regs = &jh7110_clk_pll_reg;
> >> + regset->nregs = 1;
> >
> > You never set regset->base, so this function creates a registers file
> > that just shows the contents of address 0. I don't think you tested
> > this.
>
> Will add the regset->base.
>
> >
> >> +
> >> + debugfs_create_regset32("registers", 0400, dentry, regset);
> >> +}
> >> +#else
> >> +#define jh7110_pll_debug_init NULL
> >> +#endif
> >> +
> >> +static const struct clk_ops jh7110_pll_ops = {
> >> + .recalc_rate = jh7110_pll_recalc_rate,
> >> + .determine_rate = jh7110_pll_determine_rate,
> >> + .set_rate = jh7110_pll_set_rate,
> >> + .debug_init = jh7110_pll_debug_init,
> >> +};
> >> +
> >> +static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data)
> >> +{
> >> + struct jh7110_clk_pll_priv *priv = data;
> >> + unsigned int idx = clkspec->args[0];
> >> +
> >> + if (idx < priv->pll_nums)
> >> + return &priv->data[idx].hw;
> >> +
> >> + return ERR_PTR(-EINVAL);
> >> +}
> >> +
> >> +static int jh7110_pll_probe(struct platform_device *pdev)
> >> +{
> >> + const struct jh7110_pll_conf_variant *variant;
> >> + struct jh7110_clk_pll_priv *priv;
> >> + struct jh7110_clk_pll_data *data;
> >> + int ret;
> >> + unsigned int idx;
> >> +
> >> + variant = of_device_get_match_data(&pdev->dev);
> >> + if (!variant)
> >> + return -ENOMEM;
> >> +
> >> + priv = devm_kzalloc(&pdev->dev, struct_size(priv, data, variant->pll_nums),
> >> + GFP_KERNEL);
> >> + if (!priv)
> >> + return -ENOMEM;
> >> +
> >> + priv->dev = &pdev->dev;
> >> + priv->syscon_regmap = syscon_node_to_regmap(priv->dev->of_node->parent);
> >> + if (IS_ERR(priv->syscon_regmap))
> >> + return PTR_ERR(priv->syscon_regmap);
> >> +
> >> + priv->pll_nums = variant->pll_nums;
> >> + for (idx = 0; idx < priv->pll_nums; idx++) {
> >> + struct clk_parent_data parents = {
> >> + .index = 0,
> >> + };
> >> + struct clk_init_data init = {
> >> + .name = variant->conf[idx].name,
> >> + .ops = &jh7110_pll_ops,
> >> + .parent_data = &parents,
> >> + .num_parents = 1,
> >> + .flags = 0,
> >> + };
> >> +
> >> + data = &priv->data[idx];
> >> + data->conf = variant->conf[idx];
> >
> > Why do you need to copy all this static data? Can't you just reference
> > the static const version you already have?
>
> Will use the address variable to reference it.
>
> >
> >> + data->hw.init = &init;
> >> + data->idx = idx;
> >> +
> >> + ret = devm_clk_hw_register(&pdev->dev, &data->hw);
> >> + if (ret)
> >> + return ret;
> >> + }
> >> +
> >> + return devm_of_clk_add_hw_provider(&pdev->dev, jh7110_pll_get, priv);
> >> +}
> >> +
> >> +static const struct of_device_id jh7110_pll_match[] = {
> >> + { .compatible = "starfive,jh7110-pll", .data = &jh7110_pll_variant },
> >> + { /* sentinel */ }
> >> +};
> >> +MODULE_DEVICE_TABLE(of, jh7110_pll_match);
> >> +
> >> +static struct platform_driver jh7110_pll_driver = {
> >> + .driver = {
> >> + .name = "clk-starfive-jh7110-pll",
> >> + .of_match_table = jh7110_pll_match,
> >> + },
> >> +};
> >> +builtin_platform_driver_probe(jh7110_pll_driver, jh7110_pll_probe);
> >> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-pll.h b/drivers/clk/starfive/clk-starfive-jh7110-pll.h
> >> new file mode 100644
> >> index 000000000000..526f21670fe3
> >> --- /dev/null
> >> +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.h
> >
> > This header is never used outside of clk-starfive-jh7110-pll.c. Please
> > just merge it into that file.
>
> Will fix.
>
> >
> >> @@ -0,0 +1,331 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 OR MIT */
> >> +/*
> >> + * StarFive JH7110 PLL Clock Generator Driver
> >> + *
> >> + * Copyright (C) 2023 StarFive Technology Co., Ltd.
> >> + */
> >> +
> >> +#ifndef _CLK_STARFIVE_JH7110_PLL_H_
> >> +#define _CLK_STARFIVE_JH7110_PLL_H_
> >> +
> >> +#include <linux/bits.h>
> >> +
> >> +/* The decimal places are counted by expanding them by a factor of STARFIVE_PLL_FRAC_PATR_SIZE */
> >> +#define STARFIVE_PLL_FRAC_PATR_SIZE 1000
> >> +
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_OFFSET 0x18
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_SHIFT 24
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DACPD_MASK BIT(24)
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_OFFSET 0x18
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_SHIFT 25
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_DSMPD_MASK BIT(25)
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_OFFSET 0x1c
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_SHIFT 0
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FBDIV_MASK GENMASK(11, 0)
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_OFFSET 0x20
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_SHIFT 0
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_FRAC_MASK GENMASK(23, 0)
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_OFFSET 0x20
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_SHIFT 28
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_POSTDIV1_MASK GENMASK(29, 28)
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_OFFSET 0x24
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_SHIFT 0
> >> +#define STARFIVE_JH7110_CLK_PLL0_OUT_PREDIV_MASK GENMASK(5, 0)
> >> +
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_OFFSET 0x24
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_SHIFT 15
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DACPD_MASK BIT(15)
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_OFFSET 0x24
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_SHIFT 16
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_DSMPD_MASK BIT(16)
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_OFFSET 0x24
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_SHIFT 17
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FBDIV_MASK GENMASK(28, 17)
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_OFFSET 0x28
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_SHIFT 0
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_FRAC_MASK GENMASK(23, 0)
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_OFFSET 0x28
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_SHIFT 28
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_POSTDIV1_MASK GENMASK(29, 28)
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_OFFSET 0x2c
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_SHIFT 0
> >> +#define STARFIVE_JH7110_CLK_PLL1_OUT_PREDIV_MASK GENMASK(5, 0)
> >> +
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_OFFSET 0x2c
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_SHIFT 15
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DACPD_MASK BIT(15)
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_OFFSET 0x2c
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_SHIFT 16
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_DSMPD_MASK BIT(16)
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_OFFSET 0x2c
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_SHIFT 17
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FBDIV_MASK GENMASK(28, 17)
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_OFFSET 0x30
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_SHIFT 0
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_FRAC_MASK GENMASK(23, 0)
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_OFFSET 0x30
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_SHIFT 28
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_POSTDIV1_MASK GENMASK(29, 28)
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_OFFSET 0x34
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_SHIFT 0
> >> +#define STARFIVE_JH7110_CLK_PLL2_OUT_PREDIV_MASK GENMASK(5, 0)
> >> +
> >> +#define JH7110_PLL(_idx, _name, _nums, _val) \
> >> +[_idx] = { \
> >> + .name = _name, \
> >> + .offsets = { \
> >> + .dacpd = STARFIVE_##_idx##_DACPD_OFFSET, \
> >> + .dsmpd = STARFIVE_##_idx##_DSMPD_OFFSET, \
> >> + .fbdiv = STARFIVE_##_idx##_FBDIV_OFFSET, \
> >> + .frac = STARFIVE_##_idx##_FRAC_OFFSET, \
> >> + .prediv = STARFIVE_##_idx##_PREDIV_OFFSET, \
> >> + .postdiv1 = STARFIVE_##_idx##_POSTDIV1_OFFSET, \
> >> + }, \
> >> + .masks = { \
> >> + .dacpd = STARFIVE_##_idx##_DACPD_MASK, \
> >> + .dsmpd = STARFIVE_##_idx##_DSMPD_MASK, \
> >> + .fbdiv = STARFIVE_##_idx##_FBDIV_MASK, \
> >> + .frac = STARFIVE_##_idx##_FRAC_MASK, \
> >> + .prediv = STARFIVE_##_idx##_PREDIV_MASK, \
> >> + .postdiv1 = STARFIVE_##_idx##_POSTDIV1_MASK, \
> >> + }, \
> >> + .shifts = { \
> >> + .dacpd = STARFIVE_##_idx##_DACPD_SHIFT, \
> >> + .dsmpd = STARFIVE_##_idx##_DSMPD_SHIFT, \
> >> + .fbdiv = STARFIVE_##_idx##_FBDIV_SHIFT, \
> >> + .frac = STARFIVE_##_idx##_FRAC_SHIFT, \
> >> + .prediv = STARFIVE_##_idx##_PREDIV_SHIFT, \
> >> + .postdiv1 = STARFIVE_##_idx##_POSTDIV1_SHIFT, \
> >> + }, \
> >> + .preset_val_nums = _nums, \
> >> + .preset_val = _val, \
> >> +}
> >> +
> >> +struct jh7110_pll_syscon_offset {
> >> + unsigned int dacpd;
> >> + unsigned int dsmpd;
> >> + unsigned int fbdiv;
> >> + unsigned int frac;
> >> + unsigned int prediv;
> >> + unsigned int postdiv1;
> >> +};
> >> +
> >> +struct jh7110_pll_syscon_mask {
> >> + u32 dacpd;
> >> + u32 dsmpd;
> >> + u32 fbdiv;
> >> + u32 frac;
> >> + u32 prediv;
> >> + u32 postdiv1;
> >> +};
> >> +
> >> +struct jh7110_pll_syscon_shift {
> >> + char dacpd;
> >> + char dsmpd;
> >> + char fbdiv;
> >> + char frac;
> >> + char prediv;
> >> + char postdiv1;
> >> +};
> >> +
> >> +struct jh7110_pll_syscon_val {
> >> + unsigned long freq;
> >> + u32 prediv;
> >> + u32 fbdiv;
> >> + u32 postdiv1;
> >> +/* Both daxpd and dsmpd set 1 while integer mode */
> >> +/* Both daxpd and dsmpd set 0 while fraction mode */
> >> + u32 dacpd;
> >> + u32 dsmpd;
> >> +/* frac value should be decimals multiplied by 2^24 */
> >> + u32 frac;
> >> +};
> >> +
> >> +struct jh7110_pll_syscon_conf {
> >> + char *name;
> >> + struct jh7110_pll_syscon_offset offsets;
> >> + struct jh7110_pll_syscon_mask masks;
> >> + struct jh7110_pll_syscon_shift shifts;
> >> + unsigned int preset_val_nums;
> >> + const struct jh7110_pll_syscon_val *preset_val;
> >> +};
> >> +
> >> +struct jh7110_clk_pll_data {
> >> + struct clk_hw hw;
> >> + unsigned int idx;
> >> + unsigned int freq_select_idx;
> >> + struct jh7110_pll_syscon_conf conf;
> >> +};
> >> +
> >> +struct jh7110_clk_pll_priv {
> >> + unsigned int pll_nums;
> >> + struct device *dev;
> >> + struct regmap *syscon_regmap;
> >> + struct jh7110_clk_pll_data data[];
> >> +};
> >> +
> >> +enum jh7110_pll0_freq_index {
> >> + JH7110_PLL0_FREQ_375 = 0,
> >> + JH7110_PLL0_FREQ_500,
> >> + JH7110_PLL0_FREQ_625,
> >> + JH7110_PLL0_FREQ_750,
> >> + JH7110_PLL0_FREQ_875,
> >> + JH7110_PLL0_FREQ_1000,
> >> + JH7110_PLL0_FREQ_1250,
> >> + JH7110_PLL0_FREQ_1375,
> >> + JH7110_PLL0_FREQ_1500,
> >> + JH7110_PLL0_FREQ_MAX
> >> +};
> >> +
> >> +enum jh7110_pll1_freq_index {
> >> + JH7110_PLL1_FREQ_1066 = 0,
> >> + JH7110_PLL1_FREQ_1200,
> >> + JH7110_PLL1_FREQ_1400,
> >> + JH7110_PLL1_FREQ_1600,
> >> + JH7110_PLL1_FREQ_MAX
> >> +};
> >> +
> >> +enum jh7110_pll2_freq_index {
> >> + JH7110_PLL2_FREQ_1188 = 0,
> >> + JH7110_PLL2_FREQ_12288,
> >> + JH7110_PLL2_FREQ_MAX
> >> +};
> >> +
> >> +/*
> >> + * Because the pll frequency is relatively fixed,
> >> + * it cannot be set arbitrarily, so it needs a specific configuration.
> >> + * PLL0 frequency should be multiple of 125MHz (USB frequency).
> >> + */
> >> +static const struct jh7110_pll_syscon_val
> >> + jh7110_pll0_syscon_val_preset[] = {
> >> + [JH7110_PLL0_FREQ_375] = {
> >> + .freq = 375000000,
> >> + .prediv = 8,
> >> + .fbdiv = 125,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL0_FREQ_500] = {
> >> + .freq = 500000000,
> >> + .prediv = 6,
> >> + .fbdiv = 125,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL0_FREQ_625] = {
> >> + .freq = 625000000,
> >> + .prediv = 24,
> >> + .fbdiv = 625,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL0_FREQ_750] = {
> >> + .freq = 750000000,
> >> + .prediv = 4,
> >> + .fbdiv = 125,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL0_FREQ_875] = {
> >> + .freq = 875000000,
> >> + .prediv = 24,
> >> + .fbdiv = 875,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL0_FREQ_1000] = {
> >> + .freq = 1000000000,
> >> + .prediv = 3,
> >> + .fbdiv = 125,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL0_FREQ_1250] = {
> >> + .freq = 1250000000,
> >> + .prediv = 12,
> >> + .fbdiv = 625,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL0_FREQ_1375] = {
> >> + .freq = 1375000000,
> >> + .prediv = 24,
> >> + .fbdiv = 1375,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL0_FREQ_1500] = {
> >> + .freq = 1500000000,
> >> + .prediv = 2,
> >> + .fbdiv = 125,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> +};
> >> +
> >> +static const struct jh7110_pll_syscon_val
> >> + jh7110_pll1_syscon_val_preset[] = {
> >> + [JH7110_PLL1_FREQ_1066] = {
> >> + .freq = 1066000000,
> >> + .prediv = 12,
> >> + .fbdiv = 533,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL1_FREQ_1200] = {
> >> + .freq = 1200000000,
> >> + .prediv = 1,
> >> + .fbdiv = 50,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL1_FREQ_1400] = {
> >> + .freq = 1400000000,
> >> + .prediv = 6,
> >> + .fbdiv = 350,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL1_FREQ_1600] = {
> >> + .freq = 1600000000,
> >> + .prediv = 3,
> >> + .fbdiv = 200,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> +};
> >> +
> >> +static const struct jh7110_pll_syscon_val
> >> + jh7110_pll2_syscon_val_preset[] = {
> >> + [JH7110_PLL2_FREQ_1188] = {
> >> + .freq = 1188000000,
> >> + .prediv = 2,
> >> + .fbdiv = 99,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> + [JH7110_PLL2_FREQ_12288] = {
> >> + .freq = 1228800000,
> >> + .prediv = 5,
> >> + .fbdiv = 256,
> >> + .postdiv1 = 1,
> >> + .dacpd = 1,
> >> + .dsmpd = 1,
> >> + },
> >> +};
> >> +
> >> +#endif
> >> --
> >> 2.25.1
> >
> > In general this driver is overly generic even though it is a driver
> > specific to the JH7110 SoC. Rather than try to explain all the ways
> > you can simplify it, I decided it would be easier to show you:
> >
> > https://github.com/esmil/linux/commit/9b7f325267c9a760eda6612c7ffbf22366790878
> >
> > It has all the same functionality, fixes all of the above and saves
> > more than 100 lines of code, so please use that for your next
> > revision.
> >
>
> Thanks for you suggestions. I will fix it by referring to these.
>
> Best regards,
> Xingyu Wu

2023-06-02 16:47:41

by Torsten Duwe

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Tue, 23 May 2023 10:56:43 +0800
Xingyu Wu <[email protected]> wrote:

> On 2023/5/19 22:16, Conor Dooley wrote:
> > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
> >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
> >> [...]
> >> > #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
> >> > #define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
> >> >
> >> > +/* PLL clocks */
> >> > +#define JH7110_CLK_PLL0_OUT 0
> >> > +#define JH7110_CLK_PLL1_OUT 1
> >> > +#define JH7110_CLK_PLL2_OUT 2
> >>
> >> In U-Boot commit 58c9c60b Yanhong Wang added:
> >>
> >> +
> >> +#define JH7110_SYSCLK_PLL0_OUT 190
> >> +#define JH7110_SYSCLK_PLL1_OUT 191
> >> +#define JH7110_SYSCLK_PLL2_OUT 192
> >> +
> >> +#define JH7110_SYSCLK_END 193
> >>
> >> in that respective file.
> >>
> >> > +#define JH7110_PLLCLK_END 3
> >> > +
> >> > /* SYSCRG clocks */
> >> > #define JH7110_SYSCLK_CPU_ROOT 0
> >>
> >> If the symbolic names referred to the same items, would it be possible
> >> to keep the two files in sync somehow?
> >
> > Ohh, that's not good.. If you pass the U-Boot dtb to Linux it won't
> > understand the numbering. The headers are part of the dt-binding :/
>
> Because PLL driver is separated from SYSCRG drivers in Linux,

Can you _please_ point me at that "PLL driver" "in Linux" ?
I seem to be unable to find it. All I can see is a stub in
drivers/clk/starfive/clk-starfive-jh7110-sys.c, which simply
sets the PLLs to 1000, 1066 and 1188 MHz fixed, respectively.

The comment above says

| They will be dropped and registered in the PLL clock driver instead.

and that's the one I'm looking for.

Thanks,

Torsten

2023-06-02 17:03:26

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Fri, Jun 02, 2023 at 06:39:22PM +0200, Torsten Duwe wrote:
> On Tue, 23 May 2023 10:56:43 +0800
> Xingyu Wu <[email protected]> wrote:
>
> > On 2023/5/19 22:16, Conor Dooley wrote:
> > > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe wrote:
> > >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
> > >> [...]
> > >> > #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
> > >> > #define __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__
> > >> >
> > >> > +/* PLL clocks */
> > >> > +#define JH7110_CLK_PLL0_OUT 0
> > >> > +#define JH7110_CLK_PLL1_OUT 1
> > >> > +#define JH7110_CLK_PLL2_OUT 2
> > >>
> > >> In U-Boot commit 58c9c60b Yanhong Wang added:
> > >>
> > >> +
> > >> +#define JH7110_SYSCLK_PLL0_OUT 190
> > >> +#define JH7110_SYSCLK_PLL1_OUT 191
> > >> +#define JH7110_SYSCLK_PLL2_OUT 192
> > >> +
> > >> +#define JH7110_SYSCLK_END 193
> > >>
> > >> in that respective file.
> > >>
> > >> > +#define JH7110_PLLCLK_END 3
> > >> > +
> > >> > /* SYSCRG clocks */
> > >> > #define JH7110_SYSCLK_CPU_ROOT 0
> > >>
> > >> If the symbolic names referred to the same items, would it be possible
> > >> to keep the two files in sync somehow?
> > >
> > > Ohh, that's not good.. If you pass the U-Boot dtb to Linux it won't
> > > understand the numbering. The headers are part of the dt-binding :/
> >
> > Because PLL driver is separated from SYSCRG drivers in Linux,
>
> Can you _please_ point me at that "PLL driver" "in Linux" ?

It's patch 2 in this series:
https://lore.kernel.org/linux-riscv/[email protected]/T/#m4b2d74c36b3bb961a1187ec5cda1a0a0de875f0e

HTH,
Conor.

> I seem to be unable to find it. All I can see is a stub in
> drivers/clk/starfive/clk-starfive-jh7110-sys.c, which simply
> sets the PLLs to 1000, 1066 and 1188 MHz fixed, respectively.
>
> The comment above says
>
> | They will be dropped and registered in the PLL clock driver instead.
>
> and that's the one I'm looking for.
>
> Thanks,
>
> Torsten


Attachments:
(No filename) (2.11 kB)
signature.asc (235.00 B)
Download all attachments

2023-06-02 17:28:37

by Torsten Duwe

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Fri, Jun 02, 2023 at 05:43:25PM +0100, Conor Dooley wrote:
> >
> > Can you _please_ point me at that "PLL driver" "in Linux" ?
>
> It's patch 2 in this series:
> https://lore.kernel.org/linux-riscv/[email protected]/T/#m4b2d74c36b3bb961a1187ec5cda1a0a0de875f0e
>
Unfortunately, it's not, AFAICS. I'm looking for the driver that
will control the PLLs' parameters, grepping for "pll" should yield
results, to start with. The thing should act on the SYS_SYSCON iomem,
at 0x13030000. Ideally, a DT node should point it there...

Torsten




2023-06-02 17:31:26

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Fri, Jun 02, 2023 at 06:57:13PM +0200, Torsten Duwe wrote:
> On Fri, Jun 02, 2023 at 05:43:25PM +0100, Conor Dooley wrote:
> > >
> > > Can you _please_ point me at that "PLL driver" "in Linux" ?
> >
> > It's patch 2 in this series:
> > https://lore.kernel.org/linux-riscv/[email protected]/T/#m4b2d74c36b3bb961a1187ec5cda1a0a0de875f0e
> >
> Unfortunately, it's not, AFAICS. I'm looking for the driver that
> will control the PLLs' parameters, grepping for "pll" should yield
> results, to start with. The thing should act on the SYS_SYSCON iomem,
> at 0x13030000. Ideally, a DT node should point it there...

The driver binds against a child node of the syscon @ 1303_0000:
https://lore.kernel.org/linux-riscv/[email protected]/T/#m882de9210850eb6f871cafc3418f3202ba915de8

Am I missing something?

Cheers,
Conor.


Attachments:
(No filename) (904.00 B)
signature.asc (235.00 B)
Download all attachments

2023-06-02 23:09:19

by Torsten Duwe

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On Fri, Jun 02, 2023 at 05:59:29PM +0100, Conor Dooley wrote:
> On Fri, Jun 02, 2023 at 06:57:13PM +0200, Torsten Duwe wrote:
> > On Fri, Jun 02, 2023 at 05:43:25PM +0100, Conor Dooley wrote:
> > > >
> > > > Can you _please_ point me at that "PLL driver" "in Linux" ?
> > >
> > > It's patch 2 in this series:
> > > https://lore.kernel.org/linux-riscv/[email protected]/T/#m4b2d74c36b3bb961a1187ec5cda1a0a0de875f0e
> > >
> > Unfortunately, it's not, AFAICS. I'm looking for the driver that
> > will control the PLLs' parameters, grepping for "pll" should yield
> > results, to start with. The thing should act on the SYS_SYSCON iomem,
> > at 0x13030000. Ideally, a DT node should point it there...
>
> The driver binds against a child node of the syscon @ 1303_0000:
> https://lore.kernel.org/linux-riscv/[email protected]/T/#m882de9210850eb6f871cafc3418f3202ba915de8
>
> Am I missing something?

No, you're right. Seems I took a wrong turn somewhere. I prefer
patchwork, where available, and probably got into the wrong series.
Found the correct one:

https://patchwork.kernel.org/project/linux-riscv/patch/[email protected]/

Now only the device tree needs to match against that, and U-Boot
needs to remain still functional...

Thanks and sorry for the noise.

Torsten



2023-06-12 03:32:39

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v4 1/7] dt-bindings: clock: Add StarFive JH7110 PLL clock generator

On 2023/5/26 20:23, Conor Dooley wrote:
> On Fri, May 26, 2023 at 09:34:32AM +0200, Torsten Duwe wrote:
>> On Wed, 24 May 2023 11:19:48 +0100
>> Conor Dooley <[email protected]> wrote:
>>
>> > On Wed, May 24, 2023 at 05:00:02PM +0800, Xingyu Wu wrote:
>> > > On 2023/5/23 19:28, Conor Dooley wrote:
>> > > > On Tue, May 23, 2023 at 01:10:06PM +0200, Torsten Duwe wrote:
>> > > >> On Tue, 23 May 2023 09:28:39 +0100
>> > > >> Conor Dooley <[email protected]> wrote:
>> > > >>
>> > > >> > On Tue, May 23, 2023 at 10:56:43AM +0800, Xingyu Wu wrote:
>> > > >> > > On 2023/5/19 22:16, Conor Dooley wrote:
>> > > >> > > > On Fri, May 19, 2023 at 03:57:33PM +0200, Torsten Duwe
>> > > >> > > > wrote:
>> > > >> > > >> On Fri, May 12, 2023 at 10:20:30AM +0800, Xingyu Wu wrote:
>> [...]
>>
>> > > >> > > Because PLL driver is separated from SYSCRG drivers in
>> > > >> > > Linux, the numbering starts from 0. But in Uboot, the PLL
>> > > >> > > driver is included in the SYSCRG driver, and the number
>> > > >> > > follows the SYSCRG.
>> > > >> >
>> > > >> > Unfortunately, how you choose to construct your drivers has
>> > > >> > nothing to do with this.
>>
>> Exactly. As I wrote (quote below), the PLLx frequencies are controlled
>> by the I/O block SYS_SYSCON (starting there at offset 0x18), according
>> to the public datasheets. All(?) other clocks are derived from those in
>> the *_CRG units. That *is* the hardware to be described, in *the* (one
>> and only!) DT. U-Boot, and any OS, are free to reorganise their driver
>> framework around that, but the hardware description is quite clear.
>
> The dt-binding that is in this series specifies that the pll clock
> controller is a child of the syscon:
> https://lore.kernel.org/linux-riscv/[email protected]/T/#Z2e.:..:20230512022036.97987-6-xingyu.wu::40starfivetech.com:1soc:starfive:starfive::2cjh7110-syscon.yaml
>
> That seems correct to me & U-Boot's devicetree is not compliant.
>
>> > > >> > These defines/numbers appear in the dts and are part of the DT
>> > > >> > ABI. The same dts is supposed to work for Linux & U-Boot.
>> > > >>
>> > > >> The JH7110 has 6 blocks of 64k iomem in that functional area:
>> > > >> {SYS,STG,AON} x {CRG,SYSCON}. None of these has 190 clocks.
>> > > >> The good news: the current DTS, as proposed here and in U-Boot
>> > > >> master, provides nodes for all 6 entities. The bad news is that
>> > > >> the clock assignments to those nodes and their numbering is
>> > > >> messed up.
>> > > >>
>> > > >> AFAICT PLL{0,1,2} _are_ generated in SYS_SYSCON and thus U-Boot
>> > > >> gets it wrong, in addition to the erroneous DTS.
>> > > >
>> > > > The numbers are kinda hocus-pocus anyway, they are just made up
>> > > > since the clock numbering usually isn't something with a nice TRM
>> > > > to go and reference (unlike interrupts which usually are
>> > > > documented in that way). It is very helpful to make them aligned
>> > > > some register/bit positions or, but that is not required.
>> > > > IOW U-Boot is not wrong per se to use 190 instead of 0, but it is
>> > > > wrong to have different numbers in both places.
>>
>> U-Boot reuses the Common Clock Framework from Linux, and I'm not sure
>> whether the clock IDs need to be unique in order for the appropriate
>> clock to be found.
>
> Unique within the clock controller, otherwise it is impossible to tell
> the difference between <&cctrl 1> and <&cctrl 1> apart! (The same
> follows even with increased #clock-cells, something must be unique).
> That's besides the point of this particular issue though.
>
>> But that would be the only restriction, if it
>> applies. Even then, each driver could register a clock with its own,
>> arbitrarily chosen base offset with the CCF, so each CRG unit could
>> still have its own clocks enumerated starting with 0 in the DTB.
>>
>> > > > It sounds like you're saying that (and I have not looked) the
>> > > > U-Boot dts actually has structural difference w.r.t. what
>> > > > provides which clock? If so, that'll need to be fixed
>> > > > independently of the numbering problem.
>>
>> > >
>> > > Oh, unfortunately, the 7110 can not support to mix the uboot dtb
>> > > and linux dtb up.
>> >
>> > What does "cannot support" mean? It's normal and desirable for the
>>
>> IMHO "desirable" is too weak.
>
> Yeah, agreed. I just don't like being prescriptive about what happens in
> projects that I do not maintain things for I guess.
>
>> > same dtb to be usable for both. The Linux kernel's dt-bindings are
>> > used for multiple projects, not just Linux - it'd be silly for
>> > U-Boot, FreeBSD etc etc to go off and each have their open set of
>> > (incompatible) bindings.
>> >
>> > > If boot the Linux and should use the linux dtb instead of the uboot
>> > > dtb. Because all clock ids and reset ids in Linux and Uboot are
>> > > different include PLL, and some modules can work in Linux but not
>> > > in uboot.
>> [...]
>> >
>> > > I suggest to boot Linux with its own linux dtb.
>>
>> This is a fragile band-aid, to be used only as a last resort. It
>> creates more problems than it solves. Your DTB will then match your
>> kernel, but whether it describes the actual hardware is a game of
>> chance. Doesn't the VisionFive2 have an RPi connector... ?
>>
>> One of the IMO few valid use cases of adding a DTB to the kernel
>> at boot is OpenWRT, when you build an OS Image for a particular piece
>> of hardware you have at hand.
>>
>> > I suggest to make sure that you can use the same dtb for both.
>>
>> Interestingly enough, U-Boot already has the PLL driver in a separate
>> file. I have a half-baked patch here that moves the sys_syscon DT
>> matching into that file...
>
> If you have patches that fix the devicetree & drivers in U-Boot, please
> post them. I don't really care at all which set of arbitrary numbers are
> chosen (as long as there is one and one only) but it looks like U-Boot's
> devicetree has an incorrect description of the clock controllers.
>

Hi Conor and Torsten,
After our internal discussions, it was decided to make the change on Uboot.
The clock id in Uboot are changed to be same with Linux and the PLL clocks become the child node of SYSCON.
And we will send this patch on Uboot soon.

Best Regards,
Xingyu Wu