struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
if (atomic->disable_fbc)
- intel_fbc_disable_crtc(crtc);
+ intel_fbc_deactivate(crtc);
if (crtc->atomic.disable_ips)
hsw_disable_ips(crtc);
if (intel_crtc->config->has_pch_encoder)
intel_wait_for_vblank(dev, pipe);
intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
+
+ intel_fbc_enable(intel_crtc);
}
/* IPS only exists on ULT machines and is tied to pipe A. */
intel_wait_for_vblank(dev, hsw_workaround_pipe);
intel_wait_for_vblank(dev, hsw_workaround_pipe);
}
+
+ intel_fbc_enable(intel_crtc);
}
static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force)
}
intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
+
+ intel_fbc_disable_crtc(intel_crtc);
}
static void haswell_crtc_disable(struct drm_crtc *crtc)
if (intel_crtc->config->has_pch_encoder)
intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
true);
+
+ intel_fbc_disable_crtc(intel_crtc);
}
static void i9xx_pfit_enable(struct intel_crtc *crtc)
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->enable(encoder);
+
+ intel_fbc_enable(intel_crtc);
}
static void i9xx_pfit_disable(struct intel_crtc *crtc)
if (!IS_GEN2(dev))
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
+
+ intel_fbc_disable_crtc(intel_crtc);
}
static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
to_intel_plane(primary)->frontbuffer_bit);
mutex_unlock(&dev->struct_mutex);
- intel_fbc_disable_crtc(intel_crtc);
+ intel_fbc_deactivate(intel_crtc);
intel_frontbuffer_flip_prepare(dev,
to_intel_plane(primary)->frontbuffer_bit);
WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
intel_fbc_cancel_work(dev_priv);
- dev_priv->fbc.crtc = crtc;
work = kzalloc(sizeof(*work), GFP_KERNEL);
if (work == NULL) {
schedule_delayed_work(&work->work, msecs_to_jiffies(50));
}
-static void intel_fbc_deactivate(struct drm_i915_private *dev_priv)
+static void __intel_fbc_deactivate(struct drm_i915_private *dev_priv)
{
WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
dev_priv->fbc.deactivate(dev_priv);
}
-static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
-{
- intel_fbc_deactivate(dev_priv);
- dev_priv->fbc.crtc = NULL;
-}
-
-/**
- * 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);
-}
-
/*
- * intel_fbc_disable_crtc - disable FBC if it's associated with crtc
+ * intel_fbc_deactivate - deactivate FBC if it's associated with crtc
* @crtc: the CRTC
*
- * This function disables FBC if it's associated with the provided CRTC.
+ * This function deactivates FBC if it's associated with the provided CRTC.
*/
-void intel_fbc_disable_crtc(struct intel_crtc *crtc)
+void intel_fbc_deactivate(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
mutex_lock(&dev_priv->fbc.lock);
if (dev_priv->fbc.crtc == crtc)
- __intel_fbc_disable(dev_priv);
+ __intel_fbc_deactivate(dev_priv);
mutex_unlock(&dev_priv->fbc.lock);
}
DRM_DEBUG_KMS("Disabling FBC: %s\n", reason);
}
-static bool crtc_is_valid(struct intel_crtc *crtc)
+static bool crtc_can_fbc(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
if (fbc_on_pipe_a_only(dev_priv) && crtc->pipe != PIPE_A)
return false;
+ return true;
+}
+
+static bool crtc_is_valid(struct intel_crtc *crtc)
+{
if (!intel_crtc_active(&crtc->base))
return false;
}
/**
- * __intel_fbc_update - enable/disable FBC as needed, unlocked
+ * __intel_fbc_update - activate/deactivate FBC as needed, unlocked
* @crtc: the CRTC that triggered the update
*
- * This function completely reevaluates the status of FBC, then enables,
- * disables or maintains it on the same state.
+ * This function completely reevaluates the status of FBC, then activates,
+ * deactivates or maintains it on the same state.
*/
static void __intel_fbc_update(struct intel_crtc *crtc)
{
goto out_disable;
}
- if (dev_priv->fbc.crtc != NULL && dev_priv->fbc.crtc != crtc)
+ if (!dev_priv->fbc.enabled || dev_priv->fbc.crtc != crtc)
return;
- if (intel_vgpu_active(dev_priv->dev))
- i915.enable_fbc = 0;
-
- if (i915.enable_fbc < 0) {
- set_no_fbc_reason(dev_priv, "disabled per chip default");
- goto out_disable;
- }
-
- if (!i915.enable_fbc) {
- set_no_fbc_reason(dev_priv, "disabled per module param");
- goto out_disable;
- }
-
if (!crtc_is_valid(crtc)) {
set_no_fbc_reason(dev_priv, "no output");
goto out_disable;
* disabling paths we do need to wait for a vblank at
* some point. And we wait before enabling FBC anyway.
*/
- DRM_DEBUG_KMS("disabling active FBC for update\n");
- __intel_fbc_disable(dev_priv);
+ DRM_DEBUG_KMS("deactivating FBC for update\n");
+ __intel_fbc_deactivate(dev_priv);
}
intel_fbc_schedule_activation(crtc);
out_disable:
/* Multiple disables should be harmless */
if (intel_fbc_is_active(dev_priv)) {
- DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
- __intel_fbc_disable(dev_priv);
+ DRM_DEBUG_KMS("unsupported config, deactivating FBC\n");
+ __intel_fbc_deactivate(dev_priv);
}
__intel_fbc_cleanup_cfb(dev_priv);
}
/*
- * intel_fbc_update - enable/disable FBC as needed
+ * intel_fbc_update - activate/deactivate FBC as needed
* @crtc: the CRTC that triggered the update
*
- * This function reevaluates the overall state and enables or disables FBC.
+ * This function reevaluates the overall state and activates or deactivates FBC.
*/
void intel_fbc_update(struct intel_crtc *crtc)
{
mutex_lock(&dev_priv->fbc.lock);
- if (dev_priv->fbc.active || dev_priv->fbc.fbc_work)
+ if (dev_priv->fbc.enabled)
fbc_bits = INTEL_FRONTBUFFER_PRIMARY(dev_priv->fbc.crtc->pipe);
else
fbc_bits = dev_priv->fbc.possible_framebuffer_bits;
dev_priv->fbc.busy_bits |= (fbc_bits & frontbuffer_bits);
if (dev_priv->fbc.busy_bits)
- intel_fbc_deactivate(dev_priv);
+ __intel_fbc_deactivate(dev_priv);
mutex_unlock(&dev_priv->fbc.lock);
}
dev_priv->fbc.busy_bits &= ~frontbuffer_bits;
- if (!dev_priv->fbc.busy_bits && dev_priv->fbc.crtc) {
- intel_fbc_deactivate(dev_priv);
+ if (!dev_priv->fbc.busy_bits && dev_priv->fbc.enabled) {
+ __intel_fbc_deactivate(dev_priv);
__intel_fbc_update(dev_priv->fbc.crtc);
}
mutex_unlock(&dev_priv->fbc.lock);
}
+/**
+ * intel_fbc_enable: tries to enable FBC on the CRTC
+ * @crtc: the CRTC
+ *
+ * This function checks if it's possible to enable FBC on the following CRTC,
+ * then enables it. Notice that it doesn't activate FBC.
+ */
+void intel_fbc_enable(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.enabled) {
+ WARN_ON(dev_priv->fbc.crtc == crtc);
+ goto out;
+ }
+
+ WARN_ON(dev_priv->fbc.active);
+ WARN_ON(dev_priv->fbc.crtc != NULL);
+
+ if (intel_vgpu_active(dev_priv->dev)) {
+ set_no_fbc_reason(dev_priv, "VGPU is active");
+ goto out;
+ }
+
+ if (i915.enable_fbc < 0) {
+ set_no_fbc_reason(dev_priv, "disabled per chip default");
+ goto out;
+ }
+
+ if (!i915.enable_fbc) {
+ set_no_fbc_reason(dev_priv, "disabled per module param");
+ goto out;
+ }
+
+ if (!crtc_can_fbc(crtc)) {
+ set_no_fbc_reason(dev_priv, "no enabled pipes can have FBC");
+ goto out;
+ }
+
+ DRM_DEBUG_KMS("Enabling FBC on pipe %c\n", pipe_name(crtc->pipe));
+ dev_priv->fbc.no_fbc_reason = "FBC enabled but not active yet\n";
+
+ dev_priv->fbc.enabled = true;
+ dev_priv->fbc.crtc = crtc;
+out:
+ mutex_unlock(&dev_priv->fbc.lock);
+}
+
+/**
+ * __intel_fbc_disable - disable FBC
+ * @dev_priv: i915 device instance
+ *
+ * This is the low level function that actually disables FBC. Callers should
+ * grab the FBC lock.
+ */
+static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
+{
+ struct intel_crtc *crtc = dev_priv->fbc.crtc;
+
+ WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
+ WARN_ON(!dev_priv->fbc.enabled);
+ WARN_ON(dev_priv->fbc.active);
+ assert_pipe_disabled(dev_priv, crtc->pipe);
+
+ DRM_DEBUG_KMS("Disabling FBC on pipe %c\n", pipe_name(crtc->pipe));
+
+ dev_priv->fbc.enabled = false;
+ dev_priv->fbc.crtc = NULL;
+}
+
+/**
+ * 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) {
+ WARN_ON(!dev_priv->fbc.enabled);
+ WARN_ON(dev_priv->fbc.active);
+ __intel_fbc_disable(dev_priv);
+ }
+ mutex_unlock(&dev_priv->fbc.lock);
+}
+
+/**
+ * intel_fbc_disable - globally disable FBC
+ * @dev_priv: i915 device instance
+ *
+ * This function disables FBC regardless of which CRTC is associated with it.
+ */
+void intel_fbc_disable(struct drm_i915_private *dev_priv)
+{
+ if (!fbc_supported(dev_priv))
+ return;
+
+ mutex_lock(&dev_priv->fbc.lock);
+ if (dev_priv->fbc.enabled)
+ __intel_fbc_disable(dev_priv);
+ mutex_unlock(&dev_priv->fbc.lock);
+}
+
/**
* intel_fbc_init - Initialize FBC
* @dev_priv: the i915 device
enum pipe pipe;
mutex_init(&dev_priv->fbc.lock);
+ dev_priv->fbc.enabled = false;
dev_priv->fbc.active = false;
if (!HAS_FBC(dev_priv)) {