|
@@ -421,6 +421,16 @@ void intel_disable_fbc(struct drm_device *dev)
|
|
|
dev_priv->fbc.plane = -1;
|
|
|
}
|
|
|
|
|
|
+static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
|
|
|
+ enum no_fbc_reason reason)
|
|
|
+{
|
|
|
+ if (dev_priv->fbc.no_fbc_reason == reason)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ dev_priv->fbc.no_fbc_reason = reason;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* intel_update_fbc - enable/disable FBC as needed
|
|
|
* @dev: the drm_device
|
|
@@ -450,11 +460,16 @@ void intel_update_fbc(struct drm_device *dev)
|
|
|
struct drm_i915_gem_object *obj;
|
|
|
unsigned int max_hdisplay, max_vdisplay;
|
|
|
|
|
|
- if (!i915_powersave)
|
|
|
+ if (!I915_HAS_FBC(dev)) {
|
|
|
+ set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
- if (!I915_HAS_FBC(dev))
|
|
|
+ if (!i915_powersave) {
|
|
|
+ if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
|
|
|
+ DRM_DEBUG_KMS("fbc disabled per module param\n");
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* If FBC is already on, we just have to verify that we can
|
|
@@ -469,9 +484,8 @@ void intel_update_fbc(struct drm_device *dev)
|
|
|
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->fbc.no_fbc_reason =
|
|
|
- FBC_MULTIPLE_PIPES;
|
|
|
+ if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
|
|
|
+ DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
|
|
|
goto out_disable;
|
|
|
}
|
|
|
crtc = tmp_crtc;
|
|
@@ -479,8 +493,8 @@ void intel_update_fbc(struct drm_device *dev)
|
|
|
}
|
|
|
|
|
|
if (!crtc || crtc->fb == NULL) {
|
|
|
- DRM_DEBUG_KMS("no output, disabling\n");
|
|
|
- dev_priv->fbc.no_fbc_reason = FBC_NO_OUTPUT;
|
|
|
+ if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
|
|
|
+ DRM_DEBUG_KMS("no output, disabling\n");
|
|
|
goto out_disable;
|
|
|
}
|
|
|
|
|
@@ -491,20 +505,20 @@ void intel_update_fbc(struct drm_device *dev)
|
|
|
|
|
|
if (i915_enable_fbc < 0 &&
|
|
|
INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) {
|
|
|
- DRM_DEBUG_KMS("disabled per chip default\n");
|
|
|
- dev_priv->fbc.no_fbc_reason = FBC_CHIP_DEFAULT;
|
|
|
+ if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
|
|
|
+ DRM_DEBUG_KMS("disabled per chip default\n");
|
|
|
goto out_disable;
|
|
|
}
|
|
|
if (!i915_enable_fbc) {
|
|
|
- DRM_DEBUG_KMS("fbc disabled per module param\n");
|
|
|
- dev_priv->fbc.no_fbc_reason = FBC_MODULE_PARAM;
|
|
|
+ if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
|
|
|
+ DRM_DEBUG_KMS("fbc disabled per module param\n");
|
|
|
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->fbc.no_fbc_reason = FBC_UNSUPPORTED_MODE;
|
|
|
+ if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
|
|
|
+ DRM_DEBUG_KMS("mode incompatible with compression, "
|
|
|
+ "disabling\n");
|
|
|
goto out_disable;
|
|
|
}
|
|
|
|
|
@@ -517,14 +531,14 @@ void intel_update_fbc(struct drm_device *dev)
|
|
|
}
|
|
|
if ((crtc->mode.hdisplay > max_hdisplay) ||
|
|
|
(crtc->mode.vdisplay > max_vdisplay)) {
|
|
|
- DRM_DEBUG_KMS("mode too large for compression, disabling\n");
|
|
|
- dev_priv->fbc.no_fbc_reason = FBC_MODE_TOO_LARGE;
|
|
|
+ if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE))
|
|
|
+ DRM_DEBUG_KMS("mode too large for compression, disabling\n");
|
|
|
goto out_disable;
|
|
|
}
|
|
|
if ((IS_I915GM(dev) || IS_I945GM(dev) || IS_HASWELL(dev)) &&
|
|
|
intel_crtc->plane != 0) {
|
|
|
- DRM_DEBUG_KMS("plane not 0, disabling compression\n");
|
|
|
- dev_priv->fbc.no_fbc_reason = FBC_BAD_PLANE;
|
|
|
+ if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE))
|
|
|
+ DRM_DEBUG_KMS("plane not 0, disabling compression\n");
|
|
|
goto out_disable;
|
|
|
}
|
|
|
|
|
@@ -533,8 +547,8 @@ void intel_update_fbc(struct drm_device *dev)
|
|
|
*/
|
|
|
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->fbc.no_fbc_reason = FBC_NOT_TILED;
|
|
|
+ if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED))
|
|
|
+ DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
|
|
|
goto out_disable;
|
|
|
}
|
|
|
|
|
@@ -543,8 +557,8 @@ void intel_update_fbc(struct drm_device *dev)
|
|
|
goto out_disable;
|
|
|
|
|
|
if (i915_gem_stolen_setup_compression(dev, intel_fb->obj->base.size)) {
|
|
|
- DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
|
|
|
- dev_priv->fbc.no_fbc_reason = FBC_STOLEN_TOO_SMALL;
|
|
|
+ if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL))
|
|
|
+ DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
|
|
|
goto out_disable;
|
|
|
}
|
|
|
|
|
@@ -587,6 +601,7 @@ void intel_update_fbc(struct drm_device *dev)
|
|
|
}
|
|
|
|
|
|
intel_enable_fbc(crtc, 500);
|
|
|
+ dev_priv->fbc.no_fbc_reason = FBC_OK;
|
|
|
return;
|
|
|
|
|
|
out_disable:
|
|
@@ -1665,9 +1680,6 @@ static void i830_update_wm(struct drm_device *dev)
|
|
|
I915_WRITE(FW_BLC, fwater_lo);
|
|
|
}
|
|
|
|
|
|
-#define ILK_LP0_PLANE_LATENCY 700
|
|
|
-#define ILK_LP0_CURSOR_LATENCY 1300
|
|
|
-
|
|
|
/*
|
|
|
* Check the wm result.
|
|
|
*
|
|
@@ -1782,9 +1794,9 @@ static void ironlake_update_wm(struct drm_device *dev)
|
|
|
enabled = 0;
|
|
|
if (g4x_compute_wm0(dev, PIPE_A,
|
|
|
&ironlake_display_wm_info,
|
|
|
- ILK_LP0_PLANE_LATENCY,
|
|
|
+ dev_priv->wm.pri_latency[0] * 100,
|
|
|
&ironlake_cursor_wm_info,
|
|
|
- ILK_LP0_CURSOR_LATENCY,
|
|
|
+ dev_priv->wm.cur_latency[0] * 100,
|
|
|
&plane_wm, &cursor_wm)) {
|
|
|
I915_WRITE(WM0_PIPEA_ILK,
|
|
|
(plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
|
|
@@ -1796,9 +1808,9 @@ static void ironlake_update_wm(struct drm_device *dev)
|
|
|
|
|
|
if (g4x_compute_wm0(dev, PIPE_B,
|
|
|
&ironlake_display_wm_info,
|
|
|
- ILK_LP0_PLANE_LATENCY,
|
|
|
+ dev_priv->wm.pri_latency[0] * 100,
|
|
|
&ironlake_cursor_wm_info,
|
|
|
- ILK_LP0_CURSOR_LATENCY,
|
|
|
+ dev_priv->wm.cur_latency[0] * 100,
|
|
|
&plane_wm, &cursor_wm)) {
|
|
|
I915_WRITE(WM0_PIPEB_ILK,
|
|
|
(plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
|
|
@@ -1822,7 +1834,7 @@ static void ironlake_update_wm(struct drm_device *dev)
|
|
|
|
|
|
/* WM1 */
|
|
|
if (!ironlake_compute_srwm(dev, 1, enabled,
|
|
|
- ILK_READ_WM1_LATENCY() * 500,
|
|
|
+ dev_priv->wm.pri_latency[1] * 500,
|
|
|
&ironlake_display_srwm_info,
|
|
|
&ironlake_cursor_srwm_info,
|
|
|
&fbc_wm, &plane_wm, &cursor_wm))
|
|
@@ -1830,14 +1842,14 @@ static void ironlake_update_wm(struct drm_device *dev)
|
|
|
|
|
|
I915_WRITE(WM1_LP_ILK,
|
|
|
WM1_LP_SR_EN |
|
|
|
- (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
|
|
|
+ (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) |
|
|
|
(fbc_wm << WM1_LP_FBC_SHIFT) |
|
|
|
(plane_wm << WM1_LP_SR_SHIFT) |
|
|
|
cursor_wm);
|
|
|
|
|
|
/* WM2 */
|
|
|
if (!ironlake_compute_srwm(dev, 2, enabled,
|
|
|
- ILK_READ_WM2_LATENCY() * 500,
|
|
|
+ dev_priv->wm.pri_latency[2] * 500,
|
|
|
&ironlake_display_srwm_info,
|
|
|
&ironlake_cursor_srwm_info,
|
|
|
&fbc_wm, &plane_wm, &cursor_wm))
|
|
@@ -1845,7 +1857,7 @@ static void ironlake_update_wm(struct drm_device *dev)
|
|
|
|
|
|
I915_WRITE(WM2_LP_ILK,
|
|
|
WM2_LP_EN |
|
|
|
- (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
|
|
|
+ (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) |
|
|
|
(fbc_wm << WM1_LP_FBC_SHIFT) |
|
|
|
(plane_wm << WM1_LP_SR_SHIFT) |
|
|
|
cursor_wm);
|
|
@@ -1859,7 +1871,7 @@ static void ironlake_update_wm(struct drm_device *dev)
|
|
|
static void sandybridge_update_wm(struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
- int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
|
|
|
+ int latency = dev_priv->wm.pri_latency[0] * 100; /* In unit 0.1us */
|
|
|
u32 val;
|
|
|
int fbc_wm, plane_wm, cursor_wm;
|
|
|
unsigned int enabled;
|
|
@@ -1914,7 +1926,7 @@ static void sandybridge_update_wm(struct drm_device *dev)
|
|
|
|
|
|
/* WM1 */
|
|
|
if (!ironlake_compute_srwm(dev, 1, enabled,
|
|
|
- SNB_READ_WM1_LATENCY() * 500,
|
|
|
+ dev_priv->wm.pri_latency[1] * 500,
|
|
|
&sandybridge_display_srwm_info,
|
|
|
&sandybridge_cursor_srwm_info,
|
|
|
&fbc_wm, &plane_wm, &cursor_wm))
|
|
@@ -1922,14 +1934,14 @@ static void sandybridge_update_wm(struct drm_device *dev)
|
|
|
|
|
|
I915_WRITE(WM1_LP_ILK,
|
|
|
WM1_LP_SR_EN |
|
|
|
- (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
|
|
|
+ (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) |
|
|
|
(fbc_wm << WM1_LP_FBC_SHIFT) |
|
|
|
(plane_wm << WM1_LP_SR_SHIFT) |
|
|
|
cursor_wm);
|
|
|
|
|
|
/* WM2 */
|
|
|
if (!ironlake_compute_srwm(dev, 2, enabled,
|
|
|
- SNB_READ_WM2_LATENCY() * 500,
|
|
|
+ dev_priv->wm.pri_latency[2] * 500,
|
|
|
&sandybridge_display_srwm_info,
|
|
|
&sandybridge_cursor_srwm_info,
|
|
|
&fbc_wm, &plane_wm, &cursor_wm))
|
|
@@ -1937,14 +1949,14 @@ static void sandybridge_update_wm(struct drm_device *dev)
|
|
|
|
|
|
I915_WRITE(WM2_LP_ILK,
|
|
|
WM2_LP_EN |
|
|
|
- (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
|
|
|
+ (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) |
|
|
|
(fbc_wm << WM1_LP_FBC_SHIFT) |
|
|
|
(plane_wm << WM1_LP_SR_SHIFT) |
|
|
|
cursor_wm);
|
|
|
|
|
|
/* WM3 */
|
|
|
if (!ironlake_compute_srwm(dev, 3, enabled,
|
|
|
- SNB_READ_WM3_LATENCY() * 500,
|
|
|
+ dev_priv->wm.pri_latency[3] * 500,
|
|
|
&sandybridge_display_srwm_info,
|
|
|
&sandybridge_cursor_srwm_info,
|
|
|
&fbc_wm, &plane_wm, &cursor_wm))
|
|
@@ -1952,7 +1964,7 @@ static void sandybridge_update_wm(struct drm_device *dev)
|
|
|
|
|
|
I915_WRITE(WM3_LP_ILK,
|
|
|
WM3_LP_EN |
|
|
|
- (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
|
|
|
+ (dev_priv->wm.pri_latency[3] << WM1_LP_LATENCY_SHIFT) |
|
|
|
(fbc_wm << WM1_LP_FBC_SHIFT) |
|
|
|
(plane_wm << WM1_LP_SR_SHIFT) |
|
|
|
cursor_wm);
|
|
@@ -1961,7 +1973,7 @@ static void sandybridge_update_wm(struct drm_device *dev)
|
|
|
static void ivybridge_update_wm(struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
- int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
|
|
|
+ int latency = dev_priv->wm.pri_latency[0] * 100; /* In unit 0.1us */
|
|
|
u32 val;
|
|
|
int fbc_wm, plane_wm, cursor_wm;
|
|
|
int ignore_fbc_wm, ignore_plane_wm, ignore_cursor_wm;
|
|
@@ -2031,7 +2043,7 @@ static void ivybridge_update_wm(struct drm_device *dev)
|
|
|
|
|
|
/* WM1 */
|
|
|
if (!ironlake_compute_srwm(dev, 1, enabled,
|
|
|
- SNB_READ_WM1_LATENCY() * 500,
|
|
|
+ dev_priv->wm.pri_latency[1] * 500,
|
|
|
&sandybridge_display_srwm_info,
|
|
|
&sandybridge_cursor_srwm_info,
|
|
|
&fbc_wm, &plane_wm, &cursor_wm))
|
|
@@ -2039,14 +2051,14 @@ static void ivybridge_update_wm(struct drm_device *dev)
|
|
|
|
|
|
I915_WRITE(WM1_LP_ILK,
|
|
|
WM1_LP_SR_EN |
|
|
|
- (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
|
|
|
+ (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) |
|
|
|
(fbc_wm << WM1_LP_FBC_SHIFT) |
|
|
|
(plane_wm << WM1_LP_SR_SHIFT) |
|
|
|
cursor_wm);
|
|
|
|
|
|
/* WM2 */
|
|
|
if (!ironlake_compute_srwm(dev, 2, enabled,
|
|
|
- SNB_READ_WM2_LATENCY() * 500,
|
|
|
+ dev_priv->wm.pri_latency[2] * 500,
|
|
|
&sandybridge_display_srwm_info,
|
|
|
&sandybridge_cursor_srwm_info,
|
|
|
&fbc_wm, &plane_wm, &cursor_wm))
|
|
@@ -2054,19 +2066,19 @@ static void ivybridge_update_wm(struct drm_device *dev)
|
|
|
|
|
|
I915_WRITE(WM2_LP_ILK,
|
|
|
WM2_LP_EN |
|
|
|
- (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
|
|
|
+ (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) |
|
|
|
(fbc_wm << WM1_LP_FBC_SHIFT) |
|
|
|
(plane_wm << WM1_LP_SR_SHIFT) |
|
|
|
cursor_wm);
|
|
|
|
|
|
/* WM3, note we have to correct the cursor latency */
|
|
|
if (!ironlake_compute_srwm(dev, 3, enabled,
|
|
|
- SNB_READ_WM3_LATENCY() * 500,
|
|
|
+ dev_priv->wm.pri_latency[3] * 500,
|
|
|
&sandybridge_display_srwm_info,
|
|
|
&sandybridge_cursor_srwm_info,
|
|
|
&fbc_wm, &plane_wm, &ignore_cursor_wm) ||
|
|
|
!ironlake_compute_srwm(dev, 3, enabled,
|
|
|
- 2 * SNB_READ_WM3_LATENCY() * 500,
|
|
|
+ dev_priv->wm.cur_latency[3] * 500,
|
|
|
&sandybridge_display_srwm_info,
|
|
|
&sandybridge_cursor_srwm_info,
|
|
|
&ignore_fbc_wm, &ignore_plane_wm, &cursor_wm))
|
|
@@ -2074,14 +2086,14 @@ static void ivybridge_update_wm(struct drm_device *dev)
|
|
|
|
|
|
I915_WRITE(WM3_LP_ILK,
|
|
|
WM3_LP_EN |
|
|
|
- (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
|
|
|
+ (dev_priv->wm.pri_latency[3] << WM1_LP_LATENCY_SHIFT) |
|
|
|
(fbc_wm << WM1_LP_FBC_SHIFT) |
|
|
|
(plane_wm << WM1_LP_SR_SHIFT) |
|
|
|
cursor_wm);
|
|
|
}
|
|
|
|
|
|
-static uint32_t hsw_wm_get_pixel_rate(struct drm_device *dev,
|
|
|
- struct drm_crtc *crtc)
|
|
|
+static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev,
|
|
|
+ struct drm_crtc *crtc)
|
|
|
{
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
uint32_t pixel_rate, pfit_size;
|
|
@@ -2111,30 +2123,38 @@ static uint32_t hsw_wm_get_pixel_rate(struct drm_device *dev,
|
|
|
return pixel_rate;
|
|
|
}
|
|
|
|
|
|
-static uint32_t hsw_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel,
|
|
|
+/* latency must be in 0.1us units. */
|
|
|
+static uint32_t ilk_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel,
|
|
|
uint32_t latency)
|
|
|
{
|
|
|
uint64_t ret;
|
|
|
|
|
|
+ if (WARN(latency == 0, "Latency value missing\n"))
|
|
|
+ return UINT_MAX;
|
|
|
+
|
|
|
ret = (uint64_t) pixel_rate * bytes_per_pixel * latency;
|
|
|
ret = DIV_ROUND_UP_ULL(ret, 64 * 10000) + 2;
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static uint32_t hsw_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
|
|
|
+/* latency must be in 0.1us units. */
|
|
|
+static uint32_t ilk_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
|
|
|
uint32_t horiz_pixels, uint8_t bytes_per_pixel,
|
|
|
uint32_t latency)
|
|
|
{
|
|
|
uint32_t ret;
|
|
|
|
|
|
+ if (WARN(latency == 0, "Latency value missing\n"))
|
|
|
+ return UINT_MAX;
|
|
|
+
|
|
|
ret = (latency * pixel_rate) / (pipe_htotal * 10000);
|
|
|
ret = (ret + 1) * horiz_pixels * bytes_per_pixel;
|
|
|
ret = DIV_ROUND_UP(ret, 64) + 2;
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static uint32_t hsw_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels,
|
|
|
+static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels,
|
|
|
uint8_t bytes_per_pixel)
|
|
|
{
|
|
|
return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2;
|
|
@@ -2142,15 +2162,11 @@ static uint32_t hsw_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels,
|
|
|
|
|
|
struct hsw_pipe_wm_parameters {
|
|
|
bool active;
|
|
|
- bool sprite_enabled;
|
|
|
- uint8_t pri_bytes_per_pixel;
|
|
|
- uint8_t spr_bytes_per_pixel;
|
|
|
- uint8_t cur_bytes_per_pixel;
|
|
|
- uint32_t pri_horiz_pixels;
|
|
|
- uint32_t spr_horiz_pixels;
|
|
|
- uint32_t cur_horiz_pixels;
|
|
|
uint32_t pipe_htotal;
|
|
|
uint32_t pixel_rate;
|
|
|
+ struct intel_plane_wm_parameters pri;
|
|
|
+ struct intel_plane_wm_parameters spr;
|
|
|
+ struct intel_plane_wm_parameters cur;
|
|
|
};
|
|
|
|
|
|
struct hsw_wm_maximums {
|
|
@@ -2160,15 +2176,6 @@ struct hsw_wm_maximums {
|
|
|
uint16_t fbc;
|
|
|
};
|
|
|
|
|
|
-struct hsw_lp_wm_result {
|
|
|
- bool enable;
|
|
|
- bool fbc_enable;
|
|
|
- uint32_t pri_val;
|
|
|
- uint32_t spr_val;
|
|
|
- uint32_t cur_val;
|
|
|
- uint32_t fbc_val;
|
|
|
-};
|
|
|
-
|
|
|
struct hsw_wm_values {
|
|
|
uint32_t wm_pipe[3];
|
|
|
uint32_t wm_lp[3];
|
|
@@ -2177,128 +2184,289 @@ struct hsw_wm_values {
|
|
|
bool enable_fbc_wm;
|
|
|
};
|
|
|
|
|
|
-enum hsw_data_buf_partitioning {
|
|
|
- HSW_DATA_BUF_PART_1_2,
|
|
|
- HSW_DATA_BUF_PART_5_6,
|
|
|
+/* used in computing the new watermarks state */
|
|
|
+struct intel_wm_config {
|
|
|
+ unsigned int num_pipes_active;
|
|
|
+ bool sprites_enabled;
|
|
|
+ bool sprites_scaled;
|
|
|
+ bool fbc_wm_enabled;
|
|
|
};
|
|
|
|
|
|
-/* For both WM_PIPE and WM_LP. */
|
|
|
-static uint32_t hsw_compute_pri_wm(struct hsw_pipe_wm_parameters *params,
|
|
|
+/*
|
|
|
+ * For both WM_PIPE and WM_LP.
|
|
|
+ * mem_value must be in 0.1us units.
|
|
|
+ */
|
|
|
+static uint32_t ilk_compute_pri_wm(struct hsw_pipe_wm_parameters *params,
|
|
|
uint32_t mem_value,
|
|
|
bool is_lp)
|
|
|
{
|
|
|
uint32_t method1, method2;
|
|
|
|
|
|
- /* TODO: for now, assume the primary plane is always enabled. */
|
|
|
- if (!params->active)
|
|
|
+ if (!params->active || !params->pri.enabled)
|
|
|
return 0;
|
|
|
|
|
|
- method1 = hsw_wm_method1(params->pixel_rate,
|
|
|
- params->pri_bytes_per_pixel,
|
|
|
+ method1 = ilk_wm_method1(params->pixel_rate,
|
|
|
+ params->pri.bytes_per_pixel,
|
|
|
mem_value);
|
|
|
|
|
|
if (!is_lp)
|
|
|
return method1;
|
|
|
|
|
|
- method2 = hsw_wm_method2(params->pixel_rate,
|
|
|
+ method2 = ilk_wm_method2(params->pixel_rate,
|
|
|
params->pipe_htotal,
|
|
|
- params->pri_horiz_pixels,
|
|
|
- params->pri_bytes_per_pixel,
|
|
|
+ params->pri.horiz_pixels,
|
|
|
+ params->pri.bytes_per_pixel,
|
|
|
mem_value);
|
|
|
|
|
|
return min(method1, method2);
|
|
|
}
|
|
|
|
|
|
-/* For both WM_PIPE and WM_LP. */
|
|
|
-static uint32_t hsw_compute_spr_wm(struct hsw_pipe_wm_parameters *params,
|
|
|
+/*
|
|
|
+ * For both WM_PIPE and WM_LP.
|
|
|
+ * mem_value must be in 0.1us units.
|
|
|
+ */
|
|
|
+static uint32_t ilk_compute_spr_wm(struct hsw_pipe_wm_parameters *params,
|
|
|
uint32_t mem_value)
|
|
|
{
|
|
|
uint32_t method1, method2;
|
|
|
|
|
|
- if (!params->active || !params->sprite_enabled)
|
|
|
+ if (!params->active || !params->spr.enabled)
|
|
|
return 0;
|
|
|
|
|
|
- method1 = hsw_wm_method1(params->pixel_rate,
|
|
|
- params->spr_bytes_per_pixel,
|
|
|
+ method1 = ilk_wm_method1(params->pixel_rate,
|
|
|
+ params->spr.bytes_per_pixel,
|
|
|
mem_value);
|
|
|
- method2 = hsw_wm_method2(params->pixel_rate,
|
|
|
+ method2 = ilk_wm_method2(params->pixel_rate,
|
|
|
params->pipe_htotal,
|
|
|
- params->spr_horiz_pixels,
|
|
|
- params->spr_bytes_per_pixel,
|
|
|
+ params->spr.horiz_pixels,
|
|
|
+ params->spr.bytes_per_pixel,
|
|
|
mem_value);
|
|
|
return min(method1, method2);
|
|
|
}
|
|
|
|
|
|
-/* For both WM_PIPE and WM_LP. */
|
|
|
-static uint32_t hsw_compute_cur_wm(struct hsw_pipe_wm_parameters *params,
|
|
|
+/*
|
|
|
+ * For both WM_PIPE and WM_LP.
|
|
|
+ * mem_value must be in 0.1us units.
|
|
|
+ */
|
|
|
+static uint32_t ilk_compute_cur_wm(struct hsw_pipe_wm_parameters *params,
|
|
|
uint32_t mem_value)
|
|
|
{
|
|
|
- if (!params->active)
|
|
|
+ if (!params->active || !params->cur.enabled)
|
|
|
return 0;
|
|
|
|
|
|
- return hsw_wm_method2(params->pixel_rate,
|
|
|
+ return ilk_wm_method2(params->pixel_rate,
|
|
|
params->pipe_htotal,
|
|
|
- params->cur_horiz_pixels,
|
|
|
- params->cur_bytes_per_pixel,
|
|
|
+ params->cur.horiz_pixels,
|
|
|
+ params->cur.bytes_per_pixel,
|
|
|
mem_value);
|
|
|
}
|
|
|
|
|
|
/* Only for WM_LP. */
|
|
|
-static uint32_t hsw_compute_fbc_wm(struct hsw_pipe_wm_parameters *params,
|
|
|
- uint32_t pri_val,
|
|
|
- uint32_t mem_value)
|
|
|
+static uint32_t ilk_compute_fbc_wm(struct hsw_pipe_wm_parameters *params,
|
|
|
+ uint32_t pri_val)
|
|
|
{
|
|
|
- if (!params->active)
|
|
|
+ if (!params->active || !params->pri.enabled)
|
|
|
return 0;
|
|
|
|
|
|
- return hsw_wm_fbc(pri_val,
|
|
|
- params->pri_horiz_pixels,
|
|
|
- params->pri_bytes_per_pixel);
|
|
|
+ return ilk_wm_fbc(pri_val,
|
|
|
+ params->pri.horiz_pixels,
|
|
|
+ params->pri.bytes_per_pixel);
|
|
|
}
|
|
|
|
|
|
-static bool hsw_compute_lp_wm(uint32_t mem_value, struct hsw_wm_maximums *max,
|
|
|
- struct hsw_pipe_wm_parameters *params,
|
|
|
- struct hsw_lp_wm_result *result)
|
|
|
+static unsigned int ilk_display_fifo_size(const struct drm_device *dev)
|
|
|
{
|
|
|
- enum pipe pipe;
|
|
|
- uint32_t pri_val[3], spr_val[3], cur_val[3], fbc_val[3];
|
|
|
+ if (INTEL_INFO(dev)->gen >= 7)
|
|
|
+ return 768;
|
|
|
+ else
|
|
|
+ return 512;
|
|
|
+}
|
|
|
|
|
|
- for (pipe = PIPE_A; pipe <= PIPE_C; pipe++) {
|
|
|
- struct hsw_pipe_wm_parameters *p = ¶ms[pipe];
|
|
|
+/* Calculate the maximum primary/sprite plane watermark */
|
|
|
+static unsigned int ilk_plane_wm_max(const struct drm_device *dev,
|
|
|
+ int level,
|
|
|
+ const struct intel_wm_config *config,
|
|
|
+ enum intel_ddb_partitioning ddb_partitioning,
|
|
|
+ bool is_sprite)
|
|
|
+{
|
|
|
+ unsigned int fifo_size = ilk_display_fifo_size(dev);
|
|
|
+ unsigned int max;
|
|
|
|
|
|
- pri_val[pipe] = hsw_compute_pri_wm(p, mem_value, true);
|
|
|
- spr_val[pipe] = hsw_compute_spr_wm(p, mem_value);
|
|
|
- cur_val[pipe] = hsw_compute_cur_wm(p, mem_value);
|
|
|
- fbc_val[pipe] = hsw_compute_fbc_wm(p, pri_val[pipe], mem_value);
|
|
|
- }
|
|
|
+ /* if sprites aren't enabled, sprites get nothing */
|
|
|
+ if (is_sprite && !config->sprites_enabled)
|
|
|
+ return 0;
|
|
|
|
|
|
- result->pri_val = max3(pri_val[0], pri_val[1], pri_val[2]);
|
|
|
- result->spr_val = max3(spr_val[0], spr_val[1], spr_val[2]);
|
|
|
- result->cur_val = max3(cur_val[0], cur_val[1], cur_val[2]);
|
|
|
- result->fbc_val = max3(fbc_val[0], fbc_val[1], fbc_val[2]);
|
|
|
+ /* HSW allows LP1+ watermarks even with multiple pipes */
|
|
|
+ if (level == 0 || config->num_pipes_active > 1) {
|
|
|
+ fifo_size /= INTEL_INFO(dev)->num_pipes;
|
|
|
|
|
|
- if (result->fbc_val > max->fbc) {
|
|
|
- result->fbc_enable = false;
|
|
|
- result->fbc_val = 0;
|
|
|
- } else {
|
|
|
- result->fbc_enable = true;
|
|
|
+ /*
|
|
|
+ * For some reason the non self refresh
|
|
|
+ * FIFO size is only half of the self
|
|
|
+ * refresh FIFO size on ILK/SNB.
|
|
|
+ */
|
|
|
+ if (INTEL_INFO(dev)->gen <= 6)
|
|
|
+ fifo_size /= 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (config->sprites_enabled) {
|
|
|
+ /* level 0 is always calculated with 1:1 split */
|
|
|
+ if (level > 0 && ddb_partitioning == INTEL_DDB_PART_5_6) {
|
|
|
+ if (is_sprite)
|
|
|
+ fifo_size *= 5;
|
|
|
+ fifo_size /= 6;
|
|
|
+ } else {
|
|
|
+ fifo_size /= 2;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ /* clamp to max that the registers can hold */
|
|
|
+ if (INTEL_INFO(dev)->gen >= 7)
|
|
|
+ /* IVB/HSW primary/sprite plane watermarks */
|
|
|
+ max = level == 0 ? 127 : 1023;
|
|
|
+ else if (!is_sprite)
|
|
|
+ /* ILK/SNB primary plane watermarks */
|
|
|
+ max = level == 0 ? 127 : 511;
|
|
|
+ else
|
|
|
+ /* ILK/SNB sprite plane watermarks */
|
|
|
+ max = level == 0 ? 63 : 255;
|
|
|
+
|
|
|
+ return min(fifo_size, max);
|
|
|
+}
|
|
|
+
|
|
|
+/* Calculate the maximum cursor plane watermark */
|
|
|
+static unsigned int ilk_cursor_wm_max(const struct drm_device *dev,
|
|
|
+ int level,
|
|
|
+ const struct intel_wm_config *config)
|
|
|
+{
|
|
|
+ /* HSW LP1+ watermarks w/ multiple pipes */
|
|
|
+ if (level > 0 && config->num_pipes_active > 1)
|
|
|
+ return 64;
|
|
|
+
|
|
|
+ /* otherwise just report max that registers can hold */
|
|
|
+ if (INTEL_INFO(dev)->gen >= 7)
|
|
|
+ return level == 0 ? 63 : 255;
|
|
|
+ else
|
|
|
+ return level == 0 ? 31 : 63;
|
|
|
+}
|
|
|
+
|
|
|
+/* Calculate the maximum FBC watermark */
|
|
|
+static unsigned int ilk_fbc_wm_max(void)
|
|
|
+{
|
|
|
+ /* max that registers can hold */
|
|
|
+ return 15;
|
|
|
+}
|
|
|
+
|
|
|
+static void ilk_wm_max(struct drm_device *dev,
|
|
|
+ int level,
|
|
|
+ const struct intel_wm_config *config,
|
|
|
+ enum intel_ddb_partitioning ddb_partitioning,
|
|
|
+ struct hsw_wm_maximums *max)
|
|
|
+{
|
|
|
+ max->pri = ilk_plane_wm_max(dev, level, config, ddb_partitioning, false);
|
|
|
+ max->spr = ilk_plane_wm_max(dev, level, config, ddb_partitioning, true);
|
|
|
+ max->cur = ilk_cursor_wm_max(dev, level, config);
|
|
|
+ max->fbc = ilk_fbc_wm_max();
|
|
|
+}
|
|
|
+
|
|
|
+static bool ilk_check_wm(int level,
|
|
|
+ const struct hsw_wm_maximums *max,
|
|
|
+ struct intel_wm_level *result)
|
|
|
+{
|
|
|
+ bool ret;
|
|
|
+
|
|
|
+ /* already determined to be invalid? */
|
|
|
+ if (!result->enable)
|
|
|
+ return false;
|
|
|
+
|
|
|
result->enable = result->pri_val <= max->pri &&
|
|
|
result->spr_val <= max->spr &&
|
|
|
result->cur_val <= max->cur;
|
|
|
- return result->enable;
|
|
|
+
|
|
|
+ ret = result->enable;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * HACK until we can pre-compute everything,
|
|
|
+ * and thus fail gracefully if LP0 watermarks
|
|
|
+ * are exceeded...
|
|
|
+ */
|
|
|
+ if (level == 0 && !result->enable) {
|
|
|
+ if (result->pri_val > max->pri)
|
|
|
+ DRM_DEBUG_KMS("Primary WM%d too large %u (max %u)\n",
|
|
|
+ level, result->pri_val, max->pri);
|
|
|
+ if (result->spr_val > max->spr)
|
|
|
+ DRM_DEBUG_KMS("Sprite WM%d too large %u (max %u)\n",
|
|
|
+ level, result->spr_val, max->spr);
|
|
|
+ if (result->cur_val > max->cur)
|
|
|
+ DRM_DEBUG_KMS("Cursor WM%d too large %u (max %u)\n",
|
|
|
+ level, result->cur_val, max->cur);
|
|
|
+
|
|
|
+ result->pri_val = min_t(uint32_t, result->pri_val, max->pri);
|
|
|
+ result->spr_val = min_t(uint32_t, result->spr_val, max->spr);
|
|
|
+ result->cur_val = min_t(uint32_t, result->cur_val, max->cur);
|
|
|
+ result->enable = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ DRM_DEBUG_KMS("WM%d: %sabled\n", level, result->enable ? "en" : "dis");
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static void ilk_compute_wm_level(struct drm_i915_private *dev_priv,
|
|
|
+ int level,
|
|
|
+ struct hsw_pipe_wm_parameters *p,
|
|
|
+ struct intel_wm_level *result)
|
|
|
+{
|
|
|
+ uint16_t pri_latency = dev_priv->wm.pri_latency[level];
|
|
|
+ uint16_t spr_latency = dev_priv->wm.spr_latency[level];
|
|
|
+ uint16_t cur_latency = dev_priv->wm.cur_latency[level];
|
|
|
+
|
|
|
+ /* WM1+ latency values stored in 0.5us units */
|
|
|
+ if (level > 0) {
|
|
|
+ pri_latency *= 5;
|
|
|
+ spr_latency *= 5;
|
|
|
+ cur_latency *= 5;
|
|
|
+ }
|
|
|
+
|
|
|
+ result->pri_val = ilk_compute_pri_wm(p, pri_latency, level);
|
|
|
+ result->spr_val = ilk_compute_spr_wm(p, spr_latency);
|
|
|
+ result->cur_val = ilk_compute_cur_wm(p, cur_latency);
|
|
|
+ result->fbc_val = ilk_compute_fbc_wm(p, result->pri_val);
|
|
|
+ result->enable = true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool hsw_compute_lp_wm(struct drm_i915_private *dev_priv,
|
|
|
+ int level, struct hsw_wm_maximums *max,
|
|
|
+ struct hsw_pipe_wm_parameters *params,
|
|
|
+ struct intel_wm_level *result)
|
|
|
+{
|
|
|
+ enum pipe pipe;
|
|
|
+ struct intel_wm_level res[3];
|
|
|
+
|
|
|
+ for (pipe = PIPE_A; pipe <= PIPE_C; pipe++)
|
|
|
+ ilk_compute_wm_level(dev_priv, level, ¶ms[pipe], &res[pipe]);
|
|
|
+
|
|
|
+ result->pri_val = max3(res[0].pri_val, res[1].pri_val, res[2].pri_val);
|
|
|
+ result->spr_val = max3(res[0].spr_val, res[1].spr_val, res[2].spr_val);
|
|
|
+ result->cur_val = max3(res[0].cur_val, res[1].cur_val, res[2].cur_val);
|
|
|
+ result->fbc_val = max3(res[0].fbc_val, res[1].fbc_val, res[2].fbc_val);
|
|
|
+ result->enable = true;
|
|
|
+
|
|
|
+ return ilk_check_wm(level, max, result);
|
|
|
}
|
|
|
|
|
|
static uint32_t hsw_compute_wm_pipe(struct drm_i915_private *dev_priv,
|
|
|
- uint32_t mem_value, enum pipe pipe,
|
|
|
+ enum pipe pipe,
|
|
|
struct hsw_pipe_wm_parameters *params)
|
|
|
{
|
|
|
uint32_t pri_val, cur_val, spr_val;
|
|
|
+ /* WM0 latency values stored in 0.1us units */
|
|
|
+ uint16_t pri_latency = dev_priv->wm.pri_latency[0];
|
|
|
+ uint16_t spr_latency = dev_priv->wm.spr_latency[0];
|
|
|
+ uint16_t cur_latency = dev_priv->wm.cur_latency[0];
|
|
|
|
|
|
- pri_val = hsw_compute_pri_wm(params, mem_value, false);
|
|
|
- spr_val = hsw_compute_spr_wm(params, mem_value);
|
|
|
- cur_val = hsw_compute_cur_wm(params, mem_value);
|
|
|
+ pri_val = ilk_compute_pri_wm(params, pri_latency, false);
|
|
|
+ spr_val = ilk_compute_spr_wm(params, spr_latency);
|
|
|
+ cur_val = ilk_compute_cur_wm(params, cur_latency);
|
|
|
|
|
|
WARN(pri_val > 127,
|
|
|
"Primary WM error, mode not supported for pipe %c\n",
|
|
@@ -2337,27 +2505,116 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc)
|
|
|
PIPE_WM_LINETIME_TIME(linetime);
|
|
|
}
|
|
|
|
|
|
+static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[5])
|
|
|
+{
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+
|
|
|
+ if (IS_HASWELL(dev)) {
|
|
|
+ uint64_t sskpd = I915_READ64(MCH_SSKPD);
|
|
|
+
|
|
|
+ wm[0] = (sskpd >> 56) & 0xFF;
|
|
|
+ if (wm[0] == 0)
|
|
|
+ wm[0] = sskpd & 0xF;
|
|
|
+ wm[1] = (sskpd >> 4) & 0xFF;
|
|
|
+ wm[2] = (sskpd >> 12) & 0xFF;
|
|
|
+ wm[3] = (sskpd >> 20) & 0x1FF;
|
|
|
+ wm[4] = (sskpd >> 32) & 0x1FF;
|
|
|
+ } else if (INTEL_INFO(dev)->gen >= 6) {
|
|
|
+ uint32_t sskpd = I915_READ(MCH_SSKPD);
|
|
|
+
|
|
|
+ wm[0] = (sskpd >> SSKPD_WM0_SHIFT) & SSKPD_WM_MASK;
|
|
|
+ wm[1] = (sskpd >> SSKPD_WM1_SHIFT) & SSKPD_WM_MASK;
|
|
|
+ wm[2] = (sskpd >> SSKPD_WM2_SHIFT) & SSKPD_WM_MASK;
|
|
|
+ wm[3] = (sskpd >> SSKPD_WM3_SHIFT) & SSKPD_WM_MASK;
|
|
|
+ } else if (INTEL_INFO(dev)->gen >= 5) {
|
|
|
+ uint32_t mltr = I915_READ(MLTR_ILK);
|
|
|
+
|
|
|
+ /* ILK primary LP0 latency is 700 ns */
|
|
|
+ wm[0] = 7;
|
|
|
+ wm[1] = (mltr >> MLTR_WM1_SHIFT) & ILK_SRLT_MASK;
|
|
|
+ wm[2] = (mltr >> MLTR_WM2_SHIFT) & ILK_SRLT_MASK;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void intel_fixup_spr_wm_latency(struct drm_device *dev, uint16_t wm[5])
|
|
|
+{
|
|
|
+ /* ILK sprite LP0 latency is 1300 ns */
|
|
|
+ if (INTEL_INFO(dev)->gen == 5)
|
|
|
+ wm[0] = 13;
|
|
|
+}
|
|
|
+
|
|
|
+static void intel_fixup_cur_wm_latency(struct drm_device *dev, uint16_t wm[5])
|
|
|
+{
|
|
|
+ /* ILK cursor LP0 latency is 1300 ns */
|
|
|
+ if (INTEL_INFO(dev)->gen == 5)
|
|
|
+ wm[0] = 13;
|
|
|
+
|
|
|
+ /* WaDoubleCursorLP3Latency:ivb */
|
|
|
+ if (IS_IVYBRIDGE(dev))
|
|
|
+ wm[3] *= 2;
|
|
|
+}
|
|
|
+
|
|
|
+static void intel_print_wm_latency(struct drm_device *dev,
|
|
|
+ const char *name,
|
|
|
+ const uint16_t wm[5])
|
|
|
+{
|
|
|
+ int level, max_level;
|
|
|
+
|
|
|
+ /* how many WM levels are we expecting */
|
|
|
+ if (IS_HASWELL(dev))
|
|
|
+ max_level = 4;
|
|
|
+ else if (INTEL_INFO(dev)->gen >= 6)
|
|
|
+ max_level = 3;
|
|
|
+ else
|
|
|
+ max_level = 2;
|
|
|
+
|
|
|
+ for (level = 0; level <= max_level; level++) {
|
|
|
+ unsigned int latency = wm[level];
|
|
|
+
|
|
|
+ if (latency == 0) {
|
|
|
+ DRM_ERROR("%s WM%d latency not provided\n",
|
|
|
+ name, level);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* WM1+ latency values in 0.5us units */
|
|
|
+ if (level > 0)
|
|
|
+ latency *= 5;
|
|
|
+
|
|
|
+ DRM_DEBUG_KMS("%s WM%d latency %u (%u.%u usec)\n",
|
|
|
+ name, level, wm[level],
|
|
|
+ latency / 10, latency % 10);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void intel_setup_wm_latency(struct drm_device *dev)
|
|
|
+{
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+
|
|
|
+ intel_read_wm_latency(dev, dev_priv->wm.pri_latency);
|
|
|
+
|
|
|
+ memcpy(dev_priv->wm.spr_latency, dev_priv->wm.pri_latency,
|
|
|
+ sizeof(dev_priv->wm.pri_latency));
|
|
|
+ memcpy(dev_priv->wm.cur_latency, dev_priv->wm.pri_latency,
|
|
|
+ sizeof(dev_priv->wm.pri_latency));
|
|
|
+
|
|
|
+ intel_fixup_spr_wm_latency(dev, dev_priv->wm.spr_latency);
|
|
|
+ intel_fixup_cur_wm_latency(dev, dev_priv->wm.cur_latency);
|
|
|
+
|
|
|
+ intel_print_wm_latency(dev, "Primary", dev_priv->wm.pri_latency);
|
|
|
+ intel_print_wm_latency(dev, "Sprite", dev_priv->wm.spr_latency);
|
|
|
+ intel_print_wm_latency(dev, "Cursor", dev_priv->wm.cur_latency);
|
|
|
+}
|
|
|
+
|
|
|
static void hsw_compute_wm_parameters(struct drm_device *dev,
|
|
|
struct hsw_pipe_wm_parameters *params,
|
|
|
- uint32_t *wm,
|
|
|
struct hsw_wm_maximums *lp_max_1_2,
|
|
|
struct hsw_wm_maximums *lp_max_5_6)
|
|
|
{
|
|
|
- struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
struct drm_crtc *crtc;
|
|
|
struct drm_plane *plane;
|
|
|
- uint64_t sskpd = I915_READ64(MCH_SSKPD);
|
|
|
enum pipe pipe;
|
|
|
- int pipes_active = 0, sprites_enabled = 0;
|
|
|
-
|
|
|
- if ((sskpd >> 56) & 0xFF)
|
|
|
- wm[0] = (sskpd >> 56) & 0xFF;
|
|
|
- else
|
|
|
- wm[0] = sskpd & 0xF;
|
|
|
- wm[1] = ((sskpd >> 4) & 0xFF) * 5;
|
|
|
- wm[2] = ((sskpd >> 12) & 0xFF) * 5;
|
|
|
- wm[3] = ((sskpd >> 20) & 0x1FF) * 5;
|
|
|
- wm[4] = ((sskpd >> 32) & 0x1FF) * 5;
|
|
|
+ struct intel_wm_config config = {};
|
|
|
|
|
|
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
@@ -2370,15 +2627,18 @@ static void hsw_compute_wm_parameters(struct drm_device *dev,
|
|
|
if (!p->active)
|
|
|
continue;
|
|
|
|
|
|
- pipes_active++;
|
|
|
+ config.num_pipes_active++;
|
|
|
|
|
|
p->pipe_htotal = intel_crtc->config.adjusted_mode.htotal;
|
|
|
- p->pixel_rate = hsw_wm_get_pixel_rate(dev, crtc);
|
|
|
- p->pri_bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
|
|
|
- p->cur_bytes_per_pixel = 4;
|
|
|
- p->pri_horiz_pixels =
|
|
|
+ p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
|
|
|
+ p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
|
|
|
+ p->cur.bytes_per_pixel = 4;
|
|
|
+ p->pri.horiz_pixels =
|
|
|
intel_crtc->config.requested_mode.hdisplay;
|
|
|
- p->cur_horiz_pixels = 64;
|
|
|
+ p->cur.horiz_pixels = 64;
|
|
|
+ /* TODO: for now, assume primary and cursor planes are always enabled. */
|
|
|
+ p->pri.enabled = true;
|
|
|
+ p->cur.enabled = true;
|
|
|
}
|
|
|
|
|
|
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
|
|
@@ -2388,59 +2648,53 @@ static void hsw_compute_wm_parameters(struct drm_device *dev,
|
|
|
pipe = intel_plane->pipe;
|
|
|
p = ¶ms[pipe];
|
|
|
|
|
|
- p->sprite_enabled = intel_plane->wm.enable;
|
|
|
- p->spr_bytes_per_pixel = intel_plane->wm.bytes_per_pixel;
|
|
|
- p->spr_horiz_pixels = intel_plane->wm.horiz_pixels;
|
|
|
+ p->spr = intel_plane->wm;
|
|
|
|
|
|
- if (p->sprite_enabled)
|
|
|
- sprites_enabled++;
|
|
|
+ config.sprites_enabled |= p->spr.enabled;
|
|
|
+ config.sprites_scaled |= p->spr.scaled;
|
|
|
}
|
|
|
|
|
|
- if (pipes_active > 1) {
|
|
|
- lp_max_1_2->pri = lp_max_5_6->pri = sprites_enabled ? 128 : 256;
|
|
|
- lp_max_1_2->spr = lp_max_5_6->spr = 128;
|
|
|
- lp_max_1_2->cur = lp_max_5_6->cur = 64;
|
|
|
- } else {
|
|
|
- lp_max_1_2->pri = sprites_enabled ? 384 : 768;
|
|
|
- lp_max_5_6->pri = sprites_enabled ? 128 : 768;
|
|
|
- lp_max_1_2->spr = 384;
|
|
|
- lp_max_5_6->spr = 640;
|
|
|
- lp_max_1_2->cur = lp_max_5_6->cur = 255;
|
|
|
- }
|
|
|
- lp_max_1_2->fbc = lp_max_5_6->fbc = 15;
|
|
|
+ ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_1_2, lp_max_1_2);
|
|
|
+
|
|
|
+ /* 5/6 split only in single pipe config on IVB+ */
|
|
|
+ if (INTEL_INFO(dev)->gen >= 7 && config.num_pipes_active <= 1)
|
|
|
+ ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_5_6, lp_max_5_6);
|
|
|
+ else
|
|
|
+ *lp_max_5_6 = *lp_max_1_2;
|
|
|
}
|
|
|
|
|
|
static void hsw_compute_wm_results(struct drm_device *dev,
|
|
|
struct hsw_pipe_wm_parameters *params,
|
|
|
- uint32_t *wm,
|
|
|
struct hsw_wm_maximums *lp_maximums,
|
|
|
struct hsw_wm_values *results)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
struct drm_crtc *crtc;
|
|
|
- struct hsw_lp_wm_result lp_results[4] = {};
|
|
|
+ struct intel_wm_level lp_results[4] = {};
|
|
|
enum pipe pipe;
|
|
|
int level, max_level, wm_lp;
|
|
|
|
|
|
for (level = 1; level <= 4; level++)
|
|
|
- if (!hsw_compute_lp_wm(wm[level], lp_maximums, params,
|
|
|
+ if (!hsw_compute_lp_wm(dev_priv, level,
|
|
|
+ lp_maximums, params,
|
|
|
&lp_results[level - 1]))
|
|
|
break;
|
|
|
max_level = level - 1;
|
|
|
|
|
|
+ memset(results, 0, sizeof(*results));
|
|
|
+
|
|
|
/* The spec says it is preferred to disable FBC WMs instead of disabling
|
|
|
* a WM level. */
|
|
|
results->enable_fbc_wm = true;
|
|
|
for (level = 1; level <= max_level; level++) {
|
|
|
- if (!lp_results[level - 1].fbc_enable) {
|
|
|
+ if (lp_results[level - 1].fbc_val > lp_maximums->fbc) {
|
|
|
results->enable_fbc_wm = false;
|
|
|
- break;
|
|
|
+ lp_results[level - 1].fbc_val = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- memset(results, 0, sizeof(*results));
|
|
|
for (wm_lp = 1; wm_lp <= 3; wm_lp++) {
|
|
|
- const struct hsw_lp_wm_result *r;
|
|
|
+ const struct intel_wm_level *r;
|
|
|
|
|
|
level = (max_level == 4 && wm_lp > 1) ? wm_lp + 1 : wm_lp;
|
|
|
if (level > max_level)
|
|
@@ -2455,8 +2709,7 @@ static void hsw_compute_wm_results(struct drm_device *dev,
|
|
|
}
|
|
|
|
|
|
for_each_pipe(pipe)
|
|
|
- results->wm_pipe[pipe] = hsw_compute_wm_pipe(dev_priv, wm[0],
|
|
|
- pipe,
|
|
|
+ results->wm_pipe[pipe] = hsw_compute_wm_pipe(dev_priv, pipe,
|
|
|
¶ms[pipe]);
|
|
|
|
|
|
for_each_pipe(pipe) {
|
|
@@ -2497,11 +2750,11 @@ static struct hsw_wm_values *hsw_find_best_result(struct hsw_wm_values *r1,
|
|
|
*/
|
|
|
static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
|
|
|
struct hsw_wm_values *results,
|
|
|
- enum hsw_data_buf_partitioning partitioning)
|
|
|
+ enum intel_ddb_partitioning partitioning)
|
|
|
{
|
|
|
struct hsw_wm_values previous;
|
|
|
uint32_t val;
|
|
|
- enum hsw_data_buf_partitioning prev_partitioning;
|
|
|
+ enum intel_ddb_partitioning prev_partitioning;
|
|
|
bool prev_enable_fbc_wm;
|
|
|
|
|
|
previous.wm_pipe[0] = I915_READ(WM0_PIPEA_ILK);
|
|
@@ -2518,7 +2771,7 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
|
|
|
previous.wm_linetime[2] = I915_READ(PIPE_WM_LINETIME(PIPE_C));
|
|
|
|
|
|
prev_partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ?
|
|
|
- HSW_DATA_BUF_PART_5_6 : HSW_DATA_BUF_PART_1_2;
|
|
|
+ INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
|
|
|
|
|
|
prev_enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS);
|
|
|
|
|
@@ -2557,7 +2810,7 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
|
|
|
|
|
|
if (prev_partitioning != partitioning) {
|
|
|
val = I915_READ(WM_MISC);
|
|
|
- if (partitioning == HSW_DATA_BUF_PART_1_2)
|
|
|
+ if (partitioning == INTEL_DDB_PART_1_2)
|
|
|
val &= ~WM_MISC_DATA_PARTITION_5_6;
|
|
|
else
|
|
|
val |= WM_MISC_DATA_PARTITION_5_6;
|
|
@@ -2594,44 +2847,39 @@ static void haswell_update_wm(struct drm_device *dev)
|
|
|
struct hsw_wm_maximums lp_max_1_2, lp_max_5_6;
|
|
|
struct hsw_pipe_wm_parameters params[3];
|
|
|
struct hsw_wm_values results_1_2, results_5_6, *best_results;
|
|
|
- uint32_t wm[5];
|
|
|
- enum hsw_data_buf_partitioning partitioning;
|
|
|
+ enum intel_ddb_partitioning partitioning;
|
|
|
|
|
|
- hsw_compute_wm_parameters(dev, params, wm, &lp_max_1_2, &lp_max_5_6);
|
|
|
+ hsw_compute_wm_parameters(dev, params, &lp_max_1_2, &lp_max_5_6);
|
|
|
|
|
|
- hsw_compute_wm_results(dev, params, wm, &lp_max_1_2, &results_1_2);
|
|
|
+ hsw_compute_wm_results(dev, params,
|
|
|
+ &lp_max_1_2, &results_1_2);
|
|
|
if (lp_max_1_2.pri != lp_max_5_6.pri) {
|
|
|
- hsw_compute_wm_results(dev, params, wm, &lp_max_5_6,
|
|
|
- &results_5_6);
|
|
|
+ hsw_compute_wm_results(dev, params,
|
|
|
+ &lp_max_5_6, &results_5_6);
|
|
|
best_results = hsw_find_best_result(&results_1_2, &results_5_6);
|
|
|
} else {
|
|
|
best_results = &results_1_2;
|
|
|
}
|
|
|
|
|
|
partitioning = (best_results == &results_1_2) ?
|
|
|
- HSW_DATA_BUF_PART_1_2 : HSW_DATA_BUF_PART_5_6;
|
|
|
+ INTEL_DDB_PART_1_2 : INTEL_DDB_PART_5_6;
|
|
|
|
|
|
hsw_write_wm_values(dev_priv, best_results, partitioning);
|
|
|
}
|
|
|
|
|
|
-static void haswell_update_sprite_wm(struct drm_device *dev, int pipe,
|
|
|
+static void haswell_update_sprite_wm(struct drm_plane *plane,
|
|
|
+ struct drm_crtc *crtc,
|
|
|
uint32_t sprite_width, int pixel_size,
|
|
|
- bool enable)
|
|
|
+ bool enabled, bool scaled)
|
|
|
{
|
|
|
- struct drm_plane *plane;
|
|
|
+ struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
|
|
|
|
- list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
|
|
|
- struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
|
-
|
|
|
- if (intel_plane->pipe == pipe) {
|
|
|
- intel_plane->wm.enable = enable;
|
|
|
- intel_plane->wm.horiz_pixels = sprite_width + 1;
|
|
|
- intel_plane->wm.bytes_per_pixel = pixel_size;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ intel_plane->wm.enabled = enabled;
|
|
|
+ intel_plane->wm.scaled = scaled;
|
|
|
+ intel_plane->wm.horiz_pixels = sprite_width;
|
|
|
+ intel_plane->wm.bytes_per_pixel = pixel_size;
|
|
|
|
|
|
- haswell_update_wm(dev);
|
|
|
+ haswell_update_wm(plane->dev);
|
|
|
}
|
|
|
|
|
|
static bool
|
|
@@ -2710,17 +2958,20 @@ sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
|
|
|
return *sprite_wm > 0x3ff ? false : true;
|
|
|
}
|
|
|
|
|
|
-static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
|
|
|
+static void sandybridge_update_sprite_wm(struct drm_plane *plane,
|
|
|
+ struct drm_crtc *crtc,
|
|
|
uint32_t sprite_width, int pixel_size,
|
|
|
- bool enable)
|
|
|
+ bool enabled, bool scaled)
|
|
|
{
|
|
|
+ struct drm_device *dev = plane->dev;
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
- int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
|
|
|
+ int pipe = to_intel_plane(plane)->pipe;
|
|
|
+ int latency = dev_priv->wm.spr_latency[0] * 100; /* In unit 0.1us */
|
|
|
u32 val;
|
|
|
int sprite_wm, reg;
|
|
|
int ret;
|
|
|
|
|
|
- if (!enable)
|
|
|
+ if (!enabled)
|
|
|
return;
|
|
|
|
|
|
switch (pipe) {
|
|
@@ -2755,7 +3006,7 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
|
|
|
ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
|
|
|
pixel_size,
|
|
|
&sandybridge_display_srwm_info,
|
|
|
- SNB_READ_WM1_LATENCY() * 500,
|
|
|
+ dev_priv->wm.spr_latency[1] * 500,
|
|
|
&sprite_wm);
|
|
|
if (!ret) {
|
|
|
DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %c\n",
|
|
@@ -2771,7 +3022,7 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
|
|
|
ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
|
|
|
pixel_size,
|
|
|
&sandybridge_display_srwm_info,
|
|
|
- SNB_READ_WM2_LATENCY() * 500,
|
|
|
+ dev_priv->wm.spr_latency[2] * 500,
|
|
|
&sprite_wm);
|
|
|
if (!ret) {
|
|
|
DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %c\n",
|
|
@@ -2783,7 +3034,7 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
|
|
|
ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
|
|
|
pixel_size,
|
|
|
&sandybridge_display_srwm_info,
|
|
|
- SNB_READ_WM3_LATENCY() * 500,
|
|
|
+ dev_priv->wm.spr_latency[3] * 500,
|
|
|
&sprite_wm);
|
|
|
if (!ret) {
|
|
|
DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %c\n",
|
|
@@ -2833,15 +3084,16 @@ void intel_update_watermarks(struct drm_device *dev)
|
|
|
dev_priv->display.update_wm(dev);
|
|
|
}
|
|
|
|
|
|
-void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
|
|
|
+void intel_update_sprite_watermarks(struct drm_plane *plane,
|
|
|
+ struct drm_crtc *crtc,
|
|
|
uint32_t sprite_width, int pixel_size,
|
|
|
- bool enable)
|
|
|
+ bool enabled, bool scaled)
|
|
|
{
|
|
|
- struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+ struct drm_i915_private *dev_priv = plane->dev->dev_private;
|
|
|
|
|
|
if (dev_priv->display.update_sprite_wm)
|
|
|
- dev_priv->display.update_sprite_wm(dev, pipe, sprite_width,
|
|
|
- pixel_size, enable);
|
|
|
+ dev_priv->display.update_sprite_wm(plane, crtc, sprite_width,
|
|
|
+ pixel_size, enabled, scaled);
|
|
|
}
|
|
|
|
|
|
static struct drm_i915_gem_object *
|
|
@@ -2858,7 +3110,7 @@ intel_alloc_context_page(struct drm_device *dev)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
- ret = i915_gem_object_pin(ctx, 4096, true, false);
|
|
|
+ ret = i915_gem_obj_ggtt_pin(ctx, 4096, true, false);
|
|
|
if (ret) {
|
|
|
DRM_ERROR("failed to pin power context: %d\n", ret);
|
|
|
goto err_unref;
|
|
@@ -5194,8 +5446,12 @@ void intel_init_pm(struct drm_device *dev)
|
|
|
|
|
|
/* For FIFO watermark updates */
|
|
|
if (HAS_PCH_SPLIT(dev)) {
|
|
|
+ intel_setup_wm_latency(dev);
|
|
|
+
|
|
|
if (IS_GEN5(dev)) {
|
|
|
- if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
|
|
|
+ if (dev_priv->wm.pri_latency[1] &&
|
|
|
+ dev_priv->wm.spr_latency[1] &&
|
|
|
+ dev_priv->wm.cur_latency[1])
|
|
|
dev_priv->display.update_wm = ironlake_update_wm;
|
|
|
else {
|
|
|
DRM_DEBUG_KMS("Failed to get proper latency. "
|
|
@@ -5204,7 +5460,9 @@ void intel_init_pm(struct drm_device *dev)
|
|
|
}
|
|
|
dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
|
|
|
} else if (IS_GEN6(dev)) {
|
|
|
- if (SNB_READ_WM0_LATENCY()) {
|
|
|
+ if (dev_priv->wm.pri_latency[0] &&
|
|
|
+ dev_priv->wm.spr_latency[0] &&
|
|
|
+ dev_priv->wm.cur_latency[0]) {
|
|
|
dev_priv->display.update_wm = sandybridge_update_wm;
|
|
|
dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
|
|
|
} else {
|
|
@@ -5214,7 +5472,9 @@ void intel_init_pm(struct drm_device *dev)
|
|
|
}
|
|
|
dev_priv->display.init_clock_gating = gen6_init_clock_gating;
|
|
|
} else if (IS_IVYBRIDGE(dev)) {
|
|
|
- if (SNB_READ_WM0_LATENCY()) {
|
|
|
+ if (dev_priv->wm.pri_latency[0] &&
|
|
|
+ dev_priv->wm.spr_latency[0] &&
|
|
|
+ dev_priv->wm.cur_latency[0]) {
|
|
|
dev_priv->display.update_wm = ivybridge_update_wm;
|
|
|
dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
|
|
|
} else {
|
|
@@ -5224,7 +5484,9 @@ void intel_init_pm(struct drm_device *dev)
|
|
|
}
|
|
|
dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
|
|
|
} else if (IS_HASWELL(dev)) {
|
|
|
- if (I915_READ64(MCH_SSKPD)) {
|
|
|
+ if (dev_priv->wm.pri_latency[0] &&
|
|
|
+ dev_priv->wm.spr_latency[0] &&
|
|
|
+ dev_priv->wm.cur_latency[0]) {
|
|
|
dev_priv->display.update_wm = haswell_update_wm;
|
|
|
dev_priv->display.update_sprite_wm =
|
|
|
haswell_update_sprite_wm;
|