* [PATCH v4 0/5] Add support to 2 panels in bonded-DSI mode
@ 2026-05-21 14:46 Jun Nie
2026-05-21 14:46 ` [PATCH v4 1/5] drm/msm/dsi: support DSC configurations with slice_per_pkt > 1 Jun Nie
` (5 more replies)
0 siblings, 6 replies; 16+ messages in thread
From: Jun Nie @ 2026-05-21 14:46 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Jun Nie, Jonathan Marek
The 2 DSI interfaces may be connected to 2 independent panels in bonded-DSI
mode. Horizontal timing and DSC configuration are adjusted per individual
panel in DSI host side. Support to multiple slice per packet is added for
the device setup to test the usage case. A panel driver is included as an
use case example.
Changes vs v3:
- A panel driver is added as an use case example.
- Move dsc_slice_per_pkt to struct drm_dsc_config.
- Polish commit messages.
- Link to v3: https://lore.kernel.org/all/20250924-dsi-dual-panel-upstream-v3-0-6927284f1098@linaro.org
Changes vs v2:
- Polish commit message to describe usage case and requirements to
panel driver.
- Remove changes in device tree and add dual_panel flag in mipi_dsi_device
to pass information from panel to dsi host.
- Drop the register programming to DSI_VBIF_CTRL, as no issue is seen
in latest test.
- Link to v2: https://lore.kernel.org/r/20250220-dual-dsi-v2-0-6c0038d5a2ef@linaro.org
Change vs v1:
- Add device tree binding for dual panel case in handling frame width for
DSC to avoid breaking existing dual-DSI case.
- Leverage Marijn's patch to configure proper slice per interface in
dsi_update_dsc_timing().
- Polish commit comments.
- Link to v1: https://lore.kernel.org/all/20240829-sm8650-v6-11-hmd-pocf-mdss-quad-upstream-8-v1-0-bdb05b4b5a2e@linaro.org/
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
Jun Nie (5):
drm/msm/dsi: support DSC configurations with slice_per_pkt > 1
drm/mipi-dsi: Add flag to support dual-panel configurations
drm/msm/dsi: Support dual panel use case with single CRTC
dt-bindings: display: Add Synaptics R63455 panel support
drm/panel: Add driver for Synaptics R63455 DSI panel
.../bindings/display/panel/synaptics,r63455.yaml | 125 ++++
drivers/gpu/drm/msm/dsi/dsi_host.c | 33 +-
drivers/gpu/drm/panel/Kconfig | 9 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-synaptics-r63455.c | 631 +++++++++++++++++++++
include/drm/display/drm_dsc.h | 7 +
include/drm/drm_mipi_dsi.h | 2 +
7 files changed, 792 insertions(+), 16 deletions(-)
---
base-commit: 6654f8f33aa6229a90d4401519a62a2bf96cb851
change-id: 20260521-sm8650-7-1-bonded-dsi-7a7d5b70f687
Best regards,
--
Jun Nie <jun.nie@linaro.org>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v4 1/5] drm/msm/dsi: support DSC configurations with slice_per_pkt > 1
2026-05-21 14:46 [PATCH v4 0/5] Add support to 2 panels in bonded-DSI mode Jun Nie
@ 2026-05-21 14:46 ` Jun Nie
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
2026-05-21 14:46 ` [PATCH v4 2/5] drm/mipi-dsi: Add flag to support dual-panel configurations Jun Nie
` (4 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Jun Nie @ 2026-05-21 14:46 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Jun Nie, Jonathan Marek
Some panels require multiple slice to be sent in a single DSC packet. And
this feature is a must for specific panels, such as Sharp ls026b3sa06. Add
a dsc_slice_per_pkt member into struct drm_dsc_config and support the
feature in msm mdss driver.
Co-developed-by: Jonathan Marek <jonathan@marek.ca>
Signed-off-by: Jonathan Marek <jonathan@marek.ca>
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
drivers/gpu/drm/msm/dsi/dsi_host.c | 23 ++++++++---------------
include/drm/display/drm_dsc.h | 7 +++++++
2 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 53ff23f4f68ab..d14b6e41dcd90 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -166,6 +166,7 @@ struct msm_dsi_host {
struct drm_display_mode *mode;
struct drm_dsc_config *dsc;
+ unsigned int dsc_slice_per_pkt;
/* connected device info */
unsigned int channel;
@@ -938,17 +939,10 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod
slice_per_intf = dsc->slice_count;
total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf;
- bytes_per_pkt = dsc->slice_chunk_size; /* * slice_per_pkt; */
+ bytes_per_pkt = dsc->slice_chunk_size * msm_host->dsc_slice_per_pkt;
eol_byte_num = total_bytes_per_intf % 3;
-
- /*
- * Typically, pkt_per_line = slice_per_intf * slice_per_pkt.
- *
- * Since the current driver only supports slice_per_pkt = 1,
- * pkt_per_line will be equal to slice per intf for now.
- */
- pkt_per_line = slice_per_intf;
+ pkt_per_line = slice_per_intf / msm_host->dsc_slice_per_pkt;
if (is_cmd_mode) /* packet data type */
reg = DSI_COMMAND_COMPRESSION_MODE_CTRL_STREAM0_DATATYPE(MIPI_DSI_DCS_LONG_WRITE);
@@ -1104,12 +1098,8 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
else
/*
* When DSC is enabled, WC = slice_chunk_size * slice_per_pkt + 1.
- * Currently, the driver only supports default value of slice_per_pkt = 1
- *
- * TODO: Expand mipi_dsi_device struct to hold slice_per_pkt info
- * and adjust DSC math to account for slice_per_pkt.
*/
- wc = msm_host->dsc->slice_chunk_size + 1;
+ wc = msm_host->dsc->slice_chunk_size * msm_host->dsc_slice_per_pkt + 1;
dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL,
DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) |
@@ -1719,8 +1709,11 @@ static int dsi_host_attach(struct mipi_dsi_host *host,
msm_host->lanes = dsi->lanes;
msm_host->format = dsi->format;
msm_host->mode_flags = dsi->mode_flags;
- if (dsi->dsc)
+ if (dsi->dsc) {
msm_host->dsc = dsi->dsc;
+ /* for backwards compatibility, assume 1 if not set */
+ msm_host->dsc_slice_per_pkt = dsi->dsc->dsc_slice_per_pkt ?: 1;
+ }
if (msm_host->format == MIPI_DSI_FMT_RGB101010) {
if (!msm_dsi_host_version_geq(msm_host, MSM_DSI_VER_MAJOR_6G,
diff --git a/include/drm/display/drm_dsc.h b/include/drm/display/drm_dsc.h
index bbbe7438473d3..c522ab3d71853 100644
--- a/include/drm/display/drm_dsc.h
+++ b/include/drm/display/drm_dsc.h
@@ -267,6 +267,13 @@ struct drm_dsc_config {
* Offset adjustment for second line in Native 4:2:0 mode
*/
u16 second_line_offset_adj;
+
+ /**
+ * @dsc_slice_per_pkt:
+ * Number of DSC slices to be sent in a single packet. This is not
+ * part of DSC standard, and only used in some DSI panels so far.
+ */
+ unsigned int dsc_slice_per_pkt;
};
/**
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 2/5] drm/mipi-dsi: Add flag to support dual-panel configurations
2026-05-21 14:46 [PATCH v4 0/5] Add support to 2 panels in bonded-DSI mode Jun Nie
2026-05-21 14:46 ` [PATCH v4 1/5] drm/msm/dsi: support DSC configurations with slice_per_pkt > 1 Jun Nie
@ 2026-05-21 14:46 ` Jun Nie
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
2026-05-21 14:46 ` [PATCH v4 3/5] drm/msm/dsi: Support dual panel use case with single CRTC Jun Nie
` (3 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Jun Nie @ 2026-05-21 14:46 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Jun Nie
Some devices treat two independent physical DSI panels as a single
logical panel from the CRTC's perspective. However, two separate DSI
hosts are still required to drive the panels individually.
Introduce a `dual_panel` flag to the `mipi_dsi_device` struct. This
allows a panel driver to inform the DSI host that it is part of a
dual-panel setup, enabling the host to coordinate both physical
displays as one.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
include/drm/drm_mipi_dsi.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 2ab651a36115d..889ef1421207a 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -169,6 +169,7 @@ struct mipi_dsi_device_info {
* @host: DSI host for this peripheral
* @dev: driver model device node for this peripheral
* @attached: the DSI device has been successfully attached
+ * @dual_panel: the DSI device is one instance of dual panel
* @name: DSI peripheral chip type
* @channel: virtual channel assigned to the peripheral
* @format: pixel format for video mode
@@ -186,6 +187,7 @@ struct mipi_dsi_device {
struct mipi_dsi_host *host;
struct device dev;
bool attached;
+ bool dual_panel;
char name[DSI_DEV_NAME_SIZE];
unsigned int channel;
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 3/5] drm/msm/dsi: Support dual panel use case with single CRTC
2026-05-21 14:46 [PATCH v4 0/5] Add support to 2 panels in bonded-DSI mode Jun Nie
2026-05-21 14:46 ` [PATCH v4 1/5] drm/msm/dsi: support DSC configurations with slice_per_pkt > 1 Jun Nie
2026-05-21 14:46 ` [PATCH v4 2/5] drm/mipi-dsi: Add flag to support dual-panel configurations Jun Nie
@ 2026-05-21 14:46 ` Jun Nie
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
2026-05-21 14:46 ` [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support Jun Nie
` (2 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Jun Nie @ 2026-05-21 14:46 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Jun Nie
Support a hardware configuration where two independent DSI panels are
driven by a single, synchronous CRTC. This configuration uses a bonded
DSI link to provide a unified vblank for both displays.
This allows application software to treat the two displays as a single,
wide framebuffer with a synchronized refresh cycle, simplifying rendering
logic for side-by-side panel arrangements.
At the DSI host level, the frame width for each link must be that of an
individual panel. The driver therefore halves the CRTC's horizontal
resolution before configuring the DSI host and any DSC encoders, ensuring
each panel receives the correct half of the framebuffer.
While the DSI panel driver should manage two panels togehter.
1. During probe, the driver finds the sibling dsi host via device tree
phandle and register the 2nd panel to get another mipi_dsi_device.
2. Set dual_panel flag on both mipi_dsi_device.
3. Prepare DSC data per requirement from single panel.
4. All DSI commands should be send on every DSI link.
5. Handle power supply for 2 panels in one shot, the same is true to
brightness.
6. From the CRTC's perspective, the two panels appear as one wide display.
The driver exposes a DRM mode where the horizontal timings (hdisplay,
hsync_start, etc.) are doubled, while the vertical timings remain those
of a single panel. Because 2 panels are expected to be mounted in
left/right position.
To maintain synchronization, both DSI links are configured to share a
single clock source, with the DSI1 controller using the clock provided
to DSI0 as below.
&mdss_dsi1 {
assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>,
<&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>;
assigned-clock-parents = <&mdss_dsi0_phy 0>, <&mdss_dsi0_phy 1>;
}
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
drivers/gpu/drm/msm/dsi/dsi_host.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index d14b6e41dcd90..4d7ac01aa393d 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -186,6 +186,7 @@ struct msm_dsi_host {
bool registered;
bool power_on;
bool enabled;
+ bool is_dual_panel;
int irq;
};
@@ -1024,7 +1025,10 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
return;
}
- dsc->pic_width = mode->hdisplay;
+ if (msm_host->is_dual_panel)
+ dsc->pic_width = hdisplay;
+ else
+ dsc->pic_width = mode->hdisplay;
dsc->pic_height = mode->vdisplay;
DBG("Mode %dx%d\n", dsc->pic_width, dsc->pic_height);
@@ -1705,6 +1709,7 @@ static int dsi_host_attach(struct mipi_dsi_host *host,
if (dsi->lanes > msm_host->num_data_lanes)
return -EINVAL;
+ msm_host->is_dual_panel = dsi->dual_panel;
msm_host->channel = dsi->channel;
msm_host->lanes = dsi->lanes;
msm_host->format = dsi->format;
@@ -2596,6 +2601,9 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
if (!msm_host->dsc)
return MODE_OK;
+ if (msm_host->is_dual_panel)
+ pic_width = mode->hdisplay / 2;
+
if (pic_width % dsc->slice_width) {
pr_err("DSI: pic_width %d has to be multiple of slice %d\n",
pic_width, dsc->slice_width);
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support
2026-05-21 14:46 [PATCH v4 0/5] Add support to 2 panels in bonded-DSI mode Jun Nie
` (2 preceding siblings ...)
2026-05-21 14:46 ` [PATCH v4 3/5] drm/msm/dsi: Support dual panel use case with single CRTC Jun Nie
@ 2026-05-21 14:46 ` Jun Nie
2026-05-21 19:45 ` Conor Dooley
` (3 more replies)
2026-05-21 14:46 ` [PATCH v4 5/5] drm/panel: Add driver for Synaptics R63455 DSI panel Jun Nie
2026-05-25 10:00 ` Claude review: Add support to 2 panels in bonded-DSI mode Claude Code Review Bot
5 siblings, 4 replies; 16+ messages in thread
From: Jun Nie @ 2026-05-21 14:46 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Jun Nie
Add support for the dual-panel system found in the virtual reality device.
This system consists of two physical 2160x2160 panels, each connected via
a MIPI DSI interface. The backlight is managed through DSI link.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
.../bindings/display/panel/synaptics,r63455.yaml | 125 +++++++++++++++++++++
1 file changed, 125 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml b/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml
new file mode 100644
index 0000000000000..a94b355ed9557
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml
@@ -0,0 +1,125 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/synaptics,r63455.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synaptics R63455 based dual 2160x2160 MIPI-DSI Panel
+
+maintainers:
+ - Jun Nie <jun.nie@linaro.org>
+
+description:
+ Synaptics R63455 is a Virtual Reality Display Driver and VR Bridge, used in
+ pair in Headset devices. The Virtual Reality Display complex is composed of
+ two strictly identical display panels, each driven by its own DSI interface
+ but forms a single virtual display for the human eye perception and thus
+ requires a strict synchronization of the two display panel content update.
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - sharp,ls026b3sa06
+ - boe,vs026c4m-n52-6000
+ - const: synaptics,r63455
+
+ reset-gpios:
+ maxItems: 2
+ description: 2 reset pins for 2 physical panels
+
+ left-pos-supply:
+ description: Positive 5.7V supply for left panel
+
+ right-pos-supply:
+ description: Positive 5.7V supply for right panel
+
+ left-neg-supply:
+ description: Negative 5.7V supply for left panel
+
+ right-neg-supply:
+ description: Negative 5.7V supply for right panel
+
+ left-backlight-supply:
+ description: Backlight 21V supply for left panel
+
+ right-backlight-supply:
+ description: Backlight 21V supply for right panel
+
+ vdda-supply:
+ description: core 1.8V supply for panels
+
+ ports: $ref: /schemas/graph.yaml#/properties/ports
+
+required:
+ - compatible
+ - reset-gpios
+ - left-pos-supply
+ - left-neg-supply
+ - right-pos-supply
+ - right-neg-supply
+ - left-backlight-supply
+ - right-backlight-supply
+ - vdda-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ &mdss_dsi0 {
+ vdda-supply = <&vreg_l3i_1p2>;
+ status = "okay";
+
+ qcom,dual-dsi-mode;
+ qcom,master-dsi;
+
+ panel: panel@0 {
+ compatible = "sharp,ls026b3sa06", "synaptics,r63455";
+ reg = <0>;
+
+ reset-gpios = <&pm8550_gpios 3 GPIO_ACTIVE_HIGH>,
+ <&pm8550_gpios 11 GPIO_ACTIVE_HIGH>;
+
+ left-pos-supply = <&vpos_left>;
+ left-neg-supply = <&vneg_left>;
+ right-pos-supply = <&vpos_right>;
+ right-neg-supply = <&vneg_right>;
+ left-backlight-supply = <&backlight_left>;
+ right-backlight-supply = <&backlight_right>;
+
+ vdda-supply = <&vreg_l12b_1p8>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ panel0_in: endpoint {
+ remote-endpoint = <&mdss_dsi0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ panel1_in: endpoint {
+ remote-endpoint = <&mdss_dsi1_out>;
+ };
+ };
+ };
+ };
+
+ &mdss_dsi0_out {
+ remote-endpoint = <&panel0_in>;
+ data-lanes = <0 1 2>;
+ };
+
+ &mdss_dsi1_out {
+ remote-endpoint = <&panel1_in>;
+ data-lanes = <0 1 2>;
+ };
+...
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 5/5] drm/panel: Add driver for Synaptics R63455 DSI panel
2026-05-21 14:46 [PATCH v4 0/5] Add support to 2 panels in bonded-DSI mode Jun Nie
` (3 preceding siblings ...)
2026-05-21 14:46 ` [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support Jun Nie
@ 2026-05-21 14:46 ` Jun Nie
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
2026-05-25 10:00 ` Claude review: Add support to 2 panels in bonded-DSI mode Claude Code Review Bot
5 siblings, 1 reply; 16+ messages in thread
From: Jun Nie @ 2026-05-21 14:46 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree,
Jun Nie
Add support for the DSI panels used in the virtual reality device.
The device features two physical panels, each providing a MIPI DSI
interface and a built-in LED backlight and expose a single logical
panel to the DRM framework.
Signed-off-by: Jun Nie <jun.nie@linaro.org>
---
drivers/gpu/drm/panel/Kconfig | 9 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-synaptics-r63455.c | 631 +++++++++++++++++++++++++
3 files changed, 641 insertions(+)
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 7c2d9feb4064e..1ef3f51ec6593 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -1227,6 +1227,15 @@ config DRM_PANEL_SYNAPTICS_TDDI
namesake, with varying resolutions and data lanes. They also have a
built-in LED backlight and a touch controller.
+config DRM_PANEL_SYNAPTICS_R63455
+ tristate "Synaptics R63455-based panels"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y if you want to enable support for panels based on the
+ Synaptics R63455 controller.
+
config DRM_PANEL_TDO_TL070WSH30
tristate "TDO TL070WSH30 DSI panel"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index dc8a05f2c34d9..ee6b41151804c 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -115,6 +115,7 @@ obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o
obj-$(CONFIG_DRM_PANEL_SUMMIT) += panel-summit.o
obj-$(CONFIG_DRM_PANEL_SYNAPTICS_R63353) += panel-synaptics-r63353.o
obj-$(CONFIG_DRM_PANEL_SYNAPTICS_TDDI) += panel-synaptics-tddi.o
+obj-$(CONFIG_DRM_PANEL_SYNAPTICS_R63455) += panel-synaptics-r63455.o
obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o
obj-$(CONFIG_DRM_PANEL_SONY_TD4353_JDI) += panel-sony-td4353-jdi.o
obj-$(CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521) += panel-sony-tulip-truly-nt35521.o
diff --git a/drivers/gpu/drm/panel/panel-synaptics-r63455.c b/drivers/gpu/drm/panel/panel-synaptics-r63455.c
new file mode 100644
index 0000000000000..e429c28c7efc9
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-synaptics-r63455.c
@@ -0,0 +1,631 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026, Linaro Ltd. All rights reserved.
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/display/drm_dsc.h>
+#include <drm/display/drm_dsc_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
+#define R63455_MF_CMD_ACCESS_PROTECT 0xb0
+#define R63455_SEQ_CTL 0xd6
+#define R63455_DSI_CTL 0xb6
+#define R63455_DISP_MODE 0xb7
+#define R63455_GEN_OUTPIN_SET 0xb9
+#define R63455_DISP_SET1 0xc0
+#define R63455_DISP_SET2 0xf1
+#define R63455_DISP_SET3 0xc6
+#define R63455_DISP_SET3_2 0xcd
+#define R63455_DISP_SET4 0xcf
+#define R63455_DISP_SET5 0xec
+#define R63455_DISP_SET6 0xef
+#define R63455_TE_GPIO_CTL 0xbe
+#define R63455_PPS_SET 0xe6
+
+#define BRIGHTNESS_DEFAULT 256
+#define BRIGHTNESS_MAX_120 367
+
+#define VBP 100
+#define VFP 700
+#define VID_VS_DELAY 1112
+#define GPO1_TES1 4068
+#define RTN 59
+
+static const char * const vdda_driver[] = {
+ "vdda",
+};
+
+static const char * const dual_backlight_driver[] = {
+ "left-backlight",
+ "right-backlight",
+};
+
+static const char * const dual_lcd_bias_pos[] = {
+ "left-pos",
+ "right-pos",
+};
+
+static const char * const dual_lcd_bias_neg[] = {
+ "left-neg",
+ "right-neg"
+};
+
+struct r63455_ctx {
+ struct device *dev;
+ struct drm_panel panel;
+
+ struct regulator_bulk_data reg_vdda[ARRAY_SIZE(vdda_driver)];
+ struct regulator_bulk_data reg_bl[ARRAY_SIZE(dual_backlight_driver)];
+ struct regulator_bulk_data reg_lcd_bias_pos[ARRAY_SIZE(dual_lcd_bias_pos)];
+ struct regulator_bulk_data reg_lcd_bias_neg[ARRAY_SIZE(dual_lcd_bias_neg)];
+
+ struct gpio_descs *reset_gpios;
+ int (*dsi_init_seq)(struct drm_panel *panel);
+ struct backlight_device *backlight;
+ struct mipi_dsi_device *dsi[2];
+ struct drm_dsc_config dsc_cfg;
+};
+
+static inline struct r63455_ctx *panel_to_ctx(struct drm_panel *panel)
+{
+ return container_of(panel, struct r63455_ctx, panel);
+}
+
+static const struct drm_display_mode modes = {
+ .name = "4320x2160_120",
+ .clock = (2160 + 24 + 20 + 20) * (2160 + 404 + 1 + 20) * 120 * 2 / 1000,
+ .hdisplay = 2160 * 2,
+ .hsync_start = (2160 + 24) * 2,
+ .hsync_end = (2160 + 24 + 20) * 2,
+ .htotal = (2160 + 24 + 20 + 20) * 2,
+ .vdisplay = 2160,
+ .vsync_start = 2160 + 404,
+ .vsync_end = 2160 + 404 + 1,
+ .vtotal = 2160 + 404 + 1 + 20,
+ .width_mm = 50 * 2,
+ .height_mm = 50,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+#define r63455_dsi_write_seq(ctx, dsi_ctx, cmd, seq...) \
+ do { \
+ u8 d[] = {cmd, seq}; \
+ dsi_ctx.dsi = ctx->dsi[0]; \
+ mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, d, ARRAY_SIZE(d)); \
+ dsi_ctx.dsi = ctx->dsi[1]; \
+ mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, d, ARRAY_SIZE(d)); \
+ } while (0)
+
+#define r63455_dsi_write_buffer(ctx, dsi_ctx, d) \
+ do { \
+ dsi_ctx.dsi = ctx->dsi[0]; \
+ mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, d, ARRAY_SIZE(d)); \
+ dsi_ctx.dsi = ctx->dsi[1]; \
+ mipi_dsi_dcs_write_buffer_multi(&dsi_ctx, d, ARRAY_SIZE(d)); \
+ } while (0)
+
+#define LE16_BYTE0(val) (le16_to_cpu(val) & 0xff)
+#define LE16_BYTE1(val) ((le16_to_cpu(val) >> 8) & 0xff)
+#define BE16_BYTE0(val) (be16_to_cpu(val) & 0xff)
+#define BE16_BYTE1(val) ((be16_to_cpu(val) >> 8) & 0xff)
+
+static int r63455_dsi_populate_dsc_params(struct r63455_ctx *ctx)
+{
+ int ret;
+ struct drm_dsc_config *dsc = &ctx->dsc_cfg;
+
+ dsc->simple_422 = 0;
+ dsc->convert_rgb = 1;
+ dsc->vbr_enable = 0;
+
+ drm_dsc_set_const_params(dsc);
+ drm_dsc_set_rc_buf_thresh(dsc);
+
+ /* handle only bpp = bpc = 8, pre-SCR panels */
+ ret = drm_dsc_setup_rc_params(dsc, DRM_DSC_1_1_PRE_SCR);
+ if (ret < 0)
+ DRM_DEV_ERROR(ctx->dev, "failed to setup dsc params\n");
+
+ dsc->initial_scale_value = drm_dsc_initial_scale_value(dsc);
+ dsc->line_buf_depth = dsc->bits_per_component + 1;
+
+ return drm_dsc_compute_rc_parameters(dsc);
+}
+
+static int r63455_init_dsc_config(struct r63455_ctx *ctx)
+{
+ ctx->dsc_cfg = (struct drm_dsc_config) {
+ .dsc_version_major = 0x1,
+ .dsc_version_minor = 0x2,
+ .dsc_slice_per_pkt = 4,
+ .slice_height = 48,
+ .slice_width = 540,
+ .slice_count = 4,
+ .bits_per_component = 8,
+ .bits_per_pixel = 8 << 4,
+ .block_pred_enable = true,
+
+ .pic_width = 2160,
+ .pic_height = 2160,
+ };
+
+ return r63455_dsi_populate_dsc_params(ctx);
+}
+
+static int r63455_panel_on_sharp_ls026b3sa06(struct drm_panel *panel)
+{
+ struct r63455_ctx *ctx = panel_to_ctx(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { 0 };
+
+ u8 pps_cmd[1 + sizeof(struct drm_dsc_picture_parameter_set)];
+
+ drm_dsc_pps_payload_pack((void *)&pps_cmd[1], &ctx->dsc_cfg);
+ pps_cmd[0] = R63455_PPS_SET;
+
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_MF_CMD_ACCESS_PROTECT, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_SEQ_CTL, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx,
+ R63455_DSI_CTL,
+ 0x20, 0x6b, 0x80, 0x06, 0x33, 0x9a, 0x00, 0x1a,
+ 0x7a);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_MODE,
+ 0x54, 0x00, 0x00, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_GEN_OUTPIN_SET,
+ 0xf, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xf, 0xb2, 0x00, 0x64);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET3,
+ 0x08, 0x70, 0x28, 0x48, 0x00, 0x00, 0x13, 0x21,
+ 0xff, 0x00, 0x0f, 0x01, 0x14, 0x17, 0x00, 0x00,
+ 0x00, 0x02, 0x40, 0x0C, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x70, 0x08,
+ 0xD0, 0x02, 0x21, 0x6F, 0x08, 0x5A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET1,
+ RTN, 0x86, LE16_BYTE0(VBP), LE16_BYTE1(VBP), 0x08,
+ 0x70, BE16_BYTE0(VFP), BE16_BYTE1(VFP), 0x00,
+ 0x00, 0x08, 0x3B, 0x00, 0x00, 0x19, 0x01, 0x22);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET3_2, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET4,
+ 0x8b, 0x00, 0x80, 0x46, 0x61, 0x00, 0x8b);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET5,
+ BE16_BYTE0(VID_VS_DELAY),
+ BE16_BYTE1(VID_VS_DELAY),
+ 0x00, 0x00, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET6,
+ 0x00, 0x24, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x03,
+ 0x1D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_TE_GPIO_CTL,
+ 0x00, 0x6A, 0x02);
+ r63455_dsi_write_buffer(ctx, dsi_ctx, pps_cmd);
+ r63455_dsi_write_seq(ctx, dsi_ctx, MIPI_DCS_SET_TEAR_ON, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x40);
+ r63455_dsi_write_seq(ctx, dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
+ mipi_dsi_msleep(&dsi_ctx, 170);
+ r63455_dsi_write_seq(ctx, dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
+ mipi_dsi_msleep(&dsi_ctx, 200);
+
+ return dsi_ctx.accum_err;
+}
+
+static int r63455_panel_on_boe_vs026c4m_n52_26000(struct drm_panel *panel)
+{
+ struct r63455_ctx *ctx = panel_to_ctx(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { 0 };
+
+ u8 pps_cmd[1 + sizeof(struct drm_dsc_picture_parameter_set)];
+
+ drm_dsc_pps_payload_pack((void *)&pps_cmd[1], &ctx->dsc_cfg);
+ pps_cmd[0] = R63455_PPS_SET;
+
+ r63455_dsi_write_seq(ctx, dsi_ctx,
+ R63455_MF_CMD_ACCESS_PROTECT, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_SEQ_CTL, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DSI_CTL,
+ 0x20, 0x6b, 0x80, 0x06, 0x33, 0x9A, 0x00,
+ 0x1a, 0x7a);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_MODE,
+ 0x54, 0x00, 0x00, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_GEN_OUTPIN_SET,
+ 0xf, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xf, 0xb2,
+ 0xf, 0xb2, 0x00, 0x64);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET3,
+ 0x0B, 0x70, 0x08, 0x48, 0x00, 0x00, 0x13, 0x01,
+ 0xFF, 0x00, 0x01, 0x09, 0x16, 0x16, 0x00, 0x00,
+ 0x00, 0x01, 0x40, 0x0C, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x70, 0x08,
+ 0xD0, 0x02, 0x21, 0x6F, 0x08, 0x5A, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET1,
+ RTN, 0x86, LE16_BYTE0(VBP), LE16_BYTE1(VBP), 0x08,
+ 0x70, BE16_BYTE0(VFP), BE16_BYTE1(VFP), 0x00,
+ 0x00, 0x08, 0x3A, 0x00, 0x00, 0x17, 0x00, 0x17);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET3_2, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET4,
+ 0x8b, 0x00, 0x80, 0x46, 0x61, 0x00, 0x8b);
+ r63455_dsi_write_seq(ctx, dsi_ctx, R63455_DISP_SET5,
+ BE16_BYTE0(VID_VS_DELAY), BE16_BYTE1(VID_VS_DELAY),
+ 0x00, 0x00, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx,
+ R63455_TE_GPIO_CTL, 0x00, 0x6A, 0x02);
+ r63455_dsi_write_buffer(ctx, dsi_ctx, pps_cmd);
+ r63455_dsi_write_seq(ctx, dsi_ctx, MIPI_DCS_SET_TEAR_ON, 0x00);
+ r63455_dsi_write_seq(ctx, dsi_ctx, MIPI_DCS_EXIT_SLEEP_MODE);
+ mipi_dsi_msleep(&dsi_ctx, 170);
+ r63455_dsi_write_seq(ctx, dsi_ctx, MIPI_DCS_SET_DISPLAY_ON);
+ mipi_dsi_msleep(&dsi_ctx, 200);
+
+ return dsi_ctx.accum_err;
+}
+
+static int r63455_set_brightness(struct r63455_ctx *ctx, u16 brightness,
+ u16 pulse_offset_rows)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { 0 };
+ u16 gpo1_tew1;
+
+ gpo1_tew1 = brightness > BRIGHTNESS_MAX_120 ?
+ BRIGHTNESS_MAX_120 : brightness;
+
+ ctx->dsi[0]->mode_flags &= ~MIPI_DSI_MODE_LPM;
+ ctx->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ r63455_dsi_write_seq(ctx, dsi_ctx,
+ R63455_GEN_OUTPIN_SET,
+ 0x0f, 0xe4,
+ BE16_BYTE0(gpo1_tew1),
+ BE16_BYTE1(gpo1_tew1),
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0xb2,
+ BE16_BYTE0(brightness),
+ BE16_BYTE1(brightness));
+
+ ctx->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
+ ctx->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ return dsi_ctx.accum_err;
+}
+
+static int r63455_disable(struct drm_panel *panel)
+{
+ struct r63455_ctx *ctx = panel_to_ctx(panel);
+ struct mipi_dsi_multi_context dsi_ctx = { 0 };
+
+ ctx->dsi[0]->mode_flags &= ~MIPI_DSI_MODE_LPM;
+ ctx->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ r63455_dsi_write_seq(ctx, dsi_ctx, MIPI_DCS_SET_DISPLAY_OFF);
+ r63455_dsi_write_seq(ctx, dsi_ctx, MIPI_DCS_SET_TEAR_OFF);
+ r63455_dsi_write_seq(ctx, dsi_ctx, MIPI_DCS_ENTER_SLEEP_MODE);
+
+ mipi_dsi_msleep(&dsi_ctx, 200);
+
+ if (dsi_ctx.accum_err)
+ return dsi_ctx.accum_err;
+
+ return backlight_disable(ctx->backlight);
+}
+
+static int r63455_unprepare(struct drm_panel *panel)
+{
+ struct r63455_ctx *ctx = panel_to_ctx(panel);
+ int ret;
+
+ gpiod_set_value(ctx->reset_gpios->desc[0], 0);
+ gpiod_set_value(ctx->reset_gpios->desc[1], 0);
+
+ msleep(25);
+ ret = regulator_bulk_disable(ARRAY_SIZE(ctx->reg_lcd_bias_neg),
+ ctx->reg_lcd_bias_neg);
+ if (ret)
+ dev_err(ctx->dev, "Could not disable bias negative\n");
+
+ usleep_range(1000, 2000);
+ ret = regulator_bulk_disable(ARRAY_SIZE(ctx->reg_lcd_bias_pos),
+ ctx->reg_lcd_bias_pos);
+ if (ret)
+ dev_err(ctx->dev, "Could not disable bias positive\n");
+
+ msleep(20);
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(ctx->reg_vdda), ctx->reg_vdda);
+ if (ret)
+ dev_err(ctx->dev, "Could not disable vdda\n");
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(ctx->reg_bl), ctx->reg_bl);
+ if (ret)
+ dev_err(ctx->dev,
+ "failed to disable regulator backlight: %d\n", ret);
+
+ return ret;
+}
+
+static int r63455_enable(struct drm_panel *panel)
+{
+ struct r63455_ctx *ctx = panel_to_ctx(panel);
+ int ret;
+
+ ctx->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
+ ctx->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ msleep(20);
+ ret = ctx->dsi_init_seq(panel);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev, "dsi init failed\n");
+ return ret;
+ }
+ ctx->backlight->props.pulse_offset_rows = GPO1_TES1;
+
+ ret = backlight_enable(ctx->backlight);
+ if (ret < 0) {
+ DRM_DEV_ERROR(ctx->dev, "failed to enable backlight\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int r63455_prepare(struct drm_panel *panel)
+{
+ struct r63455_ctx *ctx = panel_to_ctx(panel);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->reg_bl), ctx->reg_bl);
+ if (ret) {
+ dev_err(ctx->dev, "Could not enable backlight\n");
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->reg_vdda), ctx->reg_vdda);
+ if (ret) {
+ dev_err(ctx->dev, "Could not enable vdda\n");
+ goto bl_off;
+ }
+
+ usleep_range(1000, 2000);
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->reg_lcd_bias_pos),
+ ctx->reg_lcd_bias_pos);
+ if (ret) {
+ dev_err(ctx->dev, "Could not enable bias positive\n");
+ goto vdda_off;
+ }
+ usleep_range(1000, 2000);
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->reg_lcd_bias_neg),
+ ctx->reg_lcd_bias_neg);
+ if (ret) {
+ dev_err(ctx->dev, "Could not enable bias negative\n");
+ goto bias_off;
+ }
+
+ msleep(20);
+ gpiod_set_value(ctx->reset_gpios->desc[0], 1);
+ gpiod_set_value(ctx->reset_gpios->desc[1], 1);
+
+ return 0;
+
+bl_off:
+ regulator_bulk_disable(ARRAY_SIZE(ctx->reg_bl), ctx->reg_bl);
+vdda_off:
+ regulator_bulk_disable(ARRAY_SIZE(ctx->reg_vdda), ctx->reg_vdda);
+bias_off:
+ regulator_bulk_disable(ARRAY_SIZE(ctx->reg_lcd_bias_pos),
+ ctx->reg_lcd_bias_pos);
+ return ret;
+}
+
+static int r63455_bl_update_status(struct backlight_device *bl)
+{
+ struct mipi_dsi_device *dsi = bl_get_data(bl);
+ struct r63455_ctx *r63455_ctx = mipi_dsi_get_drvdata(dsi);
+
+ return r63455_set_brightness(r63455_ctx, bl->props.brightness,
+ bl->props.pulse_offset_rows);
+}
+
+static const struct backlight_ops r63455_bl_ops = {
+ .update_status = r63455_bl_update_status,
+};
+
+static int r63455_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ return drm_connector_helper_get_modes_fixed(connector, &modes);
+}
+
+static const struct drm_panel_funcs r63455_drm_funcs = {
+ .disable = r63455_disable,
+ .enable = r63455_enable,
+ .unprepare = r63455_unprepare,
+ .prepare = r63455_prepare,
+ .get_modes = r63455_get_modes,
+};
+
+static int r63455_panel_add(struct r63455_ctx *ctx)
+{
+ struct device *dev = ctx->dev;
+ struct backlight_properties bl_props;
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(ctx->reg_vdda); i++)
+ ctx->reg_vdda[i].supply = vdda_driver[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->reg_vdda),
+ ctx->reg_vdda);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(dual_backlight_driver); i++)
+ ctx->reg_bl[i].supply = dual_backlight_driver[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->reg_bl),
+ ctx->reg_bl);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(ctx->reg_lcd_bias_pos); i++)
+ ctx->reg_lcd_bias_pos[i].supply = dual_lcd_bias_pos[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->reg_lcd_bias_pos),
+ ctx->reg_lcd_bias_pos);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(ctx->reg_lcd_bias_neg); i++)
+ ctx->reg_lcd_bias_neg[i].supply = dual_lcd_bias_neg[i];
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->reg_lcd_bias_neg),
+ ctx->reg_lcd_bias_neg);
+ if (ret < 0)
+ return ret;
+
+ ctx->reset_gpios = devm_gpiod_get_array(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpios))
+ return PTR_ERR(ctx->reset_gpios);
+
+ memset(&bl_props, 0, sizeof(bl_props));
+ bl_props.type = BACKLIGHT_RAW;
+ bl_props.brightness = BRIGHTNESS_DEFAULT;
+ bl_props.max_brightness = BRIGHTNESS_MAX_120;
+
+ ctx->backlight = devm_backlight_device_register(dev, dev_name(dev),
+ dev, ctx->dsi[0],
+ &r63455_bl_ops,
+ &bl_props);
+ if (IS_ERR(ctx->backlight)) {
+ ret = PTR_ERR(ctx->backlight);
+ dev_err(dev, "Failed to register backlight (%d)\n", ret);
+ return ret;
+ }
+
+ ctx->panel.prepare_prev_first = true;
+ return devm_drm_panel_add(dev, &ctx->panel);
+}
+
+static int r63455_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct r63455_ctx *ctx;
+ struct mipi_dsi_device *dsi1_device;
+ struct device_node *dsi1;
+ struct mipi_dsi_host *dsi1_host;
+ struct mipi_dsi_device *dsi_dev;
+ int ret = 0;
+ int i;
+
+ const struct mipi_dsi_device_info info = {
+ .type = "r63455-dsi-panel",
+ .channel = 0,
+ .node = NULL,
+ };
+
+ ctx = devm_drm_panel_alloc(&dsi->dev, __typeof(*ctx), panel,
+ &r63455_drm_funcs, DRM_MODE_CONNECTOR_DSI);
+
+ ctx->dsi_init_seq = of_device_get_match_data(dev);
+ if (!ctx->dsi_init_seq)
+ return -ENODEV;
+
+ dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
+ if (!dsi1) {
+ DRM_DEV_ERROR(dev, "failed to get secondary dsi\n");
+ return -ENODEV;
+ }
+
+ dsi1_host = of_find_mipi_dsi_host_by_node(dsi1);
+ of_node_put(dsi1);
+ if (!dsi1_host) {
+ DRM_DEV_ERROR(dev, "failed to find secondary dsi host\n");
+ return -EPROBE_DEFER;
+ }
+
+ dsi1_device = mipi_dsi_device_register_full(dsi1_host, &info);
+ if (IS_ERR(dsi1_device)) {
+ DRM_DEV_ERROR(dev, "failed to create dsi device\n");
+ return PTR_ERR(dsi1_device);
+ }
+
+ ctx->dsi[1] = dsi1_device;
+ mipi_dsi_set_drvdata(dsi, ctx);
+ ctx->dev = dev;
+ ctx->dsi[0] = dsi;
+
+ ret = r63455_init_dsc_config(ctx);
+ if (ret)
+ return ret;
+
+ ctx->dsi[0]->dsc = &ctx->dsc_cfg;
+ ctx->dsi[0]->dual_panel = true;
+ ctx->dsi[1]->dual_panel = true;
+ ctx->dsi[1]->dsc = &ctx->dsc_cfg;
+
+ ret = r63455_panel_add(ctx);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to add panel %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < 2; i++) {
+ dsi_dev = ctx->dsi[i];
+ dsi_dev->lanes = 3;
+ dsi_dev->format = MIPI_DSI_FMT_RGB888;
+ dsi_dev->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS;
+ ret = devm_mipi_dsi_attach(dev, dsi_dev);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "dsi attach failed i = %d\n", i);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct of_device_id r63455_of_match[] = {
+ {
+ .compatible = "sharp,ls026b3sa06",
+ .data = r63455_panel_on_sharp_ls026b3sa06,
+ },
+ {
+ .compatible = "boe,vs026c4m-n52-6000",
+ .data = r63455_panel_on_boe_vs026c4m_n52_26000,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, r63455_of_match);
+
+static struct mipi_dsi_driver r63455_driver = {
+ .driver = {
+ .name = "panel-synaptics-r63455",
+ .of_match_table = r63455_of_match,
+ },
+ .probe = r63455_probe,
+};
+module_mipi_dsi_driver(r63455_driver);
+
+MODULE_DESCRIPTION("Synaptics R63455 DSI Panel Driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support
2026-05-21 14:46 ` [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support Jun Nie
@ 2026-05-21 19:45 ` Conor Dooley
2026-05-21 20:24 ` Dmitry Baryshkov
` (2 subsequent siblings)
3 siblings, 0 replies; 16+ messages in thread
From: Conor Dooley @ 2026-05-21 19:45 UTC (permalink / raw)
To: Jun Nie
Cc: Rob Clark, Dmitry Baryshkov, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-msm, dri-devel,
freedreno, linux-kernel, devicetree
[-- Attachment #1: Type: text/plain, Size: 4787 bytes --]
On Thu, May 21, 2026 at 10:46:06PM +0800, Jun Nie wrote:
> Add support for the dual-panel system found in the virtual reality device.
> This system consists of two physical 2160x2160 panels, each connected via
> a MIPI DSI interface. The backlight is managed through DSI link.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> ---
> .../bindings/display/panel/synaptics,r63455.yaml | 125 +++++++++++++++++++++
> 1 file changed, 125 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml b/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml
> new file mode 100644
> index 0000000000000..a94b355ed9557
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml
> @@ -0,0 +1,125 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/panel/synaptics,r63455.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Synaptics R63455 based dual 2160x2160 MIPI-DSI Panel
> +
> +maintainers:
> + - Jun Nie <jun.nie@linaro.org>
> +
> +description:
> + Synaptics R63455 is a Virtual Reality Display Driver and VR Bridge, used in
> + pair in Headset devices. The Virtual Reality Display complex is composed of
> + two strictly identical display panels, each driven by its own DSI interface
> + but forms a single virtual display for the human eye perception and thus
> + requires a strict synchronization of the two display panel content update.
> +
> +allOf:
> + - $ref: panel-common.yaml#
> +
> +properties:
> + compatible:
> + items:
> + - enum:
> + - sharp,ls026b3sa06
> + - boe,vs026c4m-n52-6000
> + - const: synaptics,r63455
> +
> + reset-gpios:
> + maxItems: 2
> + description: 2 reset pins for 2 physical panels
> +
> + left-pos-supply:
> + description: Positive 5.7V supply for left panel
> +
> + right-pos-supply:
> + description: Positive 5.7V supply for right panel
> +
> + left-neg-supply:
> + description: Negative 5.7V supply for left panel
> +
> + right-neg-supply:
> + description: Negative 5.7V supply for right panel
> +
> + left-backlight-supply:
> + description: Backlight 21V supply for left panel
> +
> + right-backlight-supply:
> + description: Backlight 21V supply for right panel
> +
> + vdda-supply:
> + description: core 1.8V supply for panels
> +
> + ports: $ref: /schemas/graph.yaml#/properties/ports
Missing a newline in this, but also probably missing going into more
detail about the ports themselves.
Sashiko complaints look valid.
pw-bot: changes-requested
Thanks,
Conor.
> +
> +required:
> + - compatible
> + - reset-gpios
> + - left-pos-supply
> + - left-neg-supply
> + - right-pos-supply
> + - right-neg-supply
> + - left-backlight-supply
> + - right-backlight-supply
> + - vdda-supply
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/gpio/gpio.h>
> +
> + &mdss_dsi0 {
> + vdda-supply = <&vreg_l3i_1p2>;
> + status = "okay";
> +
> + qcom,dual-dsi-mode;
> + qcom,master-dsi;
> +
> + panel: panel@0 {
> + compatible = "sharp,ls026b3sa06", "synaptics,r63455";
> + reg = <0>;
> +
> + reset-gpios = <&pm8550_gpios 3 GPIO_ACTIVE_HIGH>,
> + <&pm8550_gpios 11 GPIO_ACTIVE_HIGH>;
> +
> + left-pos-supply = <&vpos_left>;
> + left-neg-supply = <&vneg_left>;
> + right-pos-supply = <&vpos_right>;
> + right-neg-supply = <&vneg_right>;
> + left-backlight-supply = <&backlight_left>;
> + right-backlight-supply = <&backlight_right>;
> +
> + vdda-supply = <&vreg_l12b_1p8>;
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + port@0 {
> + reg = <0>;
> + panel0_in: endpoint {
> + remote-endpoint = <&mdss_dsi0_out>;
> + };
> + };
> +
> + port@1 {
> + reg = <1>;
> + panel1_in: endpoint {
> + remote-endpoint = <&mdss_dsi1_out>;
> + };
> + };
> + };
> + };
> +
> + &mdss_dsi0_out {
> + remote-endpoint = <&panel0_in>;
> + data-lanes = <0 1 2>;
> + };
> +
> + &mdss_dsi1_out {
> + remote-endpoint = <&panel1_in>;
> + data-lanes = <0 1 2>;
> + };
> +...
>
> --
> 2.43.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support
2026-05-21 14:46 ` [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support Jun Nie
2026-05-21 19:45 ` Conor Dooley
@ 2026-05-21 20:24 ` Dmitry Baryshkov
2026-05-22 6:32 ` Neil Armstrong
2026-05-21 20:46 ` Rob Herring (Arm)
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
3 siblings, 1 reply; 16+ messages in thread
From: Dmitry Baryshkov @ 2026-05-21 20:24 UTC (permalink / raw)
To: Jun Nie
Cc: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Neil Armstrong, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-arm-msm, dri-devel, freedreno, linux-kernel, devicetree
On Thu, May 21, 2026 at 10:46:06PM +0800, Jun Nie wrote:
> Add support for the dual-panel system found in the virtual reality device.
> This system consists of two physical 2160x2160 panels, each connected via
> a MIPI DSI interface. The backlight is managed through DSI link.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> ---
> .../bindings/display/panel/synaptics,r63455.yaml | 125 +++++++++++++++++++++
> 1 file changed, 125 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml b/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml
> new file mode 100644
> index 0000000000000..a94b355ed9557
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml
> @@ -0,0 +1,125 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/panel/synaptics,r63455.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Synaptics R63455 based dual 2160x2160 MIPI-DSI Panel
> +
> +maintainers:
> + - Jun Nie <jun.nie@linaro.org>
> +
> +description:
> + Synaptics R63455 is a Virtual Reality Display Driver and VR Bridge, used in
> + pair in Headset devices. The Virtual Reality Display complex is composed of
> + two strictly identical display panels, each driven by its own DSI interface
> + but forms a single virtual display for the human eye perception and thus
> + requires a strict synchronization of the two display panel content update.
> +
> +allOf:
> + - $ref: panel-common.yaml#
> +
> +properties:
> + compatible:
> + items:
> + - enum:
> + - sharp,ls026b3sa06
> + - boe,vs026c4m-n52-6000
> + - const: synaptics,r63455
> +
> + reset-gpios:
> + maxItems: 2
> + description: 2 reset pins for 2 physical panels
> +
> + left-pos-supply:
> + description: Positive 5.7V supply for left panel
So, is the R63455 driving both panels or are there two panels, each
having R63455 controller? What if somebody gets a single Sharp panel and
wants to use it in their device? How will it match these bindings?
> +
> + right-pos-supply:
> + description: Positive 5.7V supply for right panel
> +
> + left-neg-supply:
> + description: Negative 5.7V supply for left panel
> +
> + right-neg-supply:
> + description: Negative 5.7V supply for right panel
> +
> + left-backlight-supply:
> + description: Backlight 21V supply for left panel
> +
> + right-backlight-supply:
> + description: Backlight 21V supply for right panel
> +
> + vdda-supply:
> + description: core 1.8V supply for panels
> +
> + ports: $ref: /schemas/graph.yaml#/properties/ports
> +
> +required:
> + - compatible
> + - reset-gpios
> + - left-pos-supply
> + - left-neg-supply
> + - right-pos-supply
> + - right-neg-supply
> + - left-backlight-supply
> + - right-backlight-supply
> + - vdda-supply
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/gpio/gpio.h>
> +
> + &mdss_dsi0 {
Please drop the MDSS specifics, there should be one (or two) DSI busses,
driving your panels. The rests are details which are not necessary for
the example.
> + vdda-supply = <&vreg_l3i_1p2>;
> + status = "okay";
> +
> + qcom,dual-dsi-mode;
> + qcom,master-dsi;
> +
> + panel: panel@0 {
> + compatible = "sharp,ls026b3sa06", "synaptics,r63455";
> + reg = <0>;
> +
> + reset-gpios = <&pm8550_gpios 3 GPIO_ACTIVE_HIGH>,
> + <&pm8550_gpios 11 GPIO_ACTIVE_HIGH>;
> +
> + left-pos-supply = <&vpos_left>;
> + left-neg-supply = <&vneg_left>;
> + right-pos-supply = <&vpos_right>;
> + right-neg-supply = <&vneg_right>;
> + left-backlight-supply = <&backlight_left>;
> + right-backlight-supply = <&backlight_right>;
> +
> + vdda-supply = <&vreg_l12b_1p8>;
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + port@0 {
> + reg = <0>;
> + panel0_in: endpoint {
> + remote-endpoint = <&mdss_dsi0_out>;
What is mdss_dsi0_out?
> + };
> + };
> +
> + port@1 {
> + reg = <1>;
> + panel1_in: endpoint {
> + remote-endpoint = <&mdss_dsi1_out>;
> + };
> + };
> + };
> + };
> +
> + &mdss_dsi0_out {
> + remote-endpoint = <&panel0_in>;
> + data-lanes = <0 1 2>;
> + };
> +
> + &mdss_dsi1_out {
> + remote-endpoint = <&panel1_in>;
> + data-lanes = <0 1 2>;
> + };
> +...
>
> --
> 2.43.0
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support
2026-05-21 14:46 ` [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support Jun Nie
2026-05-21 19:45 ` Conor Dooley
2026-05-21 20:24 ` Dmitry Baryshkov
@ 2026-05-21 20:46 ` Rob Herring (Arm)
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
3 siblings, 0 replies; 16+ messages in thread
From: Rob Herring (Arm) @ 2026-05-21 20:46 UTC (permalink / raw)
To: Jun Nie
Cc: Simona Vetter, Thomas Zimmermann, Krzysztof Kozlowski,
Marijn Suijten, Neil Armstrong, linux-kernel, devicetree,
linux-arm-msm, Dmitry Baryshkov, Rob Clark, Maxime Ripard,
dri-devel, Maarten Lankhorst, Jessica Zhang, Conor Dooley,
David Airlie, freedreno, Dmitry Baryshkov, Abhinav Kumar,
Sean Paul
On Thu, 21 May 2026 22:46:06 +0800, Jun Nie wrote:
> Add support for the dual-panel system found in the virtual reality device.
> This system consists of two physical 2160x2160 panels, each connected via
> a MIPI DSI interface. The backlight is managed through DSI link.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> ---
> .../bindings/display/panel/synaptics,r63455.yaml | 125 +++++++++++++++++++++
> 1 file changed, 125 insertions(+)
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
./Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml:26:9: [warning] wrong indentation: expected 10 but found 8 (indentation)
./Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml:55:14: [error] syntax error: mapping values are not allowed here (syntax)
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml: ignoring, error parsing file
./Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml:55:14: mapping values are not allowed here
make[2]: *** Deleting file 'Documentation/devicetree/bindings/display/panel/synaptics,r63455.example.dts'
Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml:55:14: mapping values are not allowed here
make[2]: *** [Documentation/devicetree/bindings/Makefile:26: Documentation/devicetree/bindings/display/panel/synaptics,r63455.example.dts] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1659: dt_binding_check] Error 2
make: *** [Makefile:248: __sub-make] Error 2
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20260521-sm8650-7-1-bonded-dsi-v4-4-a4dd5e0850f1@linaro.org
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support
2026-05-21 20:24 ` Dmitry Baryshkov
@ 2026-05-22 6:32 ` Neil Armstrong
0 siblings, 0 replies; 16+ messages in thread
From: Neil Armstrong @ 2026-05-22 6:32 UTC (permalink / raw)
To: Dmitry Baryshkov, Jun Nie
Cc: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-msm, dri-devel,
freedreno, linux-kernel, devicetree
On 5/21/26 22:24, Dmitry Baryshkov wrote:
> On Thu, May 21, 2026 at 10:46:06PM +0800, Jun Nie wrote:
>> Add support for the dual-panel system found in the virtual reality device.
>> This system consists of two physical 2160x2160 panels, each connected via
>> a MIPI DSI interface. The backlight is managed through DSI link.
>>
>> Signed-off-by: Jun Nie <jun.nie@linaro.org>
>> ---
>> .../bindings/display/panel/synaptics,r63455.yaml | 125 +++++++++++++++++++++
>> 1 file changed, 125 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml b/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml
>> new file mode 100644
>> index 0000000000000..a94b355ed9557
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/panel/synaptics,r63455.yaml
>> @@ -0,0 +1,125 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/display/panel/synaptics,r63455.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Synaptics R63455 based dual 2160x2160 MIPI-DSI Panel
>> +
>> +maintainers:
>> + - Jun Nie <jun.nie@linaro.org>
>> +
>> +description:
>> + Synaptics R63455 is a Virtual Reality Display Driver and VR Bridge, used in
>> + pair in Headset devices. The Virtual Reality Display complex is composed of
>> + two strictly identical display panels, each driven by its own DSI interface
>> + but forms a single virtual display for the human eye perception and thus
>> + requires a strict synchronization of the two display panel content update.
>> +
>> +allOf:
>> + - $ref: panel-common.yaml#
>> +
>> +properties:
>> + compatible:
>> + items:
>> + - enum:
>> + - sharp,ls026b3sa06
>> + - boe,vs026c4m-n52-6000
>> + - const: synaptics,r63455
>> +
>> + reset-gpios:
>> + maxItems: 2
>> + description: 2 reset pins for 2 physical panels
>> +
>> + left-pos-supply:
>> + description: Positive 5.7V supply for left panel
>
> So, is the R63455 driving both panels or are there two panels, each
> having R63455 controller? What if somebody gets a single Sharp panel and
> wants to use it in their device? How will it match these bindings?
It's highly improbable, those are very specialized panels that are designed
for xr usage in pair. Yes a hobbyist could try to use a single panel
but it's only usable when placed close to an eye, and barely useless if you
don't have both eyes.
Let's skip highly improbable use-cases and focus on the main use case of the
hardware device.
>
>> +
>> + right-pos-supply:
>> + description: Positive 5.7V supply for right panel
>> +
>> + left-neg-supply:
>> + description: Negative 5.7V supply for left panel
>> +
>> + right-neg-supply:
>> + description: Negative 5.7V supply for right panel
>> +
>> + left-backlight-supply:
>> + description: Backlight 21V supply for left panel
>> +
>> + right-backlight-supply:
>> + description: Backlight 21V supply for right panel
>> +
>> + vdda-supply:
>> + description: core 1.8V supply for panels
>> +
>> + ports: $ref: /schemas/graph.yaml#/properties/ports
>> +
>> +required:
>> + - compatible
>> + - reset-gpios
>> + - left-pos-supply
>> + - left-neg-supply
>> + - right-pos-supply
>> + - right-neg-supply
>> + - left-backlight-supply
>> + - right-backlight-supply
>> + - vdda-supply
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/gpio/gpio.h>
>> +
>> + &mdss_dsi0 {
>
> Please drop the MDSS specifics, there should be one (or two) DSI busses,
> driving your panels. The rests are details which are not necessary for
> the example.
>
>> + vdda-supply = <&vreg_l3i_1p2>;
>> + status = "okay";
>> +
>> + qcom,dual-dsi-mode;
>> + qcom,master-dsi;
>> +
>> + panel: panel@0 {
>> + compatible = "sharp,ls026b3sa06", "synaptics,r63455";
>> + reg = <0>;
>> +
>> + reset-gpios = <&pm8550_gpios 3 GPIO_ACTIVE_HIGH>,
>> + <&pm8550_gpios 11 GPIO_ACTIVE_HIGH>;
>> +
>> + left-pos-supply = <&vpos_left>;
>> + left-neg-supply = <&vneg_left>;
>> + right-pos-supply = <&vpos_right>;
>> + right-neg-supply = <&vneg_right>;
>> + left-backlight-supply = <&backlight_left>;
>> + right-backlight-supply = <&backlight_right>;
>> +
>> + vdda-supply = <&vreg_l12b_1p8>;
>> +
>> + ports {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + port@0 {
>> + reg = <0>;
>> + panel0_in: endpoint {
>> + remote-endpoint = <&mdss_dsi0_out>;
>
> What is mdss_dsi0_out?
>
>> + };
>> + };
>> +
>> + port@1 {
>> + reg = <1>;
>> + panel1_in: endpoint {
>> + remote-endpoint = <&mdss_dsi1_out>;
>> + };
>> + };
>> + };
>> + };
>> +
>> + &mdss_dsi0_out {
>> + remote-endpoint = <&panel0_in>;
>> + data-lanes = <0 1 2>;
>> + };
>> +
>> + &mdss_dsi1_out {
>> + remote-endpoint = <&panel1_in>;
>> + data-lanes = <0 1 2>;
>> + };
>> +...
>>
>> --
>> 2.43.0
>>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: Add support to 2 panels in bonded-DSI mode
2026-05-21 14:46 [PATCH v4 0/5] Add support to 2 panels in bonded-DSI mode Jun Nie
` (4 preceding siblings ...)
2026-05-21 14:46 ` [PATCH v4 5/5] drm/panel: Add driver for Synaptics R63455 DSI panel Jun Nie
@ 2026-05-25 10:00 ` Claude Code Review Bot
5 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-05-25 10:00 UTC (permalink / raw)
To: dri-devel-reviews
Overall Series Review
Subject: Add support to 2 panels in bonded-DSI mode
Author: Jun Nie <jun.nie@linaro.org>
Patches: 10
Reviewed: 2026-05-25T20:00:01.551184
---
This v4 series adds support for driving two independent physical DSI panels in bonded-DSI mode from a single CRTC, targeting VR headset use cases (left/right eye panels). It touches the MSM DSI host driver to support `slice_per_pkt > 1` for DSC and dual-panel frame width halving, adds a `dual_panel` flag to the core MIPI DSI struct, introduces a new DT binding, and adds a panel driver for the Synaptics R63455.
The overall architecture — having the panel driver register the second DSI device and set `dual_panel` so the host halves the frame — is reasonable, though several issues need attention before this can be merged:
1. **Build breakage**: The panel driver uses `backlight_properties.pulse_offset_rows`, which does not exist in the kernel backlight struct. This will fail to compile.
2. **`dsc_slice_per_pkt` placement**: Adding a non-standard field to `struct drm_dsc_config` (a struct that maps to the DSC standard parameter set) is debatable and needs DRM maintainer buy-in.
3. **Missing division-by-zero guard**: `dsc_slice_per_pkt` is used as a divisor without validation.
4. **DT binding issues**: YAML schema errors and questionable use of vendor-prefixed supply names instead of generic ones.
5. **Panel driver quality**: Uses deprecated API (`of_device_get_match_data`), includes an unused header, and has error-handling gaps.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/msm/dsi: support DSC configurations with slice_per_pkt > 1
2026-05-21 14:46 ` [PATCH v4 1/5] drm/msm/dsi: support DSC configurations with slice_per_pkt > 1 Jun Nie
@ 2026-05-25 10:00 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-05-25 10:00 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Concept**: Replaces the hardcoded `slice_per_pkt = 1` assumption in the MSM DSI host with support for configurable values. A `dsc_slice_per_pkt` field is added to `struct drm_dsc_config`.
**Issues:**
1. **Division by zero risk**: In `dsi_update_dsc_timing()`, the new code does:
```c
pkt_per_line = slice_per_intf / msm_host->dsc_slice_per_pkt;
```
If `dsc_slice_per_pkt` is 0 (e.g. a panel driver that sets `dsc` but doesn't set this new field, and the `?: 1` fallback in `dsi_host_attach` is somehow bypassed or a different code path sets the DSC config), this is an OOPS. The fallback at attach time (`dsi->dsc->dsc_slice_per_pkt ?: 1`) is good but fragile — consider also clamping or validating in `dsi_update_dsc_timing` itself.
2. **Questionable placement in `drm_dsc_config`**: The comment says "This is not part of DSC standard, and only used in some DSI panels so far." Adding transport-layer packetization config to a struct representing the DSC standard parameter set conflates concerns. The existing `msm_dsi_host` already has a local `dsc_slice_per_pkt` field — you could keep it purely there, and pass it from `mipi_dsi_device` via a separate field rather than polluting `drm_dsc_config`. This needs buy-in from DRM core maintainers (Maxime, Thomas, etc.).
3. **Naming redundancy**: The field is called `dsc_slice_per_pkt` inside `struct drm_dsc_config`. Since it's already in a `dsc` struct, just `slice_per_pkt` would be sufficient and consistent with how other fields like `slice_count`, `slice_width` etc. are named.
4. **The `pkt_per_line` log2 encoding check**: The existing code at line 964 warns if `pkt_per_line > 4` because the register field is log2-encoded and only supports 1, 2, 4. With `slice_per_pkt > 1`, `pkt_per_line` can now be smaller (e.g., 4 slices / 4 slice_per_pkt = 1), but there's no validation that `slice_per_intf` is evenly divisible by `dsc_slice_per_pkt`, which could give non-power-of-2 results.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/mipi-dsi: Add flag to support dual-panel configurations
2026-05-21 14:46 ` [PATCH v4 2/5] drm/mipi-dsi: Add flag to support dual-panel configurations Jun Nie
@ 2026-05-25 10:00 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-05-25 10:00 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Concept**: Adds a `bool dual_panel` to `struct mipi_dsi_device` so a panel driver can signal the DSI host that it's part of a dual-panel setup.
**Issues:**
1. **Generic name, MSM-specific semantics**: The field is added to the core DRM MIPI DSI header (`include/drm/drm_mipi_dsi.h`), making it part of the cross-driver API. However, only the MSM DSI host consumes it. The commit message describes very MSM-specific behavior (bonded-DSI, shared clock from DSI0 PHY). Other DSI host drivers won't understand this flag. If the intent is for this to be a generic DRM concept, the semantics need proper documentation and potentially discussion on dri-devel about what "dual_panel" means generically vs. bonded DSI.
2. **No documentation of expected behavior**: The field lacks a kerneldoc description of what a host driver should *do* when it sees this flag set. The commit message talks about halving horizontal timings, but that's buried in the cover letter and patch 3, not in the header.
3. **Name ambiguity**: `dual_panel` could mean many things — two panels on different CRTCs, a dual-scan panel, etc. Something like `bonded_panel` or `is_bonded_dsi_panel` would be clearer about the intended semantics.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/msm/dsi: Support dual panel use case with single CRTC
2026-05-21 14:46 ` [PATCH v4 3/5] drm/msm/dsi: Support dual panel use case with single CRTC Jun Nie
@ 2026-05-25 10:00 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-05-25 10:00 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Concept**: When `is_dual_panel` is set, halves `dsc->pic_width` and `pic_width` in check_dsc so the DSI host configures DSC for a single panel's width.
**Issues:**
1. **Correct fix for `dsc->pic_width`**: In `dsi_timing_setup()`, the existing code (line 1033 upstream) sets `dsc->pic_width = mode->hdisplay`, which is indeed wrong for bonded DSI since `mode->hdisplay` is the full doubled width. The patch changes this to use `hdisplay` (the local variable), which is correct for bonded DSI (`hdisplay` was already halved on line 1019). However, the patch uses `msm_host->is_dual_panel` to decide, while the existing `is_bonded_dsi` parameter already covers this case. This creates two overlapping concepts:
- `is_bonded_dsi`: the existing bonded DSI path (already halves timings)
- `is_dual_panel`: the new dual-panel path
The patch only sets `dsc->pic_width = hdisplay` when `is_dual_panel` is true, but `hdisplay` has already been halved for `is_bonded_dsi` as well. So for the existing bonded-DSI-with-single-panel case, `dsc->pic_width` is still set to `mode->hdisplay` (the full width), which appears to be a pre-existing bug that this patch doesn't fix. The relationship between these two flags needs clarification.
2. **`msm_dsi_host_check_dsc` fix is incomplete**: The patch adds:
```c
if (msm_host->is_dual_panel)
pic_width = mode->hdisplay / 2;
```
But `pic_width` was already initialized to `mode->hdisplay` on the previous line. The fix works but note that `is_bonded_dsi` (the existing bonded DSI flag, not dual_panel) also requires halving for the pre-existing single-panel bonded case. This function currently has no concept of `is_bonded_dsi` at all, which may be an existing limitation.
3. **Commit message typo**: "togehter" → "together" in line "While the DSI panel driver should manage two panels togehter."
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: dt-bindings: display: Add Synaptics R63455 panel support
2026-05-21 14:46 ` [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support Jun Nie
` (2 preceding siblings ...)
2026-05-21 20:46 ` Rob Herring (Arm)
@ 2026-05-25 10:00 ` Claude Code Review Bot
3 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-05-25 10:00 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Concept**: DT binding for a dual-panel VR display driven by Synaptics R63455 controllers.
**Issues:**
1. **YAML schema error in `ports`**: The line:
```yaml
ports: $ref: /schemas/graph.yaml#/properties/ports
```
This is incorrect YAML syntax. It should be:
```yaml
ports:
$ref: /schemas/graph.yaml#/properties/ports
```
2. **Non-standard supply naming**: Using `left-pos-supply`, `right-neg-supply`, etc. is unusual. DT bindings typically use generic supply names or names derived from the chip's pin names (e.g., `vpos-left-supply`). The `left-`/`right-` prefix convention isn't established in existing bindings. DT maintainers may push back on this.
3. **Missing port definitions**: The `ports` property references the graph schema but doesn't define `port@0` and `port@1` with their own descriptions within the schema, so the binding doesn't actually constrain or document which ports exist.
4. **Example has syntax issues**: The example DT uses `&mdss_dsi0 { ... }` overlay syntax with missing closing braces. The `};` for the `panel@0` node appears to close at the wrong level (the `};` on line 972 closes the ports node, but the panel node itself is not properly closed before `&mdss_dsi0_out`). This would fail `dt_binding_check`.
5. **`data-lanes` in example**: The example shows `data-lanes = <0 1 2>;` (3 lanes), which matches the panel driver, but this property isn't defined in the binding schema itself.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
* Claude review: drm/panel: Add driver for Synaptics R63455 DSI panel
2026-05-21 14:46 ` [PATCH v4 5/5] drm/panel: Add driver for Synaptics R63455 DSI panel Jun Nie
@ 2026-05-25 10:00 ` Claude Code Review Bot
0 siblings, 0 replies; 16+ messages in thread
From: Claude Code Review Bot @ 2026-05-25 10:00 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**Concept**: Panel driver managing two R63455-based panels as a single logical display for VR.
**Issues:**
1. **Build breakage — `pulse_offset_rows` does not exist**: The code uses:
```c
ctx->backlight->props.pulse_offset_rows = GPO1_TES1;
```
and in `r63455_bl_update_status`:
```c
bl->props.pulse_offset_rows
```
The field `pulse_offset_rows` does not exist in `struct backlight_properties` in the kernel. This will not compile. It appears to be a custom extension that was never submitted upstream, or a leftover from an out-of-tree tree. The brightness-related pulse timing should likely be handled within the panel driver directly rather than via backlight properties.
2. **Deprecated API — `of_device_get_match_data`**: Line:
```c
ctx->dsi_init_seq = of_device_get_match_data(dev);
```
Should use `device_get_match_data(dev)` instead. `of_device_get_match_data` is deprecated in favor of the bus-agnostic version.
3. **Missing `IS_ERR` check after `devm_drm_panel_alloc`**: The probe function does:
```c
ctx = devm_drm_panel_alloc(&dsi->dev, __typeof(*ctx), panel,
&r63455_drm_funcs, DRM_MODE_CONNECTOR_DSI);
ctx->dsi_init_seq = of_device_get_match_data(dev);
```
There's no `IS_ERR(ctx)` check. `devm_drm_panel_alloc` can return `ERR_PTR(-ENOMEM)`, which would cause a NULL-pointer dereference on the next line.
4. **Unused header**: `#include <linux/of_device.h>` — with the switch to `device_get_match_data()`, this would be unnecessary. Even with `of_device_get_match_data`, this header is largely deprecated in favor of `<linux/property.h>`.
5. **Unused header**: `#include <linux/pinctrl/consumer.h>` — the driver doesn't use any pinctrl APIs.
6. **`LE16_BYTE0`/`LE16_BYTE1` and `BE16_BYTE0`/`BE16_BYTE1` macros are confusing**: These macros take a `val` that is a plain integer constant (e.g., `VBP = 100`), then call `le16_to_cpu()` or `be16_to_cpu()` on it. Since the input is a host-endian constant (not actually little- or big-endian data), this is incorrect usage of endian conversion functions. On little-endian ARM, `le16_to_cpu(100)` happens to be a no-op and `be16_to_cpu(100)` byte-swaps, but the semantic is wrong. These should just use plain shift/mask operations: `(val & 0xff)` and `((val >> 8) & 0xff)`.
7. **Error handling in `r63455_unprepare`**: The function continues disabling regulators even after errors, which is reasonable for cleanup, but it only returns the *last* error code. If `reg_lcd_bias_neg` disable fails but `reg_bl` disable succeeds, the error from `reg_lcd_bias_neg` is lost.
8. **No `remove` or cleanup for `dsi1_device`**: In probe, `mipi_dsi_device_register_full()` is called to create `dsi1_device`, but there's no corresponding `mipi_dsi_device_unregister()` in an error path or remove callback. Since only `devm_mipi_dsi_attach` is used (which handles detach), the device registration itself leaks on driver unbind. Consider using `devm_mipi_dsi_device_register_full()` if available, or adding cleanup.
9. **Function name typo**: `r63455_panel_on_boe_vs026c4m_n52_26000` — the compatible string is `boe,vs026c4m-n52-6000`, but the function name has `26000` (an extra `2`).
10. **`of_graph_get_remote_node` returns a reference**: Line:
```c
dsi1 = of_graph_get_remote_node(dsi->dev.of_node, 1, -1);
```
The `of_node_put(dsi1)` is correctly called a few lines later, but if `of_find_mipi_dsi_host_by_node` fails and returns `-EPROBE_DEFER`, the function returns without any issue. This is fine. However, `dsi1` is used as the node to find the host, but the host's node is the *parent* of the endpoint — `of_graph_get_remote_node` returns the remote port's parent device node, which should be correct for `of_find_mipi_dsi_host_by_node`. This looks correct.
11. **Mode `.clock` computation**: The clock calculation:
```c
.clock = (2160 + 24 + 20 + 20) * (2160 + 404 + 1 + 20) * 120 * 2 / 1000,
```
The `* 2` is for the doubled horizontal resolution. The result is `(2224) * (2585) * 120 * 2 / 1000 = 1,380,787.2` → truncated to `1380787` kHz (~1.38 GHz pixel clock). This seems extremely high for a DSI link but may be correct for a compressed/DSC mode. Worth double-checking.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-05-25 10:00 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-21 14:46 [PATCH v4 0/5] Add support to 2 panels in bonded-DSI mode Jun Nie
2026-05-21 14:46 ` [PATCH v4 1/5] drm/msm/dsi: support DSC configurations with slice_per_pkt > 1 Jun Nie
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
2026-05-21 14:46 ` [PATCH v4 2/5] drm/mipi-dsi: Add flag to support dual-panel configurations Jun Nie
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
2026-05-21 14:46 ` [PATCH v4 3/5] drm/msm/dsi: Support dual panel use case with single CRTC Jun Nie
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
2026-05-21 14:46 ` [PATCH v4 4/5] dt-bindings: display: Add Synaptics R63455 panel support Jun Nie
2026-05-21 19:45 ` Conor Dooley
2026-05-21 20:24 ` Dmitry Baryshkov
2026-05-22 6:32 ` Neil Armstrong
2026-05-21 20:46 ` Rob Herring (Arm)
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
2026-05-21 14:46 ` [PATCH v4 5/5] drm/panel: Add driver for Synaptics R63455 DSI panel Jun Nie
2026-05-25 10:00 ` Claude review: " Claude Code Review Bot
2026-05-25 10:00 ` Claude review: Add support to 2 panels in bonded-DSI mode Claude Code Review Bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox