Porting MIPI-DSI drivers to newer versions of Linux

MIPI-DSI is a display interface for, especially embedded, display panels, commonly used on embedded hardware.
These display panels generally need different initialization code, and depending on hardware also different power management code. As such Linux has code to support a wide variety of drivers for various DSI display panels.

In some cases, however, you may encounter a DSI display panel where the only Linux driver is for an older version of Linux. The Linux kernel is known for having an unstable driver interface, so these drivers just no longer work with newer versions of Linux.

This post will describe the changes you need to perform to allow your driver to be compatible with newer versions of Linux, based on a simplified version of the “clockworkpi”[1] CWD686 panel that I have recently ported fromn 5.10 to 6.6.

The original

static int cwd686_probe(struct mipi_dsi_device *dsi)
{
	struct device *dev = &dsi->dev;
	struct cwd686 *ctx;
	int ret;

    /* [snip…] */
	
	drm_panel_init(&ctx->panel, dev, &cwd686_drm_funcs, DRM_MODE_CONNECTOR_DSI);

	drm_panel_add(&ctx->panel);

	ret = mipi_dsi_attach(dsi);
	if (ret < 0) {
		dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret);
		return ret;
	}

	return 0;
}

static int cwd686_remove(struct mipi_dsi_device *dsi)
{
	struct cwd686 *ctx = mipi_dsi_get_drvdata(dsi);

	mipi_dsi_detach(dsi);
	drm_panel_remove(&ctx->panel);

    return 0;
}

Issue 1: cwd686_remove has the incorrect type

This is very simple to fix. Linux changed the return type of the mipi_dsi_driver remove function to not return a status code.

Simply change the int return type to void, and then remove the return values in the function

static void cwd686_remove(struct mipi_dsi_device *dsi)
{
	struct cwd686 *ctx = mipi_dsi_get_drvdata(dsi);

	mipi_dsi_detach(dsi);
	drm_panel_remove(&ctx->panel);
}

Issue 2: the panel fails to initialize with error code -517 and it doesn’t retry

This is a bug in the code. Error code -517 is EPROBE_DEFER, which is the error returned when a driver is not yet ready for initialization. In the case the mipi_dsi driver is not initialized yet, you need to remove the drm panel:

static int cwd686_probe(struct mipi_dsi_device *dsi)
{
	struct device *dev = &dsi->dev;
	struct cwd686 *ctx;
	int ret;

    /* [snip…] */
	
	drm_panel_init(&ctx->panel, dev, &cwd686_drm_funcs, DRM_MODE_CONNECTOR_DSI);

	drm_panel_add(&ctx->panel);

	ret = mipi_dsi_attach(dsi);
	if (ret < 0) {
		dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret);
        drm_panel_remove(&ctx->panel);
		return ret;
	}

	return 0;
}

Issue 3: The panel fails to initialize with error code -110

I encountered this on the RPi Compute Module 4. This can have a variety of issues, but in this case it was because the MIPI-DSI hardware was not fully initialized when the panel is enabled.

This is a change that was seemingly done in 5.15 and you now need to include this line:

ctx->panel.prepare_prev_first = true;

before the drm_panel_add(&ctx->panel); call in the probe function:

static int cwd686_probe(struct mipi_dsi_device *dsi)
{
	struct device *dev = &dsi->dev;
	struct cwd686 *ctx;
	int ret;

    /* [snip…] */
	
	drm_panel_init(&ctx->panel, dev, &cwd686_drm_funcs, DRM_MODE_CONNECTOR_DSI);

    ctx->panel.prepare_prev_first = true;
	drm_panel_add(&ctx->panel);

	ret = mipi_dsi_attach(dsi);
	if (ret < 0) {
		dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret);
        drm_panel_remove(&ctx->panel);
		return ret;
	}

	return 0;
}

Issue 4: Undefined reference to prepare_upstream_first in the prepare function

The kernel renamed this property to prepare_prev_first. Simply change the name.

Conclusion

At this point my LCD panel driver started working on Linux 6.6. I hope this article also helped you with yours as well.

The compilation errors ought to be relatively simple to figure out, but the prepare_prev_first change took me over a day of googling and debugging to figure out. I didn’t run into issue 3 myself, as the vendor driver already didn’t have this issue, but I have seen it mentioned on the raspberry pi forums.

It would be great if Linux had a stable driver API, but unfortunately the reality is that the project does not care about downstream drivers while also making the upstreaming process complex and annoying.


  1. 1.The panel is of unknown provenance, but only clockworkpi sells it.