MIPI/DSI on Verdin i.MX8MP

Hi all,

My goal is to get a Display working with my TorizonOS based i.MX8MP, but due to my limited Device Tree Experience, I’m a bit stuck. Our setup is as follows:
i.MX8MP with TorizonOS 7.1.0. and a working Slint application (Tested with HDMI using the preinstalled HDMI overlay), which should output via MIPI to a connected FPD Serializer (https://www.ti.com/product/DS90UB941AS-Q1), then Deserializer (https://www.ti.com/product/DS90UB926Q-Q1) and in the end RGB display:
display_chain

What I did until now was I enabled the verdin-imx8mp_dsi-to-lvds_panel-cap-touch-10inch-lvds_overlay.dtbo, and then I was able to see the MIPI data lines active, but the MIPI clock line shows nothing at all.
Following up on that, I now want to use a custom overlay, but as mentioned have not really much experience with it and do not know what is even needed. Does the Linux need to know that there is a serializer/deserializer in between? Do I really need to specify the display in the end of the chain, or does MIPI just fire-and-forget?
My guess is that I need to specify something instead of the lvds_ti_sn65dsi84 bridge, and then the correct panel (I guess I should already see the pixel clock without this?)

Any help is welcome!
Cheers
Tim

Example .dts:

// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/*
 * Copyright 2023 Toradex
 */

/dts-v1/;
/plugin/;

/ {
	compatible = "toradex,verdin-imx8mp";
};

#include <dt-bindings/gpio/gpio.h>

/* LCDIF to MIPI-DSI */
&lcdif1 {
	status = "okay";
};

&mipi_dsi {
	#address-cells = <1>;
	#size-cells = <0>;
	status = "okay";

	port@1 {
		mipi_dsi_bridge1_out: endpoint {
			attach-bridge;
			remote-endpoint = <&dsi84_in>;
		};
	};
};

&lvds_ti_sn65dsi84 {
	status = "okay";

	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@0 {
			reg = <0>;

			dsi84_in: endpoint {
				remote-endpoint = <&mipi_dsi_bridge1_out>;
				data-lanes = <1 2 3 4>;
			};
		};

		port@2 {
			reg = <2>;

			lvds_out_panel: endpoint {
				remote-endpoint = <&panel_in_lvds>;
			};
		};
	};
};

&panel_lvds {
	compatible = "panel-lvds";
	backlight = <&backlight>;
	data-mapping = "vesa-24";
	height-mm = <136>;
	width-mm = <217>;
	status = "okay";

	panel-timing {
		clock-frequency = <68900000 71100000 73400000>;
		de-active = <1>;
		hactive = <1280 1280 1280>;
		hback-porch = <23 60 71>;
		hfront-porch = <23 60 71>;
		hsync-len = <15 40 47>;
		pixelclk-active = <1>; /* positive edge */
		vactive = <800 800 800>;
		vback-porch = <5 7 10>;
		vfront-porch = <5 7 10>;
		vsync-len = <6 9 12>;
	};

	port {
		panel_in_lvds: endpoint {
			remote-endpoint = <&lvds_out_panel>;
		};
	};
};

Hi, I’m the Toradex AI Assistant. The Toradex Support team will follow up with you shortly!

Did you like my answer?

:+1: :-1:


Hello Tim,

Thank you for reaching out with your question about configuring a display on the Verdin i.MX8MP with TorizonOS. Let’s go through the steps to help you set up your display using Device Tree Overlays.

  1. Device Tree Overlays: These are used to modify the device tree without recompiling the entire kernel, which is ideal for customizing hardware configurations like display interfaces.

  2. Serializer/Deserializer Configuration: Generally, the Linux kernel does not need to be explicitly aware of the serializer/deserializer (DS90UB941AS-Q1 and DS90UB926Q-Q1) unless they require specific configuration or initialization. These components typically act as transparent data conduits. However, ensure any necessary configurations, such as I2C settings, are handled either in the device tree or through user-space utilities.

  3. Custom Overlay Creation: Since you have a custom display setup, creating a custom device tree overlay is necessary. This involves:

    • Defining the MIPI DSI interface in the device tree.
    • Specifying the data lanes and any necessary bridge components.
    • Configuring the final display panel with the correct timings and resolutions.
  4. Display Panel Configuration: Ensure the display panel’s timing parameters (e.g., hsync, vsync, pixel clock) are correctly specified in the device tree. These should match the specifications provided in the display’s datasheet.

  5. Testing the Configuration: After deploying your custom overlay, reboot the system and verify the display output. You can use tools like modetest from the libdrm-tests package to check the display configuration and ensure that the system recognizes the display.

By following these steps, you should be able to configure your display setup on the Verdin i.MX8MP. If you encounter issues, double-check the connections and ensure that all components are correctly configured in the device tree.

I hope this helps you get your display up and running smoothly!

Best regards,
Toradex AI Assistant

Please, also check if these links can help you solve your problem:

Device Tree Overlays (Linux) | Toradex Developer Center.

I’m fairly certain that I only need to specify the MIPI/DSI output and the panel, but I am running into the following error during boot:
imx_sec_dsim_drv: probe of 32e60000.mipi_dsi failed with error -2

torizon@verdin-imx8mp-15337625:~$ dmesg | grep -E 'drm|panel|display|mipi|dsi'
[    0.057607] platform 32e60000.mipi_dsi: Fixed dependency cycle(s) with /soc@0/bus@32c00000/lcd-controller@32e80000
[    0.057630] platform 32e60000.mipi_dsi: Fixed dependency cycle(s) with /soc@0/bus@32c00000/mipi_dsi@32e60000/panel@0
[    0.057898] platform 32e60000.mipi_dsi: Fixed dependency cycle(s) with /soc@0/bus@32c00000/lcd-controller@32e80000
[    0.057970] platform 32e80000.lcd-controller: Fixed dependency cycle(s) with /soc@0/bus@32c00000/mipi_dsi@32e60000
[    2.179091] Kernel module loaded from ramdisk: sec_dsim - result: 0
[    2.184245] Kernel module loaded from ramdisk: display_connector - result: 0
[    2.189936] imx_sec_dsim_drv: probe of 32e60000.mipi_dsi failed with error -2
[    2.190769] Kernel module loaded from ramdisk: sec_mipi_dsim_imx - result: 0
[    2.195576] Kernel module loaded from ramdisk: ti_sn65dsi83 - result: 0
[    4.839343] systemd[1]: Starting Load Kernel Module drm...
[    4.918185] systemd[1]: modprobe@drm.service: Deactivated successfully.
[    4.918762] systemd[1]: Finished Load Kernel Module drm.

This is my current overlay:

// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/*
 * Copyright 2023 Toradex
 */

/dts-v1/;
/plugin/;

/ {
	compatible = "toradex,verdin-imx8mp";
};

#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/clock/imx8mp-clock.h>

&lcdif1 {
	status = "okay";
};

&mipi_dsi {
    status = "okay";
    #address-cells = <1>;
    #size-cells = <0>;

    enable-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_gpio_10_dsi>;
    clock-names = "pix";
    clocks = <&clk IMX8MP_CLK_MEDIA_DISP1_PIX_ROOT>;

    panel@0 {
        compatible = "panel-simple";
        status = "okay";

        panel-timing {
            clock-frequency = <51230769>;
            hactive = <1024>;
            vactive = <600>;
            hsync-len = <10>;
            hfront-porch = <150>;
            hback-porch = <160>;
            vsync-len = <10>;
            vfront-porch = <2>;
            vback-porch = <23>;
            pixelclk-active = <1>;
        };

		ports {
			#address-cells = <1>;
			#size-cells = <0>;

			port@0 {
				reg = <0>;
				panel_in_dsi: endpoint {
					remote-endpoint = <&dsi_out_panel>;
				};
			};
		};

    };
    
    ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@1 {
			reg = <1>;
			dsi_out_panel: endpoint {
				remote-endpoint = <&panel_in_dsi>;
			};
		};
	};
};

Am I missing something? Maybe with the clock/pinctrl?

Following up on this, the previous error was related to some wrong clocks definitions. RIght now I get this error:

torizon@verdin-imx8mp-15337625:~$ dmesg | grep -E 'drm|panel|display|mipi|dsi'
[    0.058759] platform 32e60000.mipi_dsi: Fixed dependency cycle(s) with /soc@0/bus@32c00000/mipi_dsi@32e60000/panel@0
[    2.383380] imx-drm display-subsystem: bound imx-lcdifv3-crtc.0 (ops lcdifv3_crtc_ops)
[    2.391623] [drm] Initialized imx-drm 1.0.0 20120507 for display-subsystem on minor 0
[    2.399499] imx-drm display-subsystem: [drm] Cannot find any crtc or sizes
[    3.520099] Kernel module loaded from ramdisk: sec_dsim - result: 0
[    3.532200] Kernel module loaded from ramdisk: display_connector - result: 0
[    3.545968] Kernel module loaded from ramdisk: sec_mipi_dsim_imx - result: 0
[    3.558623] Kernel module loaded from ramdisk: ti_sn65dsi83 - result: 0
[    7.316756] systemd[1]: Starting Load Kernel Module drm...
[    7.548655] systemd[1]: modprobe@drm.service: Deactivated successfully.
[    7.557703] systemd[1]: Finished Load Kernel Module drm.

so there seems to be some issue still with DRM not recognizing the panel i defined (panel-simple).
When running a weston container for example, the logs mention that no drm device found → but in /dev/dri/ at least I see the cardo (which is from imx-drm)

root@verdin-imx8mp-15337625:/var/rootdirs/home/torizon# cat /sys/kernel/debug/dri/0/name 
imx-drm dev=display-subsystem unique=display-subsystem

My overlay looks like this:

/dts-v1/;
/plugin/;

/ {
    compatible = "toradex,verdin-imx8mp";
};

&lcdif1 {
    status = "okay";
};

&mipi_dsi {
    status = "okay";

    port {
        dsi_out_panel: endpoint {
        remote-endpoint = <&panel_in_dsi>;
        };
    };

    panel@ {
        compatible = "panel-simple";
        status = "okay";
        reg = <0>;

        panel-timing {
            clock-frequency = <30000000>;
            hactive = <800>;
            vactive = <480>;
            hsync-len = <30>;
            hfront-porch = <30>;
            hback-porch = <20>;
            vsync-len = <10>;
            vfront-porch = <10>;
            vback-porch = <5>;
            pixelclk-active = <0>;
        };

        port {
            panel_in_dsi: endpoint {
            remote-endpoint = <&dsi_out_panel>;
            };
        };
    };
};

Maybe a bit closer, but still stuck :face_with_diagonal_mouth:

Hi Tim,

I have some experience in this area, not with ds90ub941 but with sn65dsi86 ( mipi to eDP) interface to a different processor , but similar principles would apply.

Youll need a driver for the FPDLink serialiser IC , check the latest kernel source from kernel.org or ask TI.

In the device tree there needs to be a kind of chain, LCDIF->BRIDGE->FPD link, no LCD panel definition was required just a generic panel
I found the device trees included in the kernel source helped a bit to understand how it works in principle but a fair amount of try and debug was needed.

Hi @chad.au

Thanks for the input!

What I’m wondering now is if I do not need to interact with the bridge via I2C (in the case I can just use it’s defaults), is it enough to specify a generic panel for MIPI? I guess that with the panel-simple driver, this should work? (see the last device tree i posted)
Or where exactly should the generic panel then be defined?

Best regards
Tim

Hi Tim,

If you search the TI support forums for DS90UB941 you’ll see many posts

For the DSI86 there was no need to define the panel at all , the endpoint was a Displayport connector as shown below.

But Displayport has an I2C channel which is used to communicate the EDID paramter set of the display and then the DRM layer has an function that decides what display resolutions are possible based on the MIPI DSI clock system available frequencies and error margin.

The FPD-Link III interface supports full duplex control, including I2C and SPI communication, over the same differential link, so there should be a way to communicate panel parameters over the FPD Link. TI has a newer device DS90UH981-Q1 which has more features for this.

For DS90UB941 since theres no driver you may need to create a panel driver much like a standard MIP-DSI LCD panel driver , there are many examples online.
And then manually configure the DS90UB941 using the I2C port as the TI forum posts describe

&dp_connector{
 compatible = "dp-connector";
 label = "dp0";
 type = "full-size";
 port {
  dp_connector_in: endpoint {
   remote-endpoint = <&edp_bridge_out>;
  };
 };
};

My suggestion here would be similar to what @chad.au has already stated.

I did a quick look and it does seem like there really is no driver for this IC, as stated by TI themselves: DS90UB941AS-Q1: Linux Kernel Driver - Interface forum - Interface - TI E2E support forums

I don’t have any further comments since I’ve never used this IC myself, so my knowledge about it is probably the same as yours. For in-depth questions on this IC you may need to reach out to TI about the specifics of getting it setup.

For our DSI to LVDS overlay you can see everything has driver support in the Linux kernel by default. This makes it relatively simple to define them in the device tree and create the link from mipi dsi → sn65dsi84 bridge → generic LVDS panel.

Best Regards,
Jeremias

Hi @jeremias.tx @chad.au

If I pretend to not have any ser/deser (I do not need to make any configurations there…) in between and I want to add a “dummy” panel to my MIPI output, how would that work?
Similar to how I now have my DT set up?

So the equivalent to the &panel_lvds from the DSI to LVDS overlay, but without the bridge in between.

As far as I understand, that is why this panel-simple exists in the first place, but it is not working for me…

If I pretend to not have any ser/deser (I do not need to make any configurations there…) in between and I want to add a “dummy” panel to my MIPI output, how would that work?
Similar to how I now have my DT set up?

Without having ever worked on it, I’m not really sure how that would work. From an abstraction point of view with a bridge it’s clear how that makes sense. The mipi dsi node outputs dsi signals which the sn65dsi84 bridge accepts and outputs an LVDS signal to the lvds panel driver. In this chain everything gets the expected input it wants.

In your theoretical abstraction we would just have the mipi dsi outputting dsi signal straight to the rgb panel driver, which I imagine the driver would be confused about. Of course on the hardware level you do have the ser/deser in-between. But the software level the system would not know anything about that, since there’s nothing explicit in the device tree to tell it so.

I would need to see if I can find anything on this topic as my knowledge on this is limited.

Best Regards,
Jeremias

Should you be using the panel-simple-dsi syntax?
https://www.kernel.org/doc/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml

If I was tackling this , I would first get the RGB panel connected via a MIPI-DSI to RGB converter to the iMX8 mipi port and get it going, then attempt to add the FPDLink.

You can also decompile the Device tree Binary using the device tree compiler to check if it has all the elements needed. I found dtc can exclude elements from overlays without warning if your syntax isn’t 100% compliant, maybe theres a way to make it generate warnings.

With

&mipi_dsi {
    status = "okay";
    panel@0 {
        compatible = "lg,lh500wx1-sd03";
        reg = <0>;
    };
};

we were able to get a MIPI DSI output, so Linux recognized it as a DSI panel. The relevant settings are in a panel_desc_dsi struct in panel-simple.c. However, there are only certain panels defined and we obv. can’t overwrite the parameters there with overlays, I guess the only way is to then make a patch and a custom yocto build, which we would like to avoid… (we use torizoncore builder).
Or do you see any other way to add our settings into the driver?
Basically any of these (also from panel-simple.c):

static const struct of_device_id dsi_of_match[] = {
	{
		.compatible = "auo,b080uan01",
		.data = &auo_b080uan01
	}, {
		.compatible = "boe,tv080wum-nl0",
		.data = &boe_tv080wum_nl0
	}, {
		.compatible = "lg,ld070wx3-sl01",
		.data = &lg_ld070wx3_sl01
	}, {
		.compatible = "lg,lh500wx1-sd03",
		.data = &lg_lh500wx1_sd03
	}, {
		.compatible = "panasonic,vvx10f004b00",
		.data = &panasonic_vvx10f004b00
	}, {
		.compatible = "lg,acx467akm-7",
		.data = &lg_acx467akm_7
	}, {
		.compatible = "osddisplays,osd101t2045-53ts",
		.data = &osd101t2045_53ts
	}, {
		/* sentinel */
	}
};

Or do you see any other way to add our settings into the driver?

Well the DSI panel abstraction doesn’t have a generic compatible since DSI displays aren’t really generic in their design and usually require their own specific logic/driver to operate. As opposed to lvds and rgb panels which have the panel-lvds and panel-dpi compatibles respectively that allow you to provide generic display timing values.

I discussed this use-case a bit internally and some comments. We couldn’t find any past cases similar to this, so some experimentation is definitely needed here. Our best educated guess here would be to create a separate panel node that defines your display timings like this for example: display-rvt101hvdwc00b_overlay.dtsi « overlays - device-tree-overlays.git - Sources for Device Tree Overlays

Then connect this node directly to the mipi_dsi node via the port endpoint properties. That said we’re not entirely sure if any panel type node can be connected directly to the mipi_dsi node even if the panel does not describe a dsi panel. This is all assuming of course the hardware side of things is properly configured and setup.

One other note, you mentioned you do at least get DSI output on the hardware side. In Linux with any of your device tree configurations are there any logs coming from the DSI/display subsystems in dmesg? Maybe there’s a hint there.

Best Regards,
Jeremias

In most cases I have seen the best way is to create your own panel driver in /drivers/gpu/drm/panel and add it to the makefile and Kconfig so that you can select it when doing a kernel configuration using menuconfig.

You would then add it to the device tree using for example compatible = “leadtek,ltk050h3123w-qc03”;
The who dsi definition would look something like this - maybe slightly different for IMX8:

&dsi {
	#address-cells = <1>;
	#size-cells = <0>;
	status = "okay";

	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@0 {
			reg = <0>;
			dsi_in: endpoint {
				remote-endpoint = <&ltdc_ep0_out>;
			};
		};

		port@1 {
			reg = <1>;
			dsi_out:endpoint{
				remote-endpoint = <&dsi_panel_in>;
			};
		};
	};

	panel_dsi:panel-dsi@0{
		compatible = "leadtek,ltk050h3123w-qc03";
		reg = <0>;
		reset-gpios = <&gpiob 14 GPIO_ACTIVE_LOW>;
		backlight = <&lcd_backlight>;
/*		power-supply = <&v3v3>; */
		status = "okay";
		port{
			dsi_panel_in:endpoint{
				remote-endpoint = <&dsi_out>;
			};
		};
	};
};

I have the following output (with the panel described as my comment above):

torizon@verdin-imx8mp-15337625:~$ dmesg | grep -E 'drm|dsi|mipi|panel'
[    0.059473] platform 32e60000.mipi_dsi: Fixed dependency cycle(s) with /soc@0/bus@32c00000/lcd-controller@32e80000
[    0.059723] platform 32e60000.mipi_dsi: Fixed dependency cycle(s) with /soc@0/bus@32c00000/lcd-controller@32e80000
[    0.059820] platform 32e80000.lcd-controller: Fixed dependency cycle(s) with /soc@0/bus@32c00000/mipi_dsi@32e60000
[    4.221642] Kernel module loaded from ramdisk: sec_dsim - result: 0
[    4.246999] imx-drm display-subsystem: bound imx-lcdifv3-crtc.0 (ops lcdifv3_crtc_ops)
[    4.255064] imx_sec_dsim_drv 32e60000.mipi_dsi: version number is 0x1060200
[    4.262664] imx-drm display-subsystem: bound 32e60000.mipi_dsi (ops imx_sec_dsim_ops [sec_mipi_dsim_imx])
[    4.272885] [drm] Initialized imx-drm 1.0.0 20120507 for display-subsystem on minor 0
[    4.283162] imx-drm display-subsystem: [drm] fb0: imx-drmdrmfb frame buffer device
[    4.360998] Kernel module loaded from ramdisk: sec_mipi_dsim_imx - result: 0
[    4.372724] Kernel module loaded from ramdisk: ti_sn65dsi83 - result: 0
[    7.537621] systemd[1]: Starting Load Kernel Module drm...
[    7.798847] [drm] Initialized vivante 1.0.0 20170808 for 40000000.mix_gpu_ml on minor 1

and on the hardware end, we can see the clock and data. But of course now the settings are the ones from "lg,lh500wx1-sd03" (in panel-simple.c)
I think the dmesg output looks quite ok, but as mentioned, without having to touch the kernel driver itself (and therefore ditching TorizonCore builder etc.), we can’t set our own panel settings.

and on the hardware end, we can see the clock and data. But of course now the settings are the ones from "lg,lh500wx1-sd03" (in panel-simple.c)

My question here, and I’m not entirely sure myself. In the device tree if you specify timings for a DSI panel. When the signal goes through the serializer/deserializer hardware, would the timing signals be correct for your RGB display at the end?

This is assuming you have the settings/timings for your display.

I think the dmesg output looks quite ok, but as mentioned, without having to touch the kernel driver itself (and therefore ditching TorizonCore builder etc.), we can’t set our own panel settings.

Well in theory, you could create a separate new out-of-tree driver for your display settings and that would work with TorizonCore Builder. Though creating such a standalone driver is arguably more complex than just modifying the already existing driver code. Again though this is usually the case when defining new DSI panel timings in Linux.

I’m still curious if it’s possible to connect a RGB/LVDS panel in the device tree to the mipi_dsi node and have that work. Since RGB/LVDS panels allow one to specify custom display timings unlike the DSI panel abstraction.

Best Regards,
Jeremias