On Tue, Apr 16, 2019 at 01:36:03PM +0300, Jani Nikula wrote: > Signed-off-by: Jani Nikula <jani.nikula@xxxxxxxxx> pipe_config_compare is used both for the atomic_check logic, and the verifier. I think stuffing it into the verifier code is misplacing it as much as e.g. stuffing it into intel_atomic_check.c file. What I'd do instead is create an intel_crtc_state.[hc] pair and collect everything that operates on struct intel_crtc_state, plus the struct itself. Of course we might want to split out specific subtopics from this, like e.g. the fairly massive amount of code related to compute clock state. -Daniel > --- > drivers/gpu/drm/i915/intel_display.c | 471 +-------------------------- > drivers/gpu/drm/i915/intel_drv.h | 9 +- > drivers/gpu/drm/i915/intel_verify.c | 465 ++++++++++++++++++++++++++ > drivers/gpu/drm/i915/intel_verify.h | 8 + > 4 files changed, 478 insertions(+), 475 deletions(-) > > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index 31a931..14899f 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -202,9 +202,9 @@ static void intel_update_czclk(struct drm_i915_private *dev_priv) > DRM_DEBUG_DRIVER("CZ clock rate: %d kHz\n", dev_priv->czclk_freq); > } > > -static inline u32 /* units of 100MHz */ > -intel_fdi_link_freq(struct drm_i915_private *dev_priv, > - const struct intel_crtc_state *pipe_config) > +/* units of 100MHz */ > +u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv, > + const struct intel_crtc_state *pipe_config) > { > if (HAS_DDI(dev_priv)) > return pipe_config->port_clock; /* SPLL */ > @@ -11904,471 +11904,6 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, > return 0; > } > > -static bool intel_fuzzy_clock_check(int clock1, int clock2) > -{ > - int diff; > - > - if (clock1 == clock2) > - return true; > - > - if (!clock1 || !clock2) > - return false; > - > - diff = abs(clock1 - clock2); > - > - if (((((diff + clock1 + clock2) * 100)) / (clock1 + clock2)) < 105) > - return true; > - > - return false; > -} > - > -static bool > -intel_compare_m_n(unsigned int m, unsigned int n, > - unsigned int m2, unsigned int n2, > - bool exact) > -{ > - if (m == m2 && n == n2) > - return true; > - > - if (exact || !m || !n || !m2 || !n2) > - return false; > - > - BUILD_BUG_ON(DATA_LINK_M_N_MASK > INT_MAX); > - > - if (n > n2) { > - while (n > n2) { > - m2 <<= 1; > - n2 <<= 1; > - } > - } else if (n < n2) { > - while (n < n2) { > - m <<= 1; > - n <<= 1; > - } > - } > - > - if (n != n2) > - return false; > - > - return intel_fuzzy_clock_check(m, m2); > -} > - > -static bool > -intel_compare_link_m_n(const struct intel_link_m_n *m_n, > - struct intel_link_m_n *m2_n2, > - bool adjust) > -{ > - if (m_n->tu == m2_n2->tu && > - intel_compare_m_n(m_n->gmch_m, m_n->gmch_n, > - m2_n2->gmch_m, m2_n2->gmch_n, !adjust) && > - intel_compare_m_n(m_n->link_m, m_n->link_n, > - m2_n2->link_m, m2_n2->link_n, !adjust)) { > - if (adjust) > - *m2_n2 = *m_n; > - > - return true; > - } > - > - return false; > -} > - > -static bool > -intel_compare_infoframe(const union hdmi_infoframe *a, > - const union hdmi_infoframe *b) > -{ > - return memcmp(a, b, sizeof(*a)) == 0; > -} > - > -static void > -pipe_config_infoframe_err(struct drm_i915_private *dev_priv, > - bool adjust, const char *name, > - const union hdmi_infoframe *a, > - const union hdmi_infoframe *b) > -{ > - if (adjust) { > - if ((drm_debug & DRM_UT_KMS) == 0) > - return; > - > - drm_dbg(DRM_UT_KMS, "mismatch in %s infoframe", name); > - drm_dbg(DRM_UT_KMS, "expected:"); > - hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, a); > - drm_dbg(DRM_UT_KMS, "found"); > - hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, b); > - } else { > - drm_err("mismatch in %s infoframe", name); > - drm_err("expected:"); > - hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, a); > - drm_err("found"); > - hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, b); > - } > -} > - > -static void __printf(3, 4) > -pipe_config_err(bool adjust, const char *name, const char *format, ...) > -{ > - struct va_format vaf; > - va_list args; > - > - va_start(args, format); > - vaf.fmt = format; > - vaf.va = &args; > - > - if (adjust) > - drm_dbg(DRM_UT_KMS, "mismatch in %s %pV", name, &vaf); > - else > - drm_err("mismatch in %s %pV", name, &vaf); > - > - va_end(args); > -} > - > -static bool fastboot_enabled(struct drm_i915_private *dev_priv) > -{ > - if (i915_modparams.fastboot != -1) > - return i915_modparams.fastboot; > - > - /* Enable fastboot by default on Skylake and newer */ > - if (INTEL_GEN(dev_priv) >= 9) > - return true; > - > - /* Enable fastboot by default on VLV and CHV */ > - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) > - return true; > - > - /* Disabled by default on all others */ > - return false; > -} > - > -bool > -intel_pipe_config_compare(struct drm_i915_private *dev_priv, > - struct intel_crtc_state *current_config, > - struct intel_crtc_state *pipe_config, > - bool adjust) > -{ > - bool ret = true; > - bool fixup_inherited = adjust && > - (current_config->base.mode.private_flags & I915_MODE_FLAG_INHERITED) && > - !(pipe_config->base.mode.private_flags & I915_MODE_FLAG_INHERITED); > - > - if (fixup_inherited && !fastboot_enabled(dev_priv)) { > - DRM_DEBUG_KMS("initial modeset and fastboot not set\n"); > - ret = false; > - } > - > -#define PIPE_CONF_CHECK_X(name) do { \ > - if (current_config->name != pipe_config->name) { \ > - pipe_config_err(adjust, __stringify(name), \ > - "(expected 0x%08x, found 0x%08x)\n", \ > - current_config->name, \ > - pipe_config->name); \ > - ret = false; \ > - } \ > -} while (0) > - > -#define PIPE_CONF_CHECK_I(name) do { \ > - if (current_config->name != pipe_config->name) { \ > - pipe_config_err(adjust, __stringify(name), \ > - "(expected %i, found %i)\n", \ > - current_config->name, \ > - pipe_config->name); \ > - ret = false; \ > - } \ > -} while (0) > - > -#define PIPE_CONF_CHECK_BOOL(name) do { \ > - if (current_config->name != pipe_config->name) { \ > - pipe_config_err(adjust, __stringify(name), \ > - "(expected %s, found %s)\n", \ > - yesno(current_config->name), \ > - yesno(pipe_config->name)); \ > - ret = false; \ > - } \ > -} while (0) > - > -/* > - * Checks state where we only read out the enabling, but not the entire > - * state itself (like full infoframes or ELD for audio). These states > - * require a full modeset on bootup to fix up. > - */ > -#define PIPE_CONF_CHECK_BOOL_INCOMPLETE(name) do { \ > - if (!fixup_inherited || (!current_config->name && !pipe_config->name)) { \ > - PIPE_CONF_CHECK_BOOL(name); \ > - } else { \ > - pipe_config_err(adjust, __stringify(name), \ > - "unable to verify whether state matches exactly, forcing modeset (expected %s, found %s)\n", \ > - yesno(current_config->name), \ > - yesno(pipe_config->name)); \ > - ret = false; \ > - } \ > -} while (0) > - > -#define PIPE_CONF_CHECK_P(name) do { \ > - if (current_config->name != pipe_config->name) { \ > - pipe_config_err(adjust, __stringify(name), \ > - "(expected %p, found %p)\n", \ > - current_config->name, \ > - pipe_config->name); \ > - ret = false; \ > - } \ > -} while (0) > - > -#define PIPE_CONF_CHECK_M_N(name) do { \ > - if (!intel_compare_link_m_n(¤t_config->name, \ > - &pipe_config->name,\ > - adjust)) { \ > - pipe_config_err(adjust, __stringify(name), \ > - "(expected tu %i gmch %i/%i link %i/%i, " \ > - "found tu %i, gmch %i/%i link %i/%i)\n", \ > - current_config->name.tu, \ > - current_config->name.gmch_m, \ > - current_config->name.gmch_n, \ > - current_config->name.link_m, \ > - current_config->name.link_n, \ > - pipe_config->name.tu, \ > - pipe_config->name.gmch_m, \ > - pipe_config->name.gmch_n, \ > - pipe_config->name.link_m, \ > - pipe_config->name.link_n); \ > - ret = false; \ > - } \ > -} while (0) > - > -/* This is required for BDW+ where there is only one set of registers for > - * switching between high and low RR. > - * This macro can be used whenever a comparison has to be made between one > - * hw state and multiple sw state variables. > - */ > -#define PIPE_CONF_CHECK_M_N_ALT(name, alt_name) do { \ > - if (!intel_compare_link_m_n(¤t_config->name, \ > - &pipe_config->name, adjust) && \ > - !intel_compare_link_m_n(¤t_config->alt_name, \ > - &pipe_config->name, adjust)) { \ > - pipe_config_err(adjust, __stringify(name), \ > - "(expected tu %i gmch %i/%i link %i/%i, " \ > - "or tu %i gmch %i/%i link %i/%i, " \ > - "found tu %i, gmch %i/%i link %i/%i)\n", \ > - current_config->name.tu, \ > - current_config->name.gmch_m, \ > - current_config->name.gmch_n, \ > - current_config->name.link_m, \ > - current_config->name.link_n, \ > - current_config->alt_name.tu, \ > - current_config->alt_name.gmch_m, \ > - current_config->alt_name.gmch_n, \ > - current_config->alt_name.link_m, \ > - current_config->alt_name.link_n, \ > - pipe_config->name.tu, \ > - pipe_config->name.gmch_m, \ > - pipe_config->name.gmch_n, \ > - pipe_config->name.link_m, \ > - pipe_config->name.link_n); \ > - ret = false; \ > - } \ > -} while (0) > - > -#define PIPE_CONF_CHECK_FLAGS(name, mask) do { \ > - if ((current_config->name ^ pipe_config->name) & (mask)) { \ > - pipe_config_err(adjust, __stringify(name), \ > - "(%x) (expected %i, found %i)\n", \ > - (mask), \ > - current_config->name & (mask), \ > - pipe_config->name & (mask)); \ > - ret = false; \ > - } \ > -} while (0) > - > -#define PIPE_CONF_CHECK_CLOCK_FUZZY(name) do { \ > - if (!intel_fuzzy_clock_check(current_config->name, pipe_config->name)) { \ > - pipe_config_err(adjust, __stringify(name), \ > - "(expected %i, found %i)\n", \ > - current_config->name, \ > - pipe_config->name); \ > - ret = false; \ > - } \ > -} while (0) > - > -#define PIPE_CONF_CHECK_INFOFRAME(name) do { \ > - if (!intel_compare_infoframe(¤t_config->infoframes.name, \ > - &pipe_config->infoframes.name)) { \ > - pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \ > - ¤t_config->infoframes.name, \ > - &pipe_config->infoframes.name); \ > - ret = false; \ > - } \ > -} while (0) > - > -#define PIPE_CONF_QUIRK(quirk) \ > - ((current_config->quirks | pipe_config->quirks) & (quirk)) > - > - PIPE_CONF_CHECK_I(cpu_transcoder); > - > - PIPE_CONF_CHECK_BOOL(has_pch_encoder); > - PIPE_CONF_CHECK_I(fdi_lanes); > - PIPE_CONF_CHECK_M_N(fdi_m_n); > - > - PIPE_CONF_CHECK_I(lane_count); > - PIPE_CONF_CHECK_X(lane_lat_optim_mask); > - > - if (INTEL_GEN(dev_priv) < 8) { > - PIPE_CONF_CHECK_M_N(dp_m_n); > - > - if (current_config->has_drrs) > - PIPE_CONF_CHECK_M_N(dp_m2_n2); > - } else > - PIPE_CONF_CHECK_M_N_ALT(dp_m_n, dp_m2_n2); > - > - PIPE_CONF_CHECK_X(output_types); > - > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hdisplay); > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_htotal); > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_start); > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_end); > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hsync_start); > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hsync_end); > - > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vdisplay); > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vtotal); > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vblank_start); > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vblank_end); > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_start); > - PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_end); > - > - PIPE_CONF_CHECK_I(pixel_multiplier); > - PIPE_CONF_CHECK_I(output_format); > - PIPE_CONF_CHECK_BOOL(has_hdmi_sink); > - if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) || > - IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) > - PIPE_CONF_CHECK_BOOL(limited_color_range); > - > - PIPE_CONF_CHECK_BOOL(hdmi_scrambling); > - PIPE_CONF_CHECK_BOOL(hdmi_high_tmds_clock_ratio); > - PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_infoframe); > - > - PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio); > - > - PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags, > - DRM_MODE_FLAG_INTERLACE); > - > - if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) { > - PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags, > - DRM_MODE_FLAG_PHSYNC); > - PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags, > - DRM_MODE_FLAG_NHSYNC); > - PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags, > - DRM_MODE_FLAG_PVSYNC); > - PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags, > - DRM_MODE_FLAG_NVSYNC); > - } > - > - PIPE_CONF_CHECK_X(gmch_pfit.control); > - /* pfit ratios are autocomputed by the hw on gen4+ */ > - if (INTEL_GEN(dev_priv) < 4) > - PIPE_CONF_CHECK_X(gmch_pfit.pgm_ratios); > - PIPE_CONF_CHECK_X(gmch_pfit.lvds_border_bits); > - > - if (!adjust) { > - PIPE_CONF_CHECK_I(pipe_src_w); > - PIPE_CONF_CHECK_I(pipe_src_h); > - > - PIPE_CONF_CHECK_BOOL(pch_pfit.enabled); > - if (current_config->pch_pfit.enabled) { > - PIPE_CONF_CHECK_X(pch_pfit.pos); > - PIPE_CONF_CHECK_X(pch_pfit.size); > - } > - > - PIPE_CONF_CHECK_I(scaler_state.scaler_id); > - PIPE_CONF_CHECK_CLOCK_FUZZY(pixel_rate); > - > - PIPE_CONF_CHECK_X(gamma_mode); > - if (IS_CHERRYVIEW(dev_priv)) > - PIPE_CONF_CHECK_X(cgm_mode); > - else > - PIPE_CONF_CHECK_X(csc_mode); > - PIPE_CONF_CHECK_BOOL(gamma_enable); > - PIPE_CONF_CHECK_BOOL(csc_enable); > - } > - > - PIPE_CONF_CHECK_BOOL(double_wide); > - > - PIPE_CONF_CHECK_P(shared_dpll); > - PIPE_CONF_CHECK_X(dpll_hw_state.dpll); > - PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md); > - PIPE_CONF_CHECK_X(dpll_hw_state.fp0); > - PIPE_CONF_CHECK_X(dpll_hw_state.fp1); > - PIPE_CONF_CHECK_X(dpll_hw_state.wrpll); > - PIPE_CONF_CHECK_X(dpll_hw_state.spll); > - PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1); > - PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1); > - PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2); > - PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr0); > - PIPE_CONF_CHECK_X(dpll_hw_state.ebb0); > - PIPE_CONF_CHECK_X(dpll_hw_state.ebb4); > - PIPE_CONF_CHECK_X(dpll_hw_state.pll0); > - PIPE_CONF_CHECK_X(dpll_hw_state.pll1); > - PIPE_CONF_CHECK_X(dpll_hw_state.pll2); > - PIPE_CONF_CHECK_X(dpll_hw_state.pll3); > - PIPE_CONF_CHECK_X(dpll_hw_state.pll6); > - PIPE_CONF_CHECK_X(dpll_hw_state.pll8); > - PIPE_CONF_CHECK_X(dpll_hw_state.pll9); > - PIPE_CONF_CHECK_X(dpll_hw_state.pll10); > - PIPE_CONF_CHECK_X(dpll_hw_state.pcsdw12); > - PIPE_CONF_CHECK_X(dpll_hw_state.mg_refclkin_ctl); > - PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_coreclkctl1); > - PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_hsclkctl); > - PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div0); > - PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div1); > - PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_lf); > - PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_frac_lock); > - PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_ssc); > - PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_bias); > - PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_tdc_coldst_bias); > - > - PIPE_CONF_CHECK_X(dsi_pll.ctrl); > - PIPE_CONF_CHECK_X(dsi_pll.div); > - > - if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) > - PIPE_CONF_CHECK_I(pipe_bpp); > - > - PIPE_CONF_CHECK_CLOCK_FUZZY(base.adjusted_mode.crtc_clock); > - PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock); > - > - PIPE_CONF_CHECK_I(min_voltage_level); > - > - PIPE_CONF_CHECK_X(infoframes.enable); > - PIPE_CONF_CHECK_X(infoframes.gcp); > - PIPE_CONF_CHECK_INFOFRAME(avi); > - PIPE_CONF_CHECK_INFOFRAME(spd); > - PIPE_CONF_CHECK_INFOFRAME(hdmi); > - > -#undef PIPE_CONF_CHECK_X > -#undef PIPE_CONF_CHECK_I > -#undef PIPE_CONF_CHECK_BOOL > -#undef PIPE_CONF_CHECK_BOOL_INCOMPLETE > -#undef PIPE_CONF_CHECK_P > -#undef PIPE_CONF_CHECK_FLAGS > -#undef PIPE_CONF_CHECK_CLOCK_FUZZY > -#undef PIPE_CONF_QUIRK > - > - return ret; > -} > - > -void intel_pipe_config_sanity_check(struct drm_i915_private *dev_priv, > - const struct intel_crtc_state *pipe_config) > -{ > - if (pipe_config->has_pch_encoder) { > - int fdi_dotclock = intel_dotclock_calculate(intel_fdi_link_freq(dev_priv, pipe_config), > - &pipe_config->fdi_m_n); > - int dotclock = pipe_config->base.adjusted_mode.crtc_clock; > - > - /* > - * FDI already provided one idea for the dotclock. > - * Yell if the encoder disagrees. > - */ > - WARN(!intel_fuzzy_clock_check(fdi_dotclock, dotclock), > - "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n", > - fdi_dotclock, dotclock); > - } > -} > - > static void update_scanline_offset(const struct intel_crtc_state *crtc_state) > { > struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index 77767c..ed853b2 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -1668,17 +1668,12 @@ int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data, > struct drm_file *file_priv); > enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, > enum pipe pipe); > -void intel_pipe_config_sanity_check(struct drm_i915_private *dev_priv, > - const struct intel_crtc_state *pipe_config); > -bool > -intel_pipe_config_compare(struct drm_i915_private *dev_priv, > - struct intel_crtc_state *current_config, > - struct intel_crtc_state *pipe_config, > - bool adjust); > void intel_dump_pipe_config(struct intel_crtc *crtc, > struct intel_crtc_state *pipe_config, > const char *context); > void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state); > +u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv, > + const struct intel_crtc_state *pipe_config); > static inline bool > intel_crtc_has_type(const struct intel_crtc_state *crtc_state, > enum intel_output_type type) > diff --git a/drivers/gpu/drm/i915/intel_verify.c b/drivers/gpu/drm/i915/intel_verify.c > index 4c8990..9785ad 100644 > --- a/drivers/gpu/drm/i915/intel_verify.c > +++ b/drivers/gpu/drm/i915/intel_verify.c > @@ -10,6 +10,471 @@ > #include "intel_pm.h" > #include "intel_verify.h" > > +static bool intel_fuzzy_clock_check(int clock1, int clock2) > +{ > + int diff; > + > + if (clock1 == clock2) > + return true; > + > + if (!clock1 || !clock2) > + return false; > + > + diff = abs(clock1 - clock2); > + > + if (((((diff + clock1 + clock2) * 100)) / (clock1 + clock2)) < 105) > + return true; > + > + return false; > +} > + > +static bool > +intel_compare_m_n(unsigned int m, unsigned int n, > + unsigned int m2, unsigned int n2, > + bool exact) > +{ > + if (m == m2 && n == n2) > + return true; > + > + if (exact || !m || !n || !m2 || !n2) > + return false; > + > + BUILD_BUG_ON(DATA_LINK_M_N_MASK > INT_MAX); > + > + if (n > n2) { > + while (n > n2) { > + m2 <<= 1; > + n2 <<= 1; > + } > + } else if (n < n2) { > + while (n < n2) { > + m <<= 1; > + n <<= 1; > + } > + } > + > + if (n != n2) > + return false; > + > + return intel_fuzzy_clock_check(m, m2); > +} > + > +static bool > +intel_compare_link_m_n(const struct intel_link_m_n *m_n, > + struct intel_link_m_n *m2_n2, > + bool adjust) > +{ > + if (m_n->tu == m2_n2->tu && > + intel_compare_m_n(m_n->gmch_m, m_n->gmch_n, > + m2_n2->gmch_m, m2_n2->gmch_n, !adjust) && > + intel_compare_m_n(m_n->link_m, m_n->link_n, > + m2_n2->link_m, m2_n2->link_n, !adjust)) { > + if (adjust) > + *m2_n2 = *m_n; > + > + return true; > + } > + > + return false; > +} > + > +static bool > +intel_compare_infoframe(const union hdmi_infoframe *a, > + const union hdmi_infoframe *b) > +{ > + return memcmp(a, b, sizeof(*a)) == 0; > +} > + > +static void > +pipe_config_infoframe_err(struct drm_i915_private *dev_priv, > + bool adjust, const char *name, > + const union hdmi_infoframe *a, > + const union hdmi_infoframe *b) > +{ > + if (adjust) { > + if ((drm_debug & DRM_UT_KMS) == 0) > + return; > + > + drm_dbg(DRM_UT_KMS, "mismatch in %s infoframe", name); > + drm_dbg(DRM_UT_KMS, "expected:"); > + hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, a); > + drm_dbg(DRM_UT_KMS, "found"); > + hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, b); > + } else { > + drm_err("mismatch in %s infoframe", name); > + drm_err("expected:"); > + hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, a); > + drm_err("found"); > + hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, b); > + } > +} > + > +static void __printf(3, 4) > +pipe_config_err(bool adjust, const char *name, const char *format, ...) > +{ > + struct va_format vaf; > + va_list args; > + > + va_start(args, format); > + vaf.fmt = format; > + vaf.va = &args; > + > + if (adjust) > + drm_dbg(DRM_UT_KMS, "mismatch in %s %pV", name, &vaf); > + else > + drm_err("mismatch in %s %pV", name, &vaf); > + > + va_end(args); > +} > + > +static bool fastboot_enabled(struct drm_i915_private *dev_priv) > +{ > + if (i915_modparams.fastboot != -1) > + return i915_modparams.fastboot; > + > + /* Enable fastboot by default on Skylake and newer */ > + if (INTEL_GEN(dev_priv) >= 9) > + return true; > + > + /* Enable fastboot by default on VLV and CHV */ > + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) > + return true; > + > + /* Disabled by default on all others */ > + return false; > +} > + > +bool > +intel_pipe_config_compare(struct drm_i915_private *dev_priv, > + struct intel_crtc_state *current_config, > + struct intel_crtc_state *pipe_config, > + bool adjust) > +{ > + bool ret = true; > + bool fixup_inherited = adjust && > + (current_config->base.mode.private_flags & I915_MODE_FLAG_INHERITED) && > + !(pipe_config->base.mode.private_flags & I915_MODE_FLAG_INHERITED); > + > + if (fixup_inherited && !fastboot_enabled(dev_priv)) { > + DRM_DEBUG_KMS("initial modeset and fastboot not set\n"); > + ret = false; > + } > + > +#define PIPE_CONF_CHECK_X(name) do { \ > + if (current_config->name != pipe_config->name) { \ > + pipe_config_err(adjust, __stringify(name), \ > + "(expected 0x%08x, found 0x%08x)\n", \ > + current_config->name, \ > + pipe_config->name); \ > + ret = false; \ > + } \ > +} while (0) > + > +#define PIPE_CONF_CHECK_I(name) do { \ > + if (current_config->name != pipe_config->name) { \ > + pipe_config_err(adjust, __stringify(name), \ > + "(expected %i, found %i)\n", \ > + current_config->name, \ > + pipe_config->name); \ > + ret = false; \ > + } \ > +} while (0) > + > +#define PIPE_CONF_CHECK_BOOL(name) do { \ > + if (current_config->name != pipe_config->name) { \ > + pipe_config_err(adjust, __stringify(name), \ > + "(expected %s, found %s)\n", \ > + yesno(current_config->name), \ > + yesno(pipe_config->name)); \ > + ret = false; \ > + } \ > +} while (0) > + > +/* > + * Checks state where we only read out the enabling, but not the entire > + * state itself (like full infoframes or ELD for audio). These states > + * require a full modeset on bootup to fix up. > + */ > +#define PIPE_CONF_CHECK_BOOL_INCOMPLETE(name) do { \ > + if (!fixup_inherited || (!current_config->name && !pipe_config->name)) { \ > + PIPE_CONF_CHECK_BOOL(name); \ > + } else { \ > + pipe_config_err(adjust, __stringify(name), \ > + "unable to verify whether state matches exactly, forcing modeset (expected %s, found %s)\n", \ > + yesno(current_config->name), \ > + yesno(pipe_config->name)); \ > + ret = false; \ > + } \ > +} while (0) > + > +#define PIPE_CONF_CHECK_P(name) do { \ > + if (current_config->name != pipe_config->name) { \ > + pipe_config_err(adjust, __stringify(name), \ > + "(expected %p, found %p)\n", \ > + current_config->name, \ > + pipe_config->name); \ > + ret = false; \ > + } \ > +} while (0) > + > +#define PIPE_CONF_CHECK_M_N(name) do { \ > + if (!intel_compare_link_m_n(¤t_config->name, \ > + &pipe_config->name,\ > + adjust)) { \ > + pipe_config_err(adjust, __stringify(name), \ > + "(expected tu %i gmch %i/%i link %i/%i, " \ > + "found tu %i, gmch %i/%i link %i/%i)\n", \ > + current_config->name.tu, \ > + current_config->name.gmch_m, \ > + current_config->name.gmch_n, \ > + current_config->name.link_m, \ > + current_config->name.link_n, \ > + pipe_config->name.tu, \ > + pipe_config->name.gmch_m, \ > + pipe_config->name.gmch_n, \ > + pipe_config->name.link_m, \ > + pipe_config->name.link_n); \ > + ret = false; \ > + } \ > +} while (0) > + > +/* This is required for BDW+ where there is only one set of registers for > + * switching between high and low RR. > + * This macro can be used whenever a comparison has to be made between one > + * hw state and multiple sw state variables. > + */ > +#define PIPE_CONF_CHECK_M_N_ALT(name, alt_name) do { \ > + if (!intel_compare_link_m_n(¤t_config->name, \ > + &pipe_config->name, adjust) && \ > + !intel_compare_link_m_n(¤t_config->alt_name, \ > + &pipe_config->name, adjust)) { \ > + pipe_config_err(adjust, __stringify(name), \ > + "(expected tu %i gmch %i/%i link %i/%i, " \ > + "or tu %i gmch %i/%i link %i/%i, " \ > + "found tu %i, gmch %i/%i link %i/%i)\n", \ > + current_config->name.tu, \ > + current_config->name.gmch_m, \ > + current_config->name.gmch_n, \ > + current_config->name.link_m, \ > + current_config->name.link_n, \ > + current_config->alt_name.tu, \ > + current_config->alt_name.gmch_m, \ > + current_config->alt_name.gmch_n, \ > + current_config->alt_name.link_m, \ > + current_config->alt_name.link_n, \ > + pipe_config->name.tu, \ > + pipe_config->name.gmch_m, \ > + pipe_config->name.gmch_n, \ > + pipe_config->name.link_m, \ > + pipe_config->name.link_n); \ > + ret = false; \ > + } \ > +} while (0) > + > +#define PIPE_CONF_CHECK_FLAGS(name, mask) do { \ > + if ((current_config->name ^ pipe_config->name) & (mask)) { \ > + pipe_config_err(adjust, __stringify(name), \ > + "(%x) (expected %i, found %i)\n", \ > + (mask), \ > + current_config->name & (mask), \ > + pipe_config->name & (mask)); \ > + ret = false; \ > + } \ > +} while (0) > + > +#define PIPE_CONF_CHECK_CLOCK_FUZZY(name) do { \ > + if (!intel_fuzzy_clock_check(current_config->name, pipe_config->name)) { \ > + pipe_config_err(adjust, __stringify(name), \ > + "(expected %i, found %i)\n", \ > + current_config->name, \ > + pipe_config->name); \ > + ret = false; \ > + } \ > +} while (0) > + > +#define PIPE_CONF_CHECK_INFOFRAME(name) do { \ > + if (!intel_compare_infoframe(¤t_config->infoframes.name, \ > + &pipe_config->infoframes.name)) { \ > + pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \ > + ¤t_config->infoframes.name, \ > + &pipe_config->infoframes.name); \ > + ret = false; \ > + } \ > +} while (0) > + > +#define PIPE_CONF_QUIRK(quirk) \ > + ((current_config->quirks | pipe_config->quirks) & (quirk)) > + > + PIPE_CONF_CHECK_I(cpu_transcoder); > + > + PIPE_CONF_CHECK_BOOL(has_pch_encoder); > + PIPE_CONF_CHECK_I(fdi_lanes); > + PIPE_CONF_CHECK_M_N(fdi_m_n); > + > + PIPE_CONF_CHECK_I(lane_count); > + PIPE_CONF_CHECK_X(lane_lat_optim_mask); > + > + if (INTEL_GEN(dev_priv) < 8) { > + PIPE_CONF_CHECK_M_N(dp_m_n); > + > + if (current_config->has_drrs) > + PIPE_CONF_CHECK_M_N(dp_m2_n2); > + } else > + PIPE_CONF_CHECK_M_N_ALT(dp_m_n, dp_m2_n2); > + > + PIPE_CONF_CHECK_X(output_types); > + > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hdisplay); > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_htotal); > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_start); > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_end); > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hsync_start); > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hsync_end); > + > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vdisplay); > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vtotal); > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vblank_start); > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vblank_end); > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_start); > + PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_end); > + > + PIPE_CONF_CHECK_I(pixel_multiplier); > + PIPE_CONF_CHECK_I(output_format); > + PIPE_CONF_CHECK_BOOL(has_hdmi_sink); > + if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) || > + IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) > + PIPE_CONF_CHECK_BOOL(limited_color_range); > + > + PIPE_CONF_CHECK_BOOL(hdmi_scrambling); > + PIPE_CONF_CHECK_BOOL(hdmi_high_tmds_clock_ratio); > + PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_infoframe); > + > + PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio); > + > + PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags, > + DRM_MODE_FLAG_INTERLACE); > + > + if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) { > + PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags, > + DRM_MODE_FLAG_PHSYNC); > + PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags, > + DRM_MODE_FLAG_NHSYNC); > + PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags, > + DRM_MODE_FLAG_PVSYNC); > + PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags, > + DRM_MODE_FLAG_NVSYNC); > + } > + > + PIPE_CONF_CHECK_X(gmch_pfit.control); > + /* pfit ratios are autocomputed by the hw on gen4+ */ > + if (INTEL_GEN(dev_priv) < 4) > + PIPE_CONF_CHECK_X(gmch_pfit.pgm_ratios); > + PIPE_CONF_CHECK_X(gmch_pfit.lvds_border_bits); > + > + if (!adjust) { > + PIPE_CONF_CHECK_I(pipe_src_w); > + PIPE_CONF_CHECK_I(pipe_src_h); > + > + PIPE_CONF_CHECK_BOOL(pch_pfit.enabled); > + if (current_config->pch_pfit.enabled) { > + PIPE_CONF_CHECK_X(pch_pfit.pos); > + PIPE_CONF_CHECK_X(pch_pfit.size); > + } > + > + PIPE_CONF_CHECK_I(scaler_state.scaler_id); > + PIPE_CONF_CHECK_CLOCK_FUZZY(pixel_rate); > + > + PIPE_CONF_CHECK_X(gamma_mode); > + if (IS_CHERRYVIEW(dev_priv)) > + PIPE_CONF_CHECK_X(cgm_mode); > + else > + PIPE_CONF_CHECK_X(csc_mode); > + PIPE_CONF_CHECK_BOOL(gamma_enable); > + PIPE_CONF_CHECK_BOOL(csc_enable); > + } > + > + PIPE_CONF_CHECK_BOOL(double_wide); > + > + PIPE_CONF_CHECK_P(shared_dpll); > + PIPE_CONF_CHECK_X(dpll_hw_state.dpll); > + PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md); > + PIPE_CONF_CHECK_X(dpll_hw_state.fp0); > + PIPE_CONF_CHECK_X(dpll_hw_state.fp1); > + PIPE_CONF_CHECK_X(dpll_hw_state.wrpll); > + PIPE_CONF_CHECK_X(dpll_hw_state.spll); > + PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1); > + PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1); > + PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2); > + PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr0); > + PIPE_CONF_CHECK_X(dpll_hw_state.ebb0); > + PIPE_CONF_CHECK_X(dpll_hw_state.ebb4); > + PIPE_CONF_CHECK_X(dpll_hw_state.pll0); > + PIPE_CONF_CHECK_X(dpll_hw_state.pll1); > + PIPE_CONF_CHECK_X(dpll_hw_state.pll2); > + PIPE_CONF_CHECK_X(dpll_hw_state.pll3); > + PIPE_CONF_CHECK_X(dpll_hw_state.pll6); > + PIPE_CONF_CHECK_X(dpll_hw_state.pll8); > + PIPE_CONF_CHECK_X(dpll_hw_state.pll9); > + PIPE_CONF_CHECK_X(dpll_hw_state.pll10); > + PIPE_CONF_CHECK_X(dpll_hw_state.pcsdw12); > + PIPE_CONF_CHECK_X(dpll_hw_state.mg_refclkin_ctl); > + PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_coreclkctl1); > + PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_hsclkctl); > + PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div0); > + PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div1); > + PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_lf); > + PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_frac_lock); > + PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_ssc); > + PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_bias); > + PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_tdc_coldst_bias); > + > + PIPE_CONF_CHECK_X(dsi_pll.ctrl); > + PIPE_CONF_CHECK_X(dsi_pll.div); > + > + if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) > + PIPE_CONF_CHECK_I(pipe_bpp); > + > + PIPE_CONF_CHECK_CLOCK_FUZZY(base.adjusted_mode.crtc_clock); > + PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock); > + > + PIPE_CONF_CHECK_I(min_voltage_level); > + > + PIPE_CONF_CHECK_X(infoframes.enable); > + PIPE_CONF_CHECK_X(infoframes.gcp); > + PIPE_CONF_CHECK_INFOFRAME(avi); > + PIPE_CONF_CHECK_INFOFRAME(spd); > + PIPE_CONF_CHECK_INFOFRAME(hdmi); > + > +#undef PIPE_CONF_CHECK_X > +#undef PIPE_CONF_CHECK_I > +#undef PIPE_CONF_CHECK_BOOL > +#undef PIPE_CONF_CHECK_BOOL_INCOMPLETE > +#undef PIPE_CONF_CHECK_P > +#undef PIPE_CONF_CHECK_FLAGS > +#undef PIPE_CONF_CHECK_CLOCK_FUZZY > +#undef PIPE_CONF_QUIRK > + > + return ret; > +} > + > +void intel_pipe_config_sanity_check(struct drm_i915_private *dev_priv, > + const struct intel_crtc_state *pipe_config) > +{ > + if (pipe_config->has_pch_encoder) { > + int fdi_dotclock = intel_dotclock_calculate(intel_fdi_link_freq(dev_priv, pipe_config), > + &pipe_config->fdi_m_n); > + int dotclock = pipe_config->base.adjusted_mode.crtc_clock; > + > + /* > + * FDI already provided one idea for the dotclock. > + * Yell if the encoder disagrees. > + */ > + WARN(!intel_fuzzy_clock_check(fdi_dotclock, dotclock), > + "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n", > + fdi_dotclock, dotclock); > + } > +} > + > static void verify_wm_state(struct drm_crtc *crtc, > struct drm_crtc_state *new_state) > { > diff --git a/drivers/gpu/drm/i915/intel_verify.h b/drivers/gpu/drm/i915/intel_verify.h > index 4b751ea..faaf8f 100644 > --- a/drivers/gpu/drm/i915/intel_verify.h > +++ b/drivers/gpu/drm/i915/intel_verify.h > @@ -10,7 +10,15 @@ struct drm_atomic_state; > struct drm_crtc; > struct drm_crtc_state; > struct drm_device; > +struct drm_i915_private; > +struct intel_crtc_state; > > +void intel_pipe_config_sanity_check(struct drm_i915_private *dev_priv, > + const struct intel_crtc_state *pipe_config); > +bool intel_pipe_config_compare(struct drm_i915_private *dev_priv, > + struct intel_crtc_state *current_config, > + struct intel_crtc_state *pipe_config, > + bool adjust); > void intel_verify_modeset_crtc(struct drm_crtc *crtc, > struct drm_atomic_state *state, > struct drm_crtc_state *old_state, > -- > 2.20.1 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx