FreeBSD/sys/dev/drm2/i915/intel_pm.c
/**
 * intel_update_fbc - enable/disable FBC as needed
 * @dev: the drm_device
 *
 * Set up the framebuffer compression hardware at mode set time.  We
 * enable it if possible:
 *   - plane A only (on pre-965)
 *   - no pixel mulitply/line duplication
 *   - no alpha buffer discard
 *   - no dual wide
 *   - framebuffer <= 2048 in width, 1536 in height
 *
 * We can't assume that any compression will take place (worst case),
 * so the compressed buffer has to be the same size as the uncompressed
 * one.  It also must reside (along with the line length buffer) in
 * stolen memory.
 *
 * We need to enable/disable FBC on a global basis.
 */
enable/disable FBC as needed
@dev: the drm_device

Set up the framebuffer compression hardware at mode set time.

We can't assume that any compression will take place (worst case),
so the compressed buffer has to be the same size as the uncompressed
one.  It also must reside (along with the line length buffer) in
stolen memory.

We need to enable/disable FBC on a global basis.
enable / disable FBC as needed @dev : the drm_device Set up the framebuffer compression hardware at mode set time . We can ' t assume that any compression will take place ( worst case ) so the compressed buffer has to be the same size as the uncompressed one . It also must reside ( along with the line length buffer ) in stolen memory . We need to enable / disable FBC on a global basis .
void intel_update_fbc(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_crtc *crtc = NULL, *tmp_crtc;
	struct intel_crtc *intel_crtc;
	struct drm_framebuffer *fb;
	struct intel_framebuffer *intel_fb;
	struct drm_i915_gem_object *obj;
	int enable_fbc;
	if (!i915_powersave)
		return;
	if (!I915_HAS_FBC(dev))
		return;
	list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
		if (intel_crtc_active(tmp_crtc) &&
		    !to_intel_crtc(tmp_crtc)->primary_disabled) {
			if (crtc) {
				DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
				dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
				goto out_disable;
			}
			crtc = tmp_crtc;
		}
	}
	if (!crtc || crtc->fb == NULL) {
		DRM_DEBUG_KMS("no output, disabling\n");
		dev_priv->no_fbc_reason = FBC_NO_OUTPUT;
		goto out_disable;
	}
	intel_crtc = to_intel_crtc(crtc);
	fb = crtc->fb;
	intel_fb = to_intel_framebuffer(fb);
	obj = intel_fb->obj;
	enable_fbc = i915_enable_fbc;
	if (enable_fbc < 0) {
		DRM_DEBUG_KMS("fbc set to per-chip default\n");
		enable_fbc = 1;
		if (INTEL_INFO(dev)->gen <= 6)
			enable_fbc = 0;
	}
	if (!enable_fbc) {
		DRM_DEBUG_KMS("fbc disabled per module param\n");
		dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
		goto out_disable;
	}
	if (intel_fb->obj->base.size > dev_priv->cfb_size) {
		DRM_DEBUG_KMS("framebuffer too large, disabling "
			      "compression\n");
		dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
		goto out_disable;
	}
	if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
	    (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
		DRM_DEBUG_KMS("mode incompatible with compression, "
			      "disabling\n");
		dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
		goto out_disable;
	}
	if ((crtc->mode.hdisplay > 2048) ||
	    (crtc->mode.vdisplay > 1536)) {
		DRM_DEBUG_KMS("mode too large for compression, disabling\n");
		dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
		goto out_disable;
	}
	if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
		DRM_DEBUG_KMS("plane not 0, disabling compression\n");
		dev_priv->no_fbc_reason = FBC_BAD_PLANE;
		goto out_disable;
	}
	if (obj->tiling_mode != I915_TILING_X ||
	    obj->fence_reg == I915_FENCE_REG_NONE) {
		DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
		dev_priv->no_fbc_reason = FBC_NOT_TILED;
		goto out_disable;
	}
	if (kdb_active)
		goto out_disable;
	if (dev_priv->cfb_plane == intel_crtc->plane &&
	    dev_priv->cfb_fb == fb->base.id &&
	    dev_priv->cfb_y == crtc->y)
		return;
	if (intel_fbc_enabled(dev)) {
		DRM_DEBUG_KMS("disabling active FBC for update\n");
		intel_disable_fbc(dev);
	}
	intel_enable_fbc(crtc, 500);
	return;
out_disable:
	if (intel_fbc_enabled(dev)) {
		DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
		intel_disable_fbc(dev);
	}
}
void intel_update_fbc ( struct drm_device * dev ) { struct drm_i915_private * dev_priv = dev -> dev_private ; struct drm_crtc * crtc = NULL , * tmp_crtc ; struct intel_crtc * intel_crtc ; struct drm_framebuffer * fb ; struct intel_framebuffer * intel_fb ; struct drm_i915_gem_object * obj ; int enable_fbc ; if ( ! i915_powersave ) return ; if ( ! I915_HAS_FBC ( dev ) ) return ; list_for_each_entry ( tmp_crtc , & dev -> mode_config . crtc_list , head ) { if ( intel_crtc_active ( tmp_crtc ) && ! to_intel_crtc ( tmp_crtc ) -> primary_disabled ) { if ( crtc ) { DRM_DEBUG_KMS ( " \n " ) ; dev_priv -> no_fbc_reason = FBC_MULTIPLE_PIPES ; goto out_disable ; } crtc = tmp_crtc ; } } if ( ! crtc || crtc -> fb == NULL ) { DRM_DEBUG_KMS ( " \n " ) ; dev_priv -> no_fbc_reason = FBC_NO_OUTPUT ; goto out_disable ; } intel_crtc = to_intel_crtc ( crtc ) ; fb = crtc -> fb ; intel_fb = to_intel_framebuffer ( fb ) ; obj = intel_fb -> obj ; enable_fbc = i915_enable_fbc ; if ( enable_fbc < 0 ) { DRM_DEBUG_KMS ( " \n " ) ; enable_fbc = 1 ; if ( INTEL_INFO ( dev ) -> gen <= 6 ) enable_fbc = 0 ; } if ( ! enable_fbc ) { DRM_DEBUG_KMS ( " \n " ) ; dev_priv -> no_fbc_reason = FBC_MODULE_PARAM ; goto out_disable ; } if ( intel_fb -> obj -> base . size > dev_priv -> cfb_size ) { DRM_DEBUG_KMS ( " " " \n " ) ; dev_priv -> no_fbc_reason = FBC_STOLEN_TOO_SMALL ; goto out_disable ; } if ( ( crtc -> mode . flags & DRM_MODE_FLAG_INTERLACE ) || ( crtc -> mode . flags & DRM_MODE_FLAG_DBLSCAN ) ) { DRM_DEBUG_KMS ( " " " \n " ) ; dev_priv -> no_fbc_reason = FBC_UNSUPPORTED_MODE ; goto out_disable ; } if ( ( crtc -> mode . hdisplay > 2048 ) || ( crtc -> mode . vdisplay > 1536 ) ) { DRM_DEBUG_KMS ( " \n " ) ; dev_priv -> no_fbc_reason = FBC_MODE_TOO_LARGE ; goto out_disable ; } if ( ( IS_I915GM ( dev ) || IS_I945GM ( dev ) ) && intel_crtc -> plane != 0 ) { DRM_DEBUG_KMS ( " \n " ) ; dev_priv -> no_fbc_reason = FBC_BAD_PLANE ; goto out_disable ; } if ( obj -> tiling_mode != I915_TILING_X || obj -> fence_reg == I915_FENCE_REG_NONE ) { DRM_DEBUG_KMS ( " \n " ) ; dev_priv -> no_fbc_reason = FBC_NOT_TILED ; goto out_disable ; } if ( kdb_active ) goto out_disable ; if ( dev_priv -> cfb_plane == intel_crtc -> plane && dev_priv -> cfb_fb == fb -> base . id && dev_priv -> cfb_y == crtc -> y ) return ; if ( intel_fbc_enabled ( dev ) ) { DRM_DEBUG_KMS ( " \n " ) ; intel_disable_fbc ( dev ) ; } intel_enable_fbc ( crtc , 500 ) ; return ; out_disable : if ( intel_fbc_enabled ( dev ) ) { DRM_DEBUG_KMS ( " \n " ) ; intel_disable_fbc ( dev ) ; } }
intel_update_fbc - enable/disable FBC as needed
 @dev: the drm_device
intel_update_fbc - enable / disable FBC as needed @dev : the drm_device
/*
	 * If FBC is already on, we just have to verify that we can
	 * keep it that way...
	 * Need to disable if:
	 *   - more than one pipe is active
	 *   - changing FBC params (stride, fence, mode)
	 *   - new fb is too large to fit in compressed buffer
	 *   - going to an unsupported config (interlace, pixel multiply, etc.)
	 */ /* The use of a CPU fence is mandatory in order to detect writes
	 * by the CPU to the scanout and trigger updates to the FBC.
	 */ /* If the kernel debugger is active, always disable compression */ /* If the scanout has not changed, don't modify the FBC settings.
	 * Note that we make the fundamental assumption that the fb->obj
	 * cannot be unpinned (and have its GTT offset and fence revoked)
	 * without first being decoupled from the scanout and FBC disabled.
	 */ /* We update FBC along two paths, after changing fb/crtc
		 * configuration (modeswitching) and after page-flipping
		 * finishes. For the latter, we know that not only did
		 * we disable the FBC at the start of the page-flip
		 * sequence, but also more than one vblank has passed.
		 *
		 * For the former case of modeswitching, it is possible
		 * to switch between two FBC valid configurations
		 * instantaneously so we do need to disable the FBC
		 * before we can modify its control registers. We also
		 * have to wait for the next vblank for that to take
		 * effect. However, since we delay enabling FBC we can
		 * assume that a vblank has passed since disabling and
		 * that we can safely alter the registers in the deferred
		 * callback.
		 *
		 * In the scenario that we go from a valid to invalid
		 * and then back to valid FBC configuration we have
		 * no strict enforcement that a vblank occurred since
		 * disabling the FBC. However, along all current pipe
		 * disabling paths we do need to wait for a vblank at
		 * some point. And we wait before enabling FBC anyway.
		 */ /* Multiple disables should be harmless */