[Intel-gfx] [PATCH 30/35] drm/i915: Replace the ILK/SNB/IVB/HSW watermark code
Paulo Zanoni
przanoni at gmail.com
Fri Jul 5 19:51:36 CEST 2013
2013/7/5 <ville.syrjala at linux.intel.com>:
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
>
> There is a major problem with the watermark registers; they're not
> double buffered. So we need to make sure we update them at the correct
> time when messing about with planes. The correct time is the beginning
> of vblank.
>
> So when we determine that the watermarks need to updated hand in hand
> with the next vblank, we store the pre-computed watermarks under
> intel_crtc, and when the vblank happens, we promote the pending
> watermarks to active status.
>
> on HSW when the watermarks for any pipe change, we must merge the
> watermarks from all pipes so that we can determine the correct LP1+
> watermark levels. For simplicity we follow the same codepaths for
> pre-HSW hardware as well, but there all the LP1+ watermarks will be
> disabled when multiple pipes are enabled. Once the watermarks are
> merged we check them for validity, disabling any invalid levels.
>
> Touching the watermark registers causes the hardware to re-evaluate the
> watermarks, which expeds some power. So after merging the watermarks
> we check which watermark registers actually need to be changed. And
> finally we write the watermarks registers in the correct order.
This patch is way too big for us, poor reviewers. Can you split this
into many many many tiny patches? I see *a lot* of different changes
here.
>
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> ---
> drivers/gpu/drm/i915/i915_drv.h | 12 +
> drivers/gpu/drm/i915/i915_irq.c | 12 +-
> drivers/gpu/drm/i915/i915_reg.h | 2 +
> drivers/gpu/drm/i915/intel_drv.h | 22 +
> drivers/gpu/drm/i915/intel_pm.c | 1546 ++++++++++++++++----------------------
> 5 files changed, 686 insertions(+), 908 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index fd57bed..446be9a 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1198,6 +1198,7 @@ typedef struct drm_i915_private {
>
> struct i915_suspend_saved_registers regfile;
>
> + /* per-device watermark state */
> struct {
> /* watermark latency values for primary */
> uint16_t pri_latency[5];
> @@ -1205,6 +1206,17 @@ typedef struct drm_i915_private {
> uint16_t spr_latency[5];
> /* watermark latency values for cursor */
> uint16_t cur_latency[5];
> + /* protects all watermark state */
> + spinlock_t lock;
> + /* current state of FBC_WM */
> + bool fbc_wm_enabled;
> + /* current state of DDB partitioning */
> + enum intel_ddb_partitioning ddb_partitioning;
> + /*
> + * LP1+ values currently programmed into the hardware
> + * [0] = LP1, [1] = LP2, [2] = LP3
> + */
> + struct intel_wm_level hw[3];
> } wm;
>
> /* Old dri1 support infrastructure, beware the dragons ya fools entering
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 4c1b1e3..ee5127f 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1240,8 +1240,10 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
> intel_opregion_asle_intr(dev);
>
> for (i = 0; i < 3; i++) {
> - if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
> + if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i))) {
> + ilk_update_pipe_wm(dev, i);
> drm_handle_vblank(dev, i);
> + }
> if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) {
> intel_prepare_page_flip(dev, i);
> intel_finish_page_flip_plane(dev, i);
> @@ -1343,11 +1345,15 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
> if (de_iir & DE_GSE)
> intel_opregion_asle_intr(dev);
>
> - if (de_iir & DE_PIPEA_VBLANK)
> + if (de_iir & DE_PIPEA_VBLANK) {
> + ilk_update_pipe_wm(dev, 0);
> drm_handle_vblank(dev, 0);
> + }
>
> - if (de_iir & DE_PIPEB_VBLANK)
> + if (de_iir & DE_PIPEB_VBLANK) {
> + ilk_update_pipe_wm(dev, 1);
> drm_handle_vblank(dev, 1);
> + }
>
> if (de_iir & DE_POISON)
> DRM_ERROR("Poison interrupt\n");
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 9b51be8..e595f54 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -3762,6 +3762,8 @@
> #define DISP_ARB_CTL 0x45000
> #define DISP_TILE_SURFACE_SWIZZLING (1<<13)
> #define DISP_FBC_WM_DIS (1<<15)
> +#define DISP_ARB_CTL2 0x45004
> +#define DISP_DATA_PARTITION_5_6 (1<<6)
> #define GEN7_MSG_CTL 0x45010
> #define WAIT_FOR_PCH_RESET_ACK (1<<1)
> #define WAIT_FOR_PCH_FLR_ACK (1<<0)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 4afaeb2..a5c15ab 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -292,6 +292,15 @@ struct intel_crtc_config {
> bool ips_enabled;
> };
>
> +struct intel_pipe_wm {
> + bool pipe_enabled;
> + bool sprites_enabled;
> + bool sprites_scaled;
> + bool fbc_wm_enabled;
> + uint32_t linetime;
> + struct intel_wm_level wm[5];
> +};
> +
> struct intel_crtc {
> struct drm_crtc base;
> enum pipe pipe;
> @@ -332,6 +341,18 @@ struct intel_crtc {
> /* Access to these should be protected by dev_priv->irq_lock. */
> bool cpu_fifo_underrun_disabled;
> bool pch_fifo_underrun_disabled;
> +
> + /* per-pipe watermark state */
> + struct {
> + /* watermarks queued for next vblank */
> + struct intel_pipe_wm pending;
> + /* watermarks currently being used */
> + struct intel_pipe_wm active;
> + /* LP0 values currently programmed into the hardware */
> + struct intel_wm_level hw;
> + /* indicates that 'pending' contains changed watermarks */
> + bool dirty;
> + } wm;
> };
>
> struct intel_plane_wm_parameters {
> @@ -838,5 +859,6 @@ extern bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
> extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
> enum transcoder pch_transcoder,
> bool enable);
> +extern void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe);
>
> #endif /* __INTEL_DRV_H__ */
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index c4e94bb..7fd922dc 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -32,6 +32,11 @@
> #include <linux/module.h>
> #include <drm/i915_powerwell.h>
>
> +static const char *yesno(int v)
> +{
> + return v ? "yes" : "no";
> +}
> +
> #define FORCEWAKE_ACK_TIMEOUT_MS 2
>
> /* FBC, or Frame Buffer Compression, is a technique employed to compress the
> @@ -1668,424 +1673,6 @@ static void i830_update_wm(struct drm_crtc *crtc)
> I915_WRITE(FW_BLC, fwater_lo);
> }
>
> -#define ILK_LP0_PLANE_LATENCY 700
> -#define ILK_LP0_CURSOR_LATENCY 1300
> -
> -/*
> - * Check the wm result.
> - *
> - * If any calculated watermark values is larger than the maximum value that
> - * can be programmed into the associated watermark register, that watermark
> - * must be disabled.
> - */
> -static bool ironlake_check_srwm(struct drm_device *dev, int level,
> - int fbc_wm, int display_wm, int cursor_wm,
> - const struct intel_watermark_params *display,
> - const struct intel_watermark_params *cursor)
> -{
> - struct drm_i915_private *dev_priv = dev->dev_private;
> -
> - DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d,"
> - " cursor %d\n", level, display_wm, fbc_wm, cursor_wm);
> -
> - if (fbc_wm > SNB_FBC_MAX_SRWM) {
> - DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n",
> - fbc_wm, SNB_FBC_MAX_SRWM, level);
> -
> - /* fbc has it's own way to disable FBC WM */
> - I915_WRITE(DISP_ARB_CTL,
> - I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS);
> - return false;
> - } else if (INTEL_INFO(dev)->gen >= 6) {
> - /* enable FBC WM (except on ILK, where it must remain off) */
> - I915_WRITE(DISP_ARB_CTL,
> - I915_READ(DISP_ARB_CTL) & ~DISP_FBC_WM_DIS);
> - }
> -
> - if (display_wm > display->max_wm) {
> - DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n",
> - display_wm, SNB_DISPLAY_MAX_SRWM, level);
> - return false;
> - }
> -
> - if (cursor_wm > cursor->max_wm) {
> - DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n",
> - cursor_wm, SNB_CURSOR_MAX_SRWM, level);
> - return false;
> - }
> -
> - if (!(fbc_wm || display_wm || cursor_wm)) {
> - DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level);
> - return false;
> - }
> -
> - return true;
> -}
> -
> -/*
> - * Compute watermark values of WM[1-3],
> - */
> -static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane,
> - int latency_ns,
> - const struct intel_watermark_params *display,
> - const struct intel_watermark_params *cursor,
> - int *fbc_wm, int *display_wm, int *cursor_wm)
> -{
> - struct drm_crtc *crtc;
> - unsigned long line_time_us;
> - int hdisplay, htotal, pixel_size, clock;
> - int line_count, line_size;
> - int small, large;
> - int entries;
> -
> - if (!latency_ns) {
> - *fbc_wm = *display_wm = *cursor_wm = 0;
> - return false;
> - }
> -
> - crtc = intel_get_crtc_for_plane(dev, plane);
> - hdisplay = crtc->mode.hdisplay;
> - htotal = crtc->mode.htotal;
> - clock = crtc->mode.clock;
> - pixel_size = crtc->fb->bits_per_pixel / 8;
> -
> - line_time_us = (htotal * 1000) / clock;
> - line_count = (latency_ns / line_time_us + 1000) / 1000;
> - line_size = hdisplay * pixel_size;
> -
> - /* Use the minimum of the small and large buffer method for primary */
> - small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
> - large = line_count * line_size;
> -
> - entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
> - *display_wm = entries + display->guard_size;
> -
> - /*
> - * Spec says:
> - * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2
> - */
> - *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2;
> -
> - /* calculate the self-refresh watermark for display cursor */
> - entries = line_count * pixel_size * 64;
> - entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
> - *cursor_wm = entries + cursor->guard_size;
> -
> - return ironlake_check_srwm(dev, level,
> - *fbc_wm, *display_wm, *cursor_wm,
> - display, cursor);
> -}
> -
> -static void ironlake_update_wm(struct drm_crtc *crtc)
> -{
> - struct drm_device *dev = crtc->dev;
> - struct drm_i915_private *dev_priv = dev->dev_private;
> - int fbc_wm, plane_wm, cursor_wm;
> - unsigned int enabled;
> -
> - enabled = 0;
> - if (g4x_compute_wm0(dev, PIPE_A,
> - &ironlake_display_wm_info,
> - ILK_LP0_PLANE_LATENCY,
> - &ironlake_cursor_wm_info,
> - ILK_LP0_CURSOR_LATENCY,
> - &plane_wm, &cursor_wm)) {
> - I915_WRITE(WM0_PIPEA_ILK,
> - (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
> - DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
> - " plane %d, " "cursor: %d\n",
> - plane_wm, cursor_wm);
> - enabled |= 1 << PIPE_A;
> - }
> -
> - if (g4x_compute_wm0(dev, PIPE_B,
> - &ironlake_display_wm_info,
> - ILK_LP0_PLANE_LATENCY,
> - &ironlake_cursor_wm_info,
> - ILK_LP0_CURSOR_LATENCY,
> - &plane_wm, &cursor_wm)) {
> - I915_WRITE(WM0_PIPEB_ILK,
> - (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
> - DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
> - " plane %d, cursor: %d\n",
> - plane_wm, cursor_wm);
> - enabled |= 1 << PIPE_B;
> - }
> -
> - /*
> - * Calculate and update the self-refresh watermark only when one
> - * display plane is used.
> - */
> - I915_WRITE(WM3_LP_ILK, 0);
> - I915_WRITE(WM2_LP_ILK, 0);
> - I915_WRITE(WM1_LP_ILK, 0);
> -
> - if (!single_plane_enabled(enabled))
> - return;
> - enabled = ffs(enabled) - 1;
> -
> - /* WM1 */
> - if (!ironlake_compute_srwm(dev, 1, enabled,
> - ILK_READ_WM1_LATENCY() * 500,
> - &ironlake_display_srwm_info,
> - &ironlake_cursor_srwm_info,
> - &fbc_wm, &plane_wm, &cursor_wm))
> - return;
> -
> - I915_WRITE(WM1_LP_ILK,
> - WM1_LP_SR_EN |
> - (ILK_READ_WM1_LATENCY() << 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,
> - &ironlake_display_srwm_info,
> - &ironlake_cursor_srwm_info,
> - &fbc_wm, &plane_wm, &cursor_wm))
> - return;
> -
> - I915_WRITE(WM2_LP_ILK,
> - WM2_LP_EN |
> - (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
> - (fbc_wm << WM1_LP_FBC_SHIFT) |
> - (plane_wm << WM1_LP_SR_SHIFT) |
> - cursor_wm);
> -
> - /*
> - * WM3 is unsupported on ILK, probably because we don't have latency
> - * data for that power state
> - */
> -}
> -
> -static void sandybridge_update_wm(struct drm_crtc *crtc)
> -{
> - struct drm_device *dev = crtc->dev;
> - struct drm_i915_private *dev_priv = dev->dev_private;
> - int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
> - u32 val;
> - int fbc_wm, plane_wm, cursor_wm;
> - unsigned int enabled;
> -
> - enabled = 0;
> - if (g4x_compute_wm0(dev, PIPE_A,
> - &sandybridge_display_wm_info, latency,
> - &sandybridge_cursor_wm_info, latency,
> - &plane_wm, &cursor_wm)) {
> - val = I915_READ(WM0_PIPEA_ILK);
> - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
> - I915_WRITE(WM0_PIPEA_ILK, val |
> - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
> - DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
> - " plane %d, " "cursor: %d\n",
> - plane_wm, cursor_wm);
> - enabled |= 1 << PIPE_A;
> - }
> -
> - if (g4x_compute_wm0(dev, PIPE_B,
> - &sandybridge_display_wm_info, latency,
> - &sandybridge_cursor_wm_info, latency,
> - &plane_wm, &cursor_wm)) {
> - val = I915_READ(WM0_PIPEB_ILK);
> - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
> - I915_WRITE(WM0_PIPEB_ILK, val |
> - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
> - DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
> - " plane %d, cursor: %d\n",
> - plane_wm, cursor_wm);
> - enabled |= 1 << PIPE_B;
> - }
> -
> - /*
> - * Calculate and update the self-refresh watermark only when one
> - * display plane is used.
> - *
> - * SNB support 3 levels of watermark.
> - *
> - * WM1/WM2/WM2 watermarks have to be enabled in the ascending order,
> - * and disabled in the descending order
> - *
> - */
> - I915_WRITE(WM3_LP_ILK, 0);
> - I915_WRITE(WM2_LP_ILK, 0);
> - I915_WRITE(WM1_LP_ILK, 0);
> -
> - if (!single_plane_enabled(enabled) ||
> - dev_priv->sprite_scaling_enabled)
> - return;
> - enabled = ffs(enabled) - 1;
> -
> - /* WM1 */
> - if (!ironlake_compute_srwm(dev, 1, enabled,
> - SNB_READ_WM1_LATENCY() * 500,
> - &sandybridge_display_srwm_info,
> - &sandybridge_cursor_srwm_info,
> - &fbc_wm, &plane_wm, &cursor_wm))
> - return;
> -
> - I915_WRITE(WM1_LP_ILK,
> - WM1_LP_SR_EN |
> - (SNB_READ_WM1_LATENCY() << 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,
> - &sandybridge_display_srwm_info,
> - &sandybridge_cursor_srwm_info,
> - &fbc_wm, &plane_wm, &cursor_wm))
> - return;
> -
> - I915_WRITE(WM2_LP_ILK,
> - WM2_LP_EN |
> - (SNB_READ_WM2_LATENCY() << 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,
> - &sandybridge_display_srwm_info,
> - &sandybridge_cursor_srwm_info,
> - &fbc_wm, &plane_wm, &cursor_wm))
> - return;
> -
> - I915_WRITE(WM3_LP_ILK,
> - WM3_LP_EN |
> - (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
> - (fbc_wm << WM1_LP_FBC_SHIFT) |
> - (plane_wm << WM1_LP_SR_SHIFT) |
> - cursor_wm);
> -}
> -
> -static void ivybridge_update_wm(struct drm_crtc *crtc)
> -{
> - struct drm_device *dev = crtc->dev;
> - struct drm_i915_private *dev_priv = dev->dev_private;
> - int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
> - u32 val;
> - int fbc_wm, plane_wm, cursor_wm;
> - int ignore_fbc_wm, ignore_plane_wm, ignore_cursor_wm;
> - unsigned int enabled;
> -
> - enabled = 0;
> - if (g4x_compute_wm0(dev, PIPE_A,
> - &sandybridge_display_wm_info, latency,
> - &sandybridge_cursor_wm_info, latency,
> - &plane_wm, &cursor_wm)) {
> - val = I915_READ(WM0_PIPEA_ILK);
> - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
> - I915_WRITE(WM0_PIPEA_ILK, val |
> - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
> - DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
> - " plane %d, " "cursor: %d\n",
> - plane_wm, cursor_wm);
> - enabled |= 1 << PIPE_A;
> - }
> -
> - if (g4x_compute_wm0(dev, PIPE_B,
> - &sandybridge_display_wm_info, latency,
> - &sandybridge_cursor_wm_info, latency,
> - &plane_wm, &cursor_wm)) {
> - val = I915_READ(WM0_PIPEB_ILK);
> - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
> - I915_WRITE(WM0_PIPEB_ILK, val |
> - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
> - DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
> - " plane %d, cursor: %d\n",
> - plane_wm, cursor_wm);
> - enabled |= 1 << PIPE_B;
> - }
> -
> - if (g4x_compute_wm0(dev, PIPE_C,
> - &sandybridge_display_wm_info, latency,
> - &sandybridge_cursor_wm_info, latency,
> - &plane_wm, &cursor_wm)) {
> - val = I915_READ(WM0_PIPEC_IVB);
> - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
> - I915_WRITE(WM0_PIPEC_IVB, val |
> - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
> - DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
> - " plane %d, cursor: %d\n",
> - plane_wm, cursor_wm);
> - enabled |= 1 << PIPE_C;
> - }
> -
> - /*
> - * Calculate and update the self-refresh watermark only when one
> - * display plane is used.
> - *
> - * SNB support 3 levels of watermark.
> - *
> - * WM1/WM2/WM2 watermarks have to be enabled in the ascending order,
> - * and disabled in the descending order
> - *
> - */
> - I915_WRITE(WM3_LP_ILK, 0);
> - I915_WRITE(WM2_LP_ILK, 0);
> - I915_WRITE(WM1_LP_ILK, 0);
> -
> - if (!single_plane_enabled(enabled) ||
> - dev_priv->sprite_scaling_enabled)
> - return;
> - enabled = ffs(enabled) - 1;
> -
> - /* WM1 */
> - if (!ironlake_compute_srwm(dev, 1, enabled,
> - SNB_READ_WM1_LATENCY() * 500,
> - &sandybridge_display_srwm_info,
> - &sandybridge_cursor_srwm_info,
> - &fbc_wm, &plane_wm, &cursor_wm))
> - return;
> -
> - I915_WRITE(WM1_LP_ILK,
> - WM1_LP_SR_EN |
> - (SNB_READ_WM1_LATENCY() << 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,
> - &sandybridge_display_srwm_info,
> - &sandybridge_cursor_srwm_info,
> - &fbc_wm, &plane_wm, &cursor_wm))
> - return;
> -
> - I915_WRITE(WM2_LP_ILK,
> - WM2_LP_EN |
> - (SNB_READ_WM2_LATENCY() << 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,
> - &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,
> - &sandybridge_display_srwm_info,
> - &sandybridge_cursor_srwm_info,
> - &ignore_fbc_wm, &ignore_plane_wm, &cursor_wm))
> - return;
> -
> - I915_WRITE(WM3_LP_ILK,
> - WM3_LP_EN |
> - (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
> - (fbc_wm << WM1_LP_FBC_SHIFT) |
> - (plane_wm << WM1_LP_SR_SHIFT) |
> - cursor_wm);
> -}
> -
> static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev,
> struct drm_crtc *crtc)
> {
> @@ -2168,14 +1755,6 @@ struct hsw_wm_maximums {
> uint16_t fbc;
> };
>
> -struct hsw_wm_values {
> - uint32_t wm_pipe[3];
> - uint32_t wm_lp[3];
> - uint32_t wm_lp_spr[3];
> - uint32_t wm_linetime[3];
> - bool enable_fbc_wm;
> -};
> -
> /* used in computing the new watermarks state */
> struct intel_wm_config {
> unsigned int pipes_active;
> @@ -2351,6 +1930,16 @@ static void ilk_wm_max(struct drm_device *dev,
> max->fbc = ilk_fbc_wm_max();
> }
>
> +/*
> + * We use memcmp() to determine if watermarks need updating,
> + * so keeping all disabled watermark levels consistently
> + * zeroed avoids false positives.
> + */
> +static void ilk_disable_wm_level(struct intel_wm_level *wm)
> +{
> + memset(wm, 0, sizeof(*wm));
> +}
> +
> static bool ilk_check_wm(int level,
> const struct hsw_wm_maximums *max,
> struct intel_wm_level *result)
> @@ -2381,6 +1970,9 @@ static bool ilk_check_wm(int level,
>
> DRM_DEBUG_KMS("WM%d: %sabled\n", level, result->enable ? "en" : "dis");
>
> + if (!result->enable)
> + ilk_disable_wm_level(result);
> +
> return ret;
> }
>
> @@ -2406,52 +1998,603 @@ static void ilk_compute_wm_level(struct drm_i915_private *dev_priv,
> 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,
> - enum pipe pipe,
> - struct hsw_pipe_wm_parameters *params)
> -{
> - uint32_t pri_val, cur_val, spr_val;
> - 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 = ilk_compute_pri_wm(params, pri_latency, 0);
> - 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",
> - pipe_name(pipe));
> - WARN(spr_val > 127,
> - "Sprite WM error, mode not supported for pipe %c\n",
> - pipe_name(pipe));
> - WARN(cur_val > 63,
> - "Cursor WM error, mode not supported for pipe %c\n",
> - pipe_name(pipe));
> -
> - return (pri_val << WM0_PIPE_PLANE_SHIFT) |
> - (spr_val << WM0_PIPE_SPRITE_SHIFT) |
> - cur_val;
> +/* The value we need to program into the WM_LPx latency field */
> +static unsigned int ilk_wm_lp_latency(struct drm_device *dev, int level)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> +
> + if (INTEL_INFO(dev)->gen > 7 || IS_HASWELL(dev))
> + return 2 * level;
> + else
> + return dev_priv->wm.pri_latency[level];
> +}
> +
> +/*
> + * Merge the watermarks from all active pipes for a specific level.
> + */
> +static void ilk_merge_wm_level(struct drm_device *dev,
> + int level,
> + struct intel_wm_level *ret_wm)
> +{
> + struct intel_crtc *intel_crtc;
> +
> + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) {
> + const struct intel_pipe_wm *pipe_wm = &intel_crtc->wm.active;
> + const struct intel_wm_level *wm = &pipe_wm->wm[level];
> +
> + if (!pipe_wm->pipe_enabled)
> + continue;
> +
> + if (!wm->enable)
> + break;
> +
> + ret_wm->enable = true;
> + ret_wm->pri_val = max(ret_wm->pri_val, wm->pri_val);
> + ret_wm->spr_val = max(ret_wm->spr_val, wm->spr_val);
> + ret_wm->cur_val = max(ret_wm->cur_val, wm->cur_val);
> + ret_wm->fbc_val = max(ret_wm->fbc_val, wm->fbc_val);
> + }
> +}
> +
> +/*
> + * Merge all low power watermarks for all active pipes.
> + */
> +static void ilk_wm_merge(struct drm_device *dev,
> + struct intel_wm_config *config,
> + struct intel_pipe_wm *merged)
> +{
> + int level;
> +
> + /* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */
> + if (config->pipes_active > 1 &&
> + (INTEL_INFO(dev)->gen <= 6 || IS_IVYBRIDGE(dev)))
> + return;
> +
> + /* ILK: FBC WM must remain disabled */
> + merged->fbc_wm_enabled = INTEL_INFO(dev)->gen >= 6;
> +
> + /* merge each level */
> + for (level = 1; level <= 4; level++) {
> + struct intel_wm_level *wm = &merged->wm[level];
> +
> + ilk_merge_wm_level(dev, level, wm);
> + }
> +}
> +
> +static void ilk_wm_limit(struct drm_device *dev,
> + const struct intel_wm_config *config,
> + const struct hsw_wm_maximums *max,
> + struct intel_pipe_wm *merged)
> +{
> + int level;
> +
> + for (level = 1; level <= 4; level++) {
> + struct intel_wm_level *wm = &merged->wm[level];
> +
> + if (!ilk_check_wm(level, max, wm))
> + break;
> +
> + /*
> + * If FBC WM is exceeded, disable just FBC WM
> + * instead if the whole level.
> + */
> + if (wm->fbc_val > max->fbc)
> + merged->fbc_wm_enabled = false;
> + }
> +
> + if (merged->fbc_wm_enabled)
> + return;
> +
> + /* Make sure we don't write garbage to the registers, */
> + for (level = 1; level <= 4; level++) {
> + struct intel_wm_level *wm = &merged->wm[level];
> +
> + wm->fbc_val = 0;
> + }
> +
> + /*
> + * LP2+ watermarks must be disabled when FBC watermark is disabled on ILK
> + * In practice this is always happens since we always disable FBC WM on ILK.
> + */
> + if (INTEL_INFO(dev)->gen == 5 && intel_fbc_enabled(dev)) {
> + for (level = 2; level <= 4; level++) {
> + struct intel_wm_level *wm = &merged->wm[level];
> +
> + ilk_disable_wm_level(wm);
> + }
> + }
> +}
> +
> +static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *merged)
> +{
> + /* LP1,LP2,LP3 levels are either 1,2,3 or 1,3,4 */
> + return wm_lp + (wm_lp >= 2 && merged->wm[4].enable);
> +}
> +
> +/* dirty bits used to track which watermarks need changes */
> +#define WM_DIRTY_PIPE(pipe) (1 << (pipe))
> +#define WM_DIRTY_LP(wm_lp) (1 << (15 + (wm_lp)))
> +#define WM_DIRTY_FBC (1 << 24)
> +#define WM_DIRTY_DDB (1 << 25)
> +
> +/* Determine which watermarks registers need reprogramming. */
> +static unsigned int ilk_compute_wm_dirty(struct drm_device *dev,
> + const struct intel_wm_config *config,
> + enum intel_ddb_partitioning ddb_partitioning,
> + const struct intel_pipe_wm *merged)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + struct intel_crtc *intel_crtc;
> + unsigned int dirty = 0;
> + int wm_lp;
> +
> + /* Do LP0 watermarks need updates? */
> + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) {
> + const struct intel_wm_level *wm = &intel_crtc->wm.active.wm[0];
> +
> + if (memcmp(&intel_crtc->wm.hw, wm, sizeof(*wm)))
> + dirty |= WM_DIRTY_PIPE(intel_crtc->pipe);
> + }
> +
> + if (config->fbc_wm_enabled != dev_priv->wm.fbc_wm_enabled)
> + dirty |= WM_DIRTY_FBC;
> +
> + if (ddb_partitioning != dev_priv->wm.ddb_partitioning)
> + dirty |= WM_DIRTY_DDB;
> +
> + /* Need to disable LP1+ watermarks when changing DDB/FBC WM */
> + if (dirty & (WM_DIRTY_FBC | WM_DIRTY_DDB)) {
> + dirty |= WM_DIRTY_LP(1) | WM_DIRTY_LP(2) | WM_DIRTY_LP(3);
> +
> + /* LP1+ watermarks already deemed dirty, no need to continue */
> + return dirty;
> + }
> +
> + /* Find the lowest numbered LP1+ watermark in need of an update... */
> + for (wm_lp = 1; wm_lp <= 3; wm_lp++) {
> + int level = ilk_wm_lp_to_level(wm_lp, merged);
> + const struct intel_wm_level *wm = &merged->wm[level];
> +
> + if (memcmp(&dev_priv->wm.hw[wm_lp - 1], wm, sizeof(*wm)))
> + break;
> + }
> +
> + /* ...and mark it and all higher numbered LP1+ watermarks as dirty */
> + for (; wm_lp <= 3; wm_lp++)
> + dirty |= WM_DIRTY_LP(wm_lp);
> +
> + return dirty;
> +}
> +
> +/* Disable LP1+ watermarks */
> +static void ilk_disable_lp_wm(struct drm_i915_private *dev_priv,
> + unsigned int dirty)
> +{
> + int wm_lp;
> +
> + for (wm_lp = 3; wm_lp >= 1; wm_lp--) {
> + static const unsigned int ilk_wm_lp_reg[] = {
> + [1] = WM1_LP_ILK,
> + [2] = WM2_LP_ILK,
> + [3] = WM3_LP_ILK,
> + };
> + struct intel_wm_level *hw = &dev_priv->wm.hw[wm_lp - 1];
> +
> + if (!(dirty & WM_DIRTY_LP(wm_lp))) {
> + /* all lower dirty bits must be set when a higher bit is set */
> + WARN_ON(wm_lp > 1 && dirty & WM_DIRTY_LP(wm_lp - 1));
> + WARN_ON(wm_lp > 2 && dirty & WM_DIRTY_LP(wm_lp - 2));
> + break;
> + }
> +
> + /* This LP watermark already disabled? */
> + if (!hw->enable)
> + continue;
> +
> + DRM_DEBUG_KMS("disabling LP%d watermark\n", wm_lp);
> +
> + /*
> + * Simply writing 0 to the register in the middle of the frame
> + * can cause immediate underruns on ILK. Instead we must clear
> + * only the enable bit. I assume the hardware will take a while
> + * to get out of low power mode, during which time it still
> + * consults the watermarks levels.
> + */
> + I915_WRITE(ilk_wm_lp_reg[wm_lp],
> + I915_READ(ilk_wm_lp_reg[wm_lp]) & ~WM1_LP_SR_EN);
> +
> + /* ILK/SNB have a separate enable bit for sprite LP1 watermark */
> + if (hw->spr_val && INTEL_INFO(dev_priv->dev)->gen <= 6) {
> + WARN_ON(wm_lp != 1);
> + I915_WRITE(WM1S_LP_ILK, I915_READ(WM1S_LP_ILK) & ~WM1S_LP_EN);
> + }
> +
> + ilk_disable_wm_level(hw);
> + }
> +}
> +
> +struct intel_pipe_wm *ivb_find_best_wm(struct intel_pipe_wm *r1,
> + struct intel_pipe_wm *r2)
> +{
> + int level, level1 = 0, level2 = 0;
> +
> + for (level = 1; level <= 4; level++) {
> + if (r1->wm[level].enable)
> + level1 = level;
> + if (r2->wm[level].enable)
> + level2 = level;
> + }
> +
> + if (level1 == level2) {
> + if (r2->fbc_wm_enabled && !r1->fbc_wm_enabled)
> + return r2;
> + else
> + return r1;
> + } else if (level1 > level2) {
> + return r1;
> + } else {
> + return r2;
> + }
> +}
> +
> +/* Program the watermark registers */
> +static void ilk_program_watermarks(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + struct drm_crtc *crtc;
> + struct intel_pipe_wm merged_1_2 = {}, merged_5_6 = {}, *merged;
> + struct hsw_wm_maximums lp_max_1_2, lp_max_5_6;
> + int wm_lp;
> + unsigned int dirty;
> + struct intel_wm_config config = {};
> + struct intel_crtc *intel_crtc;
> + enum intel_ddb_partitioning ddb_partitioning;
> +
> + /* ILK: FBC WM must remain disabled */
> + config.fbc_wm_enabled = INTEL_INFO(dev)->gen >= 6 && intel_fbc_enabled(dev);
> +
> + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) {
> + const struct intel_pipe_wm *wm = &intel_crtc->wm.active;
> +
> + if (!wm->pipe_enabled)
> + continue;
> +
> + config.sprites_enabled |= wm->sprites_enabled;
> + config.sprites_scaled |= wm->sprites_scaled;
> + config.pipes_active++;
> + }
> +
> + ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_1_2, &lp_max_1_2);
> +
> + ilk_wm_merge(dev, &config, &merged_1_2);
> +
> + /* 5/6 DDB partitioning only in single pipe config on IVB+ */
> + if (INTEL_INFO(dev)->gen >= 7 && config.pipes_active <= 1) {
> + ilk_wm_max(dev, 1, &config, INTEL_DDB_PART_5_6, &lp_max_5_6);
> +
> + merged_5_6 = merged_1_2;
> +
> + ilk_wm_limit(dev, &config, &lp_max_1_2, &merged_1_2);
> + ilk_wm_limit(dev, &config, &lp_max_5_6, &merged_5_6);
> +
> + merged = ivb_find_best_wm(&merged_1_2, &merged_5_6);
> + } else {
> + ilk_wm_limit(dev, &config, &lp_max_1_2, &merged_1_2);
> + merged = &merged_1_2;
> + }
> +
> + ddb_partitioning = merged == &merged_1_2 ?
> + INTEL_DDB_PART_1_2 : INTEL_DDB_PART_5_6;
> +
> + DRM_DEBUG_KMS("WM: pipes active=%u, sprites enabled=%s, "
> + "sprites scaled=%s, FBC WM enabled=%s, "
> + "DDB partitioning=%s\n",
> + config.pipes_active,
> + yesno(config.sprites_enabled),
> + yesno(config.sprites_scaled),
> + yesno(config.fbc_wm_enabled),
> + ddb_partitioning == INTEL_DDB_PART_1_2 ? "1/2" : "5/6");
> +
> + dirty = ilk_compute_wm_dirty(dev, &config, ddb_partitioning, merged);
> + if (!dirty) {
> + DRM_DEBUG_KMS("WM: all clean\n");
> + return;
> + }
> +
> + DRM_DEBUG_KMS("WM: dirty %s%s%s%s%s%s%s%s\n",
> + dirty & WM_DIRTY_DDB ? "DDB," : "",
> + dirty & WM_DIRTY_FBC ? "FBC," : "",
> + dirty & WM_DIRTY_LP(3) ? "LP3," : "",
> + dirty & WM_DIRTY_LP(2) ? "LP2," : "",
> + dirty & WM_DIRTY_LP(1) ? "LP1," : "",
> + dirty & WM_DIRTY_PIPE(PIPE_A) ? "LP0(A)," : "",
> + dirty & WM_DIRTY_PIPE(PIPE_B) ? "LP0(B)," : "",
> + dirty & WM_DIRTY_PIPE(PIPE_C) ? "LP0(C)," : "");
> +
> + /*
> + * LP1+ watermarks need to be disabled prior to
> + * changing DDB partitioning, FBC watermark disable,
> + * or lower numbered LP1+ watermarks. "dirty" knows
> + * which watermarks need disabling.
> + */
> + ilk_disable_lp_wm(dev_priv, dirty);
> +
> + /* program LP0 watermarks */
> + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> + static const unsigned int ilk_wm0_pipe_reg[] = {
> + [PIPE_A] = WM0_PIPEA_ILK,
> + [PIPE_B] = WM0_PIPEB_ILK,
> + [PIPE_C] = WM0_PIPEC_IVB,
> + };
> + struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> + const struct intel_pipe_wm *pipe_wm = &intel_crtc->wm.active;
> + const struct intel_wm_level *wm = &pipe_wm->wm[0];
> +
> + if (!(dirty & WM_DIRTY_PIPE(intel_crtc->pipe)))
> + continue;
> +
> + DRM_DEBUG_KMS("Pipe %c LP0: pri=%u, spr=%u, cur=%u\n",
> + pipe_name(intel_crtc->pipe),
> + wm->pri_val, wm->spr_val, wm->cur_val);
> +
> + I915_WRITE(ilk_wm0_pipe_reg[intel_crtc->pipe],
> + wm->pri_val << WM0_PIPE_PLANE_SHIFT |
> + wm->spr_val << WM0_PIPE_SPRITE_SHIFT |
> + wm->cur_val);
> +
> + if (INTEL_INFO(dev)->gen > 7 || IS_HASWELL(dev))
> + I915_WRITE(PIPE_WM_LINETIME(intel_crtc->pipe),
> + pipe_wm->linetime);
> +
> + intel_crtc->wm.hw = *wm;
> + }
> +
> + /* configure FBC watermark */
> + if (dirty & WM_DIRTY_FBC) {
> + uint32_t tmp = I915_READ(DISP_ARB_CTL);
> +
> + DRM_DEBUG_KMS("WM: FBC watermark = %s\n", yesno(config.fbc_wm_enabled));
> +
> + if (config.fbc_wm_enabled)
> + tmp &= ~DISP_FBC_WM_DIS;
> + else
> + tmp |= DISP_FBC_WM_DIS;
> +
> + I915_WRITE(DISP_ARB_CTL, tmp);
> +
> + dev_priv->wm.fbc_wm_enabled = config.fbc_wm_enabled;
> + }
> +
> + /* configure DDB partitioning */
> + if (dirty & WM_DIRTY_DDB) {
> + DRM_DEBUG_KMS("WM: DDB partitioning = %s\n",
> + ddb_partitioning == INTEL_DDB_PART_1_2 ? "1/2" : "5/6");
> +
> + if (INTEL_INFO(dev)->gen > 7 || IS_HASWELL(dev)) {
> + uint32_t tmp = I915_READ(WM_MISC);
> +
> + if (ddb_partitioning == INTEL_DDB_PART_5_6)
> + tmp |= WM_MISC_DATA_PARTITION_5_6;
> + else
> + tmp &= ~WM_MISC_DATA_PARTITION_5_6;
> +
> + I915_WRITE(DISP_ARB_CTL, tmp);
> + } else {
> + uint32_t tmp = I915_READ(DISP_ARB_CTL2);
> +
> + if (ddb_partitioning == INTEL_DDB_PART_5_6)
> + tmp |= DISP_DATA_PARTITION_5_6;
> + else
> + tmp &= ~DISP_DATA_PARTITION_5_6;
> +
> + I915_WRITE(DISP_ARB_CTL2, tmp);
> + }
> +
> + dev_priv->wm.ddb_partitioning = ddb_partitioning;
> + }
> +
> + /* program LP1+ watermarks */
> + for (wm_lp = 1; wm_lp <= 3; wm_lp++) {
> + static const unsigned int wm_lp_reg[] = {
> + [1] = WM1_LP_ILK,
> + [2] = WM2_LP_ILK,
> + [3] = WM3_LP_ILK,
> + };
> + static const unsigned int wm_spr_lp_reg[] = {
> + [1] = WM1S_LP_ILK,
> + [2] = WM2S_LP_IVB,
> + [3] = WM3S_LP_IVB,
> + };
> + int level = ilk_wm_lp_to_level(wm_lp, merged);
> + const struct intel_wm_level *wm = &merged->wm[level];
> +
> + if (!wm->enable)
> + break;
> +
> + if (!(dirty & WM_DIRTY_LP(wm_lp)))
> + continue;
> +
> + DRM_DEBUG_KMS("LP%d (level %d): pri=%u, spr=%u, cur=%u, fbc=%u, latency=%u\n",
> + wm_lp, level, wm->pri_val, wm->spr_val,
> + wm->cur_val, wm->fbc_val, ilk_wm_lp_latency(dev, level));
> +
> + if (wm->spr_val) {
> + if (INTEL_INFO(dev)->gen <= 6) {
> + WARN_ON(wm_lp != 1);
> + I915_WRITE(WM1S_LP_ILK, WM1S_LP_EN | wm->spr_val);
> + } else {
> + I915_WRITE(wm_spr_lp_reg[wm_lp], wm->spr_val);
> + }
> + }
> +
> + I915_WRITE(wm_lp_reg[wm_lp], WM1_LP_SR_EN |
> + ilk_wm_lp_latency(dev, level) << WM1_LP_LATENCY_SHIFT |
> + wm->fbc_val << WM1_LP_FBC_SHIFT |
> + wm->pri_val << WM1_LP_SR_SHIFT |
> + wm->cur_val);
> +
> + dev_priv->wm.hw[wm_lp - 1] = *wm;
> + }
> +}
> +
> +static uint32_t
> +hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc);
> +
> +static int ilk_max_wm_level(const struct drm_device *dev,
> + const struct intel_pipe_wm *pipe_wm)
> +{
> + /* HSW: LP1+ watermarks allowed even with multiple pipes */
> + if (INTEL_INFO(dev)->gen > 7 || IS_HASWELL(dev)) {
> + WARN_ON(pipe_wm->sprites_scaled);
> + return 4;
> + }
> +
> + /* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
> + if (pipe_wm->sprites_scaled)
> + return 0;
> +
> + /* ILK/SNB: LP2+ watermarks only w/o sprites */
> + if (INTEL_INFO(dev)->gen <= 6 && pipe_wm->sprites_enabled)
> + return 1;
> +
> + return 3;
> +}
> +
> +/* Compute new watermarks for the pipe */
> +static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
> + struct intel_pipe_wm *pipe_wm)
> +{
> + struct drm_device *dev = crtc->dev;
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> + struct hsw_wm_maximums max;
> + struct drm_plane *plane;
> + struct hsw_pipe_wm_parameters p = {};
> + struct intel_wm_config config = {};
> + int level, max_level;
> +
> + p.active = intel_crtc_active(crtc);
> +
> + if (p.active) {
> + p.pipe_htotal = intel_crtc->config.adjusted_mode.htotal;
> + p.pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
> +
> + /* TODO: for now, assume primary and cursor planes are always enabled. */
> + p.pri.enabled = true;
> + p.pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
> + p.pri.horiz_pixels = intel_crtc->config.requested_mode.hdisplay;
> +
> + p.cur.enabled = true;
> + p.cur.bytes_per_pixel = 4;
> + p.cur.horiz_pixels = 64;
> +
> + config.pipes_active = 1;
> + }
> +
> + list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> + struct intel_plane *intel_plane = to_intel_plane(plane);
> +
> + if (intel_plane->pipe != intel_crtc->pipe)
> + continue;
> +
> + p.spr = intel_plane->wm;
> +
> + config.sprites_enabled |= p.spr.enabled;
> + config.sprites_scaled |= p.spr.scaled;
> + }
> +
> + pipe_wm->pipe_enabled = p.active;
> + pipe_wm->sprites_enabled = config.sprites_enabled;
> + pipe_wm->sprites_scaled = config.sprites_scaled;
> +
> + max_level = ilk_max_wm_level(dev, pipe_wm);
> +
> + for (level = 0; level <= max_level; level++)
> + ilk_compute_wm_level(dev_priv, level, &p, &pipe_wm->wm[level]);
> +
> + if (IS_HASWELL(dev))
> + pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc);
> +
> + ilk_wm_max(dev, 0, &config, false, &max);
> +
> + /* At least LP0 must be valid */
> + return ilk_check_wm(0, &max, &pipe_wm->wm[0]);
> +}
> +
> +/* Prepare the pipe to update the its watermarks on the next vblank */
> +static void intel_setup_pipe_wm(struct intel_crtc *intel_crtc,
> + const struct intel_pipe_wm *pipe_wm)
> +{
> + struct drm_device *dev = intel_crtc->base.dev;
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + int pipe = intel_crtc->pipe;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dev_priv->wm.lock, flags);
> +
> + /* do the watermarks actually need changing? */
> + if (!memcmp(&intel_crtc->wm.pending, pipe_wm, sizeof(*pipe_wm)))
> + goto out;
> +
> + /*
> + * We might already have a pending watermark update, in
> + * which case we shouldn't grab another vblank reference.
> + */
> + if (!intel_crtc->wm.dirty && drm_vblank_get(dev, pipe)) {
> + if (intel_crtc->active)
> + DRM_ERROR("can't setup watermarks for pipe %c\n", pipe_name(pipe));
> + /* copy the new stuff over anyway. */
> + intel_crtc->wm.pending = *pipe_wm;
> + goto out;
> + }
> +
> + /*
> + * When going from no-scaling to scaling, disable LP1+
> + * watermarks ahead of time.
> + *
> + * WaCxSRDisabledForSpriteScaling:ivb
> + */
> + /*
> + * FIXME is this sufficient of do we need extra vbl waits?
> + * Something like this is needed on IVB. Do we need this on ILK/SNB too?
> + */
> + if (!intel_crtc->wm.active.sprites_scaled && pipe_wm->sprites_scaled) {
> + DRM_DEBUG_KMS("going to enable scaling, disabling LP1+ watermarks\n");
> + ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP(1) |
> + WM_DIRTY_LP(2) | WM_DIRTY_LP(3));
> + }
> +
> + intel_crtc->wm.pending = *pipe_wm;
> + intel_crtc->wm.dirty = true;
> + DRM_DEBUG_KMS("pipe %c new watermarks are pending\n", pipe_name(pipe));
> +
> + out:
> + spin_unlock_irqrestore(&dev_priv->wm.lock, flags);
> +}
> +
> +/* Call from vblank irq */
> +void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
> + struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dev_priv->wm.lock, flags);
> +
> + if (intel_crtc->wm.dirty) {
> + DRM_DEBUG_KMS("pipe %c vblank, programming new watermarks\n",
> + pipe_name(pipe));
> +
> + drm_vblank_put(dev, pipe);
> +
> + intel_crtc->wm.active = intel_crtc->wm.pending;
> + intel_crtc->wm.dirty = false;
> +
> + ilk_program_watermarks(dev);
> + }
> +
> + spin_unlock_irqrestore(&dev_priv->wm.lock, flags);
> }
>
> static uint32_t
> @@ -2565,271 +2708,24 @@ static void intel_setup_wm_latency(struct drm_device *dev)
> intel_print_wm_latency(dev, dev_priv->wm.cur_latency);
> }
>
> -static void hsw_compute_wm_parameters(struct drm_device *dev,
> - struct hsw_pipe_wm_parameters *params,
> - struct hsw_wm_maximums *lp_max_1_2,
> - struct hsw_wm_maximums *lp_max_5_6)
> +static void ilk_update_wm(struct drm_crtc *crtc)
> {
> - struct drm_crtc *crtc;
> - struct drm_plane *plane;
> - enum pipe pipe;
> - struct intel_wm_config config = {};
> + struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> + struct intel_pipe_wm pipe_wm = {};
> + bool ret;
>
> - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> - struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> - struct hsw_pipe_wm_parameters *p;
> + ret = intel_compute_pipe_wm(crtc, &pipe_wm);
> + if (!ret)
> + DRM_ERROR("crtc %u (pipe %c) LP0 watermarks invalid\n",
> + crtc->base.id, pipe_name(intel_crtc->pipe));
>
> - pipe = intel_crtc->pipe;
> - p = ¶ms[pipe];
> -
> - p->active = intel_crtc_active(crtc);
> - if (!p->active)
> - continue;
> -
> - config.pipes_active++;
> -
> - p->pipe_htotal = intel_crtc->config.adjusted_mode.htotal;
> - 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;
> - /* 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) {
> - struct intel_plane *intel_plane = to_intel_plane(plane);
> - struct hsw_pipe_wm_parameters *p;
> -
> - pipe = intel_plane->pipe;
> - p = ¶ms[pipe];
> -
> - p->spr = intel_plane->wm;
> -
> - config.sprites_enabled |= p->spr.enabled;
> - config.sprites_scaled |= p->spr.scaled;
> - }
> -
> - 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.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,
> - 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 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(dev_priv, level,
> - lp_maximums, params,
> - &lp_results[level - 1]))
> - break;
> - max_level = level - 1;
> -
> - /* 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_val > lp_maximums->fbc) {
> - results->enable_fbc_wm = false;
> - lp_results[level - 1].fbc_val = 0;
> - }
> - }
> -
> - memset(results, 0, sizeof(*results));
> - for (wm_lp = 1; wm_lp <= 3; wm_lp++) {
> - const struct intel_wm_level *r;
> -
> - level = (max_level == 4 && wm_lp > 1) ? wm_lp + 1 : wm_lp;
> - if (level > max_level)
> - break;
> -
> - r = &lp_results[level - 1];
> - results->wm_lp[wm_lp - 1] = HSW_WM_LP_VAL(level * 2,
> - r->fbc_val,
> - r->pri_val,
> - r->cur_val);
> - results->wm_lp_spr[wm_lp - 1] = r->spr_val;
> - }
> -
> - for_each_pipe(pipe)
> - results->wm_pipe[pipe] = hsw_compute_wm_pipe(dev_priv, pipe,
> - ¶ms[pipe]);
> -
> - for_each_pipe(pipe) {
> - crtc = dev_priv->pipe_to_crtc_mapping[pipe];
> - results->wm_linetime[pipe] = hsw_compute_linetime_wm(dev, crtc);
> - }
> -}
> -
> -/* Find the result with the highest level enabled. Check for enable_fbc_wm in
> - * case both are at the same level. Prefer r1 in case they're the same. */
> -static struct hsw_wm_values *hsw_find_best_result(struct hsw_wm_values *r1,
> - struct hsw_wm_values *r2)
> -{
> - int i, val_r1 = 0, val_r2 = 0;
> -
> - for (i = 0; i < 3; i++) {
> - if (r1->wm_lp[i] & WM3_LP_EN)
> - val_r1 = r1->wm_lp[i] & WM1_LP_LATENCY_MASK;
> - if (r2->wm_lp[i] & WM3_LP_EN)
> - val_r2 = r2->wm_lp[i] & WM1_LP_LATENCY_MASK;
> - }
> -
> - if (val_r1 == val_r2) {
> - if (r2->enable_fbc_wm && !r1->enable_fbc_wm)
> - return r2;
> - else
> - return r1;
> - } else if (val_r1 > val_r2) {
> - return r1;
> - } else {
> - return r2;
> - }
> -}
> -
> -/*
> - * The spec says we shouldn't write when we don't need, because every write
> - * causes WMs to be re-evaluated, expending some power.
> - */
> -static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
> - struct hsw_wm_values *results,
> - enum intel_ddb_partitioning partitioning)
> -{
> - struct hsw_wm_values previous;
> - uint32_t val;
> - enum intel_ddb_partitioning prev_partitioning;
> - bool prev_enable_fbc_wm;
> -
> - previous.wm_pipe[0] = I915_READ(WM0_PIPEA_ILK);
> - previous.wm_pipe[1] = I915_READ(WM0_PIPEB_ILK);
> - previous.wm_pipe[2] = I915_READ(WM0_PIPEC_IVB);
> - previous.wm_lp[0] = I915_READ(WM1_LP_ILK);
> - previous.wm_lp[1] = I915_READ(WM2_LP_ILK);
> - previous.wm_lp[2] = I915_READ(WM3_LP_ILK);
> - previous.wm_lp_spr[0] = I915_READ(WM1S_LP_ILK);
> - previous.wm_lp_spr[1] = I915_READ(WM2S_LP_IVB);
> - previous.wm_lp_spr[2] = I915_READ(WM3S_LP_IVB);
> - previous.wm_linetime[0] = I915_READ(PIPE_WM_LINETIME(PIPE_A));
> - previous.wm_linetime[1] = I915_READ(PIPE_WM_LINETIME(PIPE_B));
> - previous.wm_linetime[2] = I915_READ(PIPE_WM_LINETIME(PIPE_C));
> -
> - prev_partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ?
> - INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
> -
> - prev_enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS);
> -
> - if (memcmp(results->wm_pipe, previous.wm_pipe,
> - sizeof(results->wm_pipe)) == 0 &&
> - memcmp(results->wm_lp, previous.wm_lp,
> - sizeof(results->wm_lp)) == 0 &&
> - memcmp(results->wm_lp_spr, previous.wm_lp_spr,
> - sizeof(results->wm_lp_spr)) == 0 &&
> - memcmp(results->wm_linetime, previous.wm_linetime,
> - sizeof(results->wm_linetime)) == 0 &&
> - partitioning == prev_partitioning &&
> - results->enable_fbc_wm == prev_enable_fbc_wm)
> - return;
> -
> - if (previous.wm_lp[2] != 0)
> - I915_WRITE(WM3_LP_ILK, 0);
> - if (previous.wm_lp[1] != 0)
> - I915_WRITE(WM2_LP_ILK, 0);
> - if (previous.wm_lp[0] != 0)
> - I915_WRITE(WM1_LP_ILK, 0);
> -
> - if (previous.wm_pipe[0] != results->wm_pipe[0])
> - I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]);
> - if (previous.wm_pipe[1] != results->wm_pipe[1])
> - I915_WRITE(WM0_PIPEB_ILK, results->wm_pipe[1]);
> - if (previous.wm_pipe[2] != results->wm_pipe[2])
> - I915_WRITE(WM0_PIPEC_IVB, results->wm_pipe[2]);
> -
> - if (previous.wm_linetime[0] != results->wm_linetime[0])
> - I915_WRITE(PIPE_WM_LINETIME(PIPE_A), results->wm_linetime[0]);
> - if (previous.wm_linetime[1] != results->wm_linetime[1])
> - I915_WRITE(PIPE_WM_LINETIME(PIPE_B), results->wm_linetime[1]);
> - if (previous.wm_linetime[2] != results->wm_linetime[2])
> - I915_WRITE(PIPE_WM_LINETIME(PIPE_C), results->wm_linetime[2]);
> -
> - if (prev_partitioning != partitioning) {
> - val = I915_READ(WM_MISC);
> - if (partitioning == INTEL_DDB_PART_1_2)
> - val &= ~WM_MISC_DATA_PARTITION_5_6;
> - else
> - val |= WM_MISC_DATA_PARTITION_5_6;
> - I915_WRITE(WM_MISC, val);
> - }
> -
> - if (prev_enable_fbc_wm != results->enable_fbc_wm) {
> - val = I915_READ(DISP_ARB_CTL);
> - if (results->enable_fbc_wm)
> - val &= ~DISP_FBC_WM_DIS;
> - else
> - val |= DISP_FBC_WM_DIS;
> - I915_WRITE(DISP_ARB_CTL, val);
> - }
> -
> - if (previous.wm_lp_spr[0] != results->wm_lp_spr[0])
> - I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]);
> - if (previous.wm_lp_spr[1] != results->wm_lp_spr[1])
> - I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]);
> - if (previous.wm_lp_spr[2] != results->wm_lp_spr[2])
> - I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]);
> -
> - if (results->wm_lp[0] != 0)
> - I915_WRITE(WM1_LP_ILK, results->wm_lp[0]);
> - if (results->wm_lp[1] != 0)
> - I915_WRITE(WM2_LP_ILK, results->wm_lp[1]);
> - if (results->wm_lp[2] != 0)
> - I915_WRITE(WM3_LP_ILK, results->wm_lp[2]);
> -}
> -
> -static void haswell_update_wm(struct drm_crtc *crtc)
> -{
> - struct drm_device *dev = crtc->dev;
> - struct drm_i915_private *dev_priv = dev->dev_private;
> - 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;
> - enum intel_ddb_partitioning partitioning;
> -
> - hsw_compute_wm_parameters(dev, params, &lp_max_1_2, &lp_max_5_6);
> -
> - 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,
> - &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) ?
> - INTEL_DDB_PART_1_2 : INTEL_DDB_PART_5_6;
> -
> - hsw_write_wm_values(dev_priv, best_results, partitioning);
> + intel_setup_pipe_wm(intel_crtc, &pipe_wm);
> }
>
> -static void haswell_update_sprite_wm(struct drm_plane *plane,
> - struct drm_crtc *crtc,
> - uint32_t sprite_width, int pixel_size,
> - bool enabled, bool scaled)
> +static void ilk_update_sprite_wm(struct drm_plane *plane,
> + struct drm_crtc *crtc,
> + uint32_t sprite_width, int pixel_size,
> + bool enabled, bool scaled)
> {
> struct intel_plane *intel_plane = to_intel_plane(plane);
>
> @@ -2838,169 +2734,7 @@ static void haswell_update_sprite_wm(struct drm_plane *plane,
> intel_plane->wm.horiz_pixels = sprite_width;
> intel_plane->wm.bytes_per_pixel = pixel_size;
>
> - haswell_update_wm(crtc);
> -}
> -
> -static bool
> -sandybridge_compute_sprite_wm(struct drm_device *dev, int plane,
> - uint32_t sprite_width, int pixel_size,
> - const struct intel_watermark_params *display,
> - int display_latency_ns, int *sprite_wm)
> -{
> - struct drm_crtc *crtc;
> - int clock;
> - int entries, tlb_miss;
> -
> - crtc = intel_get_crtc_for_plane(dev, plane);
> - if (!intel_crtc_active(crtc)) {
> - *sprite_wm = display->guard_size;
> - return false;
> - }
> -
> - clock = crtc->mode.clock;
> -
> - /* Use the small buffer method to calculate the sprite watermark */
> - entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
> - tlb_miss = display->fifo_size*display->cacheline_size -
> - sprite_width * 8;
> - if (tlb_miss > 0)
> - entries += tlb_miss;
> - entries = DIV_ROUND_UP(entries, display->cacheline_size);
> - *sprite_wm = entries + display->guard_size;
> - if (*sprite_wm > (int)display->max_wm)
> - *sprite_wm = display->max_wm;
> -
> - return true;
> -}
> -
> -static bool
> -sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
> - uint32_t sprite_width, int pixel_size,
> - const struct intel_watermark_params *display,
> - int latency_ns, int *sprite_wm)
> -{
> - struct drm_crtc *crtc;
> - unsigned long line_time_us;
> - int clock;
> - int line_count, line_size;
> - int small, large;
> - int entries;
> -
> - if (!latency_ns) {
> - *sprite_wm = 0;
> - return false;
> - }
> -
> - crtc = intel_get_crtc_for_plane(dev, plane);
> - clock = crtc->mode.clock;
> - if (!clock) {
> - *sprite_wm = 0;
> - return false;
> - }
> -
> - line_time_us = (sprite_width * 1000) / clock;
> - if (!line_time_us) {
> - *sprite_wm = 0;
> - return false;
> - }
> -
> - line_count = (latency_ns / line_time_us + 1000) / 1000;
> - line_size = sprite_width * pixel_size;
> -
> - /* Use the minimum of the small and large buffer method for primary */
> - small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
> - large = line_count * line_size;
> -
> - entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
> - *sprite_wm = entries + display->guard_size;
> -
> - return *sprite_wm > 0x3ff ? false : true;
> -}
> -
> -static void sandybridge_update_sprite_wm(struct drm_plane *plane,
> - struct drm_crtc *crtc,
> - uint32_t sprite_width, int pixel_size,
> - bool enable, bool scaled)
> -{
> - struct drm_device *dev = plane->dev;
> - struct drm_i915_private *dev_priv = dev->dev_private;
> - int pipe = to_intel_plane(plane)->pipe;
> - int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
> - u32 val;
> - int sprite_wm, reg;
> - int ret;
> -
> - if (!enable)
> - return;
> -
> - switch (pipe) {
> - case 0:
> - reg = WM0_PIPEA_ILK;
> - break;
> - case 1:
> - reg = WM0_PIPEB_ILK;
> - break;
> - case 2:
> - reg = WM0_PIPEC_IVB;
> - break;
> - default:
> - return; /* bad pipe */
> - }
> -
> - ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size,
> - &sandybridge_display_wm_info,
> - latency, &sprite_wm);
> - if (!ret) {
> - DRM_DEBUG_KMS("failed to compute sprite wm for pipe %c\n",
> - pipe_name(pipe));
> - return;
> - }
> -
> - val = I915_READ(reg);
> - val &= ~WM0_PIPE_SPRITE_MASK;
> - I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
> - DRM_DEBUG_KMS("sprite watermarks For pipe %c - %d\n", pipe_name(pipe), sprite_wm);
> -
> -
> - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
> - pixel_size,
> - &sandybridge_display_srwm_info,
> - SNB_READ_WM1_LATENCY() * 500,
> - &sprite_wm);
> - if (!ret) {
> - DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %c\n",
> - pipe_name(pipe));
> - return;
> - }
> - I915_WRITE(WM1S_LP_ILK, sprite_wm);
> -
> - /* Only IVB has two more LP watermarks for sprite */
> - if (!IS_IVYBRIDGE(dev))
> - return;
> -
> - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
> - pixel_size,
> - &sandybridge_display_srwm_info,
> - SNB_READ_WM2_LATENCY() * 500,
> - &sprite_wm);
> - if (!ret) {
> - DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %c\n",
> - pipe_name(pipe));
> - return;
> - }
> - I915_WRITE(WM2S_LP_IVB, sprite_wm);
> -
> - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
> - pixel_size,
> - &sandybridge_display_srwm_info,
> - SNB_READ_WM3_LATENCY() * 500,
> - &sprite_wm);
> - if (!ret) {
> - DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %c\n",
> - pipe_name(pipe));
> - return;
> - }
> - I915_WRITE(WM3S_LP_IVB, sprite_wm);
> + ilk_update_wm(crtc);
> }
>
> /**
> @@ -5372,6 +5106,8 @@ void intel_init_pm(struct drm_device *dev)
> {
> struct drm_i915_private *dev_priv = dev->dev_private;
>
> + spin_lock_init(&dev_priv->wm.lock);
> +
> if (I915_HAS_FBC(dev)) {
> if (HAS_PCH_SPLIT(dev)) {
> dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
> @@ -5407,9 +5143,10 @@ void intel_init_pm(struct drm_device *dev)
> if (IS_GEN5(dev)) {
> 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 {
> + dev_priv->wm.cur_latency[1]) {
> + dev_priv->display.update_wm = ilk_update_wm;
> + dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
> + } else {
> DRM_DEBUG_KMS("Failed to get proper latency. "
> "Disable CxSR\n");
> dev_priv->display.update_wm = NULL;
> @@ -5419,8 +5156,8 @@ void intel_init_pm(struct drm_device *dev)
> 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;
> + dev_priv->display.update_wm = ilk_update_wm;
> + dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
> } else {
> DRM_DEBUG_KMS("Failed to read display plane latency. "
> "Disable CxSR\n");
> @@ -5431,8 +5168,8 @@ void intel_init_pm(struct drm_device *dev)
> 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;
> + dev_priv->display.update_wm = ilk_update_wm;
> + dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
> } else {
> DRM_DEBUG_KMS("Failed to read display plane latency. "
> "Disable CxSR\n");
> @@ -5443,9 +5180,8 @@ void intel_init_pm(struct drm_device *dev)
> 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;
> + dev_priv->display.update_wm = ilk_update_wm;
> + dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
> } else {
> DRM_DEBUG_KMS("Failed to read display plane latency. "
> "Disable CxSR\n");
> --
> 1.8.1.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Paulo Zanoni
More information about the Intel-gfx
mailing list