mirror of
https://github.com/torvalds/linux.git
synced 2024-11-20 02:51:44 +00:00
drm/i915: Add frame buffer compression support on Ironlake mobile
About 0.2W power can be saved on one HP laptop. Signed-off-by: Zhao Yakui <yakui.zhao@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
parent
c936f44d1b
commit
b52eb4dcab
@ -1257,7 +1257,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
||||
drm_mm_put_block(compressed_fb);
|
||||
}
|
||||
|
||||
if (!IS_GM45(dev)) {
|
||||
if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) {
|
||||
compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096,
|
||||
4096, 0);
|
||||
if (!compressed_llb) {
|
||||
@ -1283,8 +1283,9 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
||||
|
||||
intel_disable_fbc(dev);
|
||||
dev_priv->compressed_fb = compressed_fb;
|
||||
|
||||
if (IS_GM45(dev)) {
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
|
||||
else if (IS_GM45(dev)) {
|
||||
I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
|
||||
} else {
|
||||
I915_WRITE(FBC_CFB_BASE, cfb_base);
|
||||
@ -1292,7 +1293,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
||||
dev_priv->compressed_llb = compressed_llb;
|
||||
}
|
||||
|
||||
DRM_DEBUG("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base,
|
||||
DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base,
|
||||
ll_base, size >> 20);
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ static const struct intel_device_info intel_ironlake_d_info = {
|
||||
|
||||
static const struct intel_device_info intel_ironlake_m_info = {
|
||||
.is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1,
|
||||
.need_gfx_hws = 1, .has_rc6 = 1,
|
||||
.need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
|
||||
.has_hotplug = 1,
|
||||
};
|
||||
|
||||
|
@ -1042,6 +1042,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev);
|
||||
extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
|
||||
extern void i8xx_disable_fbc(struct drm_device *dev);
|
||||
extern void g4x_disable_fbc(struct drm_device *dev);
|
||||
extern void ironlake_disable_fbc(struct drm_device *dev);
|
||||
extern void intel_disable_fbc(struct drm_device *dev);
|
||||
extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
|
||||
extern bool intel_fbc_enabled(struct drm_device *dev);
|
||||
|
@ -530,6 +530,21 @@
|
||||
#define DPFC_CHICKEN 0x3224
|
||||
#define DPFC_HT_MODIFY (1<<31)
|
||||
|
||||
/* Framebuffer compression for Ironlake */
|
||||
#define ILK_DPFC_CB_BASE 0x43200
|
||||
#define ILK_DPFC_CONTROL 0x43208
|
||||
/* The bit 28-8 is reserved */
|
||||
#define DPFC_RESERVED (0x1FFFFF00)
|
||||
#define ILK_DPFC_RECOMP_CTL 0x4320c
|
||||
#define ILK_DPFC_STATUS 0x43210
|
||||
#define ILK_DPFC_FENCE_YOFF 0x43218
|
||||
#define ILK_DPFC_CHICKEN 0x43224
|
||||
#define ILK_FBC_RT_BASE 0x2128
|
||||
#define ILK_FBC_RT_VALID (1<<0)
|
||||
|
||||
#define ILK_DISPLAY_CHICKEN1 0x42000
|
||||
#define ILK_FBCQ_DIS (1<<22)
|
||||
|
||||
/*
|
||||
* GPIO regs
|
||||
*/
|
||||
@ -2491,6 +2506,10 @@
|
||||
#define ILK_VSDPFD_FULL (1<<21)
|
||||
#define ILK_DSPCLK_GATE 0x42020
|
||||
#define ILK_DPARB_CLK_GATE (1<<5)
|
||||
/* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */
|
||||
#define ILK_CLK_FBC (1<<7)
|
||||
#define ILK_DPFC_DIS1 (1<<8)
|
||||
#define ILK_DPFC_DIS2 (1<<9)
|
||||
|
||||
#define DISP_ARB_CTL 0x45000
|
||||
#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
|
||||
|
@ -602,7 +602,9 @@ void i915_save_display(struct drm_device *dev)
|
||||
|
||||
/* Only save FBC state on the platform that supports FBC */
|
||||
if (I915_HAS_FBC(dev)) {
|
||||
if (IS_GM45(dev)) {
|
||||
if (IS_IRONLAKE_M(dev)) {
|
||||
dev_priv->saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE);
|
||||
} else if (IS_GM45(dev)) {
|
||||
dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
|
||||
} else {
|
||||
dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
|
||||
@ -706,7 +708,10 @@ void i915_restore_display(struct drm_device *dev)
|
||||
|
||||
/* only restore FBC info on the platform that supports FBC*/
|
||||
if (I915_HAS_FBC(dev)) {
|
||||
if (IS_GM45(dev)) {
|
||||
if (IS_IRONLAKE_M(dev)) {
|
||||
ironlake_disable_fbc(dev);
|
||||
I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
|
||||
} else if (IS_GM45(dev)) {
|
||||
g4x_disable_fbc(dev);
|
||||
I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
|
||||
} else {
|
||||
|
@ -1123,6 +1123,67 @@ static bool g4x_fbc_enabled(struct drm_device *dev)
|
||||
return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
|
||||
}
|
||||
|
||||
static void ironlake_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 = to_intel_bo(intel_fb->obj);
|
||||
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 = I915_READ(ILK_DPFC_CONTROL);
|
||||
dpfc_ctl &= DPFC_RESERVED;
|
||||
dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
|
||||
if (obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence);
|
||||
I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
|
||||
} else {
|
||||
I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY);
|
||||
}
|
||||
|
||||
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
|
||||
I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
|
||||
(stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
|
||||
(interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
|
||||
I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
|
||||
I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID);
|
||||
/* enable it... */
|
||||
I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) |
|
||||
DPFC_CTL_EN);
|
||||
|
||||
DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
|
||||
}
|
||||
|
||||
void ironlake_disable_fbc(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpfc_ctl;
|
||||
|
||||
/* Disable compression */
|
||||
dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
|
||||
dpfc_ctl &= ~DPFC_CTL_EN;
|
||||
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
|
||||
intel_wait_for_vblank(dev);
|
||||
|
||||
DRM_DEBUG_KMS("disabled FBC\n");
|
||||
}
|
||||
|
||||
static bool ironlake_fbc_enabled(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
|
||||
}
|
||||
|
||||
bool intel_fbc_enabled(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
@ -1966,6 +2027,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
|
||||
intel_crtc_load_lut(crtc);
|
||||
|
||||
intel_update_fbc(crtc, &crtc->mode);
|
||||
|
||||
break;
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
DRM_DEBUG_KMS("crtc %d dpms off\n", pipe);
|
||||
@ -1980,6 +2043,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
I915_READ(dspbase_reg);
|
||||
}
|
||||
|
||||
if (dev_priv->cfb_plane == plane &&
|
||||
dev_priv->display.disable_fbc)
|
||||
dev_priv->display.disable_fbc(dev);
|
||||
|
||||
i915_disable_vga(dev);
|
||||
|
||||
/* disable cpu pipe, disable after all planes disabled */
|
||||
@ -5452,6 +5519,26 @@ void intel_init_clock_gating(struct drm_device *dev)
|
||||
(I915_READ(DISP_ARB_CTL) |
|
||||
DISP_FBC_WM_DIS));
|
||||
}
|
||||
/*
|
||||
* Based on the document from hardware guys the following bits
|
||||
* should be set unconditionally in order to enable FBC.
|
||||
* The bit 22 of 0x42000
|
||||
* The bit 22 of 0x42004
|
||||
* The bit 7,8,9 of 0x42020.
|
||||
*/
|
||||
if (IS_IRONLAKE_M(dev)) {
|
||||
I915_WRITE(ILK_DISPLAY_CHICKEN1,
|
||||
I915_READ(ILK_DISPLAY_CHICKEN1) |
|
||||
ILK_FBCQ_DIS);
|
||||
I915_WRITE(ILK_DISPLAY_CHICKEN2,
|
||||
I915_READ(ILK_DISPLAY_CHICKEN2) |
|
||||
ILK_DPARB_GATE);
|
||||
I915_WRITE(ILK_DSPCLK_GATE,
|
||||
I915_READ(ILK_DSPCLK_GATE) |
|
||||
ILK_DPFC_DIS1 |
|
||||
ILK_DPFC_DIS2 |
|
||||
ILK_CLK_FBC);
|
||||
}
|
||||
return;
|
||||
} else if (IS_G4X(dev)) {
|
||||
uint32_t dspclk_gate;
|
||||
@ -5530,7 +5617,11 @@ static void intel_init_display(struct drm_device *dev)
|
||||
dev_priv->display.dpms = i9xx_crtc_dpms;
|
||||
|
||||
if (I915_HAS_FBC(dev)) {
|
||||
if (IS_GM45(dev)) {
|
||||
if (IS_IRONLAKE_M(dev)) {
|
||||
dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
|
||||
dev_priv->display.enable_fbc = ironlake_enable_fbc;
|
||||
dev_priv->display.disable_fbc = ironlake_disable_fbc;
|
||||
} else 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;
|
||||
|
Loading…
Reference in New Issue
Block a user