2023-02-21 08:33:58

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v2 00/11] Add new partial clock and reset drivers for StarFive JH7110

This patch serises are to add new partial clock drivers and reset
supports about System-Top-Group(STG), Image-Signal-Process(ISP)
and Video-Output(VOUT) for the StarFive JH7110 RISC-V SoC.

Patches 1 to 3 are about the System-Top-Group clock and reset
generator(STGCRG) part.
The first patch adds docunmentation to describe STG bindings, and
the second patch adds support about STG resets. The last patch adds
clock driver to support STG clocks for JH7110.

Patches 4 to 6 are about the Image-Signal-Process clock and reset
gennerator(ISPCRG) part.
The first patch adds docunmentation to describe ISP bindings, and
the second patch adds support about ISP resets. The last patch adds
clock driver to support ISP clocks for JH7110.

Patches 7 to 9 are about the Video-Output clock and reset
generator(VOUTCRG) part.
The first patch adds docunmentation to describe VOUT bindings, and
the second patch adds support about VOUT resets. The last patch adds
clock driver to support VOUT clocks for JH7110.

Patch 10 adds external clocks which ISP and VOUT clock driver need.
Patch 11 adds device node about STGCRG, ISPCRG and VOUTCRG to JH7110 dts.

Patches 2, 3, 5, 6, 8 and 9 are dependent on the patchset [1] which
is about JH71x0 clock and reset driver.
Patches 6 and 9 also are dependent on the patchset [2] which is about
JH7110 PMU driver(Accpeted).
Patchdes 10 and 11 are dependent on the patchset [1] and [3] which is
about JH7110 device tree and PMU node.
This patchset should be applied after the patchset [1], [2], [3]:
[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/[email protected]/
[3] https://lore.kernel.org/all/[email protected]/

Changes since v1:
- Modified the binding and dropped the indentation.
- Removed the useless header files in the drivers.
- Used an array lookup instead of a pile of conditions about parent
clocks' name.
- Added clocks operation on driver remove.

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

Xingyu Wu (11):
dt-bindings: clock: Add StarFive JH7110 System-Top-Group clock and
reset generator
reset: starfive: jh7110: Add StarFive System-Top-Group reset support
clk: starfive: Add StarFive JH7110 System-Top-Group clock driver
dt-bindings: clock: Add StarFive JH7110 Image-Signal-Process clock and
reset generator
reset: starfive: jh7110: Add StarFive Image-Signal-Process reset
support
clk: starfive: Add StarFive JH7110 Image-Signal-Process clock driver
dt-bindings: clock: Add StarFive JH7110 Video-Output clock and reset
generator
reset: starfive: jh7110: Add StarFive Video-Output reset support
clk: starfive: Add StarFive JH7110 Video-Output clock driver
riscv: dts: starfive: jh7110: Add DVP and HDMI TX pixel external
clocks
riscv: dts: starfive: jh7110: Add STGCRG/ISPCRG/VOUTCRG nodes

.../clock/starfive,jh7110-ispcrg.yaml | 97 +++++++
.../clock/starfive,jh7110-stgcrg.yaml | 82 ++++++
.../clock/starfive,jh7110-voutcrg.yaml | 96 +++++++
MAINTAINERS | 1 +
.../jh7110-starfive-visionfive-2.dtsi | 8 +
arch/riscv/boot/dts/starfive/jh7110.dtsi | 71 +++++
drivers/clk/starfive/Kconfig | 33 +++
drivers/clk/starfive/Makefile | 3 +
.../clk/starfive/clk-starfive-jh7110-isp.c | 254 +++++++++++++++++
.../clk/starfive/clk-starfive-jh7110-stg.c | 176 ++++++++++++
.../clk/starfive/clk-starfive-jh7110-vout.c | 261 ++++++++++++++++++
.../reset/starfive/reset-starfive-jh7110.c | 30 ++
.../dt-bindings/clock/starfive,jh7110-crg.h | 74 +++++
.../dt-bindings/reset/starfive,jh7110-crg.h | 60 ++++
14 files changed, 1246 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-ispcrg.yaml
create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-stgcrg.yaml
create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-voutcrg.yaml
create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-isp.c
create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-stg.c
create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-vout.c


base-commit: c9c3395d5e3dcc6daee66c6908354d47bf98cb0c
prerequisite-patch-id: 4dc515731ce237184553c1606ffb3afaeb51c3d8
prerequisite-patch-id: ac150a8c622e858e088df8121093d448df49c245
prerequisite-patch-id: a4255724d4698f1238663443024de56de38d717b
prerequisite-patch-id: a798370d170dc2bcc79ed86f741c21c1e6d87c78
prerequisite-patch-id: 203d2500cadc112bd20fefc56eabf1470d3d2d2d
prerequisite-patch-id: 315303931e4b6499de7127a88113763f86e97e16
prerequisite-patch-id: 40cb8212ddb024c20593f73d8b87d9894877e172
prerequisite-patch-id: a1673a9e9f19d6fab5a51abb721e54e36636f067
prerequisite-patch-id: 94860423c7acc9025249d4bb36652a585bd0a797
prerequisite-patch-id: b5084253283929d9a6d0e66c350400c7c85d034d
prerequisite-patch-id: a428ed7a2aa45abab86923dc467e1e6b08427e85
prerequisite-patch-id: d4f80829fca7ce370a6fad766593cdcb502fa245
prerequisite-patch-id: e3490e19e089fe284334db300ee189b619a61628
prerequisite-patch-id: 34298e3882261bc2d72955b1570cc9612ab7d662
prerequisite-patch-id: 377c5c282a0776feee9acd10b565adbd5275a67e
prerequisite-patch-id: 3ccee718de0750adbf8d0b77d553a2778a344f64
prerequisite-patch-id: 4710f2ac22dca0bdd9ff5d744d2c37cab3c74515
prerequisite-patch-id: 65f2aed865d88e6fa468d2923527b523d4313857
prerequisite-patch-id: 258ea5f9b8bf41b6981345dcc81795f25865d38f
prerequisite-patch-id: 8b6f2c9660c0ac0ee4e73e4c21aca8e6b75e81b9
prerequisite-patch-id: e3b986b9c60b2b93b7812ec174c9e1b4cfb14c97
prerequisite-patch-id: a2b3a9cff8a683422eb0ccf3a0850091401812d4
prerequisite-patch-id: dbb0c0151b8bdf093e6ce79fd2fe3f60791a6e0b
prerequisite-patch-id: ea9a6d0313dd3936c8de0239dc2072c3360a2f6b
prerequisite-patch-id: d57e95d31686772abc4c4d5aa1cadc344dc293cd
prerequisite-patch-id: 29aab7148bf56a20acddcb8a11f290705fcc97f6
prerequisite-patch-id: eeecb5367bea99627210b661986ca5b49e2a9d63
prerequisite-patch-id: c02658f677990683d4c4957e06c19ed3a3a0cfab
prerequisite-patch-id: 2ddada18ab6ea5cd1da14212aaf59632f5203d40
--
2.25.1



2023-02-21 08:34:01

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v2 08/11] reset: starfive: jh7110: Add StarFive Video-Output reset support

Add auxiliary_device_id to support StarFive JH7110 Video-Output resets
of which the auxiliary device name is "clk_starfive_jh71x0.reset-vout".

Signed-off-by: Xingyu Wu <[email protected]>
---
drivers/reset/starfive/reset-starfive-jh7110.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/drivers/reset/starfive/reset-starfive-jh7110.c b/drivers/reset/starfive/reset-starfive-jh7110.c
index e3b7b6941217..ad967398f227 100644
--- a/drivers/reset/starfive/reset-starfive-jh7110.c
+++ b/drivers/reset/starfive/reset-starfive-jh7110.c
@@ -52,6 +52,12 @@ static const struct reset_info jh7110_isp_info = {
.status_offset = 0x3C,
};

+static const struct reset_info jh7110_vout_info = {
+ .nr_resets = JH7110_VOUTRST_END,
+ .assert_offset = 0x48,
+ .status_offset = 0x4C,
+};
+
static const struct auxiliary_device_id jh7110_reset_ids[] = {
{
.name = "clk_starfive_jh71x0.reset-sys",
@@ -69,6 +75,10 @@ static const struct auxiliary_device_id jh7110_reset_ids[] = {
.name = "clk_starfive_jh71x0.reset-isp",
.driver_data = (kernel_ulong_t)&jh7110_isp_info,
},
+ {
+ .name = "clk_starfive_jh71x0.reset-vout",
+ .driver_data = (kernel_ulong_t)&jh7110_vout_info,
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(auxiliary, jh7110_reset_ids);
--
2.25.1


2023-02-21 08:34:03

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v2 06/11] clk: starfive: Add StarFive JH7110 Image-Signal-Process clock driver

Add driver for the StarFive JH7110 Image-Signal-Process clock controller.

Signed-off-by: Xingyu Wu <[email protected]>
---
drivers/clk/starfive/Kconfig | 11 +
drivers/clk/starfive/Makefile | 1 +
.../clk/starfive/clk-starfive-jh7110-isp.c | 254 ++++++++++++++++++
3 files changed, 266 insertions(+)
create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-isp.c

diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
index a462b6e53543..59499acb95f7 100644
--- a/drivers/clk/starfive/Kconfig
+++ b/drivers/clk/starfive/Kconfig
@@ -53,3 +53,14 @@ config CLK_STARFIVE_JH7110_STG
help
Say yes here to support the System-Top-Group clock controller
on the StarFive JH7110 SoC.
+
+config CLK_STARFIVE_JH7110_ISP
+ tristate "StarFive JH7110 Image-Signal-Process clock support"
+ depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
+ select AUXILIARY_BUS
+ select CLK_STARFIVE_JH71X0
+ select RESET_STARFIVE_JH7110
+ default CLK_STARFIVE_JH7110_SYS
+ help
+ Say yes here to support the Image-Signal-Process clock controller
+ on the StarFive JH7110 SoC.
diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
index b81e97ee2659..76fb9f8d628b 100644
--- a/drivers/clk/starfive/Makefile
+++ b/drivers/clk/starfive/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
+obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
diff --git a/drivers/clk/starfive/clk-starfive-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
new file mode 100644
index 000000000000..b5bce1ac22e0
--- /dev/null
+++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * StarFive JH7110 Image-Signal-Process Clock Driver
+ *
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <dt-bindings/clock/starfive,jh7110-crg.h>
+
+#include "clk-starfive-jh71x0.h"
+
+/* external clocks */
+#define JH7110_ISPCLK_ISP_TOP_CORE (JH7110_ISPCLK_END + 0)
+#define JH7110_ISPCLK_ISP_TOP_AXI (JH7110_ISPCLK_END + 1)
+#define JH7110_ISPCLK_NOC_BUS_ISP_AXI (JH7110_ISPCLK_END + 2)
+#define JH7110_ISPCLK_DVP_CLK (JH7110_ISPCLK_END + 3)
+#define JH7110_ISPCLK_EXT_END (JH7110_ISPCLK_END + 4)
+
+static const struct jh71x0_clk_data jh7110_ispclk_data[] = {
+ /* syscon */
+ JH71X0__DIV(JH7110_ISPCLK_DOM4_APB_FUNC, "dom4_apb_func", 15,
+ JH7110_ISPCLK_ISP_TOP_AXI),
+ JH71X0__DIV(JH7110_ISPCLK_MIPI_RX0_PXL, "mipi_rx0_pxl", 8,
+ JH7110_ISPCLK_ISP_TOP_CORE),
+ JH71X0__INV(JH7110_ISPCLK_DVP_INV, "dvp_inv", JH7110_ISPCLK_DVP_CLK),
+ /* vin */
+ JH71X0__DIV(JH7110_ISPCLK_M31DPHY_CFGCLK_IN, "m31dphy_cfgclk_in", 16,
+ JH7110_ISPCLK_ISP_TOP_CORE),
+ JH71X0__DIV(JH7110_ISPCLK_M31DPHY_REFCLK_IN, "m31dphy_refclk_in", 16,
+ JH7110_ISPCLK_ISP_TOP_CORE),
+ JH71X0__DIV(JH7110_ISPCLK_M31DPHY_TXCLKESC_LAN0, "m31dphy_txclkesc_lan0", 60,
+ JH7110_ISPCLK_ISP_TOP_CORE),
+ JH71X0_GATE(JH7110_ISPCLK_VIN_PCLK, "vin_pclk", CLK_IGNORE_UNUSED,
+ JH7110_ISPCLK_DOM4_APB_FUNC),
+ JH71X0__DIV(JH7110_ISPCLK_VIN_SYS_CLK, "vin_sys_clk", 8, JH7110_ISPCLK_ISP_TOP_CORE),
+ JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF0, "vin_pixel_clk_if0", CLK_IGNORE_UNUSED,
+ JH7110_ISPCLK_MIPI_RX0_PXL),
+ JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF1, "vin_pixel_clk_if1", CLK_IGNORE_UNUSED,
+ JH7110_ISPCLK_MIPI_RX0_PXL),
+ JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF2, "vin_pixel_clk_if2", CLK_IGNORE_UNUSED,
+ JH7110_ISPCLK_MIPI_RX0_PXL),
+ JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF3, "vin_pixel_clk_if3", CLK_IGNORE_UNUSED,
+ JH7110_ISPCLK_MIPI_RX0_PXL),
+ JH71X0__MUX(JH7110_ISPCLK_VIN_CLK_P_AXIWR, "vin_clk_p_axiwr", 2,
+ JH7110_ISPCLK_MIPI_RX0_PXL,
+ JH7110_ISPCLK_DVP_INV),
+ /* ispv2_top_wrapper */
+ JH71X0_GMUX(JH7110_ISPCLK_ISPV2_TOP_WRAPPER_CLK_C, "ispv2_top_wrapper_clk_c",
+ CLK_IGNORE_UNUSED, 2,
+ JH7110_ISPCLK_MIPI_RX0_PXL,
+ JH7110_ISPCLK_DVP_INV),
+};
+
+struct isp_top_crg {
+ struct clk_bulk_data *top_clks;
+ struct reset_control *top_rsts;
+ int top_clks_num;
+ void __iomem *base;
+};
+
+static struct clk_bulk_data jh7110_isp_top_clks[] = {
+ { .id = "isp_top_core" },
+ { .id = "isp_top_axi" }
+};
+
+static struct isp_top_crg *top_crg_from(void __iomem **base)
+{
+ return container_of(base, struct isp_top_crg, base);
+}
+
+static int jh7110_isp_top_crg_get(struct jh71x0_clk_priv *priv, struct isp_top_crg *top)
+{
+ int ret;
+
+ top->top_clks = jh7110_isp_top_clks;
+ top->top_clks_num = ARRAY_SIZE(jh7110_isp_top_clks);
+ ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
+ if (ret) {
+ dev_err(priv->dev, "top clks get failed: %d\n", ret);
+ return ret;
+ }
+
+ /* The resets should be shared and other ISP modules will use its. */
+ top->top_rsts = devm_reset_control_array_get_shared(priv->dev);
+ if (IS_ERR(top->top_rsts)) {
+ dev_err(priv->dev, "top rsts get failed\n");
+ return PTR_ERR(top->top_rsts);
+ }
+
+ return 0;
+}
+
+static int jh7110_isp_top_crg_enable(struct isp_top_crg *top)
+{
+ int ret;
+
+ ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
+ if (ret)
+ return ret;
+
+ return reset_control_deassert(top->top_rsts);
+}
+
+static void jh7110_isp_top_crg_disable(struct isp_top_crg *top)
+{
+ clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
+}
+
+static struct clk_hw *jh7110_ispclk_get(struct of_phandle_args *clkspec, void *data)
+{
+ struct jh71x0_clk_priv *priv = data;
+ unsigned int idx = clkspec->args[0];
+
+ if (idx < JH7110_ISPCLK_END)
+ return &priv->reg[idx].hw;
+
+ return ERR_PTR(-EINVAL);
+}
+
+static int jh7110_ispcrg_probe(struct platform_device *pdev)
+{
+ struct jh71x0_clk_priv *priv;
+ struct isp_top_crg *top;
+ unsigned int idx;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev,
+ struct_size(priv, reg, JH7110_ISPCLK_END),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
+ if (!top)
+ return -ENOMEM;
+
+ spin_lock_init(&priv->rmw_lock);
+ priv->dev = &pdev->dev;
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ top->base = priv->base;
+ dev_set_drvdata(priv->dev, (void *)(&top->base));
+
+ pm_runtime_enable(priv->dev);
+ ret = pm_runtime_get_sync(priv->dev);
+ if (ret < 0) {
+ dev_err(priv->dev, "failed to turn on power: %d\n", ret);
+ return ret;
+ }
+
+ ret = jh7110_isp_top_crg_get(priv, top);
+ if (ret)
+ goto err_clk;
+
+ ret = jh7110_isp_top_crg_enable(top);
+ if (ret)
+ goto err_clk;
+
+ for (idx = 0; idx < JH7110_ISPCLK_END; idx++) {
+ u32 max = jh7110_ispclk_data[idx].max;
+ struct clk_parent_data parents[4] = {};
+ struct clk_init_data init = {
+ .name = jh7110_ispclk_data[idx].name,
+ .ops = starfive_jh71x0_clk_ops(max),
+ .parent_data = parents,
+ .num_parents =
+ ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
+ .flags = jh7110_ispclk_data[idx].flags,
+ };
+ struct jh71x0_clk *clk = &priv->reg[idx];
+ unsigned int i;
+ char *fw_name[JH7110_ISPCLK_EXT_END - JH7110_ISPCLK_END] = {
+ "isp_top_core",
+ "isp_top_axi",
+ "noc_bus_isp_axi",
+ "dvp_clk"
+ };
+
+ for (i = 0; i < init.num_parents; i++) {
+ unsigned int pidx = jh7110_ispclk_data[idx].parents[i];
+
+ if (pidx < JH7110_ISPCLK_END)
+ parents[i].hw = &priv->reg[pidx].hw;
+ else
+ parents[i].fw_name = fw_name[pidx - JH7110_ISPCLK_END];
+ }
+
+ clk->hw.init = &init;
+ clk->idx = idx;
+ clk->max_div = max & JH71X0_CLK_DIV_MASK;
+
+ ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
+ if (ret)
+ goto err_exit;
+ }
+
+ ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_ispclk_get, priv);
+ if (ret)
+ goto err_exit;
+
+ ret = jh7110_reset_controller_register(priv, "reset-isp", 3);
+ if (ret)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ jh7110_isp_top_crg_disable(top);
+err_clk:
+ pm_runtime_put_sync(priv->dev);
+ pm_runtime_disable(priv->dev);
+ return ret;
+}
+
+static int jh7110_ispcrg_remove(struct platform_device *pdev)
+{
+ void __iomem **base = dev_get_drvdata(&pdev->dev);
+ struct isp_top_crg *top = top_crg_from(base);
+
+ jh7110_isp_top_crg_disable(top);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id jh7110_ispcrg_match[] = {
+ { .compatible = "starfive,jh7110-ispcrg" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jh7110_ispcrg_match);
+
+static struct platform_driver jh7110_ispcrg_driver = {
+ .probe = jh7110_ispcrg_probe,
+ .remove = jh7110_ispcrg_remove,
+ .driver = {
+ .name = "clk-starfive-jh7110-isp",
+ .of_match_table = jh7110_ispcrg_match,
+ },
+};
+module_platform_driver(jh7110_ispcrg_driver);
+
+MODULE_AUTHOR("Xingyu Wu <[email protected]>");
+MODULE_DESCRIPTION("StarFive JH7110 Image-Signal-Process clock driver");
+MODULE_LICENSE("GPL");
--
2.25.1


2023-02-21 08:34:06

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v2 07/11] dt-bindings: clock: Add StarFive JH7110 Video-Output clock and reset generator

Add bindings for the Video-Output clock and reset generator (VOUTCRG)
on the JH7110 RISC-V SoC by StarFive Ltd.

Signed-off-by: Xingyu Wu <[email protected]>
---
.../clock/starfive,jh7110-voutcrg.yaml | 96 +++++++++++++++++++
.../dt-bindings/clock/starfive,jh7110-crg.h | 22 +++++
.../dt-bindings/reset/starfive,jh7110-crg.h | 16 ++++
3 files changed, 134 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-voutcrg.yaml

diff --git a/Documentation/devicetree/bindings/clock/starfive,jh7110-voutcrg.yaml b/Documentation/devicetree/bindings/clock/starfive,jh7110-voutcrg.yaml
new file mode 100644
index 000000000000..a6a43d86a392
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/starfive,jh7110-voutcrg.yaml
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/starfive,jh7110-voutcrg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JH7110 Video-Output Clock and Reset Generator
+
+maintainers:
+ - Xingyu Wu <[email protected]>
+
+properties:
+ compatible:
+ const: starfive,jh7110-voutcrg
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Vout Top core
+ - description: Vout Top Ahb
+ - description: Vout Top Axi
+ - description: Vout Top HDMI MCLK
+ - description: I2STX0 BCLK
+ - description: external HDMI pixel
+
+ clock-names:
+ items:
+ - const: vout_src
+ - const: vout_top_ahb
+ - const: vout_top_axi
+ - const: vout_top_hdmitx0_mclk
+ - const: i2stx0_bclk
+ - const: hdmitx0_pixelclk
+
+ resets:
+ items:
+ - description: Vout Top core
+
+ reset-names:
+ items:
+ - const: vout_top_src
+
+ '#clock-cells':
+ const: 1
+ description:
+ See <dt-bindings/clock/starfive,jh7110-crg.h> for valid indices.
+
+ '#reset-cells':
+ const: 1
+ description:
+ See <dt-bindings/reset/starfive,jh7110-crg.h> for valid indices.
+
+ power-domains:
+ maxItems: 1
+ description:
+ Vout domain power
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - '#clock-cells'
+ - '#reset-cells'
+ - power-domains
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/starfive,jh7110-crg.h>
+ #include <dt-bindings/power/starfive,jh7110-pmu.h>
+ #include <dt-bindings/reset/starfive,jh7110-crg.h>
+
+ voutcrg: clock-controller@295C0000 {
+ compatible = "starfive,jh7110-voutcrg";
+ reg = <0x295C0000 0x10000>;
+ clocks = <&syscrg JH7110_SYSCLK_VOUT_SRC>,
+ <&syscrg JH7110_SYSCLK_VOUT_TOP_AHB>,
+ <&syscrg JH7110_SYSCLK_VOUT_TOP_AXI>,
+ <&syscrg JH7110_SYSCLK_VOUT_TOP_HDMITX0_MCLK>,
+ <&syscrg JH7110_SYSCLK_I2STX0_BCLK>,
+ <&hdmitx0_pixelclk>;
+ clock-names = "vout_src", "vout_top_ahb",
+ "vout_top_axi", "vout_top_hdmitx0_mclk",
+ "i2stx0_bclk", "hdmitx0_pixelclk";
+ resets = <&syscrg JH7110_SYSRST_VOUT_TOP_SRC>;
+ reset-names = "vout_top_src";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ power-domains = <&pwrc JH7110_PD_VOUT>;
+ };
diff --git a/include/dt-bindings/clock/starfive,jh7110-crg.h b/include/dt-bindings/clock/starfive,jh7110-crg.h
index 91ee589809c3..3ebece93cbd3 100644
--- a/include/dt-bindings/clock/starfive,jh7110-crg.h
+++ b/include/dt-bindings/clock/starfive,jh7110-crg.h
@@ -274,4 +274,26 @@

#define JH7110_ISPCLK_END 14

+/* VOUTCRG clocks */
+#define JH7110_VOUTCLK_APB 0
+#define JH7110_VOUTCLK_DC8200_PIX 1
+#define JH7110_VOUTCLK_DSI_SYS 2
+#define JH7110_VOUTCLK_TX_ESC 3
+#define JH7110_VOUTCLK_DC8200_AXI 4
+#define JH7110_VOUTCLK_DC8200_CORE 5
+#define JH7110_VOUTCLK_DC8200_AHB 6
+#define JH7110_VOUTCLK_DC8200_PIX0 7
+#define JH7110_VOUTCLK_DC8200_PIX1 8
+#define JH7110_VOUTCLK_DOM_VOUT_TOP_LCD 9
+#define JH7110_VOUTCLK_DSITX_APB 10
+#define JH7110_VOUTCLK_DSITX_SYS 11
+#define JH7110_VOUTCLK_DSITX_DPI 12
+#define JH7110_VOUTCLK_DSITX_TXESC 13
+#define JH7110_VOUTCLK_MIPITX_DPHY_TXESC 14
+#define JH7110_VOUTCLK_HDMI_TX_MCLK 15
+#define JH7110_VOUTCLK_HDMI_TX_BCLK 16
+#define JH7110_VOUTCLK_HDMI_TX_SYS 17
+
+#define JH7110_VOUTCLK_END 18
+
#endif /* __DT_BINDINGS_CLOCK_STARFIVE_JH7110_CRG_H__ */
diff --git a/include/dt-bindings/reset/starfive,jh7110-crg.h b/include/dt-bindings/reset/starfive,jh7110-crg.h
index f23c160ec538..3a3a14bed136 100644
--- a/include/dt-bindings/reset/starfive,jh7110-crg.h
+++ b/include/dt-bindings/reset/starfive,jh7110-crg.h
@@ -195,4 +195,20 @@

#define JH7110_ISPRST_END 12

+/* VOUTCRG resets */
+#define JH7110_VOUTRST_DC8200_AXI 0
+#define JH7110_VOUTRST_DC8200_AHB 1
+#define JH7110_VOUTRST_DC8200_CORE 2
+#define JH7110_VOUTRST_DSITX_DPI 3
+#define JH7110_VOUTRST_DSITX_APB 4
+#define JH7110_VOUTRST_DSITX_RXESC 5
+#define JH7110_VOUTRST_DSITX_SYS 6
+#define JH7110_VOUTRST_DSITX_TXBYTEHS 7
+#define JH7110_VOUTRST_DSITX_TXESC 8
+#define JH7110_VOUTRST_HDMI_TX_HDMI 9
+#define JH7110_VOUTRST_MIPITX_DPHY_SYS 10
+#define JH7110_VOUTRST_MIPITX_DPHY_TXBYTEHS 11
+
+#define JH7110_VOUTRST_END 12
+
#endif /* __DT_BINDINGS_RESET_STARFIVE_JH7110_CRG_H__ */
--
2.25.1


2023-02-21 08:34:09

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v2 11/11] riscv: dts: starfive: jh7110: Add STGCRG/ISPCRG/VOUTCRG nodes

Add STGCRG/ISPCRG/VOUTCRG new node to support JH7110
System-Top-Group, Image-Signal-Process and Video-Output
clock and reset drivers for the JH7110 RISC-V SoC.

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

diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
index a5e6fb3ad188..697ab59191a1 100644
--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
@@ -6,6 +6,7 @@

/dts-v1/;
#include <dt-bindings/clock/starfive,jh7110-crg.h>
+#include <dt-bindings/power/starfive,jh7110-pmu.h>
#include <dt-bindings/reset/starfive,jh7110-crg.h>

/ {
@@ -374,6 +375,25 @@ i2c2: i2c@10050000 {
status = "disabled";
};

+ stgcrg: clock-controller@10230000 {
+ compatible = "starfive,jh7110-stgcrg";
+ reg = <0x0 0x10230000 0x0 0x10000>;
+ clocks = <&osc>,
+ <&syscrg JH7110_SYSCLK_HIFI4_CORE>,
+ <&syscrg JH7110_SYSCLK_STG_AXIAHB>,
+ <&syscrg JH7110_SYSCLK_USB_125M>,
+ <&syscrg JH7110_SYSCLK_CPU_BUS>,
+ <&syscrg JH7110_SYSCLK_HIFI4_AXI>,
+ <&syscrg JH7110_SYSCLK_NOCSTG_BUS>,
+ <&syscrg JH7110_SYSCLK_APB_BUS>;
+ clock-names = "osc", "hifi4_core",
+ "stg_axiahb", "usb_125m",
+ "cpu_bus", "hifi4_axi",
+ "nocstg_bus", "apb_bus";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
uart3: serial@12000000 {
compatible = "snps,dw-apb-uart";
reg = <0x0 0x12000000 0x0 0x10000>;
@@ -522,5 +542,44 @@ pwrc: power-controller@17030000 {
interrupts = <111>;
#power-domain-cells = <1>;
};
+
+ ispcrg: clock-controller@19810000 {
+ compatible = "starfive,jh7110-ispcrg";
+ reg = <0x0 0x19810000 0x0 0x10000>;
+ clocks = <&syscrg JH7110_SYSCLK_ISP_TOP_CORE>,
+ <&syscrg JH7110_SYSCLK_ISP_TOP_AXI>,
+ <&syscrg JH7110_SYSCLK_NOC_BUS_ISP_AXI>,
+ <&dvp_clk>;
+ clock-names = "isp_top_core", "isp_top_axi",
+ "noc_bus_isp_axi", "dvp_clk";
+ resets = <&syscrg JH7110_SYSRST_ISP_TOP>,
+ <&syscrg JH7110_SYSRST_ISP_TOP_AXI>,
+ <&syscrg JH7110_SYSRST_NOC_BUS_ISP_AXI>;
+ reset-names = "isp_top_core",
+ "isp_top_axi",
+ "noc_bus_isp_axi";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ power-domains = <&pwrc JH7110_PD_ISP>;
+ };
+
+ voutcrg: clock-controller@295C0000 {
+ compatible = "starfive,jh7110-voutcrg";
+ reg = <0x0 0x295C0000 0x0 0x10000>;
+ clocks = <&syscrg JH7110_SYSCLK_VOUT_SRC>,
+ <&syscrg JH7110_SYSCLK_VOUT_TOP_AHB>,
+ <&syscrg JH7110_SYSCLK_VOUT_TOP_AXI>,
+ <&syscrg JH7110_SYSCLK_VOUT_TOP_HDMITX0_MCLK>,
+ <&syscrg JH7110_SYSCLK_I2STX0_BCLK>,
+ <&hdmitx0_pixelclk>;
+ clock-names = "vout_src", "vout_top_ahb",
+ "vout_top_axi", "vout_top_hdmitx0_mclk",
+ "i2stx0_bclk", "hdmitx0_pixelclk";
+ resets = <&syscrg JH7110_SYSRST_VOUT_TOP_SRC>;
+ reset-names = "vout_top_src";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ power-domains = <&pwrc JH7110_PD_VOUT>;
+ };
};
};
--
2.25.1


2023-02-21 08:34:13

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v2 10/11] riscv: dts: starfive: jh7110: Add DVP and HDMI TX pixel external clocks

Add DVP and HDMI TX pixel external fixed clocks and the rates are
74.25MHz and 297MHz.

Signed-off-by: Xingyu Wu <[email protected]>
---
.../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 8 ++++++++
arch/riscv/boot/dts/starfive/jh7110.dtsi | 12 ++++++++++++
2 files changed, 20 insertions(+)

diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
index c2aa8946a0f1..27af817a55aa 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
@@ -86,6 +86,14 @@ &mclk_ext {
clock-frequency = <12288000>;
};

+&dvp_clk {
+ clock-frequency = <74250000>;
+};
+
+&hdmitx0_pixelclk {
+ clock-frequency = <297000000>;
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins>;
diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
index 005ead2624d4..a5e6fb3ad188 100644
--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
@@ -245,6 +245,18 @@ mclk_ext: mclk-ext-clock {
#clock-cells = <0>;
};

+ dvp_clk: dvp-clk-clock {
+ compatible = "fixed-clock";
+ clock-output-names = "dvp_clk";
+ #clock-cells = <0>;
+ };
+
+ hdmitx0_pixelclk: hdmitx0-pixelclk-clock {
+ compatible = "fixed-clock";
+ clock-output-names = "hdmitx0_pixelclk";
+ #clock-cells = <0>;
+ };
+
soc {
compatible = "simple-bus";
interrupt-parent = <&plic>;
--
2.25.1


2023-02-21 08:34:16

by Xingyu Wu

[permalink] [raw]
Subject: [PATCH v2 09/11] clk: starfive: Add StarFive JH7110 Video-Output clock driver

Add driver for the StarFive JH7110 Video-Output clock controller.

Signed-off-by: Xingyu Wu <[email protected]>
---
drivers/clk/starfive/Kconfig | 11 +
drivers/clk/starfive/Makefile | 1 +
.../clk/starfive/clk-starfive-jh7110-vout.c | 261 ++++++++++++++++++
3 files changed, 273 insertions(+)
create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-vout.c

diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
index 59499acb95f7..5ebf1ed08627 100644
--- a/drivers/clk/starfive/Kconfig
+++ b/drivers/clk/starfive/Kconfig
@@ -64,3 +64,14 @@ config CLK_STARFIVE_JH7110_ISP
help
Say yes here to support the Image-Signal-Process clock controller
on the StarFive JH7110 SoC.
+
+config CLK_STARFIVE_JH7110_VOUT
+ tristate "StarFive JH7110 Video-Output clock support"
+ depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
+ select AUXILIARY_BUS
+ select CLK_STARFIVE_JH71X0
+ select RESET_STARFIVE_JH7110
+ default CLK_STARFIVE_JH7110_SYS
+ help
+ Say yes here to support the Video-Output clock controller
+ on the StarFive JH7110 SoC.
diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
index 76fb9f8d628b..841377e45bb6 100644
--- a/drivers/clk/starfive/Makefile
+++ b/drivers/clk/starfive/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
+obj-$(CONFIG_CLK_STARFIVE_JH7110_VOUT) += clk-starfive-jh7110-vout.o
diff --git a/drivers/clk/starfive/clk-starfive-jh7110-vout.c b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
new file mode 100644
index 000000000000..d786537563a4
--- /dev/null
+++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * StarFive JH7110 Video-Output Clock Driver
+ *
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <dt-bindings/clock/starfive,jh7110-crg.h>
+
+#include "clk-starfive-jh71x0.h"
+
+/* external clocks */
+#define JH7110_VOUTCLK_VOUT_SRC (JH7110_VOUTCLK_END + 0)
+#define JH7110_VOUTCLK_VOUT_TOP_AHB (JH7110_VOUTCLK_END + 1)
+#define JH7110_VOUTCLK_VOUT_TOP_AXI (JH7110_VOUTCLK_END + 2)
+#define JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK (JH7110_VOUTCLK_END + 3)
+#define JH7110_VOUTCLK_I2STX0_BCLK (JH7110_VOUTCLK_END + 4)
+#define JH7110_VOUTCLK_HDMITX0_PIXELCLK (JH7110_VOUTCLK_END + 5)
+#define JH7110_VOUTCLK_EXT_END (JH7110_VOUTCLK_END + 6)
+
+static const struct jh71x0_clk_data jh7110_voutclk_data[] = {
+ /* divider */
+ JH71X0__DIV(JH7110_VOUTCLK_APB, "apb", 8, JH7110_VOUTCLK_VOUT_TOP_AHB),
+ JH71X0__DIV(JH7110_VOUTCLK_DC8200_PIX, "dc8200_pix", 63, JH7110_VOUTCLK_VOUT_SRC),
+ JH71X0__DIV(JH7110_VOUTCLK_DSI_SYS, "dsi_sys", 31, JH7110_VOUTCLK_VOUT_SRC),
+ JH71X0__DIV(JH7110_VOUTCLK_TX_ESC, "tx_esc", 31, JH7110_VOUTCLK_VOUT_TOP_AHB),
+ /* dc8200 */
+ JH71X0_GATE(JH7110_VOUTCLK_DC8200_AXI, "dc8200_axi", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
+ JH71X0_GATE(JH7110_VOUTCLK_DC8200_CORE, "dc8200_core", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
+ JH71X0_GATE(JH7110_VOUTCLK_DC8200_AHB, "dc8200_ahb", 0, JH7110_VOUTCLK_VOUT_TOP_AHB),
+ JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX0, "dc8200_pix0", 0, 2,
+ JH7110_VOUTCLK_DC8200_PIX,
+ JH7110_VOUTCLK_HDMITX0_PIXELCLK),
+ JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX1, "dc8200_pix1", 0, 2,
+ JH7110_VOUTCLK_DC8200_PIX,
+ JH7110_VOUTCLK_HDMITX0_PIXELCLK),
+ /* LCD */
+ JH71X0_GMUX(JH7110_VOUTCLK_DOM_VOUT_TOP_LCD, "dom_vout_top_lcd", 0, 2,
+ JH7110_VOUTCLK_DC8200_PIX0,
+ JH7110_VOUTCLK_DC8200_PIX1),
+ /* dsiTx */
+ JH71X0_GATE(JH7110_VOUTCLK_DSITX_APB, "dsiTx_apb", 0, JH7110_VOUTCLK_DSI_SYS),
+ JH71X0_GATE(JH7110_VOUTCLK_DSITX_SYS, "dsiTx_sys", 0, JH7110_VOUTCLK_DSI_SYS),
+ JH71X0_GMUX(JH7110_VOUTCLK_DSITX_DPI, "dsiTx_dpi", 0, 2,
+ JH7110_VOUTCLK_DC8200_PIX,
+ JH7110_VOUTCLK_HDMITX0_PIXELCLK),
+ JH71X0_GATE(JH7110_VOUTCLK_DSITX_TXESC, "dsiTx_txesc", 0, JH7110_VOUTCLK_TX_ESC),
+ /* mipitx DPHY */
+ JH71X0_GATE(JH7110_VOUTCLK_MIPITX_DPHY_TXESC, "mipitx_dphy_txesc", 0,
+ JH7110_VOUTCLK_TX_ESC),
+ /* hdmi */
+ JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_MCLK, "hdmi_tx_mclk", 0,
+ JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK),
+ JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_BCLK, "hdmi_tx_bclk", 0,
+ JH7110_VOUTCLK_I2STX0_BCLK),
+ JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_SYS, "hdmi_tx_sys", 0, JH7110_VOUTCLK_APB),
+};
+
+struct vout_top_crg {
+ struct clk_bulk_data *top_clks;
+ struct reset_control *top_rst;
+ int top_clks_num;
+ void __iomem *base;
+};
+
+static struct clk_bulk_data jh7110_vout_top_clks[] = {
+ { .id = "vout_src" },
+ { .id = "vout_top_ahb" }
+};
+
+static struct vout_top_crg *top_crg_from(void __iomem **base)
+{
+ return container_of(base, struct vout_top_crg, base);
+}
+
+static int jh7110_vout_top_crg_get(struct jh71x0_clk_priv *priv, struct vout_top_crg *top)
+{
+ int ret;
+
+ top->top_clks = jh7110_vout_top_clks;
+ top->top_clks_num = ARRAY_SIZE(jh7110_vout_top_clks);
+ ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
+ if (ret) {
+ dev_err(priv->dev, "top clks get failed: %d\n", ret);
+ return ret;
+ }
+
+ /* The reset should be shared and other Vout modules will use its. */
+ top->top_rst = devm_reset_control_get_shared(priv->dev, NULL);
+ if (IS_ERR(top->top_rst)) {
+ dev_err(priv->dev, "top rst get failed\n");
+ return PTR_ERR(top->top_rst);
+ }
+
+ return 0;
+}
+
+static int jh7110_vout_top_crg_enable(struct vout_top_crg *top)
+{
+ int ret;
+
+ ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
+ if (ret)
+ return ret;
+
+ return reset_control_deassert(top->top_rst);
+}
+
+static void jh7110_vout_top_crg_disable(struct vout_top_crg *top)
+{
+ clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
+}
+
+static struct clk_hw *jh7110_voutclk_get(struct of_phandle_args *clkspec, void *data)
+{
+ struct jh71x0_clk_priv *priv = data;
+ unsigned int idx = clkspec->args[0];
+
+ if (idx < JH7110_VOUTCLK_END)
+ return &priv->reg[idx].hw;
+
+ return ERR_PTR(-EINVAL);
+}
+
+static int jh7110_voutcrg_probe(struct platform_device *pdev)
+{
+ struct jh71x0_clk_priv *priv;
+ struct vout_top_crg *top;
+ unsigned int idx;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev,
+ struct_size(priv, reg, JH7110_VOUTCLK_END),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
+ if (!top)
+ return -ENOMEM;
+
+ spin_lock_init(&priv->rmw_lock);
+ priv->dev = &pdev->dev;
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ top->base = priv->base;
+ dev_set_drvdata(priv->dev, (void *)(&top->base));
+
+ pm_runtime_enable(priv->dev);
+ ret = pm_runtime_get_sync(priv->dev);
+ if (ret < 0) {
+ dev_err(priv->dev, "failed to turn power: %d\n", ret);
+ return ret;
+ }
+
+ ret = jh7110_vout_top_crg_get(priv, top);
+ if (ret)
+ goto err_clk;
+
+ ret = jh7110_vout_top_crg_enable(top);
+ if (ret)
+ goto err_clk;
+
+ for (idx = 0; idx < JH7110_VOUTCLK_END; idx++) {
+ u32 max = jh7110_voutclk_data[idx].max;
+ struct clk_parent_data parents[4] = {};
+ struct clk_init_data init = {
+ .name = jh7110_voutclk_data[idx].name,
+ .ops = starfive_jh71x0_clk_ops(max),
+ .parent_data = parents,
+ .num_parents =
+ ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
+ .flags = jh7110_voutclk_data[idx].flags,
+ };
+ struct jh71x0_clk *clk = &priv->reg[idx];
+ unsigned int i;
+ char *fw_name[JH7110_VOUTCLK_EXT_END - JH7110_VOUTCLK_END] = {
+ "vout_src",
+ "vout_top_ahb",
+ "vout_top_axi",
+ "vout_top_hdmitx0_mclk",
+ "i2stx0_bclk",
+ "hdmitx0_pixelclk"
+ };
+
+ for (i = 0; i < init.num_parents; i++) {
+ unsigned int pidx = jh7110_voutclk_data[idx].parents[i];
+
+ if (pidx < JH7110_VOUTCLK_END)
+ parents[i].hw = &priv->reg[pidx].hw;
+ else if (pidx < JH7110_VOUTCLK_EXT_END)
+ parents[i].fw_name = fw_name[pidx - JH7110_VOUTCLK_END];
+ }
+
+ clk->hw.init = &init;
+ clk->idx = idx;
+ clk->max_div = max & JH71X0_CLK_DIV_MASK;
+
+ ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
+ if (ret)
+ goto err_exit;
+ }
+
+ ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_voutclk_get, priv);
+ if (ret)
+ goto err_exit;
+
+ ret = jh7110_reset_controller_register(priv, "reset-vout", 4);
+ if (ret)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ jh7110_vout_top_crg_disable(top);
+err_clk:
+ pm_runtime_put_sync(priv->dev);
+ pm_runtime_disable(priv->dev);
+ return ret;
+}
+
+static int jh7110_voutcrg_remove(struct platform_device *pdev)
+{
+ void __iomem **base = dev_get_drvdata(&pdev->dev);
+ struct vout_top_crg *top = top_crg_from(base);
+
+ jh7110_vout_top_crg_disable(top);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id jh7110_voutcrg_match[] = {
+ { .compatible = "starfive,jh7110-voutcrg" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jh7110_voutcrg_match);
+
+static struct platform_driver jh7110_voutcrg_driver = {
+ .probe = jh7110_voutcrg_probe,
+ .remove = jh7110_voutcrg_remove,
+ .driver = {
+ .name = "clk-starfive-jh7110-vout",
+ .of_match_table = jh7110_voutcrg_match,
+ },
+};
+module_platform_driver(jh7110_voutcrg_driver);
+
+MODULE_AUTHOR("Xingyu Wu <[email protected]>");
+MODULE_DESCRIPTION("StarFive JH7110 Video-Output clock driver");
+MODULE_LICENSE("GPL");
--
2.25.1


2023-02-21 11:27:42

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v2 07/11] dt-bindings: clock: Add StarFive JH7110 Video-Output clock and reset generator

On 21/02/2023 09:33, Xingyu Wu wrote:
> Add bindings for the Video-Output clock and reset generator (VOUTCRG)
> on the JH7110 RISC-V SoC by StarFive Ltd.
>
> Signed-off-by: Xingyu Wu <[email protected]>
> ---
> .../clock/starfive,jh7110-voutcrg.yaml | 96 +++++++++++++++++++
> .../dt-bindings/clock/starfive,jh7110-crg.h | 22 +++++
> .../dt-bindings/reset/starfive,jh7110-crg.h | 16 ++++
> 3 files changed, 134 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/starfive,jh7110-voutcrg.yaml
>


Reviewed-by: Krzysztof Kozlowski <[email protected]>

Best regards,
Krzysztof


2023-02-27 19:53:58

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v2 11/11] riscv: dts: starfive: jh7110: Add STGCRG/ISPCRG/VOUTCRG nodes

On Tue, Feb 21, 2023 at 04:33:23PM +0800, Xingyu Wu wrote:
> Add STGCRG/ISPCRG/VOUTCRG new node to support JH7110
> System-Top-Group, Image-Signal-Process and Video-Output
> clock and reset drivers for the JH7110 RISC-V SoC.
>
> Signed-off-by: Xingyu Wu <[email protected]>
> ---
> arch/riscv/boot/dts/starfive/jh7110.dtsi | 59 ++++++++++++++++++++++++
> 1 file changed, 59 insertions(+)
>
> diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
> index a5e6fb3ad188..697ab59191a1 100644
> --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
> +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
> @@ -6,6 +6,7 @@
>
> /dts-v1/;
> #include <dt-bindings/clock/starfive,jh7110-crg.h>
> +#include <dt-bindings/power/starfive,jh7110-pmu.h>
> #include <dt-bindings/reset/starfive,jh7110-crg.h>

Please keep these sorted alphabetically, otherwise this *looks* fine to
me.
Reviewed-by: Conor Dooley <[email protected]>

Thanks,
Conor.


Attachments:
(No filename) (988.00 B)
signature.asc (228.00 B)
Download all attachments

2023-02-27 19:56:24

by Conor Dooley

[permalink] [raw]
Subject: Re: [PATCH v2 10/11] riscv: dts: starfive: jh7110: Add DVP and HDMI TX pixel external clocks

On Tue, Feb 21, 2023 at 04:33:22PM +0800, Xingyu Wu wrote:
> Add DVP and HDMI TX pixel external fixed clocks and the rates are
> 74.25MHz and 297MHz.
>
> Signed-off-by: Xingyu Wu <[email protected]>
> ---
> .../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 8 ++++++++
> arch/riscv/boot/dts/starfive/jh7110.dtsi | 12 ++++++++++++
> 2 files changed, 20 insertions(+)
>
> diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
> index c2aa8946a0f1..27af817a55aa 100644
> --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
> +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
> @@ -86,6 +86,14 @@ &mclk_ext {
> clock-frequency = <12288000>;
> };
>
> +&dvp_clk {
> + clock-frequency = <74250000>;
> +};
> +
> +&hdmitx0_pixelclk {
> + clock-frequency = <297000000>;
> +};
> +
> &uart0 {
> pinctrl-names = "default";
> pinctrl-0 = <&uart0_pins>;
> diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
> index 005ead2624d4..a5e6fb3ad188 100644
> --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
> +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
> @@ -245,6 +245,18 @@ mclk_ext: mclk-ext-clock {
> #clock-cells = <0>;
> };
>
> + dvp_clk: dvp-clk-clock {
> + compatible = "fixed-clock";
> + clock-output-names = "dvp_clk";
> + #clock-cells = <0>;
> + };
> +
> + hdmitx0_pixelclk: hdmitx0-pixelclk-clock {
> + compatible = "fixed-clock";
> + clock-output-names = "hdmitx0_pixelclk";
> + #clock-cells = <0>;
> + };
> +

Hmm, would you mind adding these entries with no unit addresses in
alphanumerical order? Both in the soc & board dtsi files.

Thanks,
Conor.


Attachments:
(No filename) (1.73 kB)
signature.asc (228.00 B)
Download all attachments

2023-02-28 01:40:41

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v2 10/11] riscv: dts: starfive: jh7110: Add DVP and HDMI TX pixel external clocks

On 2023/2/28 3:55, Conor Dooley wrote:
> On Tue, Feb 21, 2023 at 04:33:22PM +0800, Xingyu Wu wrote:
>> Add DVP and HDMI TX pixel external fixed clocks and the rates are
>> 74.25MHz and 297MHz.
>>
>> Signed-off-by: Xingyu Wu <[email protected]>
>> ---
>> .../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 8 ++++++++
>> arch/riscv/boot/dts/starfive/jh7110.dtsi | 12 ++++++++++++
>> 2 files changed, 20 insertions(+)
>>
>> diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
>> index c2aa8946a0f1..27af817a55aa 100644
>> --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
>> +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
>> @@ -86,6 +86,14 @@ &mclk_ext {
>> clock-frequency = <12288000>;
>> };
>>
>> +&dvp_clk {
>> + clock-frequency = <74250000>;
>> +};
>> +
>> +&hdmitx0_pixelclk {
>> + clock-frequency = <297000000>;
>> +};
>> +
>> &uart0 {
>> pinctrl-names = "default";
>> pinctrl-0 = <&uart0_pins>;
>> diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
>> index 005ead2624d4..a5e6fb3ad188 100644
>> --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
>> +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
>> @@ -245,6 +245,18 @@ mclk_ext: mclk-ext-clock {
>> #clock-cells = <0>;
>> };
>>
>> + dvp_clk: dvp-clk-clock {
>> + compatible = "fixed-clock";
>> + clock-output-names = "dvp_clk";
>> + #clock-cells = <0>;
>> + };
>> +
>> + hdmitx0_pixelclk: hdmitx0-pixelclk-clock {
>> + compatible = "fixed-clock";
>> + clock-output-names = "hdmitx0_pixelclk";
>> + #clock-cells = <0>;
>> + };
>> +
>
> Hmm, would you mind adding these entries with no unit addresses in
> alphanumerical order? Both in the soc & board dtsi files.
>

Oh, It was my negligence. I will adjust it. Thanks.

Best regards,
Xingyu Wu


2023-03-02 15:40:46

by Emil Renner Berthing

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] clk: starfive: Add StarFive JH7110 Image-Signal-Process clock driver

On Tue, 21 Feb 2023 at 09:36, Xingyu Wu <[email protected]> wrote:
>
> Add driver for the StarFive JH7110 Image-Signal-Process clock controller.
>
> Signed-off-by: Xingyu Wu <[email protected]>
> ---
> drivers/clk/starfive/Kconfig | 11 +
> drivers/clk/starfive/Makefile | 1 +
> .../clk/starfive/clk-starfive-jh7110-isp.c | 254 ++++++++++++++++++
> 3 files changed, 266 insertions(+)
> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-isp.c
>
> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
> index a462b6e53543..59499acb95f7 100644
> --- a/drivers/clk/starfive/Kconfig
> +++ b/drivers/clk/starfive/Kconfig
> @@ -53,3 +53,14 @@ config CLK_STARFIVE_JH7110_STG
> help
> Say yes here to support the System-Top-Group clock controller
> on the StarFive JH7110 SoC.
> +
> +config CLK_STARFIVE_JH7110_ISP
> + tristate "StarFive JH7110 Image-Signal-Process clock support"
> + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
> + select AUXILIARY_BUS
> + select CLK_STARFIVE_JH71X0
> + select RESET_STARFIVE_JH7110
> + default CLK_STARFIVE_JH7110_SYS

default m if ARCH_STARFIVE

> + help
> + Say yes here to support the Image-Signal-Process clock controller
> + on the StarFive JH7110 SoC.
> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
> index b81e97ee2659..76fb9f8d628b 100644
> --- a/drivers/clk/starfive/Makefile
> +++ b/drivers/clk/starfive/Makefile
> @@ -7,3 +7,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
> obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
> obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
> +obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
> new file mode 100644
> index 000000000000..b5bce1ac22e0
> --- /dev/null
> +++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
> @@ -0,0 +1,254 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * StarFive JH7110 Image-Signal-Process Clock Driver
> + *
> + * Copyright (C) 2022 StarFive Technology Co., Ltd.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/reset.h>
> +
> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
> +
> +#include "clk-starfive-jh71x0.h"
> +
> +/* external clocks */
> +#define JH7110_ISPCLK_ISP_TOP_CORE (JH7110_ISPCLK_END + 0)
> +#define JH7110_ISPCLK_ISP_TOP_AXI (JH7110_ISPCLK_END + 1)
> +#define JH7110_ISPCLK_NOC_BUS_ISP_AXI (JH7110_ISPCLK_END + 2)
> +#define JH7110_ISPCLK_DVP_CLK (JH7110_ISPCLK_END + 3)
> +#define JH7110_ISPCLK_EXT_END (JH7110_ISPCLK_END + 4)
> +
> +static const struct jh71x0_clk_data jh7110_ispclk_data[] = {
> + /* syscon */
> + JH71X0__DIV(JH7110_ISPCLK_DOM4_APB_FUNC, "dom4_apb_func", 15,
> + JH7110_ISPCLK_ISP_TOP_AXI),
> + JH71X0__DIV(JH7110_ISPCLK_MIPI_RX0_PXL, "mipi_rx0_pxl", 8,
> + JH7110_ISPCLK_ISP_TOP_CORE),
> + JH71X0__INV(JH7110_ISPCLK_DVP_INV, "dvp_inv", JH7110_ISPCLK_DVP_CLK),
> + /* vin */
> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_CFGCLK_IN, "m31dphy_cfgclk_in", 16,
> + JH7110_ISPCLK_ISP_TOP_CORE),
> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_REFCLK_IN, "m31dphy_refclk_in", 16,
> + JH7110_ISPCLK_ISP_TOP_CORE),
> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_TXCLKESC_LAN0, "m31dphy_txclkesc_lan0", 60,
> + JH7110_ISPCLK_ISP_TOP_CORE),
> + JH71X0_GATE(JH7110_ISPCLK_VIN_PCLK, "vin_pclk", CLK_IGNORE_UNUSED,
> + JH7110_ISPCLK_DOM4_APB_FUNC),
> + JH71X0__DIV(JH7110_ISPCLK_VIN_SYS_CLK, "vin_sys_clk", 8, JH7110_ISPCLK_ISP_TOP_CORE),
> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF0, "vin_pixel_clk_if0", CLK_IGNORE_UNUSED,
> + JH7110_ISPCLK_MIPI_RX0_PXL),
> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF1, "vin_pixel_clk_if1", CLK_IGNORE_UNUSED,
> + JH7110_ISPCLK_MIPI_RX0_PXL),
> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF2, "vin_pixel_clk_if2", CLK_IGNORE_UNUSED,
> + JH7110_ISPCLK_MIPI_RX0_PXL),
> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF3, "vin_pixel_clk_if3", CLK_IGNORE_UNUSED,
> + JH7110_ISPCLK_MIPI_RX0_PXL),
> + JH71X0__MUX(JH7110_ISPCLK_VIN_CLK_P_AXIWR, "vin_clk_p_axiwr", 2,
> + JH7110_ISPCLK_MIPI_RX0_PXL,
> + JH7110_ISPCLK_DVP_INV),
> + /* ispv2_top_wrapper */
> + JH71X0_GMUX(JH7110_ISPCLK_ISPV2_TOP_WRAPPER_CLK_C, "ispv2_top_wrapper_clk_c",
> + CLK_IGNORE_UNUSED, 2,
> + JH7110_ISPCLK_MIPI_RX0_PXL,
> + JH7110_ISPCLK_DVP_INV),
> +};

Are all the clocks marked CLK_IGNORE_UNUSED here critical or are they
just marked like so because the corresponding drivers don't yet claim
the clocks they need? Please mark the clocks that can never be turned
off CLK_IS_CRITICAL and remove the flag from the rest of the clocks.

> +struct isp_top_crg {
> + struct clk_bulk_data *top_clks;
> + struct reset_control *top_rsts;
> + int top_clks_num;
> + void __iomem *base;
> +};
> +
> +static struct clk_bulk_data jh7110_isp_top_clks[] = {
> + { .id = "isp_top_core" },
> + { .id = "isp_top_axi" }
> +};
> +
> +static struct isp_top_crg *top_crg_from(void __iomem **base)
> +{
> + return container_of(base, struct isp_top_crg, base);
> +}
> +
> +static int jh7110_isp_top_crg_get(struct jh71x0_clk_priv *priv, struct isp_top_crg *top)
> +{
> + int ret;
> +
> + top->top_clks = jh7110_isp_top_clks;
> + top->top_clks_num = ARRAY_SIZE(jh7110_isp_top_clks);
> + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
> + if (ret) {
> + dev_err(priv->dev, "top clks get failed: %d\n", ret);
> + return ret;
> + }
> +
> + /* The resets should be shared and other ISP modules will use its. */
> + top->top_rsts = devm_reset_control_array_get_shared(priv->dev);
> + if (IS_ERR(top->top_rsts)) {
> + dev_err(priv->dev, "top rsts get failed\n");
> + return PTR_ERR(top->top_rsts);
> + }
> +
> + return 0;
> +}
> +
> +static int jh7110_isp_top_crg_enable(struct isp_top_crg *top)
> +{
> + int ret;
> +
> + ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
> + if (ret)
> + return ret;
> +
> + return reset_control_deassert(top->top_rsts);
> +}
> +
> +static void jh7110_isp_top_crg_disable(struct isp_top_crg *top)
> +{
> + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
> +}
> +
> +static struct clk_hw *jh7110_ispclk_get(struct of_phandle_args *clkspec, void *data)
> +{
> + struct jh71x0_clk_priv *priv = data;
> + unsigned int idx = clkspec->args[0];
> +
> + if (idx < JH7110_ISPCLK_END)
> + return &priv->reg[idx].hw;
> +
> + return ERR_PTR(-EINVAL);
> +}
> +
> +static int jh7110_ispcrg_probe(struct platform_device *pdev)
> +{
> + struct jh71x0_clk_priv *priv;
> + struct isp_top_crg *top;
> + unsigned int idx;
> + int ret;
> +
> + priv = devm_kzalloc(&pdev->dev,
> + struct_size(priv, reg, JH7110_ISPCLK_END),
> + GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
> + if (!top)
> + return -ENOMEM;
> +
> + spin_lock_init(&priv->rmw_lock);
> + priv->dev = &pdev->dev;
> + priv->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(priv->base))
> + return PTR_ERR(priv->base);
> +
> + top->base = priv->base;
> + dev_set_drvdata(priv->dev, (void *)(&top->base));
> +
> + pm_runtime_enable(priv->dev);
> + ret = pm_runtime_get_sync(priv->dev);
> + if (ret < 0) {
> + dev_err(priv->dev, "failed to turn on power: %d\n", ret);
> + return ret;
> + }
> +
> + ret = jh7110_isp_top_crg_get(priv, top);
> + if (ret)
> + goto err_clk;
> +
> + ret = jh7110_isp_top_crg_enable(top);
> + if (ret)
> + goto err_clk;
> +
> + for (idx = 0; idx < JH7110_ISPCLK_END; idx++) {
> + u32 max = jh7110_ispclk_data[idx].max;
> + struct clk_parent_data parents[4] = {};
> + struct clk_init_data init = {
> + .name = jh7110_ispclk_data[idx].name,
> + .ops = starfive_jh71x0_clk_ops(max),
> + .parent_data = parents,
> + .num_parents =
> + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
> + .flags = jh7110_ispclk_data[idx].flags,
> + };
> + struct jh71x0_clk *clk = &priv->reg[idx];
> + unsigned int i;
> + char *fw_name[JH7110_ISPCLK_EXT_END - JH7110_ISPCLK_END] = {
> + "isp_top_core",
> + "isp_top_axi",
> + "noc_bus_isp_axi",
> + "dvp_clk"
> + };
> +
> + for (i = 0; i < init.num_parents; i++) {
> + unsigned int pidx = jh7110_ispclk_data[idx].parents[i];
> +
> + if (pidx < JH7110_ISPCLK_END)
> + parents[i].hw = &priv->reg[pidx].hw;
> + else
> + parents[i].fw_name = fw_name[pidx - JH7110_ISPCLK_END];
> + }
> +
> + clk->hw.init = &init;
> + clk->idx = idx;
> + clk->max_div = max & JH71X0_CLK_DIV_MASK;
> +
> + ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
> + if (ret)
> + goto err_exit;
> + }
> +
> + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_ispclk_get, priv);
> + if (ret)
> + goto err_exit;
> +
> + ret = jh7110_reset_controller_register(priv, "reset-isp", 3);
> + if (ret)
> + goto err_exit;
> +
> + return 0;
> +
> +err_exit:
> + jh7110_isp_top_crg_disable(top);
> +err_clk:
> + pm_runtime_put_sync(priv->dev);
> + pm_runtime_disable(priv->dev);
> + return ret;
> +}
> +
> +static int jh7110_ispcrg_remove(struct platform_device *pdev)
> +{
> + void __iomem **base = dev_get_drvdata(&pdev->dev);
> + struct isp_top_crg *top = top_crg_from(base);
> +
> + jh7110_isp_top_crg_disable(top);
> + pm_runtime_disable(&pdev->dev);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id jh7110_ispcrg_match[] = {
> + { .compatible = "starfive,jh7110-ispcrg" },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, jh7110_ispcrg_match);
> +
> +static struct platform_driver jh7110_ispcrg_driver = {
> + .probe = jh7110_ispcrg_probe,
> + .remove = jh7110_ispcrg_remove,
> + .driver = {
> + .name = "clk-starfive-jh7110-isp",
> + .of_match_table = jh7110_ispcrg_match,
> + },
> +};
> +module_platform_driver(jh7110_ispcrg_driver);
> +
> +MODULE_AUTHOR("Xingyu Wu <[email protected]>");
> +MODULE_DESCRIPTION("StarFive JH7110 Image-Signal-Process clock driver");
> +MODULE_LICENSE("GPL");
> --
> 2.25.1
>
>
> _______________________________________________
> linux-riscv mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-riscv

2023-03-02 15:49:43

by Emil Renner Berthing

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] clk: starfive: Add StarFive JH7110 Video-Output clock driver

On Tue, 21 Feb 2023 at 09:40, Xingyu Wu <[email protected]> wrote:
>
> Add driver for the StarFive JH7110 Video-Output clock controller.
>
> Signed-off-by: Xingyu Wu <[email protected]>
> ---
> drivers/clk/starfive/Kconfig | 11 +
> drivers/clk/starfive/Makefile | 1 +
> .../clk/starfive/clk-starfive-jh7110-vout.c | 261 ++++++++++++++++++
> 3 files changed, 273 insertions(+)
> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-vout.c
>
> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
> index 59499acb95f7..5ebf1ed08627 100644
> --- a/drivers/clk/starfive/Kconfig
> +++ b/drivers/clk/starfive/Kconfig
> @@ -64,3 +64,14 @@ config CLK_STARFIVE_JH7110_ISP
> help
> Say yes here to support the Image-Signal-Process clock controller
> on the StarFive JH7110 SoC.
> +
> +config CLK_STARFIVE_JH7110_VOUT
> + tristate "StarFive JH7110 Video-Output clock support"
> + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
> + select AUXILIARY_BUS
> + select CLK_STARFIVE_JH71X0
> + select RESET_STARFIVE_JH7110
> + default CLK_STARFIVE_JH7110_SYS

default m if ARCH_STARFIVE

> + help
> + Say yes here to support the Video-Output clock controller
> + on the StarFive JH7110 SoC.
> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
> index 76fb9f8d628b..841377e45bb6 100644
> --- a/drivers/clk/starfive/Makefile
> +++ b/drivers/clk/starfive/Makefile
> @@ -8,3 +8,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
> obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
> obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
> +obj-$(CONFIG_CLK_STARFIVE_JH7110_VOUT) += clk-starfive-jh7110-vout.o
> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-vout.c b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
> new file mode 100644
> index 000000000000..d786537563a4
> --- /dev/null
> +++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
> @@ -0,0 +1,261 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * StarFive JH7110 Video-Output Clock Driver
> + *
> + * Copyright (C) 2022 StarFive Technology Co., Ltd.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/reset.h>
> +
> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
> +
> +#include "clk-starfive-jh71x0.h"
> +
> +/* external clocks */
> +#define JH7110_VOUTCLK_VOUT_SRC (JH7110_VOUTCLK_END + 0)
> +#define JH7110_VOUTCLK_VOUT_TOP_AHB (JH7110_VOUTCLK_END + 1)
> +#define JH7110_VOUTCLK_VOUT_TOP_AXI (JH7110_VOUTCLK_END + 2)
> +#define JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK (JH7110_VOUTCLK_END + 3)
> +#define JH7110_VOUTCLK_I2STX0_BCLK (JH7110_VOUTCLK_END + 4)
> +#define JH7110_VOUTCLK_HDMITX0_PIXELCLK (JH7110_VOUTCLK_END + 5)
> +#define JH7110_VOUTCLK_EXT_END (JH7110_VOUTCLK_END + 6)
> +
> +static const struct jh71x0_clk_data jh7110_voutclk_data[] = {
> + /* divider */
> + JH71X0__DIV(JH7110_VOUTCLK_APB, "apb", 8, JH7110_VOUTCLK_VOUT_TOP_AHB),
> + JH71X0__DIV(JH7110_VOUTCLK_DC8200_PIX, "dc8200_pix", 63, JH7110_VOUTCLK_VOUT_SRC),
> + JH71X0__DIV(JH7110_VOUTCLK_DSI_SYS, "dsi_sys", 31, JH7110_VOUTCLK_VOUT_SRC),
> + JH71X0__DIV(JH7110_VOUTCLK_TX_ESC, "tx_esc", 31, JH7110_VOUTCLK_VOUT_TOP_AHB),
> + /* dc8200 */
> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AXI, "dc8200_axi", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_CORE, "dc8200_core", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AHB, "dc8200_ahb", 0, JH7110_VOUTCLK_VOUT_TOP_AHB),
> + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX0, "dc8200_pix0", 0, 2,
> + JH7110_VOUTCLK_DC8200_PIX,
> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
> + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX1, "dc8200_pix1", 0, 2,
> + JH7110_VOUTCLK_DC8200_PIX,
> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
> + /* LCD */
> + JH71X0_GMUX(JH7110_VOUTCLK_DOM_VOUT_TOP_LCD, "dom_vout_top_lcd", 0, 2,
> + JH7110_VOUTCLK_DC8200_PIX0,
> + JH7110_VOUTCLK_DC8200_PIX1),
> + /* dsiTx */
> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_APB, "dsiTx_apb", 0, JH7110_VOUTCLK_DSI_SYS),
> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_SYS, "dsiTx_sys", 0, JH7110_VOUTCLK_DSI_SYS),
> + JH71X0_GMUX(JH7110_VOUTCLK_DSITX_DPI, "dsiTx_dpi", 0, 2,
> + JH7110_VOUTCLK_DC8200_PIX,
> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_TXESC, "dsiTx_txesc", 0, JH7110_VOUTCLK_TX_ESC),
> + /* mipitx DPHY */
> + JH71X0_GATE(JH7110_VOUTCLK_MIPITX_DPHY_TXESC, "mipitx_dphy_txesc", 0,
> + JH7110_VOUTCLK_TX_ESC),
> + /* hdmi */
> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_MCLK, "hdmi_tx_mclk", 0,
> + JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK),
> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_BCLK, "hdmi_tx_bclk", 0,
> + JH7110_VOUTCLK_I2STX0_BCLK),
> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_SYS, "hdmi_tx_sys", 0, JH7110_VOUTCLK_APB),
> +};
> +
> +struct vout_top_crg {
> + struct clk_bulk_data *top_clks;
> + struct reset_control *top_rst;
> + int top_clks_num;
> + void __iomem *base;
> +};
> +
> +static struct clk_bulk_data jh7110_vout_top_clks[] = {
> + { .id = "vout_src" },
> + { .id = "vout_top_ahb" }
> +};
> +
> +static struct vout_top_crg *top_crg_from(void __iomem **base)
> +{
> + return container_of(base, struct vout_top_crg, base);
> +}
> +
> +static int jh7110_vout_top_crg_get(struct jh71x0_clk_priv *priv, struct vout_top_crg *top)
> +{
> + int ret;
> +
> + top->top_clks = jh7110_vout_top_clks;
> + top->top_clks_num = ARRAY_SIZE(jh7110_vout_top_clks);
> + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
> + if (ret) {
> + dev_err(priv->dev, "top clks get failed: %d\n", ret);
> + return ret;
> + }
> +
> + /* The reset should be shared and other Vout modules will use its. */
> + top->top_rst = devm_reset_control_get_shared(priv->dev, NULL);
> + if (IS_ERR(top->top_rst)) {
> + dev_err(priv->dev, "top rst get failed\n");
> + return PTR_ERR(top->top_rst);
> + }
> +
> + return 0;
> +}
> +
> +static int jh7110_vout_top_crg_enable(struct vout_top_crg *top)
> +{
> + int ret;
> +
> + ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
> + if (ret)
> + return ret;

Hmm.. do all the clocks used as input really need to be enabled for
any one of the vout clocks to work?

In other words: suppose you just need a single clock in the VOUTCRG
domain. Do we really need to turn on all the input clocks for the
VOUTCRG for that one clock to work? Normally I'd expect the clock
framework to make sure all parents of that clock are enabled.

> +
> + return reset_control_deassert(top->top_rst);
> +}
> +
> +static void jh7110_vout_top_crg_disable(struct vout_top_crg *top)
> +{
> + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
> +}
> +
> +static struct clk_hw *jh7110_voutclk_get(struct of_phandle_args *clkspec, void *data)
> +{
> + struct jh71x0_clk_priv *priv = data;
> + unsigned int idx = clkspec->args[0];
> +
> + if (idx < JH7110_VOUTCLK_END)
> + return &priv->reg[idx].hw;
> +
> + return ERR_PTR(-EINVAL);
> +}
> +
> +static int jh7110_voutcrg_probe(struct platform_device *pdev)
> +{
> + struct jh71x0_clk_priv *priv;
> + struct vout_top_crg *top;
> + unsigned int idx;
> + int ret;
> +
> + priv = devm_kzalloc(&pdev->dev,
> + struct_size(priv, reg, JH7110_VOUTCLK_END),
> + GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
> + if (!top)
> + return -ENOMEM;
> +
> + spin_lock_init(&priv->rmw_lock);
> + priv->dev = &pdev->dev;
> + priv->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(priv->base))
> + return PTR_ERR(priv->base);
> +
> + top->base = priv->base;
> + dev_set_drvdata(priv->dev, (void *)(&top->base));
> +
> + pm_runtime_enable(priv->dev);
> + ret = pm_runtime_get_sync(priv->dev);
> + if (ret < 0) {
> + dev_err(priv->dev, "failed to turn power: %d\n", ret);
> + return ret;
> + }
> +
> + ret = jh7110_vout_top_crg_get(priv, top);
> + if (ret)
> + goto err_clk;
> +
> + ret = jh7110_vout_top_crg_enable(top);
> + if (ret)
> + goto err_clk;
> +
> + for (idx = 0; idx < JH7110_VOUTCLK_END; idx++) {
> + u32 max = jh7110_voutclk_data[idx].max;
> + struct clk_parent_data parents[4] = {};
> + struct clk_init_data init = {
> + .name = jh7110_voutclk_data[idx].name,
> + .ops = starfive_jh71x0_clk_ops(max),
> + .parent_data = parents,
> + .num_parents =
> + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
> + .flags = jh7110_voutclk_data[idx].flags,
> + };
> + struct jh71x0_clk *clk = &priv->reg[idx];
> + unsigned int i;
> + char *fw_name[JH7110_VOUTCLK_EXT_END - JH7110_VOUTCLK_END] = {

this can be const char *const fw_name[...] right?

> + "vout_src",
> + "vout_top_ahb",
> + "vout_top_axi",
> + "vout_top_hdmitx0_mclk",
> + "i2stx0_bclk",
> + "hdmitx0_pixelclk"
> + };
> +
> + for (i = 0; i < init.num_parents; i++) {
> + unsigned int pidx = jh7110_voutclk_data[idx].parents[i];
> +
> + if (pidx < JH7110_VOUTCLK_END)
> + parents[i].hw = &priv->reg[pidx].hw;
> + else if (pidx < JH7110_VOUTCLK_EXT_END)
> + parents[i].fw_name = fw_name[pidx - JH7110_VOUTCLK_END];
> + }
> +
> + clk->hw.init = &init;
> + clk->idx = idx;
> + clk->max_div = max & JH71X0_CLK_DIV_MASK;
> +
> + ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
> + if (ret)
> + goto err_exit;
> + }
> +
> + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_voutclk_get, priv);
> + if (ret)
> + goto err_exit;
> +
> + ret = jh7110_reset_controller_register(priv, "reset-vout", 4);
> + if (ret)
> + goto err_exit;
> +
> + return 0;
> +
> +err_exit:
> + jh7110_vout_top_crg_disable(top);
> +err_clk:
> + pm_runtime_put_sync(priv->dev);
> + pm_runtime_disable(priv->dev);
> + return ret;
> +}
> +
> +static int jh7110_voutcrg_remove(struct platform_device *pdev)
> +{
> + void __iomem **base = dev_get_drvdata(&pdev->dev);
> + struct vout_top_crg *top = top_crg_from(base);
> +
> + jh7110_vout_top_crg_disable(top);
> + pm_runtime_disable(&pdev->dev);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id jh7110_voutcrg_match[] = {
> + { .compatible = "starfive,jh7110-voutcrg" },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, jh7110_voutcrg_match);
> +
> +static struct platform_driver jh7110_voutcrg_driver = {
> + .probe = jh7110_voutcrg_probe,
> + .remove = jh7110_voutcrg_remove,
> + .driver = {
> + .name = "clk-starfive-jh7110-vout",
> + .of_match_table = jh7110_voutcrg_match,
> + },
> +};
> +module_platform_driver(jh7110_voutcrg_driver);
> +
> +MODULE_AUTHOR("Xingyu Wu <[email protected]>");
> +MODULE_DESCRIPTION("StarFive JH7110 Video-Output clock driver");
> +MODULE_LICENSE("GPL");
> --
> 2.25.1
>
>
> _______________________________________________
> linux-riscv mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-riscv

2023-03-03 03:37:30

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] clk: starfive: Add StarFive JH7110 Video-Output clock driver

On 2023/3/2 23:48, Emil Renner Berthing wrote:
> On Tue, 21 Feb 2023 at 09:40, Xingyu Wu <[email protected]> wrote:
>>
>> Add driver for the StarFive JH7110 Video-Output clock controller.
>>
>> Signed-off-by: Xingyu Wu <[email protected]>
>> ---
>> drivers/clk/starfive/Kconfig | 11 +
>> drivers/clk/starfive/Makefile | 1 +
>> .../clk/starfive/clk-starfive-jh7110-vout.c | 261 ++++++++++++++++++
>> 3 files changed, 273 insertions(+)
>> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-vout.c
>>
>> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
>> index 59499acb95f7..5ebf1ed08627 100644
>> --- a/drivers/clk/starfive/Kconfig
>> +++ b/drivers/clk/starfive/Kconfig
>> @@ -64,3 +64,14 @@ config CLK_STARFIVE_JH7110_ISP
>> help
>> Say yes here to support the Image-Signal-Process clock controller
>> on the StarFive JH7110 SoC.
>> +
>> +config CLK_STARFIVE_JH7110_VOUT
>> + tristate "StarFive JH7110 Video-Output clock support"
>> + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
>> + select AUXILIARY_BUS
>> + select CLK_STARFIVE_JH71X0
>> + select RESET_STARFIVE_JH7110
>> + default CLK_STARFIVE_JH7110_SYS
>
> default m if ARCH_STARFIVE

Will modify it.

>
>> + help
>> + Say yes here to support the Video-Output clock controller
>> + on the StarFive JH7110 SoC.
>> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
>> index 76fb9f8d628b..841377e45bb6 100644
>> --- a/drivers/clk/starfive/Makefile
>> +++ b/drivers/clk/starfive/Makefile
>> @@ -8,3 +8,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
>> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
>> obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
>> obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
>> +obj-$(CONFIG_CLK_STARFIVE_JH7110_VOUT) += clk-starfive-jh7110-vout.o
>> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-vout.c b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
>> new file mode 100644
>> index 000000000000..d786537563a4
>> --- /dev/null
>> +++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
>> @@ -0,0 +1,261 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * StarFive JH7110 Video-Output Clock Driver
>> + *
>> + * Copyright (C) 2022 StarFive Technology Co., Ltd.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/io.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/reset.h>
>> +
>> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
>> +
>> +#include "clk-starfive-jh71x0.h"
>> +
>> +/* external clocks */
>> +#define JH7110_VOUTCLK_VOUT_SRC (JH7110_VOUTCLK_END + 0)
>> +#define JH7110_VOUTCLK_VOUT_TOP_AHB (JH7110_VOUTCLK_END + 1)
>> +#define JH7110_VOUTCLK_VOUT_TOP_AXI (JH7110_VOUTCLK_END + 2)
>> +#define JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK (JH7110_VOUTCLK_END + 3)
>> +#define JH7110_VOUTCLK_I2STX0_BCLK (JH7110_VOUTCLK_END + 4)
>> +#define JH7110_VOUTCLK_HDMITX0_PIXELCLK (JH7110_VOUTCLK_END + 5)
>> +#define JH7110_VOUTCLK_EXT_END (JH7110_VOUTCLK_END + 6)
>> +
>> +static const struct jh71x0_clk_data jh7110_voutclk_data[] = {
>> + /* divider */
>> + JH71X0__DIV(JH7110_VOUTCLK_APB, "apb", 8, JH7110_VOUTCLK_VOUT_TOP_AHB),
>> + JH71X0__DIV(JH7110_VOUTCLK_DC8200_PIX, "dc8200_pix", 63, JH7110_VOUTCLK_VOUT_SRC),
>> + JH71X0__DIV(JH7110_VOUTCLK_DSI_SYS, "dsi_sys", 31, JH7110_VOUTCLK_VOUT_SRC),
>> + JH71X0__DIV(JH7110_VOUTCLK_TX_ESC, "tx_esc", 31, JH7110_VOUTCLK_VOUT_TOP_AHB),
>> + /* dc8200 */
>> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AXI, "dc8200_axi", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
>> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_CORE, "dc8200_core", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
>> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AHB, "dc8200_ahb", 0, JH7110_VOUTCLK_VOUT_TOP_AHB),
>> + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX0, "dc8200_pix0", 0, 2,
>> + JH7110_VOUTCLK_DC8200_PIX,
>> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
>> + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX1, "dc8200_pix1", 0, 2,
>> + JH7110_VOUTCLK_DC8200_PIX,
>> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
>> + /* LCD */
>> + JH71X0_GMUX(JH7110_VOUTCLK_DOM_VOUT_TOP_LCD, "dom_vout_top_lcd", 0, 2,
>> + JH7110_VOUTCLK_DC8200_PIX0,
>> + JH7110_VOUTCLK_DC8200_PIX1),
>> + /* dsiTx */
>> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_APB, "dsiTx_apb", 0, JH7110_VOUTCLK_DSI_SYS),
>> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_SYS, "dsiTx_sys", 0, JH7110_VOUTCLK_DSI_SYS),
>> + JH71X0_GMUX(JH7110_VOUTCLK_DSITX_DPI, "dsiTx_dpi", 0, 2,
>> + JH7110_VOUTCLK_DC8200_PIX,
>> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
>> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_TXESC, "dsiTx_txesc", 0, JH7110_VOUTCLK_TX_ESC),
>> + /* mipitx DPHY */
>> + JH71X0_GATE(JH7110_VOUTCLK_MIPITX_DPHY_TXESC, "mipitx_dphy_txesc", 0,
>> + JH7110_VOUTCLK_TX_ESC),
>> + /* hdmi */
>> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_MCLK, "hdmi_tx_mclk", 0,
>> + JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK),
>> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_BCLK, "hdmi_tx_bclk", 0,
>> + JH7110_VOUTCLK_I2STX0_BCLK),
>> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_SYS, "hdmi_tx_sys", 0, JH7110_VOUTCLK_APB),
>> +};
>> +
>> +struct vout_top_crg {
>> + struct clk_bulk_data *top_clks;
>> + struct reset_control *top_rst;
>> + int top_clks_num;
>> + void __iomem *base;
>> +};
>> +
>> +static struct clk_bulk_data jh7110_vout_top_clks[] = {
>> + { .id = "vout_src" },
>> + { .id = "vout_top_ahb" }
>> +};
>> +
>> +static struct vout_top_crg *top_crg_from(void __iomem **base)
>> +{
>> + return container_of(base, struct vout_top_crg, base);
>> +}
>> +
>> +static int jh7110_vout_top_crg_get(struct jh71x0_clk_priv *priv, struct vout_top_crg *top)
>> +{
>> + int ret;
>> +
>> + top->top_clks = jh7110_vout_top_clks;
>> + top->top_clks_num = ARRAY_SIZE(jh7110_vout_top_clks);
>> + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
>> + if (ret) {
>> + dev_err(priv->dev, "top clks get failed: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + /* The reset should be shared and other Vout modules will use its. */
>> + top->top_rst = devm_reset_control_get_shared(priv->dev, NULL);
>> + if (IS_ERR(top->top_rst)) {
>> + dev_err(priv->dev, "top rst get failed\n");
>> + return PTR_ERR(top->top_rst);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int jh7110_vout_top_crg_enable(struct vout_top_crg *top)
>> +{
>> + int ret;
>> +
>> + ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
>> + if (ret)
>> + return ret;
>
> Hmm.. do all the clocks used as input really need to be enabled for
> any one of the vout clocks to work?
>
> In other words: suppose you just need a single clock in the VOUTCRG
> domain. Do we really need to turn on all the input clocks for the
> VOUTCRG for that one clock to work? Normally I'd expect the clock
> framework to make sure all parents of that clock are enabled.

It must enable core clock and ahb clock before reading or writing VOUTCRG registers
otherwise it would be failed to read and write. And it is even crash if it don't
enable core clock before reading or writing ISPCRG registers.
This serious problem was found when debugging earlier.

>
>> +
>> + return reset_control_deassert(top->top_rst);
>> +}
>> +
>> +static void jh7110_vout_top_crg_disable(struct vout_top_crg *top)
>> +{
>> + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
>> +}
>> +
>> +static struct clk_hw *jh7110_voutclk_get(struct of_phandle_args *clkspec, void *data)
>> +{
>> + struct jh71x0_clk_priv *priv = data;
>> + unsigned int idx = clkspec->args[0];
>> +
>> + if (idx < JH7110_VOUTCLK_END)
>> + return &priv->reg[idx].hw;
>> +
>> + return ERR_PTR(-EINVAL);
>> +}
>> +
>> +static int jh7110_voutcrg_probe(struct platform_device *pdev)
>> +{
>> + struct jh71x0_clk_priv *priv;
>> + struct vout_top_crg *top;
>> + unsigned int idx;
>> + int ret;
>> +
>> + priv = devm_kzalloc(&pdev->dev,
>> + struct_size(priv, reg, JH7110_VOUTCLK_END),
>> + GFP_KERNEL);
>> + if (!priv)
>> + return -ENOMEM;
>> +
>> + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
>> + if (!top)
>> + return -ENOMEM;
>> +
>> + spin_lock_init(&priv->rmw_lock);
>> + priv->dev = &pdev->dev;
>> + priv->base = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(priv->base))
>> + return PTR_ERR(priv->base);
>> +
>> + top->base = priv->base;
>> + dev_set_drvdata(priv->dev, (void *)(&top->base));
>> +
>> + pm_runtime_enable(priv->dev);
>> + ret = pm_runtime_get_sync(priv->dev);
>> + if (ret < 0) {
>> + dev_err(priv->dev, "failed to turn power: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = jh7110_vout_top_crg_get(priv, top);
>> + if (ret)
>> + goto err_clk;
>> +
>> + ret = jh7110_vout_top_crg_enable(top);
>> + if (ret)
>> + goto err_clk;
>> +
>> + for (idx = 0; idx < JH7110_VOUTCLK_END; idx++) {
>> + u32 max = jh7110_voutclk_data[idx].max;
>> + struct clk_parent_data parents[4] = {};
>> + struct clk_init_data init = {
>> + .name = jh7110_voutclk_data[idx].name,
>> + .ops = starfive_jh71x0_clk_ops(max),
>> + .parent_data = parents,
>> + .num_parents =
>> + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
>> + .flags = jh7110_voutclk_data[idx].flags,
>> + };
>> + struct jh71x0_clk *clk = &priv->reg[idx];
>> + unsigned int i;
>> + char *fw_name[JH7110_VOUTCLK_EXT_END - JH7110_VOUTCLK_END] = {
>
> this can be const char *const fw_name[...] right?
>
>> + "vout_src",
>> + "vout_top_ahb",
>> + "vout_top_axi",
>> + "vout_top_hdmitx0_mclk",
>> + "i2stx0_bclk",
>> + "hdmitx0_pixelclk"
>> + };
>> +
>> + for (i = 0; i < init.num_parents; i++) {
>> + unsigned int pidx = jh7110_voutclk_data[idx].parents[i];
>> +
>> + if (pidx < JH7110_VOUTCLK_END)
>> + parents[i].hw = &priv->reg[pidx].hw;
>> + else if (pidx < JH7110_VOUTCLK_EXT_END)
>> + parents[i].fw_name = fw_name[pidx - JH7110_VOUTCLK_END];
>> + }
>> +
>> + clk->hw.init = &init;
>> + clk->idx = idx;
>> + clk->max_div = max & JH71X0_CLK_DIV_MASK;
>> +
>> + ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
>> + if (ret)
>> + goto err_exit;
>> + }
>> +
>> + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_voutclk_get, priv);
>> + if (ret)
>> + goto err_exit;
>> +
>> + ret = jh7110_reset_controller_register(priv, "reset-vout", 4);
>> + if (ret)
>> + goto err_exit;
>> +
>> + return 0;
>> +
>> +err_exit:
>> + jh7110_vout_top_crg_disable(top);
>> +err_clk:
>> + pm_runtime_put_sync(priv->dev);
>> + pm_runtime_disable(priv->dev);
>> + return ret;
>> +}
>> +
>> +static int jh7110_voutcrg_remove(struct platform_device *pdev)
>> +{
>> + void __iomem **base = dev_get_drvdata(&pdev->dev);
>> + struct vout_top_crg *top = top_crg_from(base);
>> +
>> + jh7110_vout_top_crg_disable(top);
>> + pm_runtime_disable(&pdev->dev);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct of_device_id jh7110_voutcrg_match[] = {
>> + { .compatible = "starfive,jh7110-voutcrg" },
>> + { /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, jh7110_voutcrg_match);
>> +
>> +static struct platform_driver jh7110_voutcrg_driver = {
>> + .probe = jh7110_voutcrg_probe,
>> + .remove = jh7110_voutcrg_remove,
>> + .driver = {
>> + .name = "clk-starfive-jh7110-vout",
>> + .of_match_table = jh7110_voutcrg_match,
>> + },
>> +};
>> +module_platform_driver(jh7110_voutcrg_driver);
>> +
>> +MODULE_AUTHOR("Xingyu Wu <[email protected]>");
>> +MODULE_DESCRIPTION("StarFive JH7110 Video-Output clock driver");
>> +MODULE_LICENSE("GPL");
>> --
>> 2.25.1
>>
>>
>> _______________________________________________
>> linux-riscv mailing list
>> [email protected]
>> http://lists.infradead.org/mailman/listinfo/linux-riscv

Best regards,
Xingyu Wu

2023-03-03 03:59:35

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] clk: starfive: Add StarFive JH7110 Image-Signal-Process clock driver

On 2023/3/2 23:39, Emil Renner Berthing wrote:
> On Tue, 21 Feb 2023 at 09:36, Xingyu Wu <[email protected]> wrote:
>>
>> Add driver for the StarFive JH7110 Image-Signal-Process clock controller.
>>
>> Signed-off-by: Xingyu Wu <[email protected]>
>> ---
>> drivers/clk/starfive/Kconfig | 11 +
>> drivers/clk/starfive/Makefile | 1 +
>> .../clk/starfive/clk-starfive-jh7110-isp.c | 254 ++++++++++++++++++
>> 3 files changed, 266 insertions(+)
>> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-isp.c
>>
>> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
>> index a462b6e53543..59499acb95f7 100644
>> --- a/drivers/clk/starfive/Kconfig
>> +++ b/drivers/clk/starfive/Kconfig
>> @@ -53,3 +53,14 @@ config CLK_STARFIVE_JH7110_STG
>> help
>> Say yes here to support the System-Top-Group clock controller
>> on the StarFive JH7110 SoC.
>> +
>> +config CLK_STARFIVE_JH7110_ISP
>> + tristate "StarFive JH7110 Image-Signal-Process clock support"
>> + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
>> + select AUXILIARY_BUS
>> + select CLK_STARFIVE_JH71X0
>> + select RESET_STARFIVE_JH7110
>> + default CLK_STARFIVE_JH7110_SYS
>
> default m if ARCH_STARFIVE

Oh, the ISPCRG and VOUTCRG depend on SYSCRG because it need to enable core clock.
So I should modify that:

default m if CLK_STARFIVE_JH7110_SYS

It that OK?

>
>> + help
>> + Say yes here to support the Image-Signal-Process clock controller
>> + on the StarFive JH7110 SoC.
>> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
>> index b81e97ee2659..76fb9f8d628b 100644
>> --- a/drivers/clk/starfive/Makefile
>> +++ b/drivers/clk/starfive/Makefile
>> @@ -7,3 +7,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
>> obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
>> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
>> obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
>> +obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
>> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
>> new file mode 100644
>> index 000000000000..b5bce1ac22e0
>> --- /dev/null
>> +++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
>> @@ -0,0 +1,254 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * StarFive JH7110 Image-Signal-Process Clock Driver
>> + *
>> + * Copyright (C) 2022 StarFive Technology Co., Ltd.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/io.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/reset.h>
>> +
>> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
>> +
>> +#include "clk-starfive-jh71x0.h"
>> +
>> +/* external clocks */
>> +#define JH7110_ISPCLK_ISP_TOP_CORE (JH7110_ISPCLK_END + 0)
>> +#define JH7110_ISPCLK_ISP_TOP_AXI (JH7110_ISPCLK_END + 1)
>> +#define JH7110_ISPCLK_NOC_BUS_ISP_AXI (JH7110_ISPCLK_END + 2)
>> +#define JH7110_ISPCLK_DVP_CLK (JH7110_ISPCLK_END + 3)
>> +#define JH7110_ISPCLK_EXT_END (JH7110_ISPCLK_END + 4)
>> +
>> +static const struct jh71x0_clk_data jh7110_ispclk_data[] = {
>> + /* syscon */
>> + JH71X0__DIV(JH7110_ISPCLK_DOM4_APB_FUNC, "dom4_apb_func", 15,
>> + JH7110_ISPCLK_ISP_TOP_AXI),
>> + JH71X0__DIV(JH7110_ISPCLK_MIPI_RX0_PXL, "mipi_rx0_pxl", 8,
>> + JH7110_ISPCLK_ISP_TOP_CORE),
>> + JH71X0__INV(JH7110_ISPCLK_DVP_INV, "dvp_inv", JH7110_ISPCLK_DVP_CLK),
>> + /* vin */
>> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_CFGCLK_IN, "m31dphy_cfgclk_in", 16,
>> + JH7110_ISPCLK_ISP_TOP_CORE),
>> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_REFCLK_IN, "m31dphy_refclk_in", 16,
>> + JH7110_ISPCLK_ISP_TOP_CORE),
>> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_TXCLKESC_LAN0, "m31dphy_txclkesc_lan0", 60,
>> + JH7110_ISPCLK_ISP_TOP_CORE),
>> + JH71X0_GATE(JH7110_ISPCLK_VIN_PCLK, "vin_pclk", CLK_IGNORE_UNUSED,
>> + JH7110_ISPCLK_DOM4_APB_FUNC),
>> + JH71X0__DIV(JH7110_ISPCLK_VIN_SYS_CLK, "vin_sys_clk", 8, JH7110_ISPCLK_ISP_TOP_CORE),
>> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF0, "vin_pixel_clk_if0", CLK_IGNORE_UNUSED,
>> + JH7110_ISPCLK_MIPI_RX0_PXL),
>> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF1, "vin_pixel_clk_if1", CLK_IGNORE_UNUSED,
>> + JH7110_ISPCLK_MIPI_RX0_PXL),
>> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF2, "vin_pixel_clk_if2", CLK_IGNORE_UNUSED,
>> + JH7110_ISPCLK_MIPI_RX0_PXL),
>> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF3, "vin_pixel_clk_if3", CLK_IGNORE_UNUSED,
>> + JH7110_ISPCLK_MIPI_RX0_PXL),
>> + JH71X0__MUX(JH7110_ISPCLK_VIN_CLK_P_AXIWR, "vin_clk_p_axiwr", 2,
>> + JH7110_ISPCLK_MIPI_RX0_PXL,
>> + JH7110_ISPCLK_DVP_INV),
>> + /* ispv2_top_wrapper */
>> + JH71X0_GMUX(JH7110_ISPCLK_ISPV2_TOP_WRAPPER_CLK_C, "ispv2_top_wrapper_clk_c",
>> + CLK_IGNORE_UNUSED, 2,
>> + JH7110_ISPCLK_MIPI_RX0_PXL,
>> + JH7110_ISPCLK_DVP_INV),
>> +};
>
> Are all the clocks marked CLK_IGNORE_UNUSED here critical or are they
> just marked like so because the corresponding drivers don't yet claim
> the clocks they need? Please mark the clocks that can never be turned
> off CLK_IS_CRITICAL and remove the flag from the rest of the clocks.

Thanks, I will test it carefully and modify it.

>
>> +struct isp_top_crg {
>> + struct clk_bulk_data *top_clks;
>> + struct reset_control *top_rsts;
>> + int top_clks_num;
>> + void __iomem *base;
>> +};
>> +
>> +static struct clk_bulk_data jh7110_isp_top_clks[] = {
>> + { .id = "isp_top_core" },
>> + { .id = "isp_top_axi" }
>> +};
>> +
>> +static struct isp_top_crg *top_crg_from(void __iomem **base)
>> +{
>> + return container_of(base, struct isp_top_crg, base);
>> +}
>> +
>> +static int jh7110_isp_top_crg_get(struct jh71x0_clk_priv *priv, struct isp_top_crg *top)
>> +{
>> + int ret;
>> +
>> + top->top_clks = jh7110_isp_top_clks;
>> + top->top_clks_num = ARRAY_SIZE(jh7110_isp_top_clks);
>> + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
>> + if (ret) {
>> + dev_err(priv->dev, "top clks get failed: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + /* The resets should be shared and other ISP modules will use its. */
>> + top->top_rsts = devm_reset_control_array_get_shared(priv->dev);
>> + if (IS_ERR(top->top_rsts)) {
>> + dev_err(priv->dev, "top rsts get failed\n");
>> + return PTR_ERR(top->top_rsts);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int jh7110_isp_top_crg_enable(struct isp_top_crg *top)
>> +{
>> + int ret;
>> +
>> + ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
>> + if (ret)
>> + return ret;
>> +
>> + return reset_control_deassert(top->top_rsts);
>> +}
>> +
>> +static void jh7110_isp_top_crg_disable(struct isp_top_crg *top)
>> +{
>> + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
>> +}
>> +
>> +static struct clk_hw *jh7110_ispclk_get(struct of_phandle_args *clkspec, void *data)
>> +{
>> + struct jh71x0_clk_priv *priv = data;
>> + unsigned int idx = clkspec->args[0];
>> +
>> + if (idx < JH7110_ISPCLK_END)
>> + return &priv->reg[idx].hw;
>> +
>> + return ERR_PTR(-EINVAL);
>> +}
>> +
>> +static int jh7110_ispcrg_probe(struct platform_device *pdev)
>> +{
>> + struct jh71x0_clk_priv *priv;
>> + struct isp_top_crg *top;
>> + unsigned int idx;
>> + int ret;
>> +
>> + priv = devm_kzalloc(&pdev->dev,
>> + struct_size(priv, reg, JH7110_ISPCLK_END),
>> + GFP_KERNEL);
>> + if (!priv)
>> + return -ENOMEM;
>> +
>> + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
>> + if (!top)
>> + return -ENOMEM;
>> +
>> + spin_lock_init(&priv->rmw_lock);
>> + priv->dev = &pdev->dev;
>> + priv->base = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(priv->base))
>> + return PTR_ERR(priv->base);
>> +
>> + top->base = priv->base;
>> + dev_set_drvdata(priv->dev, (void *)(&top->base));
>> +
>> + pm_runtime_enable(priv->dev);
>> + ret = pm_runtime_get_sync(priv->dev);
>> + if (ret < 0) {
>> + dev_err(priv->dev, "failed to turn on power: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = jh7110_isp_top_crg_get(priv, top);
>> + if (ret)
>> + goto err_clk;
>> +
>> + ret = jh7110_isp_top_crg_enable(top);
>> + if (ret)
>> + goto err_clk;
>> +
>> + for (idx = 0; idx < JH7110_ISPCLK_END; idx++) {
>> + u32 max = jh7110_ispclk_data[idx].max;
>> + struct clk_parent_data parents[4] = {};
>> + struct clk_init_data init = {
>> + .name = jh7110_ispclk_data[idx].name,
>> + .ops = starfive_jh71x0_clk_ops(max),
>> + .parent_data = parents,
>> + .num_parents =
>> + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
>> + .flags = jh7110_ispclk_data[idx].flags,
>> + };
>> + struct jh71x0_clk *clk = &priv->reg[idx];
>> + unsigned int i;
>> + char *fw_name[JH7110_ISPCLK_EXT_END - JH7110_ISPCLK_END] = {
>> + "isp_top_core",
>> + "isp_top_axi",
>> + "noc_bus_isp_axi",
>> + "dvp_clk"
>> + };
>> +
>> + for (i = 0; i < init.num_parents; i++) {
>> + unsigned int pidx = jh7110_ispclk_data[idx].parents[i];
>> +
>> + if (pidx < JH7110_ISPCLK_END)
>> + parents[i].hw = &priv->reg[pidx].hw;
>> + else
>> + parents[i].fw_name = fw_name[pidx - JH7110_ISPCLK_END];
>> + }
>> +
>> + clk->hw.init = &init;
>> + clk->idx = idx;
>> + clk->max_div = max & JH71X0_CLK_DIV_MASK;
>> +
>> + ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
>> + if (ret)
>> + goto err_exit;
>> + }
>> +
>> + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_ispclk_get, priv);
>> + if (ret)
>> + goto err_exit;
>> +
>> + ret = jh7110_reset_controller_register(priv, "reset-isp", 3);
>> + if (ret)
>> + goto err_exit;
>> +
>> + return 0;
>> +
>> +err_exit:
>> + jh7110_isp_top_crg_disable(top);
>> +err_clk:
>> + pm_runtime_put_sync(priv->dev);
>> + pm_runtime_disable(priv->dev);
>> + return ret;
>> +}
>> +
>> +static int jh7110_ispcrg_remove(struct platform_device *pdev)
>> +{
>> + void __iomem **base = dev_get_drvdata(&pdev->dev);
>> + struct isp_top_crg *top = top_crg_from(base);
>> +
>> + jh7110_isp_top_crg_disable(top);
>> + pm_runtime_disable(&pdev->dev);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct of_device_id jh7110_ispcrg_match[] = {
>> + { .compatible = "starfive,jh7110-ispcrg" },
>> + { /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, jh7110_ispcrg_match);
>> +
>> +static struct platform_driver jh7110_ispcrg_driver = {
>> + .probe = jh7110_ispcrg_probe,
>> + .remove = jh7110_ispcrg_remove,
>> + .driver = {
>> + .name = "clk-starfive-jh7110-isp",
>> + .of_match_table = jh7110_ispcrg_match,
>> + },
>> +};
>> +module_platform_driver(jh7110_ispcrg_driver);
>> +
>> +MODULE_AUTHOR("Xingyu Wu <[email protected]>");
>> +MODULE_DESCRIPTION("StarFive JH7110 Image-Signal-Process clock driver");
>> +MODULE_LICENSE("GPL");
>> --
>> 2.25.1
>>
>>
>> _______________________________________________
>> linux-riscv mailing list
>> [email protected]
>> http://lists.infradead.org/mailman/listinfo/linux-riscv

Best regards,
Xingyu Wu

2023-03-03 09:13:28

by Emil Renner Berthing

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] clk: starfive: Add StarFive JH7110 Image-Signal-Process clock driver

On Fri, 3 Mar 2023 at 04:59, Xingyu Wu <[email protected]> wrote:
> On 2023/3/2 23:39, Emil Renner Berthing wrote:
> > On Tue, 21 Feb 2023 at 09:36, Xingyu Wu <[email protected]> wrote:
> >>
> >> Add driver for the StarFive JH7110 Image-Signal-Process clock controller.
> >>
> >> Signed-off-by: Xingyu Wu <[email protected]>
> >> ---
> >> drivers/clk/starfive/Kconfig | 11 +
> >> drivers/clk/starfive/Makefile | 1 +
> >> .../clk/starfive/clk-starfive-jh7110-isp.c | 254 ++++++++++++++++++
> >> 3 files changed, 266 insertions(+)
> >> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-isp.c
> >>
> >> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
> >> index a462b6e53543..59499acb95f7 100644
> >> --- a/drivers/clk/starfive/Kconfig
> >> +++ b/drivers/clk/starfive/Kconfig
> >> @@ -53,3 +53,14 @@ config CLK_STARFIVE_JH7110_STG
> >> help
> >> Say yes here to support the System-Top-Group clock controller
> >> on the StarFive JH7110 SoC.
> >> +
> >> +config CLK_STARFIVE_JH7110_ISP
> >> + tristate "StarFive JH7110 Image-Signal-Process clock support"
> >> + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
> >> + select AUXILIARY_BUS
> >> + select CLK_STARFIVE_JH71X0
> >> + select RESET_STARFIVE_JH7110
> >> + default CLK_STARFIVE_JH7110_SYS
> >
> > default m if ARCH_STARFIVE
>
> Oh, the ISPCRG and VOUTCRG depend on SYSCRG because it need to enable core clock.
> So I should modify that:
>
> default m if CLK_STARFIVE_JH7110_SYS
>
> It that OK?

No, this symbol already has a "depends on CLK_STARFIVE_JH7110_SYS &&
JH71XX_PMU", so just do like the other drivers and default m if
ARCH_STARFIVE.

Btw. I don't see anything in the code depending on the PMU driver. Am
I just missing something could that dependency be removed?

> >
> >> + help
> >> + Say yes here to support the Image-Signal-Process clock controller
> >> + on the StarFive JH7110 SoC.
> >> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
> >> index b81e97ee2659..76fb9f8d628b 100644
> >> --- a/drivers/clk/starfive/Makefile
> >> +++ b/drivers/clk/starfive/Makefile
> >> @@ -7,3 +7,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
> >> +obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
> >> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
> >> new file mode 100644
> >> index 000000000000..b5bce1ac22e0
> >> --- /dev/null
> >> +++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
> >> @@ -0,0 +1,254 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * StarFive JH7110 Image-Signal-Process Clock Driver
> >> + *
> >> + * Copyright (C) 2022 StarFive Technology Co., Ltd.
> >> + */
> >> +
> >> +#include <linux/clk.h>
> >> +#include <linux/clk-provider.h>
> >> +#include <linux/io.h>
> >> +#include <linux/of.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/pm_runtime.h>
> >> +#include <linux/reset.h>
> >> +
> >> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
> >> +
> >> +#include "clk-starfive-jh71x0.h"
> >> +
> >> +/* external clocks */
> >> +#define JH7110_ISPCLK_ISP_TOP_CORE (JH7110_ISPCLK_END + 0)
> >> +#define JH7110_ISPCLK_ISP_TOP_AXI (JH7110_ISPCLK_END + 1)
> >> +#define JH7110_ISPCLK_NOC_BUS_ISP_AXI (JH7110_ISPCLK_END + 2)
> >> +#define JH7110_ISPCLK_DVP_CLK (JH7110_ISPCLK_END + 3)
> >> +#define JH7110_ISPCLK_EXT_END (JH7110_ISPCLK_END + 4)
> >> +
> >> +static const struct jh71x0_clk_data jh7110_ispclk_data[] = {
> >> + /* syscon */
> >> + JH71X0__DIV(JH7110_ISPCLK_DOM4_APB_FUNC, "dom4_apb_func", 15,
> >> + JH7110_ISPCLK_ISP_TOP_AXI),
> >> + JH71X0__DIV(JH7110_ISPCLK_MIPI_RX0_PXL, "mipi_rx0_pxl", 8,
> >> + JH7110_ISPCLK_ISP_TOP_CORE),
> >> + JH71X0__INV(JH7110_ISPCLK_DVP_INV, "dvp_inv", JH7110_ISPCLK_DVP_CLK),
> >> + /* vin */
> >> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_CFGCLK_IN, "m31dphy_cfgclk_in", 16,
> >> + JH7110_ISPCLK_ISP_TOP_CORE),
> >> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_REFCLK_IN, "m31dphy_refclk_in", 16,
> >> + JH7110_ISPCLK_ISP_TOP_CORE),
> >> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_TXCLKESC_LAN0, "m31dphy_txclkesc_lan0", 60,
> >> + JH7110_ISPCLK_ISP_TOP_CORE),
> >> + JH71X0_GATE(JH7110_ISPCLK_VIN_PCLK, "vin_pclk", CLK_IGNORE_UNUSED,
> >> + JH7110_ISPCLK_DOM4_APB_FUNC),
> >> + JH71X0__DIV(JH7110_ISPCLK_VIN_SYS_CLK, "vin_sys_clk", 8, JH7110_ISPCLK_ISP_TOP_CORE),
> >> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF0, "vin_pixel_clk_if0", CLK_IGNORE_UNUSED,
> >> + JH7110_ISPCLK_MIPI_RX0_PXL),
> >> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF1, "vin_pixel_clk_if1", CLK_IGNORE_UNUSED,
> >> + JH7110_ISPCLK_MIPI_RX0_PXL),
> >> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF2, "vin_pixel_clk_if2", CLK_IGNORE_UNUSED,
> >> + JH7110_ISPCLK_MIPI_RX0_PXL),
> >> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF3, "vin_pixel_clk_if3", CLK_IGNORE_UNUSED,
> >> + JH7110_ISPCLK_MIPI_RX0_PXL),
> >> + JH71X0__MUX(JH7110_ISPCLK_VIN_CLK_P_AXIWR, "vin_clk_p_axiwr", 2,
> >> + JH7110_ISPCLK_MIPI_RX0_PXL,
> >> + JH7110_ISPCLK_DVP_INV),
> >> + /* ispv2_top_wrapper */
> >> + JH71X0_GMUX(JH7110_ISPCLK_ISPV2_TOP_WRAPPER_CLK_C, "ispv2_top_wrapper_clk_c",
> >> + CLK_IGNORE_UNUSED, 2,
> >> + JH7110_ISPCLK_MIPI_RX0_PXL,
> >> + JH7110_ISPCLK_DVP_INV),
> >> +};
> >
> > Are all the clocks marked CLK_IGNORE_UNUSED here critical or are they
> > just marked like so because the corresponding drivers don't yet claim
> > the clocks they need? Please mark the clocks that can never be turned
> > off CLK_IS_CRITICAL and remove the flag from the rest of the clocks.
>
> Thanks, I will test it carefully and modify it.
>
> >
> >> +struct isp_top_crg {
> >> + struct clk_bulk_data *top_clks;
> >> + struct reset_control *top_rsts;
> >> + int top_clks_num;
> >> + void __iomem *base;
> >> +};
> >> +
> >> +static struct clk_bulk_data jh7110_isp_top_clks[] = {
> >> + { .id = "isp_top_core" },
> >> + { .id = "isp_top_axi" }
> >> +};
> >> +
> >> +static struct isp_top_crg *top_crg_from(void __iomem **base)
> >> +{
> >> + return container_of(base, struct isp_top_crg, base);
> >> +}
> >> +
> >> +static int jh7110_isp_top_crg_get(struct jh71x0_clk_priv *priv, struct isp_top_crg *top)
> >> +{
> >> + int ret;
> >> +
> >> + top->top_clks = jh7110_isp_top_clks;
> >> + top->top_clks_num = ARRAY_SIZE(jh7110_isp_top_clks);
> >> + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
> >> + if (ret) {
> >> + dev_err(priv->dev, "top clks get failed: %d\n", ret);
> >> + return ret;
> >> + }
> >> +
> >> + /* The resets should be shared and other ISP modules will use its. */
> >> + top->top_rsts = devm_reset_control_array_get_shared(priv->dev);
> >> + if (IS_ERR(top->top_rsts)) {
> >> + dev_err(priv->dev, "top rsts get failed\n");
> >> + return PTR_ERR(top->top_rsts);
> >> + }
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int jh7110_isp_top_crg_enable(struct isp_top_crg *top)
> >> +{
> >> + int ret;
> >> +
> >> + ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
> >> + if (ret)
> >> + return ret;
> >> +
> >> + return reset_control_deassert(top->top_rsts);
> >> +}
> >> +
> >> +static void jh7110_isp_top_crg_disable(struct isp_top_crg *top)
> >> +{
> >> + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
> >> +}
> >> +
> >> +static struct clk_hw *jh7110_ispclk_get(struct of_phandle_args *clkspec, void *data)
> >> +{
> >> + struct jh71x0_clk_priv *priv = data;
> >> + unsigned int idx = clkspec->args[0];
> >> +
> >> + if (idx < JH7110_ISPCLK_END)
> >> + return &priv->reg[idx].hw;
> >> +
> >> + return ERR_PTR(-EINVAL);
> >> +}
> >> +
> >> +static int jh7110_ispcrg_probe(struct platform_device *pdev)
> >> +{
> >> + struct jh71x0_clk_priv *priv;
> >> + struct isp_top_crg *top;
> >> + unsigned int idx;
> >> + int ret;
> >> +
> >> + priv = devm_kzalloc(&pdev->dev,
> >> + struct_size(priv, reg, JH7110_ISPCLK_END),
> >> + GFP_KERNEL);
> >> + if (!priv)
> >> + return -ENOMEM;
> >> +
> >> + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
> >> + if (!top)
> >> + return -ENOMEM;
> >> +
> >> + spin_lock_init(&priv->rmw_lock);
> >> + priv->dev = &pdev->dev;
> >> + priv->base = devm_platform_ioremap_resource(pdev, 0);
> >> + if (IS_ERR(priv->base))
> >> + return PTR_ERR(priv->base);
> >> +
> >> + top->base = priv->base;
> >> + dev_set_drvdata(priv->dev, (void *)(&top->base));
> >> +
> >> + pm_runtime_enable(priv->dev);
> >> + ret = pm_runtime_get_sync(priv->dev);
> >> + if (ret < 0) {
> >> + dev_err(priv->dev, "failed to turn on power: %d\n", ret);
> >> + return ret;
> >> + }
> >> +
> >> + ret = jh7110_isp_top_crg_get(priv, top);
> >> + if (ret)
> >> + goto err_clk;
> >> +
> >> + ret = jh7110_isp_top_crg_enable(top);
> >> + if (ret)
> >> + goto err_clk;
> >> +
> >> + for (idx = 0; idx < JH7110_ISPCLK_END; idx++) {
> >> + u32 max = jh7110_ispclk_data[idx].max;
> >> + struct clk_parent_data parents[4] = {};
> >> + struct clk_init_data init = {
> >> + .name = jh7110_ispclk_data[idx].name,
> >> + .ops = starfive_jh71x0_clk_ops(max),
> >> + .parent_data = parents,
> >> + .num_parents =
> >> + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
> >> + .flags = jh7110_ispclk_data[idx].flags,
> >> + };
> >> + struct jh71x0_clk *clk = &priv->reg[idx];
> >> + unsigned int i;
> >> + char *fw_name[JH7110_ISPCLK_EXT_END - JH7110_ISPCLK_END] = {
> >> + "isp_top_core",
> >> + "isp_top_axi",
> >> + "noc_bus_isp_axi",
> >> + "dvp_clk"
> >> + };
> >> +
> >> + for (i = 0; i < init.num_parents; i++) {
> >> + unsigned int pidx = jh7110_ispclk_data[idx].parents[i];
> >> +
> >> + if (pidx < JH7110_ISPCLK_END)
> >> + parents[i].hw = &priv->reg[pidx].hw;
> >> + else
> >> + parents[i].fw_name = fw_name[pidx - JH7110_ISPCLK_END];
> >> + }
> >> +
> >> + clk->hw.init = &init;
> >> + clk->idx = idx;
> >> + clk->max_div = max & JH71X0_CLK_DIV_MASK;
> >> +
> >> + ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
> >> + if (ret)
> >> + goto err_exit;
> >> + }
> >> +
> >> + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_ispclk_get, priv);
> >> + if (ret)
> >> + goto err_exit;
> >> +
> >> + ret = jh7110_reset_controller_register(priv, "reset-isp", 3);
> >> + if (ret)
> >> + goto err_exit;
> >> +
> >> + return 0;
> >> +
> >> +err_exit:
> >> + jh7110_isp_top_crg_disable(top);
> >> +err_clk:
> >> + pm_runtime_put_sync(priv->dev);
> >> + pm_runtime_disable(priv->dev);
> >> + return ret;
> >> +}
> >> +
> >> +static int jh7110_ispcrg_remove(struct platform_device *pdev)
> >> +{
> >> + void __iomem **base = dev_get_drvdata(&pdev->dev);
> >> + struct isp_top_crg *top = top_crg_from(base);
> >> +
> >> + jh7110_isp_top_crg_disable(top);
> >> + pm_runtime_disable(&pdev->dev);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static const struct of_device_id jh7110_ispcrg_match[] = {
> >> + { .compatible = "starfive,jh7110-ispcrg" },
> >> + { /* sentinel */ }
> >> +};
> >> +MODULE_DEVICE_TABLE(of, jh7110_ispcrg_match);
> >> +
> >> +static struct platform_driver jh7110_ispcrg_driver = {
> >> + .probe = jh7110_ispcrg_probe,
> >> + .remove = jh7110_ispcrg_remove,
> >> + .driver = {
> >> + .name = "clk-starfive-jh7110-isp",
> >> + .of_match_table = jh7110_ispcrg_match,
> >> + },
> >> +};
> >> +module_platform_driver(jh7110_ispcrg_driver);
> >> +
> >> +MODULE_AUTHOR("Xingyu Wu <[email protected]>");
> >> +MODULE_DESCRIPTION("StarFive JH7110 Image-Signal-Process clock driver");
> >> +MODULE_LICENSE("GPL");
> >> --
> >> 2.25.1
> >>
> >>
> >> _______________________________________________
> >> linux-riscv mailing list
> >> [email protected]
> >> http://lists.infradead.org/mailman/listinfo/linux-riscv
>
> Best regards,
> Xingyu Wu

2023-03-03 09:14:13

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] clk: starfive: Add StarFive JH7110 Image-Signal-Process clock driver

On 2023/3/3 17:01, Emil Renner Berthing wrote:
> On Fri, 3 Mar 2023 at 04:59, Xingyu Wu <[email protected]> wrote:
>> On 2023/3/2 23:39, Emil Renner Berthing wrote:
>> > On Tue, 21 Feb 2023 at 09:36, Xingyu Wu <[email protected]> wrote:
>> >>
>> >> Add driver for the StarFive JH7110 Image-Signal-Process clock controller.
>> >>
>> >> Signed-off-by: Xingyu Wu <[email protected]>
>> >> ---
>> >> drivers/clk/starfive/Kconfig | 11 +
>> >> drivers/clk/starfive/Makefile | 1 +
>> >> .../clk/starfive/clk-starfive-jh7110-isp.c | 254 ++++++++++++++++++
>> >> 3 files changed, 266 insertions(+)
>> >> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-isp.c
>> >>
>> >> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
>> >> index a462b6e53543..59499acb95f7 100644
>> >> --- a/drivers/clk/starfive/Kconfig
>> >> +++ b/drivers/clk/starfive/Kconfig
>> >> @@ -53,3 +53,14 @@ config CLK_STARFIVE_JH7110_STG
>> >> help
>> >> Say yes here to support the System-Top-Group clock controller
>> >> on the StarFive JH7110 SoC.
>> >> +
>> >> +config CLK_STARFIVE_JH7110_ISP
>> >> + tristate "StarFive JH7110 Image-Signal-Process clock support"
>> >> + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
>> >> + select AUXILIARY_BUS
>> >> + select CLK_STARFIVE_JH71X0
>> >> + select RESET_STARFIVE_JH7110
>> >> + default CLK_STARFIVE_JH7110_SYS
>> >
>> > default m if ARCH_STARFIVE
>>
>> Oh, the ISPCRG and VOUTCRG depend on SYSCRG because it need to enable core clock.
>> So I should modify that:
>>
>> default m if CLK_STARFIVE_JH7110_SYS
>>
>> It that OK?
>
> No, this symbol already has a "depends on CLK_STARFIVE_JH7110_SYS &&
> JH71XX_PMU", so just do like the other drivers and default m if
> ARCH_STARFIVE.

OK, I will modify it.

>
> Btw. I don't see anything in the code depending on the PMU driver. Am
> I just missing something could that dependency be removed?

This dependency is represented in the JH7110 device tree file and use
'power-domains' node. The VOUTCRG and ISPCRG also need to turn on power
before reading and writing registers. Uses 'pm_runtime_enable' and PMU
would help me turn on their power.

>
>> >
>> >> + help
>> >> + Say yes here to support the Image-Signal-Process clock controller
>> >> + on the StarFive JH7110 SoC.
>> >> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
>> >> index b81e97ee2659..76fb9f8d628b 100644
>> >> --- a/drivers/clk/starfive/Makefile
>> >> +++ b/drivers/clk/starfive/Makefile
>> >> @@ -7,3 +7,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
>> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
>> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
>> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
>> >> +obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
>> >> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
>> >> new file mode 100644
>> >> index 000000000000..b5bce1ac22e0
>> >> --- /dev/null
>> >> +++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
>> >> @@ -0,0 +1,254 @@
>> >> +// SPDX-License-Identifier: GPL-2.0
>> >> +/*
>> >> + * StarFive JH7110 Image-Signal-Process Clock Driver
>> >> + *
>> >> + * Copyright (C) 2022 StarFive Technology Co., Ltd.
>> >> + */
>> >> +
>> >> +#include <linux/clk.h>
>> >> +#include <linux/clk-provider.h>
>> >> +#include <linux/io.h>
>> >> +#include <linux/of.h>
>> >> +#include <linux/platform_device.h>
>> >> +#include <linux/pm_runtime.h>
>> >> +#include <linux/reset.h>
>> >> +
>> >> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
>> >> +
>> >> +#include "clk-starfive-jh71x0.h"
>> >> +
>> >> +/* external clocks */
>> >> +#define JH7110_ISPCLK_ISP_TOP_CORE (JH7110_ISPCLK_END + 0)
>> >> +#define JH7110_ISPCLK_ISP_TOP_AXI (JH7110_ISPCLK_END + 1)
>> >> +#define JH7110_ISPCLK_NOC_BUS_ISP_AXI (JH7110_ISPCLK_END + 2)
>> >> +#define JH7110_ISPCLK_DVP_CLK (JH7110_ISPCLK_END + 3)
>> >> +#define JH7110_ISPCLK_EXT_END (JH7110_ISPCLK_END + 4)
>> >> +
>> >> +static const struct jh71x0_clk_data jh7110_ispclk_data[] = {
>> >> + /* syscon */
>> >> + JH71X0__DIV(JH7110_ISPCLK_DOM4_APB_FUNC, "dom4_apb_func", 15,
>> >> + JH7110_ISPCLK_ISP_TOP_AXI),
>> >> + JH71X0__DIV(JH7110_ISPCLK_MIPI_RX0_PXL, "mipi_rx0_pxl", 8,
>> >> + JH7110_ISPCLK_ISP_TOP_CORE),
>> >> + JH71X0__INV(JH7110_ISPCLK_DVP_INV, "dvp_inv", JH7110_ISPCLK_DVP_CLK),
>> >> + /* vin */
>> >> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_CFGCLK_IN, "m31dphy_cfgclk_in", 16,
>> >> + JH7110_ISPCLK_ISP_TOP_CORE),
>> >> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_REFCLK_IN, "m31dphy_refclk_in", 16,
>> >> + JH7110_ISPCLK_ISP_TOP_CORE),
>> >> + JH71X0__DIV(JH7110_ISPCLK_M31DPHY_TXCLKESC_LAN0, "m31dphy_txclkesc_lan0", 60,
>> >> + JH7110_ISPCLK_ISP_TOP_CORE),
>> >> + JH71X0_GATE(JH7110_ISPCLK_VIN_PCLK, "vin_pclk", CLK_IGNORE_UNUSED,
>> >> + JH7110_ISPCLK_DOM4_APB_FUNC),
>> >> + JH71X0__DIV(JH7110_ISPCLK_VIN_SYS_CLK, "vin_sys_clk", 8, JH7110_ISPCLK_ISP_TOP_CORE),
>> >> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF0, "vin_pixel_clk_if0", CLK_IGNORE_UNUSED,
>> >> + JH7110_ISPCLK_MIPI_RX0_PXL),
>> >> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF1, "vin_pixel_clk_if1", CLK_IGNORE_UNUSED,
>> >> + JH7110_ISPCLK_MIPI_RX0_PXL),
>> >> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF2, "vin_pixel_clk_if2", CLK_IGNORE_UNUSED,
>> >> + JH7110_ISPCLK_MIPI_RX0_PXL),
>> >> + JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_CLK_IF3, "vin_pixel_clk_if3", CLK_IGNORE_UNUSED,
>> >> + JH7110_ISPCLK_MIPI_RX0_PXL),
>> >> + JH71X0__MUX(JH7110_ISPCLK_VIN_CLK_P_AXIWR, "vin_clk_p_axiwr", 2,
>> >> + JH7110_ISPCLK_MIPI_RX0_PXL,
>> >> + JH7110_ISPCLK_DVP_INV),
>> >> + /* ispv2_top_wrapper */
>> >> + JH71X0_GMUX(JH7110_ISPCLK_ISPV2_TOP_WRAPPER_CLK_C, "ispv2_top_wrapper_clk_c",
>> >> + CLK_IGNORE_UNUSED, 2,
>> >> + JH7110_ISPCLK_MIPI_RX0_PXL,
>> >> + JH7110_ISPCLK_DVP_INV),
>> >> +};
>> >
>> > Are all the clocks marked CLK_IGNORE_UNUSED here critical or are they
>> > just marked like so because the corresponding drivers don't yet claim
>> > the clocks they need? Please mark the clocks that can never be turned
>> > off CLK_IS_CRITICAL and remove the flag from the rest of the clocks.
>>
>> Thanks, I will test it carefully and modify it.
>>
>> >
>> >> +struct isp_top_crg {
>> >> + struct clk_bulk_data *top_clks;
>> >> + struct reset_control *top_rsts;
>> >> + int top_clks_num;
>> >> + void __iomem *base;
>> >> +};
>> >> +
>> >> +static struct clk_bulk_data jh7110_isp_top_clks[] = {
>> >> + { .id = "isp_top_core" },
>> >> + { .id = "isp_top_axi" }
>> >> +};
>> >> +
>> >> +static struct isp_top_crg *top_crg_from(void __iomem **base)
>> >> +{
>> >> + return container_of(base, struct isp_top_crg, base);
>> >> +}
>> >> +
>> >> +static int jh7110_isp_top_crg_get(struct jh71x0_clk_priv *priv, struct isp_top_crg *top)
>> >> +{
>> >> + int ret;
>> >> +
>> >> + top->top_clks = jh7110_isp_top_clks;
>> >> + top->top_clks_num = ARRAY_SIZE(jh7110_isp_top_clks);
>> >> + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
>> >> + if (ret) {
>> >> + dev_err(priv->dev, "top clks get failed: %d\n", ret);
>> >> + return ret;
>> >> + }
>> >> +
>> >> + /* The resets should be shared and other ISP modules will use its. */
>> >> + top->top_rsts = devm_reset_control_array_get_shared(priv->dev);
>> >> + if (IS_ERR(top->top_rsts)) {
>> >> + dev_err(priv->dev, "top rsts get failed\n");
>> >> + return PTR_ERR(top->top_rsts);
>> >> + }
>> >> +
>> >> + return 0;
>> >> +}
>> >> +
>> >> +static int jh7110_isp_top_crg_enable(struct isp_top_crg *top)
>> >> +{
>> >> + int ret;
>> >> +
>> >> + ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
>> >> + if (ret)
>> >> + return ret;
>> >> +
>> >> + return reset_control_deassert(top->top_rsts);
>> >> +}
>> >> +
>> >> +static void jh7110_isp_top_crg_disable(struct isp_top_crg *top)
>> >> +{
>> >> + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
>> >> +}
>> >> +
>> >> +static struct clk_hw *jh7110_ispclk_get(struct of_phandle_args *clkspec, void *data)
>> >> +{
>> >> + struct jh71x0_clk_priv *priv = data;
>> >> + unsigned int idx = clkspec->args[0];
>> >> +
>> >> + if (idx < JH7110_ISPCLK_END)
>> >> + return &priv->reg[idx].hw;
>> >> +
>> >> + return ERR_PTR(-EINVAL);
>> >> +}
>> >> +
>> >> +static int jh7110_ispcrg_probe(struct platform_device *pdev)
>> >> +{
>> >> + struct jh71x0_clk_priv *priv;
>> >> + struct isp_top_crg *top;
>> >> + unsigned int idx;
>> >> + int ret;
>> >> +
>> >> + priv = devm_kzalloc(&pdev->dev,
>> >> + struct_size(priv, reg, JH7110_ISPCLK_END),
>> >> + GFP_KERNEL);
>> >> + if (!priv)
>> >> + return -ENOMEM;
>> >> +
>> >> + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
>> >> + if (!top)
>> >> + return -ENOMEM;
>> >> +
>> >> + spin_lock_init(&priv->rmw_lock);
>> >> + priv->dev = &pdev->dev;
>> >> + priv->base = devm_platform_ioremap_resource(pdev, 0);
>> >> + if (IS_ERR(priv->base))
>> >> + return PTR_ERR(priv->base);
>> >> +
>> >> + top->base = priv->base;
>> >> + dev_set_drvdata(priv->dev, (void *)(&top->base));
>> >> +
>> >> + pm_runtime_enable(priv->dev);
>> >> + ret = pm_runtime_get_sync(priv->dev);
>> >> + if (ret < 0) {
>> >> + dev_err(priv->dev, "failed to turn on power: %d\n", ret);
>> >> + return ret;
>> >> + }
>> >> +
>> >> + ret = jh7110_isp_top_crg_get(priv, top);
>> >> + if (ret)
>> >> + goto err_clk;
>> >> +
>> >> + ret = jh7110_isp_top_crg_enable(top);
>> >> + if (ret)
>> >> + goto err_clk;
>> >> +
>> >> + for (idx = 0; idx < JH7110_ISPCLK_END; idx++) {
>> >> + u32 max = jh7110_ispclk_data[idx].max;
>> >> + struct clk_parent_data parents[4] = {};
>> >> + struct clk_init_data init = {
>> >> + .name = jh7110_ispclk_data[idx].name,
>> >> + .ops = starfive_jh71x0_clk_ops(max),
>> >> + .parent_data = parents,
>> >> + .num_parents =
>> >> + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
>> >> + .flags = jh7110_ispclk_data[idx].flags,
>> >> + };
>> >> + struct jh71x0_clk *clk = &priv->reg[idx];
>> >> + unsigned int i;
>> >> + char *fw_name[JH7110_ISPCLK_EXT_END - JH7110_ISPCLK_END] = {
>> >> + "isp_top_core",
>> >> + "isp_top_axi",
>> >> + "noc_bus_isp_axi",
>> >> + "dvp_clk"
>> >> + };
>> >> +
>> >> + for (i = 0; i < init.num_parents; i++) {
>> >> + unsigned int pidx = jh7110_ispclk_data[idx].parents[i];
>> >> +
>> >> + if (pidx < JH7110_ISPCLK_END)
>> >> + parents[i].hw = &priv->reg[pidx].hw;
>> >> + else
>> >> + parents[i].fw_name = fw_name[pidx - JH7110_ISPCLK_END];
>> >> + }
>> >> +
>> >> + clk->hw.init = &init;
>> >> + clk->idx = idx;
>> >> + clk->max_div = max & JH71X0_CLK_DIV_MASK;
>> >> +
>> >> + ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
>> >> + if (ret)
>> >> + goto err_exit;
>> >> + }
>> >> +
>> >> + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_ispclk_get, priv);
>> >> + if (ret)
>> >> + goto err_exit;
>> >> +
>> >> + ret = jh7110_reset_controller_register(priv, "reset-isp", 3);
>> >> + if (ret)
>> >> + goto err_exit;
>> >> +
>> >> + return 0;
>> >> +
>> >> +err_exit:
>> >> + jh7110_isp_top_crg_disable(top);
>> >> +err_clk:
>> >> + pm_runtime_put_sync(priv->dev);
>> >> + pm_runtime_disable(priv->dev);
>> >> + return ret;
>> >> +}
>> >> +
>> >> +static int jh7110_ispcrg_remove(struct platform_device *pdev)
>> >> +{
>> >> + void __iomem **base = dev_get_drvdata(&pdev->dev);
>> >> + struct isp_top_crg *top = top_crg_from(base);
>> >> +
>> >> + jh7110_isp_top_crg_disable(top);
>> >> + pm_runtime_disable(&pdev->dev);
>> >> +
>> >> + return 0;
>> >> +}
>> >> +
>> >> +static const struct of_device_id jh7110_ispcrg_match[] = {
>> >> + { .compatible = "starfive,jh7110-ispcrg" },
>> >> + { /* sentinel */ }
>> >> +};
>> >> +MODULE_DEVICE_TABLE(of, jh7110_ispcrg_match);
>> >> +
>> >> +static struct platform_driver jh7110_ispcrg_driver = {
>> >> + .probe = jh7110_ispcrg_probe,
>> >> + .remove = jh7110_ispcrg_remove,
>> >> + .driver = {
>> >> + .name = "clk-starfive-jh7110-isp",
>> >> + .of_match_table = jh7110_ispcrg_match,
>> >> + },
>> >> +};
>> >> +module_platform_driver(jh7110_ispcrg_driver);
>> >> +
>> >> +MODULE_AUTHOR("Xingyu Wu <[email protected]>");
>> >> +MODULE_DESCRIPTION("StarFive JH7110 Image-Signal-Process clock driver");
>> >> +MODULE_LICENSE("GPL");
>> >> --
>> >> 2.25.1
>> >>
>> >>
>> >> _______________________________________________
>> >> linux-riscv mailing list
>> >> [email protected]
>> >> http://lists.infradead.org/mailman/listinfo/linux-riscv
>>
>> Best regards,
>> Xingyu Wu


2023-03-03 09:24:26

by Emil Renner Berthing

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] clk: starfive: Add StarFive JH7110 Video-Output clock driver

On Fri, 3 Mar 2023 at 04:37, Xingyu Wu <[email protected]> wrote:
>
> On 2023/3/2 23:48, Emil Renner Berthing wrote:
> > On Tue, 21 Feb 2023 at 09:40, Xingyu Wu <[email protected]> wrote:
> >>
> >> Add driver for the StarFive JH7110 Video-Output clock controller.
> >>
> >> Signed-off-by: Xingyu Wu <[email protected]>
> >> ---
> >> drivers/clk/starfive/Kconfig | 11 +
> >> drivers/clk/starfive/Makefile | 1 +
> >> .../clk/starfive/clk-starfive-jh7110-vout.c | 261 ++++++++++++++++++
> >> 3 files changed, 273 insertions(+)
> >> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-vout.c
> >>
> >> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
> >> index 59499acb95f7..5ebf1ed08627 100644
> >> --- a/drivers/clk/starfive/Kconfig
> >> +++ b/drivers/clk/starfive/Kconfig
> >> @@ -64,3 +64,14 @@ config CLK_STARFIVE_JH7110_ISP
> >> help
> >> Say yes here to support the Image-Signal-Process clock controller
> >> on the StarFive JH7110 SoC.
> >> +
> >> +config CLK_STARFIVE_JH7110_VOUT
> >> + tristate "StarFive JH7110 Video-Output clock support"
> >> + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
> >> + select AUXILIARY_BUS
> >> + select CLK_STARFIVE_JH71X0
> >> + select RESET_STARFIVE_JH7110
> >> + default CLK_STARFIVE_JH7110_SYS
> >
> > default m if ARCH_STARFIVE
>
> Will modify it.
>
> >
> >> + help
> >> + Say yes here to support the Video-Output clock controller
> >> + on the StarFive JH7110 SoC.
> >> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
> >> index 76fb9f8d628b..841377e45bb6 100644
> >> --- a/drivers/clk/starfive/Makefile
> >> +++ b/drivers/clk/starfive/Makefile
> >> @@ -8,3 +8,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
> >> +obj-$(CONFIG_CLK_STARFIVE_JH7110_VOUT) += clk-starfive-jh7110-vout.o
> >> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-vout.c b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
> >> new file mode 100644
> >> index 000000000000..d786537563a4
> >> --- /dev/null
> >> +++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
> >> @@ -0,0 +1,261 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * StarFive JH7110 Video-Output Clock Driver
> >> + *
> >> + * Copyright (C) 2022 StarFive Technology Co., Ltd.
> >> + */
> >> +
> >> +#include <linux/clk.h>
> >> +#include <linux/clk-provider.h>
> >> +#include <linux/io.h>
> >> +#include <linux/of.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/pm_runtime.h>
> >> +#include <linux/reset.h>
> >> +
> >> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
> >> +
> >> +#include "clk-starfive-jh71x0.h"
> >> +
> >> +/* external clocks */
> >> +#define JH7110_VOUTCLK_VOUT_SRC (JH7110_VOUTCLK_END + 0)
> >> +#define JH7110_VOUTCLK_VOUT_TOP_AHB (JH7110_VOUTCLK_END + 1)
> >> +#define JH7110_VOUTCLK_VOUT_TOP_AXI (JH7110_VOUTCLK_END + 2)
> >> +#define JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK (JH7110_VOUTCLK_END + 3)
> >> +#define JH7110_VOUTCLK_I2STX0_BCLK (JH7110_VOUTCLK_END + 4)
> >> +#define JH7110_VOUTCLK_HDMITX0_PIXELCLK (JH7110_VOUTCLK_END + 5)
> >> +#define JH7110_VOUTCLK_EXT_END (JH7110_VOUTCLK_END + 6)
> >> +
> >> +static const struct jh71x0_clk_data jh7110_voutclk_data[] = {
> >> + /* divider */
> >> + JH71X0__DIV(JH7110_VOUTCLK_APB, "apb", 8, JH7110_VOUTCLK_VOUT_TOP_AHB),
> >> + JH71X0__DIV(JH7110_VOUTCLK_DC8200_PIX, "dc8200_pix", 63, JH7110_VOUTCLK_VOUT_SRC),
> >> + JH71X0__DIV(JH7110_VOUTCLK_DSI_SYS, "dsi_sys", 31, JH7110_VOUTCLK_VOUT_SRC),
> >> + JH71X0__DIV(JH7110_VOUTCLK_TX_ESC, "tx_esc", 31, JH7110_VOUTCLK_VOUT_TOP_AHB),
> >> + /* dc8200 */
> >> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AXI, "dc8200_axi", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
> >> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_CORE, "dc8200_core", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
> >> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AHB, "dc8200_ahb", 0, JH7110_VOUTCLK_VOUT_TOP_AHB),
> >> + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX0, "dc8200_pix0", 0, 2,
> >> + JH7110_VOUTCLK_DC8200_PIX,
> >> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
> >> + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX1, "dc8200_pix1", 0, 2,
> >> + JH7110_VOUTCLK_DC8200_PIX,
> >> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
> >> + /* LCD */
> >> + JH71X0_GMUX(JH7110_VOUTCLK_DOM_VOUT_TOP_LCD, "dom_vout_top_lcd", 0, 2,
> >> + JH7110_VOUTCLK_DC8200_PIX0,
> >> + JH7110_VOUTCLK_DC8200_PIX1),
> >> + /* dsiTx */
> >> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_APB, "dsiTx_apb", 0, JH7110_VOUTCLK_DSI_SYS),
> >> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_SYS, "dsiTx_sys", 0, JH7110_VOUTCLK_DSI_SYS),
> >> + JH71X0_GMUX(JH7110_VOUTCLK_DSITX_DPI, "dsiTx_dpi", 0, 2,
> >> + JH7110_VOUTCLK_DC8200_PIX,
> >> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
> >> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_TXESC, "dsiTx_txesc", 0, JH7110_VOUTCLK_TX_ESC),
> >> + /* mipitx DPHY */
> >> + JH71X0_GATE(JH7110_VOUTCLK_MIPITX_DPHY_TXESC, "mipitx_dphy_txesc", 0,
> >> + JH7110_VOUTCLK_TX_ESC),
> >> + /* hdmi */
> >> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_MCLK, "hdmi_tx_mclk", 0,
> >> + JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK),
> >> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_BCLK, "hdmi_tx_bclk", 0,
> >> + JH7110_VOUTCLK_I2STX0_BCLK),
> >> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_SYS, "hdmi_tx_sys", 0, JH7110_VOUTCLK_APB),
> >> +};
> >> +
> >> +struct vout_top_crg {
> >> + struct clk_bulk_data *top_clks;
> >> + struct reset_control *top_rst;
> >> + int top_clks_num;
> >> + void __iomem *base;
> >> +};
> >> +
> >> +static struct clk_bulk_data jh7110_vout_top_clks[] = {
> >> + { .id = "vout_src" },
> >> + { .id = "vout_top_ahb" }
> >> +};
> >> +
> >> +static struct vout_top_crg *top_crg_from(void __iomem **base)
> >> +{
> >> + return container_of(base, struct vout_top_crg, base);
> >> +}
> >> +
> >> +static int jh7110_vout_top_crg_get(struct jh71x0_clk_priv *priv, struct vout_top_crg *top)
> >> +{
> >> + int ret;
> >> +
> >> + top->top_clks = jh7110_vout_top_clks;
> >> + top->top_clks_num = ARRAY_SIZE(jh7110_vout_top_clks);
> >> + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
> >> + if (ret) {
> >> + dev_err(priv->dev, "top clks get failed: %d\n", ret);
> >> + return ret;
> >> + }
> >> +
> >> + /* The reset should be shared and other Vout modules will use its. */
> >> + top->top_rst = devm_reset_control_get_shared(priv->dev, NULL);
> >> + if (IS_ERR(top->top_rst)) {
> >> + dev_err(priv->dev, "top rst get failed\n");
> >> + return PTR_ERR(top->top_rst);
> >> + }
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int jh7110_vout_top_crg_enable(struct vout_top_crg *top)
> >> +{
> >> + int ret;
> >> +
> >> + ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
> >> + if (ret)
> >> + return ret;
> >
> > Hmm.. do all the clocks used as input really need to be enabled for
> > any one of the vout clocks to work?
> >
> > In other words: suppose you just need a single clock in the VOUTCRG
> > domain. Do we really need to turn on all the input clocks for the
> > VOUTCRG for that one clock to work? Normally I'd expect the clock
> > framework to make sure all parents of that clock are enabled.
>
> It must enable core clock and ahb clock before reading or writing VOUTCRG registers
> otherwise it would be failed to read and write. And it is even crash if it don't
> enable core clock before reading or writing ISPCRG registers.
> This serious problem was found when debugging earlier.

Ah sorry. I see now that you're only claiming the core and AHB bus.
That makes sense.

So now the question is if there are similar clocks that need to be
claimed by the AON, STG and ISP CRGs. They're most likely already
turned on by u-boot or by default which is why we don't see errors,
but Linux should still claim them if the driver needs them.

> >
> >> +
> >> + return reset_control_deassert(top->top_rst);
> >> +}
> >> +
> >> +static void jh7110_vout_top_crg_disable(struct vout_top_crg *top)
> >> +{
> >> + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
> >> +}
> >> +
> >> +static struct clk_hw *jh7110_voutclk_get(struct of_phandle_args *clkspec, void *data)
> >> +{
> >> + struct jh71x0_clk_priv *priv = data;
> >> + unsigned int idx = clkspec->args[0];
> >> +
> >> + if (idx < JH7110_VOUTCLK_END)
> >> + return &priv->reg[idx].hw;
> >> +
> >> + return ERR_PTR(-EINVAL);
> >> +}
> >> +
> >> +static int jh7110_voutcrg_probe(struct platform_device *pdev)
> >> +{
> >> + struct jh71x0_clk_priv *priv;
> >> + struct vout_top_crg *top;
> >> + unsigned int idx;
> >> + int ret;
> >> +
> >> + priv = devm_kzalloc(&pdev->dev,
> >> + struct_size(priv, reg, JH7110_VOUTCLK_END),
> >> + GFP_KERNEL);
> >> + if (!priv)
> >> + return -ENOMEM;
> >> +
> >> + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
> >> + if (!top)
> >> + return -ENOMEM;
> >> +
> >> + spin_lock_init(&priv->rmw_lock);
> >> + priv->dev = &pdev->dev;
> >> + priv->base = devm_platform_ioremap_resource(pdev, 0);
> >> + if (IS_ERR(priv->base))
> >> + return PTR_ERR(priv->base);
> >> +
> >> + top->base = priv->base;
> >> + dev_set_drvdata(priv->dev, (void *)(&top->base));
> >> +
> >> + pm_runtime_enable(priv->dev);
> >> + ret = pm_runtime_get_sync(priv->dev);
> >> + if (ret < 0) {
> >> + dev_err(priv->dev, "failed to turn power: %d\n", ret);
> >> + return ret;
> >> + }
> >> +
> >> + ret = jh7110_vout_top_crg_get(priv, top);
> >> + if (ret)
> >> + goto err_clk;
> >> +
> >> + ret = jh7110_vout_top_crg_enable(top);
> >> + if (ret)
> >> + goto err_clk;
> >> +
> >> + for (idx = 0; idx < JH7110_VOUTCLK_END; idx++) {
> >> + u32 max = jh7110_voutclk_data[idx].max;
> >> + struct clk_parent_data parents[4] = {};
> >> + struct clk_init_data init = {
> >> + .name = jh7110_voutclk_data[idx].name,
> >> + .ops = starfive_jh71x0_clk_ops(max),
> >> + .parent_data = parents,
> >> + .num_parents =
> >> + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
> >> + .flags = jh7110_voutclk_data[idx].flags,
> >> + };
> >> + struct jh71x0_clk *clk = &priv->reg[idx];
> >> + unsigned int i;
> >> + char *fw_name[JH7110_VOUTCLK_EXT_END - JH7110_VOUTCLK_END] = {
> >
> > this can be const char *const fw_name[...] right?
> >
> >> + "vout_src",
> >> + "vout_top_ahb",
> >> + "vout_top_axi",
> >> + "vout_top_hdmitx0_mclk",
> >> + "i2stx0_bclk",
> >> + "hdmitx0_pixelclk"
> >> + };
> >> +
> >> + for (i = 0; i < init.num_parents; i++) {
> >> + unsigned int pidx = jh7110_voutclk_data[idx].parents[i];
> >> +
> >> + if (pidx < JH7110_VOUTCLK_END)
> >> + parents[i].hw = &priv->reg[pidx].hw;
> >> + else if (pidx < JH7110_VOUTCLK_EXT_END)
> >> + parents[i].fw_name = fw_name[pidx - JH7110_VOUTCLK_END];
> >> + }
> >> +
> >> + clk->hw.init = &init;
> >> + clk->idx = idx;
> >> + clk->max_div = max & JH71X0_CLK_DIV_MASK;
> >> +
> >> + ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
> >> + if (ret)
> >> + goto err_exit;
> >> + }
> >> +
> >> + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_voutclk_get, priv);
> >> + if (ret)
> >> + goto err_exit;
> >> +
> >> + ret = jh7110_reset_controller_register(priv, "reset-vout", 4);
> >> + if (ret)
> >> + goto err_exit;
> >> +
> >> + return 0;
> >> +
> >> +err_exit:
> >> + jh7110_vout_top_crg_disable(top);
> >> +err_clk:
> >> + pm_runtime_put_sync(priv->dev);
> >> + pm_runtime_disable(priv->dev);
> >> + return ret;
> >> +}
> >> +
> >> +static int jh7110_voutcrg_remove(struct platform_device *pdev)
> >> +{
> >> + void __iomem **base = dev_get_drvdata(&pdev->dev);
> >> + struct vout_top_crg *top = top_crg_from(base);
> >> +
> >> + jh7110_vout_top_crg_disable(top);
> >> + pm_runtime_disable(&pdev->dev);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static const struct of_device_id jh7110_voutcrg_match[] = {
> >> + { .compatible = "starfive,jh7110-voutcrg" },
> >> + { /* sentinel */ }
> >> +};
> >> +MODULE_DEVICE_TABLE(of, jh7110_voutcrg_match);
> >> +
> >> +static struct platform_driver jh7110_voutcrg_driver = {
> >> + .probe = jh7110_voutcrg_probe,
> >> + .remove = jh7110_voutcrg_remove,
> >> + .driver = {
> >> + .name = "clk-starfive-jh7110-vout",
> >> + .of_match_table = jh7110_voutcrg_match,
> >> + },
> >> +};
> >> +module_platform_driver(jh7110_voutcrg_driver);
> >> +
> >> +MODULE_AUTHOR("Xingyu Wu <[email protected]>");
> >> +MODULE_DESCRIPTION("StarFive JH7110 Video-Output clock driver");
> >> +MODULE_LICENSE("GPL");
> >> --
> >> 2.25.1
> >>
> >>
> >> _______________________________________________
> >> linux-riscv mailing list
> >> [email protected]
> >> http://lists.infradead.org/mailman/listinfo/linux-riscv
>
> Best regards,
> Xingyu Wu

2023-03-03 09:44:01

by Xingyu Wu

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] clk: starfive: Add StarFive JH7110 Video-Output clock driver

On 2023/3/3 17:23, Emil Renner Berthing wrote:
> On Fri, 3 Mar 2023 at 04:37, Xingyu Wu <[email protected]> wrote:
>>
>> On 2023/3/2 23:48, Emil Renner Berthing wrote:
>> > On Tue, 21 Feb 2023 at 09:40, Xingyu Wu <[email protected]> wrote:
>> >>
>> >> Add driver for the StarFive JH7110 Video-Output clock controller.
>> >>
>> >> Signed-off-by: Xingyu Wu <[email protected]>
>> >> ---
>> >> drivers/clk/starfive/Kconfig | 11 +
>> >> drivers/clk/starfive/Makefile | 1 +
>> >> .../clk/starfive/clk-starfive-jh7110-vout.c | 261 ++++++++++++++++++
>> >> 3 files changed, 273 insertions(+)
>> >> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-vout.c
>> >>
>> >> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
>> >> index 59499acb95f7..5ebf1ed08627 100644
>> >> --- a/drivers/clk/starfive/Kconfig
>> >> +++ b/drivers/clk/starfive/Kconfig
>> >> @@ -64,3 +64,14 @@ config CLK_STARFIVE_JH7110_ISP
>> >> help
>> >> Say yes here to support the Image-Signal-Process clock controller
>> >> on the StarFive JH7110 SoC.
>> >> +
>> >> +config CLK_STARFIVE_JH7110_VOUT
>> >> + tristate "StarFive JH7110 Video-Output clock support"
>> >> + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
>> >> + select AUXILIARY_BUS
>> >> + select CLK_STARFIVE_JH71X0
>> >> + select RESET_STARFIVE_JH7110
>> >> + default CLK_STARFIVE_JH7110_SYS
>> >
>> > default m if ARCH_STARFIVE
>>
>> Will modify it.
>>
>> >
>> >> + help
>> >> + Say yes here to support the Video-Output clock controller
>> >> + on the StarFive JH7110 SoC.
>> >> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
>> >> index 76fb9f8d628b..841377e45bb6 100644
>> >> --- a/drivers/clk/starfive/Makefile
>> >> +++ b/drivers/clk/starfive/Makefile
>> >> @@ -8,3 +8,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
>> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
>> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
>> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
>> >> +obj-$(CONFIG_CLK_STARFIVE_JH7110_VOUT) += clk-starfive-jh7110-vout.o
>> >> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-vout.c b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
>> >> new file mode 100644
>> >> index 000000000000..d786537563a4
>> >> --- /dev/null
>> >> +++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
>> >> @@ -0,0 +1,261 @@
>> >> +// SPDX-License-Identifier: GPL-2.0
>> >> +/*
>> >> + * StarFive JH7110 Video-Output Clock Driver
>> >> + *
>> >> + * Copyright (C) 2022 StarFive Technology Co., Ltd.
>> >> + */
>> >> +
>> >> +#include <linux/clk.h>
>> >> +#include <linux/clk-provider.h>
>> >> +#include <linux/io.h>
>> >> +#include <linux/of.h>
>> >> +#include <linux/platform_device.h>
>> >> +#include <linux/pm_runtime.h>
>> >> +#include <linux/reset.h>
>> >> +
>> >> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
>> >> +
>> >> +#include "clk-starfive-jh71x0.h"
>> >> +
>> >> +/* external clocks */
>> >> +#define JH7110_VOUTCLK_VOUT_SRC (JH7110_VOUTCLK_END + 0)
>> >> +#define JH7110_VOUTCLK_VOUT_TOP_AHB (JH7110_VOUTCLK_END + 1)
>> >> +#define JH7110_VOUTCLK_VOUT_TOP_AXI (JH7110_VOUTCLK_END + 2)
>> >> +#define JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK (JH7110_VOUTCLK_END + 3)
>> >> +#define JH7110_VOUTCLK_I2STX0_BCLK (JH7110_VOUTCLK_END + 4)
>> >> +#define JH7110_VOUTCLK_HDMITX0_PIXELCLK (JH7110_VOUTCLK_END + 5)
>> >> +#define JH7110_VOUTCLK_EXT_END (JH7110_VOUTCLK_END + 6)
>> >> +
>> >> +static const struct jh71x0_clk_data jh7110_voutclk_data[] = {
>> >> + /* divider */
>> >> + JH71X0__DIV(JH7110_VOUTCLK_APB, "apb", 8, JH7110_VOUTCLK_VOUT_TOP_AHB),
>> >> + JH71X0__DIV(JH7110_VOUTCLK_DC8200_PIX, "dc8200_pix", 63, JH7110_VOUTCLK_VOUT_SRC),
>> >> + JH71X0__DIV(JH7110_VOUTCLK_DSI_SYS, "dsi_sys", 31, JH7110_VOUTCLK_VOUT_SRC),
>> >> + JH71X0__DIV(JH7110_VOUTCLK_TX_ESC, "tx_esc", 31, JH7110_VOUTCLK_VOUT_TOP_AHB),
>> >> + /* dc8200 */
>> >> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AXI, "dc8200_axi", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
>> >> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_CORE, "dc8200_core", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
>> >> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AHB, "dc8200_ahb", 0, JH7110_VOUTCLK_VOUT_TOP_AHB),
>> >> + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX0, "dc8200_pix0", 0, 2,
>> >> + JH7110_VOUTCLK_DC8200_PIX,
>> >> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
>> >> + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX1, "dc8200_pix1", 0, 2,
>> >> + JH7110_VOUTCLK_DC8200_PIX,
>> >> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
>> >> + /* LCD */
>> >> + JH71X0_GMUX(JH7110_VOUTCLK_DOM_VOUT_TOP_LCD, "dom_vout_top_lcd", 0, 2,
>> >> + JH7110_VOUTCLK_DC8200_PIX0,
>> >> + JH7110_VOUTCLK_DC8200_PIX1),
>> >> + /* dsiTx */
>> >> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_APB, "dsiTx_apb", 0, JH7110_VOUTCLK_DSI_SYS),
>> >> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_SYS, "dsiTx_sys", 0, JH7110_VOUTCLK_DSI_SYS),
>> >> + JH71X0_GMUX(JH7110_VOUTCLK_DSITX_DPI, "dsiTx_dpi", 0, 2,
>> >> + JH7110_VOUTCLK_DC8200_PIX,
>> >> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
>> >> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_TXESC, "dsiTx_txesc", 0, JH7110_VOUTCLK_TX_ESC),
>> >> + /* mipitx DPHY */
>> >> + JH71X0_GATE(JH7110_VOUTCLK_MIPITX_DPHY_TXESC, "mipitx_dphy_txesc", 0,
>> >> + JH7110_VOUTCLK_TX_ESC),
>> >> + /* hdmi */
>> >> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_MCLK, "hdmi_tx_mclk", 0,
>> >> + JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK),
>> >> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_BCLK, "hdmi_tx_bclk", 0,
>> >> + JH7110_VOUTCLK_I2STX0_BCLK),
>> >> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_SYS, "hdmi_tx_sys", 0, JH7110_VOUTCLK_APB),
>> >> +};
>> >> +
>> >> +struct vout_top_crg {
>> >> + struct clk_bulk_data *top_clks;
>> >> + struct reset_control *top_rst;
>> >> + int top_clks_num;
>> >> + void __iomem *base;
>> >> +};
>> >> +
>> >> +static struct clk_bulk_data jh7110_vout_top_clks[] = {
>> >> + { .id = "vout_src" },
>> >> + { .id = "vout_top_ahb" }
>> >> +};
>> >> +
>> >> +static struct vout_top_crg *top_crg_from(void __iomem **base)
>> >> +{
>> >> + return container_of(base, struct vout_top_crg, base);
>> >> +}
>> >> +
>> >> +static int jh7110_vout_top_crg_get(struct jh71x0_clk_priv *priv, struct vout_top_crg *top)
>> >> +{
>> >> + int ret;
>> >> +
>> >> + top->top_clks = jh7110_vout_top_clks;
>> >> + top->top_clks_num = ARRAY_SIZE(jh7110_vout_top_clks);
>> >> + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
>> >> + if (ret) {
>> >> + dev_err(priv->dev, "top clks get failed: %d\n", ret);
>> >> + return ret;
>> >> + }
>> >> +
>> >> + /* The reset should be shared and other Vout modules will use its. */
>> >> + top->top_rst = devm_reset_control_get_shared(priv->dev, NULL);
>> >> + if (IS_ERR(top->top_rst)) {
>> >> + dev_err(priv->dev, "top rst get failed\n");
>> >> + return PTR_ERR(top->top_rst);
>> >> + }
>> >> +
>> >> + return 0;
>> >> +}
>> >> +
>> >> +static int jh7110_vout_top_crg_enable(struct vout_top_crg *top)
>> >> +{
>> >> + int ret;
>> >> +
>> >> + ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
>> >> + if (ret)
>> >> + return ret;
>> >
>> > Hmm.. do all the clocks used as input really need to be enabled for
>> > any one of the vout clocks to work?
>> >
>> > In other words: suppose you just need a single clock in the VOUTCRG
>> > domain. Do we really need to turn on all the input clocks for the
>> > VOUTCRG for that one clock to work? Normally I'd expect the clock
>> > framework to make sure all parents of that clock are enabled.
>>
>> It must enable core clock and ahb clock before reading or writing VOUTCRG registers
>> otherwise it would be failed to read and write. And it is even crash if it don't
>> enable core clock before reading or writing ISPCRG registers.
>> This serious problem was found when debugging earlier.
>
> Ah sorry. I see now that you're only claiming the core and AHB bus.
> That makes sense.
>
> So now the question is if there are similar clocks that need to be
> claimed by the AON, STG and ISP CRGs. They're most likely already
> turned on by u-boot or by default which is why we don't see errors,
> but Linux should still claim them if the driver needs them.

Oh, just VOUTCRG and ISPCRG should actively enable the clock. The clocks like bus clock
are enabled by default about AONCRG and STGCRG. And these clocks already uses CLK_IS_CRITICAL
in SYSCRG to make sure it would not be disabled.

>
>> >
>> >> +
>> >> + return reset_control_deassert(top->top_rst);
>> >> +}
>> >> +
>> >> +static void jh7110_vout_top_crg_disable(struct vout_top_crg *top)
>> >> +{
>> >> + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
>> >> +}
>> >> +
>> >> +static struct clk_hw *jh7110_voutclk_get(struct of_phandle_args *clkspec, void *data)
>> >> +{
>> >> + struct jh71x0_clk_priv *priv = data;
>> >> + unsigned int idx = clkspec->args[0];
>> >> +
>> >> + if (idx < JH7110_VOUTCLK_END)
>> >> + return &priv->reg[idx].hw;
>> >> +
>> >> + return ERR_PTR(-EINVAL);
>> >> +}
>> >> +
>> >> +static int jh7110_voutcrg_probe(struct platform_device *pdev)
>> >> +{
>> >> + struct jh71x0_clk_priv *priv;
>> >> + struct vout_top_crg *top;
>> >> + unsigned int idx;
>> >> + int ret;
>> >> +
>> >> + priv = devm_kzalloc(&pdev->dev,
>> >> + struct_size(priv, reg, JH7110_VOUTCLK_END),
>> >> + GFP_KERNEL);
>> >> + if (!priv)
>> >> + return -ENOMEM;
>> >> +
>> >> + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
>> >> + if (!top)
>> >> + return -ENOMEM;
>> >> +
>> >> + spin_lock_init(&priv->rmw_lock);
>> >> + priv->dev = &pdev->dev;
>> >> + priv->base = devm_platform_ioremap_resource(pdev, 0);
>> >> + if (IS_ERR(priv->base))
>> >> + return PTR_ERR(priv->base);
>> >> +
>> >> + top->base = priv->base;
>> >> + dev_set_drvdata(priv->dev, (void *)(&top->base));
>> >> +
>> >> + pm_runtime_enable(priv->dev);
>> >> + ret = pm_runtime_get_sync(priv->dev);
>> >> + if (ret < 0) {
>> >> + dev_err(priv->dev, "failed to turn power: %d\n", ret);
>> >> + return ret;
>> >> + }
>> >> +
>> >> + ret = jh7110_vout_top_crg_get(priv, top);
>> >> + if (ret)
>> >> + goto err_clk;
>> >> +
>> >> + ret = jh7110_vout_top_crg_enable(top);
>> >> + if (ret)
>> >> + goto err_clk;
>> >> +
>> >> + for (idx = 0; idx < JH7110_VOUTCLK_END; idx++) {
>> >> + u32 max = jh7110_voutclk_data[idx].max;
>> >> + struct clk_parent_data parents[4] = {};
>> >> + struct clk_init_data init = {
>> >> + .name = jh7110_voutclk_data[idx].name,
>> >> + .ops = starfive_jh71x0_clk_ops(max),
>> >> + .parent_data = parents,
>> >> + .num_parents =
>> >> + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
>> >> + .flags = jh7110_voutclk_data[idx].flags,
>> >> + };
>> >> + struct jh71x0_clk *clk = &priv->reg[idx];
>> >> + unsigned int i;
>> >> + char *fw_name[JH7110_VOUTCLK_EXT_END - JH7110_VOUTCLK_END] = {
>> >
>> > this can be const char *const fw_name[...] right?
>> >
>> >> + "vout_src",
>> >> + "vout_top_ahb",
>> >> + "vout_top_axi",
>> >> + "vout_top_hdmitx0_mclk",
>> >> + "i2stx0_bclk",
>> >> + "hdmitx0_pixelclk"
>> >> + };
>> >> +
>> >> + for (i = 0; i < init.num_parents; i++) {
>> >> + unsigned int pidx = jh7110_voutclk_data[idx].parents[i];
>> >> +
>> >> + if (pidx < JH7110_VOUTCLK_END)
>> >> + parents[i].hw = &priv->reg[pidx].hw;
>> >> + else if (pidx < JH7110_VOUTCLK_EXT_END)
>> >> + parents[i].fw_name = fw_name[pidx - JH7110_VOUTCLK_END];
>> >> + }
>> >> +
>> >> + clk->hw.init = &init;
>> >> + clk->idx = idx;
>> >> + clk->max_div = max & JH71X0_CLK_DIV_MASK;
>> >> +
>> >> + ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
>> >> + if (ret)
>> >> + goto err_exit;
>> >> + }
>> >> +
>> >> + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_voutclk_get, priv);
>> >> + if (ret)
>> >> + goto err_exit;
>> >> +
>> >> + ret = jh7110_reset_controller_register(priv, "reset-vout", 4);
>> >> + if (ret)
>> >> + goto err_exit;
>> >> +
>> >> + return 0;
>> >> +
>> >> +err_exit:
>> >> + jh7110_vout_top_crg_disable(top);
>> >> +err_clk:
>> >> + pm_runtime_put_sync(priv->dev);
>> >> + pm_runtime_disable(priv->dev);
>> >> + return ret;
>> >> +}
>> >> +
>> >> +static int jh7110_voutcrg_remove(struct platform_device *pdev)
>> >> +{
>> >> + void __iomem **base = dev_get_drvdata(&pdev->dev);
>> >> + struct vout_top_crg *top = top_crg_from(base);
>> >> +
>> >> + jh7110_vout_top_crg_disable(top);
>> >> + pm_runtime_disable(&pdev->dev);
>> >> +
>> >> + return 0;
>> >> +}
>> >> +
>> >> +static const struct of_device_id jh7110_voutcrg_match[] = {
>> >> + { .compatible = "starfive,jh7110-voutcrg" },
>> >> + { /* sentinel */ }
>> >> +};
>> >> +MODULE_DEVICE_TABLE(of, jh7110_voutcrg_match);
>> >> +
>> >> +static struct platform_driver jh7110_voutcrg_driver = {
>> >> + .probe = jh7110_voutcrg_probe,
>> >> + .remove = jh7110_voutcrg_remove,
>> >> + .driver = {
>> >> + .name = "clk-starfive-jh7110-vout",
>> >> + .of_match_table = jh7110_voutcrg_match,
>> >> + },
>> >> +};
>> >> +module_platform_driver(jh7110_voutcrg_driver);
>> >> +
>> >> +MODULE_AUTHOR("Xingyu Wu <[email protected]>");
>> >> +MODULE_DESCRIPTION("StarFive JH7110 Video-Output clock driver");
>> >> +MODULE_LICENSE("GPL");
>> >> --
>> >> 2.25.1
>> >>
>> >>
>> >> _______________________________________________
>> >> linux-riscv mailing list
>> >> [email protected]
>> >> http://lists.infradead.org/mailman/listinfo/linux-riscv

Best regards,
Xingyu Wu


2023-03-03 09:52:36

by Emil Renner Berthing

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] clk: starfive: Add StarFive JH7110 Video-Output clock driver

On Fri, 3 Mar 2023 at 10:44, Xingyu Wu <[email protected]> wrote:
> On 2023/3/3 17:23, Emil Renner Berthing wrote:
> > On Fri, 3 Mar 2023 at 04:37, Xingyu Wu <[email protected]> wrote:
> >>
> >> On 2023/3/2 23:48, Emil Renner Berthing wrote:
> >> > On Tue, 21 Feb 2023 at 09:40, Xingyu Wu <[email protected]> wrote:
> >> >>
> >> >> Add driver for the StarFive JH7110 Video-Output clock controller.
> >> >>
> >> >> Signed-off-by: Xingyu Wu <[email protected]>
> >> >> ---
> >> >> drivers/clk/starfive/Kconfig | 11 +
> >> >> drivers/clk/starfive/Makefile | 1 +
> >> >> .../clk/starfive/clk-starfive-jh7110-vout.c | 261 ++++++++++++++++++
> >> >> 3 files changed, 273 insertions(+)
> >> >> create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-vout.c
> >> >>
> >> >> diff --git a/drivers/clk/starfive/Kconfig b/drivers/clk/starfive/Kconfig
> >> >> index 59499acb95f7..5ebf1ed08627 100644
> >> >> --- a/drivers/clk/starfive/Kconfig
> >> >> +++ b/drivers/clk/starfive/Kconfig
> >> >> @@ -64,3 +64,14 @@ config CLK_STARFIVE_JH7110_ISP
> >> >> help
> >> >> Say yes here to support the Image-Signal-Process clock controller
> >> >> on the StarFive JH7110 SoC.
> >> >> +
> >> >> +config CLK_STARFIVE_JH7110_VOUT
> >> >> + tristate "StarFive JH7110 Video-Output clock support"
> >> >> + depends on CLK_STARFIVE_JH7110_SYS && JH71XX_PMU
> >> >> + select AUXILIARY_BUS
> >> >> + select CLK_STARFIVE_JH71X0
> >> >> + select RESET_STARFIVE_JH7110
> >> >> + default CLK_STARFIVE_JH7110_SYS
> >> >
> >> > default m if ARCH_STARFIVE
> >>
> >> Will modify it.
> >>
> >> >
> >> >> + help
> >> >> + Say yes here to support the Video-Output clock controller
> >> >> + on the StarFive JH7110 SoC.
> >> >> diff --git a/drivers/clk/starfive/Makefile b/drivers/clk/starfive/Makefile
> >> >> index 76fb9f8d628b..841377e45bb6 100644
> >> >> --- a/drivers/clk/starfive/Makefile
> >> >> +++ b/drivers/clk/starfive/Makefile
> >> >> @@ -8,3 +8,4 @@ obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
> >> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
> >> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_STG) += clk-starfive-jh7110-stg.o
> >> >> obj-$(CONFIG_CLK_STARFIVE_JH7110_ISP) += clk-starfive-jh7110-isp.o
> >> >> +obj-$(CONFIG_CLK_STARFIVE_JH7110_VOUT) += clk-starfive-jh7110-vout.o
> >> >> diff --git a/drivers/clk/starfive/clk-starfive-jh7110-vout.c b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
> >> >> new file mode 100644
> >> >> index 000000000000..d786537563a4
> >> >> --- /dev/null
> >> >> +++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c
> >> >> @@ -0,0 +1,261 @@
> >> >> +// SPDX-License-Identifier: GPL-2.0
> >> >> +/*
> >> >> + * StarFive JH7110 Video-Output Clock Driver
> >> >> + *
> >> >> + * Copyright (C) 2022 StarFive Technology Co., Ltd.
> >> >> + */
> >> >> +
> >> >> +#include <linux/clk.h>
> >> >> +#include <linux/clk-provider.h>
> >> >> +#include <linux/io.h>
> >> >> +#include <linux/of.h>
> >> >> +#include <linux/platform_device.h>
> >> >> +#include <linux/pm_runtime.h>
> >> >> +#include <linux/reset.h>
> >> >> +
> >> >> +#include <dt-bindings/clock/starfive,jh7110-crg.h>
> >> >> +
> >> >> +#include "clk-starfive-jh71x0.h"
> >> >> +
> >> >> +/* external clocks */
> >> >> +#define JH7110_VOUTCLK_VOUT_SRC (JH7110_VOUTCLK_END + 0)
> >> >> +#define JH7110_VOUTCLK_VOUT_TOP_AHB (JH7110_VOUTCLK_END + 1)
> >> >> +#define JH7110_VOUTCLK_VOUT_TOP_AXI (JH7110_VOUTCLK_END + 2)
> >> >> +#define JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK (JH7110_VOUTCLK_END + 3)
> >> >> +#define JH7110_VOUTCLK_I2STX0_BCLK (JH7110_VOUTCLK_END + 4)
> >> >> +#define JH7110_VOUTCLK_HDMITX0_PIXELCLK (JH7110_VOUTCLK_END + 5)
> >> >> +#define JH7110_VOUTCLK_EXT_END (JH7110_VOUTCLK_END + 6)
> >> >> +
> >> >> +static const struct jh71x0_clk_data jh7110_voutclk_data[] = {
> >> >> + /* divider */
> >> >> + JH71X0__DIV(JH7110_VOUTCLK_APB, "apb", 8, JH7110_VOUTCLK_VOUT_TOP_AHB),
> >> >> + JH71X0__DIV(JH7110_VOUTCLK_DC8200_PIX, "dc8200_pix", 63, JH7110_VOUTCLK_VOUT_SRC),
> >> >> + JH71X0__DIV(JH7110_VOUTCLK_DSI_SYS, "dsi_sys", 31, JH7110_VOUTCLK_VOUT_SRC),
> >> >> + JH71X0__DIV(JH7110_VOUTCLK_TX_ESC, "tx_esc", 31, JH7110_VOUTCLK_VOUT_TOP_AHB),
> >> >> + /* dc8200 */
> >> >> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AXI, "dc8200_axi", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
> >> >> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_CORE, "dc8200_core", 0, JH7110_VOUTCLK_VOUT_TOP_AXI),
> >> >> + JH71X0_GATE(JH7110_VOUTCLK_DC8200_AHB, "dc8200_ahb", 0, JH7110_VOUTCLK_VOUT_TOP_AHB),
> >> >> + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX0, "dc8200_pix0", 0, 2,
> >> >> + JH7110_VOUTCLK_DC8200_PIX,
> >> >> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
> >> >> + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX1, "dc8200_pix1", 0, 2,
> >> >> + JH7110_VOUTCLK_DC8200_PIX,
> >> >> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
> >> >> + /* LCD */
> >> >> + JH71X0_GMUX(JH7110_VOUTCLK_DOM_VOUT_TOP_LCD, "dom_vout_top_lcd", 0, 2,
> >> >> + JH7110_VOUTCLK_DC8200_PIX0,
> >> >> + JH7110_VOUTCLK_DC8200_PIX1),
> >> >> + /* dsiTx */
> >> >> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_APB, "dsiTx_apb", 0, JH7110_VOUTCLK_DSI_SYS),
> >> >> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_SYS, "dsiTx_sys", 0, JH7110_VOUTCLK_DSI_SYS),
> >> >> + JH71X0_GMUX(JH7110_VOUTCLK_DSITX_DPI, "dsiTx_dpi", 0, 2,
> >> >> + JH7110_VOUTCLK_DC8200_PIX,
> >> >> + JH7110_VOUTCLK_HDMITX0_PIXELCLK),
> >> >> + JH71X0_GATE(JH7110_VOUTCLK_DSITX_TXESC, "dsiTx_txesc", 0, JH7110_VOUTCLK_TX_ESC),
> >> >> + /* mipitx DPHY */
> >> >> + JH71X0_GATE(JH7110_VOUTCLK_MIPITX_DPHY_TXESC, "mipitx_dphy_txesc", 0,
> >> >> + JH7110_VOUTCLK_TX_ESC),
> >> >> + /* hdmi */
> >> >> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_MCLK, "hdmi_tx_mclk", 0,
> >> >> + JH7110_VOUTCLK_VOUT_TOP_HDMITX0_MCLK),
> >> >> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_BCLK, "hdmi_tx_bclk", 0,
> >> >> + JH7110_VOUTCLK_I2STX0_BCLK),
> >> >> + JH71X0_GATE(JH7110_VOUTCLK_HDMI_TX_SYS, "hdmi_tx_sys", 0, JH7110_VOUTCLK_APB),
> >> >> +};
> >> >> +
> >> >> +struct vout_top_crg {
> >> >> + struct clk_bulk_data *top_clks;
> >> >> + struct reset_control *top_rst;
> >> >> + int top_clks_num;
> >> >> + void __iomem *base;
> >> >> +};
> >> >> +
> >> >> +static struct clk_bulk_data jh7110_vout_top_clks[] = {
> >> >> + { .id = "vout_src" },
> >> >> + { .id = "vout_top_ahb" }
> >> >> +};
> >> >> +
> >> >> +static struct vout_top_crg *top_crg_from(void __iomem **base)
> >> >> +{
> >> >> + return container_of(base, struct vout_top_crg, base);
> >> >> +}
> >> >> +
> >> >> +static int jh7110_vout_top_crg_get(struct jh71x0_clk_priv *priv, struct vout_top_crg *top)
> >> >> +{
> >> >> + int ret;
> >> >> +
> >> >> + top->top_clks = jh7110_vout_top_clks;
> >> >> + top->top_clks_num = ARRAY_SIZE(jh7110_vout_top_clks);
> >> >> + ret = devm_clk_bulk_get(priv->dev, top->top_clks_num, top->top_clks);
> >> >> + if (ret) {
> >> >> + dev_err(priv->dev, "top clks get failed: %d\n", ret);
> >> >> + return ret;
> >> >> + }
> >> >> +
> >> >> + /* The reset should be shared and other Vout modules will use its. */
> >> >> + top->top_rst = devm_reset_control_get_shared(priv->dev, NULL);
> >> >> + if (IS_ERR(top->top_rst)) {
> >> >> + dev_err(priv->dev, "top rst get failed\n");
> >> >> + return PTR_ERR(top->top_rst);
> >> >> + }
> >> >> +
> >> >> + return 0;
> >> >> +}
> >> >> +
> >> >> +static int jh7110_vout_top_crg_enable(struct vout_top_crg *top)
> >> >> +{
> >> >> + int ret;
> >> >> +
> >> >> + ret = clk_bulk_prepare_enable(top->top_clks_num, top->top_clks);
> >> >> + if (ret)
> >> >> + return ret;
> >> >
> >> > Hmm.. do all the clocks used as input really need to be enabled for
> >> > any one of the vout clocks to work?
> >> >
> >> > In other words: suppose you just need a single clock in the VOUTCRG
> >> > domain. Do we really need to turn on all the input clocks for the
> >> > VOUTCRG for that one clock to work? Normally I'd expect the clock
> >> > framework to make sure all parents of that clock are enabled.
> >>
> >> It must enable core clock and ahb clock before reading or writing VOUTCRG registers
> >> otherwise it would be failed to read and write. And it is even crash if it don't
> >> enable core clock before reading or writing ISPCRG registers.
> >> This serious problem was found when debugging earlier.
> >
> > Ah sorry. I see now that you're only claiming the core and AHB bus.
> > That makes sense.
> >
> > So now the question is if there are similar clocks that need to be
> > claimed by the AON, STG and ISP CRGs. They're most likely already
> > turned on by u-boot or by default which is why we don't see errors,
> > but Linux should still claim them if the driver needs them.
>
> Oh, just VOUTCRG and ISPCRG should actively enable the clock. The clocks like bus clock
> are enabled by default about AONCRG and STGCRG. And these clocks already uses CLK_IS_CRITICAL
> in SYSCRG to make sure it would not be disabled.

Oh, so maybe those clocks are not critical, but just need to be
claimed and turned on by the AONCRG and STGCRG drivers before use?

> >
> >> >
> >> >> +
> >> >> + return reset_control_deassert(top->top_rst);
> >> >> +}
> >> >> +
> >> >> +static void jh7110_vout_top_crg_disable(struct vout_top_crg *top)
> >> >> +{
> >> >> + clk_bulk_disable_unprepare(top->top_clks_num, top->top_clks);
> >> >> +}
> >> >> +
> >> >> +static struct clk_hw *jh7110_voutclk_get(struct of_phandle_args *clkspec, void *data)
> >> >> +{
> >> >> + struct jh71x0_clk_priv *priv = data;
> >> >> + unsigned int idx = clkspec->args[0];
> >> >> +
> >> >> + if (idx < JH7110_VOUTCLK_END)
> >> >> + return &priv->reg[idx].hw;
> >> >> +
> >> >> + return ERR_PTR(-EINVAL);
> >> >> +}
> >> >> +
> >> >> +static int jh7110_voutcrg_probe(struct platform_device *pdev)
> >> >> +{
> >> >> + struct jh71x0_clk_priv *priv;
> >> >> + struct vout_top_crg *top;
> >> >> + unsigned int idx;
> >> >> + int ret;
> >> >> +
> >> >> + priv = devm_kzalloc(&pdev->dev,
> >> >> + struct_size(priv, reg, JH7110_VOUTCLK_END),
> >> >> + GFP_KERNEL);
> >> >> + if (!priv)
> >> >> + return -ENOMEM;
> >> >> +
> >> >> + top = devm_kzalloc(&pdev->dev, sizeof(*top), GFP_KERNEL);
> >> >> + if (!top)
> >> >> + return -ENOMEM;
> >> >> +
> >> >> + spin_lock_init(&priv->rmw_lock);
> >> >> + priv->dev = &pdev->dev;
> >> >> + priv->base = devm_platform_ioremap_resource(pdev, 0);
> >> >> + if (IS_ERR(priv->base))
> >> >> + return PTR_ERR(priv->base);
> >> >> +
> >> >> + top->base = priv->base;
> >> >> + dev_set_drvdata(priv->dev, (void *)(&top->base));
> >> >> +
> >> >> + pm_runtime_enable(priv->dev);
> >> >> + ret = pm_runtime_get_sync(priv->dev);
> >> >> + if (ret < 0) {
> >> >> + dev_err(priv->dev, "failed to turn power: %d\n", ret);
> >> >> + return ret;
> >> >> + }
> >> >> +
> >> >> + ret = jh7110_vout_top_crg_get(priv, top);
> >> >> + if (ret)
> >> >> + goto err_clk;
> >> >> +
> >> >> + ret = jh7110_vout_top_crg_enable(top);
> >> >> + if (ret)
> >> >> + goto err_clk;
> >> >> +
> >> >> + for (idx = 0; idx < JH7110_VOUTCLK_END; idx++) {
> >> >> + u32 max = jh7110_voutclk_data[idx].max;
> >> >> + struct clk_parent_data parents[4] = {};
> >> >> + struct clk_init_data init = {
> >> >> + .name = jh7110_voutclk_data[idx].name,
> >> >> + .ops = starfive_jh71x0_clk_ops(max),
> >> >> + .parent_data = parents,
> >> >> + .num_parents =
> >> >> + ((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
> >> >> + .flags = jh7110_voutclk_data[idx].flags,
> >> >> + };
> >> >> + struct jh71x0_clk *clk = &priv->reg[idx];
> >> >> + unsigned int i;
> >> >> + char *fw_name[JH7110_VOUTCLK_EXT_END - JH7110_VOUTCLK_END] = {
> >> >
> >> > this can be const char *const fw_name[...] right?
> >> >
> >> >> + "vout_src",
> >> >> + "vout_top_ahb",
> >> >> + "vout_top_axi",
> >> >> + "vout_top_hdmitx0_mclk",
> >> >> + "i2stx0_bclk",
> >> >> + "hdmitx0_pixelclk"
> >> >> + };
> >> >> +
> >> >> + for (i = 0; i < init.num_parents; i++) {
> >> >> + unsigned int pidx = jh7110_voutclk_data[idx].parents[i];
> >> >> +
> >> >> + if (pidx < JH7110_VOUTCLK_END)
> >> >> + parents[i].hw = &priv->reg[pidx].hw;
> >> >> + else if (pidx < JH7110_VOUTCLK_EXT_END)
> >> >> + parents[i].fw_name = fw_name[pidx - JH7110_VOUTCLK_END];
> >> >> + }
> >> >> +
> >> >> + clk->hw.init = &init;
> >> >> + clk->idx = idx;
> >> >> + clk->max_div = max & JH71X0_CLK_DIV_MASK;
> >> >> +
> >> >> + ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
> >> >> + if (ret)
> >> >> + goto err_exit;
> >> >> + }
> >> >> +
> >> >> + ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_voutclk_get, priv);
> >> >> + if (ret)
> >> >> + goto err_exit;
> >> >> +
> >> >> + ret = jh7110_reset_controller_register(priv, "reset-vout", 4);
> >> >> + if (ret)
> >> >> + goto err_exit;
> >> >> +
> >> >> + return 0;
> >> >> +
> >> >> +err_exit:
> >> >> + jh7110_vout_top_crg_disable(top);
> >> >> +err_clk:
> >> >> + pm_runtime_put_sync(priv->dev);
> >> >> + pm_runtime_disable(priv->dev);
> >> >> + return ret;
> >> >> +}
> >> >> +
> >> >> +static int jh7110_voutcrg_remove(struct platform_device *pdev)
> >> >> +{
> >> >> + void __iomem **base = dev_get_drvdata(&pdev->dev);
> >> >> + struct vout_top_crg *top = top_crg_from(base);
> >> >> +
> >> >> + jh7110_vout_top_crg_disable(top);
> >> >> + pm_runtime_disable(&pdev->dev);
> >> >> +
> >> >> + return 0;
> >> >> +}
> >> >> +
> >> >> +static const struct of_device_id jh7110_voutcrg_match[] = {
> >> >> + { .compatible = "starfive,jh7110-voutcrg" },
> >> >> + { /* sentinel */ }
> >> >> +};
> >> >> +MODULE_DEVICE_TABLE(of, jh7110_voutcrg_match);
> >> >> +
> >> >> +static struct platform_driver jh7110_voutcrg_driver = {
> >> >> + .probe = jh7110_voutcrg_probe,
> >> >> + .remove = jh7110_voutcrg_remove,
> >> >> + .driver = {
> >> >> + .name = "clk-starfive-jh7110-vout",
> >> >> + .of_match_table = jh7110_voutcrg_match,
> >> >> + },
> >> >> +};
> >> >> +module_platform_driver(jh7110_voutcrg_driver);
> >> >> +
> >> >> +MODULE_AUTHOR("Xingyu Wu <[email protected]>");
> >> >> +MODULE_DESCRIPTION("StarFive JH7110 Video-Output clock driver");
> >> >> +MODULE_LICENSE("GPL");
> >> >> --
> >> >> 2.25.1
> >> >>
> >> >>
> >> >> _______________________________________________
> >> >> linux-riscv mailing list
> >> >> [email protected]
> >> >> http://lists.infradead.org/mailman/listinfo/linux-riscv
>
> Best regards,
> Xingyu Wu
>