[PATCH v3 12/19] soc: starfive: Add jh7110-vout-subsystem driver
From: Michal Wilczynski
Date: Fri Sep 04 2026 - 09:32:58 EST
Nothing in the video output subsystem can reach its own registers until
the NoC display bus clock and reset are up and PD_VOUT is powered, and
those are shared by every device in the region. Leaving them to whichever
consumer probes first works by accident and stops working as soon as the
probe order changes.
Add a driver for the subsystem node that takes the bus clock and reset,
holds a runtime PM reference so genpd keeps PD_VOUT powered, and then
populates its children. All three are released only once the last child
is gone.
Signed-off-by: Michal Wilczynski <m.wilczynski@xxxxxxxxxxx>
---
drivers/soc/starfive/Kconfig | 15 +++++
drivers/soc/starfive/Makefile | 1 +
drivers/soc/starfive/jh7110-vout-subsystem.c | 83 ++++++++++++++++++++++++++++
3 files changed, 99 insertions(+)
diff --git a/drivers/soc/starfive/Kconfig b/drivers/soc/starfive/Kconfig
index e738638ab0f755fbbabca259264abb56f3b6101f..cf5e626b8a39a75768917eee188a79256b36f1aa 100644
--- a/drivers/soc/starfive/Kconfig
+++ b/drivers/soc/starfive/Kconfig
@@ -6,6 +6,21 @@
if ARCH_STARFIVE || COMPILE_TEST
menu "Starfive SoC drivers"
+config SOC_STARFIVE_JH7110_VOUT_SUBSYSTEM
+ tristate "StarFive JH7110 video output subsystem driver"
+ depends on OF
+ select PM
+ help
+ This option enables the parent driver for the StarFive JH7110
+ video output subsystem, which the documentation calls dom_vout_top.
+
+ The subsystem covers the DC8200 display controller, the HDMI
+ transmitter, the video output clock generator and the video output
+ system controller. They share one NoC port whose clock and reset
+ gate access to the whole register region, and the region sits in
+ the PD_VOUT power domain. This driver owns those resources and
+ holds them for as long as any of its children exist.
+
config SOC_STARFIVE_JH7110_HDMI_SUBSYSTEM
tristate "StarFive JH7110 HDMI subsystem driver"
depends on OF
diff --git a/drivers/soc/starfive/Makefile b/drivers/soc/starfive/Makefile
index be89d8119212b7a7038817c2f0e8eac1984ada88..6c229020c1e563b37df43f6ac1665465a11333cc 100644
--- a/drivers/soc/starfive/Makefile
+++ b/drivers/soc/starfive/Makefile
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SOC_STARFIVE_JH7110_HDMI_SUBSYSTEM) += jh7110-hdmi-subsystem.o
+obj-$(CONFIG_SOC_STARFIVE_JH7110_VOUT_SUBSYSTEM) += jh7110-vout-subsystem.o
diff --git a/drivers/soc/starfive/jh7110-vout-subsystem.c b/drivers/soc/starfive/jh7110-vout-subsystem.c
new file mode 100644
index 0000000000000000000000000000000000000000..d06ce43d80b1637995a4c5f100d89945d27a192a
--- /dev/null
+++ b/drivers/soc/starfive/jh7110-vout-subsystem.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the StarFive JH7110 video output subsystem
+ *
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@xxxxxxxxxxx>
+ *
+ * The display hardware sits behind a single NoC port whose clock and reset
+ * gate access to every register in the region, inside the PD_VOUT power
+ * domain. Nothing below this node can reach its own registers until all three
+ * are up, so bring them up here and hold them for as long as any child device
+ * exists, rather than leaving them to whichever consumer happens to probe
+ * first.
+ */
+
+#include <linux/clk.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+static void jh7110_vout_subsys_pm_put(void *data)
+{
+ pm_runtime_put_sync(data);
+}
+
+static int jh7110_vout_subsys_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct reset_control *bus_rst;
+ struct clk *bus_clk;
+ int ret;
+
+ /*
+ * Take a runtime PM reference for the lifetime of this device. genpd
+ * only keeps PD_VOUT powered while something actually holds it, and
+ * an unclocked or unpowered access to this region wedges the bus.
+ */
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to power on PD_VOUT\n");
+
+ ret = devm_add_action_or_reset(dev, jh7110_vout_subsys_pm_put, dev);
+ if (ret)
+ return ret;
+
+ bus_clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(bus_clk))
+ return dev_err_probe(dev, PTR_ERR(bus_clk),
+ "Failed to enable NoC bus clock\n");
+
+ bus_rst = devm_reset_control_get_exclusive_deasserted(dev, NULL);
+ if (IS_ERR(bus_rst))
+ return dev_err_probe(dev, PTR_ERR(bus_rst),
+ "Failed to deassert NoC bus reset\n");
+
+ return devm_of_platform_populate(dev);
+}
+
+static const struct of_device_id jh7110_vout_subsys_of_match[] = {
+ { .compatible = "starfive,jh7110-vout-subsystem", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jh7110_vout_subsys_of_match);
+
+static struct platform_driver jh7110_vout_subsys_driver = {
+ .probe = jh7110_vout_subsys_probe,
+ .driver = {
+ .name = "jh7110-vout-subsystem",
+ .of_match_table = jh7110_vout_subsys_of_match,
+ },
+};
+module_platform_driver(jh7110_vout_subsys_driver);
+
+MODULE_AUTHOR("Michal Wilczynski <m.wilczynski@xxxxxxxxxxx>");
+MODULE_DESCRIPTION("StarFive JH7110 video output subsystem driver");
+MODULE_LICENSE("GPL");
--
2.34.1