iMX8MM and panel driver Himax8279D: imx_sec_dsim_drv: wait pkthdr tx done time out

Hello,

I want to connect the display SL101PM1794FOG-V15 (1920x1200) to the MIPI-DSI of a Verdin iMX8MM that runs with BSP6.0. This panel has the HX8279D as drive IC.

Therefore I activated the related driver in the kernel ( CONFIG_DRM_PANEL_BOE_HIMAX8279D) and made the following device tree overlay:

/dts-v1/;
/plugin/;

#include <dt-bindings/gpio/gpio.h>
#include "imx8mm-pinfunc.h"

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

&backlight {
	enable-gpios = <&gpio3 3 GPIO_ACTIVE_HIGH>;	// Verdin GPIO_10_DSI (SODIMM 21)
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_gpio_10_dsi>;

	status = "okay";
};

&gpu {
	status = "okay";
};

&lcdif {
	status = "okay";
};

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

	port@1 {
		mipi_dsi_panel1_out: endpoint {
			remote-endpoint = <&panel1_in>;
		};
	};

	panel@0 {
		compatible = "boe,himax8279d8p", "boe,himax8279d10p";
		reg = <0>;
		
		backlight = <&backlight>;

		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_panel_gpios>;
		enable-gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>;	// I2S_2_BCLK (SODIMM 42)
		pp18-gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>;		// I2S_2_SYNC (SODIMM 44)
		pp33-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>;		// I2S_2_D_OUT (SODIMM 46)

		// Alternatives Panel-Timing
		panel-timing {
			// 1920x1200p60
			clock-frequency = <159400000>;	// Panel clock/Pixel rate [Hz]

			hactive = <1200>;				// Horizontal panel resolution [px]
			hback-porch = <32 60 60>;		// Horizontal back porch timing
			hfront-porch = <42 80 81>;		// Horizontal front porch panel timing
			hsync-len = <1>;				// Horizontal sync length panel timing

			vactive = <1920>;				// Vertical panel resolution [px]
			vback-porch = <25>;				// Vertical back porch panel timing
			vfront-porch = <35 35 36>;		// Vertical front porch panel timing
			vsync-len = <1>;				// Vertical sync length panel timing

			//hsync-active = <1>;				// Horizontal sync pulse (0 selects active low, 1 selects active high) 	- If omitted then it is not used by the hardware
			//vsync-active = <1>;				// Vertical sync pulse (0 selects active low, 1 selects active high) 	- If omitted then it is not used by the hardware
			//de-active = <1>;				// Data enable (0 selects active low, 1 selects active high) 			- If omitted then it is not used by the hardware
			//pixelclk-active = <1>;			// Data driving on rising or falling edge
											//	0 to drive pixel data on falling edge and sample data on rising edge
											//	1 to drive pixel data on rising edge and sample data on falling edge
		};

		port {
        	panel1_in: endpoint {
				remote-endpoint = <&mipi_dsi_panel1_out>;
			};
		};
	};
};

&iomuxc {
	pinctrl_panel_gpios: panelgpiosgrp {
		fsl,pins = <
			MX8MM_IOMUXC_SAI5_RXD2_GPIO3_IO23		0x146	/* SODIMM 42 - reset of display (pulled-up as active-low) */
			MX8MM_IOMUXC_SAI5_RXD1_GPIO3_IO22		0x106	/* SODIMM 44 - enable of 1P8 (pulled-down as active-high) */
			MX8MM_IOMUXC_SAI5_RXD3_GPIO3_IO24		0x106	/* SODIMM 46 - enable of 3P3 (pulled-down as active-high) */
		>;
	};
};

During boot the software driver tries to send the startup commands to the panel driver (line 160 of drivers/gpu/drm/panel/panel-boe-himax8279d.c), but get a -EBUSY because of a tx timeout in line 719 of drivers/gpu/drm/bridge/sec-dsim.c:

[    8.152313] imx_sec_dsim_drv 32e10000.mipi_dsi: wait pkthdr tx done time out
[    8.152335] panel-boe-himax8279d 32e10000.mipi_dsi.0: failed to send DCS Init Code: -16
[    8.152347] imx_sec_dsim_drv 32e10000.mipi_dsi: panel prepare failed: -16

The output of dmesg: dmesg.log (39.4 KB)

I found this thread where it is pointed out that the use of mipi_dsi_dcs_write_buffer()instead of mipi_dsi_generic_write() in the prepare function can be the cause. I patched the driver source file with

diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c
index 42854bd37fd5..abb96e548349 100644
--- a/drivers/gpu/drm/panel/panel-boe-himax8279d.c
+++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c
@@ -72,7 +72,7 @@ static int send_mipi_cmds(struct drm_panel *panel, const struct panel_cmd *cmds)
 	int err;
 
 	for (i = 0; i < pinfo->desc->on_cmds_num; i++) {
-		err = mipi_dsi_dcs_write_buffer(pinfo->link, &cmds[i],
+		err = mipi_dsi_generic_write(pinfo->link, &cmds[i],
 						sizeof(struct panel_cmd));
 
 		if (err < 0)

but I get the same error.
Can someone please give me an advice how to solve this problem?

Best regards,
Markus

Hi @Mowlwurf

If I remember correctly when investigating another MIPI-DSI driver issue this is because of the wait_complete in the prepare function. It seems that the NXP driver somehow has interrupts disabled there. So one way of fixing this is to move everything to the enable function.

Here is a quick example. I didn’t test it and it is dirty but it would be interesting to see if it fixes the issue you see:

diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c
index 42854bd37fd5..5401cd5f6cd1 100644
--- a/drivers/gpu/drm/panel/panel-boe-himax8279d.c
+++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c
@@ -135,6 +135,20 @@ static int boe_panel_prepare(struct drm_panel *panel)
 	if (pinfo->prepared)
 		return 0;
 
+
+	pinfo->prepared = true;
+
+	return 0;
+}
+
+static int boe_panel_enable(struct drm_panel *panel)
+{
+	struct panel_info *pinfo = to_panel_info(panel);
+	int ret;
+
+	if (pinfo->enabled)
+		return 0;
+
 	gpiod_set_value(pinfo->pp18_gpio, 1);
 	/* T1: 5ms - 6ms */
 	usleep_range(5000, 6000);
@@ -160,44 +174,15 @@ static int boe_panel_prepare(struct drm_panel *panel)
 	err = send_mipi_cmds(panel, pinfo->desc->on_cmds);
 	if (err < 0) {
 		dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err);
-		goto poweroff;
+		return err;
 	}
 
 	err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link);
 	if (err < 0) {
 		dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
-		goto poweroff;
-	}
-
-	/* T6: 120ms - 121ms */
-	usleep_range(120000, 121000);
-
-	err = mipi_dsi_dcs_set_display_on(pinfo->link);
-	if (err < 0) {
-		dev_err(panel->dev, "failed to set display on: %d\n", err);
-		goto poweroff;
+		return err;
 	}
 
-	/* T7: 20ms - 21ms */
-	usleep_range(20000, 21000);
-
-	pinfo->prepared = true;
-
-	return 0;
-
-poweroff:
-	disable_gpios(pinfo);
-	return err;
-}
-
-static int boe_panel_enable(struct drm_panel *panel)
-{
-	struct panel_info *pinfo = to_panel_info(panel);
-	int ret;
-
-	if (pinfo->enabled)
-		return 0;
-
 	usleep_range(120000, 121000);
 
 	ret = mipi_dsi_dcs_set_display_on(pinfo->link);

I just moved everything that is part of the prepare function to the enable function. I also moved the other parts because there is a sleep in there and if interrupts are disabled it might happen that the system slows down during boot. However, that wouldn’t be necessary.

I hope this changes something.

Regards,
Stefan

Hi @stefan_e.tx,

thanks for your help. I had to modify the patch a bit to compile the kernel:

diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c
index 42854bd37fd5..8a017fc144a9 100644
--- a/drivers/gpu/drm/panel/panel-boe-himax8279d.c
+++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c
@@ -130,11 +130,23 @@ static int boe_panel_unprepare(struct drm_panel *panel)
 static int boe_panel_prepare(struct drm_panel *panel)
 {
 	struct panel_info *pinfo = to_panel_info(panel);
-	int err;
 
 	if (pinfo->prepared)
 		return 0;
 
+	pinfo->prepared = true;
+
+	return 0;
+}
+
+static int boe_panel_enable(struct drm_panel *panel)
+{
+	struct panel_info *pinfo = to_panel_info(panel);
+	int err;
+
+	if (pinfo->enabled)
+		return 0;
+
 	gpiod_set_value(pinfo->pp18_gpio, 1);
 	/* T1: 5ms - 6ms */
 	usleep_range(5000, 6000);
@@ -160,50 +172,21 @@ static int boe_panel_prepare(struct drm_panel *panel)
 	err = send_mipi_cmds(panel, pinfo->desc->on_cmds);
 	if (err < 0) {
 		dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err);
-		goto poweroff;
+		return err;
 	}
 
 	err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link);
 	if (err < 0) {
 		dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
-		goto poweroff;
+		return err;
 	}
 
-	/* T6: 120ms - 121ms */
 	usleep_range(120000, 121000);
 
 	err = mipi_dsi_dcs_set_display_on(pinfo->link);
 	if (err < 0) {
 		dev_err(panel->dev, "failed to set display on: %d\n", err);
-		goto poweroff;
-	}
-
-	/* T7: 20ms - 21ms */
-	usleep_range(20000, 21000);
-
-	pinfo->prepared = true;
-
-	return 0;
-
-poweroff:
-	disable_gpios(pinfo);
-	return err;
-}
-
-static int boe_panel_enable(struct drm_panel *panel)
-{
-	struct panel_info *pinfo = to_panel_info(panel);
-	int ret;
-
-	if (pinfo->enabled)
-		return 0;
-
-	usleep_range(120000, 121000);
-
-	ret = mipi_dsi_dcs_set_display_on(pinfo->link);
-	if (ret < 0) {
-		dev_err(panel->dev, "failed to set display on: %d\n", ret);
-		return ret;
+		return err;
 	}
 
 	pinfo->enabled = true;

Now the driver works without errors.

In the mean time it turns out, that the manufacturer of the panel has preinitialized the driver IC so I can use the simple-panel driver with the following patch instead :sunglasses::

diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
index fbd71669248f..a14b97ec0e6c 100644
--- a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
+++ b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
@@ -29,6 +29,8 @@ properties:
       # compatible must be listed in alphabetical order, ordered by compatible.
       # The description in the comment is mandatory for each compatible.
 
+        # Shenzhen AOLY Technology Co. 10.1" WUXGA TFT LCD panel
+      - aoly,SL101PM1794FOG-V15
         # AU Optronics Corporation 8.0" WUXGA TFT LCD panel
       - auo,b080uan01
         # Boe Corporation 8.0" WUXGA TFT LCD panel
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index c161d23179e8..5e15a091cd4b 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -5015,6 +5015,35 @@ struct panel_desc_dsi {
 	unsigned int lanes;
 };
 
+static const struct drm_display_mode aoly_sl101pm1794fog_v15_mode = {
+	.clock = 159420,
+	.hdisplay = 1200,
+	.hsync_start = 1200 + 80,
+	.hsync_end = 1200 + 80 + 60,
+	.htotal = 1200 + 80 + 60 + 24,
+	.vdisplay = 1920,
+	.vsync_start = 1920 + 10,
+	.vsync_end = 1920 + 10 + 14,
+	.vtotal = 1920 + 10 + 14 + 4,
+};
+
+static const struct panel_desc_dsi aoly_sl101pm1794fog_v15 = {
+	.desc = {
+		.modes = &aoly_sl101pm1794fog_v15_mode,
+		.num_modes = 1,
+		.bpc = 8,
+		.size = {
+			.width = 136,
+			.height = 217,
+		},
+		.connector_type = DRM_MODE_CONNECTOR_DSI,
+	},
+	.flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+			MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
+	.format = MIPI_DSI_FMT_RGB888,
+	.lanes = 4,
+};
+
 static const struct drm_display_mode auo_b080uan01_mode = {
 	.clock = 154500,
 	.hdisplay = 1200,
@@ -5219,6 +5248,9 @@ static const struct panel_desc_dsi osd101t2045_53ts = {
 
 static const struct of_device_id dsi_of_match[] = {
 	{
+		.compatible = "aoly,SL101PM1794FOG-V15",
+		.data = &aoly_sl101pm1794fog_v15
+	}, {
 		.compatible = "auo,b080uan01",
 		.data = &auo_b080uan01
 	}, {

Best regards,
Markus

Hi @Mowlwurf

Excellent, thanks a lot for the update and the information about the simple-panel driver. It’s good to know that there are MIPI displays out there that work with this.

Regards
Stefan