diff mbox series

[v2] drm/mipi-dsi: Add OF notifier handler

Message ID 20240627071904.4017160-1-wenst@chromium.org (mailing list archive)
State New, archived
Headers show
Series [v2] drm/mipi-dsi: Add OF notifier handler | expand

Commit Message

Chen-Yu Tsai June 27, 2024, 7:19 a.m. UTC
Add OF notifier handler needed for creating/destroying MIPI DSI devices
according to dynamic runtime changes in the DT live tree. This code is
enabled when CONFIG_OF_DYNAMIC is selected.

This is based on existing code for I2C and SPI subsystems.

Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v1:
- Added stub mipi_dsi_of_notifier in CONFIG_OF=n section for compilation

 drivers/gpu/drm/drm_mipi_dsi.c | 68 +++++++++++++++++++++++++++++++++-
 1 file changed, 67 insertions(+), 1 deletion(-)

Comments

Luca Ceresoli June 28, 2024, 10:31 a.m. UTC | #1
Hello Chen-Yu,

+Rob

On Thu, 27 Jun 2024 15:19:03 +0800
Chen-Yu Tsai <wenst@chromium.org> wrote:

> Add OF notifier handler needed for creating/destroying MIPI DSI devices
> according to dynamic runtime changes in the DT live tree. This code is
> enabled when CONFIG_OF_DYNAMIC is selected.
> 
> This is based on existing code for I2C and SPI subsystems.
> 
> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>

Thanks for copying me on this patch. Could be useful for my
hotplug-bridge work, however I'm aiming at writing code that works also
for non-DSI so we'll see. The code looks pretty fine however.

My concern however is about the usage of an OF reconfig notifier. A few
days ago Rob Herring wrote:

> a notifier is never a great design so
> maybe we can come up with something better

(https://lore.kernel.org/all/CAL_Jsq+=mGEJXsjq1UZFMJtHko_z+doiFMXnx9K7exDuznymSA@mail.gmail.com)

So maybe this is something you can clarify with him.

Luca
Chen-Yu Tsai July 4, 2024, 7:04 a.m. UTC | #2
On Fri, Jun 28, 2024 at 6:31 PM Luca Ceresoli <luca.ceresoli@bootlin.com> wrote:
>
> Hello Chen-Yu,
>
> +Rob
>
> On Thu, 27 Jun 2024 15:19:03 +0800
> Chen-Yu Tsai <wenst@chromium.org> wrote:
>
> > Add OF notifier handler needed for creating/destroying MIPI DSI devices
> > according to dynamic runtime changes in the DT live tree. This code is
> > enabled when CONFIG_OF_DYNAMIC is selected.
> >
> > This is based on existing code for I2C and SPI subsystems.
> >
> > Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
>
> Thanks for copying me on this patch. Could be useful for my
> hotplug-bridge work, however I'm aiming at writing code that works also
> for non-DSI so we'll see. The code looks pretty fine however.
>
> My concern however is about the usage of an OF reconfig notifier. A few
> days ago Rob Herring wrote:
>
> > a notifier is never a great design so
> > maybe we can come up with something better
>
> (https://lore.kernel.org/all/CAL_Jsq+=mGEJXsjq1UZFMJtHko_z+doiFMXnx9K7exDuznymSA@mail.gmail.com)
>
> So maybe this is something you can clarify with him.

Well, as mentioned in the commit message, this is based on existing code
found in the I2C and SPI cores. In these cases it is dealing with the
status flipping from disabled to okay, which then triggers the subsystem
to register a new device for the toggled device node.

If a better mechanism can be developed, then the existing code along with
the code I introduce here can be migrated over.

ChenYu

> Luca
>
> --
> Luca Ceresoli, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index a471c46f5ca6..35d6ed1fb587 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -118,6 +118,7 @@  static void mipi_dsi_dev_release(struct device *dev)
 {
 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
 
+	of_node_clear_flag(dev->of_node, OF_POPULATED);
 	of_node_put(dev->of_node);
 	kfree(dsi);
 }
@@ -158,6 +159,7 @@  static struct mipi_dsi_device *
 of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)
 {
 	struct mipi_dsi_device_info info = { };
+	struct mipi_dsi_device *device;
 	int ret;
 	u32 reg;
 
@@ -175,10 +177,72 @@  of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)
 
 	info.channel = reg;
 	info.node = of_node_get(node);
+	of_node_set_flag(node, OF_POPULATED);
 
-	return mipi_dsi_device_register_full(host, &info);
+	device = mipi_dsi_device_register_full(host, &info);
+	if (IS_ERR(device))
+		of_node_clear_flag(node, OF_POPULATED);
+
+	return device;
 }
+
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+static int of_mipi_dsi_notify(struct notifier_block *nb, unsigned long action, void *arg)
+{
+	struct of_reconfig_data *rd = arg;
+	struct mipi_dsi_host *host;
+	struct mipi_dsi_device *device;
+
+	switch (of_reconfig_get_state_change(action, rd)) {
+	case OF_RECONFIG_CHANGE_ADD:
+		host = of_find_mipi_dsi_host_by_node(rd->dn->parent);
+		if (!host)
+			return NOTIFY_OK;	/* not for us */
+
+		if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
+			return NOTIFY_OK;
+
+		/*
+		 * Clear the flag before adding the device so that fw_devlink
+		 * doesn't skip adding consumers to this device.
+		 */
+		rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE;
+		device = of_mipi_dsi_device_add(host, rd->dn);
+		if (IS_ERR(device)) {
+			dev_err(host->dev, "failed to create device for '%pOF'\n", rd->dn);
+			of_node_clear_flag(rd->dn, OF_POPULATED);
+			return notifier_from_errno(PTR_ERR(device));
+		}
+		break;
+	case OF_RECONFIG_CHANGE_REMOVE:
+		/* already depopulated? */
+		if (!of_node_check_flag(rd->dn, OF_POPULATED))
+			return NOTIFY_OK;
+
+		/* find our device by node */
+		device = of_find_mipi_dsi_device_by_node(rd->dn);
+		if (!device)
+			return NOTIFY_OK;	/* no? not meant for us */
+
+		/* unregister takes one ref away */
+		mipi_dsi_device_unregister(device);
+
+		/* and put the reference of the find */
+		put_device(&device->dev);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block mipi_dsi_of_notifier = {
+	.notifier_call = of_mipi_dsi_notify,
+};
+#else
+static struct notifier_block mipi_dsi_of_notifier __always_unused;
+#endif
 #else
+static struct notifier_block mipi_dsi_of_notifier __always_unused;
 static struct mipi_dsi_device *
 of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)
 {
@@ -1703,6 +1767,8 @@  EXPORT_SYMBOL(mipi_dsi_driver_unregister);
 
 static int __init mipi_dsi_bus_init(void)
 {
+	if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+		WARN_ON(of_reconfig_notifier_register(&mipi_dsi_of_notifier));
 	return bus_register(&mipi_dsi_bus_type);
 }
 postcore_initcall(mipi_dsi_bus_init);