void intel_fbc_pre_update(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; mutex_lock(&fbc->lock); if (!multiple_pipes_ok(crtc)) { fbc->no_fbc_reason = "more than one pipe active"; goto deactivate; } if (!fbc->enabled || fbc->crtc != crtc) goto unlock; intel_fbc_update_state_cache(crtc); deactivate: intel_fbc_deactivate(dev_priv); unlock: mutex_unlock(&fbc->lock); }
void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin) { struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; if (origin == ORIGIN_GTT || origin == ORIGIN_FLIP) return; mutex_lock(&fbc->lock); fbc->busy_bits &= ~frontbuffer_bits; if (!fbc->busy_bits && fbc->enabled && (frontbuffer_bits & intel_fbc_get_frontbuffer_bit(fbc))) { if (fbc->active) intel_fbc_recompress(dev_priv); else __intel_fbc_post_update(fbc->crtc); } mutex_unlock(&fbc->lock); }
void intel_fbc_pre_update(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct intel_fbc *fbc = &dev_priv->fbc; const char *reason = "update pending"; if (!fbc_supported(dev_priv)) return; mutex_lock(&fbc->lock); if (!multiple_pipes_ok(crtc, plane_state)) { reason = "more than one pipe active"; goto deactivate; } if (!fbc->enabled || fbc->crtc != crtc) goto unlock; intel_fbc_update_state_cache(crtc, crtc_state, plane_state); deactivate: intel_fbc_deactivate(dev_priv, reason); unlock: mutex_unlock(&fbc->lock); }
/** * intel_fbc_disable - disable FBC * @dev_priv: i915 device instance * * This function disables FBC. */ void intel_fbc_disable(struct drm_i915_private *dev_priv) { if (!fbc_supported(dev_priv)) return; mutex_lock(&dev_priv->fbc.lock); __intel_fbc_disable(dev_priv); mutex_unlock(&dev_priv->fbc.lock); }
void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) { struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; mutex_lock(&fbc->lock); __intel_fbc_cleanup_cfb(dev_priv); mutex_unlock(&fbc->lock); }
void intel_fbc_post_update(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; mutex_lock(&fbc->lock); __intel_fbc_post_update(crtc); mutex_unlock(&fbc->lock); }
/* * intel_fbc_disable_crtc - disable FBC if it's associated with crtc * @crtc: the CRTC * * This function disables FBC if it's associated with the provided CRTC. */ void intel_fbc_disable_crtc(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; if (!fbc_supported(dev_priv)) return; mutex_lock(&dev_priv->fbc.lock); if (dev_priv->fbc.crtc == crtc) __intel_fbc_disable(dev_priv); mutex_unlock(&dev_priv->fbc.lock); }
/** * intel_fbc_global_disable - globally disable FBC * @dev_priv: i915 device instance * * This function disables FBC regardless of which CRTC is associated with it. */ void intel_fbc_global_disable(struct drm_i915_private *dev_priv) { struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; mutex_lock(&fbc->lock); if (fbc->enabled) __intel_fbc_disable(dev_priv); mutex_unlock(&fbc->lock); cancel_work_sync(&fbc->work.work); }
/** * intel_fbc_disable - disable FBC if it's associated with crtc * @crtc: the CRTC * * This function disables FBC if it's associated with the provided CRTC. */ void intel_fbc_disable(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; mutex_lock(&fbc->lock); if (fbc->crtc == crtc) __intel_fbc_disable(dev_priv); mutex_unlock(&fbc->lock); cancel_work_sync(&fbc->work.work); }
/** * intel_fbc_disable - disable FBC if it's associated with crtc * @crtc: the CRTC * * This function disables FBC if it's associated with the provided CRTC. */ void intel_fbc_disable(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; mutex_lock(&fbc->lock); if (fbc->crtc == crtc) { WARN_ON(!fbc->enabled); WARN_ON(fbc->active); __intel_fbc_disable(dev_priv); } mutex_unlock(&fbc->lock); cancel_work_sync(&fbc->work.work); }
/** * intel_fbc_handle_fifo_underrun_irq - disable FBC when we get a FIFO underrun * @dev_priv: i915 device instance * * Without FBC, most underruns are harmless and don't really cause too many * problems, except for an annoying message on dmesg. With FBC, underruns can * become black screens or even worse, especially when paired with bad * watermarks. So in order for us to be on the safe side, completely disable FBC * in case we ever detect a FIFO underrun on any pipe. An underrun on any pipe * already suggests that watermarks may be bad, so try to be as safe as * possible. * * This function is called from the IRQ handler. */ void intel_fbc_handle_fifo_underrun_irq(struct drm_i915_private *dev_priv) { struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; /* There's no guarantee that underrun_detected won't be set to true * right after this check and before the work is scheduled, but that's * not a problem since we'll check it again under the work function * while FBC is locked. This check here is just to prevent us from * unnecessarily scheduling the work, and it relies on the fact that we * never switch underrun_detect back to false after it's true. */ if (READ_ONCE(fbc->underrun_detected)) return; schedule_work(&fbc->underrun_work); }
/** * intel_fbc_enable: tries to enable FBC on the CRTC * @crtc: the CRTC * @crtc_state: corresponding &drm_crtc_state for @crtc * @plane_state: corresponding &drm_plane_state for the primary plane of @crtc * * This function checks if the given CRTC was chosen for FBC, then enables it if * possible. Notice that it doesn't activate FBC. It is valid to call * intel_fbc_enable multiple times for the same pipe without an * intel_fbc_disable in the middle, as long as it is deactivated. */ void intel_fbc_enable(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; mutex_lock(&fbc->lock); if (fbc->enabled) { WARN_ON(fbc->crtc == NULL); if (fbc->crtc == crtc) { WARN_ON(!crtc_state->enable_fbc); WARN_ON(fbc->active); } goto out; } if (!crtc_state->enable_fbc) goto out; WARN_ON(fbc->active); WARN_ON(fbc->crtc != NULL); intel_fbc_update_state_cache(crtc, crtc_state, plane_state); if (intel_fbc_alloc_cfb(crtc)) { fbc->no_fbc_reason = "not enough stolen memory"; goto out; } DRM_DEBUG_KMS("Enabling FBC on pipe %c\n", pipe_name(crtc->pipe)); fbc->no_fbc_reason = "FBC enabled but not active yet\n"; fbc->enabled = true; fbc->crtc = crtc; out: mutex_unlock(&fbc->lock); }
void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin) { struct intel_fbc *fbc = &dev_priv->fbc; if (!fbc_supported(dev_priv)) return; if (origin == ORIGIN_GTT || origin == ORIGIN_FLIP) return; mutex_lock(&fbc->lock); fbc->busy_bits |= intel_fbc_get_frontbuffer_bit(fbc) & frontbuffer_bits; if (fbc->enabled && fbc->busy_bits) intel_fbc_deactivate(dev_priv); mutex_unlock(&fbc->lock); }