diff mbox

[08/21,v2] drm/i915: Add helper function to update scaler_users in crtc_state

Message ID 1426896282-23215-9-git-send-email-chandra.konduru@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Chandra Konduru March 21, 2015, 12:04 a.m. UTC
This helper function stages a scaler request for a plane/crtc into
crtc_state->scaler_users (which is a bit field). It also performs
required checks before staging any change into scaler_state.

v2:
-updates to use single copy of scaler limits (Matt)
-added force detach parameter for pfit disable purpose (me)

Signed-off-by: Chandra Konduru <chandra.konduru@intel.com>
---
 drivers/gpu/drm/i915/intel_display.c |  143 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_drv.h     |    3 +
 2 files changed, 146 insertions(+)

Comments

Matt Roper March 25, 2015, 5:15 a.m. UTC | #1
On Fri, Mar 20, 2015 at 05:04:29PM -0700, Chandra Konduru wrote:
> This helper function stages a scaler request for a plane/crtc into
> crtc_state->scaler_users (which is a bit field). It also performs
> required checks before staging any change into scaler_state.
> 
> v2:
> -updates to use single copy of scaler limits (Matt)
> -added force detach parameter for pfit disable purpose (me)
> 
> Signed-off-by: Chandra Konduru <chandra.konduru@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_display.c |  143 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_drv.h     |    3 +
>  2 files changed, 146 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 890d372..976bfb1 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -12387,6 +12387,149 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
>  	}
>  }
>  
> +/*
> + * Update crtc_state->scaler_users for requested plane or crtc based on state.

I realize you're trying to re-use some logic here, but I find the
overloaded function that works on either planes or crtcs a bit harder to
follow.  Personally I'd prefer if this were just two separate functions,
one focused on planes, one focused on CRTC's, even if it means
duplicating a little bit of the logic.

> + *
> + * plane (in)
> + *     NULL - for crtc
> + *     not NULL - for plane
> + * force_detach (in)
> + *     unconditionally scaler will be staged for detachment from crtc/plane
> + * Return
> + *     0 - scaler_usage updated successfully
> + *    error - requested scaling cannot be supported or other error condition
> + */

Probably want to put this in kerneldoc format.

> +int
> +skl_update_scaler_users(
> +	struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state,
> +	struct intel_plane *intel_plane, struct intel_plane_state *plane_state,

Might be a little easier to drop the intel_crtc and intel_plane
parameters and just pull them out of the state backpointers.

> +	int force_detach)
> +{
> +	int need_scaling;
> +	int idx;
> +	int src_w, src_h, dst_w, dst_h;
> +	int scaler_id;
> +	struct drm_framebuffer *fb;
> +	struct intel_crtc_scaler_state *scaler_state;
> +
> +	if (!intel_crtc || !crtc_state ||
> +		(intel_plane && intel_plane->base.type == DRM_PLANE_TYPE_CURSOR))
> +		return 0;
> +
> +	scaler_state = &crtc_state->scaler_state;
> +
> +	if (!scaler_state->num_scalers) {
> +		DRM_DEBUG_KMS("crtc_state = %p, num_scalers = %d\n", crtc_state,
> +			scaler_state->num_scalers);
> +		return 0;
> +	}
> +
> +	idx = intel_plane ? drm_plane_index(&intel_plane->base) : SKL_CRTC_INDEX;
> +	fb = intel_plane ? plane_state->base.fb : NULL;
> +
> +	if (intel_plane) {
> +		src_w = drm_rect_width(&plane_state->src) >> 16;
> +		src_h = drm_rect_height(&plane_state->src) >> 16;
> +		dst_w = drm_rect_width(&plane_state->dst);
> +		dst_h = drm_rect_height(&plane_state->dst);
> +		scaler_id = plane_state->scaler_id;
> +	} else {
> +		struct drm_display_mode *adjusted_mode =
> +			&crtc_state->base.adjusted_mode;
> +		src_w = crtc_state->pipe_src_w;
> +		src_h = crtc_state->pipe_src_h;
> +		dst_w = adjusted_mode->hdisplay;
> +		dst_h = adjusted_mode->vdisplay;
> +		scaler_id = scaler_state->scaler_id;
> +	}
> +	need_scaling = (src_w != dst_w || src_h != dst_h);

We're already calculating this in the plane check function; we should
probably just store the result in a plane_state field at that point so
we don't have to re-calculate it here.


> +
> +	/*
> +	 * if plane is being disabled or scaler is no more required or force detach

Maybe it will become more clear later in the patch series, but I'm not
sure I understand what 'force_detach' does.  Won't scalers that we don't
end up re-assigning automatically be cleared when we nobody makes use of
them in a new commit?

> +	 *  - free scaler binded to this plane/crtc
> +	 *  - in order to do this, update crtc->scaler_usage
> +	 *
> +	 * Here scaler state in crtc_state is set free so that
> +	 * scaler can be assigned to other user. Actual register
> +	 * update to free the scaler is done in plane/panel-fit programming.
> +	 * For this purpose crtc/plane_state->scaler_id isn't reset here.
> +	 */
> +	if (force_detach || !need_scaling || (intel_plane &&
> +		(!fb || !plane_state->visible))) {
> +		if (scaler_id >= 0) {
> +			scaler_state->scaler_users &= ~(1 << idx);
> +			scaler_state->scalers[scaler_id].in_use = 0;
> +
> +			DRM_DEBUG_KMS("Staged freeing scaler id %u.%u from %s:%d "
> +				"crtc_state = %p scaler_users = 0x%x\n",
> +				intel_crtc->pipe, scaler_id, intel_plane ? "PLANE" : "CRTC",
> +				intel_plane ? intel_plane->base.base.id :
> +				intel_crtc->base.base.id, crtc_state,
> +				scaler_state->scaler_users);
> +		}
> +		return 0;
> +	}
> +
> +	/*
> +	 * check for rect size:
> +	 *     min sizes in case of scaling involved
> +	 *     max sizes in all cases
> +	 */
> +	if ((need_scaling &&

need_scaling is guaranteed to be true now (otherwise we would have
returned above), so we can drop this test.

> +		(src_w < scaler_state->min_src_w || src_h < scaler_state->min_src_h ||
> +		 dst_w < scaler_state->min_dst_w || dst_h < scaler_state->min_dst_h)) ||
> +
> +		 src_w > scaler_state->max_src_w || src_h > scaler_state->max_src_h ||
> +		 dst_w > scaler_state->max_dst_w || dst_h > scaler_state->max_dst_h) {
> +		DRM_DEBUG_KMS("%s:%d scaler_user index %u.%u: src %ux%u dst %ux%u "
> +			"size is out of scaler range\n",
> +			intel_plane ? "PLANE" : "CRTC",
> +			intel_plane ? intel_plane->base.base.id : intel_crtc->base.base.id,
> +			intel_crtc->pipe, idx, src_w, src_h, dst_w, dst_h);
> +		return -EINVAL;
> +	}
> +
> +	/* check colorkey */
> +	if (intel_plane && need_scaling && intel_colorkey_enabled(intel_plane)) {

Can drop 'need_scaling' test again.

> +		DRM_DEBUG_KMS("PLANE:%d scaling with color key not allowed",
> +			intel_plane->base.base.id);
> +		return -EINVAL;
> +	}
> +
> +	/* Check src format */
> +	if (intel_plane && need_scaling) {

Ditto

> +		switch (fb->pixel_format) {
> +		case DRM_FORMAT_RGB565:
> +		case DRM_FORMAT_XBGR8888:
> +		case DRM_FORMAT_XRGB8888:
> +		case DRM_FORMAT_ABGR8888:
> +		case DRM_FORMAT_ARGB8888:
> +		case DRM_FORMAT_XRGB2101010:
> +		case DRM_FORMAT_ARGB2101010:
> +		case DRM_FORMAT_XBGR2101010:
> +		case DRM_FORMAT_ABGR2101010:
> +		case DRM_FORMAT_YUYV:
> +		case DRM_FORMAT_YVYU:
> +		case DRM_FORMAT_UYVY:
> +		case DRM_FORMAT_VYUY:
> +			break;
> +		default:
> +			DRM_DEBUG_KMS("PLANE:%d FB:%d format 0x%x not supported\n",
> +				intel_plane->base.base.id, fb->base.id, fb->pixel_format);

Might want to add "...while scaling" to this message to avoid confusion.

> +			return -EINVAL;
> +		}
> +	}
> +
> +	/* mark this plane as a scaler user in crtc_state */
> +	scaler_state->scaler_users |= (1 << idx);
> +	DRM_DEBUG_KMS("%s:%d staged scaling request for %ux%u->%ux%u "
> +		"crtc_state = %p scaler_users = 0x%x\n",
> +		intel_plane ? "PLANE" : "CRTC",
> +		intel_plane ? intel_plane->base.base.id : intel_crtc->base.base.id,
> +		src_w, src_h, dst_w, dst_h, crtc_state, scaler_state->scaler_users);
> +	return 0;
> +}
> +
>  static int
>  intel_check_primary_plane(struct drm_plane *plane,
>  			  struct intel_plane_state *state)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 1da5087..f5d53c9 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1138,6 +1138,9 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
>  				 struct intel_crtc_state *pipe_config);
>  void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
>  void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
> +int skl_update_scaler_users(struct intel_crtc *intel_crtc,
> +	struct intel_crtc_state *crtc_state, struct intel_plane *intel_plane,
> +	struct intel_plane_state *plane_state, int force_detach);
>  
>  /* intel_dp.c */
>  void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
> -- 
> 1.7.9.5

You should probably just squash this into the later patches where you
actually call it (e.g., patch 18) so it's more clear how/when/where it
is used.


Matt

>
Chandra Konduru March 25, 2015, 7:20 p.m. UTC | #2
> -----Original Message-----
> From: Roper, Matthew D
> Sent: Tuesday, March 24, 2015 10:15 PM
> To: Konduru, Chandra
> Cc: intel-gfx@lists.freedesktop.org; Vetter, Daniel; Conselvan De Oliveira, Ander
> Subject: Re: [PATCH 08/21 v2] drm/i915: Add helper function to update
> scaler_users in crtc_state
> 
> On Fri, Mar 20, 2015 at 05:04:29PM -0700, Chandra Konduru wrote:
> > This helper function stages a scaler request for a plane/crtc into
> > crtc_state->scaler_users (which is a bit field). It also performs
> > required checks before staging any change into scaler_state.
> >
> > v2:
> > -updates to use single copy of scaler limits (Matt) -added force
> > detach parameter for pfit disable purpose (me)
> >
> > Signed-off-by: Chandra Konduru <chandra.konduru@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_display.c |  143
> ++++++++++++++++++++++++++++++++++
> >  drivers/gpu/drm/i915/intel_drv.h     |    3 +
> >  2 files changed, 146 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/i915/intel_display.c
> > b/drivers/gpu/drm/i915/intel_display.c
> > index 890d372..976bfb1 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -12387,6 +12387,149 @@ intel_cleanup_plane_fb(struct drm_plane
> *plane,
> >  	}
> >  }
> >
> > +/*
> > + * Update crtc_state->scaler_users for requested plane or crtc based on
> state.
> 
> I realize you're trying to re-use some logic here, but I find the overloaded
> function that works on either planes or crtcs a bit harder to follow.  Personally
> I'd prefer if this were just two separate functions, one focused on planes, one
> focused on CRTC's, even if it means duplicating a little bit of the logic.
> 

Yes, this is written as per one of the earlier feedback comment. 
I know this is bit complex, but I find it is worth to take care of all 
Checks in one place covering both crtc and plane. 
To avoid any confusion, I have put sufficient commentary 
throughout the code. let me know if you think any further
commentary is required.

> > + *
> > + * plane (in)
> > + *     NULL - for crtc
> > + *     not NULL - for plane
> > + * force_detach (in)
> > + *     unconditionally scaler will be staged for detachment from crtc/plane
> > + * Return
> > + *     0 - scaler_usage updated successfully
> > + *    error - requested scaling cannot be supported or other error condition
> > + */
> 
> Probably want to put this in kerneldoc format.

Will update in next rev.

> 
> > +int
> > +skl_update_scaler_users(
> > +	struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state,
> > +	struct intel_plane *intel_plane, struct intel_plane_state
> > +*plane_state,
> 
> Might be a little easier to drop the intel_crtc and intel_plane parameters and just
> pull them out of the state backpointers.

You know there is a check caller is doing to get right crtc pointer in 
case of check_plane:
	crtc = crtc ? crtc : plane->crtc;

If crtc isn't passed, then similar check is required in this function.
As caller is already taking care of this, passing crtc just to avoid
another check. 

> 
> > +	int force_detach)
> > +{
> > +	int need_scaling;
> > +	int idx;
> > +	int src_w, src_h, dst_w, dst_h;
> > +	int scaler_id;
> > +	struct drm_framebuffer *fb;
> > +	struct intel_crtc_scaler_state *scaler_state;
> > +
> > +	if (!intel_crtc || !crtc_state ||
> > +		(intel_plane && intel_plane->base.type ==
> DRM_PLANE_TYPE_CURSOR))
> > +		return 0;
> > +
> > +	scaler_state = &crtc_state->scaler_state;
> > +
> > +	if (!scaler_state->num_scalers) {
> > +		DRM_DEBUG_KMS("crtc_state = %p, num_scalers = %d\n",
> crtc_state,
> > +			scaler_state->num_scalers);
> > +		return 0;
> > +	}
> > +
> > +	idx = intel_plane ? drm_plane_index(&intel_plane->base) :
> SKL_CRTC_INDEX;
> > +	fb = intel_plane ? plane_state->base.fb : NULL;
> > +
> > +	if (intel_plane) {
> > +		src_w = drm_rect_width(&plane_state->src) >> 16;
> > +		src_h = drm_rect_height(&plane_state->src) >> 16;
> > +		dst_w = drm_rect_width(&plane_state->dst);
> > +		dst_h = drm_rect_height(&plane_state->dst);
> > +		scaler_id = plane_state->scaler_id;
> > +	} else {
> > +		struct drm_display_mode *adjusted_mode =
> > +			&crtc_state->base.adjusted_mode;
> > +		src_w = crtc_state->pipe_src_w;
> > +		src_h = crtc_state->pipe_src_h;
> > +		dst_w = adjusted_mode->hdisplay;
> > +		dst_h = adjusted_mode->vdisplay;
> > +		scaler_id = scaler_state->scaler_id;
> > +	}
> > +	need_scaling = (src_w != dst_w || src_h != dst_h);
> 
> We're already calculating this in the plane check function; we should probably
> just store the result in a plane_state field at that point so we don't have to re-
> calculate it here.

I think you are referring to sprite plane check, but this is not there in primary plane
check function.

> 
> 
> > +
> > +	/*
> > +	 * if plane is being disabled or scaler is no more required or force
> > +detach
> 
> Maybe it will become more clear later in the patch series, but I'm not sure I
> understand what 'force_detach' does.  Won't scalers that we don't end up re-
> assigning automatically be cleared when we nobody makes use of them in a new
> commit?

Force detach, as name suggests, it stages force freeing of a scaler if one is 
attached to crtc or plane. This is used when disabling panel fitter which 
is called from crtc disable. 

> 
> > +	 *  - free scaler binded to this plane/crtc
> > +	 *  - in order to do this, update crtc->scaler_usage
> > +	 *
> > +	 * Here scaler state in crtc_state is set free so that
> > +	 * scaler can be assigned to other user. Actual register
> > +	 * update to free the scaler is done in plane/panel-fit programming.
> > +	 * For this purpose crtc/plane_state->scaler_id isn't reset here.
> > +	 */
> > +	if (force_detach || !need_scaling || (intel_plane &&
> > +		(!fb || !plane_state->visible))) {
> > +		if (scaler_id >= 0) {
> > +			scaler_state->scaler_users &= ~(1 << idx);
> > +			scaler_state->scalers[scaler_id].in_use = 0;
> > +
> > +			DRM_DEBUG_KMS("Staged freeing scaler id %u.%u
> from %s:%d "
> > +				"crtc_state = %p scaler_users = 0x%x\n",
> > +				intel_crtc->pipe, scaler_id, intel_plane ?
> "PLANE" : "CRTC",
> > +				intel_plane ? intel_plane->base.base.id :
> > +				intel_crtc->base.base.id, crtc_state,
> > +				scaler_state->scaler_users);
> > +		}
> > +		return 0;
> > +	}
> > +
> > +	/*
> > +	 * check for rect size:
> > +	 *     min sizes in case of scaling involved
> > +	 *     max sizes in all cases
> > +	 */
> > +	if ((need_scaling &&
> 
> need_scaling is guaranteed to be true now (otherwise we would have returned
> above), so we can drop this test.
> 
> > +		(src_w < scaler_state->min_src_w || src_h < scaler_state-
> >min_src_h ||
> > +		 dst_w < scaler_state->min_dst_w || dst_h <
> > +scaler_state->min_dst_h)) ||
> > +
> > +		 src_w > scaler_state->max_src_w || src_h > scaler_state-
> >max_src_h ||
> > +		 dst_w > scaler_state->max_dst_w || dst_h > scaler_state-
> >max_dst_h) {
> > +		DRM_DEBUG_KMS("%s:%d scaler_user index %u.%u: src %ux%u
> dst %ux%u "
> > +			"size is out of scaler range\n",
> > +			intel_plane ? "PLANE" : "CRTC",
> > +			intel_plane ? intel_plane->base.base.id : intel_crtc-
> >base.base.id,
> > +			intel_crtc->pipe, idx, src_w, src_h, dst_w, dst_h);
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* check colorkey */
> > +	if (intel_plane && need_scaling &&
> > +intel_colorkey_enabled(intel_plane)) {
> 
> Can drop 'need_scaling' test again.
> 
> > +		DRM_DEBUG_KMS("PLANE:%d scaling with color key not
> allowed",
> > +			intel_plane->base.base.id);
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* Check src format */
> > +	if (intel_plane && need_scaling) {
> 
> Ditto
> 
> > +		switch (fb->pixel_format) {
> > +		case DRM_FORMAT_RGB565:
> > +		case DRM_FORMAT_XBGR8888:
> > +		case DRM_FORMAT_XRGB8888:
> > +		case DRM_FORMAT_ABGR8888:
> > +		case DRM_FORMAT_ARGB8888:
> > +		case DRM_FORMAT_XRGB2101010:
> > +		case DRM_FORMAT_ARGB2101010:
> > +		case DRM_FORMAT_XBGR2101010:
> > +		case DRM_FORMAT_ABGR2101010:
> > +		case DRM_FORMAT_YUYV:
> > +		case DRM_FORMAT_YVYU:
> > +		case DRM_FORMAT_UYVY:
> > +		case DRM_FORMAT_VYUY:
> > +			break;
> > +		default:
> > +			DRM_DEBUG_KMS("PLANE:%d FB:%d format 0x%x not
> supported\n",
> > +				intel_plane->base.base.id, fb->base.id, fb-
> >pixel_format);
> 
> Might want to add "...while scaling" to this message to avoid confusion.
> 
> > +			return -EINVAL;
> > +		}
> > +	}
> > +
> > +	/* mark this plane as a scaler user in crtc_state */
> > +	scaler_state->scaler_users |= (1 << idx);
> > +	DRM_DEBUG_KMS("%s:%d staged scaling request for %ux%u->%ux%u "
> > +		"crtc_state = %p scaler_users = 0x%x\n",
> > +		intel_plane ? "PLANE" : "CRTC",
> > +		intel_plane ? intel_plane->base.base.id : intel_crtc-
> >base.base.id,
> > +		src_w, src_h, dst_w, dst_h, crtc_state, scaler_state-
> >scaler_users);
> > +	return 0;
> > +}
> > +
> >  static int
> >  intel_check_primary_plane(struct drm_plane *plane,
> >  			  struct intel_plane_state *state) diff --git
> > a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index 1da5087..f5d53c9 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1138,6 +1138,9 @@ void intel_mode_from_pipe_config(struct
> drm_display_mode *mode,
> >  				 struct intel_crtc_state *pipe_config);  void
> > intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);  void
> > intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
> > +int skl_update_scaler_users(struct intel_crtc *intel_crtc,
> > +	struct intel_crtc_state *crtc_state, struct intel_plane *intel_plane,
> > +	struct intel_plane_state *plane_state, int force_detach);
> >
> >  /* intel_dp.c */
> >  void intel_dp_init(struct drm_device *dev, int output_reg, enum port
> > port);
> > --
> > 1.7.9.5
> 
> You should probably just squash this into the later patches where you actually
> call it (e.g., patch 18) so it's more clear how/when/where it is used.

Same point came up during review of previous version, and for now it is agreed 
to keep current split to avoid redo of the whole series. I hope you are ok with this. 

> 
> 
> Matt
> 
> >
> 
> --
> Matt Roper
> Graphics Software Engineer
> IoTG Platform Enabling & Development
> Intel Corporation
> (916) 356-2795
Matt Roper March 25, 2015, 8:58 p.m. UTC | #3
On Wed, Mar 25, 2015 at 12:20:08PM -0700, Konduru, Chandra wrote:
...
> > 
> > We're already calculating this in the plane check function; we should probably
> > just store the result in a plane_state field at that point so we don't have to re-
> > calculate it here.
> 
> I think you are referring to sprite plane check, but this is not there in primary plane
> check function.

Well, it is, but it's hidden inside the drm plane helper function and
isn't directly in our i915 driver code.

I feel like "do these src/dest rectangles imply scaling?" is a question
that is going to be relevant to all drivers, not just i915, so it might
even be worth adding the field to the DRM core's state structure and
have the helper function set it for any drivers using the helper.
Hardware drivers could override this value, or could set it themselves
if they don't use the helper.  Just a thought...


Matt
Chandra Konduru March 25, 2015, 10:02 p.m. UTC | #4
> -----Original Message-----
> From: Roper, Matthew D
> Sent: Wednesday, March 25, 2015 1:59 PM
> To: Konduru, Chandra
> Cc: intel-gfx@lists.freedesktop.org; Vetter, Daniel; Conselvan De Oliveira, Ander
> Subject: Re: [PATCH 08/21 v2] drm/i915: Add helper function to update
> scaler_users in crtc_state
> 
> On Wed, Mar 25, 2015 at 12:20:08PM -0700, Konduru, Chandra wrote:
> ...
> > >
> > > We're already calculating this in the plane check function; we
> > > should probably just store the result in a plane_state field at that
> > > point so we don't have to re- calculate it here.
> >
> > I think you are referring to sprite plane check, but this is not there
> > in primary plane check function.
> 
> Well, it is, but it's hidden inside the drm plane helper function and isn't directly in
> our i915 driver code.
> 
> I feel like "do these src/dest rectangles imply scaling?" is a question that is going
> to be relevant to all drivers, not just i915, so it might even be worth adding the
> field to the DRM core's state structure and have the helper function set it for any
> drivers using the helper.
> Hardware drivers could override this value, or could set it themselves if they
> don't use the helper.  Just a thought...

I think that makes sense, but not planning in this patch series.

> 
> 
> Matt
> 
> --
> Matt Roper
> Graphics Software Engineer
> IoTG Platform Enabling & Development
> Intel Corporation
> (916) 356-2795
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 890d372..976bfb1 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -12387,6 +12387,149 @@  intel_cleanup_plane_fb(struct drm_plane *plane,
 	}
 }
 
+/*
+ * Update crtc_state->scaler_users for requested plane or crtc based on state.
+ *
+ * plane (in)
+ *     NULL - for crtc
+ *     not NULL - for plane
+ * force_detach (in)
+ *     unconditionally scaler will be staged for detachment from crtc/plane
+ * Return
+ *     0 - scaler_usage updated successfully
+ *    error - requested scaling cannot be supported or other error condition
+ */
+int
+skl_update_scaler_users(
+	struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state,
+	struct intel_plane *intel_plane, struct intel_plane_state *plane_state,
+	int force_detach)
+{
+	int need_scaling;
+	int idx;
+	int src_w, src_h, dst_w, dst_h;
+	int scaler_id;
+	struct drm_framebuffer *fb;
+	struct intel_crtc_scaler_state *scaler_state;
+
+	if (!intel_crtc || !crtc_state ||
+		(intel_plane && intel_plane->base.type == DRM_PLANE_TYPE_CURSOR))
+		return 0;
+
+	scaler_state = &crtc_state->scaler_state;
+
+	if (!scaler_state->num_scalers) {
+		DRM_DEBUG_KMS("crtc_state = %p, num_scalers = %d\n", crtc_state,
+			scaler_state->num_scalers);
+		return 0;
+	}
+
+	idx = intel_plane ? drm_plane_index(&intel_plane->base) : SKL_CRTC_INDEX;
+	fb = intel_plane ? plane_state->base.fb : NULL;
+
+	if (intel_plane) {
+		src_w = drm_rect_width(&plane_state->src) >> 16;
+		src_h = drm_rect_height(&plane_state->src) >> 16;
+		dst_w = drm_rect_width(&plane_state->dst);
+		dst_h = drm_rect_height(&plane_state->dst);
+		scaler_id = plane_state->scaler_id;
+	} else {
+		struct drm_display_mode *adjusted_mode =
+			&crtc_state->base.adjusted_mode;
+		src_w = crtc_state->pipe_src_w;
+		src_h = crtc_state->pipe_src_h;
+		dst_w = adjusted_mode->hdisplay;
+		dst_h = adjusted_mode->vdisplay;
+		scaler_id = scaler_state->scaler_id;
+	}
+	need_scaling = (src_w != dst_w || src_h != dst_h);
+
+	/*
+	 * if plane is being disabled or scaler is no more required or force detach
+	 *  - free scaler binded to this plane/crtc
+	 *  - in order to do this, update crtc->scaler_usage
+	 *
+	 * Here scaler state in crtc_state is set free so that
+	 * scaler can be assigned to other user. Actual register
+	 * update to free the scaler is done in plane/panel-fit programming.
+	 * For this purpose crtc/plane_state->scaler_id isn't reset here.
+	 */
+	if (force_detach || !need_scaling || (intel_plane &&
+		(!fb || !plane_state->visible))) {
+		if (scaler_id >= 0) {
+			scaler_state->scaler_users &= ~(1 << idx);
+			scaler_state->scalers[scaler_id].in_use = 0;
+
+			DRM_DEBUG_KMS("Staged freeing scaler id %u.%u from %s:%d "
+				"crtc_state = %p scaler_users = 0x%x\n",
+				intel_crtc->pipe, scaler_id, intel_plane ? "PLANE" : "CRTC",
+				intel_plane ? intel_plane->base.base.id :
+				intel_crtc->base.base.id, crtc_state,
+				scaler_state->scaler_users);
+		}
+		return 0;
+	}
+
+	/*
+	 * check for rect size:
+	 *     min sizes in case of scaling involved
+	 *     max sizes in all cases
+	 */
+	if ((need_scaling &&
+		(src_w < scaler_state->min_src_w || src_h < scaler_state->min_src_h ||
+		 dst_w < scaler_state->min_dst_w || dst_h < scaler_state->min_dst_h)) ||
+
+		 src_w > scaler_state->max_src_w || src_h > scaler_state->max_src_h ||
+		 dst_w > scaler_state->max_dst_w || dst_h > scaler_state->max_dst_h) {
+		DRM_DEBUG_KMS("%s:%d scaler_user index %u.%u: src %ux%u dst %ux%u "
+			"size is out of scaler range\n",
+			intel_plane ? "PLANE" : "CRTC",
+			intel_plane ? intel_plane->base.base.id : intel_crtc->base.base.id,
+			intel_crtc->pipe, idx, src_w, src_h, dst_w, dst_h);
+		return -EINVAL;
+	}
+
+	/* check colorkey */
+	if (intel_plane && need_scaling && intel_colorkey_enabled(intel_plane)) {
+		DRM_DEBUG_KMS("PLANE:%d scaling with color key not allowed",
+			intel_plane->base.base.id);
+		return -EINVAL;
+	}
+
+	/* Check src format */
+	if (intel_plane && need_scaling) {
+		switch (fb->pixel_format) {
+		case DRM_FORMAT_RGB565:
+		case DRM_FORMAT_XBGR8888:
+		case DRM_FORMAT_XRGB8888:
+		case DRM_FORMAT_ABGR8888:
+		case DRM_FORMAT_ARGB8888:
+		case DRM_FORMAT_XRGB2101010:
+		case DRM_FORMAT_ARGB2101010:
+		case DRM_FORMAT_XBGR2101010:
+		case DRM_FORMAT_ABGR2101010:
+		case DRM_FORMAT_YUYV:
+		case DRM_FORMAT_YVYU:
+		case DRM_FORMAT_UYVY:
+		case DRM_FORMAT_VYUY:
+			break;
+		default:
+			DRM_DEBUG_KMS("PLANE:%d FB:%d format 0x%x not supported\n",
+				intel_plane->base.base.id, fb->base.id, fb->pixel_format);
+			return -EINVAL;
+		}
+	}
+
+	/* mark this plane as a scaler user in crtc_state */
+	scaler_state->scaler_users |= (1 << idx);
+	DRM_DEBUG_KMS("%s:%d staged scaling request for %ux%u->%ux%u "
+		"crtc_state = %p scaler_users = 0x%x\n",
+		intel_plane ? "PLANE" : "CRTC",
+		intel_plane ? intel_plane->base.base.id : intel_crtc->base.base.id,
+		src_w, src_h, dst_w, dst_h, crtc_state, scaler_state->scaler_users);
+	return 0;
+}
+
 static int
 intel_check_primary_plane(struct drm_plane *plane,
 			  struct intel_plane_state *state)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1da5087..f5d53c9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1138,6 +1138,9 @@  void intel_mode_from_pipe_config(struct drm_display_mode *mode,
 				 struct intel_crtc_state *pipe_config);
 void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
 void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
+int skl_update_scaler_users(struct intel_crtc *intel_crtc,
+	struct intel_crtc_state *crtc_state, struct intel_plane *intel_plane,
+	struct intel_plane_state *plane_state, int force_detach);
 
 /* intel_dp.c */
 void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);