Re: [PATCH v2 12/21] drm/panel: jadard-jd9365da-h3: support variable DSI configuration

Jie Gan
2026-04-12T00:56:05Z

On 4/11/2026 8:10 PM, Dmitry Baryshkov wrote:
> Several panels support attachment either using 4 DSI lanes or just 2. In
> some cases, this requires a different panel mode to fulfill clock
> requirements. Extend the driver to handle such cases by letting the
> panel description to omit lanes specification and parsing number of
> lanes from the DT.
>
> Reviewed-by: Linus Walleij <linusw@kernel.org>
> Tested-by: Riccardo Mereu <r.mereu@arduino.cc>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
> drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c | 32 +++++++++++++++++-------
> 1 file changed, 23 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
> index 1884ad2404cd..5d9db2e1f28f 100644
> --- a/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
> +++ b/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
> @@ -10,6 +10,7 @@
>
> #include <drm/drm_mipi_dsi.h>
> #include <drm/drm_modes.h>
> +#include <drm/drm_of.h>
> #include <drm/drm_panel.h>
> #include <drm/drm_print.h>
> #include <drm/drm_probe_helper.h>
> @@ -23,7 +24,8 @@
> struct jadard;
>
> struct jadard_panel_desc {
> - const struct drm_display_mode mode;
> + const struct drm_display_mode *mode_4ln;
> + const struct drm_display_mode *mode_2ln;
> unsigned int lanes;
> enum mipi_dsi_pixel_format format;
> int (*init)(struct jadard *jadard);
> @@ -57,7 +59,10 @@ static void jadard_enable_standard_cmds(struct mipi_dsi_multi_context *dsi_ctx)
> mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe1, 0x93);
> mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe2, 0x65);
> mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe3, 0xf8);
> - mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x80, 0x03);
> + if (dsi_ctx->dsi->lanes == 2)
> + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x80, 0x01);
> + else
> + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x80, 0x03);
> }
>
> static inline struct jadard *panel_to_jadard(struct drm_panel *panel)
> @@ -151,7 +156,10 @@ static int jadard_get_modes(struct drm_panel *panel,
> {
> struct jadard *jadard = panel_to_jadard(panel);
>
> - return drm_connector_helper_get_modes_fixed(connector, &jadard->desc->mode);
> + if (jadard->dsi->lanes == 2)

Worth to add a check here:
if (jadard->dsi->lanes == 2 && jadard->desc->mode_2ln)

Some pre-existing panel desc(e.g. radxa_display_8hd_ad002_desc) only set
mode_4ln, leaving mode_2ln = NULL. So if such a panel attaches to a
2-lane DSI host, the NULL pointer dereference causes a kernel oops.

Thanks,
Jie

> + return drm_connector_helper_get_modes_fixed(connector, jadard->desc->mode_2ln);
> + else
> + return drm_connector_helper_get_modes_fixed(connector, jadard->desc->mode_4ln);
> }
>
> static enum drm_panel_orientation jadard_panel_get_orientation(struct drm_panel *panel)
> @@ -354,7 +362,7 @@ static int radxa_display_8hd_ad002_init_cmds(struct jadard *jadard)
> };
>
> static const struct jadard_panel_desc radxa_display_8hd_ad002_desc = {
> - .mode = {
> + .mode_4ln = &(const struct drm_display_mode) {
> .clock = 70000,
>
> .hdisplay = 800,
> @@ -586,7 +594,7 @@ static int cz101b4001_init_cmds(struct jadard *jadard)
> };
>
> static const struct jadard_panel_desc cz101b4001_desc = {
> - .mode = {
> + .mode_4ln = &(const struct drm_display_mode) {
> .clock = 70000,
>
> .hdisplay = 800,
> @@ -819,7 +827,7 @@ static int kingdisplay_kd101ne3_init_cmds(struct jadard *jadard)
> };
>
> static const struct jadard_panel_desc kingdisplay_kd101ne3_40ti_desc = {
> - .mode = {
> + .mode_4ln = &(const struct drm_display_mode) {
> .clock = (800 + 24 + 24 + 24) * (1280 + 30 + 4 + 8) * 60 / 1000,
>
> .hdisplay = 800,
> @@ -1070,7 +1078,7 @@ static int melfas_lmfbx101117480_init_cmds(struct jadard *jadard)
> };
>
> static const struct jadard_panel_desc melfas_lmfbx101117480_desc = {
> - .mode = {
> + .mode_4ln = &(const struct drm_display_mode) {
> .clock = (800 + 24 + 24 + 24) * (1280 + 30 + 4 + 8) * 60 / 1000,
>
> .hdisplay = 800,
> @@ -1326,7 +1334,7 @@ static int anbernic_rgds_init_cmds(struct jadard *jadard)
> };
>
> static const struct jadard_panel_desc anbernic_rgds_display_desc = {
> - .mode = {
> + .mode_4ln = &(const struct drm_display_mode) {
> .clock = (640 + 260 + 220 + 260) * (480 + 10 + 2 + 16) * 60 / 1000,
>
> .hdisplay = 640,
> @@ -1562,7 +1570,7 @@ static int taiguan_xti05101_01a_init_cmds(struct jadard *jadard)
> };
>
> static const struct jadard_panel_desc taiguan_xti05101_01a_desc = {
> - .mode = {
> + .mode_4ln = &(const struct drm_display_mode) {
> .clock = (800 + 24 + 24 + 24) * (1280 + 30 + 4 + 8) * 60 / 1000,
>
> .hdisplay = 800,
> @@ -1614,6 +1622,12 @@ static int jadard_dsi_probe(struct mipi_dsi_device *dsi)
>
> dsi->format = desc->format;
> dsi->lanes = desc->lanes;
> + if (!dsi->lanes) {
> + dsi->lanes = drm_of_get_data_lanes_count_remote(dsi->dev.of_node, 0, -1, 2, 4);
> + if (dsi->lanes < 0)
> + return dsi->lanes;
> + }
> + dev_dbg(&dsi->dev, "lanes: %d\n", dsi->lanes);
>
> jadard->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
> if (IS_ERR(jadard->reset))
>