diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_display.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_display.c | 895 |
1 files changed, 624 insertions, 271 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b4ef4d59da1a..863927f429aa 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -43,9 +43,7 @@ #include <drm/drm_fourcc.h> #include <drm/drm_probe_helper.h> #include <drm/drm_rect.h> - -#include "gem/i915_gem_lmem.h" -#include "gem/i915_gem_object.h" +#include <drm/drm_vblank.h> #include "g4x_dp.h" #include "g4x_hdmi.h" @@ -60,6 +58,7 @@ #include "intel_atomic.h" #include "intel_atomic_plane.h" #include "intel_audio.h" +#include "intel_bo.h" #include "intel_bw.h" #include "intel_cdclk.h" #include "intel_clock_gating.h" @@ -135,7 +134,8 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state); static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state); static void hsw_set_transconf(const struct intel_crtc_state *crtc_state); -static void bdw_set_pipe_misc(const struct intel_crtc_state *crtc_state); +static void bdw_set_pipe_misc(struct intel_dsb *dsb, + const struct intel_crtc_state *crtc_state); /* returns HPLL frequency in kHz */ int vlv_get_hpll_vco(struct drm_i915_private *dev_priv) @@ -253,6 +253,108 @@ static enum pipe joiner_primary_pipe(const struct intel_crtc_state *crtc_state) return ffs(crtc_state->joiner_pipes) - 1; } +/* + * The following helper functions, despite being named for bigjoiner, + * are applicable to both bigjoiner and uncompressed joiner configurations. + */ +static bool is_bigjoiner(const struct intel_crtc_state *crtc_state) +{ + return hweight8(crtc_state->joiner_pipes) >= 2; +} + +static u8 bigjoiner_primary_pipes(const struct intel_crtc_state *crtc_state) +{ + if (!is_bigjoiner(crtc_state)) + return 0; + + return crtc_state->joiner_pipes & (0b01010101 << joiner_primary_pipe(crtc_state)); +} + +static unsigned int bigjoiner_secondary_pipes(const struct intel_crtc_state *crtc_state) +{ + if (!is_bigjoiner(crtc_state)) + return 0; + + return crtc_state->joiner_pipes & (0b10101010 << joiner_primary_pipe(crtc_state)); +} + +bool intel_crtc_is_bigjoiner_primary(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + + if (!is_bigjoiner(crtc_state)) + return false; + + return BIT(crtc->pipe) & bigjoiner_primary_pipes(crtc_state); +} + +bool intel_crtc_is_bigjoiner_secondary(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + + if (!is_bigjoiner(crtc_state)) + return false; + + return BIT(crtc->pipe) & bigjoiner_secondary_pipes(crtc_state); +} + +u8 _intel_modeset_primary_pipes(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + + if (!is_bigjoiner(crtc_state)) + return BIT(crtc->pipe); + + return bigjoiner_primary_pipes(crtc_state); +} + +u8 _intel_modeset_secondary_pipes(const struct intel_crtc_state *crtc_state) +{ + return bigjoiner_secondary_pipes(crtc_state); +} + +bool intel_crtc_is_ultrajoiner(const struct intel_crtc_state *crtc_state) +{ + return intel_crtc_num_joined_pipes(crtc_state) >= 4; +} + +static u8 ultrajoiner_primary_pipes(const struct intel_crtc_state *crtc_state) +{ + if (!intel_crtc_is_ultrajoiner(crtc_state)) + return 0; + + return crtc_state->joiner_pipes & (0b00010001 << joiner_primary_pipe(crtc_state)); +} + +bool intel_crtc_is_ultrajoiner_primary(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + + return intel_crtc_is_ultrajoiner(crtc_state) && + BIT(crtc->pipe) & ultrajoiner_primary_pipes(crtc_state); +} + +/* + * The ultrajoiner enable bit doesn't seem to follow primary/secondary logic or + * any other logic, so lets just add helper function to + * at least hide this hassle.. + */ +static u8 ultrajoiner_enable_pipes(const struct intel_crtc_state *crtc_state) +{ + if (!intel_crtc_is_ultrajoiner(crtc_state)) + return 0; + + return crtc_state->joiner_pipes & (0b01110111 << joiner_primary_pipe(crtc_state)); +} + +bool intel_crtc_ultrajoiner_enable_needed(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + + return intel_crtc_is_ultrajoiner(crtc_state) && + BIT(crtc->pipe) & ultrajoiner_enable_pipes(crtc_state); +} + u8 intel_crtc_joiner_secondary_pipes(const struct intel_crtc_state *crtc_state) { if (crtc_state->joiner_pipes) @@ -277,9 +379,9 @@ bool intel_crtc_is_joiner_primary(const struct intel_crtc_state *crtc_state) crtc->pipe == joiner_primary_pipe(crtc_state); } -static int intel_joiner_num_pipes(const struct intel_crtc_state *crtc_state) +int intel_crtc_num_joined_pipes(const struct intel_crtc_state *crtc_state) { - return hweight8(crtc_state->joiner_pipes); + return hweight8(intel_crtc_joined_pipe_mask(crtc_state)); } u8 intel_crtc_joined_pipe_mask(const struct intel_crtc_state *crtc_state) @@ -291,10 +393,10 @@ u8 intel_crtc_joined_pipe_mask(const struct intel_crtc_state *crtc_state) struct intel_crtc *intel_primary_crtc(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + struct intel_display *display = to_intel_display(crtc_state); if (intel_crtc_is_joiner_secondary(crtc_state)) - return intel_crtc_for_pipe(i915, joiner_primary_pipe(crtc_state)); + return intel_crtc_for_pipe(display, joiner_primary_pipe(crtc_state)); else return to_intel_crtc(crtc_state->uapi.crtc); } @@ -320,6 +422,7 @@ intel_wait_for_pipe_off(const struct intel_crtc_state *old_crtc_state) void assert_transcoder(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder, bool state) { + struct intel_display *display = &dev_priv->display; bool cur_state; enum intel_display_power_domain power_domain; intel_wakeref_t wakeref; @@ -340,24 +443,24 @@ void assert_transcoder(struct drm_i915_private *dev_priv, cur_state = false; } - I915_STATE_WARN(dev_priv, cur_state != state, - "transcoder %s assertion failure (expected %s, current %s)\n", - transcoder_name(cpu_transcoder), str_on_off(state), - str_on_off(cur_state)); + INTEL_DISPLAY_STATE_WARN(display, cur_state != state, + "transcoder %s assertion failure (expected %s, current %s)\n", + transcoder_name(cpu_transcoder), str_on_off(state), + str_on_off(cur_state)); } static void assert_plane(struct intel_plane *plane, bool state) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane->base.dev); enum pipe pipe; bool cur_state; cur_state = plane->get_hw_state(plane, &pipe); - I915_STATE_WARN(i915, cur_state != state, - "%s assertion failure (expected %s, current %s)\n", - plane->base.name, str_on_off(state), - str_on_off(cur_state)); + INTEL_DISPLAY_STATE_WARN(display, cur_state != state, + "%s assertion failure (expected %s, current %s)\n", + plane->base.name, str_on_off(state), + str_on_off(cur_state)); } #define assert_plane_enabled(p) assert_plane(p, true) @@ -372,7 +475,7 @@ static void assert_planes_disabled(struct intel_crtc *crtc) assert_plane_disabled(plane); } -void vlv_wait_port_ready(struct drm_i915_private *dev_priv, +void vlv_wait_port_ready(struct intel_display *display, struct intel_digital_port *dig_port, unsigned int expected_mask) { @@ -385,11 +488,11 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv, fallthrough; case PORT_B: port_mask = DPLL_PORTB_READY_MASK; - dpll_reg = DPLL(dev_priv, 0); + dpll_reg = DPLL(display, 0); break; case PORT_C: port_mask = DPLL_PORTC_READY_MASK; - dpll_reg = DPLL(dev_priv, 0); + dpll_reg = DPLL(display, 0); expected_mask <<= 4; break; case PORT_D: @@ -398,11 +501,11 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv, break; } - if (intel_de_wait(dev_priv, dpll_reg, port_mask, expected_mask, 1000)) - drm_WARN(&dev_priv->drm, 1, + if (intel_de_wait(display, dpll_reg, port_mask, expected_mask, 1000)) + drm_WARN(display->drm, 1, "timed out waiting for [ENCODER:%d:%s] port ready: got 0x%x, expected 0x%x\n", dig_port->base.base.base.id, dig_port->base.base.name, - intel_de_read(dev_priv, dpll_reg) & port_mask, + intel_de_read(display, dpll_reg) & port_mask, expected_mask); } @@ -715,7 +818,7 @@ void intel_plane_disable_noatomic(struct intel_crtc *crtc, if (DISPLAY_VER(dev_priv) == 2 && !crtc_state->active_planes) intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false); - intel_plane_disable_arm(plane, crtc_state); + intel_plane_disable_arm(NULL, plane, crtc_state); intel_crtc_wait_for_next_vblank(crtc); } @@ -759,7 +862,7 @@ static void icl_set_pipe_chicken(const struct intel_crtc_state *crtc_state) */ if (IS_DG2(dev_priv)) tmp &= ~UNDERRUN_RECOVERY_ENABLE_DG2; - else if (DISPLAY_VER(dev_priv) >= 13) + else if ((DISPLAY_VER(dev_priv) >= 13) && (DISPLAY_VER(dev_priv) < 30)) tmp |= UNDERRUN_RECOVERY_DISABLE_ADLP; /* Wa_14010547955:dg2 */ @@ -1116,6 +1219,22 @@ static void intel_post_plane_update(struct intel_atomic_state *state, intel_encoders_audio_enable(state, crtc); } +static void intel_post_plane_update_after_readout(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + + /* Must be done after gamma readout due to HSW split gamma vs. IPS w/a */ + hsw_ips_post_update(state, crtc); + + /* + * Activate DRRS after state readout to avoid + * dp_m_n vs. dp_m2_n2 confusion on BDW+. + */ + intel_drrs_activate(new_crtc_state); +} + static void intel_crtc_enable_flip_done(struct intel_atomic_state *state, struct intel_crtc *crtc) { @@ -1172,8 +1291,8 @@ static void intel_crtc_async_flip_disable_wa(struct intel_atomic_state *state, * Apart from the async flip bit we want to * preserve the old state for the plane. */ - intel_plane_async_flip(plane, old_crtc_state, - old_plane_state, false); + intel_plane_async_flip(NULL, plane, + old_crtc_state, old_plane_state, false); need_vbl_wait = true; } } @@ -1249,8 +1368,8 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, * * WaCxSRDisabledForSpriteScaling:ivb */ - if (old_crtc_state->hw.active && - new_crtc_state->disable_lp_wm && ilk_disable_lp_wm(dev_priv)) + if (!HAS_GMCH(dev_priv) && old_crtc_state->hw.active && + new_crtc_state->disable_cxsr && ilk_disable_cxsr(dev_priv)) intel_crtc_wait_for_next_vblank(crtc); /* @@ -1315,7 +1434,7 @@ static void intel_crtc_disable_planes(struct intel_atomic_state *state, !(update_mask & BIT(plane->id))) continue; - intel_plane_disable_arm(plane, new_crtc_state); + intel_plane_disable_arm(NULL, plane, new_crtc_state); if (old_plane_state->uapi.visible) fb_bits |= plane->frontbuffer_bit; @@ -1502,14 +1621,6 @@ static void intel_encoders_update_pipe(struct intel_atomic_state *state, } } -static void intel_disable_primary_plane(const struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct intel_plane *plane = to_intel_plane(crtc->base.primary); - - plane->disable_arm(plane, crtc_state); -} - static void ilk_configure_cpu_transcoder(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -1575,11 +1686,7 @@ static void ilk_crtc_enable(struct intel_atomic_state *state, * On ILK+ LUT must be loaded before the pipe is running but with * clocks enabled */ - intel_color_load_luts(new_crtc_state); - intel_color_commit_noarm(new_crtc_state); - intel_color_commit_arm(new_crtc_state); - /* update DSPCNTR to configure gamma for pipe bottom color */ - intel_disable_primary_plane(new_crtc_state); + intel_color_modeset(new_crtc_state); intel_initial_watermarks(state, crtc); intel_enable_transcoder(new_crtc_state); @@ -1677,23 +1784,22 @@ static void hsw_configure_cpu_transcoder(const struct intel_crtc_state *crtc_sta static void hsw_crtc_enable(struct intel_atomic_state *state, struct intel_crtc *crtc) { + struct intel_display *display = to_intel_display(state); const struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum transcoder cpu_transcoder = new_crtc_state->cpu_transcoder; struct intel_crtc *pipe_crtc; + int i; if (drm_WARN_ON(&dev_priv->drm, crtc->active)) return; - - for_each_intel_crtc_in_pipe_mask_reverse(&dev_priv->drm, pipe_crtc, - intel_crtc_joined_pipe_mask(new_crtc_state)) - intel_dmc_enable_pipe(dev_priv, pipe_crtc->pipe); + for_each_pipe_crtc_modeset_enable(display, pipe_crtc, new_crtc_state, i) + intel_dmc_enable_pipe(display, pipe_crtc->pipe); intel_encoders_pre_pll_enable(state, crtc); - for_each_intel_crtc_in_pipe_mask_reverse(&dev_priv->drm, pipe_crtc, - intel_crtc_joined_pipe_mask(new_crtc_state)) { + for_each_pipe_crtc_modeset_enable(display, pipe_crtc, new_crtc_state, i) { const struct intel_crtc_state *pipe_crtc_state = intel_atomic_get_new_crtc_state(state, pipe_crtc); @@ -1703,27 +1809,25 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, intel_encoders_pre_enable(state, crtc); - for_each_intel_crtc_in_pipe_mask_reverse(&dev_priv->drm, pipe_crtc, - intel_crtc_joined_pipe_mask(new_crtc_state)) { + for_each_pipe_crtc_modeset_enable(display, pipe_crtc, new_crtc_state, i) { const struct intel_crtc_state *pipe_crtc_state = intel_atomic_get_new_crtc_state(state, pipe_crtc); intel_dsc_enable(pipe_crtc_state); - if (DISPLAY_VER(dev_priv) >= 13) + if (HAS_UNCOMPRESSED_JOINER(dev_priv)) intel_uncompressed_joiner_enable(pipe_crtc_state); intel_set_pipe_src_size(pipe_crtc_state); if (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv)) - bdw_set_pipe_misc(pipe_crtc_state); + bdw_set_pipe_misc(NULL, pipe_crtc_state); } if (!transcoder_is_dsi(cpu_transcoder)) hsw_configure_cpu_transcoder(new_crtc_state); - for_each_intel_crtc_in_pipe_mask_reverse(&dev_priv->drm, pipe_crtc, - intel_crtc_joined_pipe_mask(new_crtc_state)) { + for_each_pipe_crtc_modeset_enable(display, pipe_crtc, new_crtc_state, i) { const struct intel_crtc_state *pipe_crtc_state = intel_atomic_get_new_crtc_state(state, pipe_crtc); @@ -1741,12 +1845,7 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, * On ILK+ LUT must be loaded before the pipe is running but with * clocks enabled */ - intel_color_load_luts(pipe_crtc_state); - intel_color_commit_noarm(pipe_crtc_state); - intel_color_commit_arm(pipe_crtc_state); - /* update DSPCNTR to configure gamma/csc for pipe bottom color */ - if (DISPLAY_VER(dev_priv) < 9) - intel_disable_primary_plane(pipe_crtc_state); + intel_color_modeset(pipe_crtc_state); hsw_set_linetime_wm(pipe_crtc_state); @@ -1758,8 +1857,7 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, intel_encoders_enable(state, crtc); - for_each_intel_crtc_in_pipe_mask_reverse(&dev_priv->drm, pipe_crtc, - intel_crtc_joined_pipe_mask(new_crtc_state)) { + for_each_pipe_crtc_modeset_enable(display, pipe_crtc, new_crtc_state, i) { const struct intel_crtc_state *pipe_crtc_state = intel_atomic_get_new_crtc_state(state, pipe_crtc); enum pipe hsw_workaround_pipe; @@ -1776,7 +1874,7 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, hsw_workaround_pipe = pipe_crtc_state->hsw_workaround_pipe; if (IS_HASWELL(dev_priv) && hsw_workaround_pipe != INVALID_PIPE) { struct intel_crtc *wa_crtc = - intel_crtc_for_pipe(dev_priv, hsw_workaround_pipe); + intel_crtc_for_pipe(display, hsw_workaround_pipe); intel_crtc_wait_for_next_vblank(wa_crtc); intel_crtc_wait_for_next_vblank(wa_crtc); @@ -1841,10 +1939,11 @@ static void ilk_crtc_disable(struct intel_atomic_state *state, static void hsw_crtc_disable(struct intel_atomic_state *state, struct intel_crtc *crtc) { + struct intel_display *display = to_intel_display(state); const struct intel_crtc_state *old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc); - struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_crtc *pipe_crtc; + int i; /* * FIXME collapse everything to one hook. @@ -1853,8 +1952,7 @@ static void hsw_crtc_disable(struct intel_atomic_state *state, intel_encoders_disable(state, crtc); intel_encoders_post_disable(state, crtc); - for_each_intel_crtc_in_pipe_mask(&i915->drm, pipe_crtc, - intel_crtc_joined_pipe_mask(old_crtc_state)) { + for_each_pipe_crtc_modeset_disable(display, pipe_crtc, old_crtc_state, i) { const struct intel_crtc_state *old_pipe_crtc_state = intel_atomic_get_old_crtc_state(state, pipe_crtc); @@ -1863,9 +1961,8 @@ static void hsw_crtc_disable(struct intel_atomic_state *state, intel_encoders_post_pll_disable(state, crtc); - for_each_intel_crtc_in_pipe_mask(&i915->drm, pipe_crtc, - intel_crtc_joined_pipe_mask(old_crtc_state)) - intel_dmc_disable_pipe(i915, pipe_crtc->pipe); + for_each_pipe_crtc_modeset_disable(display, pipe_crtc, old_crtc_state, i) + intel_dmc_disable_pipe(display, pipe_crtc->pipe); } static void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state) @@ -2147,11 +2244,7 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state, i9xx_pfit_enable(new_crtc_state); - intel_color_load_luts(new_crtc_state); - intel_color_commit_noarm(new_crtc_state); - intel_color_commit_arm(new_crtc_state); - /* update DSPCNTR to configure gamma for pipe bottom color */ - intel_disable_primary_plane(new_crtc_state); + intel_color_modeset(new_crtc_state); intel_initial_watermarks(state, crtc); intel_enable_transcoder(new_crtc_state); @@ -2187,11 +2280,7 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state, i9xx_pfit_enable(new_crtc_state); - intel_color_load_luts(new_crtc_state); - intel_color_commit_noarm(new_crtc_state); - intel_color_commit_arm(new_crtc_state); - /* update DSPCNTR to configure gamma for pipe bottom color */ - intel_disable_primary_plane(new_crtc_state); + intel_color_modeset(new_crtc_state); if (!intel_initial_watermarks(state, crtc)) intel_update_watermarks(dev_priv); @@ -2224,9 +2313,10 @@ static void i9xx_pfit_disable(const struct intel_crtc_state *old_crtc_state) static void i9xx_crtc_disable(struct intel_atomic_state *state, struct intel_crtc *crtc) { + struct intel_display *display = to_intel_display(state); + struct drm_i915_private *dev_priv = to_i915(display->drm); struct intel_crtc_state *old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; /* @@ -2265,7 +2355,7 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state, /* clock the pipe down to 640x480@60 to potentially save power */ if (IS_I830(dev_priv)) - i830_enable_pipe(dev_priv, pipe); + i830_enable_pipe(display, pipe); } void intel_encoder_destroy(struct drm_encoder *encoder) @@ -2343,9 +2433,9 @@ static void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state) static void intel_joiner_adjust_timings(const struct intel_crtc_state *crtc_state, struct drm_display_mode *mode) { - int num_pipes = intel_joiner_num_pipes(crtc_state); + int num_pipes = intel_crtc_num_joined_pipes(crtc_state); - if (num_pipes < 2) + if (num_pipes == 1) return; mode->crtc_clock /= num_pipes; @@ -2407,7 +2497,7 @@ static void intel_crtc_readout_derived_state(struct intel_crtc_state *crtc_state drm_mode_copy(mode, pipe_mode); intel_mode_from_crtc_timings(mode, mode); mode->hdisplay = drm_rect_width(&crtc_state->pipe_src) * - (intel_joiner_num_pipes(crtc_state) ?: 1); + intel_crtc_num_joined_pipes(crtc_state); mode->vdisplay = drm_rect_height(&crtc_state->pipe_src); /* Derive per-pipe timings in case joiner is used */ @@ -2427,10 +2517,10 @@ void intel_encoder_get_config(struct intel_encoder *encoder, static void intel_joiner_compute_pipe_src(struct intel_crtc_state *crtc_state) { - int num_pipes = intel_joiner_num_pipes(crtc_state); + int num_pipes = intel_crtc_num_joined_pipes(crtc_state); int width, height; - if (num_pipes < 2) + if (num_pipes == 1) return; width = drm_rect_width(&crtc_state->pipe_src); @@ -2520,13 +2610,29 @@ static int intel_crtc_compute_pipe_mode(struct intel_crtc_state *crtc_state) return 0; } +static bool intel_crtc_needs_wa_14015401596(struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + + return intel_vrr_possible(crtc_state) && crtc_state->has_psr && + adjusted_mode->crtc_vblank_start == adjusted_mode->crtc_vdisplay && + IS_DISPLAY_VER(display, 13, 14); +} + static int intel_crtc_compute_config(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); + struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; int ret; + /* Wa_14015401596 */ + if (intel_crtc_needs_wa_14015401596(crtc_state)) + adjusted_mode->crtc_vblank_start += 1; + ret = intel_dpll_crtc_compute_clock(state, crtc); if (ret) return ret; @@ -2887,11 +2993,11 @@ static void intel_get_transcoder_timings(struct intel_crtc *crtc, static void intel_joiner_adjust_pipe_src(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - int num_pipes = intel_joiner_num_pipes(crtc_state); + int num_pipes = intel_crtc_num_joined_pipes(crtc_state); enum pipe primary_pipe, pipe = crtc->pipe; int width; - if (num_pipes < 2) + if (num_pipes == 1) return; primary_pipe = joiner_primary_pipe(crtc_state); @@ -3246,9 +3352,11 @@ static void hsw_set_transconf(const struct intel_crtc_state *crtc_state) intel_de_posting_read(dev_priv, TRANSCONF(dev_priv, cpu_transcoder)); } -static void bdw_set_pipe_misc(const struct intel_crtc_state *crtc_state) +static void bdw_set_pipe_misc(struct intel_dsb *dsb, + const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct intel_display *display = to_intel_display(crtc->base.dev); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 val = 0; @@ -3293,7 +3401,7 @@ static void bdw_set_pipe_misc(const struct intel_crtc_state *crtc_state) if (IS_BROADWELL(dev_priv)) val |= PIPE_MISC_PSR_MASK_SPRITE_ENABLE; - intel_de_write(dev_priv, PIPE_MISC(crtc->pipe), val); + intel_de_write_dsb(display, dsb, PIPE_MISC(crtc->pipe), val); } int bdw_get_pipe_misc_bpp(struct intel_crtc *crtc) @@ -3534,23 +3642,57 @@ static bool transcoder_ddi_func_is_enabled(struct drm_i915_private *dev_priv, return tmp & TRANS_DDI_FUNC_ENABLE; } -static void enabled_joiner_pipes(struct drm_i915_private *dev_priv, - u8 *primary_pipes, u8 *secondary_pipes) +static void enabled_uncompressed_joiner_pipes(struct intel_display *display, + u8 *primary_pipes, u8 *secondary_pipes) +{ + struct drm_i915_private *i915 = to_i915(display->drm); + struct intel_crtc *crtc; + + *primary_pipes = 0; + *secondary_pipes = 0; + + if (!HAS_UNCOMPRESSED_JOINER(display)) + return; + + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, + joiner_pipes(i915)) { + enum intel_display_power_domain power_domain; + enum pipe pipe = crtc->pipe; + intel_wakeref_t wakeref; + + power_domain = POWER_DOMAIN_PIPE(pipe); + with_intel_display_power_if_enabled(i915, power_domain, wakeref) { + u32 tmp = intel_de_read(display, ICL_PIPE_DSS_CTL1(pipe)); + + if (tmp & UNCOMPRESSED_JOINER_PRIMARY) + *primary_pipes |= BIT(pipe); + if (tmp & UNCOMPRESSED_JOINER_SECONDARY) + *secondary_pipes |= BIT(pipe); + } + } +} + +static void enabled_bigjoiner_pipes(struct intel_display *display, + u8 *primary_pipes, u8 *secondary_pipes) { + struct drm_i915_private *i915 = to_i915(display->drm); struct intel_crtc *crtc; *primary_pipes = 0; *secondary_pipes = 0; - for_each_intel_crtc_in_pipe_mask(&dev_priv->drm, crtc, - joiner_pipes(dev_priv)) { + if (!HAS_BIGJOINER(display)) + return; + + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, + joiner_pipes(i915)) { enum intel_display_power_domain power_domain; enum pipe pipe = crtc->pipe; intel_wakeref_t wakeref; - power_domain = intel_dsc_power_domain(crtc, (enum transcoder) pipe); - with_intel_display_power_if_enabled(dev_priv, power_domain, wakeref) { - u32 tmp = intel_de_read(dev_priv, ICL_PIPE_DSS_CTL1(pipe)); + power_domain = intel_dsc_power_domain(crtc, (enum transcoder)pipe); + with_intel_display_power_if_enabled(i915, power_domain, wakeref) { + u32 tmp = intel_de_read(display, ICL_PIPE_DSS_CTL1(pipe)); if (!(tmp & BIG_JOINER_ENABLE)) continue; @@ -3560,56 +3702,197 @@ static void enabled_joiner_pipes(struct drm_i915_private *dev_priv, else *secondary_pipes |= BIT(pipe); } + } +} - if (DISPLAY_VER(dev_priv) < 13) - continue; +static u8 expected_secondary_pipes(u8 primary_pipes, int num_pipes) +{ + u8 secondary_pipes = 0; - power_domain = POWER_DOMAIN_PIPE(pipe); - with_intel_display_power_if_enabled(dev_priv, power_domain, wakeref) { - u32 tmp = intel_de_read(dev_priv, ICL_PIPE_DSS_CTL1(pipe)); + for (int i = 1; i < num_pipes; i++) + secondary_pipes |= primary_pipes << i; - if (tmp & UNCOMPRESSED_JOINER_PRIMARY) - *primary_pipes |= BIT(pipe); - if (tmp & UNCOMPRESSED_JOINER_SECONDARY) - *secondary_pipes |= BIT(pipe); - } - } + return secondary_pipes; +} - /* Joiner pipes should always be consecutive primary and secondary */ - drm_WARN(&dev_priv->drm, *secondary_pipes != *primary_pipes << 1, - "Joiner misconfigured (primary pipes 0x%x, secondary pipes 0x%x)\n", - *primary_pipes, *secondary_pipes); +static u8 expected_uncompressed_joiner_secondary_pipes(u8 uncompjoiner_primary_pipes) +{ + return expected_secondary_pipes(uncompjoiner_primary_pipes, 2); } -static enum pipe get_joiner_primary_pipe(enum pipe pipe, u8 primary_pipes, u8 secondary_pipes) +static u8 expected_bigjoiner_secondary_pipes(u8 bigjoiner_primary_pipes) { - if ((secondary_pipes & BIT(pipe)) == 0) - return pipe; + return expected_secondary_pipes(bigjoiner_primary_pipes, 2); +} - /* ignore everything above our pipe */ - primary_pipes &= ~GENMASK(7, pipe); +static u8 get_joiner_primary_pipe(enum pipe pipe, u8 primary_pipes) +{ + primary_pipes &= GENMASK(pipe, 0); - /* highest remaining bit should be our primary pipe */ - return fls(primary_pipes) - 1; + return primary_pipes ? BIT(fls(primary_pipes) - 1) : 0; } -static u8 get_joiner_secondary_pipes(enum pipe pipe, u8 primary_pipes, u8 secondary_pipes) +static u8 expected_ultrajoiner_secondary_pipes(u8 ultrajoiner_primary_pipes) { - enum pipe primary_pipe, next_primary_pipe; + return expected_secondary_pipes(ultrajoiner_primary_pipes, 4); +} - primary_pipe = get_joiner_primary_pipe(pipe, primary_pipes, secondary_pipes); +static u8 fixup_ultrajoiner_secondary_pipes(u8 ultrajoiner_primary_pipes, + u8 ultrajoiner_secondary_pipes) +{ + return ultrajoiner_secondary_pipes | ultrajoiner_primary_pipes << 3; +} - if ((primary_pipes & BIT(primary_pipe)) == 0) - return 0; +static void enabled_ultrajoiner_pipes(struct drm_i915_private *i915, + u8 *primary_pipes, u8 *secondary_pipes) +{ + struct intel_crtc *crtc; + + *primary_pipes = 0; + *secondary_pipes = 0; + + if (!HAS_ULTRAJOINER(i915)) + return; + + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, + joiner_pipes(i915)) { + enum intel_display_power_domain power_domain; + enum pipe pipe = crtc->pipe; + intel_wakeref_t wakeref; + + power_domain = intel_dsc_power_domain(crtc, (enum transcoder)pipe); + with_intel_display_power_if_enabled(i915, power_domain, wakeref) { + u32 tmp = intel_de_read(i915, ICL_PIPE_DSS_CTL1(pipe)); + + if (!(tmp & ULTRA_JOINER_ENABLE)) + continue; + + if (tmp & PRIMARY_ULTRA_JOINER_ENABLE) + *primary_pipes |= BIT(pipe); + else + *secondary_pipes |= BIT(pipe); + } + } +} + +static void enabled_joiner_pipes(struct drm_i915_private *dev_priv, + enum pipe pipe, + u8 *primary_pipe, u8 *secondary_pipes) +{ + struct intel_display *display = to_intel_display(&dev_priv->drm); + u8 primary_ultrajoiner_pipes; + u8 primary_uncompressed_joiner_pipes, primary_bigjoiner_pipes; + u8 secondary_ultrajoiner_pipes; + u8 secondary_uncompressed_joiner_pipes, secondary_bigjoiner_pipes; + u8 ultrajoiner_pipes; + u8 uncompressed_joiner_pipes, bigjoiner_pipes; + + enabled_ultrajoiner_pipes(dev_priv, &primary_ultrajoiner_pipes, + &secondary_ultrajoiner_pipes); + /* + * For some strange reason the last pipe in the set of four + * shouldn't have ultrajoiner enable bit set in hardware. + * Set the bit anyway to make life easier. + */ + drm_WARN_ON(&dev_priv->drm, + expected_secondary_pipes(primary_ultrajoiner_pipes, 3) != + secondary_ultrajoiner_pipes); + secondary_ultrajoiner_pipes = + fixup_ultrajoiner_secondary_pipes(primary_ultrajoiner_pipes, + secondary_ultrajoiner_pipes); + + drm_WARN_ON(&dev_priv->drm, (primary_ultrajoiner_pipes & secondary_ultrajoiner_pipes) != 0); + + enabled_uncompressed_joiner_pipes(display, &primary_uncompressed_joiner_pipes, + &secondary_uncompressed_joiner_pipes); + + drm_WARN_ON(display->drm, + (primary_uncompressed_joiner_pipes & secondary_uncompressed_joiner_pipes) != 0); + + enabled_bigjoiner_pipes(display, &primary_bigjoiner_pipes, + &secondary_bigjoiner_pipes); + + drm_WARN_ON(display->drm, + (primary_bigjoiner_pipes & secondary_bigjoiner_pipes) != 0); + + ultrajoiner_pipes = primary_ultrajoiner_pipes | secondary_ultrajoiner_pipes; + uncompressed_joiner_pipes = primary_uncompressed_joiner_pipes | + secondary_uncompressed_joiner_pipes; + bigjoiner_pipes = primary_bigjoiner_pipes | secondary_bigjoiner_pipes; + + drm_WARN(display->drm, (ultrajoiner_pipes & bigjoiner_pipes) != ultrajoiner_pipes, + "Ultrajoiner pipes(%#x) should be bigjoiner pipes(%#x)\n", + ultrajoiner_pipes, bigjoiner_pipes); + + drm_WARN(display->drm, secondary_ultrajoiner_pipes != + expected_ultrajoiner_secondary_pipes(primary_ultrajoiner_pipes), + "Wrong secondary ultrajoiner pipes(expected %#x, current %#x)\n", + expected_ultrajoiner_secondary_pipes(primary_ultrajoiner_pipes), + secondary_ultrajoiner_pipes); + + drm_WARN(display->drm, (uncompressed_joiner_pipes & bigjoiner_pipes) != 0, + "Uncompressed joiner pipes(%#x) and bigjoiner pipes(%#x) can't intersect\n", + uncompressed_joiner_pipes, bigjoiner_pipes); + + drm_WARN(display->drm, secondary_bigjoiner_pipes != + expected_bigjoiner_secondary_pipes(primary_bigjoiner_pipes), + "Wrong secondary bigjoiner pipes(expected %#x, current %#x)\n", + expected_bigjoiner_secondary_pipes(primary_bigjoiner_pipes), + secondary_bigjoiner_pipes); + + drm_WARN(display->drm, secondary_uncompressed_joiner_pipes != + expected_uncompressed_joiner_secondary_pipes(primary_uncompressed_joiner_pipes), + "Wrong secondary uncompressed joiner pipes(expected %#x, current %#x)\n", + expected_uncompressed_joiner_secondary_pipes(primary_uncompressed_joiner_pipes), + secondary_uncompressed_joiner_pipes); + + *primary_pipe = 0; + *secondary_pipes = 0; + + if (ultrajoiner_pipes & BIT(pipe)) { + *primary_pipe = get_joiner_primary_pipe(pipe, primary_ultrajoiner_pipes); + *secondary_pipes = secondary_ultrajoiner_pipes & + expected_ultrajoiner_secondary_pipes(*primary_pipe); + + drm_WARN(display->drm, + expected_ultrajoiner_secondary_pipes(*primary_pipe) != + *secondary_pipes, + "Wrong ultrajoiner secondary pipes for primary_pipe %#x (expected %#x, current %#x)\n", + *primary_pipe, + expected_ultrajoiner_secondary_pipes(*primary_pipe), + *secondary_pipes); + return; + } + + if (uncompressed_joiner_pipes & BIT(pipe)) { + *primary_pipe = get_joiner_primary_pipe(pipe, primary_uncompressed_joiner_pipes); + *secondary_pipes = secondary_uncompressed_joiner_pipes & + expected_uncompressed_joiner_secondary_pipes(*primary_pipe); + + drm_WARN(display->drm, + expected_uncompressed_joiner_secondary_pipes(*primary_pipe) != + *secondary_pipes, + "Wrong uncompressed joiner secondary pipes for primary_pipe %#x (expected %#x, current %#x)\n", + *primary_pipe, + expected_uncompressed_joiner_secondary_pipes(*primary_pipe), + *secondary_pipes); + return; + } - /* ignore our primary pipe and everything below it */ - primary_pipes &= ~GENMASK(primary_pipe, 0); - /* make sure a high bit is set for the ffs() */ - primary_pipes |= BIT(7); - /* lowest remaining bit should be the next primary pipe */ - next_primary_pipe = ffs(primary_pipes) - 1; + if (bigjoiner_pipes & BIT(pipe)) { + *primary_pipe = get_joiner_primary_pipe(pipe, primary_bigjoiner_pipes); + *secondary_pipes = secondary_bigjoiner_pipes & + expected_bigjoiner_secondary_pipes(*primary_pipe); - return secondary_pipes & GENMASK(next_primary_pipe - 1, primary_pipe); + drm_WARN(display->drm, + expected_bigjoiner_secondary_pipes(*primary_pipe) != + *secondary_pipes, + "Wrong bigjoiner secondary pipes for primary_pipe %#x (expected %#x, current %#x)\n", + *primary_pipe, + expected_bigjoiner_secondary_pipes(*primary_pipe), + *secondary_pipes); + return; + } } static u8 hsw_panel_transcoders(struct drm_i915_private *i915) @@ -3628,7 +3911,7 @@ static u8 hsw_enabled_transcoders(struct intel_crtc *crtc) struct drm_i915_private *dev_priv = to_i915(dev); u8 panel_transcoder_mask = hsw_panel_transcoders(dev_priv); enum transcoder cpu_transcoder; - u8 primary_pipes, secondary_pipes; + u8 primary_pipe, secondary_pipes; u8 enabled_transcoders = 0; /* @@ -3681,10 +3964,9 @@ static u8 hsw_enabled_transcoders(struct intel_crtc *crtc) enabled_transcoders |= BIT(cpu_transcoder); /* joiner secondary -> consider the primary pipe's transcoder as well */ - enabled_joiner_pipes(dev_priv, &primary_pipes, &secondary_pipes); + enabled_joiner_pipes(dev_priv, crtc->pipe, &primary_pipe, &secondary_pipes); if (secondary_pipes & BIT(crtc->pipe)) { - cpu_transcoder = (enum transcoder) - get_joiner_primary_pipe(crtc->pipe, primary_pipes, secondary_pipes); + cpu_transcoder = (enum transcoder)ffs(primary_pipe) - 1; if (transcoder_ddi_func_is_enabled(dev_priv, cpu_transcoder)) enabled_transcoders |= BIT(cpu_transcoder); } @@ -3815,17 +4097,15 @@ static void intel_joiner_get_config(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(crtc->base.dev); - u8 primary_pipes, secondary_pipes; + u8 primary_pipe, secondary_pipes; enum pipe pipe = crtc->pipe; - enabled_joiner_pipes(i915, &primary_pipes, &secondary_pipes); + enabled_joiner_pipes(i915, pipe, &primary_pipe, &secondary_pipes); - if (((primary_pipes | secondary_pipes) & BIT(pipe)) == 0) + if (((primary_pipe | secondary_pipes) & BIT(pipe)) == 0) return; - crtc_state->joiner_pipes = - BIT(get_joiner_primary_pipe(pipe, primary_pipes, secondary_pipes)) | - get_joiner_secondary_pipes(pipe, primary_pipes, secondary_pipes); + crtc_state->joiner_pipes = primary_pipe | secondary_pipes; } static bool hsw_get_pipe_config(struct intel_crtc *crtc, @@ -3986,7 +4266,7 @@ int intel_crtc_dotclock(const struct intel_crtc_state *pipe_config) struct drm_display_mode * intel_encoder_current_mode(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_display *display = to_intel_display(encoder); struct intel_crtc_state *crtc_state; struct drm_display_mode *mode; struct intel_crtc *crtc; @@ -3995,7 +4275,7 @@ intel_encoder_current_mode(struct intel_encoder *encoder) if (!encoder->get_hw_state(encoder, &pipe)) return NULL; - crtc = intel_crtc_for_pipe(dev_priv, pipe); + crtc = intel_crtc_for_pipe(display, pipe); mode = kzalloc(sizeof(*mode), GFP_KERNEL); if (!mode) @@ -4285,22 +4565,11 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state, if (ret) return ret; - ret = intel_compute_pipe_wm(state, crtc); - if (ret) { - drm_dbg_kms(&dev_priv->drm, - "Target pipe watermarks are invalid\n"); - return ret; - } - - /* - * Calculate 'intermediate' watermarks that satisfy both the - * old state and the new state. We can program these - * immediately. - */ - ret = intel_compute_intermediate_wm(state, crtc); + ret = intel_wm_compute(state, crtc); if (ret) { drm_dbg_kms(&dev_priv->drm, - "No valid intermediate pipe watermarks are possible\n"); + "[CRTC:%d:%s] watermarks are invalid\n", + crtc->base.base.id, crtc->base.name); return ret; } @@ -4798,6 +5067,8 @@ intel_modeset_pipe_config_late(struct intel_atomic_state *state, struct drm_connector *connector; int i; + intel_vrr_compute_config_late(crtc_state); + for_each_new_connector_in_state(&state->base, connector, conn_state, i) { struct intel_encoder *encoder = @@ -5035,15 +5306,15 @@ pipe_config_cx0pll_mismatch(struct drm_printer *p, bool fastset, const struct intel_cx0pll_state *a, const struct intel_cx0pll_state *b) { - struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct intel_display *display = to_intel_display(crtc); char *chipname = a->use_c10 ? "C10" : "C20"; pipe_config_mismatch(p, fastset, crtc, name, chipname); drm_printf(p, "expected:\n"); - intel_cx0pll_dump_hw_state(i915, a); + intel_cx0pll_dump_hw_state(display, a); drm_printf(p, "found:\n"); - intel_cx0pll_dump_hw_state(i915, b); + intel_cx0pll_dump_hw_state(display, b); } bool @@ -5431,7 +5702,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_INFOFRAME(avi); PIPE_CONF_CHECK_INFOFRAME(spd); PIPE_CONF_CHECK_INFOFRAME(hdmi); - PIPE_CONF_CHECK_INFOFRAME(drm); + if (!fastset) + PIPE_CONF_CHECK_INFOFRAME(drm); PIPE_CONF_CHECK_DP_VSC_SDP(vsc); PIPE_CONF_CHECK_DP_AS_SDP(as_sdp); @@ -6732,17 +7004,12 @@ int intel_atomic_check(struct drm_device *dev, static int intel_atomic_prepare_commit(struct intel_atomic_state *state) { - struct intel_crtc_state __maybe_unused *crtc_state; - struct intel_crtc *crtc; - int i, ret; + int ret; ret = drm_atomic_helper_prepare_planes(state->base.dev, &state->base); if (ret < 0) return ret; - for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) - intel_color_prepare_commit(state, crtc); - return 0; } @@ -6823,12 +7090,12 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state, * During modesets pipe configuration was programmed as the * CRTC was enabled. */ - if (!modeset) { + if (!modeset && !new_crtc_state->use_dsb) { if (intel_crtc_needs_color_update(new_crtc_state)) - intel_color_commit_arm(new_crtc_state); + intel_color_commit_arm(NULL, new_crtc_state); if (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv)) - bdw_set_pipe_misc(new_crtc_state); + bdw_set_pipe_misc(NULL, new_crtc_state); if (intel_crtc_needs_fastset(new_crtc_state)) intel_pipe_fastset(old_crtc_state, new_crtc_state); @@ -6925,10 +7192,12 @@ static void intel_pre_update_crtc(struct intel_atomic_state *state, drm_WARN_ON(&i915->drm, !intel_display_power_is_enabled(i915, POWER_DOMAIN_DC_OFF)); if (!modeset && - intel_crtc_needs_color_update(new_crtc_state)) - intel_color_commit_noarm(new_crtc_state); + intel_crtc_needs_color_update(new_crtc_state) && + !new_crtc_state->use_dsb) + intel_color_commit_noarm(NULL, new_crtc_state); - intel_crtc_planes_update_noarm(state, crtc); + if (!new_crtc_state->use_dsb) + intel_crtc_planes_update_noarm(NULL, state, crtc); } static void intel_update_crtc(struct intel_atomic_state *state, @@ -6939,16 +7208,25 @@ static void intel_update_crtc(struct intel_atomic_state *state, struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - /* Perform vblank evasion around commit operation */ - intel_pipe_update_start(state, crtc); + if (new_crtc_state->use_dsb) { + intel_crtc_prepare_vblank_event(new_crtc_state, &crtc->dsb_event); - commit_pipe_pre_planes(state, crtc); + intel_dsb_commit(new_crtc_state->dsb_commit, false); + } else { + /* Perform vblank evasion around commit operation */ + intel_pipe_update_start(state, crtc); - intel_crtc_planes_update_arm(state, crtc); + if (new_crtc_state->dsb_commit) + intel_dsb_commit(new_crtc_state->dsb_commit, false); - commit_pipe_post_planes(state, crtc); + commit_pipe_pre_planes(state, crtc); - intel_pipe_update_end(state, crtc); + intel_crtc_planes_update_arm(NULL, state, crtc); + + commit_pipe_post_planes(state, crtc); + + intel_pipe_update_end(state, crtc); + } /* * VRR/Seamless M/N update may need to update frame timings. @@ -7273,6 +7551,24 @@ static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_stat } } +static void intel_atomic_dsb_wait_commit(struct intel_crtc_state *crtc_state) +{ + if (crtc_state->dsb_commit) + intel_dsb_wait(crtc_state->dsb_commit); + + intel_color_wait_commit(crtc_state); +} + +static void intel_atomic_dsb_cleanup(struct intel_crtc_state *crtc_state) +{ + if (crtc_state->dsb_commit) { + intel_dsb_cleanup(crtc_state->dsb_commit); + crtc_state->dsb_commit = NULL; + } + + intel_color_cleanup_commit(crtc_state); +} + static void intel_atomic_cleanup_work(struct work_struct *work) { struct intel_atomic_state *state = @@ -7283,7 +7579,7 @@ static void intel_atomic_cleanup_work(struct work_struct *work) int i; for_each_old_intel_crtc_in_state(state, crtc, old_crtc_state, i) - intel_color_cleanup_commit(old_crtc_state); + intel_atomic_dsb_cleanup(old_crtc_state); drm_atomic_helper_cleanup_planes(&i915->drm, &state->base); drm_atomic_helper_commit_cleanup_done(&state->base); @@ -7324,15 +7620,93 @@ static void intel_atomic_prepare_plane_clear_colors(struct intel_atomic_state *s * caller made sure that the object is synced wrt. the related color clear value * GPU write on it. */ - ret = i915_gem_object_read_from_page(intel_fb_obj(fb), - fb->offsets[cc_plane] + 16, - &plane_state->ccval, - sizeof(plane_state->ccval)); + ret = intel_bo_read_from_page(intel_fb_bo(fb), + fb->offsets[cc_plane] + 16, + &plane_state->ccval, + sizeof(plane_state->ccval)); /* The above could only fail if the FB obj has an unexpected backing store type. */ drm_WARN_ON(&i915->drm, ret); } } +static void intel_atomic_dsb_prepare(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + intel_color_prepare_commit(state, crtc); +} + +static void intel_atomic_dsb_finish(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + + if (!new_crtc_state->hw.active) + return; + + if (state->base.legacy_cursor_update) + return; + + /* FIXME deal with everything */ + new_crtc_state->use_dsb = + new_crtc_state->update_planes && + !new_crtc_state->vrr.enable && + !new_crtc_state->do_async_flip && + !new_crtc_state->has_psr && + !new_crtc_state->scaler_state.scaler_users && + !old_crtc_state->scaler_state.scaler_users && + !intel_crtc_needs_modeset(new_crtc_state) && + !intel_crtc_needs_fastset(new_crtc_state); + + if (!new_crtc_state->use_dsb && !new_crtc_state->dsb_color_vblank) + return; + + /* + * Rough estimate: + * ~64 registers per each plane * 8 planes = 512 + * Double that for pipe stuff and other overhead. + */ + new_crtc_state->dsb_commit = intel_dsb_prepare(state, crtc, INTEL_DSB_0, + new_crtc_state->use_dsb ? 1024 : 16); + if (!new_crtc_state->dsb_commit) { + new_crtc_state->use_dsb = false; + intel_color_cleanup_commit(new_crtc_state); + return; + } + + if (new_crtc_state->use_dsb) { + if (intel_crtc_needs_color_update(new_crtc_state)) + intel_color_commit_noarm(new_crtc_state->dsb_commit, + new_crtc_state); + intel_crtc_planes_update_noarm(new_crtc_state->dsb_commit, + state, crtc); + + intel_dsb_vblank_evade(state, new_crtc_state->dsb_commit); + + if (intel_crtc_needs_color_update(new_crtc_state)) + intel_color_commit_arm(new_crtc_state->dsb_commit, + new_crtc_state); + bdw_set_pipe_misc(new_crtc_state->dsb_commit, + new_crtc_state); + intel_crtc_planes_update_arm(new_crtc_state->dsb_commit, + state, crtc); + + if (!new_crtc_state->dsb_color_vblank) { + intel_dsb_wait_vblanks(new_crtc_state->dsb_commit, 1); + intel_dsb_wait_vblank_delay(state, new_crtc_state->dsb_commit); + intel_dsb_interrupt(new_crtc_state->dsb_commit); + } + } + + if (new_crtc_state->dsb_color_vblank) + intel_dsb_chain(state, new_crtc_state->dsb_commit, + new_crtc_state->dsb_color_vblank, true); + + intel_dsb_finish(new_crtc_state->dsb_commit); +} + static void intel_atomic_commit_tail(struct intel_atomic_state *state) { struct drm_device *dev = state->base.dev; @@ -7340,13 +7714,21 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) struct intel_crtc_state *new_crtc_state, *old_crtc_state; struct intel_crtc *crtc; struct intel_power_domain_mask put_domains[I915_MAX_PIPES] = {}; - intel_wakeref_t wakeref = 0; + intel_wakeref_t wakeref = NULL; int i; + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) + intel_atomic_dsb_prepare(state, crtc); + intel_atomic_commit_fence_wait(state); intel_td_flush(dev_priv); + intel_atomic_prepare_plane_clear_colors(state); + + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) + intel_atomic_dsb_finish(state, crtc); + drm_atomic_helper_wait_for_dependencies(&state->base); drm_dp_mst_atomic_wait_for_dependencies(&state->base); intel_atomic_global_state_wait_for_dependencies(state); @@ -7380,8 +7762,6 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) */ wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_DC_OFF); - intel_atomic_prepare_plane_clear_colors(state); - for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { if (intel_crtc_needs_modeset(new_crtc_state) || @@ -7462,7 +7842,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) if (new_crtc_state->do_async_flip) intel_crtc_disable_flip_done(state, crtc); - intel_color_wait_commit(new_crtc_state); + intel_atomic_dsb_wait_commit(new_crtc_state); } /* @@ -7497,14 +7877,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_modeset_verify_crtc(state, crtc); - /* Must be done after gamma readout due to HSW split gamma vs. IPS w/a */ - hsw_ips_post_update(state, crtc); - - /* - * Activate DRRS after state readout to avoid - * dp_m_n vs. dp_m2_n2 confusion on BDW+. - */ - intel_drrs_activate(new_crtc_state); + intel_post_plane_update_after_readout(state, crtc); /* * DSB cleanup is done in cleanup_work aligning with framebuffer @@ -7514,7 +7887,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) * FIXME get rid of this funny new->old swapping */ old_crtc_state->dsb_color_vblank = fetch_and_zero(&new_crtc_state->dsb_color_vblank); - old_crtc_state->dsb_color_commit = fetch_and_zero(&new_crtc_state->dsb_color_commit); + old_crtc_state->dsb_commit = fetch_and_zero(&new_crtc_state->dsb_commit); } /* Underruns don't always raise interrupts, so check manually */ @@ -7661,13 +8034,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, ret = intel_atomic_swap_state(state); if (ret) { - struct intel_crtc_state *new_crtc_state; - struct intel_crtc *crtc; - int i; - - for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) - intel_color_cleanup_commit(new_crtc_state); - drm_atomic_helper_unprepare_planes(dev, &state->base); intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref); return ret; @@ -7702,23 +8068,6 @@ void intel_plane_destroy(struct drm_plane *plane) kfree(to_intel_plane(plane)); } -int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data; - struct drm_crtc *drmmode_crtc; - struct intel_crtc *crtc; - - drmmode_crtc = drm_crtc_find(dev, file, pipe_from_crtc_id->crtc_id); - if (!drmmode_crtc) - return -ENOENT; - - crtc = to_intel_crtc(drmmode_crtc); - pipe_from_crtc_id->pipe = crtc->pipe; - - return 0; -} - static u32 intel_encoder_possible_clones(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; @@ -7800,7 +8149,7 @@ void intel_setup_outputs(struct drm_i915_private *dev_priv) if (HAS_DDI(dev_priv)) { if (intel_ddi_crt_present(dev_priv)) - intel_crt_init(dev_priv); + intel_crt_init(display); intel_bios_for_each_encoder(display, intel_ddi_init); @@ -7815,7 +8164,7 @@ void intel_setup_outputs(struct drm_i915_private *dev_priv) * incorrect sharing of the PPS. */ intel_lvds_init(dev_priv); - intel_crt_init(dev_priv); + intel_crt_init(display); dpd_is_edp = intel_dp_is_port_edp(dev_priv, PORT_D); @@ -7846,7 +8195,7 @@ void intel_setup_outputs(struct drm_i915_private *dev_priv) bool has_edp, has_port; if (IS_VALLEYVIEW(dev_priv) && dev_priv->display.vbt.int_crt_support) - intel_crt_init(dev_priv); + intel_crt_init(display); /* * The DP_DETECTED bit is the latched state of the DDC @@ -7892,14 +8241,14 @@ void intel_setup_outputs(struct drm_i915_private *dev_priv) vlv_dsi_init(dev_priv); } else if (IS_PINEVIEW(dev_priv)) { intel_lvds_init(dev_priv); - intel_crt_init(dev_priv); + intel_crt_init(display); } else if (IS_DISPLAY_VER(dev_priv, 3, 4)) { bool found = false; if (IS_MOBILE(dev_priv)) intel_lvds_init(dev_priv); - intel_crt_init(dev_priv); + intel_crt_init(display); if (intel_de_read(dev_priv, GEN3_SDVOB) & SDVO_DETECTED) { drm_dbg_kms(&dev_priv->drm, "probing SDVOB\n"); @@ -7941,7 +8290,7 @@ void intel_setup_outputs(struct drm_i915_private *dev_priv) if (IS_I85X(dev_priv)) intel_lvds_init(dev_priv); - intel_crt_init(dev_priv); + intel_crt_init(display); intel_dvo_init(dev_priv); } @@ -7961,8 +8310,9 @@ static int max_dotclock(struct drm_i915_private *i915) { int max_dotclock = i915->display.cdclk.max_dotclk_freq; - /* icl+ might use joiner */ - if (DISPLAY_VER(i915) >= 11) + if (HAS_ULTRAJOINER(i915)) + max_dotclock *= 4; + else if (HAS_UNCOMPRESSED_JOINER(i915) || HAS_BIGJOINER(i915)) max_dotclock *= 2; return max_dotclock; @@ -8086,7 +8436,7 @@ enum drm_mode_status intel_cpu_transcoder_mode_valid(struct drm_i915_private *de enum drm_mode_status intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv, const struct drm_display_mode *mode, - bool joiner) + int num_joined_pipes) { int plane_width_max, plane_height_max; @@ -8102,8 +8452,11 @@ intel_mode_valid_max_plane_size(struct drm_i915_private *dev_priv, * plane so let's not advertize modes that are * too big for that. */ - if (DISPLAY_VER(dev_priv) >= 11) { - plane_width_max = 5120 << joiner; + if (DISPLAY_VER(dev_priv) >= 30) { + plane_width_max = 6144 * num_joined_pipes; + plane_height_max = 4800; + } else if (DISPLAY_VER(dev_priv) >= 11) { + plane_width_max = 5120 * num_joined_pipes; plane_height_max = 4320; } else { plane_width_max = 5120; @@ -8255,9 +8608,9 @@ out: return ret; } -void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) +void i830_enable_pipe(struct intel_display *display, enum pipe pipe) { - struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe); + struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe); enum transcoder cpu_transcoder = (enum transcoder)pipe; /* 640x480@60Hz, ~25175 kHz */ struct dpll clock = { @@ -8270,10 +8623,10 @@ void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) u32 dpll, fp; int i; - drm_WARN_ON(&dev_priv->drm, + drm_WARN_ON(display->drm, i9xx_calc_dpll_params(48000, &clock) != 25154); - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(display->drm, "enabling pipe %c due to force quirk (vco=%d dot=%d)\n", pipe_name(pipe), clock.vco, clock.dot); @@ -8285,35 +8638,35 @@ void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) PLL_REF_INPUT_DREFCLK | DPLL_VCO_ENABLE; - intel_de_write(dev_priv, TRANS_HTOTAL(dev_priv, cpu_transcoder), + intel_de_write(display, TRANS_HTOTAL(display, cpu_transcoder), HACTIVE(640 - 1) | HTOTAL(800 - 1)); - intel_de_write(dev_priv, TRANS_HBLANK(dev_priv, cpu_transcoder), + intel_de_write(display, TRANS_HBLANK(display, cpu_transcoder), HBLANK_START(640 - 1) | HBLANK_END(800 - 1)); - intel_de_write(dev_priv, TRANS_HSYNC(dev_priv, cpu_transcoder), + intel_de_write(display, TRANS_HSYNC(display, cpu_transcoder), HSYNC_START(656 - 1) | HSYNC_END(752 - 1)); - intel_de_write(dev_priv, TRANS_VTOTAL(dev_priv, cpu_transcoder), + intel_de_write(display, TRANS_VTOTAL(display, cpu_transcoder), VACTIVE(480 - 1) | VTOTAL(525 - 1)); - intel_de_write(dev_priv, TRANS_VBLANK(dev_priv, cpu_transcoder), + intel_de_write(display, TRANS_VBLANK(display, cpu_transcoder), VBLANK_START(480 - 1) | VBLANK_END(525 - 1)); - intel_de_write(dev_priv, TRANS_VSYNC(dev_priv, cpu_transcoder), + intel_de_write(display, TRANS_VSYNC(display, cpu_transcoder), VSYNC_START(490 - 1) | VSYNC_END(492 - 1)); - intel_de_write(dev_priv, PIPESRC(dev_priv, pipe), + intel_de_write(display, PIPESRC(display, pipe), PIPESRC_WIDTH(640 - 1) | PIPESRC_HEIGHT(480 - 1)); - intel_de_write(dev_priv, FP0(pipe), fp); - intel_de_write(dev_priv, FP1(pipe), fp); + intel_de_write(display, FP0(pipe), fp); + intel_de_write(display, FP1(pipe), fp); /* * Apparently we need to have VGA mode enabled prior to changing * the P1/P2 dividers. Otherwise the DPLL will keep using the old * dividers, even though the register value does change. */ - intel_de_write(dev_priv, DPLL(dev_priv, pipe), + intel_de_write(display, DPLL(display, pipe), dpll & ~DPLL_VGA_MODE_DIS); - intel_de_write(dev_priv, DPLL(dev_priv, pipe), dpll); + intel_de_write(display, DPLL(display, pipe), dpll); /* Wait for the clocks to stabilize. */ - intel_de_posting_read(dev_priv, DPLL(dev_priv, pipe)); + intel_de_posting_read(display, DPLL(display, pipe)); udelay(150); /* The pixel multiplier can only be updated once the @@ -8321,46 +8674,46 @@ void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) * * So write it again. */ - intel_de_write(dev_priv, DPLL(dev_priv, pipe), dpll); + intel_de_write(display, DPLL(display, pipe), dpll); /* We do this three times for luck */ for (i = 0; i < 3 ; i++) { - intel_de_write(dev_priv, DPLL(dev_priv, pipe), dpll); - intel_de_posting_read(dev_priv, DPLL(dev_priv, pipe)); + intel_de_write(display, DPLL(display, pipe), dpll); + intel_de_posting_read(display, DPLL(display, pipe)); udelay(150); /* wait for warmup */ } - intel_de_write(dev_priv, TRANSCONF(dev_priv, pipe), TRANSCONF_ENABLE); - intel_de_posting_read(dev_priv, TRANSCONF(dev_priv, pipe)); + intel_de_write(display, TRANSCONF(display, pipe), TRANSCONF_ENABLE); + intel_de_posting_read(display, TRANSCONF(display, pipe)); intel_wait_for_pipe_scanline_moving(crtc); } -void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) +void i830_disable_pipe(struct intel_display *display, enum pipe pipe) { - struct intel_crtc *crtc = intel_crtc_for_pipe(dev_priv, pipe); + struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe); - drm_dbg_kms(&dev_priv->drm, "disabling pipe %c due to force quirk\n", + drm_dbg_kms(display->drm, "disabling pipe %c due to force quirk\n", pipe_name(pipe)); - drm_WARN_ON(&dev_priv->drm, - intel_de_read(dev_priv, DSPCNTR(dev_priv, PLANE_A)) & DISP_ENABLE); - drm_WARN_ON(&dev_priv->drm, - intel_de_read(dev_priv, DSPCNTR(dev_priv, PLANE_B)) & DISP_ENABLE); - drm_WARN_ON(&dev_priv->drm, - intel_de_read(dev_priv, DSPCNTR(dev_priv, PLANE_C)) & DISP_ENABLE); - drm_WARN_ON(&dev_priv->drm, - intel_de_read(dev_priv, CURCNTR(dev_priv, PIPE_A)) & MCURSOR_MODE_MASK); - drm_WARN_ON(&dev_priv->drm, - intel_de_read(dev_priv, CURCNTR(dev_priv, PIPE_B)) & MCURSOR_MODE_MASK); + drm_WARN_ON(display->drm, + intel_de_read(display, DSPCNTR(display, PLANE_A)) & DISP_ENABLE); + drm_WARN_ON(display->drm, + intel_de_read(display, DSPCNTR(display, PLANE_B)) & DISP_ENABLE); + drm_WARN_ON(display->drm, + intel_de_read(display, DSPCNTR(display, PLANE_C)) & DISP_ENABLE); + drm_WARN_ON(display->drm, + intel_de_read(display, CURCNTR(display, PIPE_A)) & MCURSOR_MODE_MASK); + drm_WARN_ON(display->drm, + intel_de_read(display, CURCNTR(display, PIPE_B)) & MCURSOR_MODE_MASK); - intel_de_write(dev_priv, TRANSCONF(dev_priv, pipe), 0); - intel_de_posting_read(dev_priv, TRANSCONF(dev_priv, pipe)); + intel_de_write(display, TRANSCONF(display, pipe), 0); + intel_de_posting_read(display, TRANSCONF(display, pipe)); intel_wait_for_pipe_scanline_stopped(crtc); - intel_de_write(dev_priv, DPLL(dev_priv, pipe), DPLL_VGA_MODE_DIS); - intel_de_posting_read(dev_priv, DPLL(dev_priv, pipe)); + intel_de_write(display, DPLL(display, pipe), DPLL_VGA_MODE_DIS); + intel_de_posting_read(display, DPLL(display, pipe)); } void intel_hpd_poll_fini(struct drm_i915_private *i915) |