fw_devlinks preventing a panel driver from probing

Tomi Valkeinen tomi.valkeinen at ideasonboard.com
Mon Sep 16 11:51:57 UTC 2024


Hi,

We have an issue where two devices have dependencies to each other, 
according to drivers/base/core.c's fw_devlinks, and this prevents them 
from probing. I've been adding debugging to the core.c, but so far I 
don't quite grasp the issue, so I thought to ask. Maybe someone can 
instantly say that this just won't work...

So, we have two devices, DSS (display subsystem) and an LVDS panel. The 
DSS normally outputs parallel video from its video ports (VP), but it 
has an integrated LVDS block (OLDI, Open LVDS Display Interface). The 
OLDI block takes input from DSS's parallel outputs. The OLDI is not 
modeled as a separate device (neither in the DT nor in the Linux device 
model) as it has no register space, and is controlled fully by the DSS.

To support dual-link LVDS, the DSS has two OLDI instances. They both 
take their input from the same parallel video port, but each OLDI sends 
alternate lines forward. So for a dual-link setup the connections would 
be like this:

+-----+-----+         +-------+         +----------+
|     |     |         |       |         |          |
|     | VP1 +----+--->| OLDI0 +-------->|          |
|     |     |    |    |       |         |          |
| DSS +-----+    |    +-------+         |  Panel   |
|     |     |    |    |       |         |          |
|     | VP2 |    +--->| OLDI1 +-------->|          |
|     |     |         |       |         |          |
+-----+-----+         +-------+         +----------+

As the OLDI is not a separate device, it also does not have an 
independent device tree node, but rather it's inside DSS's node. The DSS 
parallel outputs are under a normal "ports" node, but OLDI ports are 
under "oldi-txes/ports" (see below for dts to clarify this).

And I think (guess...) this is the root of the issue we're seeing, as it 
means the following, one or both of which might be the reason for this 
issue:

- OLDI fwnodes don't have an associated struct device *. I think the 
reason is that the OLDI media graph ports are one level too deep in the 
hierarchy. So while the DSS ports are associated with the DSS device, 
OLDI ports are not.

- The VP ports inside the DSS point to OLDI ports, which are also inside 
DSS. So ports from a device point to ports in the same device (and back).

If I understand the fw_devlink code correctly, in a normal case the 
links formed with media graphs are marked as a cycle 
(FWLINK_FLAG_CYCLE), and then ignored as far as probing goes.

What we see here is that when using a single-link OLDI panel, the panel 
driver's probe never gets called, as it depends on the OLDI, and the 
link between the panel and the OLDI is not a cycle.

The DSS driver probes, but the probe fails as it requires all the panel 
devices to have been probed (and thus registered to the DRM framework) 
before it can finish its setup.

With dual-link, probing does happen and the drivers work. But I believe 
this is essentially an accident, in the sense that the first link 
between the panel and the OLDI still blocks the probing, but the second 
links allows the driver core to traverse the devlinks further, causing 
it to mark the links to the panel as FWLINK_FLAG_CYCLE (or maybe it only 
marks one of those links, and that's enough).

If I set fw_devlink=off as a kernel parameter, the probing proceeds 
successfully in both single- and dual-link cases.

Now, my questions is, is this a bug in the driver core, a bug in the DT 
bindings, or something in between (DT is fine-ish, but the structure is 
something that won't be supported by the driver core).

And a follow-up question, regardless of the answer to the first one: 
which direction should I go from here =).

The device tree data (simplified) for this is as follows, first the 
dual-link case, then the single-link case:

/* Dual-link */

dss: dss at 30200000 {
	compatible = "ti,am625-dss";

	oldi-txes {
		oldi0: oldi at 0 {
			oldi0_ports: ports {
				port at 0 {
					oldi_0_in: endpoint {
						remote-endpoint = <&dpi0_out0>;
					};
				};

				port at 1 {
					oldi_0_out: endpoint {
						remote-endpoint = <&lcd_in0>;
					};
				};
			};
		};

		oldi1: oldi at 1 {
			oldi1_ports: ports {
				port at 0 {
					oldi_1_in: endpoint {
						remote-endpoint = <&dpi0_out1>;
					};
				};

				port at 1 {
					oldi_1_out: endpoint {
						remote-endpoint = <&lcd_in1>;
					};
				};
			};
		};
	};

	dss_ports: ports {
		port at 0 {
			dpi0_out0: endpoint at 0 {
				remote-endpoint = <&oldi_0_in>;
			};
			dpi0_out1: endpoint at 1 {
				remote-endpoint = <&oldi_1_in>;
			};
		};
	};
};

display {
	compatible = "microtips,mf-101hiebcaf0", "panel-simple";

	ports {
		port at 0 {
			lcd_in0: endpoint {
				remote-endpoint = <&oldi_0_out>;
			};
		};

		port at 1 {
			lcd_in1: endpoint {
				remote-endpoint = <&oldi_1_out>;
			};
		};
	};
};


/* Single-link */

dss: dss at 30200000 {
	compatible = "ti,am625-dss";

	oldi-txes {
		oldi0: oldi at 0 {
			oldi0_ports: ports {
				port at 0 {
					oldi_0_in: endpoint {
						remote-endpoint = <&dpi0_out0>;
					};
				};

				port at 1 {
					oldi_0_out: endpoint {
						remote-endpoint = <&lcd_in0>;
					};
				};
			};
		};
	};

	dss_ports: ports {
		port at 0 {
			dpi0_out0: endpoint at 0 {
				remote-endpoint = <&oldi_0_in>;
			};
		};
	};
};

display {
	compatible = "microtips,mf-101hiebcaf0", "panel-simple";

	ports {
		port at 0 {
			lcd_in0: endpoint {
				remote-endpoint = <&oldi_0_out>;
			};
		};
	};
};

  Tomi



More information about the dri-devel mailing list