[PATCH v2 2/2] drm/bridge: tc358767: Improve DPI output pixel clock accuracy
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Tue Nov 12 05:29:11 UTC 2024
Hi Marek,
Thank you for the patch.
On Tue, Nov 12, 2024 at 03:05:37AM +0100, Marek Vasut wrote:
> The Pixel PLL is not very capable and may come up with wildly inaccurate
> clock. Since DPI panels are often tolerant to slightly higher pixel clock
> without being operated outside of specification, calculate two Pixel PLL
> from either mode clock or display_timing .pixelclock.max , whichever is
> higher.
Maybe this is a leftover from v1 in the commit message, but I don't
think the code computes two pixel PLL.
> Since the Pixel PLL output clock frequency calculation always
> returns lower frequency than the requested clock frequency, passing in
> the higher clock frequency should result in output clock frequency which
> is closer to the expected pixel clock.
Is that guaranteed ?
> For the Chefree CH101 panel with 13 MHz Xtal input clock, the frequency
> without this patch is 65 MHz which is out of the panel specification of
> 68.9..73.4 MHz, while with this patch it is 71.5 MHz which is well within
> the specification and far more accurate.
I'm a bit concerned that this patch is quite a bit of a hack, but fixing
the problem correctly would be too much yak shaving :-S
>
> Keep the change isolated to DPI output.
>
> Signed-off-by: Marek Vasut <marex at denx.de>
> ---
> Cc: Andrzej Hajda <andrzej.hajda at intel.com>
> Cc: David Airlie <airlied at gmail.com>
> Cc: Jernej Skrabec <jernej.skrabec at gmail.com>
> Cc: Jonas Karlman <jonas at kwiboo.se>
> Cc: Laurent Pinchart <Laurent.pinchart at ideasonboard.com>
> Cc: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
> Cc: Maxime Ripard <mripard at kernel.org>
> Cc: Neil Armstrong <neil.armstrong at linaro.org>
> Cc: Robert Foss <rfoss at kernel.org>
> Cc: Simona Vetter <simona at ffwll.ch>
> Cc: Thomas Zimmermann <tzimmermann at suse.de>
> Cc: dri-devel at lists.freedesktop.org
> ---
> V2: - Isolate the change to DPI only, split tc_bridge_mode_set()
> - Look up display_timings and use .pixelclock.max as input
> into the PLL calculation if available. That should yield
> more accurate results for DPI panels.
> ---
> drivers/gpu/drm/bridge/tc358767.c | 47 +++++++++++++++++++++++++------
> 1 file changed, 39 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> index 0d523322fdd8e..fe9ab06d82d91 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -39,6 +39,8 @@
> #include <drm/drm_print.h>
> #include <drm/drm_probe_helper.h>
>
> +#include <video/display_timing.h>
> +
> /* Registers */
>
> /* DSI D-PHY Layer registers */
> @@ -1681,13 +1683,33 @@ static int tc_dpi_atomic_check(struct drm_bridge *bridge,
> struct drm_crtc_state *crtc_state,
> struct drm_connector_state *conn_state)
> {
> + u32 mode_clock = crtc_state->mode.clock * 1000;
> struct tc_data *tc = bridge_to_tc(bridge);
> - int adjusted_clock = 0;
> + struct drm_bridge *nb = bridge;
> + struct display_timing timings;
> + struct drm_panel *panel;
> + int adjusted_clock;
> int ret;
>
> + do {
> + if (!drm_bridge_is_panel(nb))
drm_bridge_get_panel() already checks if the bridge is related to a
panel, so I think you can drop this check.
> + continue;
> +
> + panel = drm_bridge_get_panel(nb);
> + if (!panel || !panel->funcs || !panel->funcs->get_timings)
> + continue;
> +
> + ret = panel->funcs->get_timings(panel, 1, &timings);
> + if (ret <= 0)
> + break;
> +
> + if (timings.pixelclock.max > mode_clock)
> + mode_clock = timings.pixelclock.max;
> + break;
> + } while ((nb = drm_bridge_get_next_bridge(nb)));
Can the panel be anything that the last bridge in the chain ?
> +
> ret = tc_pxl_pll_calc(tc, clk_get_rate(tc->refclk),
> - crtc_state->mode.clock * 1000,
> - &adjusted_clock, NULL);
> + mode_clock, &adjusted_clock, NULL);
> if (ret)
> return ret;
>
> @@ -1758,9 +1780,18 @@ tc_edp_mode_valid(struct drm_bridge *bridge,
> return MODE_OK;
> }
>
> -static void tc_bridge_mode_set(struct drm_bridge *bridge,
> - const struct drm_display_mode *mode,
> - const struct drm_display_mode *adj)
> +static void tc_dpi_bridge_mode_set(struct drm_bridge *bridge,
> + const struct drm_display_mode *mode,
> + const struct drm_display_mode *adj)
> +{
> + struct tc_data *tc = bridge_to_tc(bridge);
> +
> + drm_mode_copy(&tc->mode, adj);
> +}
> +
> +static void tc_edp_bridge_mode_set(struct drm_bridge *bridge,
> + const struct drm_display_mode *mode,
> + const struct drm_display_mode *adj)
> {
> struct tc_data *tc = bridge_to_tc(bridge);
>
> @@ -1977,7 +2008,7 @@ tc_edp_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
> static const struct drm_bridge_funcs tc_dpi_bridge_funcs = {
> .attach = tc_dpi_bridge_attach,
> .mode_valid = tc_dpi_mode_valid,
> - .mode_set = tc_bridge_mode_set,
> + .mode_set = tc_dpi_bridge_mode_set,
> .atomic_check = tc_dpi_atomic_check,
> .atomic_enable = tc_dpi_bridge_atomic_enable,
> .atomic_disable = tc_dpi_bridge_atomic_disable,
> @@ -1991,7 +2022,7 @@ static const struct drm_bridge_funcs tc_edp_bridge_funcs = {
> .attach = tc_edp_bridge_attach,
> .detach = tc_edp_bridge_detach,
> .mode_valid = tc_edp_mode_valid,
> - .mode_set = tc_bridge_mode_set,
> + .mode_set = tc_edp_bridge_mode_set,
> .atomic_check = tc_edp_atomic_check,
> .atomic_enable = tc_edp_bridge_atomic_enable,
> .atomic_disable = tc_edp_bridge_atomic_disable,
--
Regards,
Laurent Pinchart
More information about the dri-devel
mailing list