Re: [PATCH v3 2/2] drm: panel: add support for the Renesas R63419 based dual-DSI video mode Display Panels

From: Dmitry Baryshkov

Date: Wed May 13 2026 - 10:46:28 EST


On Mon, May 04, 2026 at 10:02:06AM +0200, Neil Armstrong wrote:
> From: KancyJoe <kancy2333@xxxxxxxxxxx>
>
> Implement support for the Renesas 63419 based dual-DSI video mode
> Display Panels found in the Ayaneo gaming handled devices.
>
> Signed-off-by: KancyJoe <kancy2333@xxxxxxxxxxx>
> Signed-off-by: Neil Armstrong <neil.armstrong@xxxxxxxxxx>
> ---
> drivers/gpu/drm/panel/Kconfig | 12 +
> drivers/gpu/drm/panel/Makefile | 1 +
> drivers/gpu/drm/panel/panel-renesas-r63419.c | 357 +++++++++++++++++++++++++++
> 3 files changed, 370 insertions(+)
>
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index d6863b28ddc5..5404d918677f 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -755,6 +755,18 @@ config DRM_PANEL_RENESAS_R61307
> This panel controller can be found in LG Optimus Vu P895 smartphone
> in combination with LCD panel.
>
> +config DRM_PANEL_RENESAS_R63419
> + tristate "Renesas R63419 dual-DSI video mode panels"
> + depends on OF && GPIOLIB
> + depends on DRM_MIPI_DSI
> + depends on BACKLIGHT_CLASS_DEVICE
> + help
> + Say Y here if you want to enable support for Ayaneo WT0600 and WT0630
> + 1440x2560 60Hz dual-DSI video mode display panels with Renesas
> + R63419 IC.
> +
> + These panels are used in Ayaneo handheld gaming devices.
> +
> config DRM_PANEL_RENESAS_R69328
> tristate "Renesas R69328 720x1280 DSI video mode panel"
> depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index a4291dc3905b..b498ee9b5929 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -75,6 +75,7 @@ obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o
> obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM692E5) += panel-raydium-rm692e5.o
> obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM69380) += panel-raydium-rm69380.o
> obj-$(CONFIG_DRM_PANEL_RENESAS_R61307) += panel-renesas-r61307.o
> +obj-$(CONFIG_DRM_PANEL_RENESAS_R63419) += panel-renesas-r63419.o
> obj-$(CONFIG_DRM_PANEL_RENESAS_R69328) += panel-renesas-r69328.o
> obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o
> obj-$(CONFIG_DRM_PANEL_SAMSUNG_AMS581VF01) += panel-samsung-ams581vf01.o
> diff --git a/drivers/gpu/drm/panel/panel-renesas-r63419.c b/drivers/gpu/drm/panel/panel-renesas-r63419.c
> new file mode 100644
> index 000000000000..2432a238cef1
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-renesas-r63419.c
> @@ -0,0 +1,357 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * DRM driver for Renesas R63419 based dual-DSI video mode panels
> + *
> + * Copyright (c) 2025, Kancy Joe <kancy2333@xxxxxxxxxxx>
> + * Copyright (C) 2026 Linaro Limited
> + * Author: Neil Armstrong <neil.armstrong@xxxxxxxxxx>
> + */
> +
> +#include <linux/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_graph.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <video/mipi_display.h>
> +
> +#include <drm/drm_connector.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_modes.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_probe_helper.h>
> +
> +struct renesas_r63419_panel {
> + struct drm_panel panel;
> + struct mipi_dsi_device *dsi[2];
> + const struct panel_desc *desc;
> +
> + struct gpio_desc *reset_gpio;
> + struct regulator_bulk_data *vdd_supplies;
> + struct regulator_bulk_data *vcc_supplies;
> + enum drm_panel_orientation orientation;
> +};
> +
> +/* VDDIO/VDD Supplies */
> +static const struct regulator_bulk_data renesas_r63419_vdd_supplies[] = {
> + { .supply = "vddio" },
> + { .supply = "vdd" },
> +};
> +
> +/* VSP/VSN/VCI Supplies */
> +static const struct regulator_bulk_data renesas_r63419_vcc_supplies[] = {
> + { .supply = "vsp" },
> + { .supply = "vsn" },
> + { .supply = "vci" },
> +};
> +
> +struct panel_desc {
> + const struct drm_display_mode *mode;
> + unsigned int lanes;
> + unsigned long mode_flags;
> + enum mipi_dsi_pixel_format format;
> + u16 height_mm;
> + u16 width_mm;

Drop, use those from the drm_display_mode.

> + const struct mipi_dsi_device_info dsi_info;
> +};
> +
> +static const struct drm_display_mode wt0600_mode = {
> + /* Dual dsi */
> + .clock = 2 * (720 + 100 + 8 + 40) * (2560 + 15 + 2 + 8) * 60 / 1000,
> + .hdisplay = 2 * 720,
> + .hsync_start = 2 * (720 + 100),
> + .hsync_end = 2 * (720 + 100 + 8),
> + .htotal = 2 * (720 + 100 + 8 + 40),
> + .vdisplay = 2560,
> + .vsync_start = 2560 + 15,
> + .vsync_end = 2560 + 15 + 2,
> + .vtotal = 2560 + 15 + 2 + 8,
> + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> +};
> +
> +static struct panel_desc wt0600_desc = {
> + .lanes = 4,
> + .width_mm = 74,
> + .height_mm = 131,
> + .mode = &wt0600_mode,
> + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
> + MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
> + .format = MIPI_DSI_FMT_RGB888,
> + .dsi_info = {
> + .type = "wt0600-2k",
> + .channel = 0,
> + .node = NULL,
> + },

I'd store just the name here and create dsi_info on stack.

> +};
> +
> +static struct panel_desc wt0630_desc = {
> + .lanes = 4,
> + .width_mm = 78,
> + .height_mm = 140,
> + .mode = &wt0600_mode, /* wt0600 only has different screen size */
> + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
> + MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
> + .format = MIPI_DSI_FMT_RGB888,
> + .dsi_info = {
> + .type = "wt0630-2k",
> + .channel = 0,
> + .node = NULL,
> + },
> +};
> +

[...]

> +static int renesas_r63419_get_modes(struct drm_panel *panel,
> + struct drm_connector *connector)
> +{
> + struct drm_display_mode *mode;
> + struct renesas_r63419_panel *ctx = to_renesas_r63419_panel(panel);
> +
> + mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
> + if (!mode)
> + return -ENOMEM;
> +
> + /* Update panel size */
> + mode->width_mm = ctx->desc->width_mm;
> + mode->height_mm = ctx->desc->height_mm;
> +
> + drm_mode_set_name(mode);
> + connector->display_info.width_mm = mode->width_mm;
> + connector->display_info.height_mm = mode->height_mm;
> + drm_mode_probed_add(connector, mode);

return drm_connector_helper_get_modes_fixed().

> +
> + return 1;
> +}
> +
> +static enum drm_panel_orientation
> +renesas_r63419_get_orientation(struct drm_panel *panel)
> +{
> + struct renesas_r63419_panel *ctx = to_renesas_r63419_panel(panel);
> +
> + return ctx->orientation;
> +}
> +
> +static const struct drm_panel_funcs renesas_r63419_panel_funcs = {
> + .disable = renesas_r63419_disable,
> + .prepare = renesas_r63419_prepare,
> + .unprepare = renesas_r63419_unprepare,
> + .get_modes = renesas_r63419_get_modes,
> + .get_orientation = renesas_r63419_get_orientation,
> +};
> +
> +static int renesas_r63419_probe(struct mipi_dsi_device *dsi)
> +{
> + struct device *dev = &dsi->dev;
> + struct renesas_r63419_panel *ctx;
> + struct device_node *dsi1_node;
> + struct mipi_dsi_host *dsi1_host;
> + int ret, i;
> +
> + ctx = devm_drm_panel_alloc(dev, struct renesas_r63419_panel, panel,
> + &renesas_r63419_panel_funcs, DRM_MODE_CONNECTOR_DSI);
> + if (IS_ERR(ctx))
> + return PTR_ERR(ctx);
> +
> + ctx->desc = of_device_get_match_data(dev);
> + if (!ctx->desc)
> + return dev_err_probe(dev, -ENODEV,
> + "Failed to get panel description\n");
> +
> + ret = devm_regulator_bulk_get_const(&dsi->dev,
> + ARRAY_SIZE(renesas_r63419_vdd_supplies),
> + renesas_r63419_vdd_supplies, &ctx->vdd_supplies);
> + if (ret < 0)
> + return ret;
> +
> + ret = devm_regulator_bulk_get_const(&dsi->dev,
> + ARRAY_SIZE(renesas_r63419_vcc_supplies),
> + renesas_r63419_vcc_supplies, &ctx->vcc_supplies);
> + if (ret < 0)
> + return ret;
> +
> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
> + if (IS_ERR(ctx->reset_gpio))
> + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
> + "Failed to get reset gpio\n");
> +
> + /* Get second DSI host */
> + dsi1_node = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
> + if (!dsi1_node)
> + return dev_err_probe(dev, -ENODEV,
> + "Failed to get remote node for second DSI\n");
> +
> + dsi1_host = of_find_mipi_dsi_host_by_node(dsi1_node);
> + of_node_put(dsi1_node);
> + if (!dsi1_host)
> + return dev_err_probe(dev, -EPROBE_DEFER,
> + "Failed to find second DSI host\n");
> +
> + /* Register the second DSI device */
> + ctx->dsi[1] = devm_mipi_dsi_device_register_full(dev, dsi1_host,
> + &ctx->desc->dsi_info);

This way we are not passing the OF node for the second DSI device...

> + if (IS_ERR(ctx->dsi[1]))
> + return dev_err_probe(dev, PTR_ERR(ctx->dsi[1]),
> + "Failed to register second DSI device\n");
> +
> + ctx->dsi[0] = dsi;
> + mipi_dsi_set_drvdata(dsi, ctx);
> +
> + /* Get panel orientation */
> + ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
> + if (ret < 0 && ret != -ENODEV)
> + return dev_err_probe(dev, ret,
> + "Failed to get panel orientation\n");
> +
> + ctx->panel.prepare_prev_first = true;
> +
> + ret = drm_panel_of_backlight(&ctx->panel);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to get backlight\n");
> +
> + drm_panel_add(&ctx->panel);

devm_drm_panel_add()

> +
> + /* Configure and attach both DSI devices */
> + for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) {
> + ctx->dsi[i]->lanes = ctx->desc->lanes;
> + ctx->dsi[i]->format = ctx->desc->format;
> + ctx->dsi[i]->mode_flags = ctx->desc->mode_flags;
> +
> + ret = mipi_dsi_attach(ctx->dsi[i]);

devm_mipi_dsi_attach()

> + if (ret < 0) {
> + drm_panel_remove(&ctx->panel);
> + return dev_err_probe(dev, ret,
> + "Failed to attach DSI device %d\n", i);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static void renesas_r63419_remove(struct mipi_dsi_device *dsi)
> +{
> + struct renesas_r63419_panel *ctx = mipi_dsi_get_drvdata(dsi);
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++)
> + mipi_dsi_detach(ctx->dsi[i]);
> +
> + drm_panel_remove(&ctx->panel);
> +}
> +
> +static const struct of_device_id renesas_r63419_of_match[] = {
> + {
> + .compatible = "ayaneo,wt0600-2k",
> + .data = &wt0600_desc,
> + },
> + {
> + .compatible = "ayaneo,wt0630-2k",
> + .data = &wt0630_desc,
> + },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, renesas_r63419_of_match);
> +
> +static struct mipi_dsi_driver renesas_r63419_driver = {
> + .probe = renesas_r63419_probe,
> + .remove = renesas_r63419_remove,
> + .driver = {
> + .name = "panel-renesas-r63419",
> + .of_match_table = renesas_r63419_of_match,
> + },
> +};
> +module_mipi_dsi_driver(renesas_r63419_driver);
> +
> +MODULE_AUTHOR("Kancy Joe <kancy2333@xxxxxxxxxxx>");
> +MODULE_AUTHOR("Neil Armstrong <neil.armstrong@xxxxxxxxxx>");
> +MODULE_DESCRIPTION("DRM driver for Renesas R63419 based dual-DSI video mode panels");
> +MODULE_LICENSE("GPL");
>
> --
> 2.34.1
>

--
With best wishes
Dmitry