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

Signed-off-by: Esben Haabendal <es...@geanix.com>
---
 drivers/gpu/drm/bridge/ti-sn65dsi83.c | 34 +++++++++++++++++++++++-----------
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c 
b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 
95563aa1b450d549be8cacbe58c45f07b93595e5..e5785447c804eeced24f80c2b8b90283623c86a9
 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
@@ -158,7 +160,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;
@@ -587,7 +589,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) |
@@ -834,6 +836,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);
@@ -845,29 +848,38 @@ 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 */
+               } else if (port0 && !port1 && !port2 && port3) {
+                       /* DSI Channel A to LVDS Channel B */
+                       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");
 

---
base-commit: b4432656b36e5cc1d50a1f2dc15357543add530e
change-id: 20250430-sn65dsi83-channel-swap-f73afc78ace8

Best regards,
-- 
Esben Haabendal <es...@geanix.com>

Reply via email to