drm/i915: framebuffer compression for GM45+
Add support for framebuffer compression on GM45 and above. Removes some unnecessary I915_HAS_FBC checks as well (this is now part of the FBC display function). Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
parent
e70236a8d3
commit
74dff28223
4 changed files with 132 additions and 26 deletions
|
@ -1119,34 +1119,47 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
|||
return;
|
||||
}
|
||||
|
||||
compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096, 4096, 0);
|
||||
if (!compressed_llb) {
|
||||
i915_warn_stolen(dev);
|
||||
return;
|
||||
cfb_base = i915_gtt_to_phys(dev, compressed_fb->start);
|
||||
if (!cfb_base) {
|
||||
DRM_ERROR("failed to get stolen phys addr, disabling FBC\n");
|
||||
drm_mm_put_block(compressed_fb);
|
||||
}
|
||||
|
||||
compressed_llb = drm_mm_get_block(compressed_llb, 4096, 4096);
|
||||
if (!compressed_llb) {
|
||||
i915_warn_stolen(dev);
|
||||
return;
|
||||
if (!IS_GM45(dev)) {
|
||||
compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096,
|
||||
4096, 0);
|
||||
if (!compressed_llb) {
|
||||
i915_warn_stolen(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
compressed_llb = drm_mm_get_block(compressed_llb, 4096, 4096);
|
||||
if (!compressed_llb) {
|
||||
i915_warn_stolen(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
ll_base = i915_gtt_to_phys(dev, compressed_llb->start);
|
||||
if (!ll_base) {
|
||||
DRM_ERROR("failed to get stolen phys addr, disabling FBC\n");
|
||||
drm_mm_put_block(compressed_fb);
|
||||
drm_mm_put_block(compressed_llb);
|
||||
}
|
||||
}
|
||||
|
||||
dev_priv->cfb_size = size;
|
||||
|
||||
cfb_base = i915_gtt_to_phys(dev, compressed_fb->start);
|
||||
ll_base = i915_gtt_to_phys(dev, compressed_llb->start);
|
||||
if (!cfb_base || !ll_base) {
|
||||
DRM_ERROR("failed to get stolen phys addr, disabling FBC\n");
|
||||
drm_mm_put_block(compressed_fb);
|
||||
drm_mm_put_block(compressed_llb);
|
||||
if (IS_GM45(dev)) {
|
||||
g4x_disable_fbc(dev);
|
||||
I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
|
||||
} else {
|
||||
i8xx_disable_fbc(dev);
|
||||
I915_WRITE(FBC_CFB_BASE, cfb_base);
|
||||
I915_WRITE(FBC_LL_BASE, ll_base);
|
||||
}
|
||||
|
||||
i8xx_disable_fbc(dev);
|
||||
|
||||
DRM_DEBUG("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base,
|
||||
ll_base, size >> 20);
|
||||
I915_WRITE(FBC_CFB_BASE, cfb_base);
|
||||
I915_WRITE(FBC_LL_BASE, ll_base);
|
||||
}
|
||||
|
||||
static int i915_load_modeset_init(struct drm_device *dev,
|
||||
|
@ -1194,7 +1207,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
|
|||
goto out;
|
||||
|
||||
/* Try to set up FBC with a reasonable compressed buffer size */
|
||||
if (IS_MOBILE(dev) && (IS_I9XX(dev) || IS_I965G(dev)) &&
|
||||
if (IS_MOBILE(dev) && (IS_I9XX(dev) || IS_I965G(dev) || IS_GM45(dev)) &&
|
||||
i915_powersave) {
|
||||
int cfb_size;
|
||||
|
||||
|
|
|
@ -827,6 +827,7 @@ static inline void opregion_enable_asle(struct drm_device *dev) { return; }
|
|||
extern void intel_modeset_init(struct drm_device *dev);
|
||||
extern void intel_modeset_cleanup(struct drm_device *dev);
|
||||
extern void i8xx_disable_fbc(struct drm_device *dev);
|
||||
extern void g4x_disable_fbc(struct drm_device *dev);
|
||||
|
||||
/**
|
||||
* Lock test for when it's just for synchronization of ring access.
|
||||
|
|
|
@ -351,6 +351,33 @@
|
|||
|
||||
#define FBC_LL_SIZE (1536)
|
||||
|
||||
/* Framebuffer compression for GM45+ */
|
||||
#define DPFC_CB_BASE 0x3200
|
||||
#define DPFC_CONTROL 0x3208
|
||||
#define DPFC_CTL_EN (1<<31)
|
||||
#define DPFC_CTL_PLANEA (0<<30)
|
||||
#define DPFC_CTL_PLANEB (1<<30)
|
||||
#define DPFC_CTL_FENCE_EN (1<<29)
|
||||
#define DPFC_SR_EN (1<<10)
|
||||
#define DPFC_CTL_LIMIT_1X (0<<6)
|
||||
#define DPFC_CTL_LIMIT_2X (1<<6)
|
||||
#define DPFC_CTL_LIMIT_4X (2<<6)
|
||||
#define DPFC_RECOMP_CTL 0x320c
|
||||
#define DPFC_RECOMP_STALL_EN (1<<27)
|
||||
#define DPFC_RECOMP_STALL_WM_SHIFT (16)
|
||||
#define DPFC_RECOMP_STALL_WM_MASK (0x07ff0000)
|
||||
#define DPFC_RECOMP_TIMER_COUNT_SHIFT (0)
|
||||
#define DPFC_RECOMP_TIMER_COUNT_MASK (0x0000003f)
|
||||
#define DPFC_STATUS 0x3210
|
||||
#define DPFC_INVAL_SEG_SHIFT (16)
|
||||
#define DPFC_INVAL_SEG_MASK (0x07ff0000)
|
||||
#define DPFC_COMP_SEG_SHIFT (0)
|
||||
#define DPFC_COMP_SEG_MASK (0x000003ff)
|
||||
#define DPFC_STATUS2 0x3214
|
||||
#define DPFC_FENCE_YOFF 0x3218
|
||||
#define DPFC_CHICKEN 0x3224
|
||||
#define DPFC_HT_MODIFY (1<<31)
|
||||
|
||||
/*
|
||||
* GPIO regs
|
||||
*/
|
||||
|
|
|
@ -1030,6 +1030,65 @@ static bool i8xx_fbc_enabled(struct drm_crtc *crtc)
|
|||
return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
|
||||
}
|
||||
|
||||
static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_framebuffer *fb = crtc->fb;
|
||||
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
|
||||
struct drm_i915_gem_object *obj_priv = intel_fb->obj->driver_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA :
|
||||
DPFC_CTL_PLANEB);
|
||||
unsigned long stall_watermark = 200;
|
||||
u32 dpfc_ctl;
|
||||
|
||||
dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
|
||||
dev_priv->cfb_fence = obj_priv->fence_reg;
|
||||
dev_priv->cfb_plane = intel_crtc->plane;
|
||||
|
||||
dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
|
||||
if (obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
dpfc_ctl |= DPFC_CTL_FENCE_EN | dev_priv->cfb_fence;
|
||||
I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
|
||||
} else {
|
||||
I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY);
|
||||
}
|
||||
|
||||
I915_WRITE(DPFC_CONTROL, dpfc_ctl);
|
||||
I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
|
||||
(stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
|
||||
(interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
|
||||
I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
|
||||
|
||||
/* enable it... */
|
||||
I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN);
|
||||
|
||||
DRM_DEBUG("enabled fbc on plane %d\n", intel_crtc->plane);
|
||||
}
|
||||
|
||||
void g4x_disable_fbc(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpfc_ctl;
|
||||
|
||||
/* Disable compression */
|
||||
dpfc_ctl = I915_READ(DPFC_CONTROL);
|
||||
dpfc_ctl &= ~DPFC_CTL_EN;
|
||||
I915_WRITE(DPFC_CONTROL, dpfc_ctl);
|
||||
intel_wait_for_vblank(dev);
|
||||
|
||||
DRM_DEBUG("disabled FBC\n");
|
||||
}
|
||||
|
||||
static bool g4x_fbc_enabled(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_update_fbc - enable/disable FBC as needed
|
||||
* @crtc: CRTC to point the compressor at
|
||||
|
@ -1097,7 +1156,7 @@ static void intel_update_fbc(struct drm_crtc *crtc,
|
|||
DRM_DEBUG("mode too large for compression, disabling\n");
|
||||
goto out_disable;
|
||||
}
|
||||
if (IS_I9XX(dev) && plane != 0) {
|
||||
if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
|
||||
DRM_DEBUG("plane not 0, disabling compression\n");
|
||||
goto out_disable;
|
||||
}
|
||||
|
@ -1265,7 +1324,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
I915_READ(dspbase);
|
||||
}
|
||||
|
||||
if (I915_HAS_FBC(dev) && (IS_I965G(dev) || plane == 0))
|
||||
if ((IS_I965G(dev) || plane == 0))
|
||||
intel_update_fbc(crtc, &crtc->mode);
|
||||
|
||||
intel_wait_for_vblank(dev);
|
||||
|
@ -1774,7 +1833,8 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
|
||||
intel_crtc_load_lut(crtc);
|
||||
|
||||
intel_update_fbc(crtc, &crtc->mode);
|
||||
if ((IS_I965G(dev) || plane == 0))
|
||||
intel_update_fbc(crtc, &crtc->mode);
|
||||
|
||||
/* Give the overlay scaler a chance to enable if it's on this pipe */
|
||||
//intel_crtc_dpms_video(crtc, true); TODO
|
||||
|
@ -2988,7 +3048,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
/* Flush the plane changes */
|
||||
ret = intel_pipe_set_base(crtc, x, y, old_fb);
|
||||
|
||||
intel_update_fbc(crtc, &crtc->mode);
|
||||
if ((IS_I965G(dev) || plane == 0))
|
||||
intel_update_fbc(crtc, &crtc->mode);
|
||||
|
||||
intel_update_watermarks(dev);
|
||||
|
||||
|
@ -3121,7 +3182,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
drm_gem_object_unreference(intel_crtc->cursor_bo);
|
||||
}
|
||||
|
||||
if (I915_HAS_FBC(dev) && (IS_I965G(dev) || plane == 0))
|
||||
if ((IS_I965G(dev) || plane == 0))
|
||||
intel_update_fbc(crtc, &crtc->mode);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
@ -4108,12 +4169,16 @@ static void intel_init_display(struct drm_device *dev)
|
|||
|
||||
/* Only mobile has FBC, leave pointers NULL for other chips */
|
||||
if (IS_MOBILE(dev)) {
|
||||
/* 855GM needs testing */
|
||||
if (IS_I965GM(dev) || IS_I945GM(dev) || IS_I915GM(dev)) {
|
||||
if (IS_GM45(dev)) {
|
||||
dev_priv->display.fbc_enabled = g4x_fbc_enabled;
|
||||
dev_priv->display.enable_fbc = g4x_enable_fbc;
|
||||
dev_priv->display.disable_fbc = g4x_disable_fbc;
|
||||
} else if (IS_I965GM(dev) || IS_I945GM(dev) || IS_I915GM(dev)) {
|
||||
dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
|
||||
dev_priv->display.enable_fbc = i8xx_enable_fbc;
|
||||
dev_priv->display.disable_fbc = i8xx_disable_fbc;
|
||||
}
|
||||
/* 855GM needs testing */
|
||||
}
|
||||
|
||||
/* Returns the core display clock speed */
|
||||
|
|
Reference in a new issue