diff mbox

[10/21,v3] drm/i915: Helper function to detach a scaler from a plane or crtc

Message ID 1427325699-30077-1-git-send-email-chandra.konduru@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Chandra Konduru March 25, 2015, 11:21 p.m. UTC
This function is called from commit path of a plane or crtc.
It programs scaler registers to detach (aka. unbinds) scaler
from requested plane or crtc if it isn't in use. It also resets
scaler_id in crtc/plane state.

v2:
-improved a log message (me)

v3:
-improved commentary (Matt)
-added a case where scaler id needs to be reset (me)

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

Patch

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 5c365f3..8290c7d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2836,6 +2836,63 @@  u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier,
 	}
 }
 
+/*
+ * This function detaches (aka. unbinds) a scaler from plane or crtc
+ * if scaler is not in use.
+ * It resets scaler_id in plane or crtc
+ * To request detach a scaler from crtc, call plane as NULL
+ */
+void skl_detach_scaler(struct drm_crtc *crtc, struct drm_plane *plane)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc_state *crtc_state;
+	struct intel_crtc *intel_crtc;
+	struct intel_plane *intel_plane;
+	struct intel_plane_state *plane_state;
+	int *scaler_id;
+	int idx;
+
+	intel_crtc = to_intel_crtc(crtc);
+	intel_plane = plane ? to_intel_plane(plane) : NULL;
+	crtc_state = intel_crtc->config;
+	plane_state = plane ? to_intel_plane_state(plane->state) : NULL;
+
+	idx = plane ? drm_plane_index(plane) : SKL_CRTC_INDEX;
+	scaler_id = plane ? (plane_state ? &plane_state->scaler_id : NULL) :
+		&crtc_state->scaler_state.scaler_id;
+
+	if (!scaler_id || (scaler_id && *scaler_id < 0))
+		return;
+
+	/*
+	 * staged scaler state can trigger below:
+	 *
+	 * 1) scaler is freed and not attached to any other user. In this case,
+	 *    reg programming needed to update hw. And reset scaler_id to -1
+	 *    to indicate scaler isn't used. Once done, both sw and hw states
+	 *    are in sync.
+	 * 2) scaler is freed and attached to other user. In this case, registers
+	 *    shouldn't be touched here because scaler is used by new owner.
+	 *    Just reset scaler_id to -1.
+	 * 3) scaler is with same user as before. In this case, registers
+	 *    shouldn't be touched. No action needed.
+	 */
+	if (!crtc_state->scaler_state.scalers[*scaler_id].in_use) {
+		I915_WRITE(SKL_PS_CTRL(intel_crtc->pipe, (*scaler_id)), 0);
+		I915_WRITE(SKL_PS_WIN_POS(intel_crtc->pipe, (*scaler_id)), 0);
+		I915_WRITE(SKL_PS_WIN_SZ(intel_crtc->pipe, (*scaler_id)), 0);
+		DRM_DEBUG_KMS("Detached and disabled scaler id %u.%u from %s:%d\n",
+			intel_crtc->pipe, *scaler_id, plane ? "PLANE" : "CRTC",
+			plane ? plane->base.id : crtc->base.id);
+		*scaler_id = -1;
+	}
+
+	if (!(crtc_state->scaler_state.scaler_users & (1 << idx))) {
+		*scaler_id = -1;
+	}
+}
+
 static void skylake_update_primary_plane(struct drm_crtc *crtc,
 					 struct drm_framebuffer *fb,
 					 int x, int y)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a9d787d..f25d14d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1141,6 +1141,7 @@  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);
+void skl_detach_scaler(struct drm_crtc *crtc, struct drm_plane *plane);
 
 /* intel_dp.c */
 void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);