[PATCH 1/2] drm/bridge: ti-sn65dsi83: Support LVDS Channel B on SN65DSI84

From: Esben Haabendal

Date: Sat Jul 11 2026 - 07:52:00 EST


This adds support for using SN65DSI84 in single-link mode with output to
LVDS Channel B.

Signed-off-by: Esben Haabendal <esben@xxxxxxxxxx>
---
drivers/gpu/drm/bridge/ti-sn65dsi83.c | 36 ++++++++++++++++++++++++-----------
1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 42b451432bbb..32e9eadd7452 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -11,6 +11,8 @@
* = 1x Single-link DSI ~ 2x Single-link or 1x Dual-link LVDS
* - Supported
* - Dual-link LVDS mode tested
+ * - Single-link to LVDS Channel A tested.
+ * - Single-link to LVDS Channel B tested.
* - 2x Single-link LVDS mode unsupported
* (should be easy to add by someone who has the HW)
* - SN65DSI85
@@ -162,7 +164,7 @@ struct sn65dsi83 {
struct gpio_desc *enable_gpio;
struct regulator *vcc;
bool lvds_dual_link;
- bool lvds_dual_link_even_odd_swap;
+ bool lvds_channel_swap;
int lvds_vod_swing_conf[2];
int lvds_term_conf[2];
int irq;
@@ -642,7 +644,7 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
REG_LVDS_VCOM_CHA_LVDS_VOD_SWING(ctx->lvds_vod_swing_conf[CHANNEL_A]) |
REG_LVDS_VCOM_CHB_LVDS_VOD_SWING(ctx->lvds_vod_swing_conf[CHANNEL_B]));
regmap_write(ctx->regmap, REG_LVDS_LANE,
- (ctx->lvds_dual_link_even_odd_swap ?
+ (ctx->lvds_channel_swap ?
REG_LVDS_LANE_EVEN_ODD_SWAP : 0) |
(ctx->lvds_term_conf[CHANNEL_A] ?
REG_LVDS_LANE_CHA_LVDS_TERM : 0) |
@@ -893,6 +895,7 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model)
{
struct drm_bridge *panel_bridge;
struct device *dev = ctx->dev;
+ u32 panel_port = 2;
int ret;

ret = sn65dsi83_parse_lvds_endpoint(ctx, CHANNEL_A);
@@ -904,29 +907,40 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model)
return ret;

ctx->lvds_dual_link = false;
- ctx->lvds_dual_link_even_odd_swap = false;
+ ctx->lvds_channel_swap = false;
if (model != MODEL_SN65DSI83) {
- struct device_node *port2, *port3;
+ struct device_node *port0, *port1, *port2, *port3;
int dual_link;

+ port0 = of_graph_get_port_by_id(dev->of_node, 0);
+ port1 = of_graph_get_port_by_id(dev->of_node, 1);
port2 = of_graph_get_port_by_id(dev->of_node, 2);
port3 = of_graph_get_port_by_id(dev->of_node, 3);
dual_link = drm_of_lvds_get_dual_link_pixel_order(port2, port3);
- of_node_put(port2);
- of_node_put(port3);

if (dual_link == DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS) {
- ctx->lvds_dual_link = true;
/* Odd pixels to LVDS Channel A, even pixels to B */
- ctx->lvds_dual_link_even_odd_swap = false;
- } else if (dual_link == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS) {
ctx->lvds_dual_link = true;
+ } else if (dual_link == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS) {
/* Even pixels to LVDS Channel A, odd pixels to B */
- ctx->lvds_dual_link_even_odd_swap = true;
+ ctx->lvds_dual_link = true;
+ ctx->lvds_channel_swap = true;
+ } else if (port0 && !port1 && port2 && !port3) {
+ /* DSI Channel A to LVDS Channel A */
+ pr_warn("%s: DSI Channel A to LVDS Channel A\n", __func__);
+ } else if (port0 && !port1 && !port2 && port3) {
+ /* DSI Channel A to LVDS Channel B */
+ pr_warn("%s: DSI Channel A to LVDS Channel B\n", __func__);
+ ctx->lvds_channel_swap = true;
+ panel_port = 3;
}
+ of_node_put(port0);
+ of_node_put(port1);
+ of_node_put(port2);
+ of_node_put(port3);
}

- panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 2, 0);
+ panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, panel_port, 0);
if (IS_ERR(panel_bridge))
return dev_err_probe(dev, PTR_ERR(panel_bridge), "Failed to get panel bridge\n");


--
2.55.0