lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <8cd9d1c4-2e9f-4766-b224-21925c4f991d@ideasonboard.com>
Date: Thu, 17 Jul 2025 19:10:37 +0300
From: Tomi Valkeinen <tomi.valkeinen@...asonboard.com>
To: Jayesh Choudhary <j-choudhary@...com>
Cc: airlied@...il.com, simona@...ll.ch, linux-kernel@...r.kernel.org,
 jyri.sarha@....fi, maarten.lankhorst@...ux.intel.com, mripard@...nel.org,
 tzimmermann@...e.de, dri-devel@...ts.freedesktop.org, devarsht@...com,
 mwalle@...nel.org
Subject: Re: [PATCH v4 2/3] drm/tidss: Remove max_pclk_khz from tidss display
 features

Hi,

On 04/07/2025 12:48, Jayesh Choudhary wrote:
> TIDSS hardware by itself does not have variable max_pclk for each VP.
> The maximum pixel clock is determined by the limiting factor between
> the functional clock and the PLL (parent to the VP/pixel clock).

I'm sorry, what does that mean? "limiting factor between the func clock
and the PLL"?.

> The limitation that has been modeled till now comes from the clock
> (PLL can only be programmed to a particular max value). Instead of
> putting it as a constant field in dispc_features, we can query the
> DM to see if requested clock can be set or not and use it in

DM? Yes, I know what you mean with it, but I feel it's just extra
obfuscation here. You use clk_round_rate() to see if the requested rate
can be used.

> "mode_valid()".

Why quotes?

> Replace constant "max_pclk_khz" in dispc_features with "curr_max_pclk"

Here it's "curr", below "cur". In the patch it looks to be
curr_max_pclk. Just use "current_max_pclk".

However, I would perhaps do a few changes here: We can as well store the
highest rate we have called clk_round_rate() with. So, maybe fields
named: max_successful_rate[vp] and max_attempted_rate[vp]. In
check_pixel_clock() you can first check the max_successful_rate. If
requested rate is lower, return 0. Then check max_attempted_rate, and if
requested rate is lower, fail. Otherwise call clk_round_rate().

> in tidss_device structure which would be modified in runtime.
> In mode_valid() call, check if a best frequency match for mode clock
> can be found or not using "clk_round_rate()". Based on that, propagate
> "cur_max_pclk" and query DM again only if the requested mode clock

Here, also, no need to mention DM.

> is greater than cur_max_pclk. (As the preferred display mode is usually
> the max resolution, driver ends up checking the highest clock the first
> time itself which is used in subsequent checks)
> 
> Since TIDSS display controller provides clock tolerance of 5%, we use
> this while checking the curr_max_pclk. Also, move up "dispc_pclk_diff()"
> before it is called.

I'm not sure if that's a good thing to do. Although the function is
called check_pixel_clock(), we're checking if the rate is too high (the
error returned is MODE_CLOCK_HIGH, so maybe the function is misnamed).
So, e.g., if the requested rate is 100MHz, and clk_round_rate() returns
150MHz, the behavior is not correct: we can support higher clocks than
100 MHz, it's just that the requested rate can't be presented exactly
enough.

Perhaps the check_pixel_clock() could just be inline in
dispc_vp_mode_valid().

At the moment we do check for the 5% tolerance in
dispc_vp_set_clk_rate(), but we just print a warning there, and don't
fail. If we do want to fail, I think the correct error code is
MODE_CLOCK_RANGE. However, failing here would be a change of behavior.
In the minimum I would add that check as a separate step, not in this patch.

> This will make the existing compatibles reusable if DSS features are
> same across two SoCs with the only difference being the pixel clock.

That's true, but afaik we don't need that. The reason we need this is
that if a SoC has two DSS instances (of the same DSS IP), but different
PLLs are used, with the current method we'd need separate compatible
strings for the two DSS instances. As the PLL's max rate is external,
not related to the DSS, we need to remove any hardcoded maximums from
the DSS driver and instead as the clock framework for the max.

 Tomi

> Fixes: 7246e0929945 ("drm/tidss: Add OLDI bridge support")
> Reviewed-by: Devarsh Thakkar <devarsht@...com>
> Signed-off-by: Jayesh Choudhary <j-choudhary@...com>
> ---
>  drivers/gpu/drm/tidss/tidss_dispc.c | 77 +++++++++++------------------
>  drivers/gpu/drm/tidss/tidss_dispc.h |  1 -
>  drivers/gpu/drm/tidss/tidss_drv.h   |  5 ++
>  3 files changed, 34 insertions(+), 49 deletions(-)
> 
> diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
> index 3f6cff2ab1b2..fb59a6a0f86a 100644
> --- a/drivers/gpu/drm/tidss/tidss_dispc.c
> +++ b/drivers/gpu/drm/tidss/tidss_dispc.c
> @@ -58,10 +58,6 @@ static const u16 tidss_k2g_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
>  const struct dispc_features dispc_k2g_feats = {
>  	.min_pclk_khz = 4375,
>  
> -	.max_pclk_khz = {
> -		[DISPC_VP_DPI] = 150000,
> -	},
> -
>  	/*
>  	 * XXX According TRM the RGB input buffer width up to 2560 should
>  	 *     work on 3 taps, but in practice it only works up to 1280.
> @@ -144,11 +140,6 @@ static const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
>  };
>  
>  const struct dispc_features dispc_am65x_feats = {
> -	.max_pclk_khz = {
> -		[DISPC_VP_DPI] = 165000,
> -		[DISPC_VP_OLDI_AM65X] = 165000,
> -	},
> -
>  	.scaling = {
>  		.in_width_max_5tap_rgb = 1280,
>  		.in_width_max_3tap_rgb = 2560,
> @@ -244,11 +235,6 @@ static const u16 tidss_j721e_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
>  };
>  
>  const struct dispc_features dispc_j721e_feats = {
> -	.max_pclk_khz = {
> -		[DISPC_VP_DPI] = 170000,
> -		[DISPC_VP_INTERNAL] = 600000,
> -	},
> -
>  	.scaling = {
>  		.in_width_max_5tap_rgb = 2048,
>  		.in_width_max_3tap_rgb = 4096,
> @@ -315,11 +301,6 @@ const struct dispc_features dispc_j721e_feats = {
>  };
>  
>  const struct dispc_features dispc_am625_feats = {
> -	.max_pclk_khz = {
> -		[DISPC_VP_DPI] = 165000,
> -		[DISPC_VP_INTERNAL] = 170000,
> -	},
> -
>  	.scaling = {
>  		.in_width_max_5tap_rgb = 1280,
>  		.in_width_max_3tap_rgb = 2560,
> @@ -376,15 +357,6 @@ const struct dispc_features dispc_am625_feats = {
>  };
>  
>  const struct dispc_features dispc_am62a7_feats = {
> -	/*
> -	 * if the code reaches dispc_mode_valid with VP1,
> -	 * it should return MODE_BAD.
> -	 */
> -	.max_pclk_khz = {
> -		[DISPC_VP_TIED_OFF] = 0,
> -		[DISPC_VP_DPI] = 165000,
> -	},
> -
>  	.scaling = {
>  		.in_width_max_5tap_rgb = 1280,
>  		.in_width_max_3tap_rgb = 2560,
> @@ -441,10 +413,6 @@ const struct dispc_features dispc_am62a7_feats = {
>  };
>  
>  const struct dispc_features dispc_am62l_feats = {
> -	.max_pclk_khz = {
> -		[DISPC_VP_DPI] = 165000,
> -	},
> -
>  	.subrev = DISPC_AM62L,
>  
>  	.common = "common",
> @@ -1347,25 +1315,49 @@ static void dispc_vp_set_default_color(struct dispc_device *dispc,
>  			DISPC_OVR_DEFAULT_COLOR2, (v >> 32) & 0xffff);
>  }
>  
> +/*
> + * Calculate the percentage difference between the requested pixel clock rate
> + * and the effective rate resulting from calculating the clock divider value.
> + */
> +unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate)
> +{
> +	int r = rate / 100, rr = real_rate / 100;
> +
> +	return (unsigned int)(abs(((rr - r) * 100) / r));
> +}
> +
> +static int check_pixel_clock(struct dispc_device *dispc,
> +			     u32 hw_videoport, unsigned long clock)
> +{
> +	if (clock > dispc->tidss->curr_max_pclk[hw_videoport] &&
> +	    !dispc->tidss->is_oldi_vp[hw_videoport]) {
> +		unsigned long round_clock = clk_round_rate(dispc->vp_clk[hw_videoport], clock);
> +
> +		if (dispc_pclk_diff(clock, round_clock) > 5)
> +			return -EINVAL;
> +
> +		dispc->tidss->curr_max_pclk[hw_videoport] = round_clock;
> +	}
> +
> +	return 0;
> +}
> +
>  enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc,
>  					 u32 hw_videoport,
>  					 const struct drm_display_mode *mode)
>  {
>  	u32 hsw, hfp, hbp, vsw, vfp, vbp;
>  	enum dispc_vp_bus_type bus_type;
> -	int max_pclk;
>  
>  	bus_type = dispc->feat->vp_bus_type[hw_videoport];
>  
> -	max_pclk = dispc->feat->max_pclk_khz[bus_type];
> -
> -	if (WARN_ON(max_pclk == 0))
> +	if (WARN_ON(bus_type == DISPC_VP_TIED_OFF))
>  		return MODE_BAD;
>  
>  	if (mode->clock < dispc->feat->min_pclk_khz)
>  		return MODE_CLOCK_LOW;
>  
> -	if (mode->clock > max_pclk)
> +	if (check_pixel_clock(dispc, hw_videoport, mode->clock * 1000))
>  		return MODE_CLOCK_HIGH;
>  
>  	if (mode->hdisplay > 4096)
> @@ -1437,17 +1429,6 @@ void dispc_vp_disable_clk(struct dispc_device *dispc, u32 hw_videoport)
>  	clk_disable_unprepare(dispc->vp_clk[hw_videoport]);
>  }
>  
> -/*
> - * Calculate the percentage difference between the requested pixel clock rate
> - * and the effective rate resulting from calculating the clock divider value.
> - */
> -unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate)
> -{
> -	int r = rate / 100, rr = real_rate / 100;
> -
> -	return (unsigned int)(abs(((rr - r) * 100) / r));
> -}
> -
>  int dispc_vp_set_clk_rate(struct dispc_device *dispc, u32 hw_videoport,
>  			  unsigned long rate)
>  {
> diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h
> index 60c1b400eb89..fbfe6e304ac8 100644
> --- a/drivers/gpu/drm/tidss/tidss_dispc.h
> +++ b/drivers/gpu/drm/tidss/tidss_dispc.h
> @@ -78,7 +78,6 @@ enum dispc_dss_subrevision {
>  
>  struct dispc_features {
>  	int min_pclk_khz;
> -	int max_pclk_khz[DISPC_VP_MAX_BUS_TYPE];
>  
>  	struct dispc_features_scaling scaling;
>  
> diff --git a/drivers/gpu/drm/tidss/tidss_drv.h b/drivers/gpu/drm/tidss/tidss_drv.h
> index 82beaaceadb3..5cf21d5f56f2 100644
> --- a/drivers/gpu/drm/tidss/tidss_drv.h
> +++ b/drivers/gpu/drm/tidss/tidss_drv.h
> @@ -25,6 +25,11 @@ struct tidss_device {
>  	const struct dispc_features *feat;
>  	struct dispc_device *dispc;
>  	bool is_oldi_vp[TIDSS_MAX_PORTS];
> +	/*
> +	 * stores highest pixel clock value found to be valid while checking
> +	 * supported modes for connected display
> +	 */
> +	unsigned long curr_max_pclk[TIDSS_MAX_PORTS];
>  
>  
>  	unsigned int num_crtcs;


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ