diff mbox

[10/20] drm/i915: Add atomic function to setup scalers scalers for a crtc.

Message ID 1427943589-6254-11-git-send-email-chandra.konduru@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Chandra Konduru April 2, 2015, 2:59 a.m. UTC
intel_atomic_setup_scalers sets up scalers based on staged scaling
requests coming from a crtc and its planes. This function should be
called from crtc level check path.

If staged requests are supportable, function assigns scalers to
requested planes and crtc. This function also takes into account
the current planes using scalers but not being part of this
atomic state for optimal operation of scalers. Note that the scaler
assignement itself is staged into crtc_state and respective
plane_states for later commit after all checks have been done.

overall high level flow:
 - scaler requests are staged into crtc_state by planes/crtc
 - check whether staged scaling requests can be supported
 - add planes using scalers that aren't in current transaction
 - assign scalers to requested users
 - as part of plane commit, scalers will be committed
   (i.e., either attached or detached) to respective planes in hw
 - as part of crtc_commit, scaler will be either attached or detached
   to crtc in hw

v2:
-removed a log message (me)
-changed input parameter to crtc_state (me)

v3:
-remove assigning plane_state returned by drm_atomic_get_plane_state (Matt)
-fail if there is an error from drm_atomic_get_plane_state (Matt)

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

Comments

Matt Roper April 2, 2015, 11:04 p.m. UTC | #1
On Wed, Apr 01, 2015 at 07:59:39PM -0700, Chandra Konduru wrote:
> intel_atomic_setup_scalers sets up scalers based on staged scaling
> requests coming from a crtc and its planes. This function should be
> called from crtc level check path.
> 
> If staged requests are supportable, function assigns scalers to
> requested planes and crtc. This function also takes into account
> the current planes using scalers but not being part of this
> atomic state for optimal operation of scalers. Note that the scaler
> assignement itself is staged into crtc_state and respective
> plane_states for later commit after all checks have been done.
> 
> overall high level flow:
>  - scaler requests are staged into crtc_state by planes/crtc
>  - check whether staged scaling requests can be supported
>  - add planes using scalers that aren't in current transaction
>  - assign scalers to requested users
>  - as part of plane commit, scalers will be committed
>    (i.e., either attached or detached) to respective planes in hw
>  - as part of crtc_commit, scaler will be either attached or detached
>    to crtc in hw
> 
> v2:
> -removed a log message (me)
> -changed input parameter to crtc_state (me)
> 
> v3:
> -remove assigning plane_state returned by drm_atomic_get_plane_state (Matt)
> -fail if there is an error from drm_atomic_get_plane_state (Matt)
> 
> Signed-off-by: Chandra Konduru <chandra.konduru@intel.com>

So looking ahead through the patch series, it looks like the places you
call this are:
 * intel_crtc_compute_config() --- Will presumably move to check_crtc()
   once we're farther along with atomic conversion.
 * intel_atomic_check() --- Handles updates via atomic ioctl (will also
   handle legacy plane updates once we switch to full atomic helpers)
 * skylake_pfit_update()

Since we're on transitional plane helpers today (which don't create a
top-level atomic transaction and thus never call intel_atomic_check),
does this ever get called for legacy SetPlane() operations on today's
driver?  Is it correct to assume that the switch back to full atomic
helpers is a prereq for merging this, or am I overlooking something?


Matt

> ---
>  drivers/gpu/drm/i915/intel_atomic.c |  142 +++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_drv.h    |    3 +
>  2 files changed, 145 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> index 3903b90..fab1f13 100644
> --- a/drivers/gpu/drm/i915/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/intel_atomic.c
> @@ -241,3 +241,145 @@ intel_crtc_destroy_state(struct drm_crtc *crtc,
>  {
>  	drm_atomic_helper_crtc_destroy_state(crtc, state);
>  }
> +
> +/**
> + * intel_atomic_setup_scalers() - setup scalers for crtc per staged requests
> + * @dev: DRM device
> + * @crtc: intel crtc
> + * @crtc_state: incoming crtc_state to validate and setup scalers
> + *
> + * This function sets up scalers based on staged scaling requests for
> + * a @crtc and its planes. It is called from crtc level check path. If request
> + * is a supportable request, it attaches scalers to requested planes and crtc.
> + *
> + * This function takes into account the current scaler(s) in use by any planes
> + * not being part of this atomic state
> + *
> + *  Returns:
> + *         0 - scalers were setup succesfully
> + *         error code - otherwise
> + */
> +int intel_atomic_setup_scalers(struct drm_device *dev,
> +	struct intel_crtc *intel_crtc,
> +	struct intel_crtc_state *crtc_state)
> +{
> +	struct drm_plane *plane = NULL;
> +	struct intel_plane *intel_plane;
> +	struct intel_plane_state *plane_state = NULL;
> +	struct intel_crtc_scaler_state *scaler_state;
> +	struct drm_atomic_state *drm_state;
> +	int num_scalers_need;
> +	int i, j;
> +
> +	if (INTEL_INFO(dev)->gen < 9 || !intel_crtc || !crtc_state)
> +		return 0;
> +
> +	scaler_state = &crtc_state->scaler_state;
> +	drm_state = crtc_state->base.state;
> +
> +	num_scalers_need = hweight32(scaler_state->scaler_users);
> +	DRM_DEBUG_KMS("crtc_state = %p need = %d avail = %d scaler_users = 0x%x\n",
> +		crtc_state, num_scalers_need, scaler_state->num_scalers,
> +		scaler_state->scaler_users);
> +
> +	/* if there is no change in scaler configuration, return */
> +	if (scaler_state->scaler_users ==
> +		intel_crtc->config->scaler_state.scaler_users)
> +		return 0;
> +
> +	/*
> +	 * High level flow:
> +	 * - staged scaler requests are already in scaler_state->scaler_users
> +	 * - check whether staged scaling requests can be supported
> +	 * - add planes using scalers that aren't in current transaction
> +	 * - assign scalers to requested users
> +	 * - as part of plane commit, scalers will be committed
> +	 *   (i.e., either attached or detached) to respective planes in hw
> +	 * - as part of crtc_commit, scaler will be either attached or detached
> +	 *   to crtc in hw
> +	 */
> +
> +	/* fail if required scalers > available scalers */
> +	if (num_scalers_need > scaler_state->num_scalers){
> +		DRM_DEBUG_KMS("Too many scaling requests %d > %d\n",
> +			num_scalers_need, scaler_state->num_scalers);
> +		return -EINVAL;
> +	}
> +
> +	/* walkthrough scaler_users bits and start assigning scalers */
> +	for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) {
> +		int *scaler_id;
> +
> +		/* skip if scaler not required */
> +		if (!(scaler_state->scaler_users & (1 << i)))
> +			continue;
> +
> +		if (i == SKL_CRTC_INDEX) {
> +			/* panel fitter case: assign as a crtc scaler */
> +			scaler_id = &scaler_state->scaler_id;
> +		} else {
> +			if (!drm_state)
> +				continue;
> +
> +			/* plane scaler case: assign as a plane scaler */
> +			/* find the plane that set the bit as scaler_user */
> +			plane = drm_state->planes[i];
> +
> +			/*
> +			 * to enable/disable hq mode, add planes that are using scaler
> +			 * into this transaction
> +			 */
> +			if (!plane) {
> +				struct drm_plane_state *state;
> +				plane = drm_plane_from_index(dev, i);
> +				state = drm_atomic_get_plane_state(drm_state, plane);
> +				if (IS_ERR(state)) {
> +					DRM_DEBUG_KMS("Failed to add [PLANE:%d] to drm_state\n",
> +						plane->base.id);
> +					return PTR_ERR(state);
> +				}
> +			}
> +
> +			intel_plane = to_intel_plane(plane);
> +
> +			/* plane on different crtc cannot be a scaler user of this crtc */
> +			if (WARN_ON(intel_plane->pipe != intel_crtc->pipe)) {
> +				continue;
> +			}
> +
> +			plane_state = to_intel_plane_state(drm_state->plane_states[i]);
> +			scaler_id = &plane_state->scaler_id;
> +		}
> +
> +		if (*scaler_id < 0) {
> +			/* find a free scaler */
> +			for (j = 0; j < scaler_state->num_scalers; j++) {
> +				if (!scaler_state->scalers[j].in_use) {
> +					scaler_state->scalers[j].in_use = 1;
> +					*scaler_id = scaler_state->scalers[j].id;
> +					DRM_DEBUG_KMS("Attached scaler id %u.%u to %s:%d\n",
> +						intel_crtc->pipe,
> +						i == SKL_CRTC_INDEX ? scaler_state->scaler_id :
> +							plane_state->scaler_id,
> +						i == SKL_CRTC_INDEX ? "CRTC" : "PLANE",
> +						i == SKL_CRTC_INDEX ?  intel_crtc->base.base.id :
> +						plane->base.id);
> +					break;
> +				}
> +			}
> +		}
> +
> +		if (WARN_ON(*scaler_id < 0)) {
> +			DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n",
> +				i == SKL_CRTC_INDEX ? "CRTC" : "PLANE",
> +				i == SKL_CRTC_INDEX ? intel_crtc->base.base.id:plane->base.id);
> +			continue;
> +		}
> +
> +		/* set scaler mode */
> +		scaler_state->scalers[*scaler_id].mode = (num_scalers_need == 1) ?
> +			PS_SCALER_MODE_HQ : PS_SCALER_MODE_DYN;
> +	}
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index e20ddd5..1381d11 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1407,6 +1407,9 @@ intel_atomic_get_crtc_state(struct drm_atomic_state *state,
>  
>  	return to_intel_crtc_state(crtc_state);
>  }
> +int intel_atomic_setup_scalers(struct drm_device *dev,
> +	struct intel_crtc *intel_crtc,
> +	struct intel_crtc_state *crtc_state);
>  
>  /* intel_atomic_plane.c */
>  struct intel_plane_state *intel_create_plane_state(struct drm_plane *plane);
> -- 
> 1.7.9.5
>
Chandra Konduru April 6, 2015, 4:44 a.m. UTC | #2
> -----Original Message-----
> From: Roper, Matthew D
> Sent: Thursday, April 02, 2015 4:05 PM
> To: Konduru, Chandra
> Cc: intel-gfx@lists.freedesktop.org; Vetter, Daniel; Conselvan De Oliveira, Ander
> Subject: Re: [PATCH 10/20] drm/i915: Add atomic function to setup scalers
> scalers for a crtc.
> 
> On Wed, Apr 01, 2015 at 07:59:39PM -0700, Chandra Konduru wrote:
> > intel_atomic_setup_scalers sets up scalers based on staged scaling
> > requests coming from a crtc and its planes. This function should be
> > called from crtc level check path.
> >
> > If staged requests are supportable, function assigns scalers to
> > requested planes and crtc. This function also takes into account the
> > current planes using scalers but not being part of this atomic state
> > for optimal operation of scalers. Note that the scaler assignement
> > itself is staged into crtc_state and respective plane_states for later
> > commit after all checks have been done.
> >
> > overall high level flow:
> >  - scaler requests are staged into crtc_state by planes/crtc
> >  - check whether staged scaling requests can be supported
> >  - add planes using scalers that aren't in current transaction
> >  - assign scalers to requested users
> >  - as part of plane commit, scalers will be committed
> >    (i.e., either attached or detached) to respective planes in hw
> >  - as part of crtc_commit, scaler will be either attached or detached
> >    to crtc in hw
> >
> > v2:
> > -removed a log message (me)
> > -changed input parameter to crtc_state (me)
> >
> > v3:
> > -remove assigning plane_state returned by drm_atomic_get_plane_state
> > (Matt) -fail if there is an error from drm_atomic_get_plane_state
> > (Matt)
> >
> > Signed-off-by: Chandra Konduru <chandra.konduru@intel.com>
> 
> So looking ahead through the patch series, it looks like the places you call this
> are:
>  * intel_crtc_compute_config() --- Will presumably move to check_crtc()
>    once we're farther along with atomic conversion.
>  * intel_atomic_check() --- Handles updates via atomic ioctl (will also
>    handle legacy plane updates once we switch to full atomic helpers)
>  * skylake_pfit_update()
> 
> Since we're on transitional plane helpers today (which don't create a top-level
> atomic transaction and thus never call intel_atomic_check), does this ever get
> called for legacy SetPlane() operations on today's driver?  Is it correct to assume
> that the switch back to full atomic helpers is a prereq for merging this, or am I
> overlooking something?

With current state of tree:
- it is required and called for panel fitting.
- it will be called for plane scaling once update_plane ptr switched to full atomic 
   helpers. Until then not called.

> 
> 
> Matt
> 
> > ---
> >  drivers/gpu/drm/i915/intel_atomic.c |  142
> +++++++++++++++++++++++++++++++++++
> >  drivers/gpu/drm/i915/intel_drv.h    |    3 +
> >  2 files changed, 145 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/i915/intel_atomic.c
> > b/drivers/gpu/drm/i915/intel_atomic.c
> > index 3903b90..fab1f13 100644
> > --- a/drivers/gpu/drm/i915/intel_atomic.c
> > +++ b/drivers/gpu/drm/i915/intel_atomic.c
> > @@ -241,3 +241,145 @@ intel_crtc_destroy_state(struct drm_crtc *crtc,
> > {
> >  	drm_atomic_helper_crtc_destroy_state(crtc, state);  }
> > +
> > +/**
> > + * intel_atomic_setup_scalers() - setup scalers for crtc per staged
> > +requests
> > + * @dev: DRM device
> > + * @crtc: intel crtc
> > + * @crtc_state: incoming crtc_state to validate and setup scalers
> > + *
> > + * This function sets up scalers based on staged scaling requests for
> > + * a @crtc and its planes. It is called from crtc level check path.
> > +If request
> > + * is a supportable request, it attaches scalers to requested planes and crtc.
> > + *
> > + * This function takes into account the current scaler(s) in use by
> > +any planes
> > + * not being part of this atomic state
> > + *
> > + *  Returns:
> > + *         0 - scalers were setup succesfully
> > + *         error code - otherwise
> > + */
> > +int intel_atomic_setup_scalers(struct drm_device *dev,
> > +	struct intel_crtc *intel_crtc,
> > +	struct intel_crtc_state *crtc_state) {
> > +	struct drm_plane *plane = NULL;
> > +	struct intel_plane *intel_plane;
> > +	struct intel_plane_state *plane_state = NULL;
> > +	struct intel_crtc_scaler_state *scaler_state;
> > +	struct drm_atomic_state *drm_state;
> > +	int num_scalers_need;
> > +	int i, j;
> > +
> > +	if (INTEL_INFO(dev)->gen < 9 || !intel_crtc || !crtc_state)
> > +		return 0;
> > +
> > +	scaler_state = &crtc_state->scaler_state;
> > +	drm_state = crtc_state->base.state;
> > +
> > +	num_scalers_need = hweight32(scaler_state->scaler_users);
> > +	DRM_DEBUG_KMS("crtc_state = %p need = %d avail = %d scaler_users =
> 0x%x\n",
> > +		crtc_state, num_scalers_need, scaler_state->num_scalers,
> > +		scaler_state->scaler_users);
> > +
> > +	/* if there is no change in scaler configuration, return */
> > +	if (scaler_state->scaler_users ==
> > +		intel_crtc->config->scaler_state.scaler_users)
> > +		return 0;
> > +
> > +	/*
> > +	 * High level flow:
> > +	 * - staged scaler requests are already in scaler_state->scaler_users
> > +	 * - check whether staged scaling requests can be supported
> > +	 * - add planes using scalers that aren't in current transaction
> > +	 * - assign scalers to requested users
> > +	 * - as part of plane commit, scalers will be committed
> > +	 *   (i.e., either attached or detached) to respective planes in hw
> > +	 * - as part of crtc_commit, scaler will be either attached or detached
> > +	 *   to crtc in hw
> > +	 */
> > +
> > +	/* fail if required scalers > available scalers */
> > +	if (num_scalers_need > scaler_state->num_scalers){
> > +		DRM_DEBUG_KMS("Too many scaling requests %d > %d\n",
> > +			num_scalers_need, scaler_state->num_scalers);
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* walkthrough scaler_users bits and start assigning scalers */
> > +	for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) {
> > +		int *scaler_id;
> > +
> > +		/* skip if scaler not required */
> > +		if (!(scaler_state->scaler_users & (1 << i)))
> > +			continue;
> > +
> > +		if (i == SKL_CRTC_INDEX) {
> > +			/* panel fitter case: assign as a crtc scaler */
> > +			scaler_id = &scaler_state->scaler_id;
> > +		} else {
> > +			if (!drm_state)
> > +				continue;
> > +
> > +			/* plane scaler case: assign as a plane scaler */
> > +			/* find the plane that set the bit as scaler_user */
> > +			plane = drm_state->planes[i];
> > +
> > +			/*
> > +			 * to enable/disable hq mode, add planes that are using
> scaler
> > +			 * into this transaction
> > +			 */
> > +			if (!plane) {
> > +				struct drm_plane_state *state;
> > +				plane = drm_plane_from_index(dev, i);
> > +				state =
> drm_atomic_get_plane_state(drm_state, plane);
> > +				if (IS_ERR(state)) {
> > +					DRM_DEBUG_KMS("Failed to add
> [PLANE:%d] to drm_state\n",
> > +						plane->base.id);
> > +					return PTR_ERR(state);
> > +				}
> > +			}
> > +
> > +			intel_plane = to_intel_plane(plane);
> > +
> > +			/* plane on different crtc cannot be a scaler user of this
> crtc */
> > +			if (WARN_ON(intel_plane->pipe != intel_crtc->pipe)) {
> > +				continue;
> > +			}
> > +
> > +			plane_state = to_intel_plane_state(drm_state-
> >plane_states[i]);
> > +			scaler_id = &plane_state->scaler_id;
> > +		}
> > +
> > +		if (*scaler_id < 0) {
> > +			/* find a free scaler */
> > +			for (j = 0; j < scaler_state->num_scalers; j++) {
> > +				if (!scaler_state->scalers[j].in_use) {
> > +					scaler_state->scalers[j].in_use = 1;
> > +					*scaler_id = scaler_state->scalers[j].id;
> > +					DRM_DEBUG_KMS("Attached scaler id
> %u.%u to %s:%d\n",
> > +						intel_crtc->pipe,
> > +						i == SKL_CRTC_INDEX ?
> scaler_state->scaler_id :
> > +							plane_state-
> >scaler_id,
> > +						i == SKL_CRTC_INDEX ? "CRTC"
> : "PLANE",
> > +						i == SKL_CRTC_INDEX ?
> intel_crtc->base.base.id :
> > +						plane->base.id);
> > +					break;
> > +				}
> > +			}
> > +		}
> > +
> > +		if (WARN_ON(*scaler_id < 0)) {
> > +			DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n",
> > +				i == SKL_CRTC_INDEX ? "CRTC" : "PLANE",
> > +				i == SKL_CRTC_INDEX ? intel_crtc-
> >base.base.id:plane->base.id);
> > +			continue;
> > +		}
> > +
> > +		/* set scaler mode */
> > +		scaler_state->scalers[*scaler_id].mode = (num_scalers_need ==
> 1) ?
> > +			PS_SCALER_MODE_HQ : PS_SCALER_MODE_DYN;
> > +	}
> > +
> > +	return 0;
> > +}
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > b/drivers/gpu/drm/i915/intel_drv.h
> > index e20ddd5..1381d11 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1407,6 +1407,9 @@ intel_atomic_get_crtc_state(struct
> > drm_atomic_state *state,
> >
> >  	return to_intel_crtc_state(crtc_state);  }
> > +int intel_atomic_setup_scalers(struct drm_device *dev,
> > +	struct intel_crtc *intel_crtc,
> > +	struct intel_crtc_state *crtc_state);
> >
> >  /* intel_atomic_plane.c */
> >  struct intel_plane_state *intel_create_plane_state(struct drm_plane
> > *plane);
> > --
> > 1.7.9.5
> >
> 
> --
> 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_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 3903b90..fab1f13 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -241,3 +241,145 @@  intel_crtc_destroy_state(struct drm_crtc *crtc,
 {
 	drm_atomic_helper_crtc_destroy_state(crtc, state);
 }
+
+/**
+ * intel_atomic_setup_scalers() - setup scalers for crtc per staged requests
+ * @dev: DRM device
+ * @crtc: intel crtc
+ * @crtc_state: incoming crtc_state to validate and setup scalers
+ *
+ * This function sets up scalers based on staged scaling requests for
+ * a @crtc and its planes. It is called from crtc level check path. If request
+ * is a supportable request, it attaches scalers to requested planes and crtc.
+ *
+ * This function takes into account the current scaler(s) in use by any planes
+ * not being part of this atomic state
+ *
+ *  Returns:
+ *         0 - scalers were setup succesfully
+ *         error code - otherwise
+ */
+int intel_atomic_setup_scalers(struct drm_device *dev,
+	struct intel_crtc *intel_crtc,
+	struct intel_crtc_state *crtc_state)
+{
+	struct drm_plane *plane = NULL;
+	struct intel_plane *intel_plane;
+	struct intel_plane_state *plane_state = NULL;
+	struct intel_crtc_scaler_state *scaler_state;
+	struct drm_atomic_state *drm_state;
+	int num_scalers_need;
+	int i, j;
+
+	if (INTEL_INFO(dev)->gen < 9 || !intel_crtc || !crtc_state)
+		return 0;
+
+	scaler_state = &crtc_state->scaler_state;
+	drm_state = crtc_state->base.state;
+
+	num_scalers_need = hweight32(scaler_state->scaler_users);
+	DRM_DEBUG_KMS("crtc_state = %p need = %d avail = %d scaler_users = 0x%x\n",
+		crtc_state, num_scalers_need, scaler_state->num_scalers,
+		scaler_state->scaler_users);
+
+	/* if there is no change in scaler configuration, return */
+	if (scaler_state->scaler_users ==
+		intel_crtc->config->scaler_state.scaler_users)
+		return 0;
+
+	/*
+	 * High level flow:
+	 * - staged scaler requests are already in scaler_state->scaler_users
+	 * - check whether staged scaling requests can be supported
+	 * - add planes using scalers that aren't in current transaction
+	 * - assign scalers to requested users
+	 * - as part of plane commit, scalers will be committed
+	 *   (i.e., either attached or detached) to respective planes in hw
+	 * - as part of crtc_commit, scaler will be either attached or detached
+	 *   to crtc in hw
+	 */
+
+	/* fail if required scalers > available scalers */
+	if (num_scalers_need > scaler_state->num_scalers){
+		DRM_DEBUG_KMS("Too many scaling requests %d > %d\n",
+			num_scalers_need, scaler_state->num_scalers);
+		return -EINVAL;
+	}
+
+	/* walkthrough scaler_users bits and start assigning scalers */
+	for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) {
+		int *scaler_id;
+
+		/* skip if scaler not required */
+		if (!(scaler_state->scaler_users & (1 << i)))
+			continue;
+
+		if (i == SKL_CRTC_INDEX) {
+			/* panel fitter case: assign as a crtc scaler */
+			scaler_id = &scaler_state->scaler_id;
+		} else {
+			if (!drm_state)
+				continue;
+
+			/* plane scaler case: assign as a plane scaler */
+			/* find the plane that set the bit as scaler_user */
+			plane = drm_state->planes[i];
+
+			/*
+			 * to enable/disable hq mode, add planes that are using scaler
+			 * into this transaction
+			 */
+			if (!plane) {
+				struct drm_plane_state *state;
+				plane = drm_plane_from_index(dev, i);
+				state = drm_atomic_get_plane_state(drm_state, plane);
+				if (IS_ERR(state)) {
+					DRM_DEBUG_KMS("Failed to add [PLANE:%d] to drm_state\n",
+						plane->base.id);
+					return PTR_ERR(state);
+				}
+			}
+
+			intel_plane = to_intel_plane(plane);
+
+			/* plane on different crtc cannot be a scaler user of this crtc */
+			if (WARN_ON(intel_plane->pipe != intel_crtc->pipe)) {
+				continue;
+			}
+
+			plane_state = to_intel_plane_state(drm_state->plane_states[i]);
+			scaler_id = &plane_state->scaler_id;
+		}
+
+		if (*scaler_id < 0) {
+			/* find a free scaler */
+			for (j = 0; j < scaler_state->num_scalers; j++) {
+				if (!scaler_state->scalers[j].in_use) {
+					scaler_state->scalers[j].in_use = 1;
+					*scaler_id = scaler_state->scalers[j].id;
+					DRM_DEBUG_KMS("Attached scaler id %u.%u to %s:%d\n",
+						intel_crtc->pipe,
+						i == SKL_CRTC_INDEX ? scaler_state->scaler_id :
+							plane_state->scaler_id,
+						i == SKL_CRTC_INDEX ? "CRTC" : "PLANE",
+						i == SKL_CRTC_INDEX ?  intel_crtc->base.base.id :
+						plane->base.id);
+					break;
+				}
+			}
+		}
+
+		if (WARN_ON(*scaler_id < 0)) {
+			DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n",
+				i == SKL_CRTC_INDEX ? "CRTC" : "PLANE",
+				i == SKL_CRTC_INDEX ? intel_crtc->base.base.id:plane->base.id);
+			continue;
+		}
+
+		/* set scaler mode */
+		scaler_state->scalers[*scaler_id].mode = (num_scalers_need == 1) ?
+			PS_SCALER_MODE_HQ : PS_SCALER_MODE_DYN;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e20ddd5..1381d11 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1407,6 +1407,9 @@  intel_atomic_get_crtc_state(struct drm_atomic_state *state,
 
 	return to_intel_crtc_state(crtc_state);
 }
+int intel_atomic_setup_scalers(struct drm_device *dev,
+	struct intel_crtc *intel_crtc,
+	struct intel_crtc_state *crtc_state);
 
 /* intel_atomic_plane.c */
 struct intel_plane_state *intel_create_plane_state(struct drm_plane *plane);