linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: boris.brezillon@free-electrons.com (Boris Brezillon)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] drm: atmel_hlcdc: Add support for get_timings
Date: Tue, 26 May 2015 11:28:53 +0200	[thread overview]
Message-ID: <20150526112853.688d26b7@bbrezillon> (raw)
In-Reply-To: <1432199216-1139-1-git-send-email-davidcdueck@googlemail.com>

Hi David,

On Thu, 21 May 2015 11:06:56 +0200
David Dueck <davidcdueck@googlemail.com> wrote:

> drm_panel supports querying timing ranges. If the supplied mode does
> not work with the hlcdc we query the panel and try to find a suitable
> mode.

This patch looks good to me.

Philip, Thierry, could you confirm this is the correct way of dealing
with timing ranges.

> 
> Signed-off-by: David Dueck <davidcdueck@googlemail.com>
> ---
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 118 +++++++++++++++++++----
>  1 file changed, 98 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 9c45130..ea36c24 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -20,6 +20,7 @@
>   */
>  
>  #include <linux/of_graph.h>
> +#include <video/display_timing.h>
>  
>  #include <drm/drmP.h>
>  #include <drm/drm_panel.h>
> @@ -78,6 +79,8 @@ drm_encoder_to_atmel_hlcdc_rgb_output(struct drm_encoder *encoder)
>  struct atmel_hlcdc_panel {
>  	struct atmel_hlcdc_rgb_output base;
>  	struct drm_panel *panel;
> +	struct display_timing *timings;
> +	unsigned int num_timings;
>  };
>  
>  static inline struct atmel_hlcdc_panel *
> @@ -104,14 +107,6 @@ static void atmel_hlcdc_panel_encoder_disable(struct drm_encoder *encoder)
>  	drm_panel_disable(panel->panel);
>  }
>  
> -static bool
> -atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder,
> -				     const struct drm_display_mode *mode,
> -				     struct drm_display_mode *adjusted)
> -{
> -	return true;
> -}
> -
>  static void
>  atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder,
>  				 struct drm_display_mode *mode,
> @@ -142,8 +137,86 @@ atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder,
>  			   cfg);
>  }
>  
> +/**
> + * atmel_hlcdc_choose_parameter - choose timing parameter
> + * @dc_min: minimum parameter value allowed by dc
> + * @dc_max: maximum parameter value allowed by dc
> + * @te: parameter range allowed by panel
> + * @result: chosen parameter
> + *
> + * DESCRIPTION:
> + * If there is overlap in the allowed ranges, we will pick a parameter
> + * minimizing the distance to te.typ. If not, we return te.min or te.max.
> + **/
> +static u32 atmel_hlcdc_choose_parameter(u32 dc_min, u32 dc_max,
> +					struct timing_entry te)
> +{
> +	if (te.typ <= dc_max && te.typ >= dc_min)
> +		return te.typ;
> +	else if (te.typ > dc_max)
> +		return max(dc_max, te.min);
> +	else
> +		return min(dc_min, te.max);
> +}
> +
> +static void atmel_hlcdc_calculate_mode(struct display_timing *timings,
> +				       struct drm_display_mode *adjusted_mode)
> +{
> +	u32 hsync_len, hfront_porch, hback_porch;
> +	u32 vsync_len, vfront_porch, vback_porch;
> +
> +	hsync_len = atmel_hlcdc_choose_parameter(1, 0x40, timings->hsync_len);
> +	vsync_len = atmel_hlcdc_choose_parameter(1, 0x40, timings->vsync_len);
> +
> +	hfront_porch = atmel_hlcdc_choose_parameter(1, 0x200,
> +						    timings->hfront_porch);
> +	hback_porch = atmel_hlcdc_choose_parameter(1, 0x200,
> +						   timings->hback_porch);
> +	vfront_porch = atmel_hlcdc_choose_parameter(1, 0x40,
> +						    timings->vfront_porch);
> +	vback_porch = atmel_hlcdc_choose_parameter(0, 0x40,
> +						   timings->vback_porch);
> +
> +	adjusted_mode->hsync_start = adjusted_mode->hdisplay + hfront_porch;
> +	adjusted_mode->hsync_end = adjusted_mode->hsync_start + hsync_len;
> +	adjusted_mode->htotal = adjusted_mode->hsync_end + hback_porch;
> +
> +	adjusted_mode->vsync_start = adjusted_mode->vdisplay + vfront_porch;
> +	adjusted_mode->vsync_end = adjusted_mode->vsync_start + vsync_len;
> +	adjusted_mode->vtotal = adjusted_mode->vsync_end + vback_porch;
> +}
> +
> +static int
> +atmel_hlcdc_panel_encoder_atomic_check(struct drm_encoder *encoder,
> +				       struct drm_crtc_state *crtc_state,
> +				       struct drm_connector_state *conn_state)
> +{
> +	struct atmel_hlcdc_rgb_output *rgb =
> +			drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
> +	struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
> +	struct drm_display_mode *mode = &crtc_state->mode;
> +	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
> +	int i;
> +
> +	if (atmel_hlcdc_dc_mode_valid(rgb->dc, mode) == MODE_OK)
> +		return 0;
> +
> +	for (i = 0; i < panel->num_timings; i++) {
> +		if (panel->timings->hactive.typ != mode->hdisplay ||
> +		    panel->timings->vactive.typ != mode->vdisplay)
> +			continue;
> +
> +		atmel_hlcdc_calculate_mode(panel->timings, adjusted_mode);
> +		if (atmel_hlcdc_dc_mode_valid(rgb->dc, adjusted_mode) ==
> +		    MODE_OK)
> +			return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
>  static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = {
> -	.mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup,
> +	.atomic_check = atmel_hlcdc_panel_encoder_atomic_check,
>  	.mode_set = atmel_hlcdc_rgb_encoder_mode_set,
>  	.disable = atmel_hlcdc_panel_encoder_disable,
>  	.enable = atmel_hlcdc_panel_encoder_enable,
> @@ -168,16 +241,6 @@ static int atmel_hlcdc_panel_get_modes(struct drm_connector *connector)
>  	return panel->panel->funcs->get_modes(panel->panel);
>  }
>  
> -static int atmel_hlcdc_rgb_mode_valid(struct drm_connector *connector,
> -				      struct drm_display_mode *mode)
> -{
> -	struct atmel_hlcdc_rgb_output *rgb =
> -			drm_connector_to_atmel_hlcdc_rgb_output(connector);
> -
> -	return atmel_hlcdc_dc_mode_valid(rgb->dc, mode);
> -}
> -
> -
>  
>  static struct drm_encoder *
>  atmel_hlcdc_rgb_best_encoder(struct drm_connector *connector)
> @@ -190,7 +253,6 @@ atmel_hlcdc_rgb_best_encoder(struct drm_connector *connector)
>  
>  static struct drm_connector_helper_funcs atmel_hlcdc_panel_connector_helper_funcs = {
>  	.get_modes = atmel_hlcdc_panel_get_modes,
> -	.mode_valid = atmel_hlcdc_rgb_mode_valid,
>  	.best_encoder = atmel_hlcdc_rgb_best_encoder,
>  };
>  
> @@ -273,6 +335,22 @@ static int atmel_hlcdc_create_panel_output(struct drm_device *dev,
>  	drm_panel_attach(p, &panel->base.connector);
>  	panel->panel = p;
>  
> +	if (!panel->panel->funcs->get_timings)
> +		return 0;
> +
> +	panel->num_timings =
> +		panel->panel->funcs->get_timings(panel->panel, 0, NULL);
> +	panel->timings =
> +		devm_kzalloc(dev->dev,
> +			     panel->num_timings * sizeof(struct display_timing),
> +			     GFP_KERNEL);
> +
> +	if (!panel->timings)
> +		return 0;
> +
> +	panel->panel->funcs->get_timings(panel->panel, panel->num_timings,
> +					 panel->timings);
> +
>  	return 0;
>  
>  err_encoder_cleanup:



-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

  reply	other threads:[~2015-05-26  9:28 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-21  9:06 [PATCH] drm: atmel_hlcdc: Add support for get_timings David Dueck
2015-05-26  9:28 ` Boris Brezillon [this message]
2015-05-28 11:13   ` Philipp Zabel
2015-05-28 12:45     ` Boris Brezillon
2015-05-28 13:51       ` Philipp Zabel
2015-05-28 14:15         ` Boris Brezillon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150526112853.688d26b7@bbrezillon \
    --to=boris.brezillon@free-electrons.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).