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@xxxxxxxxx> --- drivers/gpu/drm/i915/intel_display.c | 57 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 58 insertions(+) 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); -- 1.7.9.5 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx