Commit d0d72774 authored by Luca Ceresoli's avatar Luca Ceresoli
Browse files

drm/bridge: ti-sn65dsi83: halve horizontal syncs for dual LVDS output

Dual LVDS output (available on the SN65DSI84) requires HSYNC_PULSE_WIDTH
and HORIZONTAL_BACK_PORCH to be divided by two with respect to the values
used for single LVDS output.

While not clearly stated in the datasheet, this is needed according to the
DSI Tuner [0] output. It also makes sense intuitively because in dual LVDS
output two pixels at a time are output and so the output clock is half of
the pixel clock.

Some dual-LVDS panels refuse to show any picture without this fix.

Divide by two HORIZONTAL_FRONT_PORCH too, even though this register is used
only for test pattern generation which is not currently implemented by this
driver.

[0] https://www.ti.com/tool/DSI-TUNER



Fixes: ceb515ba ("drm/bridge: ti-sn65dsi83: Add TI SN65DSI83 and SN65DSI84 driver")
Cc: stable@vger.kernel.org
Reviewed-by: default avatarMarek Vasut <marek.vasut@mailbox.org>
Link: https://patch.msgid.link/20260226-ti-sn65dsi83-dual-lvds-fixes-and-test-pattern-v1-2-2e15f5a9a6a0@bootlin.com


Signed-off-by: default avatarLuca Ceresoli <luca.ceresoli@bootlin.com>
parent 2f22702d
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -517,6 +517,7 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
					struct drm_atomic_state *state)
{
	struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
	const unsigned int dual_factor = ctx->lvds_dual_link ? 2 : 1;
	const struct drm_bridge_state *bridge_state;
	const struct drm_crtc_state *crtc_state;
	const struct drm_display_mode *mode;
@@ -653,18 +654,18 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
	/* 32 + 1 pixel clock to ensure proper operation */
	le16val = cpu_to_le16(32 + 1);
	regmap_bulk_write(ctx->regmap, REG_VID_CHA_SYNC_DELAY_LOW, &le16val, 2);
	le16val = cpu_to_le16(mode->hsync_end - mode->hsync_start);
	le16val = cpu_to_le16((mode->hsync_end - mode->hsync_start) / dual_factor);
	regmap_bulk_write(ctx->regmap, REG_VID_CHA_HSYNC_PULSE_WIDTH_LOW,
			  &le16val, 2);
	le16val = cpu_to_le16(mode->vsync_end - mode->vsync_start);
	regmap_bulk_write(ctx->regmap, REG_VID_CHA_VSYNC_PULSE_WIDTH_LOW,
			  &le16val, 2);
	regmap_write(ctx->regmap, REG_VID_CHA_HORIZONTAL_BACK_PORCH,
		     mode->htotal - mode->hsync_end);
		     (mode->htotal - mode->hsync_end) / dual_factor);
	regmap_write(ctx->regmap, REG_VID_CHA_VERTICAL_BACK_PORCH,
		     mode->vtotal - mode->vsync_end);
	regmap_write(ctx->regmap, REG_VID_CHA_HORIZONTAL_FRONT_PORCH,
		     mode->hsync_start - mode->hdisplay);
		     (mode->hsync_start - mode->hdisplay) / dual_factor);
	regmap_write(ctx->regmap, REG_VID_CHA_VERTICAL_FRONT_PORCH,
		     mode->vsync_start - mode->vdisplay);
	regmap_write(ctx->regmap, REG_VID_CHA_TEST_PATTERN, 0x00);