drm/i915/display: split out hw state readout and sanitize
authorJani Nikula <jani.nikula@intel.com>
Fri, 17 Jun 2022 09:48:16 +0000 (12:48 +0300)
committerJani Nikula <jani.nikula@intel.com>
Mon, 20 Jun 2022 16:28:42 +0000 (19:28 +0300)
Split out the modeset hardware state readout and sanitize, or state
setup, to a separate file.

Do some drive-by checkpatch fixes while at it.

v2: Rebase

Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220617094817.3466584-1-jani.nikula@intel.com
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_display.h
drivers/gpu/drm/i915/display/intel_modeset_setup.c [new file with mode: 0644]
drivers/gpu/drm/i915/display/intel_modeset_setup.h [new file with mode: 0644]

index ea25322..f95c69b 100644 (file)
@@ -234,6 +234,7 @@ i915-y += \
        display/intel_hotplug.o \
        display/intel_lpe_audio.o \
        display/intel_modeset_verify.o \
+       display/intel_modeset_setup.o \
        display/intel_overlay.o \
        display/intel_pch_display.o \
        display/intel_pch_refclk.o \
index 4a37992..712f7c9 100644 (file)
 #include "intel_hdcp.h"
 #include "intel_hotplug.h"
 #include "intel_modeset_verify.h"
+#include "intel_modeset_setup.h"
 #include "intel_overlay.h"
 #include "intel_panel.h"
 #include "intel_pch_display.h"
@@ -130,8 +131,6 @@ static void ilk_set_pipeconf(const struct intel_crtc_state *crtc_state);
 static void hsw_set_transconf(const struct intel_crtc_state *crtc_state);
 static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state);
 static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state);
-static void intel_modeset_setup_hw_state(struct drm_device *dev,
-                                        struct drm_modeset_acquire_ctx *ctx);
 
 /**
  * intel_update_watermarks - update FIFO watermark values based on current modes
@@ -166,7 +165,7 @@ static void intel_modeset_setup_hw_state(struct drm_device *dev,
  * We don't use the sprite, so we can ignore that.  And on Crestline we have
  * to set the non-SR watermarks to 8.
  */
-static void intel_update_watermarks(struct drm_i915_private *dev_priv)
+void intel_update_watermarks(struct drm_i915_private *dev_priv)
 {
        if (dev_priv->wm_disp->update_wm)
                dev_priv->wm_disp->update_wm(dev_priv);
@@ -733,10 +732,9 @@ u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
                                 DRM_MODE_ROTATE_0);
 }
 
-static void
-intel_set_plane_visible(struct intel_crtc_state *crtc_state,
-                       struct intel_plane_state *plane_state,
-                       bool visible)
+void intel_set_plane_visible(struct intel_crtc_state *crtc_state,
+                            struct intel_plane_state *plane_state,
+                            bool visible)
 {
        struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
 
@@ -748,7 +746,7 @@ intel_set_plane_visible(struct intel_crtc_state *crtc_state,
                crtc_state->uapi.plane_mask &= ~drm_plane_mask(&plane->base);
 }
 
-static void fixup_plane_bitmasks(struct intel_crtc_state *crtc_state)
+void intel_plane_fixup_bitmasks(struct intel_crtc_state *crtc_state)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
        struct drm_plane *plane;
@@ -783,7 +781,7 @@ void intel_plane_disable_noatomic(struct intel_crtc *crtc,
                    crtc->base.base.id, crtc->base.name);
 
        intel_set_plane_visible(crtc_state, plane_state, false);
-       fixup_plane_bitmasks(crtc_state);
+       intel_plane_fixup_bitmasks(crtc_state);
        crtc_state->data_rate[plane->id] = 0;
        crtc_state->data_rate_y[plane->id] = 0;
        crtc_state->rel_data_rate[plane->id] = 0;
@@ -2209,9 +2207,8 @@ static void get_crtc_power_domains(struct intel_crtc_state *crtc_state,
                set_bit(intel_dsc_power_domain(crtc, cpu_transcoder), mask->bits);
 }
 
-static void
-modeset_get_crtc_power_domains(struct intel_crtc_state *crtc_state,
-                              struct intel_power_domain_mask *old_domains)
+void intel_modeset_get_crtc_power_domains(struct intel_crtc_state *crtc_state,
+                                         struct intel_power_domain_mask *old_domains)
 {
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@@ -2235,8 +2232,8 @@ modeset_get_crtc_power_domains(struct intel_crtc_state *crtc_state,
                                               domain);
 }
 
-static void modeset_put_crtc_power_domains(struct intel_crtc *crtc,
-                                          struct intel_power_domain_mask *domains)
+void intel_modeset_put_crtc_power_domains(struct intel_crtc *crtc,
+                                         struct intel_power_domain_mask *domains)
 {
        intel_display_power_put_mask_in_set(to_i915(crtc->base.dev),
                                            &crtc->enabled_power_domains,
@@ -2416,89 +2413,6 @@ static void i9xx_crtc_disable(struct intel_atomic_state *state,
                i830_enable_pipe(dev_priv, pipe);
 }
 
-static void intel_crtc_disable_noatomic(struct intel_crtc *crtc,
-                                       struct drm_modeset_acquire_ctx *ctx)
-{
-       struct intel_encoder *encoder;
-       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-       struct intel_bw_state *bw_state =
-               to_intel_bw_state(dev_priv->bw_obj.state);
-       struct intel_cdclk_state *cdclk_state =
-               to_intel_cdclk_state(dev_priv->cdclk.obj.state);
-       struct intel_dbuf_state *dbuf_state =
-               to_intel_dbuf_state(dev_priv->dbuf.obj.state);
-       struct intel_crtc_state *crtc_state =
-               to_intel_crtc_state(crtc->base.state);
-       struct intel_plane *plane;
-       struct drm_atomic_state *state;
-       struct intel_crtc_state *temp_crtc_state;
-       enum pipe pipe = crtc->pipe;
-       int ret;
-
-       if (!crtc_state->hw.active)
-               return;
-
-       for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
-               const struct intel_plane_state *plane_state =
-                       to_intel_plane_state(plane->base.state);
-
-               if (plane_state->uapi.visible)
-                       intel_plane_disable_noatomic(crtc, plane);
-       }
-
-       state = drm_atomic_state_alloc(&dev_priv->drm);
-       if (!state) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "failed to disable [CRTC:%d:%s], out of memory",
-                           crtc->base.base.id, crtc->base.name);
-               return;
-       }
-
-       state->acquire_ctx = ctx;
-
-       /* Everything's already locked, -EDEADLK can't happen. */
-       temp_crtc_state = intel_atomic_get_crtc_state(state, crtc);
-       ret = drm_atomic_add_affected_connectors(state, &crtc->base);
-
-       drm_WARN_ON(&dev_priv->drm, IS_ERR(temp_crtc_state) || ret);
-
-       dev_priv->display->crtc_disable(to_intel_atomic_state(state), crtc);
-
-       drm_atomic_state_put(state);
-
-       drm_dbg_kms(&dev_priv->drm,
-                   "[CRTC:%d:%s] hw state adjusted, was enabled, now disabled\n",
-                   crtc->base.base.id, crtc->base.name);
-
-       crtc->active = false;
-       crtc->base.enabled = false;
-
-       drm_WARN_ON(&dev_priv->drm,
-                   drm_atomic_set_mode_for_crtc(&crtc_state->uapi, NULL) < 0);
-       crtc_state->uapi.active = false;
-       crtc_state->uapi.connector_mask = 0;
-       crtc_state->uapi.encoder_mask = 0;
-       intel_crtc_free_hw_state(crtc_state);
-       memset(&crtc_state->hw, 0, sizeof(crtc_state->hw));
-
-       for_each_encoder_on_crtc(&dev_priv->drm, &crtc->base, encoder)
-               encoder->base.crtc = NULL;
-
-       intel_fbc_disable(crtc);
-       intel_update_watermarks(dev_priv);
-       intel_disable_shared_dpll(crtc_state);
-
-       intel_display_power_put_all_in_set(dev_priv, &crtc->enabled_power_domains);
-
-       cdclk_state->min_cdclk[pipe] = 0;
-       cdclk_state->min_voltage_level[pipe] = 0;
-       cdclk_state->active_pipes &= ~BIT(pipe);
-
-       dbuf_state->active_pipes &= ~BIT(pipe);
-
-       bw_state->data_rate[pipe] = 0;
-       bw_state->num_active_planes[pipe] = 0;
-}
 
 /*
  * turn all crtc's off, but do not adjust state
@@ -4948,39 +4862,6 @@ static int intel_crtc_atomic_check(struct intel_atomic_state *state,
        return 0;
 }
 
-static void intel_modeset_update_connector_atomic_state(struct drm_device *dev)
-{
-       struct intel_connector *connector;
-       struct drm_connector_list_iter conn_iter;
-
-       drm_connector_list_iter_begin(dev, &conn_iter);
-       for_each_intel_connector_iter(connector, &conn_iter) {
-               struct drm_connector_state *conn_state = connector->base.state;
-               struct intel_encoder *encoder =
-                       to_intel_encoder(connector->base.encoder);
-
-               if (conn_state->crtc)
-                       drm_connector_put(&connector->base);
-
-               if (encoder) {
-                       struct intel_crtc *crtc =
-                               to_intel_crtc(encoder->base.crtc);
-                       const struct intel_crtc_state *crtc_state =
-                               to_intel_crtc_state(crtc->base.state);
-
-                       conn_state->best_encoder = &encoder->base;
-                       conn_state->crtc = &crtc->base;
-                       conn_state->max_bpc = (crtc_state->pipe_bpp ?: 24) / 3;
-
-                       drm_connector_get(&connector->base);
-               } else {
-                       conn_state->best_encoder = NULL;
-                       conn_state->crtc = NULL;
-               }
-       }
-       drm_connector_list_iter_end(&conn_iter);
-}
-
 static int
 compute_sink_pipe_bpp(const struct drm_connector_state *conn_state,
                      struct intel_crtc_state *crtc_state)
@@ -5165,27 +5046,6 @@ intel_crtc_copy_uapi_to_hw_state_modeset(struct intel_atomic_state *state,
        intel_crtc_copy_uapi_to_hw_state_nomodeset(state, crtc);
 }
 
-static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state)
-{
-       if (intel_crtc_is_bigjoiner_slave(crtc_state))
-               return;
-
-       crtc_state->uapi.enable = crtc_state->hw.enable;
-       crtc_state->uapi.active = crtc_state->hw.active;
-       drm_WARN_ON(crtc_state->uapi.crtc->dev,
-                   drm_atomic_set_mode_for_crtc(&crtc_state->uapi, &crtc_state->hw.mode) < 0);
-
-       crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode;
-       crtc_state->uapi.scaling_filter = crtc_state->hw.scaling_filter;
-
-       drm_property_replace_blob(&crtc_state->uapi.degamma_lut,
-                                 crtc_state->hw.degamma_lut);
-       drm_property_replace_blob(&crtc_state->uapi.gamma_lut,
-                                 crtc_state->hw.gamma_lut);
-       drm_property_replace_blob(&crtc_state->uapi.ctm,
-                                 crtc_state->hw.ctm);
-}
-
 static void
 copy_bigjoiner_crtc_state_nomodeset(struct intel_atomic_state *state,
                                    struct intel_crtc *slave_crtc)
@@ -6115,8 +5975,7 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state)
        return 0;
 }
 
-static void
-intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state)
+void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state)
 {
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
@@ -7670,7 +7529,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
                                            new_crtc_state, i) {
                if (intel_crtc_needs_modeset(new_crtc_state) ||
                    new_crtc_state->update_pipe) {
-                       modeset_get_crtc_power_domains(new_crtc_state, &put_domains[crtc->pipe]);
+                       intel_modeset_get_crtc_power_domains(new_crtc_state, &put_domains[crtc->pipe]);
                }
        }
 
@@ -7770,7 +7629,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
        for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
                intel_post_plane_update(state, crtc);
 
-               modeset_put_crtc_power_domains(crtc, &put_domains[crtc->pipe]);
+               intel_modeset_put_crtc_power_domains(crtc, &put_domains[crtc->pipe]);
 
                intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
 
@@ -9060,576 +8919,6 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
        intel_de_posting_read(dev_priv, DPLL(pipe));
 }
 
-static void
-intel_sanitize_plane_mapping(struct drm_i915_private *dev_priv)
-{
-       struct intel_crtc *crtc;
-
-       if (DISPLAY_VER(dev_priv) >= 4)
-               return;
-
-       for_each_intel_crtc(&dev_priv->drm, crtc) {
-               struct intel_plane *plane =
-                       to_intel_plane(crtc->base.primary);
-               struct intel_crtc *plane_crtc;
-               enum pipe pipe;
-
-               if (!plane->get_hw_state(plane, &pipe))
-                       continue;
-
-               if (pipe == crtc->pipe)
-                       continue;
-
-               drm_dbg_kms(&dev_priv->drm,
-                           "[PLANE:%d:%s] attached to the wrong pipe, disabling plane\n",
-                           plane->base.base.id, plane->base.name);
-
-               plane_crtc = intel_crtc_for_pipe(dev_priv, pipe);
-               intel_plane_disable_noatomic(plane_crtc, plane);
-       }
-}
-
-static bool intel_crtc_has_encoders(struct intel_crtc *crtc)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct intel_encoder *encoder;
-
-       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
-               return true;
-
-       return false;
-}
-
-static struct intel_connector *intel_encoder_find_connector(struct intel_encoder *encoder)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct intel_connector *connector;
-
-       for_each_connector_on_encoder(dev, &encoder->base, connector)
-               return connector;
-
-       return NULL;
-}
-
-static void intel_sanitize_fifo_underrun_reporting(const 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);
-
-       if (!crtc_state->hw.active && !HAS_GMCH(i915))
-               return;
-
-       /*
-        * We start out with underrun reporting disabled to avoid races.
-        * For correct bookkeeping mark this on active crtcs.
-        *
-        * Also on gmch platforms we dont have any hardware bits to
-        * disable the underrun reporting. Which means we need to start
-        * out with underrun reporting disabled also on inactive pipes,
-        * since otherwise we'll complain about the garbage we read when
-        * e.g. coming up after runtime pm.
-        *
-        * No protection against concurrent access is required - at
-        * worst a fifo underrun happens which also sets this to false.
-        */
-       crtc->cpu_fifo_underrun_disabled = true;
-
-       /*
-        * We track the PCH trancoder underrun reporting state
-        * within the crtc. With crtc for pipe A housing the underrun
-        * reporting state for PCH transcoder A, crtc for pipe B housing
-        * it for PCH transcoder B, etc. LPT-H has only PCH transcoder A,
-        * and marking underrun reporting as disabled for the non-existing
-        * PCH transcoders B and C would prevent enabling the south
-        * error interrupt (see cpt_can_enable_serr_int()).
-        */
-       if (intel_has_pch_trancoder(i915, crtc->pipe))
-               crtc->pch_fifo_underrun_disabled = true;
-}
-
-static void intel_sanitize_crtc(struct intel_crtc *crtc,
-                               struct drm_modeset_acquire_ctx *ctx)
-{
-       struct drm_device *dev = crtc->base.dev;
-       struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
-
-       if (crtc_state->hw.active) {
-               struct intel_plane *plane;
-
-               /* Disable everything but the primary plane */
-               for_each_intel_plane_on_crtc(dev, crtc, plane) {
-                       const struct intel_plane_state *plane_state =
-                               to_intel_plane_state(plane->base.state);
-
-                       if (plane_state->uapi.visible &&
-                           plane->base.type != DRM_PLANE_TYPE_PRIMARY)
-                               intel_plane_disable_noatomic(crtc, plane);
-               }
-
-               /* Disable any background color/etc. set by the BIOS */
-               intel_color_commit_noarm(crtc_state);
-               intel_color_commit_arm(crtc_state);
-       }
-
-       /* Adjust the state of the output pipe according to whether we
-        * have active connectors/encoders. */
-       if (crtc_state->hw.active && !intel_crtc_has_encoders(crtc) &&
-           !intel_crtc_is_bigjoiner_slave(crtc_state))
-               intel_crtc_disable_noatomic(crtc, ctx);
-}
-
-static bool has_bogus_dpll_config(const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
-
-       /*
-        * Some SNB BIOSen (eg. ASUS K53SV) are known to misprogram
-        * the hardware when a high res displays plugged in. DPLL P
-        * divider is zero, and the pipe timings are bonkers. We'll
-        * try to disable everything in that case.
-        *
-        * FIXME would be nice to be able to sanitize this state
-        * without several WARNs, but for now let's take the easy
-        * road.
-        */
-       return IS_SANDYBRIDGE(dev_priv) &&
-               crtc_state->hw.active &&
-               crtc_state->shared_dpll &&
-               crtc_state->port_clock == 0;
-}
-
-static void intel_sanitize_encoder(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_connector *connector;
-       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       struct intel_crtc_state *crtc_state = crtc ?
-               to_intel_crtc_state(crtc->base.state) : NULL;
-
-       /* We need to check both for a crtc link (meaning that the
-        * encoder is active and trying to read from a pipe) and the
-        * pipe itself being active. */
-       bool has_active_crtc = crtc_state &&
-               crtc_state->hw.active;
-
-       if (crtc_state && has_bogus_dpll_config(crtc_state)) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "BIOS has misprogrammed the hardware. Disabling pipe %c\n",
-                           pipe_name(crtc->pipe));
-               has_active_crtc = false;
-       }
-
-       connector = intel_encoder_find_connector(encoder);
-       if (connector && !has_active_crtc) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "[ENCODER:%d:%s] has active connectors but no active pipe!\n",
-                           encoder->base.base.id,
-                           encoder->base.name);
-
-               /* Connector is active, but has no active pipe. This is
-                * fallout from our resume register restoring. Disable
-                * the encoder manually again. */
-               if (crtc_state) {
-                       struct drm_encoder *best_encoder;
-
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "[ENCODER:%d:%s] manually disabled\n",
-                                   encoder->base.base.id,
-                                   encoder->base.name);
-
-                       /* avoid oopsing in case the hooks consult best_encoder */
-                       best_encoder = connector->base.state->best_encoder;
-                       connector->base.state->best_encoder = &encoder->base;
-
-                       /* FIXME NULL atomic state passed! */
-                       if (encoder->disable)
-                               encoder->disable(NULL, encoder, crtc_state,
-                                                connector->base.state);
-                       if (encoder->post_disable)
-                               encoder->post_disable(NULL, encoder, crtc_state,
-                                                     connector->base.state);
-
-                       connector->base.state->best_encoder = best_encoder;
-               }
-               encoder->base.crtc = NULL;
-
-               /* Inconsistent output/port/pipe state happens presumably due to
-                * a bug in one of the get_hw_state functions. Or someplace else
-                * in our code, like the register restore mess on resume. Clamp
-                * things to off as a safer default. */
-
-               connector->base.dpms = DRM_MODE_DPMS_OFF;
-               connector->base.encoder = NULL;
-       }
-
-       /* notify opregion of the sanitized encoder state */
-       intel_opregion_notify_encoder(encoder, connector && has_active_crtc);
-
-       if (HAS_DDI(dev_priv))
-               intel_ddi_sanitize_encoder_pll_mapping(encoder);
-}
-
-/* FIXME read out full plane state for all planes */
-static void readout_plane_state(struct drm_i915_private *dev_priv)
-{
-       struct intel_plane *plane;
-       struct intel_crtc *crtc;
-
-       for_each_intel_plane(&dev_priv->drm, plane) {
-               struct intel_plane_state *plane_state =
-                       to_intel_plane_state(plane->base.state);
-               struct intel_crtc_state *crtc_state;
-               enum pipe pipe = PIPE_A;
-               bool visible;
-
-               visible = plane->get_hw_state(plane, &pipe);
-
-               crtc = intel_crtc_for_pipe(dev_priv, pipe);
-               crtc_state = to_intel_crtc_state(crtc->base.state);
-
-               intel_set_plane_visible(crtc_state, plane_state, visible);
-
-               drm_dbg_kms(&dev_priv->drm,
-                           "[PLANE:%d:%s] hw state readout: %s, pipe %c\n",
-                           plane->base.base.id, plane->base.name,
-                           str_enabled_disabled(visible), pipe_name(pipe));
-       }
-
-       for_each_intel_crtc(&dev_priv->drm, crtc) {
-               struct intel_crtc_state *crtc_state =
-                       to_intel_crtc_state(crtc->base.state);
-
-               fixup_plane_bitmasks(crtc_state);
-       }
-}
-
-static void intel_modeset_readout_hw_state(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_cdclk_state *cdclk_state =
-               to_intel_cdclk_state(dev_priv->cdclk.obj.state);
-       struct intel_dbuf_state *dbuf_state =
-               to_intel_dbuf_state(dev_priv->dbuf.obj.state);
-       enum pipe pipe;
-       struct intel_crtc *crtc;
-       struct intel_encoder *encoder;
-       struct intel_connector *connector;
-       struct drm_connector_list_iter conn_iter;
-       u8 active_pipes = 0;
-
-       for_each_intel_crtc(dev, crtc) {
-               struct intel_crtc_state *crtc_state =
-                       to_intel_crtc_state(crtc->base.state);
-
-               __drm_atomic_helper_crtc_destroy_state(&crtc_state->uapi);
-               intel_crtc_free_hw_state(crtc_state);
-               intel_crtc_state_reset(crtc_state, crtc);
-
-               intel_crtc_get_pipe_config(crtc_state);
-
-               crtc_state->hw.enable = crtc_state->hw.active;
-
-               crtc->base.enabled = crtc_state->hw.enable;
-               crtc->active = crtc_state->hw.active;
-
-               if (crtc_state->hw.active)
-                       active_pipes |= BIT(crtc->pipe);
-
-               drm_dbg_kms(&dev_priv->drm,
-                           "[CRTC:%d:%s] hw state readout: %s\n",
-                           crtc->base.base.id, crtc->base.name,
-                           str_enabled_disabled(crtc_state->hw.active));
-       }
-
-       cdclk_state->active_pipes = dbuf_state->active_pipes = active_pipes;
-
-       readout_plane_state(dev_priv);
-
-       for_each_intel_encoder(dev, encoder) {
-               struct intel_crtc_state *crtc_state = NULL;
-
-               pipe = 0;
-
-               if (encoder->get_hw_state(encoder, &pipe)) {
-                       crtc = intel_crtc_for_pipe(dev_priv, pipe);
-                       crtc_state = to_intel_crtc_state(crtc->base.state);
-
-                       encoder->base.crtc = &crtc->base;
-                       intel_encoder_get_config(encoder, crtc_state);
-
-                       /* read out to slave crtc as well for bigjoiner */
-                       if (crtc_state->bigjoiner_pipes) {
-                               struct intel_crtc *slave_crtc;
-
-                               /* encoder should read be linked to bigjoiner master */
-                               WARN_ON(intel_crtc_is_bigjoiner_slave(crtc_state));
-
-                               for_each_intel_crtc_in_pipe_mask(&dev_priv->drm, slave_crtc,
-                                                                intel_crtc_bigjoiner_slave_pipes(crtc_state)) {
-                                       struct intel_crtc_state *slave_crtc_state;
-
-                                       slave_crtc_state = to_intel_crtc_state(slave_crtc->base.state);
-                                       intel_encoder_get_config(encoder, slave_crtc_state);
-                               }
-                       }
-               } else {
-                       encoder->base.crtc = NULL;
-               }
-
-               if (encoder->sync_state)
-                       encoder->sync_state(encoder, crtc_state);
-
-               drm_dbg_kms(&dev_priv->drm,
-                           "[ENCODER:%d:%s] hw state readout: %s, pipe %c\n",
-                           encoder->base.base.id, encoder->base.name,
-                           str_enabled_disabled(encoder->base.crtc),
-                           pipe_name(pipe));
-       }
-
-       intel_dpll_readout_hw_state(dev_priv);
-
-       drm_connector_list_iter_begin(dev, &conn_iter);
-       for_each_intel_connector_iter(connector, &conn_iter) {
-               if (connector->get_hw_state(connector)) {
-                       struct intel_crtc_state *crtc_state;
-                       struct intel_crtc *crtc;
-
-                       connector->base.dpms = DRM_MODE_DPMS_ON;
-
-                       encoder = intel_attached_encoder(connector);
-                       connector->base.encoder = &encoder->base;
-
-                       crtc = to_intel_crtc(encoder->base.crtc);
-                       crtc_state = crtc ? to_intel_crtc_state(crtc->base.state) : NULL;
-
-                       if (crtc_state && crtc_state->hw.active) {
-                               /*
-                                * This has to be done during hardware readout
-                                * because anything calling .crtc_disable may
-                                * rely on the connector_mask being accurate.
-                                */
-                               crtc_state->uapi.connector_mask |=
-                                       drm_connector_mask(&connector->base);
-                               crtc_state->uapi.encoder_mask |=
-                                       drm_encoder_mask(&encoder->base);
-                       }
-               } else {
-                       connector->base.dpms = DRM_MODE_DPMS_OFF;
-                       connector->base.encoder = NULL;
-               }
-               drm_dbg_kms(&dev_priv->drm,
-                           "[CONNECTOR:%d:%s] hw state readout: %s\n",
-                           connector->base.base.id, connector->base.name,
-                           str_enabled_disabled(connector->base.encoder));
-       }
-       drm_connector_list_iter_end(&conn_iter);
-
-       for_each_intel_crtc(dev, crtc) {
-               struct intel_bw_state *bw_state =
-                       to_intel_bw_state(dev_priv->bw_obj.state);
-               struct intel_crtc_state *crtc_state =
-                       to_intel_crtc_state(crtc->base.state);
-               struct intel_plane *plane;
-               int min_cdclk = 0;
-
-               if (crtc_state->hw.active) {
-                       /*
-                        * The initial mode needs to be set in order to keep
-                        * the atomic core happy. It wants a valid mode if the
-                        * crtc's enabled, so we do the above call.
-                        *
-                        * But we don't set all the derived state fully, hence
-                        * set a flag to indicate that a full recalculation is
-                        * needed on the next commit.
-                        */
-                       crtc_state->inherited = true;
-
-                       intel_crtc_update_active_timings(crtc_state);
-
-                       intel_crtc_copy_hw_to_uapi_state(crtc_state);
-               }
-
-               for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
-                       const struct intel_plane_state *plane_state =
-                               to_intel_plane_state(plane->base.state);
-
-                       /*
-                        * FIXME don't have the fb yet, so can't
-                        * use intel_plane_data_rate() :(
-                        */
-                       if (plane_state->uapi.visible)
-                               crtc_state->data_rate[plane->id] =
-                                       4 * crtc_state->pixel_rate;
-                       /*
-                        * FIXME don't have the fb yet, so can't
-                        * use plane->min_cdclk() :(
-                        */
-                       if (plane_state->uapi.visible && plane->min_cdclk) {
-                               if (crtc_state->double_wide || DISPLAY_VER(dev_priv) >= 10)
-                                       crtc_state->min_cdclk[plane->id] =
-                                               DIV_ROUND_UP(crtc_state->pixel_rate, 2);
-                               else
-                                       crtc_state->min_cdclk[plane->id] =
-                                               crtc_state->pixel_rate;
-                       }
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "[PLANE:%d:%s] min_cdclk %d kHz\n",
-                                   plane->base.base.id, plane->base.name,
-                                   crtc_state->min_cdclk[plane->id]);
-               }
-
-               if (crtc_state->hw.active) {
-                       min_cdclk = intel_crtc_compute_min_cdclk(crtc_state);
-                       if (drm_WARN_ON(dev, min_cdclk < 0))
-                               min_cdclk = 0;
-               }
-
-               cdclk_state->min_cdclk[crtc->pipe] = min_cdclk;
-               cdclk_state->min_voltage_level[crtc->pipe] =
-                       crtc_state->min_voltage_level;
-
-               intel_bw_crtc_update(bw_state, crtc_state);
-       }
-}
-
-static void
-get_encoder_power_domains(struct drm_i915_private *dev_priv)
-{
-       struct intel_encoder *encoder;
-
-       for_each_intel_encoder(&dev_priv->drm, encoder) {
-               struct intel_crtc_state *crtc_state;
-
-               if (!encoder->get_power_domains)
-                       continue;
-
-               /*
-                * MST-primary and inactive encoders don't have a crtc state
-                * and neither of these require any power domain references.
-                */
-               if (!encoder->base.crtc)
-                       continue;
-
-               crtc_state = to_intel_crtc_state(encoder->base.crtc->state);
-               encoder->get_power_domains(encoder, crtc_state);
-       }
-}
-
-static void intel_early_display_was(struct drm_i915_private *dev_priv)
-{
-       /*
-        * Display WA #1185 WaDisableDARBFClkGating:glk,icl,ehl,tgl
-        * Also known as Wa_14010480278.
-        */
-       if (IS_DISPLAY_VER(dev_priv, 10, 12))
-               intel_de_write(dev_priv, GEN9_CLKGATE_DIS_0,
-                              intel_de_read(dev_priv, GEN9_CLKGATE_DIS_0) | DARBF_GATING_DIS);
-
-       if (IS_HASWELL(dev_priv)) {
-               /*
-                * WaRsPkgCStateDisplayPMReq:hsw
-                * System hang if this isn't done before disabling all planes!
-                */
-               intel_de_write(dev_priv, CHICKEN_PAR1_1,
-                              intel_de_read(dev_priv, CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES);
-       }
-
-       if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv) || IS_COMETLAKE(dev_priv)) {
-               /* Display WA #1142:kbl,cfl,cml */
-               intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
-                            KBL_ARB_FILL_SPARE_22, KBL_ARB_FILL_SPARE_22);
-               intel_de_rmw(dev_priv, CHICKEN_MISC_2,
-                            KBL_ARB_FILL_SPARE_13 | KBL_ARB_FILL_SPARE_14,
-                            KBL_ARB_FILL_SPARE_14);
-       }
-}
-
-
-/* Scan out the current hw modeset state,
- * and sanitizes it to the current state
- */
-static void
-intel_modeset_setup_hw_state(struct drm_device *dev,
-                            struct drm_modeset_acquire_ctx *ctx)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_encoder *encoder;
-       struct intel_crtc *crtc;
-       intel_wakeref_t wakeref;
-
-       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
-
-       intel_early_display_was(dev_priv);
-       intel_modeset_readout_hw_state(dev);
-
-       /* HW state is read out, now we need to sanitize this mess. */
-       get_encoder_power_domains(dev_priv);
-
-       intel_pch_sanitize(dev_priv);
-
-       /*
-        * intel_sanitize_plane_mapping() may need to do vblank
-        * waits, so we need vblank interrupts restored beforehand.
-        */
-       for_each_intel_crtc(&dev_priv->drm, crtc) {
-               struct intel_crtc_state *crtc_state =
-                       to_intel_crtc_state(crtc->base.state);
-
-               intel_sanitize_fifo_underrun_reporting(crtc_state);
-
-               drm_crtc_vblank_reset(&crtc->base);
-
-               if (crtc_state->hw.active)
-                       intel_crtc_vblank_on(crtc_state);
-       }
-
-       intel_fbc_sanitize(dev_priv);
-
-       intel_sanitize_plane_mapping(dev_priv);
-
-       for_each_intel_encoder(dev, encoder)
-               intel_sanitize_encoder(encoder);
-
-       for_each_intel_crtc(&dev_priv->drm, crtc) {
-               struct intel_crtc_state *crtc_state =
-                       to_intel_crtc_state(crtc->base.state);
-
-               intel_sanitize_crtc(crtc, ctx);
-               intel_crtc_state_dump(crtc_state, NULL, "setup_hw_state");
-       }
-
-       intel_modeset_update_connector_atomic_state(dev);
-
-       intel_dpll_sanitize_state(dev_priv);
-
-       if (IS_G4X(dev_priv)) {
-               g4x_wm_get_hw_state(dev_priv);
-               g4x_wm_sanitize(dev_priv);
-       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               vlv_wm_get_hw_state(dev_priv);
-               vlv_wm_sanitize(dev_priv);
-       } else if (DISPLAY_VER(dev_priv) >= 9) {
-               skl_wm_get_hw_state(dev_priv);
-               skl_wm_sanitize(dev_priv);
-       } else if (HAS_PCH_SPLIT(dev_priv)) {
-               ilk_wm_get_hw_state(dev_priv);
-       }
-
-       for_each_intel_crtc(dev, crtc) {
-               struct intel_crtc_state *crtc_state =
-                       to_intel_crtc_state(crtc->base.state);
-               struct intel_power_domain_mask put_domains;
-
-               modeset_get_crtc_power_domains(crtc_state, &put_domains);
-               if (drm_WARN_ON(dev, !bitmap_empty(put_domains.bits, POWER_DOMAIN_NUM)))
-                       modeset_put_crtc_power_domains(crtc, &put_domains);
-       }
-
-       intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
-
-       intel_power_domains_sanitize_state(dev_priv);
-}
-
 void intel_display_resume(struct drm_device *dev)
 {
        struct drm_i915_private *i915 = to_i915(dev);
index 2feb8ae..8610e17 100644 (file)
@@ -56,6 +56,7 @@ struct intel_initial_plane_config;
 struct intel_load_detect_pipe;
 struct intel_plane;
 struct intel_plane_state;
+struct intel_power_domain_mask;
 struct intel_remapped_info;
 struct intel_rotation_info;
 struct pci_dev;
@@ -563,6 +564,7 @@ bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state);
 bool intel_pipe_config_compare(const struct intel_crtc_state *current_config,
                               const struct intel_crtc_state *pipe_config,
                               bool fastset);
+void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state);
 
 void intel_plane_destroy(struct drm_plane *plane);
 void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state);
@@ -659,10 +661,16 @@ intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
                           const struct intel_crtc_state *crtc_state);
 void intel_plane_disable_noatomic(struct intel_crtc *crtc,
                                  struct intel_plane *plane);
+void intel_set_plane_visible(struct intel_crtc_state *crtc_state,
+                            struct intel_plane_state *plane_state,
+                            bool visible);
+void intel_plane_fixup_bitmasks(struct intel_crtc_state *crtc_state);
 
 void intel_display_driver_register(struct drm_i915_private *i915);
 void intel_display_driver_unregister(struct drm_i915_private *i915);
 
+void intel_update_watermarks(struct drm_i915_private *i915);
+
 /* modesetting */
 bool intel_modeset_probe_defer(struct pci_dev *pdev);
 void intel_modeset_init_hw(struct drm_i915_private *i915);
@@ -674,6 +682,10 @@ void intel_modeset_driver_remove_noirq(struct drm_i915_private *i915);
 void intel_modeset_driver_remove_nogem(struct drm_i915_private *i915);
 void intel_display_resume(struct drm_device *dev);
 int intel_modeset_all_pipes(struct intel_atomic_state *state);
+void intel_modeset_get_crtc_power_domains(struct intel_crtc_state *crtc_state,
+                                         struct intel_power_domain_mask *old_domains);
+void intel_modeset_put_crtc_power_domains(struct intel_crtc *crtc,
+                                         struct intel_power_domain_mask *domains);
 
 /* modesetting asserts */
 void assert_transcoder(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c
new file mode 100644 (file)
index 0000000..c340f33
--- /dev/null
@@ -0,0 +1,736 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ *
+ * Read out the current hardware modeset state, and sanitize it to the current
+ * state.
+ */
+
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_atomic_state_helper.h>
+
+#include "i915_drv.h"
+#include "intel_atomic.h"
+#include "intel_bw.h"
+#include "intel_color.h"
+#include "intel_crtc.h"
+#include "intel_crtc_state_dump.h"
+#include "intel_ddi.h"
+#include "intel_de.h"
+#include "intel_display.h"
+#include "intel_display_power.h"
+#include "intel_display_types.h"
+#include "intel_modeset_setup.h"
+#include "intel_pch_display.h"
+#include "intel_pm.h"
+
+static void intel_crtc_disable_noatomic(struct intel_crtc *crtc,
+                                       struct drm_modeset_acquire_ctx *ctx)
+{
+       struct intel_encoder *encoder;
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct intel_bw_state *bw_state =
+               to_intel_bw_state(dev_priv->bw_obj.state);
+       struct intel_cdclk_state *cdclk_state =
+               to_intel_cdclk_state(dev_priv->cdclk.obj.state);
+       struct intel_dbuf_state *dbuf_state =
+               to_intel_dbuf_state(dev_priv->dbuf.obj.state);
+       struct intel_crtc_state *crtc_state =
+               to_intel_crtc_state(crtc->base.state);
+       struct intel_plane *plane;
+       struct drm_atomic_state *state;
+       struct intel_crtc_state *temp_crtc_state;
+       enum pipe pipe = crtc->pipe;
+       int ret;
+
+       if (!crtc_state->hw.active)
+               return;
+
+       for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
+               const struct intel_plane_state *plane_state =
+                       to_intel_plane_state(plane->base.state);
+
+               if (plane_state->uapi.visible)
+                       intel_plane_disable_noatomic(crtc, plane);
+       }
+
+       state = drm_atomic_state_alloc(&dev_priv->drm);
+       if (!state) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "failed to disable [CRTC:%d:%s], out of memory",
+                           crtc->base.base.id, crtc->base.name);
+               return;
+       }
+
+       state->acquire_ctx = ctx;
+
+       /* Everything's already locked, -EDEADLK can't happen. */
+       temp_crtc_state = intel_atomic_get_crtc_state(state, crtc);
+       ret = drm_atomic_add_affected_connectors(state, &crtc->base);
+
+       drm_WARN_ON(&dev_priv->drm, IS_ERR(temp_crtc_state) || ret);
+
+       dev_priv->display->crtc_disable(to_intel_atomic_state(state), crtc);
+
+       drm_atomic_state_put(state);
+
+       drm_dbg_kms(&dev_priv->drm,
+                   "[CRTC:%d:%s] hw state adjusted, was enabled, now disabled\n",
+                   crtc->base.base.id, crtc->base.name);
+
+       crtc->active = false;
+       crtc->base.enabled = false;
+
+       drm_WARN_ON(&dev_priv->drm,
+                   drm_atomic_set_mode_for_crtc(&crtc_state->uapi, NULL) < 0);
+       crtc_state->uapi.active = false;
+       crtc_state->uapi.connector_mask = 0;
+       crtc_state->uapi.encoder_mask = 0;
+       intel_crtc_free_hw_state(crtc_state);
+       memset(&crtc_state->hw, 0, sizeof(crtc_state->hw));
+
+       for_each_encoder_on_crtc(&dev_priv->drm, &crtc->base, encoder)
+               encoder->base.crtc = NULL;
+
+       intel_fbc_disable(crtc);
+       intel_update_watermarks(dev_priv);
+       intel_disable_shared_dpll(crtc_state);
+
+       intel_display_power_put_all_in_set(dev_priv, &crtc->enabled_power_domains);
+
+       cdclk_state->min_cdclk[pipe] = 0;
+       cdclk_state->min_voltage_level[pipe] = 0;
+       cdclk_state->active_pipes &= ~BIT(pipe);
+
+       dbuf_state->active_pipes &= ~BIT(pipe);
+
+       bw_state->data_rate[pipe] = 0;
+       bw_state->num_active_planes[pipe] = 0;
+}
+
+static void intel_modeset_update_connector_atomic_state(struct drm_device *dev)
+{
+       struct intel_connector *connector;
+       struct drm_connector_list_iter conn_iter;
+
+       drm_connector_list_iter_begin(dev, &conn_iter);
+       for_each_intel_connector_iter(connector, &conn_iter) {
+               struct drm_connector_state *conn_state = connector->base.state;
+               struct intel_encoder *encoder =
+                       to_intel_encoder(connector->base.encoder);
+
+               if (conn_state->crtc)
+                       drm_connector_put(&connector->base);
+
+               if (encoder) {
+                       struct intel_crtc *crtc =
+                               to_intel_crtc(encoder->base.crtc);
+                       const struct intel_crtc_state *crtc_state =
+                               to_intel_crtc_state(crtc->base.state);
+
+                       conn_state->best_encoder = &encoder->base;
+                       conn_state->crtc = &crtc->base;
+                       conn_state->max_bpc = (crtc_state->pipe_bpp ?: 24) / 3;
+
+                       drm_connector_get(&connector->base);
+               } else {
+                       conn_state->best_encoder = NULL;
+                       conn_state->crtc = NULL;
+               }
+       }
+       drm_connector_list_iter_end(&conn_iter);
+}
+
+static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state)
+{
+       if (intel_crtc_is_bigjoiner_slave(crtc_state))
+               return;
+
+       crtc_state->uapi.enable = crtc_state->hw.enable;
+       crtc_state->uapi.active = crtc_state->hw.active;
+       drm_WARN_ON(crtc_state->uapi.crtc->dev,
+                   drm_atomic_set_mode_for_crtc(&crtc_state->uapi, &crtc_state->hw.mode) < 0);
+
+       crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode;
+       crtc_state->uapi.scaling_filter = crtc_state->hw.scaling_filter;
+
+       drm_property_replace_blob(&crtc_state->uapi.degamma_lut,
+                                 crtc_state->hw.degamma_lut);
+       drm_property_replace_blob(&crtc_state->uapi.gamma_lut,
+                                 crtc_state->hw.gamma_lut);
+       drm_property_replace_blob(&crtc_state->uapi.ctm,
+                                 crtc_state->hw.ctm);
+}
+
+static void
+intel_sanitize_plane_mapping(struct drm_i915_private *dev_priv)
+{
+       struct intel_crtc *crtc;
+
+       if (DISPLAY_VER(dev_priv) >= 4)
+               return;
+
+       for_each_intel_crtc(&dev_priv->drm, crtc) {
+               struct intel_plane *plane =
+                       to_intel_plane(crtc->base.primary);
+               struct intel_crtc *plane_crtc;
+               enum pipe pipe;
+
+               if (!plane->get_hw_state(plane, &pipe))
+                       continue;
+
+               if (pipe == crtc->pipe)
+                       continue;
+
+               drm_dbg_kms(&dev_priv->drm,
+                           "[PLANE:%d:%s] attached to the wrong pipe, disabling plane\n",
+                           plane->base.base.id, plane->base.name);
+
+               plane_crtc = intel_crtc_for_pipe(dev_priv, pipe);
+               intel_plane_disable_noatomic(plane_crtc, plane);
+       }
+}
+
+static bool intel_crtc_has_encoders(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct intel_encoder *encoder;
+
+       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
+               return true;
+
+       return false;
+}
+
+static struct intel_connector *intel_encoder_find_connector(struct intel_encoder *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct intel_connector *connector;
+
+       for_each_connector_on_encoder(dev, &encoder->base, connector)
+               return connector;
+
+       return NULL;
+}
+
+static void intel_sanitize_fifo_underrun_reporting(const 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);
+
+       if (!crtc_state->hw.active && !HAS_GMCH(i915))
+               return;
+
+       /*
+        * We start out with underrun reporting disabled to avoid races.
+        * For correct bookkeeping mark this on active crtcs.
+        *
+        * Also on gmch platforms we dont have any hardware bits to
+        * disable the underrun reporting. Which means we need to start
+        * out with underrun reporting disabled also on inactive pipes,
+        * since otherwise we'll complain about the garbage we read when
+        * e.g. coming up after runtime pm.
+        *
+        * No protection against concurrent access is required - at
+        * worst a fifo underrun happens which also sets this to false.
+        */
+       crtc->cpu_fifo_underrun_disabled = true;
+
+       /*
+        * We track the PCH trancoder underrun reporting state
+        * within the crtc. With crtc for pipe A housing the underrun
+        * reporting state for PCH transcoder A, crtc for pipe B housing
+        * it for PCH transcoder B, etc. LPT-H has only PCH transcoder A,
+        * and marking underrun reporting as disabled for the non-existing
+        * PCH transcoders B and C would prevent enabling the south
+        * error interrupt (see cpt_can_enable_serr_int()).
+        */
+       if (intel_has_pch_trancoder(i915, crtc->pipe))
+               crtc->pch_fifo_underrun_disabled = true;
+}
+
+static void intel_sanitize_crtc(struct intel_crtc *crtc,
+                               struct drm_modeset_acquire_ctx *ctx)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
+
+       if (crtc_state->hw.active) {
+               struct intel_plane *plane;
+
+               /* Disable everything but the primary plane */
+               for_each_intel_plane_on_crtc(dev, crtc, plane) {
+                       const struct intel_plane_state *plane_state =
+                               to_intel_plane_state(plane->base.state);
+
+                       if (plane_state->uapi.visible &&
+                           plane->base.type != DRM_PLANE_TYPE_PRIMARY)
+                               intel_plane_disable_noatomic(crtc, plane);
+               }
+
+               /* Disable any background color/etc. set by the BIOS */
+               intel_color_commit_noarm(crtc_state);
+               intel_color_commit_arm(crtc_state);
+       }
+
+       /*
+        * Adjust the state of the output pipe according to whether we have
+        * active connectors/encoders.
+        */
+       if (crtc_state->hw.active && !intel_crtc_has_encoders(crtc) &&
+           !intel_crtc_is_bigjoiner_slave(crtc_state))
+               intel_crtc_disable_noatomic(crtc, ctx);
+}
+
+static bool has_bogus_dpll_config(const struct intel_crtc_state *crtc_state)
+{
+       struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+
+       /*
+        * Some SNB BIOSen (eg. ASUS K53SV) are known to misprogram
+        * the hardware when a high res displays plugged in. DPLL P
+        * divider is zero, and the pipe timings are bonkers. We'll
+        * try to disable everything in that case.
+        *
+        * FIXME would be nice to be able to sanitize this state
+        * without several WARNs, but for now let's take the easy
+        * road.
+        */
+       return IS_SANDYBRIDGE(dev_priv) &&
+               crtc_state->hw.active &&
+               crtc_state->shared_dpll &&
+               crtc_state->port_clock == 0;
+}
+
+static void intel_sanitize_encoder(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_connector *connector;
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+       struct intel_crtc_state *crtc_state = crtc ?
+               to_intel_crtc_state(crtc->base.state) : NULL;
+
+       /*
+        * We need to check both for a crtc link (meaning that the encoder is
+        * active and trying to read from a pipe) and the pipe itself being
+        * active.
+        */
+       bool has_active_crtc = crtc_state &&
+               crtc_state->hw.active;
+
+       if (crtc_state && has_bogus_dpll_config(crtc_state)) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "BIOS has misprogrammed the hardware. Disabling pipe %c\n",
+                           pipe_name(crtc->pipe));
+               has_active_crtc = false;
+       }
+
+       connector = intel_encoder_find_connector(encoder);
+       if (connector && !has_active_crtc) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "[ENCODER:%d:%s] has active connectors but no active pipe!\n",
+                           encoder->base.base.id,
+                           encoder->base.name);
+
+               /*
+                * Connector is active, but has no active pipe. This is fallout
+                * from our resume register restoring. Disable the encoder
+                * manually again.
+                */
+               if (crtc_state) {
+                       struct drm_encoder *best_encoder;
+
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "[ENCODER:%d:%s] manually disabled\n",
+                                   encoder->base.base.id,
+                                   encoder->base.name);
+
+                       /* avoid oopsing in case the hooks consult best_encoder */
+                       best_encoder = connector->base.state->best_encoder;
+                       connector->base.state->best_encoder = &encoder->base;
+
+                       /* FIXME NULL atomic state passed! */
+                       if (encoder->disable)
+                               encoder->disable(NULL, encoder, crtc_state,
+                                                connector->base.state);
+                       if (encoder->post_disable)
+                               encoder->post_disable(NULL, encoder, crtc_state,
+                                                     connector->base.state);
+
+                       connector->base.state->best_encoder = best_encoder;
+               }
+               encoder->base.crtc = NULL;
+
+               /*
+                * Inconsistent output/port/pipe state happens presumably due to
+                * a bug in one of the get_hw_state functions. Or someplace else
+                * in our code, like the register restore mess on resume. Clamp
+                * things to off as a safer default.
+                */
+               connector->base.dpms = DRM_MODE_DPMS_OFF;
+               connector->base.encoder = NULL;
+       }
+
+       /* notify opregion of the sanitized encoder state */
+       intel_opregion_notify_encoder(encoder, connector && has_active_crtc);
+
+       if (HAS_DDI(dev_priv))
+               intel_ddi_sanitize_encoder_pll_mapping(encoder);
+}
+
+/* FIXME read out full plane state for all planes */
+static void readout_plane_state(struct drm_i915_private *dev_priv)
+{
+       struct intel_plane *plane;
+       struct intel_crtc *crtc;
+
+       for_each_intel_plane(&dev_priv->drm, plane) {
+               struct intel_plane_state *plane_state =
+                       to_intel_plane_state(plane->base.state);
+               struct intel_crtc_state *crtc_state;
+               enum pipe pipe = PIPE_A;
+               bool visible;
+
+               visible = plane->get_hw_state(plane, &pipe);
+
+               crtc = intel_crtc_for_pipe(dev_priv, pipe);
+               crtc_state = to_intel_crtc_state(crtc->base.state);
+
+               intel_set_plane_visible(crtc_state, plane_state, visible);
+
+               drm_dbg_kms(&dev_priv->drm,
+                           "[PLANE:%d:%s] hw state readout: %s, pipe %c\n",
+                           plane->base.base.id, plane->base.name,
+                           str_enabled_disabled(visible), pipe_name(pipe));
+       }
+
+       for_each_intel_crtc(&dev_priv->drm, crtc) {
+               struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+
+               intel_plane_fixup_bitmasks(crtc_state);
+       }
+}
+
+static void intel_modeset_readout_hw_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_cdclk_state *cdclk_state =
+               to_intel_cdclk_state(dev_priv->cdclk.obj.state);
+       struct intel_dbuf_state *dbuf_state =
+               to_intel_dbuf_state(dev_priv->dbuf.obj.state);
+       enum pipe pipe;
+       struct intel_crtc *crtc;
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       struct drm_connector_list_iter conn_iter;
+       u8 active_pipes = 0;
+
+       for_each_intel_crtc(dev, crtc) {
+               struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+
+               __drm_atomic_helper_crtc_destroy_state(&crtc_state->uapi);
+               intel_crtc_free_hw_state(crtc_state);
+               intel_crtc_state_reset(crtc_state, crtc);
+
+               intel_crtc_get_pipe_config(crtc_state);
+
+               crtc_state->hw.enable = crtc_state->hw.active;
+
+               crtc->base.enabled = crtc_state->hw.enable;
+               crtc->active = crtc_state->hw.active;
+
+               if (crtc_state->hw.active)
+                       active_pipes |= BIT(crtc->pipe);
+
+               drm_dbg_kms(&dev_priv->drm,
+                           "[CRTC:%d:%s] hw state readout: %s\n",
+                           crtc->base.base.id, crtc->base.name,
+                           str_enabled_disabled(crtc_state->hw.active));
+       }
+
+       cdclk_state->active_pipes = active_pipes;
+       dbuf_state->active_pipes = active_pipes;
+
+       readout_plane_state(dev_priv);
+
+       for_each_intel_encoder(dev, encoder) {
+               struct intel_crtc_state *crtc_state = NULL;
+
+               pipe = 0;
+
+               if (encoder->get_hw_state(encoder, &pipe)) {
+                       crtc = intel_crtc_for_pipe(dev_priv, pipe);
+                       crtc_state = to_intel_crtc_state(crtc->base.state);
+
+                       encoder->base.crtc = &crtc->base;
+                       intel_encoder_get_config(encoder, crtc_state);
+
+                       /* read out to slave crtc as well for bigjoiner */
+                       if (crtc_state->bigjoiner_pipes) {
+                               struct intel_crtc *slave_crtc;
+
+                               /* encoder should read be linked to bigjoiner master */
+                               WARN_ON(intel_crtc_is_bigjoiner_slave(crtc_state));
+
+                               for_each_intel_crtc_in_pipe_mask(&dev_priv->drm, slave_crtc,
+                                                                intel_crtc_bigjoiner_slave_pipes(crtc_state)) {
+                                       struct intel_crtc_state *slave_crtc_state;
+
+                                       slave_crtc_state = to_intel_crtc_state(slave_crtc->base.state);
+                                       intel_encoder_get_config(encoder, slave_crtc_state);
+                               }
+                       }
+               } else {
+                       encoder->base.crtc = NULL;
+               }
+
+               if (encoder->sync_state)
+                       encoder->sync_state(encoder, crtc_state);
+
+               drm_dbg_kms(&dev_priv->drm,
+                           "[ENCODER:%d:%s] hw state readout: %s, pipe %c\n",
+                           encoder->base.base.id, encoder->base.name,
+                           str_enabled_disabled(encoder->base.crtc),
+                           pipe_name(pipe));
+       }
+
+       intel_dpll_readout_hw_state(dev_priv);
+
+       drm_connector_list_iter_begin(dev, &conn_iter);
+       for_each_intel_connector_iter(connector, &conn_iter) {
+               if (connector->get_hw_state(connector)) {
+                       struct intel_crtc_state *crtc_state;
+                       struct intel_crtc *crtc;
+
+                       connector->base.dpms = DRM_MODE_DPMS_ON;
+
+                       encoder = intel_attached_encoder(connector);
+                       connector->base.encoder = &encoder->base;
+
+                       crtc = to_intel_crtc(encoder->base.crtc);
+                       crtc_state = crtc ? to_intel_crtc_state(crtc->base.state) : NULL;
+
+                       if (crtc_state && crtc_state->hw.active) {
+                               /*
+                                * This has to be done during hardware readout
+                                * because anything calling .crtc_disable may
+                                * rely on the connector_mask being accurate.
+                                */
+                               crtc_state->uapi.connector_mask |=
+                                       drm_connector_mask(&connector->base);
+                               crtc_state->uapi.encoder_mask |=
+                                       drm_encoder_mask(&encoder->base);
+                       }
+               } else {
+                       connector->base.dpms = DRM_MODE_DPMS_OFF;
+                       connector->base.encoder = NULL;
+               }
+               drm_dbg_kms(&dev_priv->drm,
+                           "[CONNECTOR:%d:%s] hw state readout: %s\n",
+                           connector->base.base.id, connector->base.name,
+                           str_enabled_disabled(connector->base.encoder));
+       }
+       drm_connector_list_iter_end(&conn_iter);
+
+       for_each_intel_crtc(dev, crtc) {
+               struct intel_bw_state *bw_state =
+                       to_intel_bw_state(dev_priv->bw_obj.state);
+               struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+               struct intel_plane *plane;
+               int min_cdclk = 0;
+
+               if (crtc_state->hw.active) {
+                       /*
+                        * The initial mode needs to be set in order to keep
+                        * the atomic core happy. It wants a valid mode if the
+                        * crtc's enabled, so we do the above call.
+                        *
+                        * But we don't set all the derived state fully, hence
+                        * set a flag to indicate that a full recalculation is
+                        * needed on the next commit.
+                        */
+                       crtc_state->inherited = true;
+
+                       intel_crtc_update_active_timings(crtc_state);
+
+                       intel_crtc_copy_hw_to_uapi_state(crtc_state);
+               }
+
+               for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
+                       const struct intel_plane_state *plane_state =
+                               to_intel_plane_state(plane->base.state);
+
+                       /*
+                        * FIXME don't have the fb yet, so can't
+                        * use intel_plane_data_rate() :(
+                        */
+                       if (plane_state->uapi.visible)
+                               crtc_state->data_rate[plane->id] =
+                                       4 * crtc_state->pixel_rate;
+                       /*
+                        * FIXME don't have the fb yet, so can't
+                        * use plane->min_cdclk() :(
+                        */
+                       if (plane_state->uapi.visible && plane->min_cdclk) {
+                               if (crtc_state->double_wide || DISPLAY_VER(dev_priv) >= 10)
+                                       crtc_state->min_cdclk[plane->id] =
+                                               DIV_ROUND_UP(crtc_state->pixel_rate, 2);
+                               else
+                                       crtc_state->min_cdclk[plane->id] =
+                                               crtc_state->pixel_rate;
+                       }
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "[PLANE:%d:%s] min_cdclk %d kHz\n",
+                                   plane->base.base.id, plane->base.name,
+                                   crtc_state->min_cdclk[plane->id]);
+               }
+
+               if (crtc_state->hw.active) {
+                       min_cdclk = intel_crtc_compute_min_cdclk(crtc_state);
+                       if (drm_WARN_ON(dev, min_cdclk < 0))
+                               min_cdclk = 0;
+               }
+
+               cdclk_state->min_cdclk[crtc->pipe] = min_cdclk;
+               cdclk_state->min_voltage_level[crtc->pipe] =
+                       crtc_state->min_voltage_level;
+
+               intel_bw_crtc_update(bw_state, crtc_state);
+       }
+}
+
+static void
+get_encoder_power_domains(struct drm_i915_private *dev_priv)
+{
+       struct intel_encoder *encoder;
+
+       for_each_intel_encoder(&dev_priv->drm, encoder) {
+               struct intel_crtc_state *crtc_state;
+
+               if (!encoder->get_power_domains)
+                       continue;
+
+               /*
+                * MST-primary and inactive encoders don't have a crtc state
+                * and neither of these require any power domain references.
+                */
+               if (!encoder->base.crtc)
+                       continue;
+
+               crtc_state = to_intel_crtc_state(encoder->base.crtc->state);
+               encoder->get_power_domains(encoder, crtc_state);
+       }
+}
+
+static void intel_early_display_was(struct drm_i915_private *dev_priv)
+{
+       /*
+        * Display WA #1185 WaDisableDARBFClkGating:glk,icl,ehl,tgl
+        * Also known as Wa_14010480278.
+        */
+       if (IS_DISPLAY_VER(dev_priv, 10, 12))
+               intel_de_write(dev_priv, GEN9_CLKGATE_DIS_0,
+                              intel_de_read(dev_priv, GEN9_CLKGATE_DIS_0) | DARBF_GATING_DIS);
+
+       if (IS_HASWELL(dev_priv)) {
+               /*
+                * WaRsPkgCStateDisplayPMReq:hsw
+                * System hang if this isn't done before disabling all planes!
+                */
+               intel_de_write(dev_priv, CHICKEN_PAR1_1,
+                              intel_de_read(dev_priv, CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES);
+       }
+
+       if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv) || IS_COMETLAKE(dev_priv)) {
+               /* Display WA #1142:kbl,cfl,cml */
+               intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
+                            KBL_ARB_FILL_SPARE_22, KBL_ARB_FILL_SPARE_22);
+               intel_de_rmw(dev_priv, CHICKEN_MISC_2,
+                            KBL_ARB_FILL_SPARE_13 | KBL_ARB_FILL_SPARE_14,
+                            KBL_ARB_FILL_SPARE_14);
+       }
+}
+
+void intel_modeset_setup_hw_state(struct drm_device *dev,
+                                 struct drm_modeset_acquire_ctx *ctx)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_encoder *encoder;
+       struct intel_crtc *crtc;
+       intel_wakeref_t wakeref;
+
+       wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+
+       intel_early_display_was(dev_priv);
+       intel_modeset_readout_hw_state(dev);
+
+       /* HW state is read out, now we need to sanitize this mess. */
+       get_encoder_power_domains(dev_priv);
+
+       intel_pch_sanitize(dev_priv);
+
+       /*
+        * intel_sanitize_plane_mapping() may need to do vblank
+        * waits, so we need vblank interrupts restored beforehand.
+        */
+       for_each_intel_crtc(&dev_priv->drm, crtc) {
+               struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+
+               intel_sanitize_fifo_underrun_reporting(crtc_state);
+
+               drm_crtc_vblank_reset(&crtc->base);
+
+               if (crtc_state->hw.active)
+                       intel_crtc_vblank_on(crtc_state);
+       }
+
+       intel_fbc_sanitize(dev_priv);
+
+       intel_sanitize_plane_mapping(dev_priv);
+
+       for_each_intel_encoder(dev, encoder)
+               intel_sanitize_encoder(encoder);
+
+       for_each_intel_crtc(&dev_priv->drm, crtc) {
+               struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+
+               intel_sanitize_crtc(crtc, ctx);
+               intel_crtc_state_dump(crtc_state, NULL, "setup_hw_state");
+       }
+
+       intel_modeset_update_connector_atomic_state(dev);
+
+       intel_dpll_sanitize_state(dev_priv);
+
+       if (IS_G4X(dev_priv)) {
+               g4x_wm_get_hw_state(dev_priv);
+               g4x_wm_sanitize(dev_priv);
+       } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               vlv_wm_get_hw_state(dev_priv);
+               vlv_wm_sanitize(dev_priv);
+       } else if (DISPLAY_VER(dev_priv) >= 9) {
+               skl_wm_get_hw_state(dev_priv);
+               skl_wm_sanitize(dev_priv);
+       } else if (HAS_PCH_SPLIT(dev_priv)) {
+               ilk_wm_get_hw_state(dev_priv);
+       }
+
+       for_each_intel_crtc(dev, crtc) {
+               struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+               struct intel_power_domain_mask put_domains;
+
+               intel_modeset_get_crtc_power_domains(crtc_state, &put_domains);
+               if (drm_WARN_ON(dev, !bitmap_empty(put_domains.bits, POWER_DOMAIN_NUM)))
+                       intel_modeset_put_crtc_power_domains(crtc, &put_domains);
+       }
+
+       intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
+
+       intel_power_domains_sanitize_state(dev_priv);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.h b/drivers/gpu/drm/i915/display/intel_modeset_setup.h
new file mode 100644 (file)
index 0000000..c29b34c
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef __INTEL_MODESET_SETUP_H__
+#define __INTEL_MODESET_SETUP_H__
+
+struct drm_device;
+struct drm_modeset_acquire_ctx;
+
+void intel_modeset_setup_hw_state(struct drm_device *dev,
+                                 struct drm_modeset_acquire_ctx *ctx);
+
+#endif /* __INTEL_MODESET_SETUP_H__ */