Skip to content

Commit 9fc75c4

Browse files
tombarobertfoss
authored andcommitted
drm/bridge: tc358768: Attempt to fix DSI horizontal timings
The DSI horizontal timing calculations done by the driver seem to often lead to underflows or overflows, depending on the videomode. There are two main things the current driver doesn't seem to get right: DSI HSW and HFP, and VSDly. However, even following Toshiba's documentation it seems we don't always get a working display. This patch attempts to fix the horizontal timings for DSI event mode, and on a system with a DSI->HDMI encoder, a lot of standard HDMI modes now seem to work. The work relies on Toshiba's documentation, but also quite a bit on empirical testing. This also adds timing related debug prints to make it easier to improve on this later. The DSI pulse mode has only been tested with a fixed-resolution panel, which limits the testing of different modes on DSI pulse mode. However, as the VSDly calculation also affects pulse mode, so this might cause a regression. Reviewed-by: Peter Ujfalusi <peter.ujfalusi@gmail.com> Tested-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> Tested-by: Maxim Schwalm <maxim.schwalm@gmail.com> # Asus TF700T Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Signed-off-by: Robert Foss <rfoss@kernel.org> Link: https://patchwork.freedesktop.org/patch/msgid/20230906-tc358768-v4-12-31725f008a50@ideasonboard.com
1 parent f1dabbe commit 9fc75c4

File tree

1 file changed

+185
-28
lines changed

1 file changed

+185
-28
lines changed

drivers/gpu/drm/bridge/tc358768.c

Lines changed: 185 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/gpio/consumer.h>
1010
#include <linux/i2c.h>
1111
#include <linux/kernel.h>
12+
#include <linux/math64.h>
1213
#include <linux/media-bus-format.h>
1314
#include <linux/minmax.h>
1415
#include <linux/module.h>
@@ -157,6 +158,7 @@ struct tc358768_priv {
157158
u32 frs; /* PLL Freqency range for HSCK (post divider) */
158159

159160
u32 dsiclk; /* pll_clk / 2 */
161+
u32 pclk; /* incoming pclk rate */
160162
};
161163

162164
static inline struct tc358768_priv *dsi_host_to_tc358768(struct mipi_dsi_host
@@ -380,6 +382,7 @@ static int tc358768_calc_pll(struct tc358768_priv *priv,
380382
priv->prd = best_prd;
381383
priv->frs = frs;
382384
priv->dsiclk = best_pll / 2;
385+
priv->pclk = mode->clock * 1000;
383386

384387
return 0;
385388
}
@@ -638,6 +641,28 @@ static u32 tc358768_ps_to_ns(u32 ps)
638641
return ps / 1000;
639642
}
640643

644+
static u32 tc358768_dpi_to_ns(u32 val, u32 pclk)
645+
{
646+
return (u32)div_u64((u64)val * NANO, pclk);
647+
}
648+
649+
/* Convert value in DPI pixel clock units to DSI byte count */
650+
static u32 tc358768_dpi_to_dsi_bytes(struct tc358768_priv *priv, u32 val)
651+
{
652+
u64 m = (u64)val * priv->dsiclk / 4 * priv->dsi_lanes;
653+
u64 n = priv->pclk;
654+
655+
return (u32)div_u64(m + n - 1, n);
656+
}
657+
658+
static u32 tc358768_dsi_bytes_to_ns(struct tc358768_priv *priv, u32 val)
659+
{
660+
u64 m = (u64)val * NANO;
661+
u64 n = priv->dsiclk / 4 * priv->dsi_lanes;
662+
663+
return (u32)div_u64(m, n);
664+
}
665+
641666
static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
642667
{
643668
struct tc358768_priv *priv = bridge_to_tc358768(bridge);
@@ -647,11 +672,19 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
647672
s32 raw_val;
648673
const struct drm_display_mode *mode;
649674
u32 hsbyteclk_ps, dsiclk_ps, ui_ps;
650-
u32 dsiclk, hsbyteclk, video_start;
651-
const u32 internal_delay = 40;
675+
u32 dsiclk, hsbyteclk;
652676
int ret, i;
653677
struct videomode vm;
654678
struct device *dev = priv->dev;
679+
/* In pixelclock units */
680+
u32 dpi_htot, dpi_data_start;
681+
/* In byte units */
682+
u32 dsi_dpi_htot, dsi_dpi_data_start;
683+
u32 dsi_hsw, dsi_hbp, dsi_hact, dsi_hfp;
684+
const u32 dsi_hss = 4; /* HSS is a short packet (4 bytes) */
685+
/* In hsbyteclk units */
686+
u32 dsi_vsdly;
687+
const u32 internal_dly = 40;
655688

656689
if (mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
657690
dev_warn_once(dev, "Non-continuous mode unimplemented, falling back to continuous\n");
@@ -686,27 +719,23 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
686719
case MIPI_DSI_FMT_RGB888:
687720
val |= (0x3 << 4);
688721
hact = vm.hactive * 3;
689-
video_start = (vm.hsync_len + vm.hback_porch) * 3;
690722
data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
691723
break;
692724
case MIPI_DSI_FMT_RGB666:
693725
val |= (0x4 << 4);
694726
hact = vm.hactive * 3;
695-
video_start = (vm.hsync_len + vm.hback_porch) * 3;
696727
data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
697728
break;
698729

699730
case MIPI_DSI_FMT_RGB666_PACKED:
700731
val |= (0x4 << 4) | BIT(3);
701732
hact = vm.hactive * 18 / 8;
702-
video_start = (vm.hsync_len + vm.hback_porch) * 18 / 8;
703733
data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
704734
break;
705735

706736
case MIPI_DSI_FMT_RGB565:
707737
val |= (0x5 << 4);
708738
hact = vm.hactive * 2;
709-
video_start = (vm.hsync_len + vm.hback_porch) * 2;
710739
data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
711740
break;
712741
default:
@@ -716,9 +745,152 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
716745
return;
717746
}
718747

748+
/*
749+
* There are three important things to make TC358768 work correctly,
750+
* which are not trivial to manage:
751+
*
752+
* 1. Keep the DPI line-time and the DSI line-time as close to each
753+
* other as possible.
754+
* 2. TC358768 goes to LP mode after each line's active area. The DSI
755+
* HFP period has to be long enough for entering and exiting LP mode.
756+
* But it is not clear how to calculate this.
757+
* 3. VSDly (video start delay) has to be long enough to ensure that the
758+
* DSI TX does not start transmitting until we have started receiving
759+
* pixel data from the DPI input. It is not clear how to calculate
760+
* this either.
761+
*/
762+
763+
dpi_htot = vm.hactive + vm.hfront_porch + vm.hsync_len + vm.hback_porch;
764+
dpi_data_start = vm.hsync_len + vm.hback_porch;
765+
766+
dev_dbg(dev, "dpi horiz timing (pclk): %u + %u + %u + %u = %u\n",
767+
vm.hsync_len, vm.hback_porch, vm.hactive, vm.hfront_porch,
768+
dpi_htot);
769+
770+
dev_dbg(dev, "dpi horiz timing (ns): %u + %u + %u + %u = %u\n",
771+
tc358768_dpi_to_ns(vm.hsync_len, vm.pixelclock),
772+
tc358768_dpi_to_ns(vm.hback_porch, vm.pixelclock),
773+
tc358768_dpi_to_ns(vm.hactive, vm.pixelclock),
774+
tc358768_dpi_to_ns(vm.hfront_porch, vm.pixelclock),
775+
tc358768_dpi_to_ns(dpi_htot, vm.pixelclock));
776+
777+
dev_dbg(dev, "dpi data start (ns): %u + %u = %u\n",
778+
tc358768_dpi_to_ns(vm.hsync_len, vm.pixelclock),
779+
tc358768_dpi_to_ns(vm.hback_porch, vm.pixelclock),
780+
tc358768_dpi_to_ns(dpi_data_start, vm.pixelclock));
781+
782+
dsi_dpi_htot = tc358768_dpi_to_dsi_bytes(priv, dpi_htot);
783+
dsi_dpi_data_start = tc358768_dpi_to_dsi_bytes(priv, dpi_data_start);
784+
785+
if (dsi_dev->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
786+
dsi_hsw = tc358768_dpi_to_dsi_bytes(priv, vm.hsync_len);
787+
dsi_hbp = tc358768_dpi_to_dsi_bytes(priv, vm.hback_porch);
788+
} else {
789+
/* HBP is included in HSW in event mode */
790+
dsi_hbp = 0;
791+
dsi_hsw = tc358768_dpi_to_dsi_bytes(priv,
792+
vm.hsync_len +
793+
vm.hback_porch);
794+
795+
/*
796+
* The pixel packet includes the actual pixel data, and:
797+
* DSI packet header = 4 bytes
798+
* DCS code = 1 byte
799+
* DSI packet footer = 2 bytes
800+
*/
801+
dsi_hact = hact + 4 + 1 + 2;
802+
803+
dsi_hfp = dsi_dpi_htot - dsi_hact - dsi_hsw - dsi_hss;
804+
805+
/*
806+
* Here we should check if HFP is long enough for entering LP
807+
* and exiting LP, but it's not clear how to calculate that.
808+
* Instead, this is a naive algorithm that just adjusts the HFP
809+
* and HSW so that HFP is (at least) roughly 2/3 of the total
810+
* blanking time.
811+
*/
812+
if (dsi_hfp < (dsi_hfp + dsi_hsw + dsi_hss) * 2 / 3) {
813+
u32 old_hfp = dsi_hfp;
814+
u32 old_hsw = dsi_hsw;
815+
u32 tot = dsi_hfp + dsi_hsw + dsi_hss;
816+
817+
dsi_hsw = tot / 3;
818+
819+
/*
820+
* Seems like sometimes HSW has to be divisible by num-lanes, but
821+
* not always...
822+
*/
823+
dsi_hsw = roundup(dsi_hsw, priv->dsi_lanes);
824+
825+
dsi_hfp = dsi_dpi_htot - dsi_hact - dsi_hsw - dsi_hss;
826+
827+
dev_dbg(dev,
828+
"hfp too short, adjusting dsi hfp and dsi hsw from %u, %u to %u, %u\n",
829+
old_hfp, old_hsw, dsi_hfp, dsi_hsw);
830+
}
831+
832+
dev_dbg(dev,
833+
"dsi horiz timing (bytes): %u, %u + %u + %u + %u = %u\n",
834+
dsi_hss, dsi_hsw, dsi_hbp, dsi_hact, dsi_hfp,
835+
dsi_hss + dsi_hsw + dsi_hbp + dsi_hact + dsi_hfp);
836+
837+
dev_dbg(dev, "dsi horiz timing (ns): %u + %u + %u + %u + %u = %u\n",
838+
tc358768_dsi_bytes_to_ns(priv, dsi_hss),
839+
tc358768_dsi_bytes_to_ns(priv, dsi_hsw),
840+
tc358768_dsi_bytes_to_ns(priv, dsi_hbp),
841+
tc358768_dsi_bytes_to_ns(priv, dsi_hact),
842+
tc358768_dsi_bytes_to_ns(priv, dsi_hfp),
843+
tc358768_dsi_bytes_to_ns(priv, dsi_hss + dsi_hsw +
844+
dsi_hbp + dsi_hact + dsi_hfp));
845+
}
846+
847+
/* VSDly calculation */
848+
849+
/* Start with the HW internal delay */
850+
dsi_vsdly = internal_dly;
851+
852+
/* Convert to byte units as the other variables are in byte units */
853+
dsi_vsdly *= priv->dsi_lanes;
854+
855+
/* Do we need more delay, in addition to the internal? */
856+
if (dsi_dpi_data_start > dsi_vsdly + dsi_hss + dsi_hsw + dsi_hbp) {
857+
dsi_vsdly = dsi_dpi_data_start - dsi_hss - dsi_hsw - dsi_hbp;
858+
dsi_vsdly = roundup(dsi_vsdly, priv->dsi_lanes);
859+
}
860+
861+
dev_dbg(dev, "dsi data start (bytes) %u + %u + %u + %u = %u\n",
862+
dsi_vsdly, dsi_hss, dsi_hsw, dsi_hbp,
863+
dsi_vsdly + dsi_hss + dsi_hsw + dsi_hbp);
864+
865+
dev_dbg(dev, "dsi data start (ns) %u + %u + %u + %u = %u\n",
866+
tc358768_dsi_bytes_to_ns(priv, dsi_vsdly),
867+
tc358768_dsi_bytes_to_ns(priv, dsi_hss),
868+
tc358768_dsi_bytes_to_ns(priv, dsi_hsw),
869+
tc358768_dsi_bytes_to_ns(priv, dsi_hbp),
870+
tc358768_dsi_bytes_to_ns(priv, dsi_vsdly + dsi_hss + dsi_hsw + dsi_hbp));
871+
872+
/* Convert back to hsbyteclk */
873+
dsi_vsdly /= priv->dsi_lanes;
874+
875+
/*
876+
* The docs say that there is an internal delay of 40 cycles.
877+
* However, we get underflows if we follow that rule. If we
878+
* instead ignore the internal delay, things work. So either
879+
* the docs are wrong or the calculations are wrong.
880+
*
881+
* As a temporary fix, add the internal delay here, to counter
882+
* the subtraction when writing the register.
883+
*/
884+
dsi_vsdly += internal_dly;
885+
886+
/* Clamp to the register max */
887+
if (dsi_vsdly - internal_dly > 0x3ff) {
888+
dev_warn(dev, "VSDly too high, underflows likely\n");
889+
dsi_vsdly = 0x3ff + internal_dly;
890+
}
891+
719892
/* VSDly[9:0] */
720-
video_start = max(video_start, internal_delay + 1) - internal_delay;
721-
tc358768_write(priv, TC358768_VSDLY, video_start);
893+
tc358768_write(priv, TC358768_VSDLY, dsi_vsdly - internal_dly);
722894

723895
tc358768_write(priv, TC358768_DATAFMT, val);
724896
tc358768_write(priv, TC358768_DSITX_DT, data_type);
@@ -826,18 +998,6 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
826998

827999
/* vbp */
8281000
tc358768_write(priv, TC358768_DSI_VBPR, vm.vback_porch);
829-
830-
/* hsw * byteclk * ndl / pclk */
831-
val = (u32)div_u64(vm.hsync_len *
832-
(u64)hsbyteclk * priv->dsi_lanes,
833-
vm.pixelclock);
834-
tc358768_write(priv, TC358768_DSI_HSW, val);
835-
836-
/* hbp * byteclk * ndl / pclk */
837-
val = (u32)div_u64(vm.hback_porch *
838-
(u64)hsbyteclk * priv->dsi_lanes,
839-
vm.pixelclock);
840-
tc358768_write(priv, TC358768_DSI_HBPR, val);
8411001
} else {
8421002
/* Set event mode */
8431003
tc358768_write(priv, TC358768_DSI_EVENT, 1);
@@ -851,16 +1011,13 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
8511011

8521012
/* vbp (not used in event mode) */
8531013
tc358768_write(priv, TC358768_DSI_VBPR, 0);
1014+
}
8541015

855-
/* (hsw + hbp) * byteclk * ndl / pclk */
856-
val = (u32)div_u64((vm.hsync_len + vm.hback_porch) *
857-
(u64)hsbyteclk * priv->dsi_lanes,
858-
vm.pixelclock);
859-
tc358768_write(priv, TC358768_DSI_HSW, val);
1016+
/* hsw (bytes) */
1017+
tc358768_write(priv, TC358768_DSI_HSW, dsi_hsw);
8601018

861-
/* hbp (not used in event mode) */
862-
tc358768_write(priv, TC358768_DSI_HBPR, 0);
863-
}
1019+
/* hbp (bytes) */
1020+
tc358768_write(priv, TC358768_DSI_HBPR, dsi_hbp);
8641021

8651022
/* hact (bytes) */
8661023
tc358768_write(priv, TC358768_DSI_HACT, hact);

0 commit comments

Comments
 (0)