diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display')
127 files changed, 6543 insertions, 3332 deletions
diff --git a/drivers/gpu/drm/i915/display/g4x_dp.h b/drivers/gpu/drm/i915/display/g4x_dp.h index a38b3e1e01..a10638ab74 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.h +++ b/drivers/gpu/drm/i915/display/g4x_dp.h @@ -17,6 +17,7 @@ struct intel_crtc_state; struct intel_dp; struct intel_encoder; +#ifdef I915 const struct dpll *vlv_get_dpll(struct drm_i915_private *i915); enum pipe vlv_active_pipe(struct intel_dp *intel_dp); void g4x_dp_set_clock(struct intel_encoder *encoder, @@ -26,5 +27,30 @@ bool g4x_dp_port_enabled(struct drm_i915_private *dev_priv, enum pipe *pipe); bool g4x_dp_init(struct drm_i915_private *dev_priv, i915_reg_t output_reg, enum port port); +#else +static inline const struct dpll *vlv_get_dpll(struct drm_i915_private *i915) +{ + return NULL; +} +static inline int vlv_active_pipe(struct intel_dp *intel_dp) +{ + return 0; +} +static inline void g4x_dp_set_clock(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config) +{ +} +static inline bool g4x_dp_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t dp_reg, int port, + enum pipe *pipe) +{ + return false; +} +static inline bool g4x_dp_init(struct drm_i915_private *dev_priv, + i915_reg_t output_reg, int port) +{ + return false; +} +#endif #endif diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 634b14116d..45e044b4a8 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -16,6 +16,7 @@ #include "intel_display_types.h" #include "intel_dp_aux.h" #include "intel_dpio_phy.h" +#include "intel_fdi.h" #include "intel_fifo_underrun.h" #include "intel_hdmi.h" #include "intel_hotplug.h" @@ -133,8 +134,11 @@ static int g4x_hdmi_compute_config(struct intel_encoder *encoder, struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(encoder->base.dev); - if (HAS_PCH_SPLIT(i915)) + if (HAS_PCH_SPLIT(i915)) { crtc_state->has_pch_encoder = true; + if (!intel_fdi_compute_pipe_bpp(crtc_state)) + return -EINVAL; + } if (IS_G4X(i915)) crtc_state->has_hdmi_sink = g4x_compute_has_hdmi_sink(state, crtc); diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.h b/drivers/gpu/drm/i915/display/g4x_hdmi.h index 1e3ea7f3c8..817f55c7a3 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.h +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.h @@ -15,9 +15,21 @@ struct drm_atomic_state; struct drm_connector; struct drm_i915_private; +#ifdef I915 void g4x_hdmi_init(struct drm_i915_private *dev_priv, i915_reg_t hdmi_reg, enum port port); int g4x_hdmi_connector_atomic_check(struct drm_connector *connector, struct drm_atomic_state *state); +#else +static inline void g4x_hdmi_init(struct drm_i915_private *dev_priv, + i915_reg_t hdmi_reg, int port) +{ +} +static inline int g4x_hdmi_connector_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state) +{ + return 0; +} +#endif #endif diff --git a/drivers/gpu/drm/i915/display/hsw_ips.c b/drivers/gpu/drm/i915/display/hsw_ips.c index 8eca0de065..7dc38ac020 100644 --- a/drivers/gpu/drm/i915/display/hsw_ips.c +++ b/drivers/gpu/drm/i915/display/hsw_ips.c @@ -6,6 +6,7 @@ #include "hsw_ips.h" #include "i915_drv.h" #include "i915_reg.h" +#include "intel_color_regs.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_pcode.h" diff --git a/drivers/gpu/drm/i915/display/hsw_ips.h b/drivers/gpu/drm/i915/display/hsw_ips.h index 4eb83b3507..35364228e1 100644 --- a/drivers/gpu/drm/i915/display/hsw_ips.h +++ b/drivers/gpu/drm/i915/display/hsw_ips.h @@ -12,6 +12,7 @@ struct intel_atomic_state; struct intel_crtc; struct intel_crtc_state; +#ifdef I915 bool hsw_ips_disable(const struct intel_crtc_state *crtc_state); bool hsw_ips_pre_update(struct intel_atomic_state *state, struct intel_crtc *crtc); @@ -23,5 +24,39 @@ int hsw_ips_compute_config(struct intel_atomic_state *state, struct intel_crtc *crtc); void hsw_ips_get_config(struct intel_crtc_state *crtc_state); void hsw_ips_crtc_debugfs_add(struct intel_crtc *crtc); +#else +static inline bool hsw_ips_disable(const struct intel_crtc_state *crtc_state) +{ + return false; +} +static inline bool hsw_ips_pre_update(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + return false; +} +static inline void hsw_ips_post_update(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline bool hsw_crtc_supports_ips(struct intel_crtc *crtc) +{ + return false; +} +static inline bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state) +{ + return false; +} +static inline int hsw_ips_compute_config(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + return 0; +} +static inline void hsw_ips_get_config(struct intel_crtc_state *crtc_state) +{ +} +static inline void hsw_ips_crtc_debugfs_add(struct intel_crtc *crtc) +{ +} +#endif #endif /* __HSW_IPS_H__ */ diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index b104883244..91f2bc405c 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -17,6 +17,7 @@ #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fbc.h" +#include "intel_frontbuffer.h" #include "intel_sprite.h" /* Primary plane formats for gen <= 3 */ diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.h b/drivers/gpu/drm/i915/display/i9xx_plane.h index 027b660539..b3d724a144 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.h +++ b/drivers/gpu/drm/i915/display/i9xx_plane.h @@ -15,6 +15,7 @@ struct intel_initial_plane_config; struct intel_plane; struct intel_plane_state; +#ifdef I915 unsigned int i965_plane_max_stride(struct intel_plane *plane, u32 pixel_format, u64 modifier, unsigned int rotation); @@ -25,4 +26,26 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe); void i9xx_get_initial_plane_config(struct intel_crtc *crtc, struct intel_initial_plane_config *plane_config); +#else +static inline unsigned int i965_plane_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation) +{ + return 0; +} +static inline int i9xx_check_plane_surface(struct intel_plane_state *plane_state) +{ + return 0; +} +static inline struct intel_plane * +intel_primary_plane_create(struct drm_i915_private *dev_priv, int pipe) +{ + return NULL; +} +static inline void i9xx_get_initial_plane_config(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config) +{ +} +#endif + #endif diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.h b/drivers/gpu/drm/i915/display/i9xx_wm.h index b87ae36968..de0920730a 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.h +++ b/drivers/gpu/drm/i915/display/i9xx_wm.h @@ -12,9 +12,26 @@ struct drm_i915_private; struct intel_crtc_state; struct intel_plane_state; +#ifdef I915 bool ilk_disable_lp_wm(struct drm_i915_private *i915); void ilk_wm_sanitize(struct drm_i915_private *i915); bool intel_set_memory_cxsr(struct drm_i915_private *i915, bool enable); void i9xx_wm_init(struct drm_i915_private *i915); +#else +static inline bool ilk_disable_lp_wm(struct drm_i915_private *i915) +{ + return false; +} +static inline void ilk_wm_sanitize(struct drm_i915_private *i915) +{ +} +static inline bool intel_set_memory_cxsr(struct drm_i915_private *i915, bool enable) +{ + return false; +} +static inline void i9xx_wm_init(struct drm_i915_private *i915) +{ +} +#endif #endif /* __I9XX_WM_H__ */ diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index f7113b0321..bf0dbd7d06 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1828,7 +1828,7 @@ static void icl_dphy_param_init(struct intel_dsi *intel_dsi) u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt; u32 ths_prepare_ns, tclk_trail_ns; u32 hs_zero_cnt; - u32 tclk_pre_cnt, tclk_post_cnt; + u32 tclk_pre_cnt; tlpx_ns = intel_dsi_tlpx_ns(intel_dsi); @@ -1875,15 +1875,6 @@ static void icl_dphy_param_init(struct intel_dsi *intel_dsi) tclk_pre_cnt = ICL_TCLK_PRE_CNT_MAX; } - /* tclk post count in escape clocks */ - tclk_post_cnt = DIV_ROUND_UP(mipi_config->tclk_post, tlpx_ns); - if (tclk_post_cnt > ICL_TCLK_POST_CNT_MAX) { - drm_dbg_kms(&dev_priv->drm, - "tclk_post_cnt out of range (%d)\n", - tclk_post_cnt); - tclk_post_cnt = ICL_TCLK_POST_CNT_MAX; - } - /* hs zero cnt in escape clocks */ hs_zero_cnt = DIV_ROUND_UP(mipi_config->ths_prepare_hszero - ths_prepare_ns, tlpx_ns); @@ -1909,8 +1900,6 @@ static void icl_dphy_param_init(struct intel_dsi *intel_dsi) CLK_ZERO(clk_zero_cnt) | CLK_PRE_OVERRIDE | CLK_PRE(tclk_pre_cnt) | - CLK_POST_OVERRIDE | - CLK_POST(tclk_post_cnt) | CLK_TRAIL_OVERRIDE | CLK_TRAIL(trail_cnt)); diff --git a/drivers/gpu/drm/i915/display/intel_acpi.c b/drivers/gpu/drm/i915/display/intel_acpi.c index 9df78e7caa..0aa3999374 100644 --- a/drivers/gpu/drm/i915/display/intel_acpi.c +++ b/drivers/gpu/drm/i915/display/intel_acpi.c @@ -153,7 +153,7 @@ static acpi_handle intel_dsm_pci_probe(struct pci_dev *pdev) static bool intel_dsm_detect(void) { acpi_handle dhandle = NULL; - char acpi_method_name[255] = { 0 }; + char acpi_method_name[255] = {}; struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; struct pci_dev *pdev = NULL; int vga_count = 0; diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index 7cf51dd8c0..5d18145da2 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -259,6 +259,8 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) drm_property_blob_get(crtc_state->post_csc_lut); crtc_state->update_pipe = false; + crtc_state->update_m_n = false; + crtc_state->update_lrr = false; crtc_state->disable_lp_wm = false; crtc_state->disable_cxsr = false; crtc_state->update_wm_pre = false; diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index 60a492e186..b107435061 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -214,9 +214,6 @@ intel_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, int width, height; unsigned int rel_data_rate; - if (plane->id == PLANE_CURSOR) - return 0; - if (!plane_state->uapi.visible) return 0; @@ -244,6 +241,9 @@ intel_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, rel_data_rate = width * height * fb->format->cpp[color_plane]; + if (plane->id == PLANE_CURSOR) + return rel_data_rate; + return intel_adjusted_rate(&plane_state->uapi.src, &plane_state->uapi.dst, rel_data_rate); @@ -981,6 +981,14 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) if (fb->format->format == DRM_FORMAT_RGB565 && rotated) { hsub = 2; vsub = 2; + } else if (DISPLAY_VER(i915) >= 20 && + intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) { + /* + * This allows NV12 and P0xx formats to have odd size and/or odd + * source coordinates on DISPLAY_VER(i915) >= 20 + */ + hsub = 1; + vsub = 1; } else { hsub = fb->format->hsub; vsub = fb->format->vsub; diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 3d9c9b4f27..19605264a3 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -759,10 +759,10 @@ static void ibx_audio_codec_enable(struct intel_encoder *encoder, mutex_unlock(&i915->display.audio.mutex); } -void intel_audio_sdp_split_update(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum transcoder trans = crtc_state->cpu_transcoder; if (HAS_DP20(i915)) diff --git a/drivers/gpu/drm/i915/display/intel_audio.h b/drivers/gpu/drm/i915/display/intel_audio.h index 07d034a981..9327954b80 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.h +++ b/drivers/gpu/drm/i915/display/intel_audio.h @@ -29,7 +29,6 @@ void intel_audio_cdclk_change_pre(struct drm_i915_private *dev_priv); void intel_audio_cdclk_change_post(struct drm_i915_private *dev_priv); void intel_audio_init(struct drm_i915_private *dev_priv); void intel_audio_deinit(struct drm_i915_private *dev_priv); -void intel_audio_sdp_split_update(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state); +void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state); #endif /* __INTEL_AUDIO_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index f735b03543..4e8f1e91bb 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -521,7 +521,8 @@ static void init_bdb_blocks(struct drm_i915_private *i915, } static void -fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, +fill_detail_timing_data(struct drm_i915_private *i915, + struct drm_display_mode *panel_fixed_mode, const struct lvds_dvo_timing *dvo_timing) { panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | @@ -561,11 +562,17 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, panel_fixed_mode->height_mm = (dvo_timing->vimage_hi << 8) | dvo_timing->vimage_lo; - /* Some VBTs have bogus h/vtotal values */ - if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) - panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; - if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) - panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; + /* Some VBTs have bogus h/vsync_end values */ + if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) { + drm_dbg_kms(&i915->drm, "reducing hsync_end %d->%d\n", + panel_fixed_mode->hsync_end, panel_fixed_mode->htotal); + panel_fixed_mode->hsync_end = panel_fixed_mode->htotal; + } + if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) { + drm_dbg_kms(&i915->drm, "reducing vsync_end %d->%d\n", + panel_fixed_mode->vsync_end, panel_fixed_mode->vtotal); + panel_fixed_mode->vsync_end = panel_fixed_mode->vtotal; + } drm_mode_set_name(panel_fixed_mode); } @@ -849,7 +856,7 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915, if (!panel_fixed_mode) return; - fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); + fill_detail_timing_data(i915, panel_fixed_mode, panel_dvo_timing); panel->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; @@ -1134,7 +1141,7 @@ parse_sdvo_panel_data(struct drm_i915_private *i915, if (!panel_fixed_mode) return; - fill_detail_timing_data(panel_fixed_mode, &dtds->dtds[index]); + fill_detail_timing_data(i915, panel_fixed_mode, &dtds->dtds[index]); panel->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; @@ -2194,7 +2201,8 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) const u8 *ddc_pin_map; int i, n_entries; - if (HAS_PCH_MTP(i915) || IS_ALDERLAKE_P(i915)) { + if (INTEL_PCH_TYPE(i915) >= PCH_LNL || HAS_PCH_MTP(i915) || + IS_ALDERLAKE_P(i915)) { ddc_pin_map = adlp_ddc_pin_map; n_entries = ARRAY_SIZE(adlp_ddc_pin_map); } else if (IS_ALDERLAKE_S(i915)) { diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index f99cf8037b..c4839c67cb 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -32,6 +32,7 @@ #include "intel_cdclk.h" #include "intel_crtc.h" #include "intel_de.h" +#include "intel_dp.h" #include "intel_display_types.h" #include "intel_mchbar_regs.h" #include "intel_pci_config.h" @@ -1381,6 +1382,31 @@ static const struct intel_cdclk_vals mtl_cdclk_table[] = { {} }; +static const struct intel_cdclk_vals lnl_cdclk_table[] = { + { .refclk = 38400, .cdclk = 153600, .divider = 2, .ratio = 16, .waveform = 0xaaaa }, + { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a }, + { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 }, + { .refclk = 38400, .cdclk = 211200, .divider = 2, .ratio = 16, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 230400, .divider = 2, .ratio = 16, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 249600, .divider = 2, .ratio = 16, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 268800, .divider = 2, .ratio = 16, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 288000, .divider = 2, .ratio = 16, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 330000, .divider = 2, .ratio = 25, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 360000, .divider = 2, .ratio = 25, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 390000, .divider = 2, .ratio = 25, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 420000, .divider = 2, .ratio = 25, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 450000, .divider = 2, .ratio = 25, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 487200, .divider = 2, .ratio = 29, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 522000, .divider = 2, .ratio = 29, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff }, + {} +}; + static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk) { const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table; @@ -1840,9 +1866,10 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91 static bool pll_enable_wa_needed(struct drm_i915_private *dev_priv) { - return ((IS_DG2(dev_priv) || IS_METEORLAKE(dev_priv)) && - dev_priv->display.cdclk.hw.vco > 0 && - HAS_CDCLK_SQUASH(dev_priv)); + return (DISPLAY_VER_FULL(dev_priv) == IP_VER(20, 0) || + DISPLAY_VER_FULL(dev_priv) == IP_VER(14, 0) || + IS_DG2(dev_priv)) && + dev_priv->display.cdclk.hw.vco > 0; } static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, @@ -1879,8 +1906,7 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, dg2_cdclk_squash_program(dev_priv, waveform); val = bxt_cdclk_cd2x_div_sel(dev_priv, clock, vco) | - bxt_cdclk_cd2x_pipe(dev_priv, pipe) | - skl_cdclk_decimal(cdclk); + bxt_cdclk_cd2x_pipe(dev_priv, pipe); /* * Disable SSA Precharge when CD clock frequency < 500 MHz, @@ -1889,6 +1915,12 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) && cdclk >= 500000) val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; + + if (DISPLAY_VER(dev_priv) >= 20) + val |= MDCLK_SOURCE_SEL_CDCLK_PLL; + else + val |= skl_cdclk_decimal(cdclk); + intel_de_write(dev_priv, CDCLK_CTL, val); if (pipe != INVALID_PIPE) @@ -2533,6 +2565,48 @@ static int intel_planes_min_cdclk(const struct intel_crtc_state *crtc_state) return min_cdclk; } +static int intel_vdsc_min_cdclk(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); + int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state); + int min_cdclk = 0; + + /* + * When we decide to use only one VDSC engine, since + * each VDSC operates with 1 ppc throughput, pixel clock + * cannot be higher than the VDSC clock (cdclk) + * If there 2 VDSC engines, then pixel clock can't be higher than + * VDSC clock(cdclk) * 2 and so on. + */ + min_cdclk = max_t(int, min_cdclk, + DIV_ROUND_UP(crtc_state->pixel_rate, num_vdsc_instances)); + + if (crtc_state->bigjoiner_pipes) { + int pixel_clock = intel_dp_mode_to_fec_clock(crtc_state->hw.adjusted_mode.clock); + + /* + * According to Bigjoiner bw check: + * compressed_bpp <= PPC * CDCLK * Big joiner Interface bits / Pixel clock + * + * We have already computed compressed_bpp, so now compute the min CDCLK that + * is required to support this compressed_bpp. + * + * => CDCLK >= compressed_bpp * Pixel clock / (PPC * Bigjoiner Interface bits) + * + * Since PPC = 2 with bigjoiner + * => CDCLK >= compressed_bpp * Pixel clock / 2 * Bigjoiner Interface bits + */ + int bigjoiner_interface_bits = DISPLAY_VER(i915) > 13 ? 36 : 24; + int min_cdclk_bj = (crtc_state->dsc.compressed_bpp * pixel_clock) / + (2 * bigjoiner_interface_bits); + + min_cdclk = max(min_cdclk, min_cdclk_bj); + } + + return min_cdclk; +} + int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = @@ -2604,20 +2678,8 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) /* Account for additional needs from the planes */ min_cdclk = max(intel_planes_min_cdclk(crtc_state), min_cdclk); - /* - * When we decide to use only one VDSC engine, since - * each VDSC operates with 1 ppc throughput, pixel clock - * cannot be higher than the VDSC clock (cdclk) - * If there 2 VDSC engines, then pixel clock can't be higher than - * VDSC clock(cdclk) * 2 and so on. - */ - if (crtc_state->dsc.compression_enable) { - int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state); - - min_cdclk = max_t(int, min_cdclk, - DIV_ROUND_UP(crtc_state->pixel_rate, - num_vdsc_instances)); - } + if (crtc_state->dsc.compression_enable) + min_cdclk = max(min_cdclk, intel_vdsc_min_cdclk(crtc_state)); /* * HACK. Currently for TGL/DG2 platforms we calculate @@ -3120,7 +3182,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) } else if (intel_cdclk_needs_modeset(&old_cdclk_state->actual, &new_cdclk_state->actual)) { /* All pipes must be switched off while we change the cdclk. */ - ret = intel_modeset_all_pipes(state, "CDCLK change"); + ret = intel_modeset_all_pipes_late(state, "CDCLK change"); if (ret) return ret; @@ -3571,7 +3633,10 @@ static const struct intel_cdclk_funcs i830_cdclk_funcs = { */ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) { - if (IS_METEORLAKE(dev_priv)) { + if (DISPLAY_VER(dev_priv) >= 20) { + dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs; + dev_priv->display.cdclk.table = lnl_cdclk_table; + } else if (DISPLAY_VER(dev_priv) >= 14) { dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs; dev_priv->display.cdclk.table = mtl_cdclk_table; } else if (IS_DG2(dev_priv)) { diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 454607b4a0..1d26be54dd 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -24,6 +24,7 @@ #include "i915_reg.h" #include "intel_color.h" +#include "intel_color_regs.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_dsb.h" @@ -75,6 +76,10 @@ struct intel_color_funcs { * software state. Used by eg. the hardware state checker. */ void (*read_csc)(struct intel_crtc_state *crtc_state); + /* + * Read config other than LUTs and CSCs, before them. Optional. + */ + void (*get_config)(struct intel_crtc_state *crtc_state); }; #define CTM_COEFF_SIGN (1ULL << 63) @@ -1013,6 +1018,65 @@ static void hsw_color_commit_arm(const struct intel_crtc_state *crtc_state) crtc_state->csc_mode); } +static u32 hsw_read_gamma_mode(struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + return intel_de_read(i915, GAMMA_MODE(crtc->pipe)); +} + +static u32 ilk_read_csc_mode(struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + return intel_de_read(i915, PIPE_CSC_MODE(crtc->pipe)); +} + +static void i9xx_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct intel_plane *plane = to_intel_plane(crtc->base.primary); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + u32 tmp; + + tmp = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); + + if (tmp & DISP_PIPE_GAMMA_ENABLE) + crtc_state->gamma_enable = true; + + if (!HAS_GMCH(dev_priv) && tmp & DISP_PIPE_CSC_ENABLE) + crtc_state->csc_enable = true; +} + +static void hsw_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + + crtc_state->gamma_mode = hsw_read_gamma_mode(crtc); + crtc_state->csc_mode = ilk_read_csc_mode(crtc); + + i9xx_get_config(crtc_state); +} + +static void skl_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + u32 tmp; + + crtc_state->gamma_mode = hsw_read_gamma_mode(crtc); + crtc_state->csc_mode = ilk_read_csc_mode(crtc); + + tmp = intel_de_read(i915, SKL_BOTTOM_COLOR(crtc->pipe)); + + if (tmp & SKL_BOTTOM_COLOR_GAMMA_ENABLE) + crtc_state->gamma_enable = true; + + if (tmp & SKL_BOTTOM_COLOR_CSC_ENABLE) + crtc_state->csc_enable = true; +} + static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -1265,9 +1329,20 @@ static void ilk_load_lut_8(const struct intel_crtc_state *crtc_state, lut = blob->data; + /* + * DSB fails to correctly load the legacy LUT + * unless we either write each entry twice, + * or use non-posted writes + */ + if (crtc_state->dsb) + intel_dsb_nonpost_start(crtc_state->dsb); + for (i = 0; i < 256; i++) ilk_lut_write(crtc_state, LGC_PALETTE(pipe, i), i9xx_lut_8(&lut[i])); + + if (crtc_state->dsb) + intel_dsb_nonpost_end(crtc_state->dsb); } static void ilk_load_lut_10(const struct intel_crtc_state *crtc_state, @@ -1677,12 +1752,6 @@ static void icl_load_luts(const struct intel_crtc_state *crtc_state) MISSING_CASE(crtc_state->gamma_mode); break; } - - if (crtc_state->dsb) { - intel_dsb_finish(crtc_state->dsb); - intel_dsb_commit(crtc_state->dsb, false); - intel_dsb_wait(crtc_state->dsb); - } } static void vlv_load_luts(const struct intel_crtc_state *crtc_state) @@ -1789,6 +1858,9 @@ void intel_color_load_luts(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + if (crtc_state->dsb) + return; + i915->display.funcs.color->load_luts(crtc_state); } @@ -1805,6 +1877,9 @@ void intel_color_commit_arm(const struct intel_crtc_state *crtc_state) struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); i915->display.funcs.color->color_commit_arm(crtc_state); + + if (crtc_state->dsb) + intel_dsb_commit(crtc_state->dsb, true); } void intel_color_post_update(const struct intel_crtc_state *crtc_state) @@ -1818,14 +1893,22 @@ void intel_color_post_update(const struct intel_crtc_state *crtc_state) void intel_color_prepare_commit(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); - /* FIXME DSB has issues loading LUTs, disable it for now */ - return; + if (!crtc_state->hw.active || + intel_crtc_needs_modeset(crtc_state)) + return; if (!crtc_state->pre_csc_lut && !crtc_state->post_csc_lut) return; - crtc_state->dsb = intel_dsb_prepare(crtc, 1024); + crtc_state->dsb = intel_dsb_prepare(crtc_state, 1024); + if (!crtc_state->dsb) + return; + + i915->display.funcs.color->load_luts(crtc_state); + + intel_dsb_finish(crtc_state->dsb); } void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state) @@ -1837,6 +1920,17 @@ void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state) crtc_state->dsb = NULL; } +void intel_color_wait_commit(const struct intel_crtc_state *crtc_state) +{ + if (crtc_state->dsb) + intel_dsb_wait(crtc_state->dsb); +} + +bool intel_color_uses_dsb(const struct intel_crtc_state *crtc_state) +{ + return crtc_state->dsb; +} + static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state) { struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); @@ -1891,6 +1985,9 @@ void intel_color_get_config(struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + if (i915->display.funcs.color->get_config) + i915->display.funcs.color->get_config(crtc_state); + i915->display.funcs.color->read_luts(crtc_state); if (i915->display.funcs.color->read_csc) @@ -2865,16 +2962,16 @@ static int icl_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state) return 16; } -static bool err_check(struct drm_color_lut *lut1, - struct drm_color_lut *lut2, u32 err) +static bool err_check(const struct drm_color_lut *lut1, + const struct drm_color_lut *lut2, u32 err) { return ((abs((long)lut2->red - lut1->red)) <= err) && ((abs((long)lut2->blue - lut1->blue)) <= err) && ((abs((long)lut2->green - lut1->green)) <= err); } -static bool intel_lut_entries_equal(struct drm_color_lut *lut1, - struct drm_color_lut *lut2, +static bool intel_lut_entries_equal(const struct drm_color_lut *lut1, + const struct drm_color_lut *lut2, int lut_size, u32 err) { int i; @@ -2891,7 +2988,7 @@ static bool intel_lut_equal(const struct drm_property_blob *blob1, const struct drm_property_blob *blob2, int check_size, int precision) { - struct drm_color_lut *lut1, *lut2; + const struct drm_color_lut *lut1, *lut2; int lut_size1, lut_size2; u32 err; @@ -3204,6 +3301,16 @@ static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc) return blob; } +static void chv_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + crtc_state->cgm_mode = intel_de_read(i915, CGM_PIPE_MODE(crtc->pipe)); + + i9xx_get_config(crtc_state); +} + static void chv_read_luts(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -3267,6 +3374,15 @@ static struct drm_property_blob *ilk_read_lut_10(struct intel_crtc *crtc) return blob; } +static void ilk_get_config(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + + crtc_state->csc_mode = ilk_read_csc_mode(crtc); + + i9xx_get_config(crtc_state); +} + static void ilk_read_luts(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -3573,6 +3689,7 @@ static const struct intel_color_funcs chv_color_funcs = { .read_luts = chv_read_luts, .lut_equal = chv_lut_equal, .read_csc = chv_read_csc, + .get_config = chv_get_config, }; static const struct intel_color_funcs vlv_color_funcs = { @@ -3582,6 +3699,7 @@ static const struct intel_color_funcs vlv_color_funcs = { .read_luts = i965_read_luts, .lut_equal = i965_lut_equal, .read_csc = vlv_read_csc, + .get_config = i9xx_get_config, }; static const struct intel_color_funcs i965_color_funcs = { @@ -3590,6 +3708,7 @@ static const struct intel_color_funcs i965_color_funcs = { .load_luts = i965_load_luts, .read_luts = i965_read_luts, .lut_equal = i965_lut_equal, + .get_config = i9xx_get_config, }; static const struct intel_color_funcs i9xx_color_funcs = { @@ -3598,6 +3717,7 @@ static const struct intel_color_funcs i9xx_color_funcs = { .load_luts = i9xx_load_luts, .read_luts = i9xx_read_luts, .lut_equal = i9xx_lut_equal, + .get_config = i9xx_get_config, }; static const struct intel_color_funcs tgl_color_funcs = { @@ -3608,6 +3728,7 @@ static const struct intel_color_funcs tgl_color_funcs = { .read_luts = icl_read_luts, .lut_equal = icl_lut_equal, .read_csc = icl_read_csc, + .get_config = skl_get_config, }; static const struct intel_color_funcs icl_color_funcs = { @@ -3619,6 +3740,7 @@ static const struct intel_color_funcs icl_color_funcs = { .read_luts = icl_read_luts, .lut_equal = icl_lut_equal, .read_csc = icl_read_csc, + .get_config = skl_get_config, }; static const struct intel_color_funcs glk_color_funcs = { @@ -3629,6 +3751,7 @@ static const struct intel_color_funcs glk_color_funcs = { .read_luts = glk_read_luts, .lut_equal = glk_lut_equal, .read_csc = skl_read_csc, + .get_config = skl_get_config, }; static const struct intel_color_funcs skl_color_funcs = { @@ -3639,6 +3762,7 @@ static const struct intel_color_funcs skl_color_funcs = { .read_luts = bdw_read_luts, .lut_equal = ivb_lut_equal, .read_csc = skl_read_csc, + .get_config = skl_get_config, }; static const struct intel_color_funcs bdw_color_funcs = { @@ -3649,6 +3773,7 @@ static const struct intel_color_funcs bdw_color_funcs = { .read_luts = bdw_read_luts, .lut_equal = ivb_lut_equal, .read_csc = ilk_read_csc, + .get_config = hsw_get_config, }; static const struct intel_color_funcs hsw_color_funcs = { @@ -3659,6 +3784,7 @@ static const struct intel_color_funcs hsw_color_funcs = { .read_luts = ivb_read_luts, .lut_equal = ivb_lut_equal, .read_csc = ilk_read_csc, + .get_config = hsw_get_config, }; static const struct intel_color_funcs ivb_color_funcs = { @@ -3669,6 +3795,7 @@ static const struct intel_color_funcs ivb_color_funcs = { .read_luts = ivb_read_luts, .lut_equal = ivb_lut_equal, .read_csc = ilk_read_csc, + .get_config = ilk_get_config, }; static const struct intel_color_funcs ilk_color_funcs = { @@ -3679,6 +3806,7 @@ static const struct intel_color_funcs ilk_color_funcs = { .read_luts = ilk_read_luts, .lut_equal = ilk_lut_equal, .read_csc = ilk_read_csc, + .get_config = ilk_get_config, }; void intel_color_crtc_init(struct intel_crtc *crtc) diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h index 8002492be7..8ecd36149d 100644 --- a/drivers/gpu/drm/i915/display/intel_color.h +++ b/drivers/gpu/drm/i915/display/intel_color.h @@ -19,6 +19,8 @@ void intel_color_crtc_init(struct intel_crtc *crtc); int intel_color_check(struct intel_crtc_state *crtc_state); void intel_color_prepare_commit(struct intel_crtc_state *crtc_state); void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state); +bool intel_color_uses_dsb(const struct intel_crtc_state *crtc_state); +void intel_color_wait_commit(const struct intel_crtc_state *crtc_state); void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state); void intel_color_commit_arm(const struct intel_crtc_state *crtc_state); void intel_color_post_update(const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_color_regs.h b/drivers/gpu/drm/i915/display/intel_color_regs.h new file mode 100644 index 0000000000..9f4ae58f3e --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_color_regs.h @@ -0,0 +1,286 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_COLOR_REGS_H__ +#define __INTEL_COLOR_REGS_H__ + +#include "intel_display_reg_defs.h" + +/* legacy palette */ +#define _LGC_PALETTE_A 0x4a000 +#define _LGC_PALETTE_B 0x4a800 +/* see PALETTE_* for the bits */ +#define LGC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4) + +/* ilk/snb precision palette */ +#define _PREC_PALETTE_A 0x4b000 +#define _PREC_PALETTE_B 0x4c000 +/* 10bit mode */ +#define PREC_PALETTE_10_RED_MASK REG_GENMASK(29, 20) +#define PREC_PALETTE_10_GREEN_MASK REG_GENMASK(19, 10) +#define PREC_PALETTE_10_BLUE_MASK REG_GENMASK(9, 0) +/* 12.4 interpolated mode ldw */ +#define PREC_PALETTE_12P4_RED_LDW_MASK REG_GENMASK(29, 24) +#define PREC_PALETTE_12P4_GREEN_LDW_MASK REG_GENMASK(19, 14) +#define PREC_PALETTE_12P4_BLUE_LDW_MASK REG_GENMASK(9, 4) +/* 12.4 interpolated mode udw */ +#define PREC_PALETTE_12P4_RED_UDW_MASK REG_GENMASK(29, 20) +#define PREC_PALETTE_12P4_GREEN_UDW_MASK REG_GENMASK(19, 10) +#define PREC_PALETTE_12P4_BLUE_UDW_MASK REG_GENMASK(9, 0) +#define PREC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _PREC_PALETTE_A, _PREC_PALETTE_B) + (i) * 4) + +#define _PREC_PIPEAGCMAX 0x4d000 +#define _PREC_PIPEBGCMAX 0x4d010 +#define PREC_PIPEGCMAX(pipe, i) _MMIO(_PIPE(pipe, _PIPEAGCMAX, _PIPEBGCMAX) + (i) * 4) /* u1.16 */ + +#define _GAMMA_MODE_A 0x4a480 +#define _GAMMA_MODE_B 0x4ac80 +#define GAMMA_MODE(pipe) _MMIO_PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B) +#define PRE_CSC_GAMMA_ENABLE REG_BIT(31) /* icl+ */ +#define POST_CSC_GAMMA_ENABLE REG_BIT(30) /* icl+ */ +#define PALETTE_ANTICOL_DISABLE REG_BIT(15) /* skl+ */ +#define GAMMA_MODE_MODE_MASK REG_GENMASK(1, 0) +#define GAMMA_MODE_MODE_8BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 0) +#define GAMMA_MODE_MODE_10BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 1) +#define GAMMA_MODE_MODE_12BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 2) +#define GAMMA_MODE_MODE_SPLIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 3) /* ivb-bdw */ +#define GAMMA_MODE_MODE_12BIT_MULTI_SEG REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 3) /* icl-tgl */ + +/* pipe CSC */ +#define _PIPE_A_CSC_COEFF_RY_GY 0x49010 +#define _PIPE_A_CSC_COEFF_BY 0x49014 +#define _PIPE_A_CSC_COEFF_RU_GU 0x49018 +#define _PIPE_A_CSC_COEFF_BU 0x4901c +#define _PIPE_A_CSC_COEFF_RV_GV 0x49020 +#define _PIPE_A_CSC_COEFF_BV 0x49024 + +#define _PIPE_A_CSC_MODE 0x49028 +#define ICL_CSC_ENABLE (1 << 31) /* icl+ */ +#define ICL_OUTPUT_CSC_ENABLE (1 << 30) /* icl+ */ +#define CSC_BLACK_SCREEN_OFFSET (1 << 2) /* ilk/snb */ +#define CSC_POSITION_BEFORE_GAMMA (1 << 1) /* pre-glk */ +#define CSC_MODE_YUV_TO_RGB (1 << 0) /* ilk/snb */ + +#define _PIPE_A_CSC_PREOFF_HI 0x49030 +#define _PIPE_A_CSC_PREOFF_ME 0x49034 +#define _PIPE_A_CSC_PREOFF_LO 0x49038 +#define _PIPE_A_CSC_POSTOFF_HI 0x49040 +#define _PIPE_A_CSC_POSTOFF_ME 0x49044 +#define _PIPE_A_CSC_POSTOFF_LO 0x49048 + +#define _PIPE_B_CSC_COEFF_RY_GY 0x49110 +#define _PIPE_B_CSC_COEFF_BY 0x49114 +#define _PIPE_B_CSC_COEFF_RU_GU 0x49118 +#define _PIPE_B_CSC_COEFF_BU 0x4911c +#define _PIPE_B_CSC_COEFF_RV_GV 0x49120 +#define _PIPE_B_CSC_COEFF_BV 0x49124 +#define _PIPE_B_CSC_MODE 0x49128 +#define _PIPE_B_CSC_PREOFF_HI 0x49130 +#define _PIPE_B_CSC_PREOFF_ME 0x49134 +#define _PIPE_B_CSC_PREOFF_LO 0x49138 +#define _PIPE_B_CSC_POSTOFF_HI 0x49140 +#define _PIPE_B_CSC_POSTOFF_ME 0x49144 +#define _PIPE_B_CSC_POSTOFF_LO 0x49148 + +#define PIPE_CSC_COEFF_RY_GY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) +#define PIPE_CSC_COEFF_BY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) +#define PIPE_CSC_COEFF_RU_GU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) +#define PIPE_CSC_COEFF_BU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU) +#define PIPE_CSC_COEFF_RV_GV(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV) +#define PIPE_CSC_COEFF_BV(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV) +#define PIPE_CSC_MODE(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE) +#define PIPE_CSC_PREOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI) +#define PIPE_CSC_PREOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME) +#define PIPE_CSC_PREOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO) +#define PIPE_CSC_POSTOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI) +#define PIPE_CSC_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) +#define PIPE_CSC_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) + +/* Pipe Output CSC */ +#define _PIPE_A_OUTPUT_CSC_COEFF_RY_GY 0x49050 +#define _PIPE_A_OUTPUT_CSC_COEFF_BY 0x49054 +#define _PIPE_A_OUTPUT_CSC_COEFF_RU_GU 0x49058 +#define _PIPE_A_OUTPUT_CSC_COEFF_BU 0x4905c +#define _PIPE_A_OUTPUT_CSC_COEFF_RV_GV 0x49060 +#define _PIPE_A_OUTPUT_CSC_COEFF_BV 0x49064 +#define _PIPE_A_OUTPUT_CSC_PREOFF_HI 0x49068 +#define _PIPE_A_OUTPUT_CSC_PREOFF_ME 0x4906c +#define _PIPE_A_OUTPUT_CSC_PREOFF_LO 0x49070 +#define _PIPE_A_OUTPUT_CSC_POSTOFF_HI 0x49074 +#define _PIPE_A_OUTPUT_CSC_POSTOFF_ME 0x49078 +#define _PIPE_A_OUTPUT_CSC_POSTOFF_LO 0x4907c + +#define _PIPE_B_OUTPUT_CSC_COEFF_RY_GY 0x49150 +#define _PIPE_B_OUTPUT_CSC_COEFF_BY 0x49154 +#define _PIPE_B_OUTPUT_CSC_COEFF_RU_GU 0x49158 +#define _PIPE_B_OUTPUT_CSC_COEFF_BU 0x4915c +#define _PIPE_B_OUTPUT_CSC_COEFF_RV_GV 0x49160 +#define _PIPE_B_OUTPUT_CSC_COEFF_BV 0x49164 +#define _PIPE_B_OUTPUT_CSC_PREOFF_HI 0x49168 +#define _PIPE_B_OUTPUT_CSC_PREOFF_ME 0x4916c +#define _PIPE_B_OUTPUT_CSC_PREOFF_LO 0x49170 +#define _PIPE_B_OUTPUT_CSC_POSTOFF_HI 0x49174 +#define _PIPE_B_OUTPUT_CSC_POSTOFF_ME 0x49178 +#define _PIPE_B_OUTPUT_CSC_POSTOFF_LO 0x4917c + +#define PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe) _MMIO_PIPE(pipe,\ + _PIPE_A_OUTPUT_CSC_COEFF_RY_GY,\ + _PIPE_B_OUTPUT_CSC_COEFF_RY_GY) +#define PIPE_CSC_OUTPUT_COEFF_BY(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_COEFF_BY, \ + _PIPE_B_OUTPUT_CSC_COEFF_BY) +#define PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_COEFF_RU_GU, \ + _PIPE_B_OUTPUT_CSC_COEFF_RU_GU) +#define PIPE_CSC_OUTPUT_COEFF_BU(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_COEFF_BU, \ + _PIPE_B_OUTPUT_CSC_COEFF_BU) +#define PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_COEFF_RV_GV, \ + _PIPE_B_OUTPUT_CSC_COEFF_RV_GV) +#define PIPE_CSC_OUTPUT_COEFF_BV(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_COEFF_BV, \ + _PIPE_B_OUTPUT_CSC_COEFF_BV) +#define PIPE_CSC_OUTPUT_PREOFF_HI(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_PREOFF_HI, \ + _PIPE_B_OUTPUT_CSC_PREOFF_HI) +#define PIPE_CSC_OUTPUT_PREOFF_ME(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_PREOFF_ME, \ + _PIPE_B_OUTPUT_CSC_PREOFF_ME) +#define PIPE_CSC_OUTPUT_PREOFF_LO(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_PREOFF_LO, \ + _PIPE_B_OUTPUT_CSC_PREOFF_LO) +#define PIPE_CSC_OUTPUT_POSTOFF_HI(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_POSTOFF_HI, \ + _PIPE_B_OUTPUT_CSC_POSTOFF_HI) +#define PIPE_CSC_OUTPUT_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_POSTOFF_ME, \ + _PIPE_B_OUTPUT_CSC_POSTOFF_ME) +#define PIPE_CSC_OUTPUT_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, \ + _PIPE_A_OUTPUT_CSC_POSTOFF_LO, \ + _PIPE_B_OUTPUT_CSC_POSTOFF_LO) + +/* pipe degamma/gamma LUTs on IVB+ */ +#define _PAL_PREC_INDEX_A 0x4A400 +#define _PAL_PREC_INDEX_B 0x4AC00 +#define _PAL_PREC_INDEX_C 0x4B400 +#define PAL_PREC_SPLIT_MODE REG_BIT(31) +#define PAL_PREC_AUTO_INCREMENT REG_BIT(15) +#define PAL_PREC_INDEX_VALUE_MASK REG_GENMASK(9, 0) +#define PAL_PREC_INDEX_VALUE(x) REG_FIELD_PREP(PAL_PREC_INDEX_VALUE_MASK, (x)) +#define _PAL_PREC_DATA_A 0x4A404 +#define _PAL_PREC_DATA_B 0x4AC04 +#define _PAL_PREC_DATA_C 0x4B404 +/* see PREC_PALETTE_* for the bits */ +#define _PAL_PREC_GC_MAX_A 0x4A410 +#define _PAL_PREC_GC_MAX_B 0x4AC10 +#define _PAL_PREC_GC_MAX_C 0x4B410 +#define _PAL_PREC_EXT_GC_MAX_A 0x4A420 +#define _PAL_PREC_EXT_GC_MAX_B 0x4AC20 +#define _PAL_PREC_EXT_GC_MAX_C 0x4B420 +#define _PAL_PREC_EXT2_GC_MAX_A 0x4A430 +#define _PAL_PREC_EXT2_GC_MAX_B 0x4AC30 +#define _PAL_PREC_EXT2_GC_MAX_C 0x4B430 + +#define PREC_PAL_INDEX(pipe) _MMIO_PIPE(pipe, _PAL_PREC_INDEX_A, _PAL_PREC_INDEX_B) +#define PREC_PAL_DATA(pipe) _MMIO_PIPE(pipe, _PAL_PREC_DATA_A, _PAL_PREC_DATA_B) +#define PREC_PAL_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_GC_MAX_A, _PAL_PREC_GC_MAX_B) + (i) * 4) /* u1.16 */ +#define PREC_PAL_EXT_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT_GC_MAX_A, _PAL_PREC_EXT_GC_MAX_B) + (i) * 4) /* u3.16 */ +#define PREC_PAL_EXT2_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT2_GC_MAX_A, _PAL_PREC_EXT2_GC_MAX_B) + (i) * 4) /* glk+, u3.16 */ + +#define _PRE_CSC_GAMC_INDEX_A 0x4A484 +#define _PRE_CSC_GAMC_INDEX_B 0x4AC84 +#define _PRE_CSC_GAMC_INDEX_C 0x4B484 +#define PRE_CSC_GAMC_AUTO_INCREMENT REG_BIT(10) +#define PRE_CSC_GAMC_INDEX_VALUE_MASK REG_GENMASK(7, 0) +#define PRE_CSC_GAMC_INDEX_VALUE(x) REG_FIELD_PREP(PRE_CSC_GAMC_INDEX_VALUE_MASK, (x)) +#define _PRE_CSC_GAMC_DATA_A 0x4A488 +#define _PRE_CSC_GAMC_DATA_B 0x4AC88 +#define _PRE_CSC_GAMC_DATA_C 0x4B488 + +#define PRE_CSC_GAMC_INDEX(pipe) _MMIO_PIPE(pipe, _PRE_CSC_GAMC_INDEX_A, _PRE_CSC_GAMC_INDEX_B) +#define PRE_CSC_GAMC_DATA(pipe) _MMIO_PIPE(pipe, _PRE_CSC_GAMC_DATA_A, _PRE_CSC_GAMC_DATA_B) + +/* ICL Multi segmented gamma */ +#define _PAL_PREC_MULTI_SEG_INDEX_A 0x4A408 +#define _PAL_PREC_MULTI_SEG_INDEX_B 0x4AC08 +#define PAL_PREC_MULTI_SEG_AUTO_INCREMENT REG_BIT(15) +#define PAL_PREC_MULTI_SEG_INDEX_VALUE_MASK REG_GENMASK(4, 0) +#define PAL_PREC_MULTI_SEG_INDEX_VALUE(x) REG_FIELD_PREP(PAL_PREC_MULTI_SEG_INDEX_VALUE_MASK, (x)) + +#define _PAL_PREC_MULTI_SEG_DATA_A 0x4A40C +#define _PAL_PREC_MULTI_SEG_DATA_B 0x4AC0C +/* see PREC_PALETTE_12P4_* for the bits */ + +#define PREC_PAL_MULTI_SEG_INDEX(pipe) _MMIO_PIPE(pipe, \ + _PAL_PREC_MULTI_SEG_INDEX_A, \ + _PAL_PREC_MULTI_SEG_INDEX_B) +#define PREC_PAL_MULTI_SEG_DATA(pipe) _MMIO_PIPE(pipe, \ + _PAL_PREC_MULTI_SEG_DATA_A, \ + _PAL_PREC_MULTI_SEG_DATA_B) + +#define _PIPE_A_WGC_C01_C00 0x600B0 /* s2.10 */ +#define _PIPE_A_WGC_C02 0x600B4 /* s2.10 */ +#define _PIPE_A_WGC_C11_C10 0x600B8 /* s2.10 */ +#define _PIPE_A_WGC_C12 0x600BC /* s2.10 */ +#define _PIPE_A_WGC_C21_C20 0x600C0 /* s2.10 */ +#define _PIPE_A_WGC_C22 0x600C4 /* s2.10 */ + +#define PIPE_WGC_C01_C00(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C01_C00) +#define PIPE_WGC_C02(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C02) +#define PIPE_WGC_C11_C10(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C11_C10) +#define PIPE_WGC_C12(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C12) +#define PIPE_WGC_C21_C20(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C21_C20) +#define PIPE_WGC_C22(pipe) _MMIO_TRANS2(pipe, _PIPE_A_WGC_C22) + +/* pipe CSC & degamma/gamma LUTs on CHV */ +#define _CGM_PIPE_A_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x67900) +#define _CGM_PIPE_A_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x67904) +#define _CGM_PIPE_A_CSC_COEFF45 (VLV_DISPLAY_BASE + 0x67908) +#define _CGM_PIPE_A_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6790C) +#define _CGM_PIPE_A_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x67910) +#define _CGM_PIPE_A_DEGAMMA (VLV_DISPLAY_BASE + 0x66000) +/* cgm degamma ldw */ +#define CGM_PIPE_DEGAMMA_GREEN_LDW_MASK REG_GENMASK(29, 16) +#define CGM_PIPE_DEGAMMA_BLUE_LDW_MASK REG_GENMASK(13, 0) +/* cgm degamma udw */ +#define CGM_PIPE_DEGAMMA_RED_UDW_MASK REG_GENMASK(13, 0) +#define _CGM_PIPE_A_GAMMA (VLV_DISPLAY_BASE + 0x67000) +/* cgm gamma ldw */ +#define CGM_PIPE_GAMMA_GREEN_LDW_MASK REG_GENMASK(25, 16) +#define CGM_PIPE_GAMMA_BLUE_LDW_MASK REG_GENMASK(9, 0) +/* cgm gamma udw */ +#define CGM_PIPE_GAMMA_RED_UDW_MASK REG_GENMASK(9, 0) +#define _CGM_PIPE_A_MODE (VLV_DISPLAY_BASE + 0x67A00) +#define CGM_PIPE_MODE_GAMMA (1 << 2) +#define CGM_PIPE_MODE_CSC (1 << 1) +#define CGM_PIPE_MODE_DEGAMMA (1 << 0) + +#define _CGM_PIPE_B_CSC_COEFF01 (VLV_DISPLAY_BASE + 0x69900) +#define _CGM_PIPE_B_CSC_COEFF23 (VLV_DISPLAY_BASE + 0x69904) +#define _CGM_PIPE_B_CSC_COEFF45 (VLV_DISPLAY_BASE + 0x69908) +#define _CGM_PIPE_B_CSC_COEFF67 (VLV_DISPLAY_BASE + 0x6990C) +#define _CGM_PIPE_B_CSC_COEFF8 (VLV_DISPLAY_BASE + 0x69910) +#define _CGM_PIPE_B_DEGAMMA (VLV_DISPLAY_BASE + 0x68000) +#define _CGM_PIPE_B_GAMMA (VLV_DISPLAY_BASE + 0x69000) +#define _CGM_PIPE_B_MODE (VLV_DISPLAY_BASE + 0x69A00) + +#define CGM_PIPE_CSC_COEFF01(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF01, _CGM_PIPE_B_CSC_COEFF01) +#define CGM_PIPE_CSC_COEFF23(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF23, _CGM_PIPE_B_CSC_COEFF23) +#define CGM_PIPE_CSC_COEFF45(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF45, _CGM_PIPE_B_CSC_COEFF45) +#define CGM_PIPE_CSC_COEFF67(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF67, _CGM_PIPE_B_CSC_COEFF67) +#define CGM_PIPE_CSC_COEFF8(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_CSC_COEFF8, _CGM_PIPE_B_CSC_COEFF8) +#define CGM_PIPE_DEGAMMA(pipe, i, w) _MMIO(_PIPE(pipe, _CGM_PIPE_A_DEGAMMA, _CGM_PIPE_B_DEGAMMA) + (i) * 8 + (w) * 4) +#define CGM_PIPE_GAMMA(pipe, i, w) _MMIO(_PIPE(pipe, _CGM_PIPE_A_GAMMA, _CGM_PIPE_B_GAMMA) + (i) * 8 + (w) * 4) +#define CGM_PIPE_MODE(pipe) _MMIO_PIPE(pipe, _CGM_PIPE_A_MODE, _CGM_PIPE_B_MODE) + +/* Skylake+ pipe bottom (background) color */ +#define _SKL_BOTTOM_COLOR_A 0x70034 +#define _SKL_BOTTOM_COLOR_B 0x71034 +#define SKL_BOTTOM_COLOR_GAMMA_ENABLE REG_BIT(31) +#define SKL_BOTTOM_COLOR_CSC_ENABLE REG_BIT(30) +#define SKL_BOTTOM_COLOR(pipe) _MMIO_PIPE(pipe, _SKL_BOTTOM_COLOR_A, _SKL_BOTTOM_COLOR_B) + +#endif /* __INTEL_COLOR_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c index e2a220cf2e..143d669516 100644 --- a/drivers/gpu/drm/i915/display/intel_combo_phy.c +++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c @@ -114,10 +114,6 @@ static bool icl_verify_procmon_ref_values(struct drm_i915_private *dev_priv, procmon = icl_get_procmon_ref_values(dev_priv, phy); - drm_dbg_kms(&dev_priv->drm, - "Combo PHY %c Voltage/Process Info : %s\n", - phy_name(phy), procmon->name); - ret = check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW1(phy), (0xff << 16) | 0xff, procmon->dw1); ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW9(phy), @@ -312,14 +308,17 @@ static void icl_combo_phys_init(struct drm_i915_private *dev_priv) enum phy phy; for_each_combo_phy(dev_priv, phy) { + const struct icl_procmon *procmon; u32 val; - if (icl_combo_phy_verify_state(dev_priv, phy)) { - drm_dbg(&dev_priv->drm, - "Combo PHY %c already enabled, won't reprogram it.\n", - phy_name(phy)); + if (icl_combo_phy_verify_state(dev_priv, phy)) continue; - } + + procmon = icl_get_procmon_ref_values(dev_priv, phy); + + drm_dbg(&dev_priv->drm, + "Initializing combo PHY %c (Voltage/Process Info : %s)\n", + phy_name(phy), procmon->name); if (!has_phy_misc(dev_priv, phy)) goto skip_phy_misc; diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index ff3bcadebe..c65887870d 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -192,17 +192,17 @@ int intel_connector_update_modes(struct drm_connector *connector, /** * intel_ddc_get_modes - get modelist from monitor * @connector: DRM connector device to use - * @adapter: i2c adapter + * @ddc: DDC bus i2c adapter * * Fetch the EDID information from @connector using the DDC bus. */ int intel_ddc_get_modes(struct drm_connector *connector, - struct i2c_adapter *adapter) + struct i2c_adapter *ddc) { const struct drm_edid *drm_edid; int ret; - drm_edid = drm_edid_read_ddc(connector, adapter); + drm_edid = drm_edid_read_ddc(connector, ddc); if (!drm_edid) return 0; diff --git a/drivers/gpu/drm/i915/display/intel_connector.h b/drivers/gpu/drm/i915/display/intel_connector.h index aaf7281462..bafde3f11f 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.h +++ b/drivers/gpu/drm/i915/display/intel_connector.h @@ -26,7 +26,7 @@ bool intel_connector_get_hw_state(struct intel_connector *connector); enum pipe intel_connector_get_pipe(struct intel_connector *connector); int intel_connector_update_modes(struct drm_connector *connector, const struct drm_edid *drm_edid); -int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); +int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *ddc); void intel_attach_force_audio_property(struct drm_connector *connector); void intel_attach_broadcast_rgb_property(struct drm_connector *connector); void intel_attach_aspect_ratio_property(struct drm_connector *connector); diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 4352f90177..6f6b348b8a 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -418,6 +418,9 @@ static int pch_crt_compute_config(struct intel_encoder *encoder, return -EINVAL; pipe_config->has_pch_encoder = true; + if (!intel_fdi_compute_pipe_bpp(pipe_config)) + return -EINVAL; + pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; return 0; @@ -440,10 +443,14 @@ static int hsw_crt_compute_config(struct intel_encoder *encoder, return -EINVAL; pipe_config->has_pch_encoder = true; + if (!intel_fdi_compute_pipe_bpp(pipe_config)) + return -EINVAL; + pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; /* LPT FDI RX only supports 8bpc. */ if (HAS_PCH_LPT(dev_priv)) { + /* TODO: Check crtc_state->max_link_bpp_x16 instead of bw_constrained */ if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) { drm_dbg_kms(&dev_priv->drm, "LPT only supports 24bpp\n"); @@ -617,18 +624,18 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) } static const struct drm_edid *intel_crt_get_edid(struct drm_connector *connector, - struct i2c_adapter *i2c) + struct i2c_adapter *ddc) { const struct drm_edid *drm_edid; - drm_edid = drm_edid_read_ddc(connector, i2c); + drm_edid = drm_edid_read_ddc(connector, ddc); - if (!drm_edid && !intel_gmbus_is_forced_bit(i2c)) { + if (!drm_edid && !intel_gmbus_is_forced_bit(ddc)) { drm_dbg_kms(connector->dev, "CRT GMBUS EDID read failed, retry using GPIO bit-banging\n"); - intel_gmbus_force_bit(i2c, true); - drm_edid = drm_edid_read_ddc(connector, i2c); - intel_gmbus_force_bit(i2c, false); + intel_gmbus_force_bit(ddc, true); + drm_edid = drm_edid_read_ddc(connector, ddc); + intel_gmbus_force_bit(ddc, false); } return drm_edid; @@ -636,12 +643,12 @@ static const struct drm_edid *intel_crt_get_edid(struct drm_connector *connector /* local version of intel_ddc_get_modes() to use intel_crt_get_edid() */ static int intel_crt_ddc_get_modes(struct drm_connector *connector, - struct i2c_adapter *adapter) + struct i2c_adapter *ddc) { const struct drm_edid *drm_edid; int ret; - drm_edid = intel_crt_get_edid(connector, adapter); + drm_edid = intel_crt_get_edid(connector, ddc); if (!drm_edid) return 0; @@ -657,28 +664,23 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector)); struct drm_i915_private *dev_priv = to_i915(crt->base.base.dev); const struct drm_edid *drm_edid; - struct i2c_adapter *i2c; bool ret = false; - i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->display.vbt.crt_ddc_pin); - drm_edid = intel_crt_get_edid(connector, i2c); + drm_edid = intel_crt_get_edid(connector, connector->ddc); if (drm_edid) { - const struct edid *edid = drm_edid_raw(drm_edid); - bool is_digital = edid->input & DRM_EDID_INPUT_DIGITAL; - /* * This may be a DVI-I connector with a shared DDC * link between analog and digital outputs, so we * have to check the EDID input spec of the attached device. */ - if (!is_digital) { + if (drm_edid_is_digital(drm_edid)) { drm_dbg_kms(&dev_priv->drm, - "CRT detected via DDC:0x50 [EDID]\n"); - ret = true; + "CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); } else { drm_dbg_kms(&dev_priv->drm, - "CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); + "CRT detected via DDC:0x50 [EDID]\n"); + ret = true; } } else { drm_dbg_kms(&dev_priv->drm, @@ -841,7 +843,7 @@ intel_crt_detect(struct drm_connector *connector, connector->base.id, connector->name, force); - if (!INTEL_DISPLAY_ENABLED(dev_priv)) + if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; if (dev_priv->params.load_detect_test) { @@ -914,12 +916,6 @@ load_detect: out: intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref); - /* - * Make sure the refs for power wells enabled during detect are - * dropped to avoid a new detect cycle triggered by HPD polling. - */ - intel_display_power_flush_work(dev_priv); - return status; } @@ -930,20 +926,19 @@ static int intel_crt_get_modes(struct drm_connector *connector) struct intel_crt *crt = intel_attached_crt(to_intel_connector(connector)); struct intel_encoder *intel_encoder = &crt->base; intel_wakeref_t wakeref; - struct i2c_adapter *i2c; + struct i2c_adapter *ddc; int ret; wakeref = intel_display_power_get(dev_priv, intel_encoder->power_domain); - i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->display.vbt.crt_ddc_pin); - ret = intel_crt_ddc_get_modes(connector, i2c); + ret = intel_crt_ddc_get_modes(connector, connector->ddc); if (ret || !IS_G4X(dev_priv)) goto out; /* Try to probe digital port for output in DVI-I -> VGA mode. */ - i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPB); - ret = intel_crt_ddc_get_modes(connector, i2c); + ddc = intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPB); + ret = intel_crt_ddc_get_modes(connector, ddc); out: intel_display_power_put(dev_priv, intel_encoder->power_domain, wakeref); @@ -1001,6 +996,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv) struct intel_crt *crt; struct intel_connector *intel_connector; i915_reg_t adpa_reg; + u8 ddc_pin; u32 adpa; if (HAS_PCH_SPLIT(dev_priv)) @@ -1037,10 +1033,14 @@ void intel_crt_init(struct drm_i915_private *dev_priv) return; } + ddc_pin = dev_priv->display.vbt.crt_ddc_pin; + connector = &intel_connector->base; crt->connector = intel_connector; - drm_connector_init(&dev_priv->drm, &intel_connector->base, - &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); + drm_connector_init_with_ddc(&dev_priv->drm, connector, + &intel_crt_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + intel_gmbus_get_adapter(dev_priv, ddc_pin)); drm_encoder_init(&dev_priv->drm, &crt->base.base, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC, "CRT"); diff --git a/drivers/gpu/drm/i915/display/intel_crt.h b/drivers/gpu/drm/i915/display/intel_crt.h index c6071efd93..fe7690c2b9 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.h +++ b/drivers/gpu/drm/i915/display/intel_crt.h @@ -12,9 +12,23 @@ enum pipe; struct drm_encoder; struct drm_i915_private; +#ifdef I915 bool intel_crt_port_enabled(struct drm_i915_private *dev_priv, i915_reg_t adpa_reg, enum pipe *pipe); void intel_crt_init(struct drm_i915_private *dev_priv); void intel_crt_reset(struct drm_encoder *encoder); +#else +static inline bool intel_crt_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t adpa_reg, enum pipe *pipe) +{ + return false; +} +static inline void intel_crt_init(struct drm_i915_private *dev_priv) +{ +} +static inline void intel_crt_reset(struct drm_encoder *encoder) +{ +} +#endif #endif /* __INTEL_CRT_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 182c6dd64f..1fd068e6e2 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -24,6 +24,7 @@ #include "intel_display_trace.h" #include "intel_display_types.h" #include "intel_drrs.h" +#include "intel_dsb.h" #include "intel_dsi.h" #include "intel_fifo_underrun.h" #include "intel_pipe_crc.h" @@ -175,6 +176,7 @@ void intel_crtc_state_reset(struct intel_crtc_state *crtc_state, crtc_state->hsw_workaround_pipe = INVALID_PIPE; crtc_state->scaler_state.scaler_id = -1; crtc_state->mst_master_transcoder = INVALID_TRANSCODER; + crtc_state->max_link_bpp_x16 = INT_MAX; } static struct intel_crtc *intel_crtc_alloc(void) @@ -394,7 +396,8 @@ static bool intel_crtc_needs_vblank_work(const struct intel_crtc_state *crtc_sta return crtc_state->hw.active && !intel_crtc_needs_modeset(crtc_state) && !crtc_state->preload_luts && - intel_crtc_needs_color_update(crtc_state); + intel_crtc_needs_color_update(crtc_state) && + !intel_color_uses_dsb(crtc_state); } static void intel_crtc_vblank_work(struct kthread_work *base) @@ -468,9 +471,64 @@ static int intel_mode_vblank_start(const struct drm_display_mode *mode) return vblank_start; } +static void intel_crtc_vblank_evade_scanlines(struct intel_atomic_state *state, + struct intel_crtc *crtc, + int *min, int *max, int *vblank_start) +{ + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + const struct intel_crtc_state *crtc_state; + const struct drm_display_mode *adjusted_mode; + + /* + * During fastsets/etc. the transcoder is still + * running with the old timings at this point. + * + * TODO: maybe just use the active timings here? + */ + if (intel_crtc_needs_modeset(new_crtc_state)) + crtc_state = new_crtc_state; + else + crtc_state = old_crtc_state; + + adjusted_mode = &crtc_state->hw.adjusted_mode; + + if (crtc->mode_flags & I915_MODE_FLAG_VRR) { + /* timing changes should happen with VRR disabled */ + drm_WARN_ON(state->base.dev, intel_crtc_needs_modeset(new_crtc_state) || + new_crtc_state->update_m_n || new_crtc_state->update_lrr); + + if (intel_vrr_is_push_sent(crtc_state)) + *vblank_start = intel_vrr_vmin_vblank_start(crtc_state); + else + *vblank_start = intel_vrr_vmax_vblank_start(crtc_state); + } else { + *vblank_start = intel_mode_vblank_start(adjusted_mode); + } + + /* FIXME needs to be calibrated sensibly */ + *min = *vblank_start - intel_usecs_to_scanlines(adjusted_mode, + VBLANK_EVASION_TIME_US); + *max = *vblank_start - 1; + + /* + * M/N and TRANS_VTOTAL are double buffered on the transcoder's + * undelayed vblank, so with seamless M/N and LRR we must evade + * both vblanks. + * + * DSB execution waits for the transcoder's undelayed vblank, + * hence we must kick off the commit before that. + */ + if (new_crtc_state->dsb || new_crtc_state->update_m_n || new_crtc_state->update_lrr) + *min -= adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay; +} + /** * intel_pipe_update_start() - start update of a set of display registers - * @new_crtc_state: the new crtc state + * @state: the atomic state + * @crtc: the crtc * * Mark the start of an update to pipe registers that should be updated * atomically regarding vblank. If the next vblank will happens within @@ -480,11 +538,12 @@ static int intel_mode_vblank_start(const struct drm_display_mode *mode) * until a subsequent call to intel_pipe_update_end(). That is done to * avoid random delays. */ -void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) +void intel_pipe_update_start(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - const struct drm_display_mode *adjusted_mode = &new_crtc_state->hw.adjusted_mode; + struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); long timeout = msecs_to_jiffies_timeout(1); int scanline, min, max, vblank_start; wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); @@ -500,27 +559,7 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) if (intel_crtc_needs_vblank_work(new_crtc_state)) intel_crtc_vblank_work_init(new_crtc_state); - if (new_crtc_state->vrr.enable) { - if (intel_vrr_is_push_sent(new_crtc_state)) - vblank_start = intel_vrr_vmin_vblank_start(new_crtc_state); - else - vblank_start = intel_vrr_vmax_vblank_start(new_crtc_state); - } else { - vblank_start = intel_mode_vblank_start(adjusted_mode); - } - - /* FIXME needs to be calibrated sensibly */ - min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, - VBLANK_EVASION_TIME_US); - max = vblank_start - 1; - - /* - * M/N is double buffered on the transcoder's undelayed vblank, - * so with seamless M/N we must evade both vblanks. - */ - if (new_crtc_state->seamless_m_n && intel_crtc_needs_fastset(new_crtc_state)) - min -= adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay; - + intel_crtc_vblank_evade_scanlines(state, crtc, &min, &max, &vblank_start); if (min <= 0 || max <= 0) goto irq_disable; @@ -631,25 +670,26 @@ static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) {} /** * intel_pipe_update_end() - end update of a set of display registers - * @new_crtc_state: the new crtc state + * @state: the atomic state + * @crtc: the crtc * * Mark the end of an update started with intel_pipe_update_start(). This * re-enables interrupts and verifies the update was actually completed * before a vblank. */ -void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) +void intel_pipe_update_end(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); enum pipe pipe = crtc->pipe; int scanline_end = intel_get_crtc_scanline(crtc); u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); ktime_t end_vbl_time = ktime_get(); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - intel_psr_unlock(new_crtc_state); - if (new_crtc_state->do_async_flip) - return; + goto out; trace_intel_pipe_update_end(crtc, end_vbl_count, scanline_end); @@ -697,19 +737,10 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) */ intel_vrr_send_push(new_crtc_state); - /* - * Seamless M/N update may need to update frame timings. - * - * FIXME Should be synchronized with the start of vblank somehow... - */ - if (new_crtc_state->seamless_m_n && intel_crtc_needs_fastset(new_crtc_state)) - intel_crtc_update_active_timings(new_crtc_state, - new_crtc_state->vrr.enable); - local_irq_enable(); if (intel_vgpu_active(dev_priv)) - return; + goto out; if (crtc->debug.start_vbl_count && crtc->debug.start_vbl_count != end_vbl_count) { @@ -724,4 +755,7 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) } dbg_vblank_evade(crtc, end_vbl_time); + +out: + intel_psr_unlock(new_crtc_state); } diff --git a/drivers/gpu/drm/i915/display/intel_crtc.h b/drivers/gpu/drm/i915/display/intel_crtc.h index 51a4c8df9e..22d7993d1f 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.h +++ b/drivers/gpu/drm/i915/display/intel_crtc.h @@ -36,8 +36,10 @@ void intel_crtc_state_reset(struct intel_crtc_state *crtc_state, u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc); void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state); void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state); -void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state); -void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state); +void intel_pipe_update_start(struct intel_atomic_state *state, + struct intel_crtc *crtc); +void intel_pipe_update_end(struct intel_atomic_state *state, + struct intel_crtc *crtc); void intel_wait_for_vblank_workers(struct intel_atomic_state *state); struct intel_crtc *intel_first_crtc(struct drm_i915_private *i915); struct intel_crtc *intel_crtc_for_pipe(struct drm_i915_private *i915, diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 048e581fda..ccf225afeb 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -31,7 +31,7 @@ bool intel_is_c10phy(struct drm_i915_private *i915, enum phy phy) { - if (IS_METEORLAKE(i915) && (phy < PHY_C)) + if (DISPLAY_VER_FULL(i915) == IP_VER(14, 0) && phy < PHY_C) return true; return false; @@ -46,6 +46,22 @@ static int lane_mask_to_lane(u8 lane_mask) return ilog2(lane_mask); } +static u8 intel_cx0_get_owned_lane_mask(struct drm_i915_private *i915, + struct intel_encoder *encoder) +{ + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + + if (!intel_tc_port_in_dp_alt_mode(dig_port)) + return INTEL_CX0_BOTH_LANES; + + /* + * In DP-alt with pin assignment D, only PHY lane 0 is owned + * by display and lane 1 is owned by USB. + */ + return intel_tc_port_max_lane_count(dig_port) > 2 + ? INTEL_CX0_BOTH_LANES : INTEL_CX0_LANE0; +} + static void assert_dc_off(struct drm_i915_private *i915) { @@ -55,19 +71,38 @@ assert_dc_off(struct drm_i915_private *i915) drm_WARN_ON(&i915->drm, !enabled); } +static void intel_cx0_program_msgbus_timer(struct intel_encoder *encoder) +{ + int lane; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + + for_each_cx0_lane_in_mask(INTEL_CX0_BOTH_LANES, lane) + intel_de_rmw(i915, + XELPDP_PORT_MSGBUS_TIMER(encoder->port, lane), + XELPDP_PORT_MSGBUS_TIMER_VAL_MASK, + XELPDP_PORT_MSGBUS_TIMER_VAL); +} + /* * Prepare HW for CX0 phy transactions. * * It is required that PSR and DC5/6 are disabled before any CX0 message * bus transaction is executed. + * + * We also do the msgbus timer programming here to ensure that the timer + * is already programmed before any access to the msgbus. */ static intel_wakeref_t intel_cx0_phy_transaction_begin(struct intel_encoder *encoder) { + intel_wakeref_t wakeref; struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); intel_psr_pause(intel_dp); - return intel_display_power_get(i915, POWER_DOMAIN_DC_OFF); + wakeref = intel_display_power_get(i915, POWER_DOMAIN_DC_OFF); + intel_cx0_program_msgbus_timer(encoder); + + return wakeref; } static void intel_cx0_phy_transaction_end(struct intel_encoder *encoder, intel_wakeref_t wakeref) @@ -116,6 +151,13 @@ static int intel_cx0_wait_for_ack(struct drm_i915_private *i915, enum port port, XELPDP_MSGBUS_TIMEOUT_SLOW, val)) { drm_dbg_kms(&i915->drm, "PHY %c Timeout waiting for message ACK. Status: 0x%x\n", phy_name(phy), *val); + + if (!(intel_de_read(i915, XELPDP_PORT_MSGBUS_TIMER(port, lane)) & + XELPDP_PORT_MSGBUS_TIMER_TIMED_OUT)) + drm_dbg_kms(&i915->drm, + "PHY %c Hardware did not detect a timeout\n", + phy_name(phy)); + intel_cx0_bus_reset(i915, port, lane); return -ETIMEDOUT; } @@ -359,6 +401,7 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_ddi_buf_trans *trans; enum phy phy = intel_port_to_phy(i915, encoder->port); + u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(i915, encoder); intel_wakeref_t wakeref; int n_entries, ln; @@ -371,13 +414,13 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, } if (intel_is_c10phy(i915, phy)) { - intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1), + intel_cx0_rmw(i915, encoder->port, owned_lane_mask, PHY_C10_VDR_CONTROL(1), 0, C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED); - intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CMN(3), + intel_cx0_rmw(i915, encoder->port, owned_lane_mask, PHY_C10_VDR_CMN(3), C10_CMN3_TXVBOOST_MASK, C10_CMN3_TXVBOOST(intel_c10_get_tx_vboost_lvl(crtc_state)), MB_WRITE_UNCOMMITTED); - intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_TX(1), + intel_cx0_rmw(i915, encoder->port, owned_lane_mask, PHY_C10_VDR_TX(1), C10_TX1_TERMCTL_MASK, C10_TX1_TERMCTL(intel_c10_get_tx_term_ctl(crtc_state)), MB_WRITE_COMMITTED); @@ -385,32 +428,34 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, for (ln = 0; ln < crtc_state->lane_count; ln++) { int level = intel_ddi_level(encoder, crtc_state, ln); - int lane, tx; + int lane = ln / 2; + int tx = ln % 2; + u8 lane_mask = lane == 0 ? INTEL_CX0_LANE0 : INTEL_CX0_LANE1; - lane = ln / 2; - tx = ln % 2; + if (!(lane_mask & owned_lane_mask)) + continue; - intel_cx0_rmw(i915, encoder->port, BIT(lane), PHY_CX0_VDROVRD_CTL(lane, tx, 0), + intel_cx0_rmw(i915, encoder->port, lane_mask, PHY_CX0_VDROVRD_CTL(lane, tx, 0), C10_PHY_OVRD_LEVEL_MASK, C10_PHY_OVRD_LEVEL(trans->entries[level].snps.pre_cursor), MB_WRITE_COMMITTED); - intel_cx0_rmw(i915, encoder->port, BIT(lane), PHY_CX0_VDROVRD_CTL(lane, tx, 1), + intel_cx0_rmw(i915, encoder->port, lane_mask, PHY_CX0_VDROVRD_CTL(lane, tx, 1), C10_PHY_OVRD_LEVEL_MASK, C10_PHY_OVRD_LEVEL(trans->entries[level].snps.vswing), MB_WRITE_COMMITTED); - intel_cx0_rmw(i915, encoder->port, BIT(lane), PHY_CX0_VDROVRD_CTL(lane, tx, 2), + intel_cx0_rmw(i915, encoder->port, lane_mask, PHY_CX0_VDROVRD_CTL(lane, tx, 2), C10_PHY_OVRD_LEVEL_MASK, C10_PHY_OVRD_LEVEL(trans->entries[level].snps.post_cursor), MB_WRITE_COMMITTED); } /* Write Override enables in 0xD71 */ - intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_OVRD, + intel_cx0_rmw(i915, encoder->port, owned_lane_mask, PHY_C10_VDR_OVRD, 0, PHY_C10_VDR_OVRD_TX1 | PHY_C10_VDR_OVRD_TX2, MB_WRITE_COMMITTED); if (intel_is_c10phy(i915, phy)) - intel_cx0_rmw(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C10_VDR_CONTROL(1), + intel_cx0_rmw(i915, encoder->port, owned_lane_mask, PHY_C10_VDR_CONTROL(1), 0, C10_VDR_CTRL_UPDATE_CFG, MB_WRITE_COMMITTED); intel_cx0_phy_transaction_end(encoder, wakeref); @@ -2535,17 +2580,15 @@ static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915, { enum port port = encoder->port; enum phy phy = intel_port_to_phy(i915, port); - bool both_lanes = intel_tc_port_fia_max_lane_count(enc_to_dig_port(encoder)) > 2; - u8 lane_mask = lane_reversal ? INTEL_CX0_LANE1 : - INTEL_CX0_LANE0; - u32 lane_pipe_reset = both_lanes ? - XELPDP_LANE_PIPE_RESET(0) | - XELPDP_LANE_PIPE_RESET(1) : - XELPDP_LANE_PIPE_RESET(0); - u32 lane_phy_current_status = both_lanes ? - XELPDP_LANE_PHY_CURRENT_STATUS(0) | - XELPDP_LANE_PHY_CURRENT_STATUS(1) : - XELPDP_LANE_PHY_CURRENT_STATUS(0); + u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(i915, encoder); + u8 lane_mask = lane_reversal ? INTEL_CX0_LANE1 : INTEL_CX0_LANE0; + u32 lane_pipe_reset = owned_lane_mask == INTEL_CX0_BOTH_LANES + ? XELPDP_LANE_PIPE_RESET(0) | XELPDP_LANE_PIPE_RESET(1) + : XELPDP_LANE_PIPE_RESET(0); + u32 lane_phy_current_status = owned_lane_mask == INTEL_CX0_BOTH_LANES + ? (XELPDP_LANE_PHY_CURRENT_STATUS(0) | + XELPDP_LANE_PHY_CURRENT_STATUS(1)) + : XELPDP_LANE_PHY_CURRENT_STATUS(0); if (__intel_de_wait_for_register(i915, XELPDP_PORT_BUF_CTL1(port), XELPDP_PORT_BUF_SOC_PHY_READY, @@ -2564,15 +2607,11 @@ static void intel_cx0_phy_lane_reset(struct drm_i915_private *i915, phy_name(phy), XELPDP_PORT_RESET_START_TIMEOUT_US); intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(port), - intel_cx0_get_pclk_refclk_request(both_lanes ? - INTEL_CX0_BOTH_LANES : - INTEL_CX0_LANE0), + intel_cx0_get_pclk_refclk_request(owned_lane_mask), intel_cx0_get_pclk_refclk_request(lane_mask)); if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(port), - intel_cx0_get_pclk_refclk_ack(both_lanes ? - INTEL_CX0_BOTH_LANES : - INTEL_CX0_LANE0), + intel_cx0_get_pclk_refclk_ack(owned_lane_mask), intel_cx0_get_pclk_refclk_ack(lane_mask), XELPDP_REFCLK_ENABLE_TIMEOUT_US, 0, NULL)) drm_warn(&i915->drm, "PHY %c failed to request refclk after %dus.\n", @@ -2594,79 +2633,43 @@ static void intel_cx0_program_phy_lane(struct drm_i915_private *i915, struct intel_encoder *encoder, int lane_count, bool lane_reversal) { - u8 l0t1, l0t2, l1t1, l1t2; + int i; + u8 disables; bool dp_alt_mode = intel_tc_port_in_dp_alt_mode(enc_to_dig_port(encoder)); + u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(i915, encoder); enum port port = encoder->port; if (intel_is_c10phy(i915, intel_port_to_phy(i915, port))) - intel_cx0_rmw(i915, port, INTEL_CX0_BOTH_LANES, + intel_cx0_rmw(i915, port, owned_lane_mask, PHY_C10_VDR_CONTROL(1), 0, C10_VDR_CTRL_MSGBUS_ACCESS, MB_WRITE_COMMITTED); - /* TODO: DP-alt MFD case where only one PHY lane should be programmed. */ - l0t1 = intel_cx0_read(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(1, 2)); - l0t2 = intel_cx0_read(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(2, 2)); - l1t1 = intel_cx0_read(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(1, 2)); - l1t2 = intel_cx0_read(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(2, 2)); - - l0t1 |= CONTROL2_DISABLE_SINGLE_TX; - l0t2 |= CONTROL2_DISABLE_SINGLE_TX; - l1t1 |= CONTROL2_DISABLE_SINGLE_TX; - l1t2 |= CONTROL2_DISABLE_SINGLE_TX; - - if (lane_reversal) { - switch (lane_count) { - case 4: - l0t1 &= ~CONTROL2_DISABLE_SINGLE_TX; - fallthrough; - case 3: - l0t2 &= ~CONTROL2_DISABLE_SINGLE_TX; - fallthrough; - case 2: - l1t1 &= ~CONTROL2_DISABLE_SINGLE_TX; - fallthrough; - case 1: - l1t2 &= ~CONTROL2_DISABLE_SINGLE_TX; - break; - default: - MISSING_CASE(lane_count); - } - } else { - switch (lane_count) { - case 4: - l1t2 &= ~CONTROL2_DISABLE_SINGLE_TX; - fallthrough; - case 3: - l1t1 &= ~CONTROL2_DISABLE_SINGLE_TX; - fallthrough; - case 2: - l0t2 &= ~CONTROL2_DISABLE_SINGLE_TX; - l0t1 &= ~CONTROL2_DISABLE_SINGLE_TX; - break; - case 1: - if (dp_alt_mode) - l0t2 &= ~CONTROL2_DISABLE_SINGLE_TX; - else - l0t1 &= ~CONTROL2_DISABLE_SINGLE_TX; - break; - default: - MISSING_CASE(lane_count); - } + if (lane_reversal) + disables = REG_GENMASK8(3, 0) >> lane_count; + else + disables = REG_GENMASK8(3, 0) << lane_count; + + if (dp_alt_mode && lane_count == 1) { + disables &= ~REG_GENMASK8(1, 0); + disables |= REG_FIELD_PREP8(REG_GENMASK8(1, 0), 0x1); } - /* disable MLs */ - intel_cx0_write(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(1, 2), - l0t1, MB_WRITE_COMMITTED); - intel_cx0_write(i915, port, INTEL_CX0_LANE0, PHY_CX0_TX_CONTROL(2, 2), - l0t2, MB_WRITE_COMMITTED); - intel_cx0_write(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(1, 2), - l1t1, MB_WRITE_COMMITTED); - intel_cx0_write(i915, port, INTEL_CX0_LANE1, PHY_CX0_TX_CONTROL(2, 2), - l1t2, MB_WRITE_COMMITTED); + for (i = 0; i < 4; i++) { + int tx = i % 2 + 1; + u8 lane_mask = i < 2 ? INTEL_CX0_LANE0 : INTEL_CX0_LANE1; + + if (!(owned_lane_mask & lane_mask)) + continue; + + intel_cx0_rmw(i915, port, lane_mask, PHY_CX0_TX_CONTROL(tx, 2), + CONTROL2_DISABLE_SINGLE_TX, + disables & BIT(i) ? CONTROL2_DISABLE_SINGLE_TX : 0, + MB_WRITE_COMMITTED); + } if (intel_is_c10phy(i915, intel_port_to_phy(i915, port))) - intel_cx0_rmw(i915, port, INTEL_CX0_BOTH_LANES, + intel_cx0_rmw(i915, port, owned_lane_mask, PHY_C10_VDR_CONTROL(1), 0, C10_VDR_CTRL_UPDATE_CFG, MB_WRITE_COMMITTED); @@ -2721,39 +2724,45 @@ static void intel_cx0pll_enable(struct intel_encoder *encoder, intel_cx0_powerdown_change_sequence(i915, encoder->port, INTEL_CX0_BOTH_LANES, CX0_P2_STATE_READY); - /* 4. Program PHY internal PLL internal registers. */ + /* + * 4. Program PORT_MSGBUS_TIMER register's Message Bus Timer field to 0xA000. + * (This is done inside intel_cx0_phy_transaction_begin(), since we would need + * the right timer thresholds for readouts too.) + */ + + /* 5. Program PHY internal PLL internal registers. */ if (intel_is_c10phy(i915, phy)) intel_c10_pll_program(i915, crtc_state, encoder); else intel_c20_pll_program(i915, crtc_state, encoder); /* - * 5. Program the enabled and disabled owned PHY lane + * 6. Program the enabled and disabled owned PHY lane * transmitters over message bus */ intel_cx0_program_phy_lane(i915, encoder, crtc_state->lane_count, lane_reversal); /* - * 6. Follow the Display Voltage Frequency Switching - Sequence + * 7. Follow the Display Voltage Frequency Switching - Sequence * Before Frequency Change. We handle this step in bxt_set_cdclk(). */ /* - * 7. Program DDI_CLK_VALFREQ to match intended DDI + * 8. Program DDI_CLK_VALFREQ to match intended DDI * clock frequency. */ intel_de_write(i915, DDI_CLK_VALFREQ(encoder->port), crtc_state->port_clock); /* - * 8. Set PORT_CLOCK_CTL register PCLK PLL Request + * 9. Set PORT_CLOCK_CTL register PCLK PLL Request * LN<Lane for maxPCLK> to "1" to enable PLL. */ intel_de_rmw(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), intel_cx0_get_pclk_pll_request(INTEL_CX0_BOTH_LANES), intel_cx0_get_pclk_pll_request(maxpclk_lane)); - /* 9. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN<Lane for maxPCLK> == "1". */ + /* 10. Poll on PORT_CLOCK_CTL PCLK PLL Ack LN<Lane for maxPCLK> == "1". */ if (__intel_de_wait_for_register(i915, XELPDP_PORT_CLOCK_CTL(encoder->port), intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES), intel_cx0_get_pclk_pll_ack(maxpclk_lane), @@ -2762,7 +2771,7 @@ static void intel_cx0pll_enable(struct intel_encoder *encoder, phy_name(phy), XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US); /* - * 10. Follow the Display Voltage Frequency Switching Sequence After + * 11. Follow the Display Voltage Frequency Switching Sequence After * Frequency Change. We handle this step in bxt_set_cdclk(). */ @@ -2996,12 +3005,13 @@ intel_mtl_port_pll_type(struct intel_encoder *encoder, } void intel_c10pll_state_verify(struct intel_atomic_state *state, - struct intel_crtc_state *new_crtc_state) + struct intel_crtc *crtc) { struct drm_i915_private *i915 = to_i915(state->base.dev); - struct intel_c10pll_state mpllb_hw_state = { 0 }; - struct intel_c10pll_state *mpllb_sw_state = &new_crtc_state->cx0pll_state.c10; - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + struct intel_c10pll_state mpllb_hw_state = {}; + const struct intel_c10pll_state *mpllb_sw_state = &new_crtc_state->cx0pll_state.c10; struct intel_encoder *encoder; enum phy phy; int i; diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 4c4db5cdcb..0e0a38dac8 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -10,14 +10,16 @@ #include <linux/bitfield.h> #include <linux/bits.h> -#include "i915_drv.h" -#include "intel_display_types.h" - -struct drm_i915_private; -struct intel_encoder; -struct intel_crtc_state; enum icl_port_dpll_id; enum phy; +struct drm_i915_private; +struct intel_atomic_state; +struct intel_c10pll_state; +struct intel_c20pll_state; +struct intel_crtc; +struct intel_crtc_state; +struct intel_encoder; +struct intel_hdmi; bool intel_is_c10phy(struct drm_i915_private *dev_priv, enum phy phy); void intel_mtl_pll_enable(struct intel_encoder *encoder, @@ -33,7 +35,7 @@ void intel_c10pll_dump_hw_state(struct drm_i915_private *dev_priv, int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, const struct intel_c10pll_state *pll_state); void intel_c10pll_state_verify(struct intel_atomic_state *state, - struct intel_crtc_state *new_crtc_state); + struct intel_crtc *crtc); void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, struct intel_c20pll_state *pll_state); void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, @@ -44,4 +46,5 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); int intel_cx0_phy_check_hdmi_link_rate(struct intel_hdmi *hdmi, int clock); int intel_mtl_tbt_calc_port_clock(struct intel_encoder *encoder); + #endif /* __INTEL_CX0_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h index cb5d1be2ba..adf8f4ce0d 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -110,6 +110,19 @@ #define CX0_P4PG_STATE_DISABLE 0xC #define CX0_P2_STATE_RESET 0x2 +#define _XELPDP_PORT_MSGBUS_TIMER_LN0_A 0x640d8 +#define _XELPDP_PORT_MSGBUS_TIMER_LN0_B 0x641d8 +#define _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC1 0x16f258 +#define _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC2 0x16f458 +#define XELPDP_PORT_MSGBUS_TIMER(port, lane) _MMIO(_PICK_EVEN_2RANGES(port, PORT_TC1, \ + _XELPDP_PORT_MSGBUS_TIMER_LN0_A, \ + _XELPDP_PORT_MSGBUS_TIMER_LN0_B, \ + _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC1, \ + _XELPDP_PORT_MSGBUS_TIMER_LN0_USBC2) + (lane) * 4) +#define XELPDP_PORT_MSGBUS_TIMER_TIMED_OUT REG_BIT(31) +#define XELPDP_PORT_MSGBUS_TIMER_VAL_MASK REG_GENMASK(23, 0) +#define XELPDP_PORT_MSGBUS_TIMER_VAL REG_FIELD_PREP(XELPDP_PORT_MSGBUS_TIMER_VAL_MASK, 0xa000) + #define _XELPDP_PORT_CLOCK_CTL_A 0x640E0 #define _XELPDP_PORT_CLOCK_CTL_B 0x641E0 #define _XELPDP_PORT_CLOCK_CTL_USBC1 0x16F260 diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c7e00f57cb..9151d5add9 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3248,7 +3248,7 @@ static void intel_enable_ddi(struct intel_atomic_state *state, intel_ddi_enable_transcoder_func(encoder, crtc_state); /* Enable/Disable DP2.0 SDP split config before transcoder */ - intel_audio_sdp_split_update(encoder, crtc_state); + intel_audio_sdp_split_update(crtc_state); intel_enable_transcoder(crtc_state); @@ -3762,6 +3762,11 @@ static void intel_ddi_read_func_ctl(struct intel_encoder *encoder, intel_cpu_transcoder_get_m1_n1(crtc, cpu_transcoder, &pipe_config->dp_m_n); + if (DISPLAY_VER(dev_priv) >= 11) + pipe_config->fec_enable = + intel_de_read(dev_priv, + dp_tp_ctl_reg(encoder, pipe_config)) & DP_TP_CTL_FEC_ENABLE; + pipe_config->infoframes.enable |= intel_hdmi_infoframes_enabled(encoder, pipe_config); break; @@ -3857,11 +3862,9 @@ static void mtl_ddi_get_config(struct intel_encoder *encoder, crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder); } else if (intel_is_c10phy(i915, phy)) { intel_c10pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10); - intel_c10pll_dump_hw_state(i915, &crtc_state->cx0pll_state.c10); crtc_state->port_clock = intel_c10pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10); } else { intel_c20pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c20); - intel_c20pll_dump_hw_state(i915, &crtc_state->cx0pll_state.c20); crtc_state->port_clock = intel_c20pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c20); } @@ -4173,7 +4176,7 @@ static int intel_ddi_compute_config_late(struct intel_encoder *encoder, struct drm_connector *connector = conn_state->connector; u8 port_sync_transcoders = 0; - drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] [CRTC:%d:%s]", + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] [CRTC:%d:%s]\n", encoder->base.base.id, encoder->base.name, crtc_state->uapi.crtc->base.id, crtc_state->uapi.crtc->name); @@ -4323,15 +4326,14 @@ static int intel_hdmi_reset_link(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_hdmi *hdmi = enc_to_intel_hdmi(encoder); struct intel_connector *connector = hdmi->attached_connector; - struct i2c_adapter *adapter = - intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus); + struct i2c_adapter *ddc = connector->base.ddc; struct drm_connector_state *conn_state; struct intel_crtc_state *crtc_state; struct intel_crtc *crtc; u8 config; int ret; - if (!connector || connector->base.status != connector_status_connected) + if (connector->base.status != connector_status_connected) return 0; ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, @@ -4365,7 +4367,7 @@ static int intel_hdmi_reset_link(struct intel_encoder *encoder, !try_wait_for_completion(&conn_state->commit->hw_done)) return 0; - ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); + ret = drm_scdc_readb(ddc, SCDC_TMDS_CONFIG, &config); if (ret < 0) { drm_err(&dev_priv->drm, "[CONNECTOR:%d:%s] Failed to read TMDS config: %d\n", connector->base.base.id, connector->base.name, ret); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index a072fbb987..df582ff81b 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -77,6 +77,7 @@ #include "intel_dpll_mgr.h" #include "intel_dpt.h" #include "intel_drrs.h" +#include "intel_dsb.h" #include "intel_dsi.h" #include "intel_dvo.h" #include "intel_fb.h" @@ -87,6 +88,7 @@ #include "intel_frontbuffer.h" #include "intel_hdmi.h" #include "intel_hotplug.h" +#include "intel_link_bw.h" #include "intel_lvds.h" #include "intel_lvds_regs.h" #include "intel_modeset_setup.h" @@ -726,7 +728,7 @@ static void icl_set_pipe_chicken(const struct intel_crtc_state *crtc_state) tmp |= UNDERRUN_RECOVERY_DISABLE_ADLP; /* Wa_14010547955:dg2 */ - if (IS_DG2_DISPLAY_STEP(dev_priv, STEP_B0, STEP_FOREVER)) + if (IS_DG2(dev_priv)) tmp |= DG2_RENDER_CCSTAG_4_3_EN; intel_de_write(dev_priv, PIPE_CHICKEN(pipe), tmp); @@ -904,25 +906,53 @@ static bool needs_async_flip_vtd_wa(const struct intel_crtc_state *crtc_state) static bool planes_enabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { + if (!new_crtc_state->hw.active) + return false; + return is_enabling(active_planes, old_crtc_state, new_crtc_state); } static bool planes_disabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { + if (!old_crtc_state->hw.active) + return false; + return is_disabling(active_planes, old_crtc_state, new_crtc_state); } +static bool vrr_params_changed(const struct intel_crtc_state *old_crtc_state, + const struct intel_crtc_state *new_crtc_state) +{ + return old_crtc_state->vrr.flipline != new_crtc_state->vrr.flipline || + old_crtc_state->vrr.vmin != new_crtc_state->vrr.vmin || + old_crtc_state->vrr.vmax != new_crtc_state->vrr.vmax || + old_crtc_state->vrr.guardband != new_crtc_state->vrr.guardband || + old_crtc_state->vrr.pipeline_full != new_crtc_state->vrr.pipeline_full; +} + static bool vrr_enabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { - return is_enabling(vrr.enable, old_crtc_state, new_crtc_state); + if (!new_crtc_state->hw.active) + return false; + + return is_enabling(vrr.enable, old_crtc_state, new_crtc_state) || + (new_crtc_state->vrr.enable && + (new_crtc_state->update_m_n || new_crtc_state->update_lrr || + vrr_params_changed(old_crtc_state, new_crtc_state))); } static bool vrr_disabling(const struct intel_crtc_state *old_crtc_state, const struct intel_crtc_state *new_crtc_state) { - return is_disabling(vrr.enable, old_crtc_state, new_crtc_state); + if (!old_crtc_state->hw.active) + return false; + + return is_disabling(vrr.enable, old_crtc_state, new_crtc_state) || + (old_crtc_state->vrr.enable && + (new_crtc_state->update_m_n || new_crtc_state->update_lrr || + vrr_params_changed(old_crtc_state, new_crtc_state))); } #undef is_disabling @@ -938,6 +968,8 @@ static void intel_post_plane_update(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); enum pipe pipe = crtc->pipe; + intel_psr_post_plane_update(state, crtc); + intel_frontbuffer_flip(dev_priv, new_crtc_state->fb_bits); if (new_crtc_state->update_wm_post && new_crtc_state->hw.active) @@ -1767,7 +1799,7 @@ bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy) if (IS_DG2(dev_priv)) /* DG2's "TC1" output uses a SNPS PHY */ return false; - else if (IS_ALDERLAKE_P(dev_priv) || IS_METEORLAKE(dev_priv)) + else if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER_FULL(dev_priv) == IP_VER(14, 0)) return phy >= PHY_F && phy <= PHY_I; else if (IS_TIGERLAKE(dev_priv)) return phy >= PHY_D && phy <= PHY_I; @@ -2570,6 +2602,37 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta VTOTAL(crtc_vtotal - 1)); } +static void intel_set_transcoder_timings_lrr(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); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + u32 crtc_vdisplay, crtc_vtotal, crtc_vblank_start, crtc_vblank_end; + + crtc_vdisplay = adjusted_mode->crtc_vdisplay; + crtc_vtotal = adjusted_mode->crtc_vtotal; + crtc_vblank_start = adjusted_mode->crtc_vblank_start; + crtc_vblank_end = adjusted_mode->crtc_vblank_end; + + drm_WARN_ON(&dev_priv->drm, adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE); + + /* + * The hardware actually ignores TRANS_VBLANK.VBLANK_END in DP mode. + * But let's write it anyway to keep the state checker happy. + */ + intel_de_write(dev_priv, TRANS_VBLANK(cpu_transcoder), + VBLANK_START(crtc_vblank_start - 1) | + VBLANK_END(crtc_vblank_end - 1)); + /* + * The double buffer latch point for TRANS_VTOTAL + * is the transcoder's undelayed vblank. + */ + intel_de_write(dev_priv, TRANS_VTOTAL(cpu_transcoder), + VACTIVE(crtc_vdisplay - 1) | + VTOTAL(crtc_vtotal - 1)); +} + static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -2869,24 +2932,6 @@ bdw_get_pipe_misc_output_format(struct intel_crtc *crtc) } } -static void i9xx_get_pipe_color_config(struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct intel_plane *plane = to_intel_plane(crtc->base.primary); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - u32 tmp; - - tmp = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); - - if (tmp & DISP_PIPE_GAMMA_ENABLE) - crtc_state->gamma_enable = true; - - if (!HAS_GMCH(dev_priv) && - tmp & DISP_PIPE_CSC_ENABLE) - crtc_state->csc_enable = true; -} - static bool i9xx_get_pipe_config(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { @@ -2942,11 +2987,6 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, (tmp & TRANSCONF_WGC_ENABLE)) pipe_config->wgc_enable = true; - if (IS_CHERRYVIEW(dev_priv)) - pipe_config->cgm_mode = intel_de_read(dev_priv, - CGM_PIPE_MODE(crtc->pipe)); - - i9xx_get_pipe_color_config(pipe_config); intel_color_get_config(pipe_config); if (DISPLAY_VER(dev_priv) < 4) @@ -3344,10 +3384,6 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc, pipe_config->msa_timing_delay = REG_FIELD_GET(TRANSCONF_MSA_TIMING_DELAY_MASK, tmp); - pipe_config->csc_mode = intel_de_read(dev_priv, - PIPE_CSC_MODE(crtc->pipe)); - - i9xx_get_pipe_color_config(pipe_config); intel_color_get_config(pipe_config); pipe_config->pixel_multiplier = 1; @@ -3711,8 +3747,8 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, if (!active) goto out; - intel_dsc_get_config(pipe_config); intel_bigjoiner_get_config(pipe_config); + intel_dsc_get_config(pipe_config); if (!transcoder_is_dsi(pipe_config->cpu_transcoder) || DISPLAY_VER(dev_priv) >= 11) @@ -3738,24 +3774,6 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, pipe_config->sink_format = pipe_config->output_format; - pipe_config->gamma_mode = intel_de_read(dev_priv, - GAMMA_MODE(crtc->pipe)); - - pipe_config->csc_mode = intel_de_read(dev_priv, - PIPE_CSC_MODE(crtc->pipe)); - - if (DISPLAY_VER(dev_priv) >= 9) { - tmp = intel_de_read(dev_priv, SKL_BOTTOM_COLOR(crtc->pipe)); - - if (tmp & SKL_BOTTOM_COLOR_GAMMA_ENABLE) - pipe_config->gamma_enable = true; - - if (tmp & SKL_BOTTOM_COLOR_CSC_ENABLE) - pipe_config->csc_enable = true; - } else { - i9xx_get_pipe_color_config(pipe_config); - } - intel_color_get_config(pipe_config); tmp = intel_de_read(dev_priv, WM_LINETIME(crtc->pipe)); @@ -3993,7 +4011,7 @@ intel_encoder_current_mode(struct intel_encoder *encoder) } if (!intel_crtc_get_pipe_config(crtc_state)) { - kfree(crtc_state); + intel_crtc_destroy_state(&crtc->base, &crtc_state->uapi); kfree(mode); return NULL; } @@ -4002,7 +4020,7 @@ intel_encoder_current_mode(struct intel_encoder *encoder) intel_mode_from_crtc_timings(mode, &crtc_state->hw.adjusted_mode); - kfree(crtc_state); + intel_crtc_destroy_state(&crtc->base, &crtc_state->uapi); return mode; } @@ -4641,7 +4659,8 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state, static int intel_modeset_pipe_config(struct intel_atomic_state *state, - struct intel_crtc *crtc) + struct intel_crtc *crtc, + const struct intel_link_bw_limits *limits) { struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_crtc_state *crtc_state = @@ -4650,7 +4669,6 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, struct drm_connector_state *connector_state; int pipe_src_w, pipe_src_h; int base_bpp, ret, i; - bool retry = true; crtc_state->cpu_transcoder = (enum transcoder) crtc->pipe; @@ -4673,6 +4691,16 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, if (ret) return ret; + crtc_state->max_link_bpp_x16 = limits->max_bpp_x16[crtc->pipe]; + + if (crtc_state->pipe_bpp > to_bpp_int(crtc_state->max_link_bpp_x16)) { + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s] Link bpp limited to " BPP_X16_FMT "\n", + crtc->base.base.id, crtc->base.name, + BPP_X16_ARGS(crtc_state->max_link_bpp_x16)); + crtc_state->bw_constrained = true; + } + base_bpp = crtc_state->pipe_bpp; /* @@ -4714,7 +4742,6 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, crtc_state->output_types |= BIT(encoder->type); } -encoder_retry: /* Ensure the port clock defaults are reset when retrying. */ crtc_state->port_clock = 0; crtc_state->pixel_multiplier = 1; @@ -4754,17 +4781,6 @@ encoder_retry: ret = intel_crtc_compute_config(state, crtc); if (ret == -EDEADLK) return ret; - if (ret == -EAGAIN) { - if (drm_WARN(&i915->drm, !retry, - "[CRTC:%d:%s] loop in pipe configuration computation\n", - crtc->base.base.id, crtc->base.name)) - return -EINVAL; - - drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] bw constrained, retrying\n", - crtc->base.base.id, crtc->base.name); - retry = false; - goto encoder_retry; - } if (ret < 0) { drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] config failure: %d\n", crtc->base.base.id, crtc->base.name, ret); @@ -4984,9 +5000,6 @@ pipe_config_mismatch(bool fastset, const struct intel_crtc *crtc, static bool fastboot_enabled(struct drm_i915_private *dev_priv) { - if (dev_priv->params.fastboot != -1) - return dev_priv->params.fastboot; - /* Enable fastboot by default on Skylake and newer */ if (DISPLAY_VER(dev_priv) >= 9) return true; @@ -5111,11 +5124,13 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(name.crtc_hsync_start); \ PIPE_CONF_CHECK_I(name.crtc_hsync_end); \ PIPE_CONF_CHECK_I(name.crtc_vdisplay); \ - PIPE_CONF_CHECK_I(name.crtc_vtotal); \ PIPE_CONF_CHECK_I(name.crtc_vblank_start); \ - PIPE_CONF_CHECK_I(name.crtc_vblank_end); \ PIPE_CONF_CHECK_I(name.crtc_vsync_start); \ PIPE_CONF_CHECK_I(name.crtc_vsync_end); \ + if (!fastset || !pipe_config->update_lrr) { \ + PIPE_CONF_CHECK_I(name.crtc_vtotal); \ + PIPE_CONF_CHECK_I(name.crtc_vblank_end); \ + } \ } while (0) #define PIPE_CONF_CHECK_RECT(name) do { \ @@ -5215,7 +5230,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_X(lane_lat_optim_mask); if (HAS_DOUBLE_BUFFERED_M_N(dev_priv)) { - if (!fastset || !pipe_config->seamless_m_n) + if (!fastset || !pipe_config->update_m_n) PIPE_CONF_CHECK_M_N(dp_m_n); } else { PIPE_CONF_CHECK_M_N(dp_m_n); @@ -5353,7 +5368,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, if (IS_G4X(dev_priv) || DISPLAY_VER(dev_priv) >= 5) PIPE_CONF_CHECK_I(pipe_bpp); - if (!fastset || !pipe_config->seamless_m_n) { + if (!fastset || !pipe_config->update_m_n) { PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_clock); PIPE_CONF_CHECK_I(hw.adjusted_mode.crtc_clock); } @@ -5378,6 +5393,37 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(master_transcoder); PIPE_CONF_CHECK_X(bigjoiner_pipes); + PIPE_CONF_CHECK_BOOL(dsc.config.block_pred_enable); + PIPE_CONF_CHECK_BOOL(dsc.config.convert_rgb); + PIPE_CONF_CHECK_BOOL(dsc.config.simple_422); + PIPE_CONF_CHECK_BOOL(dsc.config.native_422); + PIPE_CONF_CHECK_BOOL(dsc.config.native_420); + PIPE_CONF_CHECK_BOOL(dsc.config.vbr_enable); + PIPE_CONF_CHECK_I(dsc.config.line_buf_depth); + PIPE_CONF_CHECK_I(dsc.config.bits_per_component); + PIPE_CONF_CHECK_I(dsc.config.pic_width); + PIPE_CONF_CHECK_I(dsc.config.pic_height); + PIPE_CONF_CHECK_I(dsc.config.slice_width); + PIPE_CONF_CHECK_I(dsc.config.slice_height); + PIPE_CONF_CHECK_I(dsc.config.initial_dec_delay); + PIPE_CONF_CHECK_I(dsc.config.initial_xmit_delay); + PIPE_CONF_CHECK_I(dsc.config.scale_decrement_interval); + PIPE_CONF_CHECK_I(dsc.config.scale_increment_interval); + PIPE_CONF_CHECK_I(dsc.config.initial_scale_value); + PIPE_CONF_CHECK_I(dsc.config.first_line_bpg_offset); + PIPE_CONF_CHECK_I(dsc.config.flatness_min_qp); + PIPE_CONF_CHECK_I(dsc.config.flatness_max_qp); + PIPE_CONF_CHECK_I(dsc.config.slice_bpg_offset); + PIPE_CONF_CHECK_I(dsc.config.nfl_bpg_offset); + PIPE_CONF_CHECK_I(dsc.config.initial_offset); + PIPE_CONF_CHECK_I(dsc.config.final_offset); + PIPE_CONF_CHECK_I(dsc.config.rc_model_size); + PIPE_CONF_CHECK_I(dsc.config.rc_quant_incr_limit0); + PIPE_CONF_CHECK_I(dsc.config.rc_quant_incr_limit1); + PIPE_CONF_CHECK_I(dsc.config.slice_chunk_size); + PIPE_CONF_CHECK_I(dsc.config.second_line_bpg_offset); + PIPE_CONF_CHECK_I(dsc.config.nsl_bpg_offset); + PIPE_CONF_CHECK_I(dsc.compression_enable); PIPE_CONF_CHECK_I(dsc.dsc_split); PIPE_CONF_CHECK_I(dsc.compressed_bpp); @@ -5386,13 +5432,14 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(splitter.link_count); PIPE_CONF_CHECK_I(splitter.pixel_overlap); - if (!fastset) + if (!fastset) { PIPE_CONF_CHECK_BOOL(vrr.enable); - PIPE_CONF_CHECK_I(vrr.vmin); - PIPE_CONF_CHECK_I(vrr.vmax); - PIPE_CONF_CHECK_I(vrr.flipline); - PIPE_CONF_CHECK_I(vrr.pipeline_full); - PIPE_CONF_CHECK_I(vrr.guardband); + PIPE_CONF_CHECK_I(vrr.vmin); + PIPE_CONF_CHECK_I(vrr.vmax); + PIPE_CONF_CHECK_I(vrr.flipline); + PIPE_CONF_CHECK_I(vrr.pipeline_full); + PIPE_CONF_CHECK_I(vrr.guardband); + } #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I @@ -5421,17 +5468,54 @@ intel_verify_planes(struct intel_atomic_state *state) plane_state->uapi.visible); } -int intel_modeset_all_pipes(struct intel_atomic_state *state, - const char *reason) +static int intel_modeset_pipe(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state, + const char *reason) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + int ret; + + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] Full modeset due to %s\n", + crtc->base.base.id, crtc->base.name, reason); + + ret = drm_atomic_add_affected_connectors(&state->base, + &crtc->base); + if (ret) + return ret; + + ret = intel_dp_mst_add_topology_state_for_crtc(state, crtc); + if (ret) + return ret; + + ret = intel_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + + crtc_state->uapi.mode_changed = true; + + return 0; +} + +/** + * intel_modeset_pipes_in_mask_early - force a full modeset on a set of pipes + * @state: intel atomic state + * @reason: the reason for the full modeset + * @mask: mask of pipes to modeset + * + * Add pipes in @mask to @state and force a full modeset on the enabled ones + * due to the description in @reason. + * This function can be called only before new plane states are computed. + * + * Returns 0 in case of success, negative error code otherwise. + */ +int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state, + const char *reason, u8 mask) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_crtc *crtc; - /* - * Add all pipes to the state, and force - * a modeset on all the active ones. - */ - for_each_intel_crtc(&dev_priv->drm, crtc) { + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, mask) { struct intel_crtc_state *crtc_state; int ret; @@ -5439,29 +5523,54 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (!crtc_state->hw.active || + if (!crtc_state->hw.enable || intel_crtc_needs_modeset(crtc_state)) continue; - drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] Full modeset due to %s\n", - crtc->base.base.id, crtc->base.name, reason); - - crtc_state->uapi.mode_changed = true; - crtc_state->update_pipe = false; - - ret = drm_atomic_add_affected_connectors(&state->base, - &crtc->base); + ret = intel_modeset_pipe(state, crtc_state, reason); if (ret) return ret; + } - ret = intel_dp_mst_add_topology_state_for_crtc(state, crtc); - if (ret) - return ret; + return 0; +} - ret = intel_atomic_add_affected_planes(state, crtc); +/** + * intel_modeset_all_pipes_late - force a full modeset on all pipes + * @state: intel atomic state + * @reason: the reason for the full modeset + * + * Add all pipes to @state and force a full modeset on the active ones due to + * the description in @reason. + * This function can be called only after new plane states are computed already. + * + * Returns 0 in case of success, negative error code otherwise. + */ +int intel_modeset_all_pipes_late(struct intel_atomic_state *state, + const char *reason) +{ + struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_crtc *crtc; + + for_each_intel_crtc(&dev_priv->drm, crtc) { + struct intel_crtc_state *crtc_state; + int ret; + + crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state->hw.active || + intel_crtc_needs_modeset(crtc_state)) + continue; + + ret = intel_modeset_pipe(state, crtc_state, reason); if (ret) return ret; + crtc_state->update_pipe = false; + crtc_state->update_m_n = false; + crtc_state->update_lrr = false; crtc_state->update_planes |= crtc_state->active_planes; crtc_state->async_flip_planes = 0; crtc_state->do_async_flip = false; @@ -5565,13 +5674,25 @@ static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_sta { struct drm_i915_private *i915 = to_i915(old_crtc_state->uapi.crtc->dev); - if (!intel_pipe_config_compare(old_crtc_state, new_crtc_state, true)) { + /* only allow LRR when the timings stay within the VRR range */ + if (old_crtc_state->vrr.in_range != new_crtc_state->vrr.in_range) + new_crtc_state->update_lrr = false; + + if (!intel_pipe_config_compare(old_crtc_state, new_crtc_state, true)) drm_dbg_kms(&i915->drm, "fastset requirement not met, forcing full modeset\n"); + else + new_crtc_state->uapi.mode_changed = false; - return; - } + if (intel_crtc_needs_modeset(new_crtc_state) || + intel_compare_link_m_n(&old_crtc_state->dp_m_n, + &new_crtc_state->dp_m_n)) + new_crtc_state->update_m_n = false; + + if (intel_crtc_needs_modeset(new_crtc_state) || + (old_crtc_state->hw.adjusted_mode.crtc_vtotal == new_crtc_state->hw.adjusted_mode.crtc_vtotal && + old_crtc_state->hw.adjusted_mode.crtc_vblank_end == new_crtc_state->hw.adjusted_mode.crtc_vblank_end)) + new_crtc_state->update_lrr = false; - new_crtc_state->uapi.mode_changed = false; if (!intel_crtc_needs_modeset(new_crtc_state)) new_crtc_state->update_pipe = true; } @@ -5912,6 +6033,17 @@ static int intel_async_flip_check_uapi(struct intel_atomic_state *state, return -EINVAL; } + /* + * FIXME: Bigjoiner+async flip is busted currently. + * Remove this check once the issues are fixed. + */ + if (new_crtc_state->bigjoiner_pipes) { + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s] async flip disallowed with bigjoiner\n", + crtc->base.base.id, crtc->base.name); + return -EINVAL; + } + for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { if (plane->pipe != crtc->pipe) @@ -5977,17 +6109,6 @@ static int intel_async_flip_check_hw(struct intel_atomic_state *state, struct in return -EINVAL; } - /* - * FIXME: Bigjoiner+async flip is busted currently. - * Remove this check once the issues are fixed. - */ - if (new_crtc_state->bigjoiner_pipes) { - drm_dbg_kms(&i915->drm, - "[CRTC:%d:%s] async flip disallowed with bigjoiner\n", - crtc->base.base.id, crtc->base.name); - return -EINVAL; - } - for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { if (plane->pipe != crtc->pipe) @@ -6183,6 +6304,101 @@ static int intel_bigjoiner_add_affected_crtcs(struct intel_atomic_state *state) return 0; } +static int intel_atomic_check_config(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits, + enum pipe *failed_pipe) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_crtc_state *new_crtc_state; + struct intel_crtc *crtc; + int ret; + int i; + + *failed_pipe = INVALID_PIPE; + + ret = intel_bigjoiner_add_affected_crtcs(state); + if (ret) + return ret; + + ret = intel_fdi_add_affected_crtcs(state); + if (ret) + return ret; + + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + if (!intel_crtc_needs_modeset(new_crtc_state)) { + if (intel_crtc_is_bigjoiner_slave(new_crtc_state)) + copy_bigjoiner_crtc_state_nomodeset(state, crtc); + else + intel_crtc_copy_uapi_to_hw_state_nomodeset(state, crtc); + continue; + } + + if (intel_crtc_is_bigjoiner_slave(new_crtc_state)) { + drm_WARN_ON(&i915->drm, new_crtc_state->uapi.enable); + continue; + } + + ret = intel_crtc_prepare_cleared_state(state, crtc); + if (ret) + break; + + if (!new_crtc_state->hw.enable) + continue; + + ret = intel_modeset_pipe_config(state, crtc, limits); + if (ret) + break; + + ret = intel_atomic_check_bigjoiner(state, crtc); + if (ret) + break; + } + + if (ret) + *failed_pipe = crtc->pipe; + + return ret; +} + +static int intel_atomic_check_config_and_link(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_link_bw_limits new_limits; + struct intel_link_bw_limits old_limits; + int ret; + + intel_link_bw_init_limits(i915, &new_limits); + old_limits = new_limits; + + while (true) { + enum pipe failed_pipe; + + ret = intel_atomic_check_config(state, &new_limits, + &failed_pipe); + if (ret) { + /* + * The bpp limit for a pipe is below the minimum it supports, set the + * limit to the minimum and recalculate the config. + */ + if (ret == -EINVAL && + intel_link_bw_set_bpp_limit_for_pipe(state, + &old_limits, + &new_limits, + failed_pipe)) + continue; + + break; + } + + old_limits = new_limits; + + ret = intel_link_bw_atomic_check(state, &new_limits); + if (ret != -EAGAIN) + break; + } + + return ret; +} /** * intel_atomic_check - validate state object * @dev: drm device @@ -6227,43 +6443,12 @@ int intel_atomic_check(struct drm_device *dev, return ret; } - ret = intel_bigjoiner_add_affected_crtcs(state); + ret = intel_atomic_check_config_and_link(state); if (ret) goto fail; for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - if (!intel_crtc_needs_modeset(new_crtc_state)) { - if (intel_crtc_is_bigjoiner_slave(new_crtc_state)) - copy_bigjoiner_crtc_state_nomodeset(state, crtc); - else - intel_crtc_copy_uapi_to_hw_state_nomodeset(state, crtc); - continue; - } - - if (intel_crtc_is_bigjoiner_slave(new_crtc_state)) { - drm_WARN_ON(&dev_priv->drm, new_crtc_state->uapi.enable); - continue; - } - - ret = intel_crtc_prepare_cleared_state(state, crtc); - if (ret) - goto fail; - - if (!new_crtc_state->hw.enable) - continue; - - ret = intel_modeset_pipe_config(state, crtc); - if (ret) - goto fail; - - ret = intel_atomic_check_bigjoiner(state, crtc); - if (ret) - goto fail; - } - - for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, - new_crtc_state, i) { if (!intel_crtc_needs_modeset(new_crtc_state)) continue; @@ -6297,6 +6482,8 @@ int intel_atomic_check(struct drm_device *dev, if (intel_cpu_transcoders_need_modeset(state, BIT(master))) { new_crtc_state->uapi.mode_changed = true; new_crtc_state->update_pipe = false; + new_crtc_state->update_m_n = false; + new_crtc_state->update_lrr = false; } } @@ -6309,6 +6496,8 @@ int intel_atomic_check(struct drm_device *dev, if (intel_cpu_transcoders_need_modeset(state, trans)) { new_crtc_state->uapi.mode_changed = true; new_crtc_state->update_pipe = false; + new_crtc_state->update_m_n = false; + new_crtc_state->update_lrr = false; } } @@ -6316,6 +6505,8 @@ int intel_atomic_check(struct drm_device *dev, if (intel_pipes_need_modeset(state, new_crtc_state->bigjoiner_pipes)) { new_crtc_state->uapi.mode_changed = true; new_crtc_state->update_pipe = false; + new_crtc_state->update_m_n = false; + new_crtc_state->update_lrr = false; } } } @@ -6494,9 +6685,12 @@ static void intel_pipe_fastset(const struct intel_crtc_state *old_crtc_state, IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) hsw_set_linetime_wm(new_crtc_state); - if (new_crtc_state->seamless_m_n) + if (new_crtc_state->update_m_n) intel_cpu_transcoder_set_m1_n1(crtc, new_crtc_state->cpu_transcoder, &new_crtc_state->dp_m_n); + + if (new_crtc_state->update_lrr) + intel_set_transcoder_timings_lrr(new_crtc_state); } static void commit_pipe_pre_planes(struct intel_atomic_state *state, @@ -6533,6 +6727,8 @@ static void commit_pipe_post_planes(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); const struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); @@ -6544,6 +6740,9 @@ static void commit_pipe_post_planes(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) >= 9 && !intel_crtc_needs_modeset(new_crtc_state)) skl_detach_scalers(new_crtc_state); + + if (vrr_enabling(old_crtc_state, new_crtc_state)) + intel_vrr_enable(new_crtc_state); } static void intel_enable_crtc(struct intel_atomic_state *state, @@ -6584,12 +6783,6 @@ static void intel_update_crtc(struct intel_atomic_state *state, intel_dpt_configure(crtc); } - if (vrr_enabling(old_crtc_state, new_crtc_state)) { - intel_vrr_enable(new_crtc_state); - intel_crtc_update_active_timings(new_crtc_state, - new_crtc_state->vrr.enable); - } - if (!modeset) { if (new_crtc_state->preload_luts && intel_crtc_needs_color_update(new_crtc_state)) @@ -6603,6 +6796,9 @@ static void intel_update_crtc(struct intel_atomic_state *state, if (DISPLAY_VER(i915) >= 11 && intel_crtc_needs_fastset(new_crtc_state)) icl_set_pipe_chicken(new_crtc_state); + + if (vrr_params_changed(old_crtc_state, new_crtc_state)) + intel_vrr_set_transcoder_timings(new_crtc_state); } intel_fbc_update(state, crtc); @@ -6616,7 +6812,7 @@ static void intel_update_crtc(struct intel_atomic_state *state, intel_crtc_planes_update_noarm(state, crtc); /* Perform vblank evasion around commit operation */ - intel_pipe_update_start(new_crtc_state); + intel_pipe_update_start(state, crtc); commit_pipe_pre_planes(state, crtc); @@ -6624,7 +6820,17 @@ static void intel_update_crtc(struct intel_atomic_state *state, commit_pipe_post_planes(state, crtc); - intel_pipe_update_end(new_crtc_state); + intel_pipe_update_end(state, crtc); + + /* + * VRR/Seamless M/N update may need to update frame timings. + * + * FIXME Should be synchronized with the start of vblank somehow... + */ + if (vrr_enabling(old_crtc_state, new_crtc_state) || + new_crtc_state->update_m_n || new_crtc_state->update_lrr) + intel_crtc_update_active_timings(new_crtc_state, + new_crtc_state->vrr.enable); /* * We usually enable FIFO underrun interrupts as part of the @@ -7033,7 +7239,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_set_cdclk_pre_plane_update(state); - intel_modeset_verify_disabled(dev_priv, state); + intel_modeset_verify_disabled(state); } intel_sagv_pre_plane_update(state); @@ -7085,6 +7291,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { if (new_crtc_state->do_async_flip) intel_crtc_disable_flip_done(state, crtc); + + intel_color_wait_commit(new_crtc_state); } /* @@ -7111,14 +7319,13 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) } intel_dbuf_post_plane_update(state); - intel_psr_post_plane_update(state); for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { intel_post_plane_update(state, crtc); intel_modeset_put_crtc_power_domains(crtc, &put_domains[crtc->pipe]); - intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state); + intel_modeset_verify_crtc(state, crtc); /* Must be done after gamma readout due to HSW split gamma vs. IPS w/a */ hsw_ips_post_update(state, crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 13b0904d42..a05c7e2b78 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -190,8 +190,6 @@ enum aux_ch { AUX_CH_E_XELPD, }; -#define aux_ch_name(a) ((a) + 'A') - enum phy { PHY_NONE = -1, @@ -516,8 +514,10 @@ void intel_plane_fixup_bitmasks(struct intel_crtc_state *crtc_state); void intel_update_watermarks(struct drm_i915_private *i915); /* modesetting */ -int intel_modeset_all_pipes(struct intel_atomic_state *state, - const char *reason); +int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state, + const char *reason, u8 pipe_mask); +int intel_modeset_all_pipes_late(struct intel_atomic_state *state, + const char *reason); 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, diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 53e5c33e08..ccfe27630f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -175,6 +175,9 @@ struct intel_hotplug { /* Whether or not to count short HPD IRQs in HPD storms */ u8 hpd_short_storm_enabled; + /* Last state reported by oob_hotplug_event for each encoder */ + unsigned long oob_hotplug_last_state; + /* * if we get a HPD irq from DP and a HPD irq from non-DP * the non-DP HPD could block the workqueue on a mode config diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 63c1fb9e47..2836826f8c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -43,12 +43,16 @@ static int i915_frontbuffer_tracking(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); + spin_lock(&dev_priv->display.fb_tracking.lock); + seq_printf(m, "FB tracking busy bits: 0x%08x\n", dev_priv->display.fb_tracking.busy_bits); seq_printf(m, "FB tracking flip bits: 0x%08x\n", dev_priv->display.fb_tracking.flip_bits); + spin_unlock(&dev_priv->display.fb_tracking.lock); + return 0; } @@ -233,14 +237,13 @@ static void intel_dp_info(struct seq_file *m, struct intel_connector *connector) { struct intel_encoder *intel_encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder); - const struct edid *edid = drm_edid_raw(connector->detect_edid); seq_printf(m, "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]); seq_printf(m, "\taudio support: %s\n", str_yes_no(connector->base.display_info.has_audio)); drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports, - edid, &intel_dp->aux); + connector->detect_edid, &intel_dp->aux); } static void intel_dp_mst_info(struct seq_file *m, @@ -641,6 +644,7 @@ static int i915_display_info(struct seq_file *m, void *unused) static int i915_shared_dplls_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); + struct intel_shared_dpll *pll; int i; drm_modeset_lock_all(&dev_priv->drm); @@ -649,11 +653,9 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) dev_priv->display.dpll.ref_clks.nssc, dev_priv->display.dpll.ref_clks.ssc); - for (i = 0; i < dev_priv->display.dpll.num_shared_dpll; i++) { - struct intel_shared_dpll *pll = &dev_priv->display.dpll.shared_dplls[i]; - - seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->info->name, - pll->info->id); + for_each_shared_dpll(dev_priv, pll, i) { + seq_printf(m, "DPLL%i: %s, id: %i\n", pll->index, + pll->info->name, pll->info->id); seq_printf(m, " pipe_mask: 0x%x, active: 0x%x, on: %s\n", pll->state.pipe_mask, pll->active_mask, str_yes_no(pll->on)); @@ -1189,8 +1191,8 @@ DEFINE_SHOW_ATTRIBUTE(i915_lpsp_capability); static int i915_dsc_fec_support_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_device *dev = connector->dev; + struct intel_connector *connector = to_intel_connector(m->private); + struct drm_i915_private *i915 = to_i915(connector->base.dev); struct drm_crtc *crtc; struct intel_dp *intel_dp; struct drm_modeset_acquire_ctx ctx; @@ -1202,7 +1204,7 @@ static int i915_dsc_fec_support_show(struct seq_file *m, void *data) do { try_again = false; - ret = drm_modeset_lock(&dev->mode_config.connection_mutex, + ret = drm_modeset_lock(&i915->drm.mode_config.connection_mutex, &ctx); if (ret) { if (ret == -EDEADLK && !drm_modeset_backoff(&ctx)) { @@ -1211,8 +1213,8 @@ static int i915_dsc_fec_support_show(struct seq_file *m, void *data) } break; } - crtc = connector->state->crtc; - if (connector->status != connector_status_connected || !crtc) { + crtc = connector->base.state->crtc; + if (connector->base.status != connector_status_connected || !crtc) { ret = -ENODEV; break; } @@ -1227,24 +1229,24 @@ static int i915_dsc_fec_support_show(struct seq_file *m, void *data) } else if (ret) { break; } - intel_dp = intel_attached_dp(to_intel_connector(connector)); + intel_dp = intel_attached_dp(connector); crtc_state = to_intel_crtc_state(crtc->state); seq_printf(m, "DSC_Enabled: %s\n", str_yes_no(crtc_state->dsc.compression_enable)); seq_printf(m, "DSC_Sink_Support: %s\n", - str_yes_no(drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd))); + str_yes_no(drm_dp_sink_supports_dsc(connector->dp.dsc_dpcd))); seq_printf(m, "DSC_Output_Format_Sink_Support: RGB: %s YCBCR420: %s YCBCR444: %s\n", - str_yes_no(drm_dp_dsc_sink_supports_format(intel_dp->dsc_dpcd, + str_yes_no(drm_dp_dsc_sink_supports_format(connector->dp.dsc_dpcd, DP_DSC_RGB)), - str_yes_no(drm_dp_dsc_sink_supports_format(intel_dp->dsc_dpcd, + str_yes_no(drm_dp_dsc_sink_supports_format(connector->dp.dsc_dpcd, DP_DSC_YCbCr420_Native)), - str_yes_no(drm_dp_dsc_sink_supports_format(intel_dp->dsc_dpcd, + str_yes_no(drm_dp_dsc_sink_supports_format(connector->dp.dsc_dpcd, DP_DSC_YCbCr444))); seq_printf(m, "Force_DSC_Enable: %s\n", str_yes_no(intel_dp->force_dsc_en)); if (!intel_dp_is_edp(intel_dp)) seq_printf(m, "FEC_Sink_Support: %s\n", - str_yes_no(drm_dp_sink_supports_fec(intel_dp->fec_capable))); + str_yes_no(drm_dp_sink_supports_fec(connector->dp.fec_capability))); } while (try_again); drm_modeset_drop_locks(&ctx); diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index c39f8a15d8..2b1ec23ba9 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -710,18 +710,61 @@ static const struct intel_display_device_info xe_hpd_display = { BIT(PORT_TC1), }; +#define XE_LPDP_FEATURES \ + .abox_mask = GENMASK(1, 0), \ + .color = { \ + .degamma_lut_size = 129, .gamma_lut_size = 1024, \ + .degamma_lut_tests = DRM_COLOR_LUT_NON_DECREASING | \ + DRM_COLOR_LUT_EQUAL_CHANNELS, \ + }, \ + .dbuf.size = 4096, \ + .dbuf.slice_mask = BIT(DBUF_S1) | BIT(DBUF_S2) | BIT(DBUF_S3) | \ + BIT(DBUF_S4), \ + .has_cdclk_crawl = 1, \ + .has_cdclk_squash = 1, \ + .has_ddi = 1, \ + .has_dp_mst = 1, \ + .has_dsb = 1, \ + .has_fpga_dbg = 1, \ + .has_hotplug = 1, \ + .has_ipc = 1, \ + .has_psr = 1, \ + .pipe_offsets = { \ + [TRANSCODER_A] = PIPE_A_OFFSET, \ + [TRANSCODER_B] = PIPE_B_OFFSET, \ + [TRANSCODER_C] = PIPE_C_OFFSET, \ + [TRANSCODER_D] = PIPE_D_OFFSET, \ + }, \ + .trans_offsets = { \ + [TRANSCODER_A] = TRANSCODER_A_OFFSET, \ + [TRANSCODER_B] = TRANSCODER_B_OFFSET, \ + [TRANSCODER_C] = TRANSCODER_C_OFFSET, \ + [TRANSCODER_D] = TRANSCODER_D_OFFSET, \ + }, \ + TGL_CURSOR_OFFSETS, \ + \ + .__runtime_defaults.cpu_transcoder_mask = \ + BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | \ + BIT(TRANSCODER_C) | BIT(TRANSCODER_D), \ + .__runtime_defaults.fbc_mask = BIT(INTEL_FBC_A) | BIT(INTEL_FBC_B), \ + .__runtime_defaults.has_dmc = 1, \ + .__runtime_defaults.has_dsc = 1, \ + .__runtime_defaults.has_hdcp = 1, \ + .__runtime_defaults.pipe_mask = \ + BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D), \ + .__runtime_defaults.port_mask = BIT(PORT_A) | BIT(PORT_B) | \ + BIT(PORT_TC1) | BIT(PORT_TC2) | BIT(PORT_TC3) | BIT(PORT_TC4) + static const struct intel_display_device_info xe_lpdp_display = { - XE_LPD_FEATURES, - .has_cdclk_crawl = 1, - .has_cdclk_squash = 1, + XE_LPDP_FEATURES, +}; - .__runtime_defaults.ip.ver = 14, - .__runtime_defaults.fbc_mask = BIT(INTEL_FBC_A) | BIT(INTEL_FBC_B), - .__runtime_defaults.cpu_transcoder_mask = - BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | - BIT(TRANSCODER_C) | BIT(TRANSCODER_D), - .__runtime_defaults.port_mask = BIT(PORT_A) | BIT(PORT_B) | - BIT(PORT_TC1) | BIT(PORT_TC2) | BIT(PORT_TC3) | BIT(PORT_TC4), +static const struct intel_display_device_info xe2_lpd_display = { + XE_LPDP_FEATURES, + + .__runtime_defaults.fbc_mask = + BIT(INTEL_FBC_A) | BIT(INTEL_FBC_B) | + BIT(INTEL_FBC_C) | BIT(INTEL_FBC_D), }; /* @@ -803,6 +846,7 @@ static const struct { const struct intel_display_device_info *display; } gmdid_display_map[] = { { 14, 0, &xe_lpdp_display }, + { 20, 0, &xe2_lpd_display }, }; static const struct intel_display_device_info * @@ -850,16 +894,12 @@ probe_gmdid_display(struct drm_i915_private *i915, u16 *ver, u16 *rel, u16 *step return &no_display; } -const struct intel_display_device_info * -intel_display_device_probe(struct drm_i915_private *i915, bool has_gmdid, - u16 *gmdid_ver, u16 *gmdid_rel, u16 *gmdid_step) +static const struct intel_display_device_info * +probe_display(struct drm_i915_private *i915) { struct pci_dev *pdev = to_pci_dev(i915->drm.dev); int i; - if (has_gmdid) - return probe_gmdid_display(i915, gmdid_ver, gmdid_rel, gmdid_step); - if (has_no_display(pdev)) { drm_dbg_kms(&i915->drm, "Device doesn't have display\n"); return &no_display; @@ -876,7 +916,30 @@ intel_display_device_probe(struct drm_i915_private *i915, bool has_gmdid, return &no_display; } -void intel_display_device_info_runtime_init(struct drm_i915_private *i915) +void intel_display_device_probe(struct drm_i915_private *i915) +{ + const struct intel_display_device_info *info; + u16 ver, rel, step; + + if (HAS_GMD_ID(i915)) + info = probe_gmdid_display(i915, &ver, &rel, &step); + else + info = probe_display(i915); + + DISPLAY_INFO(i915) = info; + + memcpy(DISPLAY_RUNTIME_INFO(i915), + &DISPLAY_INFO(i915)->__runtime_defaults, + sizeof(*DISPLAY_RUNTIME_INFO(i915))); + + if (HAS_GMD_ID(i915)) { + DISPLAY_RUNTIME_INFO(i915)->ip.ver = ver; + DISPLAY_RUNTIME_INFO(i915)->ip.rel = rel; + DISPLAY_RUNTIME_INFO(i915)->ip.step = step; + } +} + +static void __intel_display_device_info_runtime_init(struct drm_i915_private *i915) { struct intel_display_runtime_info *display_runtime = DISPLAY_RUNTIME_INFO(i915); enum pipe pipe; @@ -885,6 +948,13 @@ void intel_display_device_info_runtime_init(struct drm_i915_private *i915) BUILD_BUG_ON(BITS_PER_TYPE(display_runtime->cpu_transcoder_mask) < I915_MAX_TRANSCODERS); BUILD_BUG_ON(BITS_PER_TYPE(display_runtime->port_mask) < I915_MAX_PORTS); + /* This covers both ULT and ULX */ + if (IS_HASWELL_ULT(i915) || IS_BROADWELL_ULT(i915)) + display_runtime->port_mask &= ~BIT(PORT_D); + + if (IS_ICL_WITH_PORT_F(i915)) + display_runtime->port_mask |= BIT(PORT_F); + /* Wa_14011765242: adl-s A0,A1 */ if (IS_ALDERLAKE_S(i915) && IS_DISPLAY_STEP(i915, STEP_A0, STEP_A2)) for_each_pipe(i915, pipe) @@ -970,16 +1040,19 @@ void intel_display_device_info_runtime_init(struct drm_i915_private *i915) if (dfsm & SKL_DFSM_PIPE_B_DISABLE) { display_runtime->pipe_mask &= ~BIT(PIPE_B); display_runtime->cpu_transcoder_mask &= ~BIT(TRANSCODER_B); + display_runtime->fbc_mask &= ~BIT(INTEL_FBC_B); } if (dfsm & SKL_DFSM_PIPE_C_DISABLE) { display_runtime->pipe_mask &= ~BIT(PIPE_C); display_runtime->cpu_transcoder_mask &= ~BIT(TRANSCODER_C); + display_runtime->fbc_mask &= ~BIT(INTEL_FBC_C); } if (DISPLAY_VER(i915) >= 12 && (dfsm & TGL_DFSM_PIPE_D_DISABLE)) { display_runtime->pipe_mask &= ~BIT(PIPE_D); display_runtime->cpu_transcoder_mask &= ~BIT(TRANSCODER_D); + display_runtime->fbc_mask &= ~BIT(INTEL_FBC_D); } if (!display_runtime->pipe_mask) @@ -999,12 +1072,44 @@ void intel_display_device_info_runtime_init(struct drm_i915_private *i915) display_runtime->has_dsc = 0; } + if (DISPLAY_VER(i915) >= 20) { + u32 cap = intel_de_read(i915, XE2LPD_DE_CAP); + + if (REG_FIELD_GET(XE2LPD_DE_CAP_DSC_MASK, cap) == + XE2LPD_DE_CAP_DSC_REMOVED) + display_runtime->has_dsc = 0; + + if (REG_FIELD_GET(XE2LPD_DE_CAP_SCALER_MASK, cap) == + XE2LPD_DE_CAP_SCALER_SINGLE) { + for_each_pipe(i915, pipe) + if (display_runtime->num_scalers[pipe]) + display_runtime->num_scalers[pipe] = 1; + } + } + return; display_fused_off: memset(display_runtime, 0, sizeof(*display_runtime)); } +void intel_display_device_info_runtime_init(struct drm_i915_private *i915) +{ + if (HAS_DISPLAY(i915)) + __intel_display_device_info_runtime_init(i915); + + /* Display may have been disabled by runtime init */ + if (!HAS_DISPLAY(i915)) { + i915->drm.driver_features &= ~(DRIVER_MODESET | DRIVER_ATOMIC); + i915->display.info.__device_info = &no_display; + } + + /* Disable nuclear pageflip by default on pre-g4x */ + if (!i915->params.nuclear_pageflip && + DISPLAY_VER(i915) < 5 && !IS_G4X(i915)) + i915->drm.driver_features &= ~DRIVER_ATOMIC; +} + void intel_display_device_info_print(const struct intel_display_device_info *info, const struct intel_display_runtime_info *runtime, struct drm_printer *p) @@ -1025,3 +1130,20 @@ void intel_display_device_info_print(const struct intel_display_device_info *inf drm_printf(p, "has_dmc: %s\n", str_yes_no(runtime->has_dmc)); drm_printf(p, "has_dsc: %s\n", str_yes_no(runtime->has_dsc)); } + +/* + * Assuming the device has display hardware, should it be enabled? + * + * It's an error to call this function if the device does not have display + * hardware. + * + * Disabling display means taking over the display hardware, putting it to + * sleep, and preventing connectors from being connected via any means. + */ +bool intel_display_device_enabled(struct drm_i915_private *i915) +{ + /* Only valid when HAS_DISPLAY() is true */ + drm_WARN_ON(&i915->drm, !HAS_DISPLAY(i915)); + + return !i915->params.disable_display && !intel_opregion_headless_sku(i915); +} diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index 215e682bd8..5b5c0e5330 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -32,6 +32,7 @@ struct drm_printer; func(overlay_needs_physical); \ func(supports_tv); +#define HAS_4TILE(i915) (IS_DG2(i915) || DISPLAY_VER(i915) >= 14) #define HAS_ASYNC_FLIPS(i915) (DISPLAY_VER(i915) >= 5) #define HAS_CDCLK_CRAWL(i915) (DISPLAY_INFO(i915)->has_cdclk_crawl) #define HAS_CDCLK_SQUASH(i915) (DISPLAY_INFO(i915)->has_cdclk_squash) @@ -55,6 +56,7 @@ struct drm_printer; #define HAS_HW_SAGV_WM(i915) (DISPLAY_VER(i915) >= 13 && !IS_DGFX(i915)) #define HAS_IPC(i915) (DISPLAY_INFO(i915)->has_ipc) #define HAS_IPS(i915) (IS_HASWELL_ULT(i915) || IS_BROADWELL(i915)) +#define HAS_LRR(i915) (DISPLAY_VER(i915) >= 12) #define HAS_LSPCON(i915) (IS_DISPLAY_VER(i915, 9, 10)) #define HAS_MBUS_JOINING(i915) (IS_ALDERLAKE_P(i915) || DISPLAY_VER(i915) >= 14) #define HAS_MSO(i915) (DISPLAY_VER(i915) >= 12) @@ -71,6 +73,40 @@ struct drm_printer; #define OVERLAY_NEEDS_PHYSICAL(i915) (DISPLAY_INFO(i915)->overlay_needs_physical) #define SUPPORTS_TV(i915) (DISPLAY_INFO(i915)->supports_tv) +/* Check that device has a display IP version within the specific range. */ +#define IS_DISPLAY_IP_RANGE(__i915, from, until) ( \ + BUILD_BUG_ON_ZERO((from) < IP_VER(2, 0)) + \ + (DISPLAY_VER_FULL(__i915) >= (from) && \ + DISPLAY_VER_FULL(__i915) <= (until))) + +/* + * Check if a device has a specific IP version as well as a stepping within the + * specified range [from, until). The lower bound is inclusive, the upper + * bound is exclusive. The most common use-case of this macro is for checking + * bounds for workarounds, which usually have a stepping ("from") at which the + * hardware issue is first present and another stepping ("until") at which a + * hardware fix is present and the software workaround is no longer necessary. + * E.g., + * + * IS_DISPLAY_IP_STEP(i915, IP_VER(14, 0), STEP_A0, STEP_B2) + * IS_DISPLAY_IP_STEP(i915, IP_VER(14, 0), STEP_C0, STEP_FOREVER) + * + * "STEP_FOREVER" can be passed as "until" for workarounds that have no upper + * stepping bound for the specified IP version. + */ +#define IS_DISPLAY_IP_STEP(__i915, ipver, from, until) \ + (IS_DISPLAY_IP_RANGE((__i915), (ipver), (ipver)) && \ + IS_DISPLAY_STEP((__i915), (from), (until))) + +#define DISPLAY_INFO(i915) ((i915)->display.info.__device_info) +#define DISPLAY_RUNTIME_INFO(i915) (&(i915)->display.info.__runtime_info) + +#define DISPLAY_VER(i915) (DISPLAY_RUNTIME_INFO(i915)->ip.ver) +#define DISPLAY_VER_FULL(i915) IP_VER(DISPLAY_RUNTIME_INFO(i915)->ip.ver, \ + DISPLAY_RUNTIME_INFO(i915)->ip.rel) +#define IS_DISPLAY_VER(i915, from, until) \ + (DISPLAY_VER(i915) >= (from) && DISPLAY_VER(i915) <= (until)) + struct intel_display_runtime_info { struct { u16 ver; @@ -123,9 +159,8 @@ struct intel_display_device_info { } color; }; -const struct intel_display_device_info * -intel_display_device_probe(struct drm_i915_private *i915, bool has_gmdid, - u16 *ver, u16 *rel, u16 *step); +bool intel_display_device_enabled(struct drm_i915_private *i915); +void intel_display_device_probe(struct drm_i915_private *i915); void intel_display_device_info_runtime_init(struct drm_i915_private *i915); void intel_display_device_info_print(const struct intel_display_device_info *info, diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 8f144d4d3c..44b59ac301 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -31,6 +31,7 @@ #include "intel_display_irq.h" #include "intel_display_power.h" #include "intel_display_types.h" +#include "intel_display_wa.h" #include "intel_dkl_phy.h" #include "intel_dmc.h" #include "intel_dp.h" @@ -88,6 +89,8 @@ void intel_display_driver_init_hw(struct drm_i915_private *i915) intel_update_cdclk(i915); intel_cdclk_dump_config(i915, &i915->display.cdclk.hw, "Current CDCLK"); cdclk_state->logical = cdclk_state->actual = i915->display.cdclk.hw; + + intel_display_wa_apply(i915); } static const struct drm_mode_config_funcs intel_mode_funcs = { @@ -377,6 +380,8 @@ int intel_display_driver_probe(struct drm_i915_private *i915) void intel_display_driver_register(struct drm_i915_private *i915) { + struct drm_printer p = drm_debug_printer("i915 display info:"); + if (!HAS_DISPLAY(i915)) return; @@ -404,6 +409,9 @@ void intel_display_driver_register(struct drm_i915_private *i915) * fbdev->async_cookie. */ drm_kms_helper_poll_init(&i915->drm); + + intel_display_device_info_print(DISPLAY_INFO(i915), + DISPLAY_RUNTIME_INFO(i915), &p); } /* part #1: call before irq uninstall */ diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 62ce554755..bff4a76310 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -792,7 +792,9 @@ static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) { u32 mask; - if (DISPLAY_VER(dev_priv) >= 14) + if (DISPLAY_VER(dev_priv) >= 20) + return 0; + else if (DISPLAY_VER(dev_priv) >= 14) return TGL_DE_PORT_AUX_DDIA | TGL_DE_PORT_AUX_DDIB; else if (DISPLAY_VER(dev_priv) >= 13) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 9e01054c24..e25785ae1c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -186,8 +186,6 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) return "GMBUS"; case POWER_DOMAIN_INIT: return "INIT"; - case POWER_DOMAIN_MODESET: - return "MODESET"; case POWER_DOMAIN_GT_IRQ: return "GT_IRQ"; case POWER_DOMAIN_DC_OFF: @@ -218,7 +216,7 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv, struct i915_power_well *power_well; bool is_enabled; - if (dev_priv->runtime_pm.suspended) + if (pm_runtime_suspended(dev_priv->drm.dev)) return false; is_enabled = true; @@ -338,8 +336,6 @@ unlock: mutex_unlock(&power_domains->lock); } -#define POWER_DOMAIN_MASK (GENMASK_ULL(POWER_DOMAIN_NUM - 1, 0)) - static void __async_put_domains_mask(struct i915_power_domains *power_domains, struct intel_power_domain_mask *mask) { @@ -947,7 +943,9 @@ static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv, if (!HAS_DISPLAY(dev_priv)) return 0; - if (IS_DG2(dev_priv)) + if (DISPLAY_VER(dev_priv) >= 20) + max_dc = 2; + else if (IS_DG2(dev_priv)) max_dc = 1; else if (IS_DG1(dev_priv)) max_dc = 3; diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h index d3b5d04b7b..d6c2a5846b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.h +++ b/drivers/gpu/drm/i915/display/intel_display_power.h @@ -108,7 +108,6 @@ enum intel_display_power_domain { POWER_DOMAIN_AUX_TBT6, POWER_DOMAIN_GMBUS, - POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_TC_COLD_OFF, diff --git a/drivers/gpu/drm/i915/display/intel_display_power_map.c b/drivers/gpu/drm/i915/display/intel_display_power_map.c index 5ad04cd42c..10948b3964 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_map.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_map.c @@ -332,7 +332,6 @@ I915_DECL_PW_DOMAINS(skl_pwdoms_pw_2, I915_DECL_PW_DOMAINS(skl_pwdoms_dc_off, SKL_PW_2_POWER_DOMAINS, POWER_DOMAIN_AUX_A, - POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -437,7 +436,6 @@ I915_DECL_PW_DOMAINS(bxt_pwdoms_dc_off, BXT_PW_2_POWER_DOMAINS, POWER_DOMAIN_AUX_A, POWER_DOMAIN_GMBUS, - POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -519,7 +517,6 @@ I915_DECL_PW_DOMAINS(glk_pwdoms_dc_off, GLK_PW_2_POWER_DOMAINS, POWER_DOMAIN_AUX_A, POWER_DOMAIN_GMBUS, - POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -685,7 +682,6 @@ I915_DECL_PW_DOMAINS(icl_pwdoms_pw_2, I915_DECL_PW_DOMAINS(icl_pwdoms_dc_off, ICL_PW_2_POWER_DOMAINS, POWER_DOMAIN_AUX_A, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -861,7 +857,6 @@ I915_DECL_PW_DOMAINS(tgl_pwdoms_dc_off, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, POWER_DOMAIN_AUX_C, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -1058,7 +1053,6 @@ I915_DECL_PW_DOMAINS(rkl_pwdoms_dc_off, RKL_PW_3_POWER_DOMAINS, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -1141,7 +1135,6 @@ I915_DECL_PW_DOMAINS(dg1_pwdoms_dc_off, POWER_DOMAIN_AUDIO_MMIO, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -1311,7 +1304,6 @@ I915_DECL_PW_DOMAINS(xelpd_pwdoms_dc_off, POWER_DOMAIN_AUDIO_MMIO, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -1426,7 +1418,6 @@ I915_DECL_PW_DOMAINS(xehpd_pwdoms_dc_off, POWER_DOMAIN_AUDIO_MMIO, POWER_DOMAIN_AUX_A, POWER_DOMAIN_AUX_B, - POWER_DOMAIN_MODESET, POWER_DOMAIN_DC_OFF, POWER_DOMAIN_INIT); @@ -1545,6 +1536,56 @@ static const struct i915_power_well_desc_list xelpdp_power_wells[] = { I915_PW_DESCRIPTORS(xelpdp_power_wells_main), }; +I915_DECL_PW_DOMAINS(xe2lpd_pwdoms_pica_tc, + POWER_DOMAIN_PORT_DDI_LANES_TC1, + POWER_DOMAIN_PORT_DDI_LANES_TC2, + POWER_DOMAIN_PORT_DDI_LANES_TC3, + POWER_DOMAIN_PORT_DDI_LANES_TC4, + POWER_DOMAIN_AUX_USBC1, + POWER_DOMAIN_AUX_USBC2, + POWER_DOMAIN_AUX_USBC3, + POWER_DOMAIN_AUX_USBC4, + POWER_DOMAIN_AUX_TBT1, + POWER_DOMAIN_AUX_TBT2, + POWER_DOMAIN_AUX_TBT3, + POWER_DOMAIN_AUX_TBT4, + POWER_DOMAIN_INIT); + +static const struct i915_power_well_desc xe2lpd_power_wells_pica[] = { + { + .instances = &I915_PW_INSTANCES(I915_PW("PICA_TC", + &xe2lpd_pwdoms_pica_tc, + .id = DISP_PW_ID_NONE), + ), + .ops = &xe2lpd_pica_power_well_ops, + }, +}; + +I915_DECL_PW_DOMAINS(xe2lpd_pwdoms_dc_off, + POWER_DOMAIN_DC_OFF, + XELPD_PW_C_POWER_DOMAINS, + XELPD_PW_D_POWER_DOMAINS, + POWER_DOMAIN_AUDIO_MMIO, + POWER_DOMAIN_INIT); + +static const struct i915_power_well_desc xe2lpd_power_wells_dcoff[] = { + { + .instances = &I915_PW_INSTANCES( + I915_PW("DC_off", &xe2lpd_pwdoms_dc_off, + .id = SKL_DISP_DC_OFF), + ), + .ops = &gen9_dc_off_power_well_ops, + }, +}; + +static const struct i915_power_well_desc_list xe2lpd_power_wells[] = { + I915_PW_DESCRIPTORS(i9xx_power_wells_always_on), + I915_PW_DESCRIPTORS(icl_power_wells_pw_1), + I915_PW_DESCRIPTORS(xe2lpd_power_wells_dcoff), + I915_PW_DESCRIPTORS(xelpdp_power_wells_main), + I915_PW_DESCRIPTORS(xe2lpd_power_wells_pica), +}; + static void init_power_well_domains(const struct i915_power_well_instance *inst, struct i915_power_well *power_well) { @@ -1652,7 +1693,9 @@ int intel_display_power_map_init(struct i915_power_domains *power_domains) return 0; } - if (DISPLAY_VER(i915) >= 14) + if (DISPLAY_VER(i915) >= 20) + return set_power_wells(power_domains, xe2lpd_power_wells); + else if (DISPLAY_VER(i915) >= 14) return set_power_wells(power_domains, xelpdp_power_wells); else if (IS_DG2(i915)) return set_power_wells(power_domains, xehpd_power_wells); diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 916009894d..07d6500500 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -1794,8 +1794,13 @@ static void xelpdp_aux_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { enum aux_ch aux_ch = i915_power_well_instance(power_well)->xelpdp.aux_ch; + enum phy phy = icl_aux_pw_to_phy(dev_priv, power_well); + + if (intel_phy_is_tc(dev_priv, phy)) + icl_tc_port_assert_ref_held(dev_priv, power_well, + aux_ch_to_digital_port(dev_priv, aux_ch)); - intel_de_rmw(dev_priv, XELPDP_DP_AUX_CH_CTL(aux_ch), + intel_de_rmw(dev_priv, XELPDP_DP_AUX_CH_CTL(dev_priv, aux_ch), XELPDP_DP_AUX_CH_CTL_POWER_REQUEST, XELPDP_DP_AUX_CH_CTL_POWER_REQUEST); @@ -1813,7 +1818,7 @@ static void xelpdp_aux_power_well_disable(struct drm_i915_private *dev_priv, { enum aux_ch aux_ch = i915_power_well_instance(power_well)->xelpdp.aux_ch; - intel_de_rmw(dev_priv, XELPDP_DP_AUX_CH_CTL(aux_ch), + intel_de_rmw(dev_priv, XELPDP_DP_AUX_CH_CTL(dev_priv, aux_ch), XELPDP_DP_AUX_CH_CTL_POWER_REQUEST, 0); usleep_range(10, 30); @@ -1824,10 +1829,44 @@ static bool xelpdp_aux_power_well_enabled(struct drm_i915_private *dev_priv, { enum aux_ch aux_ch = i915_power_well_instance(power_well)->xelpdp.aux_ch; - return intel_de_read(dev_priv, XELPDP_DP_AUX_CH_CTL(aux_ch)) & + return intel_de_read(dev_priv, XELPDP_DP_AUX_CH_CTL(dev_priv, aux_ch)) & XELPDP_DP_AUX_CH_CTL_POWER_STATUS; } +static void xe2lpd_pica_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + intel_de_write(dev_priv, XE2LPD_PICA_PW_CTL, + XE2LPD_PICA_CTL_POWER_REQUEST); + + if (intel_de_wait_for_set(dev_priv, XE2LPD_PICA_PW_CTL, + XE2LPD_PICA_CTL_POWER_STATUS, 1)) { + drm_dbg_kms(&dev_priv->drm, "pica power well enable timeout\n"); + + drm_WARN(&dev_priv->drm, 1, "Power well PICA timeout when enabled"); + } +} + +static void xe2lpd_pica_power_well_disable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + intel_de_write(dev_priv, XE2LPD_PICA_PW_CTL, 0); + + if (intel_de_wait_for_clear(dev_priv, XE2LPD_PICA_PW_CTL, + XE2LPD_PICA_CTL_POWER_STATUS, 1)) { + drm_dbg_kms(&dev_priv->drm, "pica power well disable timeout\n"); + + drm_WARN(&dev_priv->drm, 1, "Power well PICA timeout when disabled"); + } +} + +static bool xe2lpd_pica_power_well_enabled(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + return intel_de_read(dev_priv, XE2LPD_PICA_PW_CTL) & + XE2LPD_PICA_CTL_POWER_STATUS; +} + const struct i915_power_well_ops i9xx_always_on_power_well_ops = { .sync_hw = i9xx_power_well_sync_hw_noop, .enable = i9xx_always_on_power_well_noop, @@ -1947,3 +1986,10 @@ const struct i915_power_well_ops xelpdp_aux_power_well_ops = { .disable = xelpdp_aux_power_well_disable, .is_enabled = xelpdp_aux_power_well_enabled, }; + +const struct i915_power_well_ops xe2lpd_pica_power_well_ops = { + .sync_hw = i9xx_power_well_sync_hw_noop, + .enable = xe2lpd_pica_power_well_enable, + .disable = xe2lpd_pica_power_well_disable, + .is_enabled = xe2lpd_pica_power_well_enabled, +}; diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.h b/drivers/gpu/drm/i915/display/intel_display_power_well.h index a873658831..9357a9a73c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.h +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.h @@ -176,5 +176,6 @@ extern const struct i915_power_well_ops icl_aux_power_well_ops; extern const struct i915_power_well_ops icl_ddi_power_well_ops; extern const struct i915_power_well_ops tgl_tc_cold_off_ops; extern const struct i915_power_well_ops xelpdp_aux_power_well_ops; +extern const struct i915_power_well_ops xe2lpd_pica_power_well_ops; #endif diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 7fc92b1474..65ea37fe8c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -500,15 +500,15 @@ struct intel_hdcp_shim { enum hdcp_wired_protocol protocol; /* Detects whether sink is HDCP2.2 capable */ - int (*hdcp_2_2_capable)(struct intel_digital_port *dig_port, + int (*hdcp_2_2_capable)(struct intel_connector *connector, bool *capable); /* Write HDCP2.2 messages */ - int (*write_2_2_msg)(struct intel_digital_port *dig_port, + int (*write_2_2_msg)(struct intel_connector *connector, void *buf, size_t size); /* Read HDCP2.2 messages */ - int (*read_2_2_msg)(struct intel_digital_port *dig_port, + int (*read_2_2_msg)(struct intel_connector *connector, u8 msg_id, void *buf, size_t size); /* @@ -516,7 +516,7 @@ struct intel_hdcp_shim { * type to Receivers. In DP HDCP2.2 Stream type is one of the input to * the HDCP2.2 Cipher for En/De-Cryption. Not applicable for HDMI. */ - int (*config_stream_type)(struct intel_digital_port *dig_port, + int (*config_stream_type)(struct intel_connector *connector, bool is_repeater, u8 type); /* Enable/Disable HDCP 2.2 stream encryption on DP MST Transport Link */ @@ -620,6 +620,12 @@ struct intel_connector { struct intel_dp *mst_port; + struct { + struct drm_dp_aux *dsc_decompression_aux; + u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]; + u8 fec_capability; + } dp; + /* Work struct to schedule a uevent on link train failure */ struct work_struct modeset_retry_work; @@ -1083,6 +1089,8 @@ struct intel_crtc_state { unsigned fb_bits; /* framebuffers to flip */ bool update_pipe; /* can a fast modeset be performed? */ + bool update_m_n; /* update M/N seamlessly during fastset? */ + bool update_lrr; /* update TRANS_VTOTAL/etc. during fastset? */ bool disable_cxsr; bool update_wm_pre, update_wm_post; /* watermarks are updated */ bool fifo_changed; /* FIFO split is changed */ @@ -1189,13 +1197,13 @@ struct intel_crtc_state { u32 ctrl, div; } dsi_pll; - int pipe_bpp; + int max_link_bpp_x16; /* in 1/16 bpp units */ + int pipe_bpp; /* in 1 bpp units */ struct intel_link_m_n dp_m_n; /* m2_n2 for eDP downclock */ struct intel_link_m_n dp_m2_n2; bool has_drrs; - bool seamless_m_n; /* PSR is supported but might not be enabled due the lack of enabled planes */ bool has_psr; @@ -1364,7 +1372,12 @@ struct intel_crtc_state { bool enhanced_framing; - /* Forward Error correction State */ + /* + * Forward Error Correction. + * + * Note: This will be false for 128b/132b, which will always have FEC + * enabled automatically. + */ bool fec_enable; bool sdp_split_enable; @@ -1385,7 +1398,7 @@ struct intel_crtc_state { /* Variable Refresh Rate state */ struct { - bool enable; + bool enable, in_range; u8 pipeline_full; u16 flipline, vmin, vmax, guardband; } vrr; @@ -1583,7 +1596,6 @@ struct intel_watermark_params { struct intel_hdmi { i915_reg_t hdmi_reg; - int ddc_bus; struct { enum drm_dp_dual_mode_type type; int max_tmds_clock; @@ -1713,10 +1725,8 @@ struct intel_dp { u8 psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE]; u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]; - u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]; u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE]; u8 lttpr_phy_caps[DP_MAX_LTTPR_COUNT][DP_LTTPR_PHY_CAP_SIZE]; - u8 fec_capable; u8 pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE]; /* source rates */ int num_source_rates; @@ -2110,4 +2120,27 @@ to_intel_frontbuffer(struct drm_framebuffer *fb) return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL; } +static inline int to_bpp_int(int bpp_x16) +{ + return bpp_x16 >> 4; +} + +static inline int to_bpp_frac(int bpp_x16) +{ + return bpp_x16 & 0xf; +} + +#define BPP_X16_FMT "%d.%04d" +#define BPP_X16_ARGS(bpp_x16) to_bpp_int(bpp_x16), (to_bpp_frac(bpp_x16) * 625) + +static inline int to_bpp_int_roundup(int bpp_x16) +{ + return (bpp_x16 + 0xf) >> 4; +} + +static inline int to_bpp_x16(int bpp) +{ + return bpp << 4; +} + #endif /* __INTEL_DISPLAY_TYPES_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.c b/drivers/gpu/drm/i915/display/intel_display_wa.c new file mode 100644 index 0000000000..ac136fd992 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_wa.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "i915_drv.h" +#include "i915_reg.h" +#include "intel_de.h" +#include "intel_display_wa.h" + +static void gen11_display_wa_apply(struct drm_i915_private *i915) +{ + /* Wa_1409120013 */ + intel_de_write(i915, ILK_DPFC_CHICKEN(INTEL_FBC_A), + DPFC_CHICKEN_COMP_DUMMY_PIXEL); + + /* Wa_14010594013 */ + intel_de_rmw(i915, GEN8_CHICKEN_DCPR_1, 0, ICL_DELAY_PMRSP); +} + +static void xe_d_display_wa_apply(struct drm_i915_private *i915) +{ + /* Wa_1409120013 */ + intel_de_write(i915, ILK_DPFC_CHICKEN(INTEL_FBC_A), + DPFC_CHICKEN_COMP_DUMMY_PIXEL); + + /* Wa_14013723622 */ + intel_de_rmw(i915, CLKREQ_POLICY, CLKREQ_POLICY_MEM_UP_OVRD, 0); +} + +static void adlp_display_wa_apply(struct drm_i915_private *i915) +{ + /* Wa_22011091694:adlp */ + intel_de_rmw(i915, GEN9_CLKGATE_DIS_5, 0, DPCE_GATING_DIS); + + /* Bspec/49189 Initialize Sequence */ + intel_de_rmw(i915, GEN8_CHICKEN_DCPR_1, DDI_CLOCK_REG_ACCESS, 0); +} + +void intel_display_wa_apply(struct drm_i915_private *i915) +{ + if (IS_ALDERLAKE_P(i915)) + adlp_display_wa_apply(i915); + else if (DISPLAY_VER(i915) == 12) + xe_d_display_wa_apply(i915); + else if (DISPLAY_VER(i915) == 11) + gen11_display_wa_apply(i915); +} diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.h b/drivers/gpu/drm/i915/display/intel_display_wa.h new file mode 100644 index 0000000000..63201d0985 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_wa.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_DISPLAY_WA_H__ +#define __INTEL_DISPLAY_WA_H__ + +struct drm_i915_private; + +void intel_display_wa_apply(struct drm_i915_private *i915); + +#endif diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 8751973b57..073b85b576 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -309,7 +309,7 @@ static const struct stepping_info * intel_get_stepping_info(struct drm_i915_private *i915, struct stepping_info *si) { - const char *step_name = intel_step_name(RUNTIME_INFO(i915)->step.display_step); + const char *step_name = intel_display_step_name(i915); si->stepping = step_name[0]; si->substepping = step_name[1]; @@ -1037,7 +1037,7 @@ void intel_dmc_init(struct drm_i915_private *i915) INIT_WORK(&dmc->work, dmc_load_work_fn); - if (IS_METEORLAKE(i915)) { + if (DISPLAY_VER_FULL(i915) == IP_VER(14, 0)) { dmc->fw_path = MTL_DMC_PATH; dmc->max_fw_size = XELPDP_DMC_MAX_FW_SIZE; } else if (IS_DG2(i915)) { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 18ee4f2a87..ef09356bcb 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -306,13 +306,13 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); int source_max = intel_dp_max_source_lane_count(dig_port); int sink_max = intel_dp->max_sink_lane_count; - int fia_max = intel_tc_port_fia_max_lane_count(dig_port); + int lane_max = intel_tc_port_max_lane_count(dig_port); int lttpr_max = drm_dp_lttpr_max_lane_count(intel_dp->lttpr_common_caps); if (lttpr_max) sink_max = min(sink_max, lttpr_max); - return min3(source_max, sink_max, fia_max); + return min3(source_max, sink_max, lane_max); } int intel_dp_max_lane_count(struct intel_dp *intel_dp) @@ -740,14 +740,41 @@ u32 intel_dp_dsc_nearest_valid_bpp(struct drm_i915_private *i915, u32 bpp, u32 p return bits_per_pixel; } -u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, - u32 link_clock, u32 lane_count, - u32 mode_clock, u32 mode_hdisplay, - bool bigjoiner, - u32 pipe_bpp, - u32 timeslots) +static +u32 get_max_compressed_bpp_with_joiner(struct drm_i915_private *i915, + u32 mode_clock, u32 mode_hdisplay, + bool bigjoiner) { - u32 bits_per_pixel, max_bpp_small_joiner_ram; + u32 max_bpp_small_joiner_ram; + + /* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */ + max_bpp_small_joiner_ram = small_joiner_ram_size_bits(i915) / mode_hdisplay; + + if (bigjoiner) { + int bigjoiner_interface_bits = DISPLAY_VER(i915) >= 14 ? 36 : 24; + /* With bigjoiner multiple dsc engines are used in parallel so PPC is 2 */ + int ppc = 2; + u32 max_bpp_bigjoiner = + i915->display.cdclk.max_cdclk_freq * ppc * bigjoiner_interface_bits / + intel_dp_mode_to_fec_clock(mode_clock); + + max_bpp_small_joiner_ram *= 2; + + return min(max_bpp_small_joiner_ram, max_bpp_bigjoiner); + } + + return max_bpp_small_joiner_ram; +} + +u16 intel_dp_dsc_get_max_compressed_bpp(struct drm_i915_private *i915, + u32 link_clock, u32 lane_count, + u32 mode_clock, u32 mode_hdisplay, + bool bigjoiner, + enum intel_output_format output_format, + u32 pipe_bpp, + u32 timeslots) +{ + u32 bits_per_pixel, joiner_max_bpp; /* * Available Link Bandwidth(Kbits/sec) = (NumberOfLanes)* @@ -768,47 +795,39 @@ u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, bits_per_pixel = ((link_clock * lane_count) * timeslots) / (intel_dp_mode_to_fec_clock(mode_clock) * 8); + /* Bandwidth required for 420 is half, that of 444 format */ + if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420) + bits_per_pixel *= 2; + + /* + * According to DSC 1.2a Section 4.1.1 Table 4.1 the maximum + * supported PPS value can be 63.9375 and with the further + * mention that for 420, 422 formats, bpp should be programmed double + * the target bpp restricting our target bpp to be 31.9375 at max. + */ + if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420) + bits_per_pixel = min_t(u32, bits_per_pixel, 31); + drm_dbg_kms(&i915->drm, "Max link bpp is %u for %u timeslots " "total bw %u pixel clock %u\n", bits_per_pixel, timeslots, (link_clock * lane_count * 8), intel_dp_mode_to_fec_clock(mode_clock)); - /* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */ - max_bpp_small_joiner_ram = small_joiner_ram_size_bits(i915) / - mode_hdisplay; - - if (bigjoiner) - max_bpp_small_joiner_ram *= 2; - - /* - * Greatest allowed DSC BPP = MIN (output BPP from available Link BW - * check, output bpp from small joiner RAM check) - */ - bits_per_pixel = min(bits_per_pixel, max_bpp_small_joiner_ram); - - if (bigjoiner) { - u32 max_bpp_bigjoiner = - i915->display.cdclk.max_cdclk_freq * 48 / - intel_dp_mode_to_fec_clock(mode_clock); - - bits_per_pixel = min(bits_per_pixel, max_bpp_bigjoiner); - } + joiner_max_bpp = get_max_compressed_bpp_with_joiner(i915, mode_clock, + mode_hdisplay, bigjoiner); + bits_per_pixel = min(bits_per_pixel, joiner_max_bpp); bits_per_pixel = intel_dp_dsc_nearest_valid_bpp(i915, bits_per_pixel, pipe_bpp); - /* - * Compressed BPP in U6.4 format so multiply by 16, for Gen 11, - * fractional part is 0 - */ - return bits_per_pixel << 4; + return bits_per_pixel; } -u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, +u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, int mode_clock, int mode_hdisplay, bool bigjoiner) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = to_i915(connector->base.dev); u8 min_slice_count, i; int max_slice_width; @@ -826,7 +845,7 @@ u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, if (mode_clock >= ((i915->display.cdclk.max_cdclk_freq * 85) / 100)) min_slice_count = max_t(u8, min_slice_count, 2); - max_slice_width = drm_dp_dsc_sink_max_slice_width(intel_dp->dsc_dpcd); + max_slice_width = drm_dp_dsc_sink_max_slice_width(connector->dp.dsc_dpcd); if (max_slice_width < DP_DSC_MIN_SLICE_WIDTH_VALUE) { drm_dbg_kms(&i915->drm, "Unsupported slice width %d by DP DSC Sink device\n", @@ -843,7 +862,7 @@ u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, u8 test_slice_count = valid_dsc_slicecount[i] << bigjoiner; if (test_slice_count > - drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, false)) + drm_dp_dsc_sink_max_slice_count(connector->dp.dsc_dpcd, false)) break; /* big joiner needs small joiner to be enabled */ @@ -916,16 +935,42 @@ dfp_can_convert_from_ycbcr444(struct intel_dp *intel_dp, return false; } +static bool +dfp_can_convert(struct intel_dp *intel_dp, + enum intel_output_format output_format, + enum intel_output_format sink_format) +{ + switch (output_format) { + case INTEL_OUTPUT_FORMAT_RGB: + return dfp_can_convert_from_rgb(intel_dp, sink_format); + case INTEL_OUTPUT_FORMAT_YCBCR444: + return dfp_can_convert_from_ycbcr444(intel_dp, sink_format); + default: + MISSING_CASE(output_format); + return false; + } + + return false; +} + static enum intel_output_format intel_dp_output_format(struct intel_connector *connector, enum intel_output_format sink_format) { struct intel_dp *intel_dp = intel_attached_dp(connector); struct drm_i915_private *i915 = dp_to_i915(intel_dp); + enum intel_output_format force_dsc_output_format = + intel_dp->force_dsc_output_format; enum intel_output_format output_format; + if (force_dsc_output_format) { + if (source_can_output(intel_dp, force_dsc_output_format) && + (!drm_dp_is_branch(intel_dp->dpcd) || + sink_format != force_dsc_output_format || + dfp_can_convert(intel_dp, force_dsc_output_format, sink_format))) + return force_dsc_output_format; - if (intel_dp->force_dsc_output_format) - return intel_dp->force_dsc_output_format; + drm_dbg_kms(&i915->drm, "Cannot force DSC output format\n"); + } if (sink_format == INTEL_OUTPUT_FORMAT_RGB || dfp_can_convert_from_rgb(intel_dp, sink_format)) @@ -951,7 +996,7 @@ int intel_dp_min_bpp(enum intel_output_format output_format) return 8 * 3; } -static int intel_dp_output_bpp(enum intel_output_format output_format, int bpp) +int intel_dp_output_bpp(enum intel_output_format output_format, int bpp) { /* * bpp value was assumed to RGB format. And YCbCr 4:2:0 output @@ -1122,7 +1167,7 @@ intel_dp_mode_valid(struct drm_connector *_connector, int target_clock = mode->clock; int max_rate, mode_rate, max_lanes, max_link_clock; int max_dotclk = dev_priv->max_dotclk_freq; - u16 dsc_max_output_bpp = 0; + u16 dsc_max_compressed_bpp = 0; u8 dsc_slice_count = 0; enum drm_mode_status status; bool dsc = false, bigjoiner = false; @@ -1164,40 +1209,46 @@ intel_dp_mode_valid(struct drm_connector *_connector, intel_dp_mode_min_output_bpp(connector, mode)); if (HAS_DSC(dev_priv) && - drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) { + drm_dp_sink_supports_dsc(connector->dp.dsc_dpcd)) { + enum intel_output_format sink_format, output_format; + int pipe_bpp; + + sink_format = intel_dp_sink_format(connector, mode); + output_format = intel_dp_output_format(connector, sink_format); /* * TBD pass the connector BPC, * for now U8_MAX so that max BPC on that platform would be picked */ - int pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, U8_MAX); + pipe_bpp = intel_dp_dsc_compute_max_bpp(connector, U8_MAX); /* * Output bpp is stored in 6.4 format so right shift by 4 to get the * integer value since we support only integer values of bpp. */ if (intel_dp_is_edp(intel_dp)) { - dsc_max_output_bpp = - drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4; + dsc_max_compressed_bpp = + drm_edp_dsc_sink_output_bpp(connector->dp.dsc_dpcd) >> 4; dsc_slice_count = - drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, + drm_dp_dsc_sink_max_slice_count(connector->dp.dsc_dpcd, true); - } else if (drm_dp_sink_supports_fec(intel_dp->fec_capable)) { - dsc_max_output_bpp = - intel_dp_dsc_get_output_bpp(dev_priv, - max_link_clock, - max_lanes, - target_clock, - mode->hdisplay, - bigjoiner, - pipe_bpp, 64) >> 4; + } else if (drm_dp_sink_supports_fec(connector->dp.fec_capability)) { + dsc_max_compressed_bpp = + intel_dp_dsc_get_max_compressed_bpp(dev_priv, + max_link_clock, + max_lanes, + target_clock, + mode->hdisplay, + bigjoiner, + output_format, + pipe_bpp, 64); dsc_slice_count = - intel_dp_dsc_get_slice_count(intel_dp, + intel_dp_dsc_get_slice_count(connector, target_clock, mode->hdisplay, bigjoiner); } - dsc = dsc_max_output_bpp && dsc_slice_count; + dsc = dsc_max_compressed_bpp && dsc_slice_count; } /* @@ -1310,33 +1361,34 @@ bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp) static bool intel_dp_source_supports_fec(struct intel_dp *intel_dp, const struct intel_crtc_state *pipe_config) { + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - /* On TGL, FEC is supported on all Pipes */ if (DISPLAY_VER(dev_priv) >= 12) return true; - if (DISPLAY_VER(dev_priv) == 11 && pipe_config->cpu_transcoder != TRANSCODER_A) + if (DISPLAY_VER(dev_priv) == 11 && encoder->port != PORT_A) return true; return false; } static bool intel_dp_supports_fec(struct intel_dp *intel_dp, + const struct intel_connector *connector, const struct intel_crtc_state *pipe_config) { return intel_dp_source_supports_fec(intel_dp, pipe_config) && - drm_dp_sink_supports_fec(intel_dp->fec_capable); + drm_dp_sink_supports_fec(connector->dp.fec_capability); } -static bool intel_dp_supports_dsc(struct intel_dp *intel_dp, +static bool intel_dp_supports_dsc(const struct intel_connector *connector, const struct intel_crtc_state *crtc_state) { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP) && !crtc_state->fec_enable) return false; return intel_dsc_source_support(crtc_state) && - drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd); + drm_dp_sink_supports_dsc(connector->dp.dsc_dpcd); } static int intel_dp_hdmi_compute_bpc(struct intel_dp *intel_dp, @@ -1423,7 +1475,7 @@ intel_dp_adjust_compliance_config(struct intel_dp *intel_dp, if (intel_dp->compliance.test_data.bpc != 0) { int bpp = 3 * intel_dp->compliance.test_data.bpc; - limits->min_bpp = limits->max_bpp = bpp; + limits->pipe.min_bpp = limits->pipe.max_bpp = bpp; pipe_config->dither_force_disable = bpp == 6 * 3; drm_dbg_kms(&i915->drm, "Setting pipe_bpp to %d\n", bpp); @@ -1485,10 +1537,12 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, int bpp, i, lane_count, clock = intel_dp_mode_clock(pipe_config, conn_state); int mode_rate, link_rate, link_avail; - for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) { - int output_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp); + for (bpp = to_bpp_int(limits->link.max_bpp_x16); + bpp >= to_bpp_int(limits->link.min_bpp_x16); + bpp -= 2 * 3) { + int link_bpp = intel_dp_output_bpp(pipe_config->output_format, bpp); - mode_rate = intel_dp_link_required(clock, output_bpp); + mode_rate = intel_dp_link_required(clock, link_bpp); for (i = 0; i < intel_dp->num_common_rates; i++) { link_rate = intel_dp_common_rate(intel_dp, i); @@ -1516,20 +1570,34 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, return -EINVAL; } -int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 max_req_bpc) +static +u8 intel_dp_dsc_max_src_input_bpc(struct drm_i915_private *i915) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); + /* Max DSC Input BPC for ICL is 10 and for TGL+ is 12 */ + if (DISPLAY_VER(i915) >= 12) + return 12; + if (DISPLAY_VER(i915) == 11) + return 10; + + return 0; +} + +int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector, + u8 max_req_bpc) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); int i, num_bpc; - u8 dsc_bpc[3] = {0}; + u8 dsc_bpc[3] = {}; u8 dsc_max_bpc; - /* Max DSC Input BPC for ICL is 10 and for TGL+ is 12 */ - if (DISPLAY_VER(i915) >= 12) - dsc_max_bpc = min_t(u8, 12, max_req_bpc); - else - dsc_max_bpc = min_t(u8, 10, max_req_bpc); + dsc_max_bpc = intel_dp_dsc_max_src_input_bpc(i915); + + if (!dsc_max_bpc) + return dsc_max_bpc; - num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd, + dsc_max_bpc = min_t(u8, dsc_max_bpc, max_req_bpc); + + num_bpc = drm_dp_dsc_sink_supported_input_bpcs(connector->dp.dsc_dpcd, dsc_bpc); for (i = 0; i < num_bpc; i++) { if (dsc_max_bpc >= dsc_bpc[i]) @@ -1539,16 +1607,14 @@ int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 max_req_bpc) return 0; } -static int intel_dp_source_dsc_version_minor(struct intel_dp *intel_dp) +static int intel_dp_source_dsc_version_minor(struct drm_i915_private *i915) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); - return DISPLAY_VER(i915) >= 14 ? 2 : 1; } -static int intel_dp_sink_dsc_version_minor(struct intel_dp *intel_dp) +static int intel_dp_sink_dsc_version_minor(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) { - return (intel_dp->dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] & DP_DSC_MINOR_MASK) >> + return (dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] & DP_DSC_MINOR_MASK) >> DP_DSC_MINOR_SHIFT; } @@ -1574,11 +1640,10 @@ static int intel_dp_get_slice_height(int vactive) return 2; } -static int intel_dp_dsc_compute_params(struct intel_encoder *encoder, +static int intel_dp_dsc_compute_params(const struct intel_connector *connector, struct intel_crtc_state *crtc_state) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_i915_private *i915 = to_i915(connector->base.dev); struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; u8 line_buf_depth; int ret; @@ -1599,17 +1664,17 @@ static int intel_dp_dsc_compute_params(struct intel_encoder *encoder, return ret; vdsc_cfg->dsc_version_major = - (intel_dp->dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] & + (connector->dp.dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] & DP_DSC_MAJOR_MASK) >> DP_DSC_MAJOR_SHIFT; vdsc_cfg->dsc_version_minor = - min(intel_dp_source_dsc_version_minor(intel_dp), - intel_dp_sink_dsc_version_minor(intel_dp)); + min(intel_dp_source_dsc_version_minor(i915), + intel_dp_sink_dsc_version_minor(connector->dp.dsc_dpcd)); if (vdsc_cfg->convert_rgb) vdsc_cfg->convert_rgb = - intel_dp->dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT] & + connector->dp.dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT] & DP_DSC_RGB; - line_buf_depth = drm_dp_dsc_sink_line_buf_depth(intel_dp->dsc_dpcd); + line_buf_depth = drm_dp_dsc_sink_line_buf_depth(connector->dp.dsc_dpcd); if (!line_buf_depth) { drm_dbg_kms(&i915->drm, "DSC Sink Line Buffer Depth invalid\n"); @@ -1624,15 +1689,16 @@ static int intel_dp_dsc_compute_params(struct intel_encoder *encoder, DSC_1_1_MAX_LINEBUF_DEPTH_BITS : line_buf_depth; vdsc_cfg->block_pred_enable = - intel_dp->dsc_dpcd[DP_DSC_BLK_PREDICTION_SUPPORT - DP_DSC_SUPPORT] & + connector->dp.dsc_dpcd[DP_DSC_BLK_PREDICTION_SUPPORT - DP_DSC_SUPPORT] & DP_DSC_BLK_PREDICTION_IS_SUPPORTED; return drm_dsc_compute_rc_parameters(vdsc_cfg); } -static bool intel_dp_dsc_supports_format(struct intel_dp *intel_dp, +static bool intel_dp_dsc_supports_format(const struct intel_connector *connector, enum intel_output_format output_format) { + struct drm_i915_private *i915 = to_i915(connector->base.dev); u8 sink_dsc_format; switch (output_format) { @@ -1643,8 +1709,8 @@ static bool intel_dp_dsc_supports_format(struct intel_dp *intel_dp, sink_dsc_format = DP_DSC_YCbCr444; break; case INTEL_OUTPUT_FORMAT_YCBCR420: - if (min(intel_dp_source_dsc_version_minor(intel_dp), - intel_dp_sink_dsc_version_minor(intel_dp)) < 2) + if (min(intel_dp_source_dsc_version_minor(i915), + intel_dp_sink_dsc_version_minor(connector->dp.dsc_dpcd)) < 2) return false; sink_dsc_format = DP_DSC_YCbCr420_Native; break; @@ -1652,7 +1718,393 @@ static bool intel_dp_dsc_supports_format(struct intel_dp *intel_dp, return false; } - return drm_dp_dsc_sink_supports_format(intel_dp->dsc_dpcd, sink_dsc_format); + return drm_dp_dsc_sink_supports_format(connector->dp.dsc_dpcd, sink_dsc_format); +} + +static bool is_bw_sufficient_for_dsc_config(u16 compressed_bpp, u32 link_clock, + u32 lane_count, u32 mode_clock, + enum intel_output_format output_format, + int timeslots) +{ + u32 available_bw, required_bw; + + available_bw = (link_clock * lane_count * timeslots) / 8; + required_bw = compressed_bpp * (intel_dp_mode_to_fec_clock(mode_clock)); + + return available_bw > required_bw; +} + +static int dsc_compute_link_config(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct link_config_limits *limits, + u16 compressed_bpp, + int timeslots) +{ + const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; + int link_rate, lane_count; + int i; + + for (i = 0; i < intel_dp->num_common_rates; i++) { + link_rate = intel_dp_common_rate(intel_dp, i); + if (link_rate < limits->min_rate || link_rate > limits->max_rate) + continue; + + for (lane_count = limits->min_lane_count; + lane_count <= limits->max_lane_count; + lane_count <<= 1) { + if (!is_bw_sufficient_for_dsc_config(compressed_bpp, link_rate, lane_count, + adjusted_mode->clock, + pipe_config->output_format, + timeslots)) + continue; + + pipe_config->lane_count = lane_count; + pipe_config->port_clock = link_rate; + + return 0; + } + } + + return -EINVAL; +} + +static +u16 intel_dp_dsc_max_sink_compressed_bppx16(const struct intel_connector *connector, + struct intel_crtc_state *pipe_config, + int bpc) +{ + u16 max_bppx16 = drm_edp_dsc_sink_output_bpp(connector->dp.dsc_dpcd); + + if (max_bppx16) + return max_bppx16; + /* + * If support not given in DPCD 67h, 68h use the Maximum Allowed bit rate + * values as given in spec Table 2-157 DP v2.0 + */ + switch (pipe_config->output_format) { + case INTEL_OUTPUT_FORMAT_RGB: + case INTEL_OUTPUT_FORMAT_YCBCR444: + return (3 * bpc) << 4; + case INTEL_OUTPUT_FORMAT_YCBCR420: + return (3 * (bpc / 2)) << 4; + default: + MISSING_CASE(pipe_config->output_format); + break; + } + + return 0; +} + +static int dsc_sink_min_compressed_bpp(struct intel_crtc_state *pipe_config) +{ + /* From Mandatory bit rate range Support Table 2-157 (DP v2.0) */ + switch (pipe_config->output_format) { + case INTEL_OUTPUT_FORMAT_RGB: + case INTEL_OUTPUT_FORMAT_YCBCR444: + return 8; + case INTEL_OUTPUT_FORMAT_YCBCR420: + return 6; + default: + MISSING_CASE(pipe_config->output_format); + break; + } + + return 0; +} + +static int dsc_sink_max_compressed_bpp(const struct intel_connector *connector, + struct intel_crtc_state *pipe_config, + int bpc) +{ + return intel_dp_dsc_max_sink_compressed_bppx16(connector, + pipe_config, bpc) >> 4; +} + +static int dsc_src_min_compressed_bpp(void) +{ + /* Min Compressed bpp supported by source is 8 */ + return 8; +} + +static int dsc_src_max_compressed_bpp(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + + /* + * Max Compressed bpp for Gen 13+ is 27bpp. + * For earlier platform is 23bpp. (Bspec:49259). + */ + if (DISPLAY_VER(i915) <= 12) + return 23; + else + return 27; +} + +/* + * From a list of valid compressed bpps try different compressed bpp and find a + * suitable link configuration that can support it. + */ +static int +icl_dsc_compute_link_config(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct link_config_limits *limits, + int dsc_max_bpp, + int dsc_min_bpp, + int pipe_bpp, + int timeslots) +{ + int i, ret; + + /* Compressed BPP should be less than the Input DSC bpp */ + dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1); + + for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp); i++) { + if (valid_dsc_bpp[i] < dsc_min_bpp || + valid_dsc_bpp[i] > dsc_max_bpp) + break; + + ret = dsc_compute_link_config(intel_dp, + pipe_config, + limits, + valid_dsc_bpp[i], + timeslots); + if (ret == 0) { + pipe_config->dsc.compressed_bpp = valid_dsc_bpp[i]; + return 0; + } + } + + return -EINVAL; +} + +/* + * From XE_LPD onwards we supports compression bpps in steps of 1 up to + * uncompressed bpp-1. So we start from max compressed bpp and see if any + * link configuration is able to support that compressed bpp, if not we + * step down and check for lower compressed bpp. + */ +static int +xelpd_dsc_compute_link_config(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct link_config_limits *limits, + int dsc_max_bpp, + int dsc_min_bpp, + int pipe_bpp, + int timeslots) +{ + u16 compressed_bpp; + int ret; + + /* Compressed BPP should be less than the Input DSC bpp */ + dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1); + + for (compressed_bpp = dsc_max_bpp; + compressed_bpp >= dsc_min_bpp; + compressed_bpp--) { + ret = dsc_compute_link_config(intel_dp, + pipe_config, + limits, + compressed_bpp, + timeslots); + if (ret == 0) { + pipe_config->dsc.compressed_bpp = compressed_bpp; + return 0; + } + } + return -EINVAL; +} + +static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp, + const struct intel_connector *connector, + struct intel_crtc_state *pipe_config, + struct link_config_limits *limits, + int pipe_bpp, + int timeslots) +{ + const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + int dsc_src_min_bpp, dsc_sink_min_bpp, dsc_min_bpp; + int dsc_src_max_bpp, dsc_sink_max_bpp, dsc_max_bpp; + int dsc_joiner_max_bpp; + + dsc_src_min_bpp = dsc_src_min_compressed_bpp(); + dsc_sink_min_bpp = dsc_sink_min_compressed_bpp(pipe_config); + dsc_min_bpp = max(dsc_src_min_bpp, dsc_sink_min_bpp); + dsc_min_bpp = max(dsc_min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); + + dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp); + dsc_sink_max_bpp = dsc_sink_max_compressed_bpp(connector, pipe_config, pipe_bpp / 3); + dsc_max_bpp = dsc_sink_max_bpp ? min(dsc_sink_max_bpp, dsc_src_max_bpp) : dsc_src_max_bpp; + + dsc_joiner_max_bpp = get_max_compressed_bpp_with_joiner(i915, adjusted_mode->clock, + adjusted_mode->hdisplay, + pipe_config->bigjoiner_pipes); + dsc_max_bpp = min(dsc_max_bpp, dsc_joiner_max_bpp); + dsc_max_bpp = min(dsc_max_bpp, to_bpp_int(limits->link.max_bpp_x16)); + + if (DISPLAY_VER(i915) >= 13) + return xelpd_dsc_compute_link_config(intel_dp, pipe_config, limits, + dsc_max_bpp, dsc_min_bpp, pipe_bpp, timeslots); + return icl_dsc_compute_link_config(intel_dp, pipe_config, limits, + dsc_max_bpp, dsc_min_bpp, pipe_bpp, timeslots); +} + +static +u8 intel_dp_dsc_min_src_input_bpc(struct drm_i915_private *i915) +{ + /* Min DSC Input BPC for ICL+ is 8 */ + return HAS_DSC(i915) ? 8 : 0; +} + +static +bool is_dsc_pipe_bpp_sufficient(struct drm_i915_private *i915, + struct drm_connector_state *conn_state, + struct link_config_limits *limits, + int pipe_bpp) +{ + u8 dsc_max_bpc, dsc_min_bpc, dsc_max_pipe_bpp, dsc_min_pipe_bpp; + + dsc_max_bpc = min(intel_dp_dsc_max_src_input_bpc(i915), conn_state->max_requested_bpc); + dsc_min_bpc = intel_dp_dsc_min_src_input_bpc(i915); + + dsc_max_pipe_bpp = min(dsc_max_bpc * 3, limits->pipe.max_bpp); + dsc_min_pipe_bpp = max(dsc_min_bpc * 3, limits->pipe.min_bpp); + + return pipe_bpp >= dsc_min_pipe_bpp && + pipe_bpp <= dsc_max_pipe_bpp; +} + +static +int intel_dp_force_dsc_pipe_bpp(struct intel_dp *intel_dp, + struct drm_connector_state *conn_state, + struct link_config_limits *limits) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + int forced_bpp; + + if (!intel_dp->force_dsc_bpc) + return 0; + + forced_bpp = intel_dp->force_dsc_bpc * 3; + + if (is_dsc_pipe_bpp_sufficient(i915, conn_state, limits, forced_bpp)) { + drm_dbg_kms(&i915->drm, "Input DSC BPC forced to %d\n", intel_dp->force_dsc_bpc); + return forced_bpp; + } + + drm_dbg_kms(&i915->drm, "Cannot force DSC BPC:%d, due to DSC BPC limits\n", + intel_dp->force_dsc_bpc); + + return 0; +} + +static int intel_dp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state, + struct link_config_limits *limits, + int timeslots) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + const struct intel_connector *connector = + to_intel_connector(conn_state->connector); + u8 max_req_bpc = conn_state->max_requested_bpc; + u8 dsc_max_bpc, dsc_max_bpp; + u8 dsc_min_bpc, dsc_min_bpp; + u8 dsc_bpc[3] = {}; + int forced_bpp, pipe_bpp; + int num_bpc, i, ret; + + forced_bpp = intel_dp_force_dsc_pipe_bpp(intel_dp, conn_state, limits); + + if (forced_bpp) { + ret = dsc_compute_compressed_bpp(intel_dp, connector, pipe_config, + limits, forced_bpp, timeslots); + if (ret == 0) { + pipe_config->pipe_bpp = forced_bpp; + return 0; + } + } + + dsc_max_bpc = intel_dp_dsc_max_src_input_bpc(i915); + if (!dsc_max_bpc) + return -EINVAL; + + dsc_max_bpc = min_t(u8, dsc_max_bpc, max_req_bpc); + dsc_max_bpp = min(dsc_max_bpc * 3, limits->pipe.max_bpp); + + dsc_min_bpc = intel_dp_dsc_min_src_input_bpc(i915); + dsc_min_bpp = max(dsc_min_bpc * 3, limits->pipe.min_bpp); + + /* + * Get the maximum DSC bpc that will be supported by any valid + * link configuration and compressed bpp. + */ + num_bpc = drm_dp_dsc_sink_supported_input_bpcs(connector->dp.dsc_dpcd, dsc_bpc); + for (i = 0; i < num_bpc; i++) { + pipe_bpp = dsc_bpc[i] * 3; + if (pipe_bpp < dsc_min_bpp) + break; + if (pipe_bpp > dsc_max_bpp) + continue; + ret = dsc_compute_compressed_bpp(intel_dp, connector, pipe_config, + limits, pipe_bpp, timeslots); + if (ret == 0) { + pipe_config->pipe_bpp = pipe_bpp; + return 0; + } + } + + return -EINVAL; +} + +static int intel_edp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state, + struct link_config_limits *limits) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + struct intel_connector *connector = + to_intel_connector(conn_state->connector); + int pipe_bpp, forced_bpp; + int dsc_src_min_bpp, dsc_sink_min_bpp, dsc_min_bpp; + int dsc_src_max_bpp, dsc_sink_max_bpp, dsc_max_bpp; + + forced_bpp = intel_dp_force_dsc_pipe_bpp(intel_dp, conn_state, limits); + + if (forced_bpp) { + pipe_bpp = forced_bpp; + } else { + int max_bpc = min(limits->pipe.max_bpp / 3, (int)conn_state->max_requested_bpc); + + /* For eDP use max bpp that can be supported with DSC. */ + pipe_bpp = intel_dp_dsc_compute_max_bpp(connector, max_bpc); + if (!is_dsc_pipe_bpp_sufficient(i915, conn_state, limits, pipe_bpp)) { + drm_dbg_kms(&i915->drm, + "Computed BPC is not in DSC BPC limits\n"); + return -EINVAL; + } + } + pipe_config->port_clock = limits->max_rate; + pipe_config->lane_count = limits->max_lane_count; + + dsc_src_min_bpp = dsc_src_min_compressed_bpp(); + dsc_sink_min_bpp = dsc_sink_min_compressed_bpp(pipe_config); + dsc_min_bpp = max(dsc_src_min_bpp, dsc_sink_min_bpp); + dsc_min_bpp = max(dsc_min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); + + dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp); + dsc_sink_max_bpp = dsc_sink_max_compressed_bpp(connector, pipe_config, pipe_bpp / 3); + dsc_max_bpp = dsc_sink_max_bpp ? min(dsc_sink_max_bpp, dsc_src_max_bpp) : dsc_src_max_bpp; + dsc_max_bpp = min(dsc_max_bpp, to_bpp_int(limits->link.max_bpp_x16)); + + /* Compressed BPP should be less than the Input DSC bpp */ + dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1); + + pipe_config->dsc.compressed_bpp = max(dsc_min_bpp, dsc_max_bpp); + + pipe_config->pipe_bpp = pipe_bpp; + + return 0; } int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, @@ -1664,52 +2116,45 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + const struct intel_connector *connector = + to_intel_connector(conn_state->connector); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - int pipe_bpp; int ret; pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) && - intel_dp_supports_fec(intel_dp, pipe_config); + intel_dp_supports_fec(intel_dp, connector, pipe_config); - if (!intel_dp_supports_dsc(intel_dp, pipe_config)) + if (!intel_dp_supports_dsc(connector, pipe_config)) return -EINVAL; - if (!intel_dp_dsc_supports_format(intel_dp, pipe_config->output_format)) + if (!intel_dp_dsc_supports_format(connector, pipe_config->output_format)) return -EINVAL; - if (compute_pipe_bpp) - pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, conn_state->max_requested_bpc); - else - pipe_bpp = pipe_config->pipe_bpp; - - if (intel_dp->force_dsc_bpc) { - pipe_bpp = intel_dp->force_dsc_bpc * 3; - drm_dbg_kms(&dev_priv->drm, "Input DSC BPP forced to %d", pipe_bpp); - } - - /* Min Input BPC for ICL+ is 8 */ - if (pipe_bpp < 8 * 3) { - drm_dbg_kms(&dev_priv->drm, - "No DSC support for less than 8bpc\n"); - return -EINVAL; - } - /* - * For now enable DSC for max bpp, max link rate, max lane count. - * Optimize this later for the minimum possible link rate/lane count - * with DSC enabled for the requested mode. + * compute pipe bpp is set to false for DP MST DSC case + * and compressed_bpp is calculated same time once + * vpci timeslots are allocated, because overall bpp + * calculation procedure is bit different for MST case. */ - pipe_config->pipe_bpp = pipe_bpp; - pipe_config->port_clock = limits->max_rate; - pipe_config->lane_count = limits->max_lane_count; + if (compute_pipe_bpp) { + if (intel_dp_is_edp(intel_dp)) + ret = intel_edp_dsc_compute_pipe_bpp(intel_dp, pipe_config, + conn_state, limits); + else + ret = intel_dp_dsc_compute_pipe_bpp(intel_dp, pipe_config, + conn_state, limits, timeslots); + if (ret) { + drm_dbg_kms(&dev_priv->drm, + "No Valid pipe bpp for given mode ret = %d\n", ret); + return ret; + } + } + /* Calculate Slice count */ if (intel_dp_is_edp(intel_dp)) { - pipe_config->dsc.compressed_bpp = - min_t(u16, drm_edp_dsc_sink_output_bpp(intel_dp->dsc_dpcd) >> 4, - pipe_config->pipe_bpp); pipe_config->dsc.slice_count = - drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd, + drm_dp_dsc_sink_max_slice_count(connector->dp.dsc_dpcd, true); if (!pipe_config->dsc.slice_count) { drm_dbg_kms(&dev_priv->drm, "Unsupported Slice Count %d\n", @@ -1717,36 +2162,10 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, return -EINVAL; } } else { - u16 dsc_max_output_bpp = 0; u8 dsc_dp_slice_count; - if (compute_pipe_bpp) { - dsc_max_output_bpp = - intel_dp_dsc_get_output_bpp(dev_priv, - pipe_config->port_clock, - pipe_config->lane_count, - adjusted_mode->crtc_clock, - adjusted_mode->crtc_hdisplay, - pipe_config->bigjoiner_pipes, - pipe_bpp, - timeslots); - /* - * According to DSC 1.2a Section 4.1.1 Table 4.1 the maximum - * supported PPS value can be 63.9375 and with the further - * mention that bpp should be programmed double the target bpp - * restricting our target bpp to be 31.9375 at max - */ - if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) - dsc_max_output_bpp = min_t(u16, dsc_max_output_bpp, 31 << 4); - - if (!dsc_max_output_bpp) { - drm_dbg_kms(&dev_priv->drm, - "Compressed BPP not supported\n"); - return -EINVAL; - } - } dsc_dp_slice_count = - intel_dp_dsc_get_slice_count(intel_dp, + intel_dp_dsc_get_slice_count(connector, adjusted_mode->crtc_clock, adjusted_mode->crtc_hdisplay, pipe_config->bigjoiner_pipes); @@ -1756,21 +2175,7 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, return -EINVAL; } - /* - * compute pipe bpp is set to false for DP MST DSC case - * and compressed_bpp is calculated same time once - * vpci timeslots are allocated, because overall bpp - * calculation procedure is bit different for MST case. - */ - if (compute_pipe_bpp) { - pipe_config->dsc.compressed_bpp = min_t(u16, - dsc_max_output_bpp >> 4, - pipe_config->pipe_bpp); - } pipe_config->dsc.slice_count = dsc_dp_slice_count; - drm_dbg_kms(&dev_priv->drm, "DSC: compressed bpp %d slice count %d\n", - pipe_config->dsc.compressed_bpp, - pipe_config->dsc.slice_count); } /* * VDSC engine operates at 1 Pixel per clock, so if peak pixel rate @@ -1780,7 +2185,7 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, if (pipe_config->bigjoiner_pipes || pipe_config->dsc.slice_count > 1) pipe_config->dsc.dsc_split = true; - ret = intel_dp_dsc_compute_params(&dig_port->base, pipe_config); + ret = intel_dp_dsc_compute_params(connector, pipe_config); if (ret < 0) { drm_dbg_kms(&dev_priv->drm, "Cannot compute valid DSC parameters for Input Bpp = %d " @@ -1800,29 +2205,85 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, return 0; } -static int -intel_dp_compute_link_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state, - bool respect_downstream_limits) +/** + * intel_dp_compute_config_link_bpp_limits - compute output link bpp limits + * @intel_dp: intel DP + * @crtc_state: crtc state + * @dsc: DSC compression mode + * @limits: link configuration limits + * + * Calculates the output link min, max bpp values in @limits based on the + * pipe bpp range, @crtc_state and @dsc mode. + * + * Returns %true in case of success. + */ +bool +intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + bool dsc, + struct link_config_limits *limits) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); const struct drm_display_mode *adjusted_mode = - &pipe_config->hw.adjusted_mode; - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct link_config_limits limits; - bool joiner_needs_dsc = false; - int ret; + &crtc_state->hw.adjusted_mode; + const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + const struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + int max_link_bpp_x16; + + max_link_bpp_x16 = min(crtc_state->max_link_bpp_x16, + to_bpp_x16(limits->pipe.max_bpp)); + + if (!dsc) { + max_link_bpp_x16 = rounddown(max_link_bpp_x16, to_bpp_x16(2 * 3)); - limits.min_rate = intel_dp_common_rate(intel_dp, 0); - limits.max_rate = intel_dp_max_link_rate(intel_dp); + if (max_link_bpp_x16 < to_bpp_x16(limits->pipe.min_bpp)) + return false; - limits.min_lane_count = 1; - limits.max_lane_count = intel_dp_max_lane_count(intel_dp); + limits->link.min_bpp_x16 = to_bpp_x16(limits->pipe.min_bpp); + } else { + /* + * TODO: set the DSC link limits already here, atm these are + * initialized only later in intel_edp_dsc_compute_pipe_bpp() / + * intel_dp_dsc_compute_pipe_bpp() + */ + limits->link.min_bpp_x16 = 0; + } - limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format); - limits.max_bpp = intel_dp_max_bpp(intel_dp, pipe_config, respect_downstream_limits); + limits->link.max_bpp_x16 = max_link_bpp_x16; + + drm_dbg_kms(&i915->drm, + "[ENCODER:%d:%s][CRTC:%d:%s] DP link limits: pixel clock %d kHz DSC %s max lanes %d max rate %d max pipe_bpp %d max link_bpp " BPP_X16_FMT "\n", + encoder->base.base.id, encoder->base.name, + crtc->base.base.id, crtc->base.name, + adjusted_mode->crtc_clock, + dsc ? "on" : "off", + limits->max_lane_count, + limits->max_rate, + limits->pipe.max_bpp, + BPP_X16_ARGS(limits->link.max_bpp_x16)); + + return true; +} + +static bool +intel_dp_compute_config_limits(struct intel_dp *intel_dp, + struct intel_crtc_state *crtc_state, + bool respect_downstream_limits, + bool dsc, + struct link_config_limits *limits) +{ + limits->min_rate = intel_dp_common_rate(intel_dp, 0); + limits->max_rate = intel_dp_max_link_rate(intel_dp); + + /* FIXME 128b/132b SST support missing */ + limits->max_rate = min(limits->max_rate, 810000); + + limits->min_lane_count = 1; + limits->max_lane_count = intel_dp_max_lane_count(intel_dp); + + limits->pipe.min_bpp = intel_dp_min_bpp(crtc_state->output_format); + limits->pipe.max_bpp = intel_dp_max_bpp(intel_dp, crtc_state, + respect_downstream_limits); if (intel_dp->use_max_params) { /* @@ -1833,16 +2294,33 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, * configuration, and typically on older panels these * values correspond to the native resolution of the panel. */ - limits.min_lane_count = limits.max_lane_count; - limits.min_rate = limits.max_rate; + limits->min_lane_count = limits->max_lane_count; + limits->min_rate = limits->max_rate; } - intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits); + intel_dp_adjust_compliance_config(intel_dp, crtc_state, limits); - drm_dbg_kms(&i915->drm, "DP link computation with max lane count %i " - "max rate %d max bpp %d pixel clock %iKHz\n", - limits.max_lane_count, limits.max_rate, - limits.max_bpp, adjusted_mode->crtc_clock); + return intel_dp_compute_config_link_bpp_limits(intel_dp, + crtc_state, + dsc, + limits); +} + +static int +intel_dp_compute_link_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state, + bool respect_downstream_limits) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); + const struct drm_display_mode *adjusted_mode = + &pipe_config->hw.adjusted_mode; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct link_config_limits limits; + bool joiner_needs_dsc = false; + bool dsc_needed; + int ret = 0; if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_clock)) @@ -1855,16 +2333,34 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, */ joiner_needs_dsc = DISPLAY_VER(i915) < 13 && pipe_config->bigjoiner_pipes; - /* - * Optimize for slow and wide for everything, because there are some - * eDP 1.3 and 1.4 panels don't work well with fast and narrow. - */ - ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, conn_state, &limits); + dsc_needed = joiner_needs_dsc || intel_dp->force_dsc_en || + !intel_dp_compute_config_limits(intel_dp, pipe_config, + respect_downstream_limits, + false, + &limits); - if (ret || joiner_needs_dsc || intel_dp->force_dsc_en) { + if (!dsc_needed) { + /* + * Optimize for slow and wide for everything, because there are some + * eDP 1.3 and 1.4 panels don't work well with fast and narrow. + */ + ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, + conn_state, &limits); + if (ret) + dsc_needed = true; + } + + if (dsc_needed) { drm_dbg_kms(&i915->drm, "Try DSC (fallback=%s, joiner=%s, force=%s)\n", str_yes_no(ret), str_yes_no(joiner_needs_dsc), str_yes_no(intel_dp->force_dsc_en)); + + if (!intel_dp_compute_config_limits(intel_dp, pipe_config, + respect_downstream_limits, + true, + &limits)) + return -EINVAL; + ret = intel_dp_dsc_compute_config(intel_dp, pipe_config, conn_state, &limits, 64, true); if (ret < 0) @@ -2140,7 +2636,7 @@ static bool can_enable_drrs(struct intel_connector *connector, static void intel_dp_drrs_compute_config(struct intel_connector *connector, struct intel_crtc_state *pipe_config, - int output_bpp) + int link_bpp) { struct drm_i915_private *i915 = to_i915(connector->base.dev); const struct drm_display_mode *downclock_mode = @@ -2148,7 +2644,7 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, int pixel_clock; if (has_seamless_m_n(connector)) - pipe_config->seamless_m_n = true; + pipe_config->update_m_n = true; if (!can_enable_drrs(connector, pipe_config, downclock_mode)) { if (intel_cpu_transcoder_has_m2_n2(i915, pipe_config->cpu_transcoder)) @@ -2165,7 +2661,7 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, if (pipe_config->splitter.enable) pixel_clock /= pipe_config->splitter.link_count; - intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock, + intel_link_compute_m_n(link_bpp, pipe_config->lane_count, pixel_clock, pipe_config->port_clock, &pipe_config->dp_m2_n2, pipe_config->fec_enable); @@ -2175,15 +2671,17 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, } static bool intel_dp_has_audio(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct intel_connector *connector = intel_dp->attached_connector; const struct intel_digital_connector_state *intel_conn_state = to_intel_digital_connector_state(conn_state); + struct intel_connector *connector = + to_intel_connector(conn_state->connector); - if (!intel_dp_port_has_audio(i915, encoder->port)) + if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) && + !intel_dp_port_has_audio(i915, encoder->port)) return false; if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO) @@ -2236,7 +2734,7 @@ intel_dp_compute_output_format(struct intel_encoder *encoder, return ret; } -static void +void intel_dp_audio_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -2244,9 +2742,12 @@ intel_dp_audio_compute_config(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = conn_state->connector; - pipe_config->sdp_split_enable = - intel_dp_has_audio(encoder, conn_state) && - intel_dp_is_uhbr(pipe_config); + pipe_config->has_audio = + intel_dp_has_audio(encoder, pipe_config, conn_state) && + intel_audio_compute_config(encoder, pipe_config, conn_state); + + pipe_config->sdp_split_enable = pipe_config->has_audio && + intel_dp_is_uhbr(pipe_config); drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] SDP split enable: %s\n", connector->base.id, connector->name, @@ -2263,15 +2764,11 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); const struct drm_display_mode *fixed_mode; struct intel_connector *connector = intel_dp->attached_connector; - int ret = 0, output_bpp; + int ret = 0, link_bpp; if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && encoder->port != PORT_A) pipe_config->has_pch_encoder = true; - pipe_config->has_audio = - intel_dp_has_audio(encoder, conn_state) && - intel_audio_compute_config(encoder, pipe_config, conn_state); - fixed_mode = intel_panel_fixed_mode(connector, adjusted_mode); if (intel_dp_is_edp(intel_dp) && fixed_mode) { ret = intel_panel_compute_config(connector, adjusted_mode); @@ -2316,10 +2813,10 @@ intel_dp_compute_config(struct intel_encoder *encoder, drm_dp_enhanced_frame_cap(intel_dp->dpcd); if (pipe_config->dsc.compression_enable) - output_bpp = pipe_config->dsc.compressed_bpp; + link_bpp = pipe_config->dsc.compressed_bpp; else - output_bpp = intel_dp_output_bpp(pipe_config->output_format, - pipe_config->pipe_bpp); + link_bpp = intel_dp_output_bpp(pipe_config->output_format, + pipe_config->pipe_bpp); if (intel_dp->mso_link_count) { int n = intel_dp->mso_link_count; @@ -2343,7 +2840,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_dp_audio_compute_config(encoder, pipe_config, conn_state); - intel_link_compute_m_n(output_bpp, + intel_link_compute_m_n(link_bpp, pipe_config->lane_count, adjusted_mode->crtc_clock, pipe_config->port_clock, @@ -2359,7 +2856,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_vrr_compute_config(pipe_config, conn_state); intel_psr_compute_config(intel_dp, pipe_config, conn_state); - intel_dp_drrs_compute_config(connector, pipe_config, output_bpp); + intel_dp_drrs_compute_config(connector, pipe_config, link_bpp); intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state); intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state); @@ -2450,7 +2947,7 @@ intel_edp_init_source_oui(struct intel_dp *intel_dp, bool careful) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); u8 oui[] = { 0x00, 0xaa, 0x01 }; - u8 buf[3] = { 0 }; + u8 buf[3] = {}; /* * During driver init, we want to be careful and avoid changing the source OUI if it's @@ -2984,43 +3481,57 @@ bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp) return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED; } -static void intel_dp_get_dsc_sink_cap(struct intel_dp *intel_dp) +static void intel_dp_read_dsc_dpcd(struct drm_dp_aux *aux, + u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); + if (drm_dp_dpcd_read(aux, DP_DSC_SUPPORT, dsc_dpcd, + DP_DSC_RECEIVER_CAP_SIZE) < 0) { + drm_err(aux->drm_dev, + "Failed to read DPCD register 0x%x\n", + DP_DSC_SUPPORT); + return; + } + + drm_dbg_kms(aux->drm_dev, "DSC DPCD: %*ph\n", + DP_DSC_RECEIVER_CAP_SIZE, + dsc_dpcd); +} + +void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, struct intel_connector *connector) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); /* * Clear the cached register set to avoid using stale values * for the sinks that do not support DSC. */ - memset(intel_dp->dsc_dpcd, 0, sizeof(intel_dp->dsc_dpcd)); + memset(connector->dp.dsc_dpcd, 0, sizeof(connector->dp.dsc_dpcd)); /* Clear fec_capable to avoid using stale values */ - intel_dp->fec_capable = 0; + connector->dp.fec_capability = 0; - /* Cache the DSC DPCD if eDP or DP rev >= 1.4 */ - if (intel_dp->dpcd[DP_DPCD_REV] >= 0x14 || - intel_dp->edp_dpcd[0] >= DP_EDP_14) { - if (drm_dp_dpcd_read(&intel_dp->aux, DP_DSC_SUPPORT, - intel_dp->dsc_dpcd, - sizeof(intel_dp->dsc_dpcd)) < 0) - drm_err(&i915->drm, - "Failed to read DPCD register 0x%x\n", - DP_DSC_SUPPORT); - - drm_dbg_kms(&i915->drm, "DSC DPCD: %*ph\n", - (int)sizeof(intel_dp->dsc_dpcd), - intel_dp->dsc_dpcd); + if (dpcd_rev < DP_DPCD_REV_14) + return; - /* FEC is supported only on DP 1.4 */ - if (!intel_dp_is_edp(intel_dp) && - drm_dp_dpcd_readb(&intel_dp->aux, DP_FEC_CAPABILITY, - &intel_dp->fec_capable) < 0) - drm_err(&i915->drm, - "Failed to read FEC DPCD register\n"); + intel_dp_read_dsc_dpcd(connector->dp.dsc_decompression_aux, + connector->dp.dsc_dpcd); - drm_dbg_kms(&i915->drm, "FEC CAPABILITY: %x\n", - intel_dp->fec_capable); + if (drm_dp_dpcd_readb(connector->dp.dsc_decompression_aux, DP_FEC_CAPABILITY, + &connector->dp.fec_capability) < 0) { + drm_err(&i915->drm, "Failed to read FEC DPCD register\n"); + return; } + + drm_dbg_kms(&i915->drm, "FEC CAPABILITY: %x\n", + connector->dp.fec_capability); +} + +static void intel_edp_get_dsc_sink_cap(u8 edp_dpcd_rev, struct intel_connector *connector) +{ + if (edp_dpcd_rev < DP_EDP_14) + return; + + intel_dp_read_dsc_dpcd(connector->dp.dsc_decompression_aux, connector->dp.dsc_dpcd); } static void intel_edp_mso_mode_fixup(struct intel_connector *connector, @@ -3112,7 +3623,7 @@ static void intel_edp_mso_init(struct intel_dp *intel_dp) } static bool -intel_edp_init_dpcd(struct intel_dp *intel_dp) +intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector) { struct drm_i915_private *dev_priv = to_i915(dp_to_dig_port(intel_dp)->base.base.dev); @@ -3191,7 +3702,8 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp) /* Read the eDP DSC DPCD registers */ if (HAS_DSC(dev_priv)) - intel_dp_get_dsc_sink_cap(intel_dp); + intel_edp_get_dsc_sink_cap(intel_dp->edp_dpcd[0], + connector); /* * If needed, program our source OUI so we can make various Intel-specific AUX services @@ -4724,14 +5236,10 @@ intel_dp_update_dfp(struct intel_dp *intel_dp, { struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_connector *connector = intel_dp->attached_connector; - const struct edid *edid; - - /* FIXME: Get rid of drm_edid_raw() */ - edid = drm_edid_raw(drm_edid); intel_dp->dfp.max_bpc = drm_dp_downstream_max_bpc(intel_dp->dpcd, - intel_dp->downstream_ports, edid); + intel_dp->downstream_ports, drm_edid); intel_dp->dfp.max_dotclock = drm_dp_downstream_max_dotclock(intel_dp->dpcd, @@ -4740,11 +5248,11 @@ intel_dp_update_dfp(struct intel_dp *intel_dp, intel_dp->dfp.min_tmds_clock = drm_dp_downstream_min_tmds_clock(intel_dp->dpcd, intel_dp->downstream_ports, - edid); + drm_edid); intel_dp->dfp.max_tmds_clock = drm_dp_downstream_max_tmds_clock(intel_dp->dpcd, intel_dp->downstream_ports, - edid); + drm_edid); intel_dp->dfp.pcon_max_frl_bw = drm_dp_get_pcon_max_frl_bw(intel_dp->dpcd, @@ -4815,7 +5323,6 @@ intel_dp_set_edid(struct intel_dp *intel_dp) struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_connector *connector = intel_dp->attached_connector; const struct drm_edid *drm_edid; - const struct edid *edid; bool vrr_capable; intel_dp_unset_edid(intel_dp); @@ -4833,10 +5340,8 @@ intel_dp_set_edid(struct intel_dp *intel_dp) intel_dp_update_dfp(intel_dp, drm_edid); intel_dp_update_420(intel_dp); - /* FIXME: Get rid of drm_edid_raw() */ - edid = drm_edid_raw(drm_edid); - - drm_dp_cec_set_edid(&intel_dp->aux, edid); + drm_dp_cec_attach(&intel_dp->aux, + connector->base.display_info.source_physical_address); } static void @@ -4862,13 +5367,32 @@ intel_dp_unset_edid(struct intel_dp *intel_dp) false); } +static void +intel_dp_detect_dsc_caps(struct intel_dp *intel_dp, struct intel_connector *connector) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + + /* Read DP Sink DSC Cap DPCD regs for DP v1.4 */ + if (!HAS_DSC(i915)) + return; + + if (intel_dp_is_edp(intel_dp)) + intel_edp_get_dsc_sink_cap(intel_dp->edp_dpcd[0], + connector); + else + intel_dp_get_dsc_sink_cap(intel_dp->dpcd[DP_DPCD_REV], + connector); +} + static int intel_dp_detect(struct drm_connector *connector, struct drm_modeset_acquire_ctx *ctx, bool force) { struct drm_i915_private *dev_priv = to_i915(connector->dev); - struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector)); + struct intel_connector *intel_connector = + to_intel_connector(connector); + struct intel_dp *intel_dp = intel_attached_dp(intel_connector); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &dig_port->base; enum drm_connector_status status; @@ -4878,7 +5402,7 @@ intel_dp_detect(struct drm_connector *connector, drm_WARN_ON(&dev_priv->drm, !drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex)); - if (!INTEL_DISPLAY_ENABLED(dev_priv)) + if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; /* Can't disconnect eDP */ @@ -4891,7 +5415,7 @@ intel_dp_detect(struct drm_connector *connector, if (status == connector_status_disconnected) { memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance)); - memset(intel_dp->dsc_dpcd, 0, sizeof(intel_dp->dsc_dpcd)); + memset(intel_connector->dp.dsc_dpcd, 0, sizeof(intel_connector->dp.dsc_dpcd)); if (intel_dp->is_mst) { drm_dbg_kms(&dev_priv->drm, @@ -4906,9 +5430,7 @@ intel_dp_detect(struct drm_connector *connector, goto out; } - /* Read DP Sink DSC Cap DPCD regs for DP v1.4 */ - if (HAS_DSC(dev_priv)) - intel_dp_get_dsc_sink_cap(intel_dp); + intel_dp_detect_dsc_caps(intel_dp, intel_connector); intel_dp_configure_mst(intel_dp); @@ -4964,12 +5486,6 @@ out: if (status != connector_status_connected && !intel_dp->is_mst) intel_dp_unset_edid(intel_dp); - /* - * Make sure the refs for power wells enabled during detect are - * dropped to avoid a new detect cycle triggered by HPD polling. - */ - intel_display_power_flush_work(dev_priv); - if (!intel_dp_is_edp(intel_dp)) drm_dp_set_subconnector_property(connector, status, @@ -4985,9 +5501,6 @@ intel_dp_force(struct drm_connector *connector) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *intel_encoder = &dig_port->base; struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); - enum intel_display_power_domain aux_domain = - intel_aux_power_domain(dig_port); - intel_wakeref_t wakeref; drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -4996,11 +5509,7 @@ intel_dp_force(struct drm_connector *connector) if (connector->status != connector_status_connected) return; - wakeref = intel_display_power_get(dev_priv, aux_domain); - intel_dp_set_edid(intel_dp); - - intel_display_power_put(dev_priv, aux_domain, wakeref); } static int intel_dp_get_modes(struct drm_connector *connector) @@ -5260,15 +5769,26 @@ static int intel_dp_connector_atomic_check(struct drm_connector *conn, return intel_modeset_synced_crtcs(state, conn); } -static void intel_dp_oob_hotplug_event(struct drm_connector *connector) +static void intel_dp_oob_hotplug_event(struct drm_connector *connector, + enum drm_connector_status hpd_state) { struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); struct drm_i915_private *i915 = to_i915(connector->dev); + bool hpd_high = hpd_state == connector_status_connected; + unsigned int hpd_pin = encoder->hpd_pin; + bool need_work = false; spin_lock_irq(&i915->irq_lock); - i915->display.hotplug.event_bits |= BIT(encoder->hpd_pin); + if (hpd_high != test_bit(hpd_pin, &i915->display.hotplug.oob_hotplug_last_state)) { + i915->display.hotplug.event_bits |= BIT(hpd_pin); + + __assign_bit(hpd_pin, &i915->display.hotplug.oob_hotplug_last_state, hpd_high); + need_work = true; + } spin_unlock_irq(&i915->irq_lock); - queue_delayed_work(i915->unordered_wq, &i915->display.hotplug.hotplug_work, 0); + + if (need_work) + queue_delayed_work(i915->unordered_wq, &i915->display.hotplug.hotplug_work, 0); } static const struct drm_connector_funcs intel_dp_connector_funcs = { @@ -5506,7 +6026,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, intel_hpd_enable_detection(encoder); /* Cache DPCD and EDID for edp. */ - has_dpcd = intel_edp_init_dpcd(intel_dp); + has_dpcd = intel_edp_init_dpcd(intel_dp, intel_connector); if (!has_dpcd) { /* if this fails, presume the device is a ghost */ @@ -5556,7 +6076,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, } mutex_lock(&dev_priv->drm.mode_config.mutex); - drm_edid = drm_edid_read_ddc(connector, &intel_dp->aux.ddc); + drm_edid = drm_edid_read_ddc(connector, connector->ddc); if (!drm_edid) { /* Fallback to EDID from ACPI OpRegion, if any */ drm_edid = intel_opregion_get_edid(intel_connector); @@ -5695,12 +6215,16 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) intel_dp->pps.active_pipe = vlv_active_pipe(intel_dp); + intel_dp_aux_init(intel_dp); + intel_connector->dp.dsc_decompression_aux = &intel_dp->aux; + drm_dbg_kms(&dev_priv->drm, "Adding %s connector on [ENCODER:%d:%s]\n", type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP", intel_encoder->base.base.id, intel_encoder->base.name); - drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); + drm_connector_init_with_ddc(dev, connector, &intel_dp_connector_funcs, + type, &intel_dp->aux.ddc); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); if (!HAS_GMCH(dev_priv) && DISPLAY_VER(dev_priv) < 12) @@ -5708,8 +6232,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, intel_connector->polled = DRM_CONNECTOR_POLL_HPD; - intel_dp_aux_init(intel_dp); - intel_connector_attach_encoder(intel_connector, intel_encoder); if (HAS_DDI(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 22099de3ca..484aea215a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -26,7 +26,14 @@ struct intel_encoder; struct link_config_limits { int min_rate, max_rate; int min_lane_count, max_lane_count; - int min_bpp, max_bpp; + struct { + /* Uncompressed DSC input or link output bpp in 1 bpp units */ + int min_bpp, max_bpp; + } pipe; + struct { + /* Compressed or uncompressed link output bpp in 1/16 bpp units */ + int min_bpp_x16, max_bpp_x16; + } link; }; void intel_edp_fixup_vbt_bpp(struct intel_encoder *encoder, int pipe_bpp); @@ -65,6 +72,9 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, struct link_config_limits *limits, int timeslots, bool recompute_pipe_bpp); +void intel_dp_audio_compute_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config, + struct drm_connector_state *conn_state); bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp); bool intel_dp_is_edp(struct intel_dp *intel_dp); bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state); @@ -106,14 +116,16 @@ void intel_read_dp_sdp(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, unsigned int type); bool intel_digital_port_connected(struct intel_encoder *encoder); -int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc); -u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915, - u32 link_clock, u32 lane_count, - u32 mode_clock, u32 mode_hdisplay, - bool bigjoiner, - u32 pipe_bpp, - u32 timeslots); -u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, +int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector, + u8 dsc_max_bpc); +u16 intel_dp_dsc_get_max_compressed_bpp(struct drm_i915_private *i915, + u32 link_clock, u32 lane_count, + u32 mode_clock, u32 mode_hdisplay, + bool bigjoiner, + enum intel_output_format output_format, + u32 pipe_bpp, + u32 timeslots); +u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, int mode_clock, int mode_hdisplay, bool bigjoiner); bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp, @@ -143,5 +155,14 @@ void intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp, void intel_dp_phy_test(struct intel_encoder *encoder); void intel_dp_wait_source_oui(struct intel_dp *intel_dp); +int intel_dp_output_bpp(enum intel_output_format output_format, int bpp); + +bool +intel_dp_compute_config_link_bpp_limits(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + bool dsc, + struct link_config_limits *limits); + +void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, struct intel_connector *connector); #endif /* __INTEL_DP_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index 2d173bd495..4431b6290c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -14,6 +14,21 @@ #include "intel_pps.h" #include "intel_tc.h" +#define AUX_CH_NAME_BUFSIZE 6 + +static const char *aux_ch_name(struct drm_i915_private *i915, + char *buf, int size, enum aux_ch aux_ch) +{ + if (DISPLAY_VER(i915) >= 13 && aux_ch >= AUX_CH_D_XELPD) + snprintf(buf, size, "%c", 'A' + aux_ch - AUX_CH_D_XELPD + AUX_CH_D); + else if (DISPLAY_VER(i915) >= 12 && aux_ch >= AUX_CH_USBC1) + snprintf(buf, size, "USBC%c", '1' + aux_ch - AUX_CH_USBC1); + else + snprintf(buf, size, "%c", 'A' + aux_ch); + + return buf; +} + u32 intel_dp_aux_pack(const u8 *src, int src_bytes) { int i; @@ -687,10 +702,10 @@ static i915_reg_t xelpdp_aux_ctl_reg(struct intel_dp *intel_dp) case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: - return XELPDP_DP_AUX_CH_CTL(aux_ch); + return XELPDP_DP_AUX_CH_CTL(dev_priv, aux_ch); default: MISSING_CASE(aux_ch); - return XELPDP_DP_AUX_CH_CTL(AUX_CH_A); + return XELPDP_DP_AUX_CH_CTL(dev_priv, AUX_CH_A); } } @@ -707,10 +722,10 @@ static i915_reg_t xelpdp_aux_data_reg(struct intel_dp *intel_dp, int index) case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: - return XELPDP_DP_AUX_CH_DATA(aux_ch, index); + return XELPDP_DP_AUX_CH_DATA(dev_priv, aux_ch, index); default: MISSING_CASE(aux_ch); - return XELPDP_DP_AUX_CH_DATA(AUX_CH_A, index); + return XELPDP_DP_AUX_CH_DATA(dev_priv, AUX_CH_A, index); } } @@ -728,6 +743,7 @@ void intel_dp_aux_init(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &dig_port->base; enum aux_ch aux_ch = dig_port->aux_ch; + char buf[AUX_CH_NAME_BUFSIZE]; if (DISPLAY_VER(dev_priv) >= 14) { intel_dp->aux_ch_ctl_reg = xelpdp_aux_ctl_reg; @@ -764,18 +780,9 @@ void intel_dp_aux_init(struct intel_dp *intel_dp) drm_dp_aux_init(&intel_dp->aux); /* Failure to allocate our preferred name is not critical */ - if (DISPLAY_VER(dev_priv) >= 13 && aux_ch >= AUX_CH_D_XELPD) - intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s", - aux_ch_name(aux_ch - AUX_CH_D_XELPD + AUX_CH_D), - encoder->base.name); - else if (DISPLAY_VER(dev_priv) >= 12 && aux_ch >= AUX_CH_USBC1) - intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX USBC%c/%s", - aux_ch - AUX_CH_USBC1 + '1', - encoder->base.name); - else - intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %c/%s", - aux_ch_name(aux_ch), - encoder->base.name); + intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %s/%s", + aux_ch_name(dev_priv, buf, sizeof(buf), aux_ch), + encoder->base.name); intel_dp->aux.transfer = intel_dp_aux_transfer; cpu_latency_qos_add_request(&intel_dp->pm_qos, PM_QOS_DEFAULT_VALUE); @@ -819,6 +826,7 @@ enum aux_ch intel_dp_aux_ch(struct intel_encoder *encoder) struct intel_encoder *other; const char *source; enum aux_ch aux_ch; + char buf[AUX_CH_NAME_BUFSIZE]; aux_ch = intel_bios_dp_aux_ch(encoder->devdata); source = "VBT"; @@ -836,16 +844,17 @@ enum aux_ch intel_dp_aux_ch(struct intel_encoder *encoder) other = get_encoder_by_aux_ch(encoder, aux_ch); if (other) { drm_dbg_kms(&i915->drm, - "[ENCODER:%d:%s] AUX CH %c already claimed by [ENCODER:%d:%s]\n", - encoder->base.base.id, encoder->base.name, aux_ch_name(aux_ch), + "[ENCODER:%d:%s] AUX CH %s already claimed by [ENCODER:%d:%s]\n", + encoder->base.base.id, encoder->base.name, + aux_ch_name(i915, buf, sizeof(buf), aux_ch), other->base.base.id, other->base.name); return AUX_CH_NONE; } drm_dbg_kms(&i915->drm, - "[ENCODER:%d:%s] Using AUX CH %c (%s)\n", + "[ENCODER:%d:%s] Using AUX CH %s (%s)\n", encoder->base.base.id, encoder->base.name, - aux_ch_name(aux_ch), source); + aux_ch_name(i915, buf, sizeof(buf), aux_ch), source); return aux_ch; } diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index 95cc525184..26ea7e9f1b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -169,7 +169,7 @@ intel_dp_aux_hdr_get_backlight(struct intel_connector *connector, enum pipe pipe struct intel_panel *panel = &connector->panel; struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); u8 tmp; - u8 buf[2] = { 0 }; + u8 buf[2] = {}; if (drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &tmp) != 1) { drm_err(&i915->drm, "[CONNECTOR:%d:%s] Failed to read current backlight mode from DPCD\n", @@ -204,7 +204,7 @@ intel_dp_aux_hdr_set_aux_backlight(const struct drm_connector_state *conn_state, struct intel_connector *connector = to_intel_connector(conn_state->connector); struct drm_device *dev = connector->base.dev; struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder); - u8 buf[4] = { 0 }; + u8 buf[4] = {}; buf[0] = level & 0xFF; buf[1] = (level & 0xFF00) >> 8; diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h b/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h index 5185345277..34f6e0a48e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h @@ -13,48 +13,34 @@ * packet size supported is 20 bytes in each direction, hence the 5 fixed data * registers */ -#define _DPA_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64010) -#define _DPA_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64014) -#define _DPB_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64110) -#define _DPB_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64114) - -#define DP_AUX_CH_CTL(aux_ch) _MMIO_PORT(aux_ch, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL) -#define DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PORT(aux_ch, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ - -#define _XELPDP_USBC1_AUX_CH_CTL 0x16F210 -#define _XELPDP_USBC2_AUX_CH_CTL 0x16F410 -#define _XELPDP_USBC3_AUX_CH_CTL 0x16F610 -#define _XELPDP_USBC4_AUX_CH_CTL 0x16F810 - -#define XELPDP_DP_AUX_CH_CTL(aux_ch) _MMIO(_PICK(aux_ch, \ - _DPA_AUX_CH_CTL, \ - _DPB_AUX_CH_CTL, \ - 0, /* port/aux_ch C is non-existent */ \ - _XELPDP_USBC1_AUX_CH_CTL, \ - _XELPDP_USBC2_AUX_CH_CTL, \ - _XELPDP_USBC3_AUX_CH_CTL, \ - _XELPDP_USBC4_AUX_CH_CTL)) - -#define _XELPDP_USBC1_AUX_CH_DATA1 0x16F214 -#define _XELPDP_USBC2_AUX_CH_DATA1 0x16F414 -#define _XELPDP_USBC3_AUX_CH_DATA1 0x16F614 -#define _XELPDP_USBC4_AUX_CH_DATA1 0x16F814 - -#define XELPDP_DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PICK(aux_ch, \ - _DPA_AUX_CH_DATA1, \ - _DPB_AUX_CH_DATA1, \ - 0, /* port/aux_ch C is non-existent */ \ - _XELPDP_USBC1_AUX_CH_DATA1, \ - _XELPDP_USBC2_AUX_CH_DATA1, \ - _XELPDP_USBC3_AUX_CH_DATA1, \ - _XELPDP_USBC4_AUX_CH_DATA1) + (i) * 4) +/* + * Wrapper macro to convert from aux_ch to the index used in some of the + * registers. + */ +#define __xe2lpd_aux_ch_idx(aux_ch) \ + (aux_ch >= AUX_CH_USBC1 ? aux_ch : AUX_CH_USBC4 + 1 + (aux_ch) - AUX_CH_A) +/* TODO: Remove implicit dev_priv */ +#define _DPA_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64010) +#define _DPB_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64110) +#define _XELPDP_USBC1_AUX_CH_CTL 0x16f210 +#define _XELPDP_USBC2_AUX_CH_CTL 0x16f410 +#define DP_AUX_CH_CTL(aux_ch) _MMIO_PORT(aux_ch, _DPA_AUX_CH_CTL, \ + _DPB_AUX_CH_CTL) +#define _XELPDP_DP_AUX_CH_CTL(aux_ch) \ + _MMIO(_PICK_EVEN_2RANGES(aux_ch, AUX_CH_USBC1, \ + _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL, \ + _XELPDP_USBC1_AUX_CH_CTL, \ + _XELPDP_USBC2_AUX_CH_CTL)) +#define XELPDP_DP_AUX_CH_CTL(i915__, aux_ch) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_DP_AUX_CH_CTL(__xe2lpd_aux_ch_idx(aux_ch)) : \ + _XELPDP_DP_AUX_CH_CTL(aux_ch)) #define DP_AUX_CH_CTL_SEND_BUSY REG_BIT(31) #define DP_AUX_CH_CTL_DONE REG_BIT(30) #define DP_AUX_CH_CTL_INTERRUPT REG_BIT(29) #define DP_AUX_CH_CTL_TIME_OUT_ERROR REG_BIT(28) - #define DP_AUX_CH_CTL_TIME_OUT_MASK REG_GENMASK(27, 26) #define DP_AUX_CH_CTL_TIME_OUT_400us REG_FIELD_PREP(DP_AUX_CH_CTL_TIME_OUT_MASK, 0) #define DP_AUX_CH_CTL_TIME_OUT_600us REG_FIELD_PREP(DP_AUX_CH_CTL_TIME_OUT_MASK, 1) @@ -83,4 +69,26 @@ #define DP_AUX_CH_CTL_SYNC_PULSE_SKL_MASK REG_GENMASK(4, 0) /* skl+ */ #define DP_AUX_CH_CTL_SYNC_PULSE_SKL(c) REG_FIELD_PREP(DP_AUX_CH_CTL_SYNC_PULSE_SKL_MASK, (c) - 1) +/* TODO: Remove implicit dev_priv */ +#define _DPA_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64014) +#define _DPB_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64114) +#define _XELPDP_USBC1_AUX_CH_DATA1 0x16f214 +#define _XELPDP_USBC2_AUX_CH_DATA1 0x16f414 +#define DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PORT(aux_ch, _DPA_AUX_CH_DATA1, \ + _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ +#define _XELPDP_DP_AUX_CH_DATA(aux_ch, i) \ + _MMIO(_PICK_EVEN_2RANGES(aux_ch, AUX_CH_USBC1, \ + _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1, \ + _XELPDP_USBC1_AUX_CH_DATA1, \ + _XELPDP_USBC2_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ +#define XELPDP_DP_AUX_CH_DATA(i915__, aux_ch, i) \ + (DISPLAY_VER(i915__) >= 20 ? \ + _XELPDP_DP_AUX_CH_DATA(__xe2lpd_aux_ch_idx(aux_ch), i) : \ + _XELPDP_DP_AUX_CH_DATA(aux_ch, i)) + +/* PICA Power Well Control */ +#define XE2LPD_PICA_PW_CTL _MMIO(0x16fe04) +#define XE2LPD_PICA_CTL_POWER_REQUEST REG_BIT(31) +#define XE2LPD_PICA_CTL_POWER_STATUS REG_BIT(30) + #endif /* __INTEL_DP_AUX_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c index e0c1771614..3a595cd433 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c @@ -330,14 +330,26 @@ static const struct hdcp2_dp_msg_data hdcp2_dp_msg_data[] = { 0, 0 }, }; +static struct drm_dp_aux * +intel_dp_hdcp_get_aux(struct intel_connector *connector) +{ + struct intel_digital_port *dig_port = intel_attached_dig_port(connector); + + if (intel_encoder_is_mst(connector->encoder)) + return &connector->port->aux; + else + return &dig_port->dp.aux; +} + static int -intel_dp_hdcp2_read_rx_status(struct intel_digital_port *dig_port, +intel_dp_hdcp2_read_rx_status(struct intel_connector *connector, u8 *rx_status) { - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct drm_dp_aux *aux = intel_dp_hdcp_get_aux(connector); ssize_t ret; - ret = drm_dp_dpcd_read(&dig_port->dp.aux, + ret = drm_dp_dpcd_read(aux, DP_HDCP_2_2_REG_RXSTATUS_OFFSET, rx_status, HDCP_2_2_DP_RXSTATUS_LEN); if (ret != HDCP_2_2_DP_RXSTATUS_LEN) { @@ -350,14 +362,14 @@ intel_dp_hdcp2_read_rx_status(struct intel_digital_port *dig_port, } static -int hdcp2_detect_msg_availability(struct intel_digital_port *dig_port, +int hdcp2_detect_msg_availability(struct intel_connector *connector, u8 msg_id, bool *msg_ready) { u8 rx_status; int ret; *msg_ready = false; - ret = intel_dp_hdcp2_read_rx_status(dig_port, &rx_status); + ret = intel_dp_hdcp2_read_rx_status(connector, &rx_status); if (ret < 0) return ret; @@ -383,12 +395,11 @@ int hdcp2_detect_msg_availability(struct intel_digital_port *dig_port, } static ssize_t -intel_dp_hdcp2_wait_for_msg(struct intel_digital_port *dig_port, +intel_dp_hdcp2_wait_for_msg(struct intel_connector *connector, const struct hdcp2_dp_msg_data *hdcp2_msg_data) { - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - struct intel_dp *dp = &dig_port->dp; - struct intel_hdcp *hdcp = &dp->attached_connector->hdcp; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_hdcp *hdcp = &connector->hdcp; u8 msg_id = hdcp2_msg_data->msg_id; int ret, timeout; bool msg_ready = false; @@ -411,8 +422,8 @@ intel_dp_hdcp2_wait_for_msg(struct intel_digital_port *dig_port, * the timeout at wait for CP_IRQ. */ intel_dp_hdcp_wait_for_cp_irq(hdcp, timeout); - ret = hdcp2_detect_msg_availability(dig_port, - msg_id, &msg_ready); + ret = hdcp2_detect_msg_availability(connector, msg_id, + &msg_ready); if (!msg_ready) ret = -ETIMEDOUT; } @@ -437,13 +448,14 @@ static const struct hdcp2_dp_msg_data *get_hdcp2_dp_msg_data(u8 msg_id) } static -int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port, +int intel_dp_hdcp2_write_msg(struct intel_connector *connector, void *buf, size_t size) { unsigned int offset; u8 *byte = buf; ssize_t ret, bytes_to_write, len; const struct hdcp2_dp_msg_data *hdcp2_msg_data; + struct drm_dp_aux *aux; hdcp2_msg_data = get_hdcp2_dp_msg_data(*byte); if (!hdcp2_msg_data) @@ -451,6 +463,8 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port, offset = hdcp2_msg_data->offset; + aux = intel_dp_hdcp_get_aux(connector); + /* No msg_id in DP HDCP2.2 msgs */ bytes_to_write = size - 1; byte++; @@ -459,7 +473,7 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port, len = bytes_to_write > DP_AUX_MAX_PAYLOAD_BYTES ? DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_write; - ret = drm_dp_dpcd_write(&dig_port->dp.aux, + ret = drm_dp_dpcd_write(aux, offset, (void *)byte, len); if (ret < 0) return ret; @@ -473,12 +487,14 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *dig_port, } static -ssize_t get_receiver_id_list_rx_info(struct intel_digital_port *dig_port, u32 *dev_cnt, u8 *byte) +ssize_t get_receiver_id_list_rx_info(struct intel_connector *connector, + u32 *dev_cnt, u8 *byte) { + struct drm_dp_aux *aux = intel_dp_hdcp_get_aux(connector); ssize_t ret; u8 *rx_info = byte; - ret = drm_dp_dpcd_read(&dig_port->dp.aux, + ret = drm_dp_dpcd_read(aux, DP_HDCP_2_2_REG_RXINFO_OFFSET, (void *)rx_info, HDCP_2_2_RXINFO_LEN); if (ret != HDCP_2_2_RXINFO_LEN) @@ -494,12 +510,13 @@ ssize_t get_receiver_id_list_rx_info(struct intel_digital_port *dig_port, u32 *d } static -int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, +int intel_dp_hdcp2_read_msg(struct intel_connector *connector, u8 msg_id, void *buf, size_t size) { + struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - struct intel_dp *dp = &dig_port->dp; - struct intel_hdcp *hdcp = &dp->attached_connector->hdcp; + struct intel_hdcp *hdcp = &connector->hdcp; + struct drm_dp_aux *aux; unsigned int offset; u8 *byte = buf; ssize_t ret, bytes_to_recv, len; @@ -513,7 +530,9 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, return -EINVAL; offset = hdcp2_msg_data->offset; - ret = intel_dp_hdcp2_wait_for_msg(dig_port, hdcp2_msg_data); + aux = intel_dp_hdcp_get_aux(connector); + + ret = intel_dp_hdcp2_wait_for_msg(connector, hdcp2_msg_data); if (ret < 0) return ret; @@ -523,7 +542,7 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, byte++; if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST) { - ret = get_receiver_id_list_rx_info(dig_port, &dev_cnt, byte); + ret = get_receiver_id_list_rx_info(connector, &dev_cnt, byte); if (ret < 0) return ret; @@ -541,11 +560,17 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_recv; /* Entire msg read timeout since initiate of msg read */ - if (bytes_to_recv == size - 1 && hdcp2_msg_data->msg_read_timeout > 0) - msg_end = ktime_add_ms(ktime_get_raw(), - hdcp2_msg_data->msg_read_timeout); + if (bytes_to_recv == size - 1 && hdcp2_msg_data->msg_read_timeout > 0) { + if (intel_encoder_is_mst(connector->encoder)) + msg_end = ktime_add_ms(ktime_get_raw(), + hdcp2_msg_data->msg_read_timeout * + connector->port->parent->num_ports); + else + msg_end = ktime_add_ms(ktime_get_raw(), + hdcp2_msg_data->msg_read_timeout); + } - ret = drm_dp_dpcd_read(&dig_port->dp.aux, offset, + ret = drm_dp_dpcd_read(aux, offset, (void *)byte, len); if (ret < 0) { drm_dbg_kms(&i915->drm, "msg_id %d, ret %zd\n", @@ -574,7 +599,7 @@ int intel_dp_hdcp2_read_msg(struct intel_digital_port *dig_port, } static -int intel_dp_hdcp2_config_stream_type(struct intel_digital_port *dig_port, +int intel_dp_hdcp2_config_stream_type(struct intel_connector *connector, bool is_repeater, u8 content_type) { int ret; @@ -593,7 +618,7 @@ int intel_dp_hdcp2_config_stream_type(struct intel_digital_port *dig_port, stream_type_msg.msg_id = HDCP_2_2_ERRATA_DP_STREAM_TYPE; stream_type_msg.stream_type = content_type; - ret = intel_dp_hdcp2_write_msg(dig_port, &stream_type_msg, + ret = intel_dp_hdcp2_write_msg(connector, &stream_type_msg, sizeof(stream_type_msg)); return ret < 0 ? ret : 0; @@ -607,7 +632,8 @@ int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port, u8 rx_status; int ret; - ret = intel_dp_hdcp2_read_rx_status(dig_port, &rx_status); + ret = intel_dp_hdcp2_read_rx_status(connector, + &rx_status); if (ret) return ret; @@ -622,14 +648,17 @@ int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port, } static -int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port, +int intel_dp_hdcp2_capable(struct intel_connector *connector, bool *capable) { + struct drm_dp_aux *aux; u8 rx_caps[3]; int ret; + aux = intel_dp_hdcp_get_aux(connector); + *capable = false; - ret = drm_dp_dpcd_read(&dig_port->dp.aux, + ret = drm_dp_dpcd_read(aux, DP_HDCP_2_2_REG_RX_CAPS_OFFSET, rx_caps, HDCP_2_2_RXCAPS_LEN); if (ret != HDCP_2_2_RXCAPS_LEN) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index a62bca622b..1abfafbbfa 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -1401,11 +1401,13 @@ void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp, * Default value of bit 31 is '0' hence discarding the write * TODO: Corrective actions on SDP corruption yet to be defined */ - if (intel_dp_is_uhbr(crtc_state)) - /* DP v2.0 SCR on SDP CRC16 for 128b/132b Link Layer */ - drm_dp_dpcd_writeb(&intel_dp->aux, - DP_SDP_ERROR_DETECTION_CONFIGURATION, - DP_SDP_CRC16_128B132B_EN); + if (!intel_dp_is_uhbr(crtc_state)) + return; + + /* DP v2.0 SCR on SDP CRC16 for 128b/132b Link Layer */ + drm_dp_dpcd_writeb(&intel_dp->aux, + DP_SDP_ERROR_DETECTION_CONFIGURATION, + DP_SDP_CRC16_128B132B_EN); lt_dbg(intel_dp, DP_PHY_DPRX, "DP2.0 SDP CRC16 for 128b/132b enabled\n"); } diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index f104bd7f8c..03ac281766 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -94,12 +94,9 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, crtc_state->lane_count = limits->max_lane_count; crtc_state->port_clock = limits->max_rate; - // TODO: Handle pbn_div changes by adding a new MST helper - if (!mst_state->pbn_div) { - mst_state->pbn_div = drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr, - crtc_state->port_clock, - crtc_state->lane_count); - } + mst_state->pbn_div = drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr, + crtc_state->port_clock, + crtc_state->lane_count); for (bpp = max_bpp; bpp >= min_bpp; bpp -= step) { drm_dbg_kms(&i915->drm, "Trying bpp %d\n", bpp); @@ -154,15 +151,24 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; int slots = -EINVAL; + int link_bpp; - slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, limits->max_bpp, - limits->min_bpp, limits, + /* + * FIXME: allocate the BW according to link_bpp, which in the case of + * YUV420 is only half of the pipe bpp value. + */ + slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, + to_bpp_int(limits->link.max_bpp_x16), + to_bpp_int(limits->link.min_bpp_x16), + limits, conn_state, 2 * 3, false); if (slots < 0) return slots; - intel_link_compute_m_n(crtc_state->pipe_bpp, + link_bpp = intel_dp_output_bpp(crtc_state->output_format, crtc_state->pipe_bpp); + + intel_link_compute_m_n(link_bpp, crtc_state->lane_count, adjusted_mode->crtc_clock, crtc_state->port_clock, @@ -178,8 +184,6 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, struct drm_connector_state *conn_state, struct link_config_limits *limits) { - struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); - struct intel_dp *intel_dp = &intel_mst->primary->dp; struct intel_connector *connector = to_intel_connector(conn_state->connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); @@ -187,7 +191,7 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, &crtc_state->hw.adjusted_mode; int slots = -EINVAL; int i, num_bpc; - u8 dsc_bpc[3] = {0}; + u8 dsc_bpc[3] = {}; int min_bpp, max_bpp, sink_min_bpp, sink_max_bpp; u8 dsc_max_bpc; bool need_timeslot_recalc = false; @@ -199,10 +203,10 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, else dsc_max_bpc = min_t(u8, 10, conn_state->max_requested_bpc); - max_bpp = min_t(u8, dsc_max_bpc * 3, limits->max_bpp); - min_bpp = limits->min_bpp; + max_bpp = min_t(u8, dsc_max_bpc * 3, limits->pipe.max_bpp); + min_bpp = limits->pipe.min_bpp; - num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd, + num_bpc = drm_dp_dsc_sink_supported_input_bpcs(connector->dp.dsc_dpcd, dsc_bpc); drm_dbg_kms(&i915->drm, "DSC Source supported min bpp %d max bpp %d\n", @@ -227,6 +231,9 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, if (max_bpp > sink_max_bpp) max_bpp = sink_max_bpp; + min_bpp = max(min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); + max_bpp = min(max_bpp, to_bpp_int(limits->link.max_bpp_x16)); + slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, max_bpp, min_bpp, limits, conn_state, 2 * 3, true); @@ -289,17 +296,39 @@ static int intel_dp_mst_update_slots(struct intel_encoder *encoder, return 0; } -static bool intel_dp_mst_has_audio(const struct drm_connector_state *conn_state) +static bool +intel_dp_mst_compute_config_limits(struct intel_dp *intel_dp, + struct intel_crtc_state *crtc_state, + bool dsc, + struct link_config_limits *limits) { - const struct intel_digital_connector_state *intel_conn_state = - to_intel_digital_connector_state(conn_state); - struct intel_connector *connector = - to_intel_connector(conn_state->connector); + /* + * for MST we always configure max link bw - the spec doesn't + * seem to suggest we should do otherwise. + */ + limits->min_rate = limits->max_rate = + intel_dp_max_link_rate(intel_dp); - if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO) - return connector->base.display_info.has_audio; - else - return intel_conn_state->force_audio == HDMI_AUDIO_ON; + limits->min_lane_count = limits->max_lane_count = + intel_dp_max_lane_count(intel_dp); + + limits->pipe.min_bpp = intel_dp_min_bpp(crtc_state->output_format); + /* + * FIXME: If all the streams can't fit into the link with + * their current pipe_bpp we should reduce pipe_bpp across + * the board until things start to fit. Until then we + * limit to <= 8bpc since that's what was hardcoded for all + * MST streams previously. This hack should be removed once + * we have the proper retry logic in place. + */ + limits->pipe.max_bpp = min(crtc_state->pipe_bpp, 24); + + intel_dp_adjust_compliance_config(intel_dp, crtc_state, limits); + + return intel_dp_compute_config_link_bpp_limits(intel_dp, + crtc_state, + dsc, + limits); } static int intel_dp_mst_compute_config(struct intel_encoder *encoder, @@ -312,7 +341,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct link_config_limits limits; - int ret; + bool dsc_needed; + int ret = 0; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL; @@ -321,42 +351,40 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; pipe_config->has_pch_encoder = false; - pipe_config->has_audio = - intel_dp_mst_has_audio(conn_state) && - intel_audio_compute_config(encoder, pipe_config, conn_state); - - /* - * for MST we always configure max link bw - the spec doesn't - * seem to suggest we should do otherwise. - */ - limits.min_rate = - limits.max_rate = intel_dp_max_link_rate(intel_dp); - - limits.min_lane_count = - limits.max_lane_count = intel_dp_max_lane_count(intel_dp); - - limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format); - /* - * FIXME: If all the streams can't fit into the link with - * their current pipe_bpp we should reduce pipe_bpp across - * the board until things start to fit. Until then we - * limit to <= 8bpc since that's what was hardcoded for all - * MST streams previously. This hack should be removed once - * we have the proper retry logic in place. - */ - limits.max_bpp = min(pipe_config->pipe_bpp, 24); + dsc_needed = intel_dp->force_dsc_en || + !intel_dp_mst_compute_config_limits(intel_dp, + pipe_config, + false, + &limits); - intel_dp_adjust_compliance_config(intel_dp, pipe_config, &limits); + if (!dsc_needed) { + ret = intel_dp_mst_compute_link_config(encoder, pipe_config, + conn_state, &limits); - ret = intel_dp_mst_compute_link_config(encoder, pipe_config, - conn_state, &limits); + if (ret == -EDEADLK) + return ret; - if (ret == -EDEADLK) - return ret; + if (ret) + dsc_needed = true; + } /* enable compression if the mode doesn't fit available BW */ - drm_dbg_kms(&dev_priv->drm, "Force DSC en = %d\n", intel_dp->force_dsc_en); - if (ret || intel_dp->force_dsc_en) { + if (dsc_needed) { + drm_dbg_kms(&dev_priv->drm, "Try DSC (fallback=%s, force=%s)\n", + str_yes_no(ret), + str_yes_no(intel_dp->force_dsc_en)); + + if (!intel_dp_mst_compute_config_limits(intel_dp, + pipe_config, + true, + &limits)) + return -EINVAL; + + /* + * FIXME: As bpc is hardcoded to 8, as mentioned above, + * WARN and ignore the debug flag force_dsc_bpc for now. + */ + drm_WARN(&dev_priv->drm, intel_dp->force_dsc_bpc, "Cannot Force BPC for MST\n"); /* * Try to get at least some timeslots and then see, if * we can fit there with DSC. @@ -387,6 +415,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, pipe_config->lane_lat_optim_mask = bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count); + intel_dp_audio_compute_config(encoder, pipe_config, conn_state); + intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); return 0; @@ -556,12 +586,8 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, struct intel_dp *intel_dp = &dig_port->dp; struct intel_connector *connector = to_intel_connector(old_conn_state->connector); - struct drm_dp_mst_topology_state *old_mst_state = - drm_atomic_get_old_mst_topology_state(&state->base, &intel_dp->mst_mgr); struct drm_dp_mst_topology_state *new_mst_state = drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); - const struct drm_dp_mst_atomic_payload *old_payload = - drm_atomic_get_mst_payload_state(old_mst_state, connector->port); struct drm_dp_mst_atomic_payload *new_payload = drm_atomic_get_mst_payload_state(new_mst_state, connector->port); struct drm_i915_private *i915 = to_i915(connector->base.dev); @@ -571,8 +597,7 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, intel_hdcp_disable(intel_mst->connector); - drm_dp_remove_payload(&intel_dp->mst_mgr, new_mst_state, - old_payload, new_payload); + drm_dp_remove_payload_part1(&intel_dp->mst_mgr, new_mst_state, new_payload); intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); } @@ -587,6 +612,14 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, struct intel_dp *intel_dp = &dig_port->dp; struct intel_connector *connector = to_intel_connector(old_conn_state->connector); + struct drm_dp_mst_topology_state *old_mst_state = + drm_atomic_get_old_mst_topology_state(&state->base, &intel_dp->mst_mgr); + struct drm_dp_mst_topology_state *new_mst_state = + drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); + const struct drm_dp_mst_atomic_payload *old_payload = + drm_atomic_get_mst_payload_state(old_mst_state, connector->port); + struct drm_dp_mst_atomic_payload *new_payload = + drm_atomic_get_mst_payload_state(new_mst_state, connector->port); struct drm_i915_private *dev_priv = to_i915(connector->base.dev); bool last_mst_stream; @@ -607,6 +640,9 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, wait_for_act_sent(encoder, old_crtc_state); + drm_dp_remove_payload_part2(&intel_dp->mst_mgr, new_mst_state, + old_payload, new_payload); + intel_ddi_disable_transcoder_func(old_crtc_state); if (DISPLAY_VER(dev_priv) >= 9) @@ -726,8 +762,8 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, ret = drm_dp_add_payload_part1(&intel_dp->mst_mgr, mst_state, drm_atomic_get_mst_payload_state(mst_state, connector->port)); if (ret < 0) - drm_err(&dev_priv->drm, "Failed to create MST payload for %s: %d\n", - connector->base.name, ret); + drm_dbg_kms(&dev_priv->drm, "Failed to create MST payload for %s: %d\n", + connector->base.name, ret); /* * Before Gen 12 this is not done as part of @@ -791,6 +827,8 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_de_rmw(dev_priv, CHICKEN_TRANS(trans), 0, FECSTALL_DIS_DPTSTREAM_DPTTG); + intel_audio_sdp_split_update(pipe_config); + intel_enable_transcoder(pipe_config); intel_crtc_vblank_on(pipe_config); @@ -911,7 +949,7 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, int max_rate, mode_rate, max_lanes, max_link_clock; int ret; bool dsc = false, bigjoiner = false; - u16 dsc_max_output_bpp = 0; + u16 dsc_max_compressed_bpp = 0; u8 dsc_slice_count = 0; int target_clock = mode->clock; @@ -965,30 +1003,31 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, } if (DISPLAY_VER(dev_priv) >= 10 && - drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) { + drm_dp_sink_supports_dsc(intel_connector->dp.dsc_dpcd)) { /* * TBD pass the connector BPC, * for now U8_MAX so that max BPC on that platform would be picked */ - int pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, U8_MAX); - - if (drm_dp_sink_supports_fec(intel_dp->fec_capable)) { - dsc_max_output_bpp = - intel_dp_dsc_get_output_bpp(dev_priv, - max_link_clock, - max_lanes, - target_clock, - mode->hdisplay, - bigjoiner, - pipe_bpp, 64) >> 4; + int pipe_bpp = intel_dp_dsc_compute_max_bpp(intel_connector, U8_MAX); + + if (drm_dp_sink_supports_fec(intel_connector->dp.fec_capability)) { + dsc_max_compressed_bpp = + intel_dp_dsc_get_max_compressed_bpp(dev_priv, + max_link_clock, + max_lanes, + target_clock, + mode->hdisplay, + bigjoiner, + INTEL_OUTPUT_FORMAT_RGB, + pipe_bpp, 64); dsc_slice_count = - intel_dp_dsc_get_slice_count(intel_dp, + intel_dp_dsc_get_slice_count(intel_connector, target_clock, mode->hdisplay, bigjoiner); } - dsc = dsc_max_output_bpp && dsc_slice_count; + dsc = dsc_max_compressed_bpp && dsc_slice_count; } /* @@ -1029,7 +1068,7 @@ intel_dp_mst_detect(struct drm_connector *connector, struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_dp *intel_dp = intel_connector->mst_port; - if (!INTEL_DISPLAY_ENABLED(i915)) + if (!intel_display_device_enabled(i915)) return connector_status_disconnected; if (drm_connector_is_unregistered(connector)) @@ -1096,6 +1135,21 @@ static int intel_dp_mst_add_properties(struct intel_dp *intel_dp, return drm_connector_set_path_property(connector, pathprop); } +static void +intel_dp_mst_read_decompression_port_dsc_caps(struct intel_dp *intel_dp, + struct intel_connector *connector) +{ + u8 dpcd_caps[DP_RECEIVER_CAP_SIZE]; + + if (!connector->dp.dsc_decompression_aux) + return; + + if (drm_dp_read_dpcd_caps(connector->dp.dsc_decompression_aux, dpcd_caps) < 0) + return; + + intel_dp_get_dsc_sink_cap(dpcd_caps[DP_DPCD_REV], connector); +} + static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop) @@ -1118,6 +1172,14 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo intel_connector->port = port; drm_dp_mst_get_port_malloc(port); + /* + * TODO: set the AUX for the actual MST port decompressing the stream. + * At the moment the driver only supports enabling this globally in the + * first downstream MST branch, via intel_dp's (root port) AUX. + */ + intel_connector->dp.dsc_decompression_aux = &intel_dp->aux; + intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector); + connector = &intel_connector->base; ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort); diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.h b/drivers/gpu/drm/i915/display/intel_dpio_phy.h index 9c7725dacb..4d43dbbdf8 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.h +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.h @@ -26,6 +26,7 @@ enum dpio_phy { DPIO_PHY2, }; +#ifdef I915 void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port, enum dpio_phy *phy, enum dpio_channel *ch); void bxt_ddi_phy_set_signal_levels(struct intel_encoder *encoder, @@ -70,5 +71,100 @@ void vlv_phy_pre_encoder_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void vlv_phy_reset_lanes(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state); +#else +static inline void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port, + enum dpio_phy *phy, enum dpio_channel *ch) +{ +} +static inline void bxt_ddi_phy_set_signal_levels(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ +} +static inline void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy) +{ +} +static inline void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy) +{ +} +static inline bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv, + enum dpio_phy phy) +{ + return false; +} +static inline bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv, + enum dpio_phy phy) +{ + return true; +} +static inline u8 bxt_ddi_phy_calc_lane_lat_optim_mask(u8 lane_count) +{ + return 0; +} +static inline void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder, + u8 lane_lat_optim_mask) +{ +} +static inline u8 bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder) +{ + return 0; +} +static inline enum dpio_channel vlv_dig_port_to_channel(struct intel_digital_port *dig_port) +{ + return DPIO_CH0; +} +static inline enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_port) +{ + return DPIO_PHY0; +} +static inline enum dpio_channel vlv_pipe_to_channel(enum pipe pipe) +{ + return DPIO_CH0; +} +static inline void chv_set_phy_signal_level(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + u32 deemph_reg_value, u32 margin_reg_value, + bool uniq_trans_scale) +{ +} +static inline void chv_data_lane_soft_reset(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + bool reset) +{ +} +static inline void chv_phy_pre_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ +} +static inline void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ +} +static inline void chv_phy_release_cl2_override(struct intel_encoder *encoder) +{ +} +static inline void chv_phy_post_pll_disable(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state) +{ +} + +static inline void vlv_set_phy_signal_level(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + u32 demph_reg_value, u32 preemph_reg_value, + u32 uniqtranscale_reg_value, u32 tx3_demph) +{ +} +static inline void vlv_phy_pre_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ +} +static inline void vlv_phy_pre_encoder_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ +} +static inline void vlv_phy_reset_lanes(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state) +{ +} +#endif #endif /* __INTEL_DPIO_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 999badfe29..d41c1dc9f6 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -7,6 +7,7 @@ #include <linux/string_helpers.h> #include "i915_reg.h" +#include "intel_atomic.h" #include "intel_crtc.h" #include "intel_cx0_phy.h" #include "intel_de.h" @@ -314,10 +315,11 @@ int pnv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; - if (WARN_ON(clock->n == 0 || clock->p == 0)) - return 0; - clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); - clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + clock->vco = clock->n == 0 ? 0 : + DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); + clock->dot = clock->p == 0 ? 0 : + DIV_ROUND_CLOSEST(clock->vco, clock->p); return clock->dot; } @@ -331,10 +333,11 @@ int i9xx_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = i9xx_dpll_compute_m(clock); clock->p = clock->p1 * clock->p2; - if (WARN_ON(clock->n + 2 == 0 || clock->p == 0)) - return 0; - clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); - clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + clock->vco = clock->n + 2 == 0 ? 0 : + DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); + clock->dot = clock->p == 0 ? 0 : + DIV_ROUND_CLOSEST(clock->vco, clock->p); return clock->dot; } @@ -343,10 +346,11 @@ int vlv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2 * 5; - if (WARN_ON(clock->n == 0 || clock->p == 0)) - return 0; - clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); - clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + clock->vco = clock->n == 0 ? 0 : + DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); + clock->dot = clock->p == 0 ? 0 : + DIV_ROUND_CLOSEST(clock->vco, clock->p); return clock->dot; } @@ -355,11 +359,11 @@ int chv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2 * 5; - if (WARN_ON(clock->n == 0 || clock->p == 0)) - return 0; - clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m), - clock->n << 22); - clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + clock->vco = clock->n == 0 ? 0 : + DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m), clock->n << 22); + clock->dot = clock->p == 0 ? 0 : + DIV_ROUND_CLOSEST(clock->vco, clock->p); return clock->dot; } @@ -1179,6 +1183,8 @@ static int ilk_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + i9xx_calc_dpll_params(refclk, &crtc_state->dpll); + ilk_compute_dpll(crtc_state, &crtc_state->dpll, &crtc_state->dpll); @@ -1253,6 +1259,8 @@ static int chv_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + chv_calc_dpll_params(refclk, &crtc_state->dpll); + chv_compute_dpll(crtc_state); /* FIXME this is a mess */ @@ -1275,9 +1283,10 @@ static int vlv_crtc_compute_clock(struct intel_atomic_state *state, if (!crtc_state->clock_set && !vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock, - refclk, NULL, &crtc_state->dpll)) { + refclk, NULL, &crtc_state->dpll)) return -EINVAL; - } + + vlv_calc_dpll_params(refclk, &crtc_state->dpll); vlv_compute_dpll(crtc_state); @@ -1327,6 +1336,8 @@ static int g4x_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + i9xx_calc_dpll_params(refclk, &crtc_state->dpll); + i9xx_compute_dpll(crtc_state, &crtc_state->dpll, &crtc_state->dpll); @@ -1365,6 +1376,8 @@ static int pnv_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + pnv_calc_dpll_params(refclk, &crtc_state->dpll); + i9xx_compute_dpll(crtc_state, &crtc_state->dpll, &crtc_state->dpll); @@ -1401,6 +1414,8 @@ static int i9xx_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + i9xx_calc_dpll_params(refclk, &crtc_state->dpll); + i9xx_compute_dpll(crtc_state, &crtc_state->dpll, &crtc_state->dpll); @@ -1441,6 +1456,8 @@ static int i8xx_crtc_compute_clock(struct intel_atomic_state *state, refclk, NULL, &crtc_state->dpll)) return -EINVAL; + i9xx_calc_dpll_params(refclk, &crtc_state->dpll); + i8xx_compute_dpll(crtc_state, &crtc_state->dpll, &crtc_state->dpll); @@ -1990,7 +2007,7 @@ int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe, vlv_enable_pll(crtc_state); } - kfree(crtc_state); + intel_crtc_destroy_state(&crtc->base, &crtc_state->uapi); return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 6d68b36292..399653a20f 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -107,22 +107,20 @@ struct intel_dpll_mgr { struct intel_crtc *crtc, struct intel_encoder *encoder); void (*update_ref_clks)(struct drm_i915_private *i915); - void (*dump_hw_state)(struct drm_i915_private *dev_priv, + void (*dump_hw_state)(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state); }; static void -intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv, +intel_atomic_duplicate_dpll_state(struct drm_i915_private *i915, struct intel_shared_dpll_state *shared_dpll) { - enum intel_dpll_id i; + struct intel_shared_dpll *pll; + int i; /* Copy shared dpll state */ - for (i = 0; i < dev_priv->display.dpll.num_shared_dpll; i++) { - struct intel_shared_dpll *pll = &dev_priv->display.dpll.shared_dplls[i]; - - shared_dpll[i] = pll->state; - } + for_each_shared_dpll(i915, pll, i) + shared_dpll[pll->index] = pll->state; } static struct intel_shared_dpll_state * @@ -144,33 +142,42 @@ intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s) /** * intel_get_shared_dpll_by_id - get a DPLL given its id - * @dev_priv: i915 device instance + * @i915: i915 device instance * @id: pll id * * Returns: * A pointer to the DPLL with @id */ struct intel_shared_dpll * -intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv, +intel_get_shared_dpll_by_id(struct drm_i915_private *i915, enum intel_dpll_id id) { - return &dev_priv->display.dpll.shared_dplls[id]; + struct intel_shared_dpll *pll; + int i; + + for_each_shared_dpll(i915, pll, i) { + if (pll->info->id == id) + return pll; + } + + MISSING_CASE(id); + return NULL; } /* For ILK+ */ -void assert_shared_dpll(struct drm_i915_private *dev_priv, +void assert_shared_dpll(struct drm_i915_private *i915, struct intel_shared_dpll *pll, bool state) { bool cur_state; struct intel_dpll_hw_state hw_state; - if (drm_WARN(&dev_priv->drm, !pll, + if (drm_WARN(&i915->drm, !pll, "asserting DPLL %s with no DPLL\n", str_on_off(state))) return; - cur_state = intel_dpll_get_hw_state(dev_priv, pll, &hw_state); - I915_STATE_WARN(dev_priv, cur_state != state, + cur_state = intel_dpll_get_hw_state(i915, pll, &hw_state); + I915_STATE_WARN(i915, cur_state != state, "%s assertion failure (expected %s, current %s)\n", pll->info->name, str_on_off(state), str_on_off(cur_state)); @@ -221,41 +228,41 @@ intel_tc_pll_enable_reg(struct drm_i915_private *i915, void intel_enable_shared_dpll(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); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_shared_dpll *pll = crtc_state->shared_dpll; unsigned int pipe_mask = BIT(crtc->pipe); unsigned int old_mask; - if (drm_WARN_ON(&dev_priv->drm, pll == NULL)) + if (drm_WARN_ON(&i915->drm, pll == NULL)) return; - mutex_lock(&dev_priv->display.dpll.lock); + mutex_lock(&i915->display.dpll.lock); old_mask = pll->active_mask; - if (drm_WARN_ON(&dev_priv->drm, !(pll->state.pipe_mask & pipe_mask)) || - drm_WARN_ON(&dev_priv->drm, pll->active_mask & pipe_mask)) + if (drm_WARN_ON(&i915->drm, !(pll->state.pipe_mask & pipe_mask)) || + drm_WARN_ON(&i915->drm, pll->active_mask & pipe_mask)) goto out; pll->active_mask |= pipe_mask; - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "enable %s (active 0x%x, on? %d) for [CRTC:%d:%s]\n", pll->info->name, pll->active_mask, pll->on, crtc->base.base.id, crtc->base.name); if (old_mask) { - drm_WARN_ON(&dev_priv->drm, !pll->on); - assert_shared_dpll_enabled(dev_priv, pll); + drm_WARN_ON(&i915->drm, !pll->on); + assert_shared_dpll_enabled(i915, pll); goto out; } - drm_WARN_ON(&dev_priv->drm, pll->on); + drm_WARN_ON(&i915->drm, pll->on); - drm_dbg_kms(&dev_priv->drm, "enabling %s\n", pll->info->name); - pll->info->funcs->enable(dev_priv, pll); + drm_dbg_kms(&i915->drm, "enabling %s\n", pll->info->name); + pll->info->funcs->enable(i915, pll); pll->on = true; out: - mutex_unlock(&dev_priv->display.dpll.lock); + mutex_unlock(&i915->display.dpll.lock); } /** @@ -267,41 +274,57 @@ out: void intel_disable_shared_dpll(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); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_shared_dpll *pll = crtc_state->shared_dpll; unsigned int pipe_mask = BIT(crtc->pipe); /* PCH only available on ILK+ */ - if (DISPLAY_VER(dev_priv) < 5) + if (DISPLAY_VER(i915) < 5) return; if (pll == NULL) return; - mutex_lock(&dev_priv->display.dpll.lock); - if (drm_WARN(&dev_priv->drm, !(pll->active_mask & pipe_mask), + mutex_lock(&i915->display.dpll.lock); + if (drm_WARN(&i915->drm, !(pll->active_mask & pipe_mask), "%s not used by [CRTC:%d:%s]\n", pll->info->name, crtc->base.base.id, crtc->base.name)) goto out; - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "disable %s (active 0x%x, on? %d) for [CRTC:%d:%s]\n", pll->info->name, pll->active_mask, pll->on, crtc->base.base.id, crtc->base.name); - assert_shared_dpll_enabled(dev_priv, pll); - drm_WARN_ON(&dev_priv->drm, !pll->on); + assert_shared_dpll_enabled(i915, pll); + drm_WARN_ON(&i915->drm, !pll->on); pll->active_mask &= ~pipe_mask; if (pll->active_mask) goto out; - drm_dbg_kms(&dev_priv->drm, "disabling %s\n", pll->info->name); - pll->info->funcs->disable(dev_priv, pll); + drm_dbg_kms(&i915->drm, "disabling %s\n", pll->info->name); + pll->info->funcs->disable(i915, pll); pll->on = false; out: - mutex_unlock(&dev_priv->display.dpll.lock); + mutex_unlock(&i915->display.dpll.lock); +} + +static unsigned long +intel_dpll_mask_all(struct drm_i915_private *i915) +{ + struct intel_shared_dpll *pll; + unsigned long dpll_mask = 0; + int i; + + for_each_shared_dpll(i915, pll, i) { + drm_WARN_ON(&i915->drm, dpll_mask & BIT(pll->info->id)); + + dpll_mask |= BIT(pll->info->id); + } + + return dpll_mask; } static struct intel_shared_dpll * @@ -310,33 +333,38 @@ intel_find_shared_dpll(struct intel_atomic_state *state, const struct intel_dpll_hw_state *pll_state, unsigned long dpll_mask) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct intel_shared_dpll *pll, *unused_pll = NULL; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + unsigned long dpll_mask_all = intel_dpll_mask_all(i915); struct intel_shared_dpll_state *shared_dpll; - enum intel_dpll_id i; + struct intel_shared_dpll *unused_pll = NULL; + enum intel_dpll_id id; shared_dpll = intel_atomic_get_shared_dpll_state(&state->base); - drm_WARN_ON(&dev_priv->drm, dpll_mask & ~(BIT(I915_NUM_PLLS) - 1)); + drm_WARN_ON(&i915->drm, dpll_mask & ~dpll_mask_all); + + for_each_set_bit(id, &dpll_mask, fls(dpll_mask_all)) { + struct intel_shared_dpll *pll; - for_each_set_bit(i, &dpll_mask, I915_NUM_PLLS) { - pll = &dev_priv->display.dpll.shared_dplls[i]; + pll = intel_get_shared_dpll_by_id(i915, id); + if (!pll) + continue; /* Only want to check enabled timings first */ - if (shared_dpll[i].pipe_mask == 0) { + if (shared_dpll[pll->index].pipe_mask == 0) { if (!unused_pll) unused_pll = pll; continue; } if (memcmp(pll_state, - &shared_dpll[i].hw_state, + &shared_dpll[pll->index].hw_state, sizeof(*pll_state)) == 0) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] sharing existing %s (pipe mask 0x%x, active 0x%x)\n", crtc->base.base.id, crtc->base.name, pll->info->name, - shared_dpll[i].pipe_mask, + shared_dpll[pll->index].pipe_mask, pll->active_mask); return pll; } @@ -344,7 +372,7 @@ intel_find_shared_dpll(struct intel_atomic_state *state, /* Ok no matching timings, maybe there's a free one? */ if (unused_pll) { - drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] allocated %s\n", + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] allocated %s\n", crtc->base.base.id, crtc->base.name, unused_pll->info->name); return unused_pll; @@ -383,14 +411,13 @@ intel_reference_shared_dpll(struct intel_atomic_state *state, const struct intel_dpll_hw_state *pll_state) { struct intel_shared_dpll_state *shared_dpll; - const enum intel_dpll_id id = pll->info->id; shared_dpll = intel_atomic_get_shared_dpll_state(&state->base); - if (shared_dpll[id].pipe_mask == 0) - shared_dpll[id].hw_state = *pll_state; + if (shared_dpll[pll->index].pipe_mask == 0) + shared_dpll[pll->index].hw_state = *pll_state; - intel_reference_shared_dpll_crtc(crtc, pll, &shared_dpll[id]); + intel_reference_shared_dpll_crtc(crtc, pll, &shared_dpll[pll->index]); } /** @@ -421,11 +448,10 @@ static void intel_unreference_shared_dpll(struct intel_atomic_state *state, const struct intel_shared_dpll *pll) { struct intel_shared_dpll_state *shared_dpll; - const enum intel_dpll_id id = pll->info->id; shared_dpll = intel_atomic_get_shared_dpll_state(&state->base); - intel_unreference_shared_dpll_crtc(crtc, pll, &shared_dpll[id]); + intel_unreference_shared_dpll_crtc(crtc, pll, &shared_dpll[pll->index]); } static void intel_put_dpll(struct intel_atomic_state *state, @@ -457,22 +483,19 @@ static void intel_put_dpll(struct intel_atomic_state *state, */ void intel_shared_dpll_swap_state(struct intel_atomic_state *state) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_shared_dpll_state *shared_dpll = state->shared_dpll; - enum intel_dpll_id i; + struct intel_shared_dpll *pll; + int i; if (!state->dpll_set) return; - for (i = 0; i < dev_priv->display.dpll.num_shared_dpll; i++) { - struct intel_shared_dpll *pll = - &dev_priv->display.dpll.shared_dplls[i]; - - swap(pll->state, shared_dpll[i]); - } + for_each_shared_dpll(i915, pll, i) + swap(pll->state, shared_dpll[pll->index]); } -static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, +static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -480,48 +503,48 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, intel_wakeref_t wakeref; u32 val; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, PCH_DPLL(id)); + val = intel_de_read(i915, PCH_DPLL(id)); hw_state->dpll = val; - hw_state->fp0 = intel_de_read(dev_priv, PCH_FP0(id)); - hw_state->fp1 = intel_de_read(dev_priv, PCH_FP1(id)); + hw_state->fp0 = intel_de_read(i915, PCH_FP0(id)); + hw_state->fp1 = intel_de_read(i915, PCH_FP1(id)); - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return val & DPLL_VCO_ENABLE; } -static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) +static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *i915) { u32 val; bool enabled; - val = intel_de_read(dev_priv, PCH_DREF_CONTROL); + val = intel_de_read(i915, PCH_DREF_CONTROL); enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK | DREF_SUPERSPREAD_SOURCE_MASK)); - I915_STATE_WARN(dev_priv, !enabled, + I915_STATE_WARN(i915, !enabled, "PCH refclk assertion failure, should be active but is disabled\n"); } -static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, +static void ibx_pch_dpll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const enum intel_dpll_id id = pll->info->id; /* PCH refclock must be enabled first */ - ibx_assert_pch_refclk_enabled(dev_priv); + ibx_assert_pch_refclk_enabled(i915); - intel_de_write(dev_priv, PCH_FP0(id), pll->state.hw_state.fp0); - intel_de_write(dev_priv, PCH_FP1(id), pll->state.hw_state.fp1); + intel_de_write(i915, PCH_FP0(id), pll->state.hw_state.fp0); + intel_de_write(i915, PCH_FP1(id), pll->state.hw_state.fp1); - intel_de_write(dev_priv, PCH_DPLL(id), pll->state.hw_state.dpll); + intel_de_write(i915, PCH_DPLL(id), pll->state.hw_state.dpll); /* Wait for the clocks to stabilize. */ - intel_de_posting_read(dev_priv, PCH_DPLL(id)); + intel_de_posting_read(i915, PCH_DPLL(id)); udelay(150); /* The pixel multiplier can only be updated once the @@ -529,18 +552,18 @@ static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, * * So write it again. */ - intel_de_write(dev_priv, PCH_DPLL(id), pll->state.hw_state.dpll); - intel_de_posting_read(dev_priv, PCH_DPLL(id)); + intel_de_write(i915, PCH_DPLL(id), pll->state.hw_state.dpll); + intel_de_posting_read(i915, PCH_DPLL(id)); udelay(200); } -static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv, +static void ibx_pch_dpll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const enum intel_dpll_id id = pll->info->id; - intel_de_write(dev_priv, PCH_DPLL(id), 0); - intel_de_posting_read(dev_priv, PCH_DPLL(id)); + intel_de_write(i915, PCH_DPLL(id), 0); + intel_de_posting_read(i915, PCH_DPLL(id)); udelay(200); } @@ -557,16 +580,16 @@ static int ibx_get_dpll(struct intel_atomic_state *state, { struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_shared_dpll *pll; - enum intel_dpll_id i; + enum intel_dpll_id id; - if (HAS_PCH_IBX(dev_priv)) { + if (HAS_PCH_IBX(i915)) { /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */ - i = (enum intel_dpll_id) crtc->pipe; - pll = &dev_priv->display.dpll.shared_dplls[i]; + id = (enum intel_dpll_id) crtc->pipe; + pll = intel_get_shared_dpll_by_id(i915, id); - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] using pre-allocated %s\n", crtc->base.base.id, crtc->base.name, pll->info->name); @@ -589,10 +612,10 @@ static int ibx_get_dpll(struct intel_atomic_state *state, return 0; } -static void ibx_dump_hw_state(struct drm_i915_private *dev_priv, +static void ibx_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, " "fp0: 0x%x, fp1: 0x%x\n", hw_state->dpll, @@ -621,57 +644,57 @@ static const struct intel_dpll_mgr pch_pll_mgr = { .dump_hw_state = ibx_dump_hw_state, }; -static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv, +static void hsw_ddi_wrpll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const enum intel_dpll_id id = pll->info->id; - intel_de_write(dev_priv, WRPLL_CTL(id), pll->state.hw_state.wrpll); - intel_de_posting_read(dev_priv, WRPLL_CTL(id)); + intel_de_write(i915, WRPLL_CTL(id), pll->state.hw_state.wrpll); + intel_de_posting_read(i915, WRPLL_CTL(id)); udelay(20); } -static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv, +static void hsw_ddi_spll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - intel_de_write(dev_priv, SPLL_CTL, pll->state.hw_state.spll); - intel_de_posting_read(dev_priv, SPLL_CTL); + intel_de_write(i915, SPLL_CTL, pll->state.hw_state.spll); + intel_de_posting_read(i915, SPLL_CTL); udelay(20); } -static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv, +static void hsw_ddi_wrpll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const enum intel_dpll_id id = pll->info->id; - intel_de_rmw(dev_priv, WRPLL_CTL(id), WRPLL_PLL_ENABLE, 0); - intel_de_posting_read(dev_priv, WRPLL_CTL(id)); + intel_de_rmw(i915, WRPLL_CTL(id), WRPLL_PLL_ENABLE, 0); + intel_de_posting_read(i915, WRPLL_CTL(id)); /* * Try to set up the PCH reference clock once all DPLLs * that depend on it have been shut down. */ - if (dev_priv->display.dpll.pch_ssc_use & BIT(id)) - intel_init_pch_refclk(dev_priv); + if (i915->display.dpll.pch_ssc_use & BIT(id)) + intel_init_pch_refclk(i915); } -static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv, +static void hsw_ddi_spll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { enum intel_dpll_id id = pll->info->id; - intel_de_rmw(dev_priv, SPLL_CTL, SPLL_PLL_ENABLE, 0); - intel_de_posting_read(dev_priv, SPLL_CTL); + intel_de_rmw(i915, SPLL_CTL, SPLL_PLL_ENABLE, 0); + intel_de_posting_read(i915, SPLL_CTL); /* * Try to set up the PCH reference clock once all DPLLs * that depend on it have been shut down. */ - if (dev_priv->display.dpll.pch_ssc_use & BIT(id)) - intel_init_pch_refclk(dev_priv); + if (i915->display.dpll.pch_ssc_use & BIT(id)) + intel_init_pch_refclk(i915); } -static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv, +static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -679,35 +702,35 @@ static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv, intel_wakeref_t wakeref; u32 val; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, WRPLL_CTL(id)); + val = intel_de_read(i915, WRPLL_CTL(id)); hw_state->wrpll = val; - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return val & WRPLL_PLL_ENABLE; } -static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv, +static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { intel_wakeref_t wakeref; u32 val; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, SPLL_CTL); + val = intel_de_read(i915, SPLL_CTL); hw_state->spll = val; - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return val & SPLL_PLL_ENABLE; } @@ -918,7 +941,7 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */, *r2_out = best.r2; } -static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv, +static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *i915, const struct intel_shared_dpll *pll, const struct intel_dpll_hw_state *pll_state) { @@ -929,8 +952,8 @@ static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv, switch (wrpll & WRPLL_REF_MASK) { case WRPLL_REF_SPECIAL_HSW: /* Muxed-SSC for BDW, non-SSC for non-ULT HSW. */ - if (IS_HASWELL(dev_priv) && !IS_HASWELL_ULT(dev_priv)) { - refclk = dev_priv->display.dpll.ref_clks.nssc; + if (IS_HASWELL(i915) && !IS_HASWELL_ULT(i915)) { + refclk = i915->display.dpll.ref_clks.nssc; break; } fallthrough; @@ -940,7 +963,7 @@ static int hsw_ddi_wrpll_get_freq(struct drm_i915_private *dev_priv, * code only cares about 5% accuracy, and spread is a max of * 0.5% downspread. */ - refclk = dev_priv->display.dpll.ref_clks.ssc; + refclk = i915->display.dpll.ref_clks.ssc; break; case WRPLL_REF_LCPLL: refclk = 2700000; @@ -996,7 +1019,7 @@ hsw_ddi_wrpll_get_dpll(struct intel_atomic_state *state, static int hsw_ddi_lcpll_compute_dpll(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); int clock = crtc_state->port_clock; switch (clock / 2) { @@ -1005,7 +1028,7 @@ hsw_ddi_lcpll_compute_dpll(struct intel_crtc_state *crtc_state) case 270000: return 0; default: - drm_dbg_kms(&dev_priv->drm, "Invalid clock for DP: %d\n", + drm_dbg_kms(&i915->drm, "Invalid clock for DP: %d\n", clock); return -EINVAL; } @@ -1014,7 +1037,7 @@ hsw_ddi_lcpll_compute_dpll(struct intel_crtc_state *crtc_state) static struct intel_shared_dpll * hsw_ddi_lcpll_get_dpll(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); struct intel_shared_dpll *pll; enum intel_dpll_id pll_id; int clock = crtc_state->port_clock; @@ -1034,7 +1057,7 @@ hsw_ddi_lcpll_get_dpll(struct intel_crtc_state *crtc_state) return NULL; } - pll = intel_get_shared_dpll_by_id(dev_priv, pll_id); + pll = intel_get_shared_dpll_by_id(i915, pll_id); if (!pll) return NULL; @@ -1170,10 +1193,10 @@ static void hsw_update_dpll_ref_clks(struct drm_i915_private *i915) i915->display.dpll.ref_clks.nssc = 135000; } -static void hsw_dump_hw_state(struct drm_i915_private *dev_priv, +static void hsw_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - drm_dbg_kms(&dev_priv->drm, "dpll_hw_state: wrpll: 0x%x spll: 0x%x\n", + drm_dbg_kms(&i915->drm, "dpll_hw_state: wrpll: 0x%x spll: 0x%x\n", hw_state->wrpll, hw_state->spll); } @@ -1191,17 +1214,17 @@ static const struct intel_shared_dpll_funcs hsw_ddi_spll_funcs = { .get_freq = hsw_ddi_spll_get_freq, }; -static void hsw_ddi_lcpll_enable(struct drm_i915_private *dev_priv, +static void hsw_ddi_lcpll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { } -static void hsw_ddi_lcpll_disable(struct drm_i915_private *dev_priv, +static void hsw_ddi_lcpll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { } -static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv, +static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -1265,60 +1288,60 @@ static const struct skl_dpll_regs skl_dpll_regs[4] = { }, }; -static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *dev_priv, +static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const enum intel_dpll_id id = pll->info->id; - intel_de_rmw(dev_priv, DPLL_CTRL1, + intel_de_rmw(i915, DPLL_CTRL1, DPLL_CTRL1_HDMI_MODE(id) | DPLL_CTRL1_SSC(id) | DPLL_CTRL1_LINK_RATE_MASK(id), pll->state.hw_state.ctrl1 << (id * 6)); - intel_de_posting_read(dev_priv, DPLL_CTRL1); + intel_de_posting_read(i915, DPLL_CTRL1); } -static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv, +static void skl_ddi_pll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const struct skl_dpll_regs *regs = skl_dpll_regs; const enum intel_dpll_id id = pll->info->id; - skl_ddi_pll_write_ctrl1(dev_priv, pll); + skl_ddi_pll_write_ctrl1(i915, pll); - intel_de_write(dev_priv, regs[id].cfgcr1, pll->state.hw_state.cfgcr1); - intel_de_write(dev_priv, regs[id].cfgcr2, pll->state.hw_state.cfgcr2); - intel_de_posting_read(dev_priv, regs[id].cfgcr1); - intel_de_posting_read(dev_priv, regs[id].cfgcr2); + intel_de_write(i915, regs[id].cfgcr1, pll->state.hw_state.cfgcr1); + intel_de_write(i915, regs[id].cfgcr2, pll->state.hw_state.cfgcr2); + intel_de_posting_read(i915, regs[id].cfgcr1); + intel_de_posting_read(i915, regs[id].cfgcr2); /* the enable bit is always bit 31 */ - intel_de_rmw(dev_priv, regs[id].ctl, 0, LCPLL_PLL_ENABLE); + intel_de_rmw(i915, regs[id].ctl, 0, LCPLL_PLL_ENABLE); - if (intel_de_wait_for_set(dev_priv, DPLL_STATUS, DPLL_LOCK(id), 5)) - drm_err(&dev_priv->drm, "DPLL %d not locked\n", id); + if (intel_de_wait_for_set(i915, DPLL_STATUS, DPLL_LOCK(id), 5)) + drm_err(&i915->drm, "DPLL %d not locked\n", id); } -static void skl_ddi_dpll0_enable(struct drm_i915_private *dev_priv, +static void skl_ddi_dpll0_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - skl_ddi_pll_write_ctrl1(dev_priv, pll); + skl_ddi_pll_write_ctrl1(i915, pll); } -static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv, +static void skl_ddi_pll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { const struct skl_dpll_regs *regs = skl_dpll_regs; const enum intel_dpll_id id = pll->info->id; /* the enable bit is always bit 31 */ - intel_de_rmw(dev_priv, regs[id].ctl, LCPLL_PLL_ENABLE, 0); - intel_de_posting_read(dev_priv, regs[id].ctl); + intel_de_rmw(i915, regs[id].ctl, LCPLL_PLL_ENABLE, 0); + intel_de_posting_read(i915, regs[id].ctl); } -static void skl_ddi_dpll0_disable(struct drm_i915_private *dev_priv, +static void skl_ddi_dpll0_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { } -static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -1328,34 +1351,34 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, intel_wakeref_t wakeref; bool ret; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; ret = false; - val = intel_de_read(dev_priv, regs[id].ctl); + val = intel_de_read(i915, regs[id].ctl); if (!(val & LCPLL_PLL_ENABLE)) goto out; - val = intel_de_read(dev_priv, DPLL_CTRL1); + val = intel_de_read(i915, DPLL_CTRL1); hw_state->ctrl1 = (val >> (id * 6)) & 0x3f; /* avoid reading back stale values if HDMI mode is not enabled */ if (val & DPLL_CTRL1_HDMI_MODE(id)) { - hw_state->cfgcr1 = intel_de_read(dev_priv, regs[id].cfgcr1); - hw_state->cfgcr2 = intel_de_read(dev_priv, regs[id].cfgcr2); + hw_state->cfgcr1 = intel_de_read(i915, regs[id].cfgcr1); + hw_state->cfgcr2 = intel_de_read(i915, regs[id].cfgcr2); } ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } -static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv, +static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -1365,7 +1388,7 @@ static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv, u32 val; bool ret; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; @@ -1373,17 +1396,17 @@ static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv, ret = false; /* DPLL0 is always enabled since it drives CDCLK */ - val = intel_de_read(dev_priv, regs[id].ctl); - if (drm_WARN_ON(&dev_priv->drm, !(val & LCPLL_PLL_ENABLE))) + val = intel_de_read(i915, regs[id].ctl); + if (drm_WARN_ON(&i915->drm, !(val & LCPLL_PLL_ENABLE))) goto out; - val = intel_de_read(dev_priv, DPLL_CTRL1); + val = intel_de_read(i915, DPLL_CTRL1); hw_state->ctrl1 = (val >> (id * 6)) & 0x3f; ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } @@ -1873,10 +1896,10 @@ static void skl_update_dpll_ref_clks(struct drm_i915_private *i915) i915->display.dpll.ref_clks.nssc = i915->display.cdclk.hw.ref; } -static void skl_dump_hw_state(struct drm_i915_private *dev_priv, +static void skl_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - drm_dbg_kms(&dev_priv->drm, "dpll_hw_state: " + drm_dbg_kms(&i915->drm, "dpll_hw_state: " "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n", hw_state->ctrl1, hw_state->cfgcr1, @@ -1914,129 +1937,129 @@ static const struct intel_dpll_mgr skl_pll_mgr = { .dump_hw_state = skl_dump_hw_state, }; -static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, - struct intel_shared_dpll *pll) +static void bxt_ddi_pll_enable(struct drm_i915_private *i915, + struct intel_shared_dpll *pll) { u32 temp; enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ enum dpio_phy phy; enum dpio_channel ch; - bxt_port_to_phy_channel(dev_priv, port, &phy, &ch); + bxt_port_to_phy_channel(i915, port, &phy, &ch); /* Non-SSC reference */ - intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_REF_SEL); + intel_de_rmw(i915, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_REF_SEL); - if (IS_GEMINILAKE(dev_priv)) { - intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), + if (IS_GEMINILAKE(i915)) { + intel_de_rmw(i915, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_POWER_ENABLE); - if (wait_for_us((intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)) & + if (wait_for_us((intel_de_read(i915, BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_POWER_STATE), 200)) - drm_err(&dev_priv->drm, + drm_err(&i915->drm, "Power state not set for PLL:%d\n", port); } /* Disable 10 bit clock */ - intel_de_rmw(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch), + intel_de_rmw(i915, BXT_PORT_PLL_EBB_4(phy, ch), PORT_PLL_10BIT_CLK_ENABLE, 0); /* Write P1 & P2 */ - intel_de_rmw(dev_priv, BXT_PORT_PLL_EBB_0(phy, ch), + intel_de_rmw(i915, BXT_PORT_PLL_EBB_0(phy, ch), PORT_PLL_P1_MASK | PORT_PLL_P2_MASK, pll->state.hw_state.ebb0); /* Write M2 integer */ - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 0), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 0), PORT_PLL_M2_INT_MASK, pll->state.hw_state.pll0); /* Write N */ - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 1), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 1), PORT_PLL_N_MASK, pll->state.hw_state.pll1); /* Write M2 fraction */ - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 2), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 2), PORT_PLL_M2_FRAC_MASK, pll->state.hw_state.pll2); /* Write M2 fraction enable */ - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 3), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 3), PORT_PLL_M2_FRAC_ENABLE, pll->state.hw_state.pll3); /* Write coeff */ - temp = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 6)); + temp = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 6)); temp &= ~PORT_PLL_PROP_COEFF_MASK; temp &= ~PORT_PLL_INT_COEFF_MASK; temp &= ~PORT_PLL_GAIN_CTL_MASK; temp |= pll->state.hw_state.pll6; - intel_de_write(dev_priv, BXT_PORT_PLL(phy, ch, 6), temp); + intel_de_write(i915, BXT_PORT_PLL(phy, ch, 6), temp); /* Write calibration val */ - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 8), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 8), PORT_PLL_TARGET_CNT_MASK, pll->state.hw_state.pll8); - intel_de_rmw(dev_priv, BXT_PORT_PLL(phy, ch, 9), + intel_de_rmw(i915, BXT_PORT_PLL(phy, ch, 9), PORT_PLL_LOCK_THRESHOLD_MASK, pll->state.hw_state.pll9); - temp = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 10)); + temp = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 10)); temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H; temp &= ~PORT_PLL_DCO_AMP_MASK; temp |= pll->state.hw_state.pll10; - intel_de_write(dev_priv, BXT_PORT_PLL(phy, ch, 10), temp); + intel_de_write(i915, BXT_PORT_PLL(phy, ch, 10), temp); /* Recalibrate with new settings */ - temp = intel_de_read(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch)); + temp = intel_de_read(i915, BXT_PORT_PLL_EBB_4(phy, ch)); temp |= PORT_PLL_RECALIBRATE; - intel_de_write(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch), temp); + intel_de_write(i915, BXT_PORT_PLL_EBB_4(phy, ch), temp); temp &= ~PORT_PLL_10BIT_CLK_ENABLE; temp |= pll->state.hw_state.ebb4; - intel_de_write(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch), temp); + intel_de_write(i915, BXT_PORT_PLL_EBB_4(phy, ch), temp); /* Enable PLL */ - intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_ENABLE); - intel_de_posting_read(dev_priv, BXT_PORT_PLL_ENABLE(port)); + intel_de_rmw(i915, BXT_PORT_PLL_ENABLE(port), 0, PORT_PLL_ENABLE); + intel_de_posting_read(i915, BXT_PORT_PLL_ENABLE(port)); - if (wait_for_us((intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_LOCK), + if (wait_for_us((intel_de_read(i915, BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_LOCK), 200)) - drm_err(&dev_priv->drm, "PLL %d not locked\n", port); + drm_err(&i915->drm, "PLL %d not locked\n", port); - if (IS_GEMINILAKE(dev_priv)) { - temp = intel_de_read(dev_priv, BXT_PORT_TX_DW5_LN0(phy, ch)); + if (IS_GEMINILAKE(i915)) { + temp = intel_de_read(i915, BXT_PORT_TX_DW5_LN0(phy, ch)); temp |= DCC_DELAY_RANGE_2; - intel_de_write(dev_priv, BXT_PORT_TX_DW5_GRP(phy, ch), temp); + intel_de_write(i915, BXT_PORT_TX_DW5_GRP(phy, ch), temp); } /* * While we write to the group register to program all lanes at once we * can read only lane registers and we pick lanes 0/1 for that. */ - temp = intel_de_read(dev_priv, BXT_PORT_PCS_DW12_LN01(phy, ch)); + temp = intel_de_read(i915, BXT_PORT_PCS_DW12_LN01(phy, ch)); temp &= ~LANE_STAGGER_MASK; temp &= ~LANESTAGGER_STRAP_OVRD; temp |= pll->state.hw_state.pcsdw12; - intel_de_write(dev_priv, BXT_PORT_PCS_DW12_GRP(phy, ch), temp); + intel_de_write(i915, BXT_PORT_PCS_DW12_GRP(phy, ch), temp); } -static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv, - struct intel_shared_dpll *pll) +static void bxt_ddi_pll_disable(struct drm_i915_private *i915, + struct intel_shared_dpll *pll) { enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ - intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), PORT_PLL_ENABLE, 0); - intel_de_posting_read(dev_priv, BXT_PORT_PLL_ENABLE(port)); + intel_de_rmw(i915, BXT_PORT_PLL_ENABLE(port), PORT_PLL_ENABLE, 0); + intel_de_posting_read(i915, BXT_PORT_PLL_ENABLE(port)); - if (IS_GEMINILAKE(dev_priv)) { - intel_de_rmw(dev_priv, BXT_PORT_PLL_ENABLE(port), + if (IS_GEMINILAKE(i915)) { + intel_de_rmw(i915, BXT_PORT_PLL_ENABLE(port), PORT_PLL_POWER_ENABLE, 0); - if (wait_for_us(!(intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)) & + if (wait_for_us(!(intel_de_read(i915, BXT_PORT_PLL_ENABLE(port)) & PORT_PLL_POWER_STATE), 200)) - drm_err(&dev_priv->drm, + drm_err(&i915->drm, "Power state not reset for PLL:%d\n", port); } } -static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, - struct intel_shared_dpll *pll, - struct intel_dpll_hw_state *hw_state) +static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *i915, + struct intel_shared_dpll *pll, + struct intel_dpll_hw_state *hw_state) { enum port port = (enum port)pll->info->id; /* 1:1 port->PLL mapping */ intel_wakeref_t wakeref; @@ -2045,49 +2068,49 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, u32 val; bool ret; - bxt_port_to_phy_channel(dev_priv, port, &phy, &ch); + bxt_port_to_phy_channel(i915, port, &phy, &ch); - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; ret = false; - val = intel_de_read(dev_priv, BXT_PORT_PLL_ENABLE(port)); + val = intel_de_read(i915, BXT_PORT_PLL_ENABLE(port)); if (!(val & PORT_PLL_ENABLE)) goto out; - hw_state->ebb0 = intel_de_read(dev_priv, BXT_PORT_PLL_EBB_0(phy, ch)); + hw_state->ebb0 = intel_de_read(i915, BXT_PORT_PLL_EBB_0(phy, ch)); hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK; - hw_state->ebb4 = intel_de_read(dev_priv, BXT_PORT_PLL_EBB_4(phy, ch)); + hw_state->ebb4 = intel_de_read(i915, BXT_PORT_PLL_EBB_4(phy, ch)); hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE; - hw_state->pll0 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 0)); + hw_state->pll0 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 0)); hw_state->pll0 &= PORT_PLL_M2_INT_MASK; - hw_state->pll1 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 1)); + hw_state->pll1 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 1)); hw_state->pll1 &= PORT_PLL_N_MASK; - hw_state->pll2 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 2)); + hw_state->pll2 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 2)); hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK; - hw_state->pll3 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 3)); + hw_state->pll3 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 3)); hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE; - hw_state->pll6 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 6)); + hw_state->pll6 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 6)); hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK | PORT_PLL_INT_COEFF_MASK | PORT_PLL_GAIN_CTL_MASK; - hw_state->pll8 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 8)); + hw_state->pll8 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 8)); hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK; - hw_state->pll9 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 9)); + hw_state->pll9 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 9)); hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK; - hw_state->pll10 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 10)); + hw_state->pll10 = intel_de_read(i915, BXT_PORT_PLL(phy, ch, 10)); hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H | PORT_PLL_DCO_AMP_MASK; @@ -2096,20 +2119,20 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, * can read only lane registers. We configure all lanes the same way, so * here just read out lanes 0/1 and output a note if lanes 2/3 differ. */ - hw_state->pcsdw12 = intel_de_read(dev_priv, + hw_state->pcsdw12 = intel_de_read(i915, BXT_PORT_PCS_DW12_LN01(phy, ch)); - if (intel_de_read(dev_priv, BXT_PORT_PCS_DW12_LN23(phy, ch)) != hw_state->pcsdw12) - drm_dbg(&dev_priv->drm, + if (intel_de_read(i915, BXT_PORT_PCS_DW12_LN23(phy, ch)) != hw_state->pcsdw12) + drm_dbg(&i915->drm, "lane stagger config different for lane 01 (%08x) and 23 (%08x)\n", hw_state->pcsdw12, - intel_de_read(dev_priv, + intel_de_read(i915, BXT_PORT_PCS_DW12_LN23(phy, ch))); hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD; ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } @@ -2300,15 +2323,15 @@ static int bxt_get_dpll(struct intel_atomic_state *state, { struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_shared_dpll *pll; enum intel_dpll_id id; /* 1:1 mapping between ports and PLLs */ id = (enum intel_dpll_id) encoder->port; - pll = intel_get_shared_dpll_by_id(dev_priv, id); + pll = intel_get_shared_dpll_by_id(i915, id); - drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] using pre-allocated %s\n", + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] using pre-allocated %s\n", crtc->base.base.id, crtc->base.name, pll->info->name); intel_reference_shared_dpll(state, crtc, @@ -2326,10 +2349,10 @@ static void bxt_update_dpll_ref_clks(struct drm_i915_private *i915) /* DSI non-SSC ref 19.2MHz */ } -static void bxt_dump_hw_state(struct drm_i915_private *dev_priv, +static void bxt_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - drm_dbg_kms(&dev_priv->drm, "dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x," + drm_dbg_kms(&i915->drm, "dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x," "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, " "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pll10: 0x%x, pcsdw12: 0x%x\n", hw_state->ebb0, @@ -2557,9 +2580,9 @@ static const struct skl_wrpll_params tgl_tbt_pll_24MHz_values = { static int icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state, struct skl_wrpll_params *pll_params) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); const struct icl_combo_pll_params *params = - dev_priv->display.dpll.ref_clks.nssc == 24000 ? + i915->display.dpll.ref_clks.nssc == 24000 ? icl_dp_combo_pll_24MHz_values : icl_dp_combo_pll_19_2MHz_values; int clock = crtc_state->port_clock; @@ -2579,12 +2602,12 @@ static int icl_calc_dp_combo_pll(struct intel_crtc_state *crtc_state, static int icl_calc_tbt_pll(struct intel_crtc_state *crtc_state, struct skl_wrpll_params *pll_params) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); - if (DISPLAY_VER(dev_priv) >= 12) { - switch (dev_priv->display.dpll.ref_clks.nssc) { + if (DISPLAY_VER(i915) >= 12) { + switch (i915->display.dpll.ref_clks.nssc) { default: - MISSING_CASE(dev_priv->display.dpll.ref_clks.nssc); + MISSING_CASE(i915->display.dpll.ref_clks.nssc); fallthrough; case 19200: case 38400: @@ -2595,9 +2618,9 @@ static int icl_calc_tbt_pll(struct intel_crtc_state *crtc_state, break; } } else { - switch (dev_priv->display.dpll.ref_clks.nssc) { + switch (i915->display.dpll.ref_clks.nssc) { default: - MISSING_CASE(dev_priv->display.dpll.ref_clks.nssc); + MISSING_CASE(i915->display.dpll.ref_clks.nssc); fallthrough; case 19200: case 38400: @@ -2853,8 +2876,8 @@ static int icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc, static int icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state, struct intel_dpll_hw_state *pll_state) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - int refclk_khz = dev_priv->display.dpll.ref_clks.nssc; + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + int refclk_khz = i915->display.dpll.ref_clks.nssc; int clock = crtc_state->port_clock; u32 dco_khz, m1div, m2div_int, m2div_rem, m2div_frac; u32 iref_ndiv, iref_trim, iref_pulse_w; @@ -2864,7 +2887,7 @@ static int icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state, u64 tmp; bool use_ssc = false; bool is_dp = !intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI); - bool is_dkl = DISPLAY_VER(dev_priv) >= 12; + bool is_dkl = DISPLAY_VER(i915) >= 12; int ret; ret = icl_mg_pll_find_divisors(clock, is_dp, use_ssc, &dco_khz, @@ -2962,8 +2985,8 @@ static int icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state, DKL_PLL_DIV0_PROP_COEFF(prop_coeff) | DKL_PLL_DIV0_FBPREDIV(m1div) | DKL_PLL_DIV0_FBDIV_INT(m2div_int); - if (dev_priv->display.vbt.override_afc_startup) { - u8 val = dev_priv->display.vbt.override_afc_startup_val; + if (i915->display.vbt.override_afc_startup) { + u8 val = i915->display.vbt.override_afc_startup_val; pll_state->mg_pll_div0 |= DKL_PLL_DIV0_AFC_STARTUP(val); } @@ -3053,16 +3076,16 @@ static int icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state, return 0; } -static int icl_ddi_mg_pll_get_freq(struct drm_i915_private *dev_priv, +static int icl_ddi_mg_pll_get_freq(struct drm_i915_private *i915, const struct intel_shared_dpll *pll, const struct intel_dpll_hw_state *pll_state) { u32 m1, m2_int, m2_frac, div1, div2, ref_clock; u64 tmp; - ref_clock = dev_priv->display.dpll.ref_clks.nssc; + ref_clock = i915->display.dpll.ref_clks.nssc; - if (DISPLAY_VER(dev_priv) >= 12) { + if (DISPLAY_VER(i915) >= 12) { m1 = pll_state->mg_pll_div0 & DKL_PLL_DIV0_FBPREDIV_MASK; m1 = m1 >> DKL_PLL_DIV0_FBPREDIV_SHIFT; m2_int = pll_state->mg_pll_div0 & DKL_PLL_DIV0_FBDIV_INT_MASK; @@ -3167,7 +3190,7 @@ static void icl_update_active_dpll(struct intel_atomic_state *state, static int icl_compute_combo_phy_dpll(struct intel_atomic_state *state, struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct icl_port_dpll *port_dpll = @@ -3184,12 +3207,12 @@ static int icl_compute_combo_phy_dpll(struct intel_atomic_state *state, if (ret) return ret; - icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state); + icl_calc_dpll_state(i915, &pll_params, &port_dpll->hw_state); /* this is mainly for the fastset check */ icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_DEFAULT); - crtc_state->port_clock = icl_ddi_combo_pll_get_freq(dev_priv, NULL, + crtc_state->port_clock = icl_ddi_combo_pll_get_freq(i915, NULL, &port_dpll->hw_state); return 0; @@ -3199,7 +3222,7 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct icl_port_dpll *port_dpll = @@ -3207,13 +3230,13 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state, enum port port = encoder->port; unsigned long dpll_mask; - if (IS_ALDERLAKE_S(dev_priv)) { + if (IS_ALDERLAKE_S(i915)) { dpll_mask = BIT(DPLL_ID_DG1_DPLL3) | BIT(DPLL_ID_DG1_DPLL2) | BIT(DPLL_ID_ICL_DPLL1) | BIT(DPLL_ID_ICL_DPLL0); - } else if (IS_DG1(dev_priv)) { + } else if (IS_DG1(i915)) { if (port == PORT_D || port == PORT_E) { dpll_mask = BIT(DPLL_ID_DG1_DPLL2) | @@ -3223,13 +3246,13 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state, BIT(DPLL_ID_DG1_DPLL0) | BIT(DPLL_ID_DG1_DPLL1); } - } else if (IS_ROCKETLAKE(dev_priv)) { + } else if (IS_ROCKETLAKE(i915)) { dpll_mask = BIT(DPLL_ID_EHL_DPLL4) | BIT(DPLL_ID_ICL_DPLL1) | BIT(DPLL_ID_ICL_DPLL0); - } else if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && - port != PORT_A) { + } else if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && + port != PORT_A) { dpll_mask = BIT(DPLL_ID_EHL_DPLL4) | BIT(DPLL_ID_ICL_DPLL1) | @@ -3239,7 +3262,7 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state, } /* Eliminate DPLLs from consideration if reserved by HTI */ - dpll_mask &= ~intel_hti_dpll_mask(dev_priv); + dpll_mask &= ~intel_hti_dpll_mask(i915); port_dpll->pll = intel_find_shared_dpll(state, crtc, &port_dpll->hw_state, @@ -3258,7 +3281,7 @@ static int icl_get_combo_phy_dpll(struct intel_atomic_state *state, static int icl_compute_tc_phy_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct icl_port_dpll *port_dpll = @@ -3271,7 +3294,7 @@ static int icl_compute_tc_phy_dplls(struct intel_atomic_state *state, if (ret) return ret; - icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state); + icl_calc_dpll_state(i915, &pll_params, &port_dpll->hw_state); port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY]; ret = icl_calc_mg_pll_state(crtc_state, &port_dpll->hw_state); @@ -3281,7 +3304,7 @@ static int icl_compute_tc_phy_dplls(struct intel_atomic_state *state, /* this is mainly for the fastset check */ icl_set_active_port_dpll(crtc_state, ICL_PORT_DPLL_MG_PHY); - crtc_state->port_clock = icl_ddi_mg_pll_get_freq(dev_priv, NULL, + crtc_state->port_clock = icl_ddi_mg_pll_get_freq(i915, NULL, &port_dpll->hw_state); return 0; @@ -3291,7 +3314,7 @@ static int icl_get_tc_phy_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct icl_port_dpll *port_dpll = @@ -3310,7 +3333,7 @@ static int icl_get_tc_phy_dplls(struct intel_atomic_state *state, port_dpll = &crtc_state->icl_port_dplls[ICL_PORT_DPLL_MG_PHY]; - dpll_id = icl_tc_port_to_pll_id(intel_port_to_tc(dev_priv, + dpll_id = icl_tc_port_to_pll_id(intel_port_to_tc(i915, encoder->port)); port_dpll->pll = intel_find_shared_dpll(state, crtc, &port_dpll->hw_state, @@ -3337,12 +3360,12 @@ static int icl_compute_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + struct drm_i915_private *i915 = to_i915(state->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); - if (intel_phy_is_combo(dev_priv, phy)) + if (intel_phy_is_combo(i915, phy)) return icl_compute_combo_phy_dpll(state, crtc); - else if (intel_phy_is_tc(dev_priv, phy)) + else if (intel_phy_is_tc(i915, phy)) return icl_compute_tc_phy_dplls(state, crtc); MISSING_CASE(phy); @@ -3354,12 +3377,12 @@ static int icl_get_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + struct drm_i915_private *i915 = to_i915(state->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); - if (intel_phy_is_combo(dev_priv, phy)) + if (intel_phy_is_combo(i915, phy)) return icl_get_combo_phy_dpll(state, crtc, encoder); - else if (intel_phy_is_tc(dev_priv, phy)) + else if (intel_phy_is_tc(i915, phy)) return icl_get_tc_phy_dplls(state, crtc, encoder); MISSING_CASE(phy); @@ -3393,7 +3416,7 @@ static void icl_put_dplls(struct intel_atomic_state *state, } } -static bool mg_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool mg_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -3403,46 +3426,46 @@ static bool mg_pll_get_hw_state(struct drm_i915_private *dev_priv, bool ret = false; u32 val; - i915_reg_t enable_reg = intel_tc_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_tc_pll_enable_reg(i915, pll); - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, enable_reg); + val = intel_de_read(i915, enable_reg); if (!(val & PLL_ENABLE)) goto out; - hw_state->mg_refclkin_ctl = intel_de_read(dev_priv, + hw_state->mg_refclkin_ctl = intel_de_read(i915, MG_REFCLKIN_CTL(tc_port)); hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK; hw_state->mg_clktop2_coreclkctl1 = - intel_de_read(dev_priv, MG_CLKTOP2_CORECLKCTL1(tc_port)); + intel_de_read(i915, MG_CLKTOP2_CORECLKCTL1(tc_port)); hw_state->mg_clktop2_coreclkctl1 &= MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; hw_state->mg_clktop2_hsclkctl = - intel_de_read(dev_priv, MG_CLKTOP2_HSCLKCTL(tc_port)); + intel_de_read(i915, MG_CLKTOP2_HSCLKCTL(tc_port)); hw_state->mg_clktop2_hsclkctl &= MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK; - hw_state->mg_pll_div0 = intel_de_read(dev_priv, MG_PLL_DIV0(tc_port)); - hw_state->mg_pll_div1 = intel_de_read(dev_priv, MG_PLL_DIV1(tc_port)); - hw_state->mg_pll_lf = intel_de_read(dev_priv, MG_PLL_LF(tc_port)); - hw_state->mg_pll_frac_lock = intel_de_read(dev_priv, + hw_state->mg_pll_div0 = intel_de_read(i915, MG_PLL_DIV0(tc_port)); + hw_state->mg_pll_div1 = intel_de_read(i915, MG_PLL_DIV1(tc_port)); + hw_state->mg_pll_lf = intel_de_read(i915, MG_PLL_LF(tc_port)); + hw_state->mg_pll_frac_lock = intel_de_read(i915, MG_PLL_FRAC_LOCK(tc_port)); - hw_state->mg_pll_ssc = intel_de_read(dev_priv, MG_PLL_SSC(tc_port)); + hw_state->mg_pll_ssc = intel_de_read(i915, MG_PLL_SSC(tc_port)); - hw_state->mg_pll_bias = intel_de_read(dev_priv, MG_PLL_BIAS(tc_port)); + hw_state->mg_pll_bias = intel_de_read(i915, MG_PLL_BIAS(tc_port)); hw_state->mg_pll_tdc_coldst_bias = - intel_de_read(dev_priv, MG_PLL_TDC_COLDST_BIAS(tc_port)); + intel_de_read(i915, MG_PLL_TDC_COLDST_BIAS(tc_port)); - if (dev_priv->display.dpll.ref_clks.nssc == 38400) { + if (i915->display.dpll.ref_clks.nssc == 38400) { hw_state->mg_pll_tdc_coldst_bias_mask = MG_PLL_TDC_COLDST_COLDSTART; hw_state->mg_pll_bias_mask = 0; } else { @@ -3455,11 +3478,11 @@ static bool mg_pll_get_hw_state(struct drm_i915_private *dev_priv, ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } -static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool dkl_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { @@ -3469,12 +3492,12 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, bool ret = false; u32 val; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, intel_tc_pll_enable_reg(dev_priv, pll)); + val = intel_de_read(i915, intel_tc_pll_enable_reg(i915, pll)); if (!(val & PLL_ENABLE)) goto out; @@ -3482,12 +3505,12 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, * All registers read here have the same HIP_INDEX_REG even though * they are on different building blocks */ - hw_state->mg_refclkin_ctl = intel_dkl_phy_read(dev_priv, + hw_state->mg_refclkin_ctl = intel_dkl_phy_read(i915, DKL_REFCLKIN_CTL(tc_port)); hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK; hw_state->mg_clktop2_hsclkctl = - intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port)); + intel_dkl_phy_read(i915, DKL_CLKTOP2_HSCLKCTL(tc_port)); hw_state->mg_clktop2_hsclkctl &= MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | @@ -3495,42 +3518,42 @@ static bool dkl_pll_get_hw_state(struct drm_i915_private *dev_priv, MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK; hw_state->mg_clktop2_coreclkctl1 = - intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port)); + intel_dkl_phy_read(i915, DKL_CLKTOP2_CORECLKCTL1(tc_port)); hw_state->mg_clktop2_coreclkctl1 &= MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; - hw_state->mg_pll_div0 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV0(tc_port)); + hw_state->mg_pll_div0 = intel_dkl_phy_read(i915, DKL_PLL_DIV0(tc_port)); val = DKL_PLL_DIV0_MASK; - if (dev_priv->display.vbt.override_afc_startup) + if (i915->display.vbt.override_afc_startup) val |= DKL_PLL_DIV0_AFC_STARTUP_MASK; hw_state->mg_pll_div0 &= val; - hw_state->mg_pll_div1 = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port)); + hw_state->mg_pll_div1 = intel_dkl_phy_read(i915, DKL_PLL_DIV1(tc_port)); hw_state->mg_pll_div1 &= (DKL_PLL_DIV1_IREF_TRIM_MASK | DKL_PLL_DIV1_TDC_TARGET_CNT_MASK); - hw_state->mg_pll_ssc = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port)); + hw_state->mg_pll_ssc = intel_dkl_phy_read(i915, DKL_PLL_SSC(tc_port)); hw_state->mg_pll_ssc &= (DKL_PLL_SSC_IREF_NDIV_RATIO_MASK | DKL_PLL_SSC_STEP_LEN_MASK | DKL_PLL_SSC_STEP_NUM_MASK | DKL_PLL_SSC_EN); - hw_state->mg_pll_bias = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port)); + hw_state->mg_pll_bias = intel_dkl_phy_read(i915, DKL_PLL_BIAS(tc_port)); hw_state->mg_pll_bias &= (DKL_PLL_BIAS_FRAC_EN_H | DKL_PLL_BIAS_FBDIV_FRAC_MASK); hw_state->mg_pll_tdc_coldst_bias = - intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); + intel_dkl_phy_read(i915, DKL_PLL_TDC_COLDST_BIAS(tc_port)); hw_state->mg_pll_tdc_coldst_bias &= (DKL_PLL_TDC_SSC_STEP_SIZE_MASK | DKL_PLL_TDC_FEED_FWD_GAIN_MASK); ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } -static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool icl_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state, i915_reg_t enable_reg) @@ -3540,94 +3563,94 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv, bool ret = false; u32 val; - wakeref = intel_display_power_get_if_enabled(dev_priv, + wakeref = intel_display_power_get_if_enabled(i915, POWER_DOMAIN_DISPLAY_CORE); if (!wakeref) return false; - val = intel_de_read(dev_priv, enable_reg); + val = intel_de_read(i915, enable_reg); if (!(val & PLL_ENABLE)) goto out; - if (IS_ALDERLAKE_S(dev_priv)) { - hw_state->cfgcr0 = intel_de_read(dev_priv, ADLS_DPLL_CFGCR0(id)); - hw_state->cfgcr1 = intel_de_read(dev_priv, ADLS_DPLL_CFGCR1(id)); - } else if (IS_DG1(dev_priv)) { - hw_state->cfgcr0 = intel_de_read(dev_priv, DG1_DPLL_CFGCR0(id)); - hw_state->cfgcr1 = intel_de_read(dev_priv, DG1_DPLL_CFGCR1(id)); - } else if (IS_ROCKETLAKE(dev_priv)) { - hw_state->cfgcr0 = intel_de_read(dev_priv, + if (IS_ALDERLAKE_S(i915)) { + hw_state->cfgcr0 = intel_de_read(i915, ADLS_DPLL_CFGCR0(id)); + hw_state->cfgcr1 = intel_de_read(i915, ADLS_DPLL_CFGCR1(id)); + } else if (IS_DG1(i915)) { + hw_state->cfgcr0 = intel_de_read(i915, DG1_DPLL_CFGCR0(id)); + hw_state->cfgcr1 = intel_de_read(i915, DG1_DPLL_CFGCR1(id)); + } else if (IS_ROCKETLAKE(i915)) { + hw_state->cfgcr0 = intel_de_read(i915, RKL_DPLL_CFGCR0(id)); - hw_state->cfgcr1 = intel_de_read(dev_priv, + hw_state->cfgcr1 = intel_de_read(i915, RKL_DPLL_CFGCR1(id)); - } else if (DISPLAY_VER(dev_priv) >= 12) { - hw_state->cfgcr0 = intel_de_read(dev_priv, + } else if (DISPLAY_VER(i915) >= 12) { + hw_state->cfgcr0 = intel_de_read(i915, TGL_DPLL_CFGCR0(id)); - hw_state->cfgcr1 = intel_de_read(dev_priv, + hw_state->cfgcr1 = intel_de_read(i915, TGL_DPLL_CFGCR1(id)); - if (dev_priv->display.vbt.override_afc_startup) { - hw_state->div0 = intel_de_read(dev_priv, TGL_DPLL0_DIV0(id)); + if (i915->display.vbt.override_afc_startup) { + hw_state->div0 = intel_de_read(i915, TGL_DPLL0_DIV0(id)); hw_state->div0 &= TGL_DPLL0_DIV0_AFC_STARTUP_MASK; } } else { - if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && + if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && id == DPLL_ID_EHL_DPLL4) { - hw_state->cfgcr0 = intel_de_read(dev_priv, + hw_state->cfgcr0 = intel_de_read(i915, ICL_DPLL_CFGCR0(4)); - hw_state->cfgcr1 = intel_de_read(dev_priv, + hw_state->cfgcr1 = intel_de_read(i915, ICL_DPLL_CFGCR1(4)); } else { - hw_state->cfgcr0 = intel_de_read(dev_priv, + hw_state->cfgcr0 = intel_de_read(i915, ICL_DPLL_CFGCR0(id)); - hw_state->cfgcr1 = intel_de_read(dev_priv, + hw_state->cfgcr1 = intel_de_read(i915, ICL_DPLL_CFGCR1(id)); } } ret = true; out: - intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); + intel_display_power_put(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref); return ret; } -static bool combo_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool combo_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { - i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); - return icl_pll_get_hw_state(dev_priv, pll, hw_state, enable_reg); + return icl_pll_get_hw_state(i915, pll, hw_state, enable_reg); } -static bool tbt_pll_get_hw_state(struct drm_i915_private *dev_priv, +static bool tbt_pll_get_hw_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_dpll_hw_state *hw_state) { - return icl_pll_get_hw_state(dev_priv, pll, hw_state, TBT_PLL_ENABLE); + return icl_pll_get_hw_state(i915, pll, hw_state, TBT_PLL_ENABLE); } -static void icl_dpll_write(struct drm_i915_private *dev_priv, +static void icl_dpll_write(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { struct intel_dpll_hw_state *hw_state = &pll->state.hw_state; const enum intel_dpll_id id = pll->info->id; i915_reg_t cfgcr0_reg, cfgcr1_reg, div0_reg = INVALID_MMIO_REG; - if (IS_ALDERLAKE_S(dev_priv)) { + if (IS_ALDERLAKE_S(i915)) { cfgcr0_reg = ADLS_DPLL_CFGCR0(id); cfgcr1_reg = ADLS_DPLL_CFGCR1(id); - } else if (IS_DG1(dev_priv)) { + } else if (IS_DG1(i915)) { cfgcr0_reg = DG1_DPLL_CFGCR0(id); cfgcr1_reg = DG1_DPLL_CFGCR1(id); - } else if (IS_ROCKETLAKE(dev_priv)) { + } else if (IS_ROCKETLAKE(i915)) { cfgcr0_reg = RKL_DPLL_CFGCR0(id); cfgcr1_reg = RKL_DPLL_CFGCR1(id); - } else if (DISPLAY_VER(dev_priv) >= 12) { + } else if (DISPLAY_VER(i915) >= 12) { cfgcr0_reg = TGL_DPLL_CFGCR0(id); cfgcr1_reg = TGL_DPLL_CFGCR1(id); div0_reg = TGL_DPLL0_DIV0(id); } else { - if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && + if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && id == DPLL_ID_EHL_DPLL4) { cfgcr0_reg = ICL_DPLL_CFGCR0(4); cfgcr1_reg = ICL_DPLL_CFGCR1(4); @@ -3637,18 +3660,18 @@ static void icl_dpll_write(struct drm_i915_private *dev_priv, } } - intel_de_write(dev_priv, cfgcr0_reg, hw_state->cfgcr0); - intel_de_write(dev_priv, cfgcr1_reg, hw_state->cfgcr1); - drm_WARN_ON_ONCE(&dev_priv->drm, dev_priv->display.vbt.override_afc_startup && + intel_de_write(i915, cfgcr0_reg, hw_state->cfgcr0); + intel_de_write(i915, cfgcr1_reg, hw_state->cfgcr1); + drm_WARN_ON_ONCE(&i915->drm, i915->display.vbt.override_afc_startup && !i915_mmio_reg_valid(div0_reg)); - if (dev_priv->display.vbt.override_afc_startup && + if (i915->display.vbt.override_afc_startup && i915_mmio_reg_valid(div0_reg)) - intel_de_rmw(dev_priv, div0_reg, + intel_de_rmw(i915, div0_reg, TGL_DPLL0_DIV0_AFC_STARTUP_MASK, hw_state->div0); - intel_de_posting_read(dev_priv, cfgcr1_reg); + intel_de_posting_read(i915, cfgcr1_reg); } -static void icl_mg_pll_write(struct drm_i915_private *dev_priv, +static void icl_mg_pll_write(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { struct intel_dpll_hw_state *hw_state = &pll->state.hw_state; @@ -3660,38 +3683,38 @@ static void icl_mg_pll_write(struct drm_i915_private *dev_priv, * during the calc/readout phase if the mask depends on some other HW * state like refclk, see icl_calc_mg_pll_state(). */ - intel_de_rmw(dev_priv, MG_REFCLKIN_CTL(tc_port), + intel_de_rmw(i915, MG_REFCLKIN_CTL(tc_port), MG_REFCLKIN_CTL_OD_2_MUX_MASK, hw_state->mg_refclkin_ctl); - intel_de_rmw(dev_priv, MG_CLKTOP2_CORECLKCTL1(tc_port), + intel_de_rmw(i915, MG_CLKTOP2_CORECLKCTL1(tc_port), MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK, hw_state->mg_clktop2_coreclkctl1); - intel_de_rmw(dev_priv, MG_CLKTOP2_HSCLKCTL(tc_port), + intel_de_rmw(i915, MG_CLKTOP2_HSCLKCTL(tc_port), MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK, hw_state->mg_clktop2_hsclkctl); - intel_de_write(dev_priv, MG_PLL_DIV0(tc_port), hw_state->mg_pll_div0); - intel_de_write(dev_priv, MG_PLL_DIV1(tc_port), hw_state->mg_pll_div1); - intel_de_write(dev_priv, MG_PLL_LF(tc_port), hw_state->mg_pll_lf); - intel_de_write(dev_priv, MG_PLL_FRAC_LOCK(tc_port), + intel_de_write(i915, MG_PLL_DIV0(tc_port), hw_state->mg_pll_div0); + intel_de_write(i915, MG_PLL_DIV1(tc_port), hw_state->mg_pll_div1); + intel_de_write(i915, MG_PLL_LF(tc_port), hw_state->mg_pll_lf); + intel_de_write(i915, MG_PLL_FRAC_LOCK(tc_port), hw_state->mg_pll_frac_lock); - intel_de_write(dev_priv, MG_PLL_SSC(tc_port), hw_state->mg_pll_ssc); + intel_de_write(i915, MG_PLL_SSC(tc_port), hw_state->mg_pll_ssc); - intel_de_rmw(dev_priv, MG_PLL_BIAS(tc_port), + intel_de_rmw(i915, MG_PLL_BIAS(tc_port), hw_state->mg_pll_bias_mask, hw_state->mg_pll_bias); - intel_de_rmw(dev_priv, MG_PLL_TDC_COLDST_BIAS(tc_port), + intel_de_rmw(i915, MG_PLL_TDC_COLDST_BIAS(tc_port), hw_state->mg_pll_tdc_coldst_bias_mask, hw_state->mg_pll_tdc_coldst_bias); - intel_de_posting_read(dev_priv, MG_PLL_TDC_COLDST_BIAS(tc_port)); + intel_de_posting_read(i915, MG_PLL_TDC_COLDST_BIAS(tc_port)); } -static void dkl_pll_write(struct drm_i915_private *dev_priv, +static void dkl_pll_write(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { struct intel_dpll_hw_state *hw_state = &pll->state.hw_state; @@ -3703,83 +3726,83 @@ static void dkl_pll_write(struct drm_i915_private *dev_priv, * though on different building block */ /* All the registers are RMW */ - val = intel_dkl_phy_read(dev_priv, DKL_REFCLKIN_CTL(tc_port)); + val = intel_dkl_phy_read(i915, DKL_REFCLKIN_CTL(tc_port)); val &= ~MG_REFCLKIN_CTL_OD_2_MUX_MASK; val |= hw_state->mg_refclkin_ctl; - intel_dkl_phy_write(dev_priv, DKL_REFCLKIN_CTL(tc_port), val); + intel_dkl_phy_write(i915, DKL_REFCLKIN_CTL(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port)); + val = intel_dkl_phy_read(i915, DKL_CLKTOP2_CORECLKCTL1(tc_port)); val &= ~MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; val |= hw_state->mg_clktop2_coreclkctl1; - intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_CORECLKCTL1(tc_port), val); + intel_dkl_phy_write(i915, DKL_CLKTOP2_CORECLKCTL1(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port)); + val = intel_dkl_phy_read(i915, DKL_CLKTOP2_HSCLKCTL(tc_port)); val &= ~(MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK); val |= hw_state->mg_clktop2_hsclkctl; - intel_dkl_phy_write(dev_priv, DKL_CLKTOP2_HSCLKCTL(tc_port), val); + intel_dkl_phy_write(i915, DKL_CLKTOP2_HSCLKCTL(tc_port), val); val = DKL_PLL_DIV0_MASK; - if (dev_priv->display.vbt.override_afc_startup) + if (i915->display.vbt.override_afc_startup) val |= DKL_PLL_DIV0_AFC_STARTUP_MASK; - intel_dkl_phy_rmw(dev_priv, DKL_PLL_DIV0(tc_port), val, + intel_dkl_phy_rmw(i915, DKL_PLL_DIV0(tc_port), val, hw_state->mg_pll_div0); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_DIV1(tc_port)); + val = intel_dkl_phy_read(i915, DKL_PLL_DIV1(tc_port)); val &= ~(DKL_PLL_DIV1_IREF_TRIM_MASK | DKL_PLL_DIV1_TDC_TARGET_CNT_MASK); val |= hw_state->mg_pll_div1; - intel_dkl_phy_write(dev_priv, DKL_PLL_DIV1(tc_port), val); + intel_dkl_phy_write(i915, DKL_PLL_DIV1(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_SSC(tc_port)); + val = intel_dkl_phy_read(i915, DKL_PLL_SSC(tc_port)); val &= ~(DKL_PLL_SSC_IREF_NDIV_RATIO_MASK | DKL_PLL_SSC_STEP_LEN_MASK | DKL_PLL_SSC_STEP_NUM_MASK | DKL_PLL_SSC_EN); val |= hw_state->mg_pll_ssc; - intel_dkl_phy_write(dev_priv, DKL_PLL_SSC(tc_port), val); + intel_dkl_phy_write(i915, DKL_PLL_SSC(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_BIAS(tc_port)); + val = intel_dkl_phy_read(i915, DKL_PLL_BIAS(tc_port)); val &= ~(DKL_PLL_BIAS_FRAC_EN_H | DKL_PLL_BIAS_FBDIV_FRAC_MASK); val |= hw_state->mg_pll_bias; - intel_dkl_phy_write(dev_priv, DKL_PLL_BIAS(tc_port), val); + intel_dkl_phy_write(i915, DKL_PLL_BIAS(tc_port), val); - val = intel_dkl_phy_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); + val = intel_dkl_phy_read(i915, DKL_PLL_TDC_COLDST_BIAS(tc_port)); val &= ~(DKL_PLL_TDC_SSC_STEP_SIZE_MASK | DKL_PLL_TDC_FEED_FWD_GAIN_MASK); val |= hw_state->mg_pll_tdc_coldst_bias; - intel_dkl_phy_write(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port), val); + intel_dkl_phy_write(i915, DKL_PLL_TDC_COLDST_BIAS(tc_port), val); - intel_dkl_phy_posting_read(dev_priv, DKL_PLL_TDC_COLDST_BIAS(tc_port)); + intel_dkl_phy_posting_read(i915, DKL_PLL_TDC_COLDST_BIAS(tc_port)); } -static void icl_pll_power_enable(struct drm_i915_private *dev_priv, +static void icl_pll_power_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll, i915_reg_t enable_reg) { - intel_de_rmw(dev_priv, enable_reg, 0, PLL_POWER_ENABLE); + intel_de_rmw(i915, enable_reg, 0, PLL_POWER_ENABLE); /* * The spec says we need to "wait" but it also says it should be * immediate. */ - if (intel_de_wait_for_set(dev_priv, enable_reg, PLL_POWER_STATE, 1)) - drm_err(&dev_priv->drm, "PLL %d Power not enabled\n", + if (intel_de_wait_for_set(i915, enable_reg, PLL_POWER_STATE, 1)) + drm_err(&i915->drm, "PLL %d Power not enabled\n", pll->info->id); } -static void icl_pll_enable(struct drm_i915_private *dev_priv, +static void icl_pll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll, i915_reg_t enable_reg) { - intel_de_rmw(dev_priv, enable_reg, 0, PLL_ENABLE); + intel_de_rmw(i915, enable_reg, 0, PLL_ENABLE); /* Timeout is actually 600us. */ - if (intel_de_wait_for_set(dev_priv, enable_reg, PLL_LOCK, 1)) - drm_err(&dev_priv->drm, "PLL %d not locked\n", pll->info->id); + if (intel_de_wait_for_set(i915, enable_reg, PLL_LOCK, 1)) + drm_err(&i915->drm, "PLL %d not locked\n", pll->info->id); } static void adlp_cmtg_clock_gating_wa(struct drm_i915_private *i915, struct intel_shared_dpll *pll) @@ -3806,12 +3829,12 @@ static void adlp_cmtg_clock_gating_wa(struct drm_i915_private *i915, struct inte drm_dbg_kms(&i915->drm, "Unexpected flags in TRANS_CMTG_CHICKEN: %08x\n", val); } -static void combo_pll_enable(struct drm_i915_private *dev_priv, +static void combo_pll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); - if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && + if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && pll->info->id == DPLL_ID_EHL_DPLL4) { /* @@ -3819,13 +3842,13 @@ static void combo_pll_enable(struct drm_i915_private *dev_priv, * This can be done by taking a reference on DPLL4 power * domain. */ - pll->wakeref = intel_display_power_get(dev_priv, + pll->wakeref = intel_display_power_get(i915, POWER_DOMAIN_DC_OFF); } - icl_pll_power_enable(dev_priv, pll, enable_reg); + icl_pll_power_enable(i915, pll, enable_reg); - icl_dpll_write(dev_priv, pll); + icl_dpll_write(i915, pll); /* * DVFS pre sequence would be here, but in our driver the cdclk code @@ -3833,19 +3856,19 @@ static void combo_pll_enable(struct drm_i915_private *dev_priv, * nothing here. */ - icl_pll_enable(dev_priv, pll, enable_reg); + icl_pll_enable(i915, pll, enable_reg); - adlp_cmtg_clock_gating_wa(dev_priv, pll); + adlp_cmtg_clock_gating_wa(i915, pll); /* DVFS post sequence would be here. See the comment above. */ } -static void tbt_pll_enable(struct drm_i915_private *dev_priv, +static void tbt_pll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - icl_pll_power_enable(dev_priv, pll, TBT_PLL_ENABLE); + icl_pll_power_enable(i915, pll, TBT_PLL_ENABLE); - icl_dpll_write(dev_priv, pll); + icl_dpll_write(i915, pll); /* * DVFS pre sequence would be here, but in our driver the cdclk code @@ -3853,22 +3876,22 @@ static void tbt_pll_enable(struct drm_i915_private *dev_priv, * nothing here. */ - icl_pll_enable(dev_priv, pll, TBT_PLL_ENABLE); + icl_pll_enable(i915, pll, TBT_PLL_ENABLE); /* DVFS post sequence would be here. See the comment above. */ } -static void mg_pll_enable(struct drm_i915_private *dev_priv, +static void mg_pll_enable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - i915_reg_t enable_reg = intel_tc_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_tc_pll_enable_reg(i915, pll); - icl_pll_power_enable(dev_priv, pll, enable_reg); + icl_pll_power_enable(i915, pll, enable_reg); - if (DISPLAY_VER(dev_priv) >= 12) - dkl_pll_write(dev_priv, pll); + if (DISPLAY_VER(i915) >= 12) + dkl_pll_write(i915, pll); else - icl_mg_pll_write(dev_priv, pll); + icl_mg_pll_write(i915, pll); /* * DVFS pre sequence would be here, but in our driver the cdclk code @@ -3876,12 +3899,12 @@ static void mg_pll_enable(struct drm_i915_private *dev_priv, * nothing here. */ - icl_pll_enable(dev_priv, pll, enable_reg); + icl_pll_enable(i915, pll, enable_reg); /* DVFS post sequence would be here. See the comment above. */ } -static void icl_pll_disable(struct drm_i915_private *dev_priv, +static void icl_pll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll, i915_reg_t enable_reg) { @@ -3893,50 +3916,50 @@ static void icl_pll_disable(struct drm_i915_private *dev_priv, * nothing here. */ - intel_de_rmw(dev_priv, enable_reg, PLL_ENABLE, 0); + intel_de_rmw(i915, enable_reg, PLL_ENABLE, 0); /* Timeout is actually 1us. */ - if (intel_de_wait_for_clear(dev_priv, enable_reg, PLL_LOCK, 1)) - drm_err(&dev_priv->drm, "PLL %d locked\n", pll->info->id); + if (intel_de_wait_for_clear(i915, enable_reg, PLL_LOCK, 1)) + drm_err(&i915->drm, "PLL %d locked\n", pll->info->id); /* DVFS post sequence would be here. See the comment above. */ - intel_de_rmw(dev_priv, enable_reg, PLL_POWER_ENABLE, 0); + intel_de_rmw(i915, enable_reg, PLL_POWER_ENABLE, 0); /* * The spec says we need to "wait" but it also says it should be * immediate. */ - if (intel_de_wait_for_clear(dev_priv, enable_reg, PLL_POWER_STATE, 1)) - drm_err(&dev_priv->drm, "PLL %d Power not disabled\n", + if (intel_de_wait_for_clear(i915, enable_reg, PLL_POWER_STATE, 1)) + drm_err(&i915->drm, "PLL %d Power not disabled\n", pll->info->id); } -static void combo_pll_disable(struct drm_i915_private *dev_priv, +static void combo_pll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - i915_reg_t enable_reg = intel_combo_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); - icl_pll_disable(dev_priv, pll, enable_reg); + icl_pll_disable(i915, pll, enable_reg); - if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && + if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && pll->info->id == DPLL_ID_EHL_DPLL4) - intel_display_power_put(dev_priv, POWER_DOMAIN_DC_OFF, + intel_display_power_put(i915, POWER_DOMAIN_DC_OFF, pll->wakeref); } -static void tbt_pll_disable(struct drm_i915_private *dev_priv, +static void tbt_pll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - icl_pll_disable(dev_priv, pll, TBT_PLL_ENABLE); + icl_pll_disable(i915, pll, TBT_PLL_ENABLE); } -static void mg_pll_disable(struct drm_i915_private *dev_priv, +static void mg_pll_disable(struct drm_i915_private *i915, struct intel_shared_dpll *pll) { - i915_reg_t enable_reg = intel_tc_pll_enable_reg(dev_priv, pll); + i915_reg_t enable_reg = intel_tc_pll_enable_reg(i915, pll); - icl_pll_disable(dev_priv, pll, enable_reg); + icl_pll_disable(i915, pll, enable_reg); } static void icl_update_dpll_ref_clks(struct drm_i915_private *i915) @@ -3945,10 +3968,10 @@ static void icl_update_dpll_ref_clks(struct drm_i915_private *i915) i915->display.dpll.ref_clks.nssc = i915->display.cdclk.hw.ref; } -static void icl_dump_hw_state(struct drm_i915_private *dev_priv, +static void icl_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "dpll_hw_state: cfgcr0: 0x%x, cfgcr1: 0x%x, div0: 0x%x, " "mg_refclkin_ctl: 0x%x, hg_clktop2_coreclkctl1: 0x%x, " "mg_clktop2_hsclkctl: 0x%x, mg_pll_div0: 0x%x, " @@ -4130,62 +4153,64 @@ static const struct intel_dpll_mgr adlp_pll_mgr = { /** * intel_shared_dpll_init - Initialize shared DPLLs - * @dev_priv: i915 device + * @i915: i915 device * - * Initialize shared DPLLs for @dev_priv. + * Initialize shared DPLLs for @i915. */ -void intel_shared_dpll_init(struct drm_i915_private *dev_priv) +void intel_shared_dpll_init(struct drm_i915_private *i915) { const struct intel_dpll_mgr *dpll_mgr = NULL; const struct dpll_info *dpll_info; int i; - mutex_init(&dev_priv->display.dpll.lock); + mutex_init(&i915->display.dpll.lock); - if (DISPLAY_VER(dev_priv) >= 14 || IS_DG2(dev_priv)) + if (DISPLAY_VER(i915) >= 14 || IS_DG2(i915)) /* No shared DPLLs on DG2; port PLLs are part of the PHY */ dpll_mgr = NULL; - else if (IS_ALDERLAKE_P(dev_priv)) + else if (IS_ALDERLAKE_P(i915)) dpll_mgr = &adlp_pll_mgr; - else if (IS_ALDERLAKE_S(dev_priv)) + else if (IS_ALDERLAKE_S(i915)) dpll_mgr = &adls_pll_mgr; - else if (IS_DG1(dev_priv)) + else if (IS_DG1(i915)) dpll_mgr = &dg1_pll_mgr; - else if (IS_ROCKETLAKE(dev_priv)) + else if (IS_ROCKETLAKE(i915)) dpll_mgr = &rkl_pll_mgr; - else if (DISPLAY_VER(dev_priv) >= 12) + else if (DISPLAY_VER(i915) >= 12) dpll_mgr = &tgl_pll_mgr; - else if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) + else if (IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) dpll_mgr = &ehl_pll_mgr; - else if (DISPLAY_VER(dev_priv) >= 11) + else if (DISPLAY_VER(i915) >= 11) dpll_mgr = &icl_pll_mgr; - else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) + else if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) dpll_mgr = &bxt_pll_mgr; - else if (DISPLAY_VER(dev_priv) == 9) + else if (DISPLAY_VER(i915) == 9) dpll_mgr = &skl_pll_mgr; - else if (HAS_DDI(dev_priv)) + else if (HAS_DDI(i915)) dpll_mgr = &hsw_pll_mgr; - else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)) + else if (HAS_PCH_IBX(i915) || HAS_PCH_CPT(i915)) dpll_mgr = &pch_pll_mgr; - if (!dpll_mgr) { - dev_priv->display.dpll.num_shared_dpll = 0; + if (!dpll_mgr) return; - } dpll_info = dpll_mgr->dpll_info; for (i = 0; dpll_info[i].name; i++) { - if (drm_WARN_ON(&dev_priv->drm, - i >= ARRAY_SIZE(dev_priv->display.dpll.shared_dplls))) + if (drm_WARN_ON(&i915->drm, + i >= ARRAY_SIZE(i915->display.dpll.shared_dplls))) + break; + + /* must fit into unsigned long bitmask on 32bit */ + if (drm_WARN_ON(&i915->drm, dpll_info[i].id >= 32)) break; - drm_WARN_ON(&dev_priv->drm, i != dpll_info[i].id); - dev_priv->display.dpll.shared_dplls[i].info = &dpll_info[i]; + i915->display.dpll.shared_dplls[i].info = &dpll_info[i]; + i915->display.dpll.shared_dplls[i].index = i; } - dev_priv->display.dpll.mgr = dpll_mgr; - dev_priv->display.dpll.num_shared_dpll = i; + i915->display.dpll.mgr = dpll_mgr; + i915->display.dpll.num_shared_dpll = i; } /** @@ -4206,10 +4231,10 @@ int intel_compute_shared_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr; + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dpll_mgr *dpll_mgr = i915->display.dpll.mgr; - if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr)) + if (drm_WARN_ON(&i915->drm, !dpll_mgr)) return -EINVAL; return dpll_mgr->compute_dplls(state, crtc, encoder); @@ -4239,10 +4264,10 @@ int intel_reserve_shared_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr; + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dpll_mgr *dpll_mgr = i915->display.dpll.mgr; - if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr)) + if (drm_WARN_ON(&i915->drm, !dpll_mgr)) return -EINVAL; return dpll_mgr->get_dplls(state, crtc, encoder); @@ -4262,8 +4287,8 @@ int intel_reserve_shared_dplls(struct intel_atomic_state *state, void intel_release_shared_dplls(struct intel_atomic_state *state, struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr; + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dpll_mgr *dpll_mgr = i915->display.dpll.mgr; /* * FIXME: this function is called for every platform having a @@ -4291,10 +4316,10 @@ void intel_update_active_dpll(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - const struct intel_dpll_mgr *dpll_mgr = dev_priv->display.dpll.mgr; + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + const struct intel_dpll_mgr *dpll_mgr = i915->display.dpll.mgr; - if (drm_WARN_ON(&dev_priv->drm, !dpll_mgr)) + if (drm_WARN_ON(&i915->drm, !dpll_mgr)) return; dpll_mgr->update_active_dpll(state, crtc, encoder); @@ -4370,10 +4395,11 @@ void intel_dpll_update_ref_clks(struct drm_i915_private *i915) void intel_dpll_readout_hw_state(struct drm_i915_private *i915) { + struct intel_shared_dpll *pll; int i; - for (i = 0; i < i915->display.dpll.num_shared_dpll; i++) - readout_dpll_hw_state(i915, &i915->display.dpll.shared_dplls[i]); + for_each_shared_dpll(i915, pll, i) + readout_dpll_hw_state(i915, pll); } static void sanitize_dpll_state(struct drm_i915_private *i915, @@ -4397,29 +4423,30 @@ static void sanitize_dpll_state(struct drm_i915_private *i915, void intel_dpll_sanitize_state(struct drm_i915_private *i915) { + struct intel_shared_dpll *pll; int i; - for (i = 0; i < i915->display.dpll.num_shared_dpll; i++) - sanitize_dpll_state(i915, &i915->display.dpll.shared_dplls[i]); + for_each_shared_dpll(i915, pll, i) + sanitize_dpll_state(i915, pll); } /** * intel_dpll_dump_hw_state - write hw_state to dmesg - * @dev_priv: i915 drm device + * @i915: i915 drm device * @hw_state: hw state to be written to the log * * Write the relevant values in @hw_state to dmesg using drm_dbg_kms. */ -void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv, +void intel_dpll_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state) { - if (dev_priv->display.dpll.mgr) { - dev_priv->display.dpll.mgr->dump_hw_state(dev_priv, hw_state); + if (i915->display.dpll.mgr) { + i915->display.dpll.mgr->dump_hw_state(i915, hw_state); } else { /* fallback for platforms that don't use the shared dpll * infrastructure */ - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, " "fp0: 0x%x, fp1: 0x%x\n", hw_state->dpll, @@ -4430,10 +4457,10 @@ void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv, } static void -verify_single_dpll_state(struct drm_i915_private *dev_priv, +verify_single_dpll_state(struct drm_i915_private *i915, struct intel_shared_dpll *pll, struct intel_crtc *crtc, - struct intel_crtc_state *new_crtc_state) + const struct intel_crtc_state *new_crtc_state) { struct intel_dpll_hw_state dpll_hw_state; u8 pipe_mask; @@ -4441,22 +4468,22 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, memset(&dpll_hw_state, 0, sizeof(dpll_hw_state)); - drm_dbg_kms(&dev_priv->drm, "%s\n", pll->info->name); + drm_dbg_kms(&i915->drm, "%s\n", pll->info->name); - active = intel_dpll_get_hw_state(dev_priv, pll, &dpll_hw_state); + active = intel_dpll_get_hw_state(i915, pll, &dpll_hw_state); if (!(pll->info->flags & INTEL_DPLL_ALWAYS_ON)) { - I915_STATE_WARN(dev_priv, !pll->on && pll->active_mask, + I915_STATE_WARN(i915, !pll->on && pll->active_mask, "pll in active use but not on in sw tracking\n"); - I915_STATE_WARN(dev_priv, pll->on && !pll->active_mask, + I915_STATE_WARN(i915, pll->on && !pll->active_mask, "pll is on but not used by any active pipe\n"); - I915_STATE_WARN(dev_priv, pll->on != active, + I915_STATE_WARN(i915, pll->on != active, "pll on state mismatch (expected %i, found %i)\n", pll->on, active); } if (!crtc) { - I915_STATE_WARN(dev_priv, + I915_STATE_WARN(i915, pll->active_mask & ~pll->state.pipe_mask, "more active pll users than references: 0x%x vs 0x%x\n", pll->active_mask, pll->state.pipe_mask); @@ -4467,32 +4494,35 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, pipe_mask = BIT(crtc->pipe); if (new_crtc_state->hw.active) - I915_STATE_WARN(dev_priv, !(pll->active_mask & pipe_mask), + I915_STATE_WARN(i915, !(pll->active_mask & pipe_mask), "pll active mismatch (expected pipe %c in active mask 0x%x)\n", pipe_name(crtc->pipe), pll->active_mask); else - I915_STATE_WARN(dev_priv, pll->active_mask & pipe_mask, + I915_STATE_WARN(i915, pll->active_mask & pipe_mask, "pll active mismatch (didn't expect pipe %c in active mask 0x%x)\n", pipe_name(crtc->pipe), pll->active_mask); - I915_STATE_WARN(dev_priv, !(pll->state.pipe_mask & pipe_mask), + I915_STATE_WARN(i915, !(pll->state.pipe_mask & pipe_mask), "pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n", pipe_mask, pll->state.pipe_mask); - I915_STATE_WARN(dev_priv, + I915_STATE_WARN(i915, pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state, sizeof(dpll_hw_state)), "pll hw state mismatch\n"); } -void intel_shared_dpll_state_verify(struct intel_crtc *crtc, - struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *new_crtc_state) +void intel_shared_dpll_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); if (new_crtc_state->shared_dpll) - verify_single_dpll_state(dev_priv, new_crtc_state->shared_dpll, + verify_single_dpll_state(i915, new_crtc_state->shared_dpll, crtc, new_crtc_state); if (old_crtc_state->shared_dpll && @@ -4500,20 +4530,21 @@ void intel_shared_dpll_state_verify(struct intel_crtc *crtc, u8 pipe_mask = BIT(crtc->pipe); struct intel_shared_dpll *pll = old_crtc_state->shared_dpll; - I915_STATE_WARN(dev_priv, pll->active_mask & pipe_mask, + I915_STATE_WARN(i915, pll->active_mask & pipe_mask, "pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n", pipe_name(crtc->pipe), pll->active_mask); - I915_STATE_WARN(dev_priv, pll->state.pipe_mask & pipe_mask, + I915_STATE_WARN(i915, pll->state.pipe_mask & pipe_mask, "pll enabled crtcs mismatch (found %x in enabled mask (0x%x))\n", pipe_name(crtc->pipe), pll->state.pipe_mask); } } -void intel_shared_dpll_verify_disabled(struct drm_i915_private *i915) +void intel_shared_dpll_verify_disabled(struct intel_atomic_state *state) { + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_shared_dpll *pll; int i; - for (i = 0; i < i915->display.dpll.num_shared_dpll; i++) - verify_single_dpll_state(i915, &i915->display.dpll.shared_dplls[i], - NULL, NULL); + for_each_shared_dpll(i915, pll, i) + verify_single_dpll_state(i915, pll, NULL, NULL); } diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index 04e6810954..dd4796a617 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -29,6 +29,10 @@ #include "intel_wakeref.h" +#define for_each_shared_dpll(__i915, __pll, __i) \ + for ((__i) = 0; (__i) < (__i915)->display.dpll.num_shared_dpll && \ + ((__pll) = &(__i915)->display.dpll.shared_dplls[(__i)]) ; (__i)++) + enum tc_port; struct drm_i915_private; struct intel_atomic_state; @@ -262,8 +266,7 @@ struct dpll_info { const struct intel_shared_dpll_funcs *funcs; /** - * @id: unique indentifier for this DPLL; should match the index in the - * dev_priv->shared_dplls array + * @id: unique indentifier for this DPLL */ enum intel_dpll_id id; @@ -291,6 +294,11 @@ struct intel_shared_dpll { struct intel_shared_dpll_state state; /** + * @index: index for atomic state + */ + u8 index; + + /** * @active_mask: mask of active pipes (i.e. DPMS on) using this DPLL */ u8 active_mask; @@ -319,9 +327,9 @@ struct intel_shared_dpll { /* shared dpll functions */ struct intel_shared_dpll * -intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv, +intel_get_shared_dpll_by_id(struct drm_i915_private *i915, enum intel_dpll_id id); -void assert_shared_dpll(struct drm_i915_private *dev_priv, +void assert_shared_dpll(struct drm_i915_private *i915, struct intel_shared_dpll *pll, bool state); #define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true) @@ -351,19 +359,18 @@ bool intel_dpll_get_hw_state(struct drm_i915_private *i915, void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state); void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state); void intel_shared_dpll_swap_state(struct intel_atomic_state *state); -void intel_shared_dpll_init(struct drm_i915_private *dev_priv); -void intel_dpll_update_ref_clks(struct drm_i915_private *dev_priv); -void intel_dpll_readout_hw_state(struct drm_i915_private *dev_priv); -void intel_dpll_sanitize_state(struct drm_i915_private *dev_priv); +void intel_shared_dpll_init(struct drm_i915_private *i915); +void intel_dpll_update_ref_clks(struct drm_i915_private *i915); +void intel_dpll_readout_hw_state(struct drm_i915_private *i915); +void intel_dpll_sanitize_state(struct drm_i915_private *i915); -void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv, +void intel_dpll_dump_hw_state(struct drm_i915_private *i915, const struct intel_dpll_hw_state *hw_state); enum intel_dpll_id icl_tc_port_to_pll_id(enum tc_port tc_port); bool intel_dpll_is_combophy(enum intel_dpll_id id); -void intel_shared_dpll_state_verify(struct intel_crtc *crtc, - struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *new_crtc_state); -void intel_shared_dpll_verify_disabled(struct drm_i915_private *i915); +void intel_shared_dpll_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc); +void intel_shared_dpll_verify_disabled(struct intel_atomic_state *state); #endif /* _INTEL_DPLL_MGR_H_ */ diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c index fbfd8f959f..48582b31b7 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.c +++ b/drivers/gpu/drm/i915/display/intel_dpt.c @@ -29,7 +29,7 @@ static inline struct i915_dpt * i915_vm_to_dpt(struct i915_address_space *vm) { BUILD_BUG_ON(offsetof(struct i915_dpt, vm)); - GEM_BUG_ON(!i915_is_dpt(vm)); + drm_WARN_ON(&vm->i915->drm, !i915_is_dpt(vm)); return container_of(vm, struct i915_dpt, vm); } diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c index 0d35b6be5b..6282ec0fc9 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.c +++ b/drivers/gpu/drm/i915/display/intel_drrs.c @@ -9,6 +9,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_drrs.h" +#include "intel_frontbuffer.h" #include "intel_panel.h" /** diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index bed058d2c3..7fd6280c54 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -5,13 +5,19 @@ */ #include "gem/i915_gem_internal.h" +#include "gem/i915_gem_lmem.h" #include "i915_drv.h" +#include "i915_irq.h" #include "i915_reg.h" +#include "intel_crtc.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_dsb.h" #include "intel_dsb_regs.h" +#include "intel_vblank.h" +#include "intel_vrr.h" +#include "skl_watermark.h" struct i915_vma; @@ -47,6 +53,8 @@ struct intel_dsb { * register. */ unsigned int ins_start_offset; + + int dewake_scanline; }; /** @@ -70,17 +78,21 @@ struct intel_dsb { #define DSB_OPCODE_SHIFT 24 #define DSB_OPCODE_NOOP 0x0 #define DSB_OPCODE_MMIO_WRITE 0x1 +#define DSB_BYTE_EN 0xf +#define DSB_BYTE_EN_SHIFT 20 +#define DSB_REG_VALUE_MASK 0xfffff #define DSB_OPCODE_WAIT_USEC 0x2 -#define DSB_OPCODE_WAIT_LINES 0x3 +#define DSB_OPCODE_WAIT_SCANLINE 0x3 #define DSB_OPCODE_WAIT_VBLANKS 0x4 #define DSB_OPCODE_WAIT_DSL_IN 0x5 #define DSB_OPCODE_WAIT_DSL_OUT 0x6 +#define DSB_SCANLINE_UPPER_SHIFT 20 +#define DSB_SCANLINE_LOWER_SHIFT 0 #define DSB_OPCODE_INTERRUPT 0x7 #define DSB_OPCODE_INDEXED_WRITE 0x9 +/* see DSB_REG_VALUE_MASK */ #define DSB_OPCODE_POLL 0xA -#define DSB_BYTE_EN 0xF -#define DSB_BYTE_EN_SHIFT 20 -#define DSB_REG_VALUE_MASK 0xfffff +/* see DSB_REG_VALUE_MASK */ static bool assert_dsb_has_room(struct intel_dsb *dsb) { @@ -93,10 +105,26 @@ static bool assert_dsb_has_room(struct intel_dsb *dsb) crtc->base.base.id, crtc->base.name, dsb->id); } +static void intel_dsb_dump(struct intel_dsb *dsb) +{ + struct intel_crtc *crtc = dsb->crtc; + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + const u32 *buf = dsb->cmd_buf; + int i; + + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] DSB %d commands {\n", + crtc->base.base.id, crtc->base.name, dsb->id); + for (i = 0; i < ALIGN(dsb->free_pos, 64 / 4); i += 4) + drm_dbg_kms(&i915->drm, + " 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", + i * 4, buf[i], buf[i+1], buf[i+2], buf[i+3]); + drm_dbg_kms(&i915->drm, "}\n"); +} + static bool is_dsb_busy(struct drm_i915_private *i915, enum pipe pipe, enum dsb_id id) { - return intel_de_read(i915, DSB_CTRL(pipe, id)) & DSB_STATUS_BUSY; + return intel_de_read_fw(i915, DSB_CTRL(pipe, id)) & DSB_STATUS_BUSY; } static void intel_dsb_emit(struct intel_dsb *dsb, u32 ldw, u32 udw) @@ -121,7 +149,15 @@ static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb, const u32 *buf = dsb->cmd_buf; u32 prev_opcode, prev_reg; - prev_opcode = buf[dsb->ins_start_offset + 1] >> DSB_OPCODE_SHIFT; + /* + * Nothing emitted yet? Must check before looking + * at the actual data since i915_gem_object_create_internal() + * does *not* give you zeroed memory! + */ + if (dsb->free_pos == 0) + return false; + + prev_opcode = buf[dsb->ins_start_offset + 1] & ~DSB_REG_VALUE_MASK; prev_reg = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK; return prev_opcode == opcode && prev_reg == i915_mmio_reg_offset(reg); @@ -129,12 +165,18 @@ static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb, static bool intel_dsb_prev_ins_is_mmio_write(struct intel_dsb *dsb, i915_reg_t reg) { - return intel_dsb_prev_ins_is_write(dsb, DSB_OPCODE_MMIO_WRITE, reg); + /* only full byte-enables can be converted to indexed writes */ + return intel_dsb_prev_ins_is_write(dsb, + DSB_OPCODE_MMIO_WRITE << DSB_OPCODE_SHIFT | + DSB_BYTE_EN << DSB_BYTE_EN_SHIFT, + reg); } static bool intel_dsb_prev_ins_is_indexed_write(struct intel_dsb *dsb, i915_reg_t reg) { - return intel_dsb_prev_ins_is_write(dsb, DSB_OPCODE_INDEXED_WRITE, reg); + return intel_dsb_prev_ins_is_write(dsb, + DSB_OPCODE_INDEXED_WRITE << DSB_OPCODE_SHIFT, + reg); } /** @@ -200,6 +242,53 @@ void intel_dsb_reg_write(struct intel_dsb *dsb, } } +static u32 intel_dsb_mask_to_byte_en(u32 mask) +{ + return (!!(mask & 0xff000000) << 3 | + !!(mask & 0x00ff0000) << 2 | + !!(mask & 0x0000ff00) << 1 | + !!(mask & 0x000000ff) << 0); +} + +/* Note: mask implemented via byte enables! */ +void intel_dsb_reg_write_masked(struct intel_dsb *dsb, + i915_reg_t reg, u32 mask, u32 val) +{ + intel_dsb_emit(dsb, val, + (DSB_OPCODE_MMIO_WRITE << DSB_OPCODE_SHIFT) | + (intel_dsb_mask_to_byte_en(mask) << DSB_BYTE_EN_SHIFT) | + i915_mmio_reg_offset(reg)); +} + +void intel_dsb_noop(struct intel_dsb *dsb, int count) +{ + int i; + + for (i = 0; i < count; i++) + intel_dsb_emit(dsb, 0, + DSB_OPCODE_NOOP << DSB_OPCODE_SHIFT); +} + +void intel_dsb_nonpost_start(struct intel_dsb *dsb) +{ + struct intel_crtc *crtc = dsb->crtc; + enum pipe pipe = crtc->pipe; + + intel_dsb_reg_write_masked(dsb, DSB_CTRL(pipe, dsb->id), + DSB_NON_POSTED, DSB_NON_POSTED); + intel_dsb_noop(dsb, 4); +} + +void intel_dsb_nonpost_end(struct intel_dsb *dsb) +{ + struct intel_crtc *crtc = dsb->crtc; + enum pipe pipe = crtc->pipe; + + intel_dsb_reg_write_masked(dsb, DSB_CTRL(pipe, dsb->id), + DSB_NON_POSTED, 0); + intel_dsb_noop(dsb, 4); +} + static void intel_dsb_align_tail(struct intel_dsb *dsb) { u32 aligned_tail, tail; @@ -216,17 +305,42 @@ static void intel_dsb_align_tail(struct intel_dsb *dsb) void intel_dsb_finish(struct intel_dsb *dsb) { + struct intel_crtc *crtc = dsb->crtc; + + /* + * DSB_FORCE_DEWAKE remains active even after DSB is + * disabled, so make sure to clear it (if set during + * intel_dsb_commit()). + */ + intel_dsb_reg_write_masked(dsb, DSB_PMCTRL_2(crtc->pipe, dsb->id), + DSB_FORCE_DEWAKE, 0); + intel_dsb_align_tail(dsb); + + i915_gem_object_flush_map(dsb->vma->obj); } -/** - * intel_dsb_commit() - Trigger workload execution of DSB. - * @dsb: DSB context - * @wait_for_vblank: wait for vblank before executing - * - * This function is used to do actual write to hardware using DSB. - */ -void intel_dsb_commit(struct intel_dsb *dsb, bool wait_for_vblank) +static int intel_dsb_dewake_scanline(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + unsigned int latency = skl_watermark_max_latency(i915); + int vblank_start; + + if (crtc_state->vrr.enable) { + vblank_start = intel_vrr_vmin_vblank_start(crtc_state); + } else { + vblank_start = adjusted_mode->crtc_vblank_start; + + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + vblank_start = DIV_ROUND_UP(vblank_start, 2); + } + + return max(0, vblank_start - intel_usecs_to_scanlines(adjusted_mode, latency)); +} + +static void _intel_dsb_commit(struct intel_dsb *dsb, u32 ctrl, + int dewake_scanline) { struct intel_crtc *crtc = dsb->crtc; struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -243,13 +357,48 @@ void intel_dsb_commit(struct intel_dsb *dsb, bool wait_for_vblank) return; } - intel_de_write(dev_priv, DSB_CTRL(pipe, dsb->id), - (wait_for_vblank ? DSB_WAIT_FOR_VBLANK : 0) | - DSB_ENABLE); - intel_de_write(dev_priv, DSB_HEAD(pipe, dsb->id), - i915_ggtt_offset(dsb->vma)); - intel_de_write(dev_priv, DSB_TAIL(pipe, dsb->id), - i915_ggtt_offset(dsb->vma) + tail); + intel_de_write_fw(dev_priv, DSB_CTRL(pipe, dsb->id), + ctrl | DSB_ENABLE); + + intel_de_write_fw(dev_priv, DSB_HEAD(pipe, dsb->id), + i915_ggtt_offset(dsb->vma)); + + if (dewake_scanline >= 0) { + int diff, hw_dewake_scanline; + + hw_dewake_scanline = intel_crtc_scanline_to_hw(crtc, dewake_scanline); + + intel_de_write_fw(dev_priv, DSB_PMCTRL(pipe, dsb->id), + DSB_ENABLE_DEWAKE | + DSB_SCANLINE_FOR_DEWAKE(hw_dewake_scanline)); + + /* + * Force DEwake immediately if we're already past + * or close to racing past the target scanline. + */ + diff = dewake_scanline - intel_get_crtc_scanline(crtc); + intel_de_write_fw(dev_priv, DSB_PMCTRL_2(pipe, dsb->id), + (diff >= 0 && diff < 5 ? DSB_FORCE_DEWAKE : 0) | + DSB_BLOCK_DEWAKE_EXTENSION); + } + + intel_de_write_fw(dev_priv, DSB_TAIL(pipe, dsb->id), + i915_ggtt_offset(dsb->vma) + tail); +} + +/** + * intel_dsb_commit() - Trigger workload execution of DSB. + * @dsb: DSB context + * @wait_for_vblank: wait for vblank before executing + * + * This function is used to do actual write to hardware using DSB. + */ +void intel_dsb_commit(struct intel_dsb *dsb, + bool wait_for_vblank) +{ + _intel_dsb_commit(dsb, + wait_for_vblank ? DSB_WAIT_FOR_VBLANK : 0, + wait_for_vblank ? dsb->dewake_scanline : -1); } void intel_dsb_wait(struct intel_dsb *dsb) @@ -258,20 +407,31 @@ void intel_dsb_wait(struct intel_dsb *dsb) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; - if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1)) + if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1)) { + u32 offset = i915_ggtt_offset(dsb->vma); + + intel_de_write_fw(dev_priv, DSB_CTRL(pipe, dsb->id), + DSB_ENABLE | DSB_HALT); + drm_err(&dev_priv->drm, - "[CRTC:%d:%s] DSB %d timed out waiting for idle\n", - crtc->base.base.id, crtc->base.name, dsb->id); + "[CRTC:%d:%s] DSB %d timed out waiting for idle (current head=0x%x, head=0x%x, tail=0x%x)\n", + crtc->base.base.id, crtc->base.name, dsb->id, + intel_de_read_fw(dev_priv, DSB_CURRENT_HEAD(pipe, dsb->id)) - offset, + intel_de_read_fw(dev_priv, DSB_HEAD(pipe, dsb->id)) - offset, + intel_de_read_fw(dev_priv, DSB_TAIL(pipe, dsb->id)) - offset); + + intel_dsb_dump(dsb); + } /* Attempt to reset it */ dsb->free_pos = 0; dsb->ins_start_offset = 0; - intel_de_write(dev_priv, DSB_CTRL(pipe, dsb->id), 0); + intel_de_write_fw(dev_priv, DSB_CTRL(pipe, dsb->id), 0); } /** * intel_dsb_prepare() - Allocate, pin and map the DSB command buffer. - * @crtc: the CRTC + * @crtc_state: the CRTC state * @max_cmds: number of commands we need to fit into command buffer * * This function prepare the command buffer which is used to store dsb @@ -280,9 +440,10 @@ void intel_dsb_wait(struct intel_dsb *dsb) * Returns: * DSB context, NULL on failure */ -struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc, +struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state, unsigned int max_cmds) { + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct drm_i915_gem_object *obj; intel_wakeref_t wakeref; @@ -303,9 +464,18 @@ struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc, /* ~1 qword per instruction, full cachelines */ size = ALIGN(max_cmds * 8, CACHELINE_BYTES); - obj = i915_gem_object_create_internal(i915, PAGE_ALIGN(size)); - if (IS_ERR(obj)) - goto out_put_rpm; + if (HAS_LMEM(i915)) { + obj = i915_gem_object_create_lmem(i915, PAGE_ALIGN(size), + I915_BO_ALLOC_CONTIGUOUS); + if (IS_ERR(obj)) + goto out_put_rpm; + } else { + obj = i915_gem_object_create_internal(i915, PAGE_ALIGN(size)); + if (IS_ERR(obj)) + goto out_put_rpm; + + i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE); + } vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0); if (IS_ERR(vma)) { @@ -328,6 +498,7 @@ struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc, dsb->size = size / 4; /* in dwords */ dsb->free_pos = 0; dsb->ins_start_offset = 0; + dsb->dewake_scanline = intel_dsb_dewake_scanline(crtc_state); return dsb; diff --git a/drivers/gpu/drm/i915/display/intel_dsb.h b/drivers/gpu/drm/i915/display/intel_dsb.h index b8148b4702..16d80f4343 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.h +++ b/drivers/gpu/drm/i915/display/intel_dsb.h @@ -11,14 +11,21 @@ #include "i915_reg_defs.h" struct intel_crtc; +struct intel_crtc_state; struct intel_dsb; -struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc, +struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state, unsigned int max_cmds); void intel_dsb_finish(struct intel_dsb *dsb); void intel_dsb_cleanup(struct intel_dsb *dsb); void intel_dsb_reg_write(struct intel_dsb *dsb, i915_reg_t reg, u32 val); +void intel_dsb_reg_write_masked(struct intel_dsb *dsb, + i915_reg_t reg, u32 mask, u32 val); +void intel_dsb_noop(struct intel_dsb *dsb, int count); +void intel_dsb_nonpost_start(struct intel_dsb *dsb); +void intel_dsb_nonpost_end(struct intel_dsb *dsb); + void intel_dsb_commit(struct intel_dsb *dsb, bool wait_for_vblank); void intel_dsb_wait(struct intel_dsb *dsb); diff --git a/drivers/gpu/drm/i915/display/intel_dsb_regs.h b/drivers/gpu/drm/i915/display/intel_dsb_regs.h index 12535d4787..210e266544 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dsb_regs.h @@ -37,6 +37,19 @@ #define DSB_DEBUG(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x14) #define DSB_POLLMASK(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x1c) #define DSB_STATUS(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x24) +#define DSB_HP_IDLE_STATUS REG_BIT(31) +#define DSB_DEWAKE_STATUS REG_BIT(30) +#define DSB_REQARB_SM_STATE_MASK REG_GENMASK(29, 27) +#define DSB_SAFE_WINDOW_LIVE REG_BIT(26) +#define DSB_VTDFAULT_ARB_SM_STATE_MASK REG_GENMASK(25, 23) +#define DSB_TLBTRANS_SM_STATE_MASK REG_GENMASK(21, 20) +#define DSB_SAFE_WINDOW REG_BIT(19) +#define DSB_POINTERS_SM_STATE_MASK REG_GENMASK(18, 17) +#define DSB_BUSY_ON_DELAYED_VBLANK REG_BIT(16) +#define DSB_MMIO_ARB_SM_STATE_MASK REG_GENMASK(15, 13) +#define DSB_MMIO_INST_SM_STATE_MASK REG_GENMASK(11, 7) +#define DSB_RESET_SM_STATE_MASK REG_GENMASK(5, 4) +#define DSB_RUN_SM_STATE_MASK REG_GENMASK(2, 0) #define DSB_INTERRUPT(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x28) #define DSB_ATS_FAULT_INT_EN REG_BIT(20) #define DSB_GTT_FAULT_INT_EN REG_BIT(19) @@ -58,10 +71,28 @@ #define DSB_RM_READY_TIMEOUT_VALUE(x) REG_FIELD_PREP(DSB_RM_READY_TIMEOUT_VALUE, (x)) /* usec */ #define DSB_RMTIMEOUTREG_CAPTURE(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x34) #define DSB_PMCTRL(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x38) +#define DSB_ENABLE_DEWAKE REG_BIT(31) +#define DSB_SCANLINE_FOR_DEWAKE_MASK REG_GENMASK(30, 0) +#define DSB_SCANLINE_FOR_DEWAKE(x) REG_FIELD_PREP(DSB_SCANLINE_FOR_DEWAKE_MASK, (x)) #define DSB_PMCTRL_2(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x3c) +#define DSB_MMIOGEN_DEWAKE_DIS REG_BIT(31) +#define DSB_FORCE_DEWAKE REG_BIT(23) +#define DSB_BLOCK_DEWAKE_EXTENSION REG_BIT(15) +#define DSB_OVERRIDE_DC5_DC6_OK REG_BIT(7) #define DSB_PF_LN_LOWER(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x40) #define DSB_PF_LN_UPPER(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x44) #define DSB_BUFRPT_CNT(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x48) #define DSB_CHICKEN(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0xf0) +#define DSB_FORCE_DMA_SYNC_RESET REG_BIT(31) +#define DSB_FORCE_VTD_ENGIE_RESET REG_BIT(30) +#define DSB_DISABLE_IPC_DEMOTE REG_BIT(29) +#define DSB_SKIP_WAITS_EN REG_BIT(23) +#define DSB_EXTEND_HP_IDLE REG_BIT(16) +#define DSB_CTRL_WAIT_SAFE_WINDOW REG_BIT(15) +#define DSB_CTRL_NO_WAIT_VBLANK REG_BIT(14) +#define DSB_INST_WAIT_SAFE_WINDOW REG_BIT(7) +#define DSB_INST_NO_WAIT_VBLANK REG_BIT(6) +#define DSB_MMIOGEN_DEWAKE_DIS_CHICKEN REG_BIT(2) +#define DSB_DISABLE_MMIO_COUNT_FOR_INDEXED REG_BIT(0) #endif /* __INTEL_DSB_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index e56ec3f2d8..24b2cbcfc1 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -565,6 +565,9 @@ static const u8 *mipi_exec_i2c(struct intel_dsi *intel_dsi, const u8 *data) u8 payload_size = *(data + 6); u8 *payload_data; + drm_dbg_kms(&i915->drm, "bus %d client-addr 0x%02x reg 0x%02x data %*ph\n", + vbt_i2c_bus_num, slave_addr, reg_offset, payload_size, data + 7); + if (intel_dsi->i2c_bus_num < 0) { intel_dsi->i2c_bus_num = vbt_i2c_bus_num; i2c_acpi_find_adapter(intel_dsi, slave_addr); diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index d1cfa966d4..9111e9d464 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -325,7 +325,7 @@ intel_dvo_detect(struct drm_connector *_connector, bool force) drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n", connector->base.base.id, connector->base.name); - if (!INTEL_DISPLAY_ENABLED(i915)) + if (!intel_display_device_enabled(i915)) return connector_status_disconnected; return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev); @@ -334,7 +334,6 @@ intel_dvo_detect(struct drm_connector *_connector, bool force) static int intel_dvo_get_modes(struct drm_connector *_connector) { struct intel_connector *connector = to_intel_connector(_connector); - struct drm_i915_private *i915 = to_i915(connector->base.dev); int num_modes; /* @@ -343,8 +342,7 @@ static int intel_dvo_get_modes(struct drm_connector *_connector) * (TV-out, for example), but for now with just TMDS and LVDS, * that's not the case. */ - num_modes = intel_ddc_get_modes(&connector->base, - intel_gmbus_get_adapter(i915, GMBUS_PIN_DPC)); + num_modes = intel_ddc_get_modes(&connector->base, connector->base.ddc); if (num_modes) return num_modes; @@ -539,9 +537,10 @@ void intel_dvo_init(struct drm_i915_private *i915) connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - drm_connector_init(&i915->drm, &connector->base, - &intel_dvo_connector_funcs, - intel_dvo_connector_type(&intel_dvo->dev)); + drm_connector_init_with_ddc(&i915->drm, &connector->base, + &intel_dvo_connector_funcs, + intel_dvo_connector_type(&intel_dvo->dev), + intel_gmbus_get_adapter(i915, GMBUS_PIN_DPC)); drm_connector_helper_add(&connector->base, &intel_dvo_connector_helper_funcs); diff --git a/drivers/gpu/drm/i915/display/intel_dvo.h b/drivers/gpu/drm/i915/display/intel_dvo.h index 3ed0fdf8ef..bf7a356422 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.h +++ b/drivers/gpu/drm/i915/display/intel_dvo.h @@ -8,6 +8,12 @@ struct drm_i915_private; +#ifdef I915 void intel_dvo_init(struct drm_i915_private *dev_priv); +#else +static inline void intel_dvo_init(struct drm_i915_private *dev_priv) +{ +} +#endif #endif /* __INTEL_DVO_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 689b7c16d3..646f367a13 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -7,11 +7,15 @@ #include <drm/drm_framebuffer.h> #include <drm/drm_modeset_helper.h> +#include <linux/dma-fence.h> +#include <linux/dma-resv.h> + #include "i915_drv.h" #include "intel_display.h" #include "intel_display_types.h" #include "intel_dpt.h" #include "intel_fb.h" +#include "intel_frontbuffer.h" #define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a)) @@ -1113,7 +1117,7 @@ static int intel_fb_offset_to_xy(int *x, int *y, return -EINVAL; } - height = drm_framebuffer_plane_height(fb->height, fb, color_plane); + height = drm_format_info_plane_height(fb->format, fb->height, color_plane); height = ALIGN(height, intel_tile_height(fb, color_plane)); /* Catch potential overflows early */ @@ -1909,6 +1913,21 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, return drm_gem_handle_create(file, &obj->base, handle); } +struct frontbuffer_fence_cb { + struct dma_fence_cb base; + struct intel_frontbuffer *front; +}; + +static void intel_user_framebuffer_fence_wake(struct dma_fence *dma, + struct dma_fence_cb *data) +{ + struct frontbuffer_fence_cb *cb = container_of(data, typeof(*cb), base); + + intel_frontbuffer_queue_flush(cb->front); + kfree(cb); + dma_fence_put(dma); +} + static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, struct drm_file *file, unsigned int flags, unsigned int color, @@ -1916,11 +1935,47 @@ static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, unsigned int num_clips) { struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_frontbuffer *front = to_intel_frontbuffer(fb); + struct dma_fence *fence; + struct frontbuffer_fence_cb *cb; + int ret = 0; - i915_gem_object_flush_if_display(obj); - intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB); + if (!atomic_read(&front->bits)) + return 0; - return 0; + if (dma_resv_test_signaled(obj->base.resv, dma_resv_usage_rw(false))) + goto flush; + + ret = dma_resv_get_singleton(obj->base.resv, dma_resv_usage_rw(false), + &fence); + if (ret || !fence) + goto flush; + + cb = kmalloc(sizeof(*cb), GFP_KERNEL); + if (!cb) { + dma_fence_put(fence); + ret = -ENOMEM; + goto flush; + } + + cb->front = front; + + intel_frontbuffer_invalidate(front, ORIGIN_DIRTYFB); + + ret = dma_fence_add_callback(fence, &cb->base, + intel_user_framebuffer_fence_wake); + if (ret) { + intel_user_framebuffer_fence_wake(fence, &cb->base); + if (ret == -ENOENT) + ret = 0; + } + + return ret; + +flush: + i915_gem_object_flush_if_display(obj); + intel_frontbuffer_flush(front, ORIGIN_DIRTYFB); + return ret; } static const struct drm_framebuffer_funcs intel_fb_funcs = { diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c index fffd568070..7b42aef37d 100644 --- a/drivers/gpu/drm/i915/display/intel_fb_pin.c +++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c @@ -35,7 +35,8 @@ intel_pin_fb_obj_dpt(struct drm_framebuffer *fb, * We are not syncing against the binding (and potential migrations) * below, so this vm must never be async. */ - GEM_WARN_ON(vm->bind_async_flags); + if (drm_WARN_ON(&dev_priv->drm, vm->bind_async_flags)) + return ERR_PTR(-EINVAL); if (WARN_ON(!i915_gem_object_is_framebuffer(obj))) return ERR_PTR(-EINVAL); diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 25382022cd..4820d21cc9 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -50,6 +50,7 @@ #include "i915_vma.h" #include "intel_cdclk.h" #include "intel_de.h" +#include "intel_display_device.h" #include "intel_display_trace.h" #include "intel_display_types.h" #include "intel_fbc.h" @@ -332,12 +333,14 @@ static void i8xx_fbc_program_cfb(struct intel_fbc *fbc) { struct drm_i915_private *i915 = fbc->i915; - GEM_BUG_ON(range_overflows_end_t(u64, i915_gem_stolen_area_address(i915), - i915_gem_stolen_node_offset(&fbc->compressed_fb), - U32_MAX)); - GEM_BUG_ON(range_overflows_end_t(u64, i915_gem_stolen_area_address(i915), - i915_gem_stolen_node_offset(&fbc->compressed_llb), - U32_MAX)); + drm_WARN_ON(&i915->drm, + range_overflows_end_t(u64, i915_gem_stolen_area_address(i915), + i915_gem_stolen_node_offset(&fbc->compressed_fb), + U32_MAX)); + drm_WARN_ON(&i915->drm, + range_overflows_end_t(u64, i915_gem_stolen_area_address(i915), + i915_gem_stolen_node_offset(&fbc->compressed_llb), + U32_MAX)); intel_de_write(i915, FBC_CFB_BASE, i915_gem_stolen_node_address(i915, &fbc->compressed_fb)); intel_de_write(i915, FBC_LL_BASE, @@ -590,6 +593,9 @@ static u32 ivb_dpfc_ctl(struct intel_fbc *fbc) if (IS_IVYBRIDGE(i915)) dpfc_ctl |= DPFC_CTL_PLANE_IVB(fbc_state->plane->i9xx_plane); + if (DISPLAY_VER(i915) >= 20) + dpfc_ctl |= DPFC_CTL_PLANE_BINDING(fbc_state->plane->id); + if (fbc_state->fence_id >= 0) dpfc_ctl |= DPFC_CTL_FENCE_EN_IVB; @@ -847,39 +853,64 @@ void intel_fbc_cleanup(struct drm_i915_private *i915) } } -static bool stride_is_valid(const struct intel_plane_state *plane_state) +static bool i8xx_fbc_stride_is_valid(const struct intel_plane_state *plane_state) { - struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); const struct drm_framebuffer *fb = plane_state->hw.fb; unsigned int stride = intel_fbc_plane_stride(plane_state) * fb->format->cpp[0]; - /* This should have been caught earlier. */ - if (drm_WARN_ON_ONCE(&i915->drm, (stride & (64 - 1)) != 0)) - return false; + return stride == 4096 || stride == 8192; +} - /* Below are the additional FBC restrictions. */ - if (stride < 512) - return false; +static bool i965_fbc_stride_is_valid(const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int stride = intel_fbc_plane_stride(plane_state) * + fb->format->cpp[0]; - if (DISPLAY_VER(i915) == 2 || DISPLAY_VER(i915) == 3) - return stride == 4096 || stride == 8192; + return stride >= 2048 && stride <= 16384; +} - if (DISPLAY_VER(i915) == 4 && !IS_G4X(i915) && stride < 2048) - return false; +static bool g4x_fbc_stride_is_valid(const struct intel_plane_state *plane_state) +{ + return true; +} + +static bool skl_fbc_stride_is_valid(const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int stride = intel_fbc_plane_stride(plane_state) * + fb->format->cpp[0]; /* Display WA #1105: skl,bxt,kbl,cfl,glk */ - if ((DISPLAY_VER(i915) == 9 || IS_GEMINILAKE(i915)) && - fb->modifier == DRM_FORMAT_MOD_LINEAR && stride & 511) + if (fb->modifier == DRM_FORMAT_MOD_LINEAR && stride & 511) return false; - if (stride > 16384) - return false; + return true; +} +static bool icl_fbc_stride_is_valid(const struct intel_plane_state *plane_state) +{ return true; } -static bool pixel_format_is_valid(const struct intel_plane_state *plane_state) +static bool stride_is_valid(const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + + if (DISPLAY_VER(i915) >= 11) + return icl_fbc_stride_is_valid(plane_state); + else if (DISPLAY_VER(i915) >= 9) + return skl_fbc_stride_is_valid(plane_state); + else if (DISPLAY_VER(i915) >= 5 || IS_G4X(i915)) + return g4x_fbc_stride_is_valid(plane_state); + else if (DISPLAY_VER(i915) == 4) + return i965_fbc_stride_is_valid(plane_state); + else + return i8xx_fbc_stride_is_valid(plane_state); +} + +static bool i8xx_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state) { struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); const struct drm_framebuffer *fb = plane_state->hw.fb; @@ -893,6 +924,22 @@ static bool pixel_format_is_valid(const struct intel_plane_state *plane_state) /* 16bpp not supported on gen2 */ if (DISPLAY_VER(i915) == 2) return false; + return true; + default: + return false; + } +} + +static bool g4x_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + + switch (fb->format->format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + return true; + case DRM_FORMAT_RGB565: /* WaFbcOnly1to1Ratio:ctg */ if (IS_G4X(i915)) return false; @@ -902,22 +949,68 @@ static bool pixel_format_is_valid(const struct intel_plane_state *plane_state) } } -static bool rotation_is_valid(const struct intel_plane_state *plane_state) +static bool lnl_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + + switch (fb->format->format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGB565: + return true; + default: + return false; + } +} + +static bool pixel_format_is_valid(const struct intel_plane_state *plane_state) { struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + + if (DISPLAY_VER(i915) >= 20) + return lnl_fbc_pixel_format_is_valid(plane_state); + else if (DISPLAY_VER(i915) >= 5 || IS_G4X(i915)) + return g4x_fbc_pixel_format_is_valid(plane_state); + else + return i8xx_fbc_pixel_format_is_valid(plane_state); +} + +static bool i8xx_fbc_rotation_is_valid(const struct intel_plane_state *plane_state) +{ + return plane_state->hw.rotation == DRM_MODE_ROTATE_0; +} + +static bool g4x_fbc_rotation_is_valid(const struct intel_plane_state *plane_state) +{ + return true; +} + +static bool skl_fbc_rotation_is_valid(const struct intel_plane_state *plane_state) +{ const struct drm_framebuffer *fb = plane_state->hw.fb; unsigned int rotation = plane_state->hw.rotation; - if (DISPLAY_VER(i915) >= 9 && fb->format->format == DRM_FORMAT_RGB565 && + if (fb->format->format == DRM_FORMAT_RGB565 && drm_rotation_90_or_270(rotation)) return false; - else if (DISPLAY_VER(i915) <= 4 && !IS_G4X(i915) && - rotation != DRM_MODE_ROTATE_0) - return false; return true; } +static bool rotation_is_valid(const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + + if (DISPLAY_VER(i915) >= 9) + return skl_fbc_rotation_is_valid(plane_state); + else if (DISPLAY_VER(i915) >= 5 || IS_G4X(i915)) + return g4x_fbc_rotation_is_valid(plane_state); + else + return i8xx_fbc_rotation_is_valid(plane_state); +} + /* * For some reason, the hardware tracking starts looking at whatever we * programmed as the display plane base address register. It does not look at @@ -951,16 +1044,21 @@ static bool intel_fbc_hw_tracking_covers_screen(const struct intel_plane_state * return effective_w <= max_w && effective_h <= max_h; } -static bool tiling_is_valid(const struct intel_plane_state *plane_state) +static bool i8xx_fbc_tiling_valid(const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + + return fb->modifier == I915_FORMAT_MOD_X_TILED; +} + +static bool skl_fbc_tiling_valid(const struct intel_plane_state *plane_state) { - struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); const struct drm_framebuffer *fb = plane_state->hw.fb; switch (fb->modifier) { case DRM_FORMAT_MOD_LINEAR: case I915_FORMAT_MOD_Y_TILED: case I915_FORMAT_MOD_Yf_TILED: - return DISPLAY_VER(i915) >= 9; case I915_FORMAT_MOD_4_TILED: case I915_FORMAT_MOD_X_TILED: return true; @@ -969,6 +1067,16 @@ static bool tiling_is_valid(const struct intel_plane_state *plane_state) } } +static bool tiling_is_valid(const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + + if (DISPLAY_VER(i915) >= 9) + return skl_fbc_tiling_valid(plane_state); + else + return i8xx_fbc_tiling_valid(plane_state); +} + static void intel_fbc_update_state(struct intel_atomic_state *state, struct intel_crtc *crtc, struct intel_plane *plane) @@ -1100,7 +1208,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, /* Wa_14016291713 */ if ((IS_DISPLAY_VER(i915, 12, 13) || - IS_MTL_DISPLAY_STEP(i915, STEP_A0, STEP_C0)) && + IS_DISPLAY_IP_STEP(i915, IP_VER(14, 0), STEP_A0, STEP_C0)) && crtc_state->has_psr) { plane_state->no_fbc_reason = "PSR1 enabled (Wa_14016291713)"; return 0; @@ -1126,7 +1234,8 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, return 0; } - if (plane_state->hw.pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE && + if (DISPLAY_VER(i915) < 20 && + plane_state->hw.pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE && fb->format->has_alpha) { plane_state->no_fbc_reason = "per-pixel alpha not supported"; return 0; @@ -1306,11 +1415,9 @@ static void __intel_fbc_post_update(struct intel_fbc *fbc) lockdep_assert_held(&fbc->lock); fbc->flip_pending = false; + fbc->busy_bits = 0; - if (!fbc->busy_bits) - intel_fbc_activate(fbc); - else - intel_fbc_deactivate(fbc, "frontbuffer write"); + intel_fbc_activate(fbc); } void intel_fbc_post_update(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_fbc.h b/drivers/gpu/drm/i915/display/intel_fbc.h index 4adb98afe6..6720ec8ee8 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.h +++ b/drivers/gpu/drm/i915/display/intel_fbc.h @@ -20,6 +20,8 @@ struct intel_plane_state; enum intel_fbc_id { INTEL_FBC_A, INTEL_FBC_B, + INTEL_FBC_C, + INTEL_FBC_D, I915_MAX_FBCS, }; diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index e12b46a84f..e6429dfebe 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -13,6 +13,7 @@ #include "intel_display_types.h" #include "intel_fdi.h" #include "intel_fdi_regs.h" +#include "intel_link_bw.h" struct intel_fdi_funcs { void (*fdi_link_train)(struct intel_crtc *crtc, @@ -119,6 +120,53 @@ void intel_fdi_link_train(struct intel_crtc *crtc, dev_priv->display.funcs.fdi->fdi_link_train(crtc, crtc_state); } +/** + * intel_fdi_add_affected_crtcs - add CRTCs on FDI affected by other modeset CRTCs + * @state: intel atomic state + * + * Add a CRTC using FDI to @state if changing another CRTC's FDI BW usage is + * known to affect the available FDI BW for the former CRTC. In practice this + * means adding CRTC B on IVYBRIDGE if its use of FDI lanes is limited (by + * CRTC C) and CRTC C is getting disabled. + * + * Returns 0 in case of success, or a negative error code otherwise. + */ +int intel_fdi_add_affected_crtcs(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_crtc_state *old_crtc_state; + const struct intel_crtc_state *new_crtc_state; + struct intel_crtc *crtc; + + if (!IS_IVYBRIDGE(i915) || INTEL_NUM_PIPES(i915) != 3) + return 0; + + crtc = intel_crtc_for_pipe(i915, PIPE_C); + new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); + if (!new_crtc_state) + return 0; + + if (!intel_crtc_needs_modeset(new_crtc_state)) + return 0; + + old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc); + if (!old_crtc_state->fdi_lanes) + return 0; + + crtc = intel_crtc_for_pipe(i915, PIPE_B); + new_crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); + if (IS_ERR(new_crtc_state)) + return PTR_ERR(new_crtc_state); + + old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc); + if (!old_crtc_state->fdi_lanes) + return 0; + + return intel_modeset_pipes_in_mask_early(state, + "FDI link BW decrease on pipe C", + BIT(PIPE_B)); +} + /* units of 100MHz */ static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state) { @@ -129,13 +177,16 @@ static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state) } static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, - struct intel_crtc_state *pipe_config) + struct intel_crtc_state *pipe_config, + enum pipe *pipe_to_reduce) { struct drm_i915_private *dev_priv = to_i915(dev); struct drm_atomic_state *state = pipe_config->uapi.state; struct intel_crtc *other_crtc; struct intel_crtc_state *other_crtc_state; + *pipe_to_reduce = pipe; + drm_dbg_kms(&dev_priv->drm, "checking fdi config on pipe %c, lanes %i\n", pipe_name(pipe), pipe_config->fdi_lanes); @@ -198,6 +249,9 @@ static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, if (pipe_required_fdi_lanes(other_crtc_state) > 2) { drm_dbg_kms(&dev_priv->drm, "fdi link B uses too many lanes to enable link C\n"); + + *pipe_to_reduce = PIPE_B; + return -EINVAL; } return 0; @@ -232,16 +286,42 @@ int intel_fdi_link_freq(struct drm_i915_private *i915, return i915->display.fdi.pll_freq; } +/** + * intel_fdi_compute_pipe_bpp - compute pipe bpp limited by max link bpp + * @crtc_state: the crtc state + * + * Compute the pipe bpp limited by the CRTC's maximum link bpp. Encoders can + * call this function during state computation in the simple case where the + * link bpp will always match the pipe bpp. This is the case for all non-DP + * encoders, while DP encoders will use a link bpp lower than pipe bpp in case + * of DSC compression. + * + * Returns %true in case of success, %false if pipe bpp would need to be + * reduced below its valid range. + */ +bool intel_fdi_compute_pipe_bpp(struct intel_crtc_state *crtc_state) +{ + int pipe_bpp = min(crtc_state->pipe_bpp, + to_bpp_int(crtc_state->max_link_bpp_x16)); + + pipe_bpp = rounddown(pipe_bpp, 2 * 3); + + if (pipe_bpp < 6 * 3) + return false; + + crtc_state->pipe_bpp = pipe_bpp; + + return true; +} + int ilk_fdi_compute_config(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *i915 = to_i915(dev); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - int lane, link_bw, fdi_dotclock, ret; - bool needs_recompute = false; + int lane, link_bw, fdi_dotclock; -retry: /* FDI is a binary signal running at ~2.7GHz, encoding * each output octet as 10 bits. The actual frequency * is stored as a divider into a 100MHz clock, and the @@ -261,25 +341,69 @@ retry: intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock, link_bw, &pipe_config->fdi_m_n, false); - ret = ilk_check_fdi_lanes(dev, crtc->pipe, pipe_config); - if (ret == -EDEADLK) + return 0; +} + +static int intel_fdi_atomic_check_bw(struct intel_atomic_state *state, + struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config, + struct intel_link_bw_limits *limits) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + enum pipe pipe_to_reduce; + int ret; + + ret = ilk_check_fdi_lanes(&i915->drm, crtc->pipe, pipe_config, + &pipe_to_reduce); + if (ret != -EINVAL) return ret; - if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) { - pipe_config->pipe_bpp -= 2*3; - drm_dbg_kms(&i915->drm, - "fdi link bw constraint, reducing pipe bpp to %i\n", - pipe_config->pipe_bpp); - needs_recompute = true; - pipe_config->bw_constrained = true; + ret = intel_link_bw_reduce_bpp(state, limits, + BIT(pipe_to_reduce), + "FDI link BW"); - goto retry; - } + return ret ? : -EAGAIN; +} + +/** + * intel_fdi_atomic_check_link - check all modeset FDI link configuration + * @state: intel atomic state + * @limits: link BW limits + * + * Check the link configuration for all modeset FDI outputs. If the + * configuration is invalid @limits will be updated if possible to + * reduce the total BW, after which the configuration for all CRTCs in + * @state must be recomputed with the updated @limits. + * + * Returns: + * - 0 if the confugration is valid + * - %-EAGAIN, if the configuration is invalid and @limits got updated + * with fallback values with which the configuration of all CRTCs + * in @state must be recomputed + * - Other negative error, if the configuration is invalid without a + * fallback possibility, or the check failed for another reason + */ +int intel_fdi_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits) +{ + struct intel_crtc *crtc; + struct intel_crtc_state *crtc_state; + int i; + + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { + int ret; + + if (!crtc_state->has_pch_encoder || + !intel_crtc_needs_modeset(crtc_state) || + !crtc_state->hw.enable) + continue; - if (needs_recompute) - return -EAGAIN; + ret = intel_fdi_atomic_check_bw(state, crtc, crtc_state, limits); + if (ret) + return ret; + } - return ret; + return 0; } static void cpt_set_fdi_bc_bifurcation(struct drm_i915_private *dev_priv, bool enable) @@ -766,7 +890,10 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, * WaFDIAutoLinkSetTimingOverrride:hsw */ intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), - FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2) | FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + FDI_RX_PWRDN_LANE1_VAL(2) | + FDI_RX_PWRDN_LANE0_VAL(2) | + FDI_RX_TP1_TO_TP2_48 | + FDI_RX_FDI_DELAY_90); /* Enable the PCH Receiver FDI PLL */ rx_ctl_val = dev_priv->display.fdi.rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | @@ -799,7 +926,9 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, * achieved on the PCH side in FDI_RX_CTL, so no need to set the * port reversal bit */ intel_de_write(dev_priv, DDI_BUF_CTL(PORT_E), - DDI_BUF_CTL_ENABLE | ((crtc_state->fdi_lanes - 1) << 1) | DDI_BUF_TRANS_SELECT(i / 2)); + DDI_BUF_CTL_ENABLE | + ((crtc_state->fdi_lanes - 1) << 1) | + DDI_BUF_TRANS_SELECT(i / 2)); intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E)); udelay(600); diff --git a/drivers/gpu/drm/i915/display/intel_fdi.h b/drivers/gpu/drm/i915/display/intel_fdi.h index 1cdb861727..477ff01369 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.h +++ b/drivers/gpu/drm/i915/display/intel_fdi.h @@ -6,16 +6,24 @@ #ifndef _INTEL_FDI_H_ #define _INTEL_FDI_H_ +#include <linux/types.h> + enum pipe; struct drm_i915_private; +struct intel_atomic_state; struct intel_crtc; struct intel_crtc_state; struct intel_encoder; +struct intel_link_bw_limits; +int intel_fdi_add_affected_crtcs(struct intel_atomic_state *state); int intel_fdi_link_freq(struct drm_i915_private *i915, const struct intel_crtc_state *pipe_config); +bool intel_fdi_compute_pipe_bpp(struct intel_crtc_state *crtc_state); int ilk_fdi_compute_config(struct intel_crtc *intel_crtc, struct intel_crtc_state *pipe_config); +int intel_fdi_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits); void intel_fdi_normal_train(struct intel_crtc *crtc); void ilk_fdi_disable(struct intel_crtc *crtc); void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc); diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c index 22392f94b6..2ea37c0414 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c @@ -55,6 +55,8 @@ * cancelled as soon as busyness is detected. */ +#include "gem/i915_gem_object_frontbuffer.h" +#include "i915_active.h" #include "i915_drv.h" #include "intel_display_trace.h" #include "intel_display_types.h" @@ -202,6 +204,33 @@ void __intel_fb_flush(struct intel_frontbuffer *front, frontbuffer_flush(i915, frontbuffer_bits, origin); } +static void intel_frontbuffer_flush_work(struct work_struct *work) +{ + struct intel_frontbuffer *front = + container_of(work, struct intel_frontbuffer, flush_work); + + i915_gem_object_flush_if_display(front->obj); + intel_frontbuffer_flush(front, ORIGIN_DIRTYFB); + intel_frontbuffer_put(front); +} + +/** + * intel_frontbuffer_queue_flush - queue flushing frontbuffer object + * @front: GEM object to flush + * + * This function is targeted for our dirty callback for queueing flush when + * dma fence is signales + */ +void intel_frontbuffer_queue_flush(struct intel_frontbuffer *front) +{ + if (!front) + return; + + kref_get(&front->ref); + if (!schedule_work(&front->flush_work)) + intel_frontbuffer_put(front); +} + static int frontbuffer_active(struct i915_active *ref) { struct intel_frontbuffer *front = @@ -223,7 +252,7 @@ static void frontbuffer_retire(struct i915_active *ref) static void frontbuffer_release(struct kref *ref) __releases(&intel_bo_to_i915(front->obj)->display.fb_tracking.lock) { - struct intel_frontbuffer *front = + struct intel_frontbuffer *ret, *front = container_of(ref, typeof(*front), ref); struct drm_i915_gem_object *obj = front->obj; @@ -231,12 +260,11 @@ static void frontbuffer_release(struct kref *ref) i915_ggtt_clear_scanout(obj); - i915_gem_object_set_frontbuffer(obj, NULL); + ret = i915_gem_object_set_frontbuffer(obj, NULL); + drm_WARN_ON(&intel_bo_to_i915(obj)->drm, ret); spin_unlock(&intel_bo_to_i915(obj)->display.fb_tracking.lock); i915_active_fini(&front->write); - - i915_gem_object_put(obj); kfree_rcu(front, rcu); } @@ -261,6 +289,7 @@ intel_frontbuffer_get(struct drm_i915_gem_object *obj) frontbuffer_active, frontbuffer_retire, I915_ACTIVE_RETIRE_SLEEPS); + INIT_WORK(&front->flush_work, intel_frontbuffer_flush_work); spin_lock(&i915->display.fb_tracking.lock); cur = i915_gem_object_set_frontbuffer(obj, front); diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.h b/drivers/gpu/drm/i915/display/intel_frontbuffer.h index 72d89be328..abb51e8bb9 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.h +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.h @@ -46,6 +46,8 @@ struct intel_frontbuffer { struct i915_active write; struct drm_i915_gem_object *obj; struct rcu_head rcu; + + struct work_struct flush_work; }; /* @@ -135,6 +137,8 @@ static inline void intel_frontbuffer_flush(struct intel_frontbuffer *front, __intel_fb_flush(front, origin, frontbuffer_bits); } +void intel_frontbuffer_queue_flush(struct intel_frontbuffer *front); + void intel_frontbuffer_track(struct intel_frontbuffer *old, struct intel_frontbuffer *new, unsigned int frontbuffer_bits); diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index e95ddb580e..40d7b6f3f4 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -155,7 +155,10 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915, const struct gmbus_pin *pins; size_t size; - if (INTEL_PCH_TYPE(i915) >= PCH_DG2) { + if (INTEL_PCH_TYPE(i915) >= PCH_LNL) { + pins = gmbus_pins_mtp; + size = ARRAY_SIZE(gmbus_pins_mtp); + } else if (INTEL_PCH_TYPE(i915) >= PCH_DG2) { pins = gmbus_pins_dg2; size = ARRAY_SIZE(gmbus_pins_dg2); } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) { @@ -778,7 +781,7 @@ int intel_gmbus_output_aksv(struct i2c_adapter *adapter) struct intel_gmbus *bus = to_intel_gmbus(adapter); struct drm_i915_private *i915 = bus->i915; u8 cmd = DRM_HDCP_DDC_AKSV; - u8 buf[DRM_HDCP_KSV_LEN] = { 0 }; + u8 buf[DRM_HDCP_KSV_LEN] = {}; struct i2c_msg msgs[] = { { .addr = DRM_HDCP_DDC_ADDR, diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index a42549fa96..c89da3568e 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -163,7 +163,6 @@ bool intel_hdcp_capable(struct intel_connector *connector) /* Is HDCP2.2 capable on Platform and Sink */ bool intel_hdcp2_capable(struct intel_connector *connector) { - struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_hdcp *hdcp = &connector->hdcp; bool capable = false; @@ -174,14 +173,8 @@ bool intel_hdcp2_capable(struct intel_connector *connector) /* If MTL+ make sure gsc is loaded and proxy is setup */ if (intel_hdcp_gsc_cs_required(i915)) { - struct intel_gt *gt = i915->media_gt; - struct intel_gsc_uc *gsc = gt ? >->uc.gsc : NULL; - - if (!gsc || !intel_uc_fw_is_running(&gsc->fw)) { - drm_dbg_kms(&i915->drm, - "GSC components required for HDCP2.2 are not ready\n"); + if (!intel_hdcp_gsc_check_status(i915)) return false; - } } /* MEI/GSC interface is solid depending on which is used */ @@ -193,7 +186,7 @@ bool intel_hdcp2_capable(struct intel_connector *connector) mutex_unlock(&i915->display.hdcp.hdcp_mutex); /* Sink's capability for HDCP2.2 */ - hdcp->shim->hdcp_2_2_capable(dig_port, &capable); + hdcp->shim->hdcp_2_2_capable(connector, &capable); return capable; } @@ -1415,7 +1408,6 @@ static int hdcp2_deauthenticate_port(struct intel_connector *connector) /* Authentication flow starts from here */ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) { - struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_hdcp *hdcp = &connector->hdcp; union { @@ -1437,12 +1429,12 @@ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) if (ret < 0) return ret; - ret = shim->write_2_2_msg(dig_port, &msgs.ake_init, + ret = shim->write_2_2_msg(connector, &msgs.ake_init, sizeof(msgs.ake_init)); if (ret < 0) return ret; - ret = shim->read_2_2_msg(dig_port, HDCP_2_2_AKE_SEND_CERT, + ret = shim->read_2_2_msg(connector, HDCP_2_2_AKE_SEND_CERT, &msgs.send_cert, sizeof(msgs.send_cert)); if (ret < 0) return ret; @@ -1471,11 +1463,11 @@ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) if (ret < 0) return ret; - ret = shim->write_2_2_msg(dig_port, &msgs.no_stored_km, size); + ret = shim->write_2_2_msg(connector, &msgs.no_stored_km, size); if (ret < 0) return ret; - ret = shim->read_2_2_msg(dig_port, HDCP_2_2_AKE_SEND_HPRIME, + ret = shim->read_2_2_msg(connector, HDCP_2_2_AKE_SEND_HPRIME, &msgs.send_hprime, sizeof(msgs.send_hprime)); if (ret < 0) return ret; @@ -1486,7 +1478,7 @@ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) if (!hdcp->is_paired) { /* Pairing is required */ - ret = shim->read_2_2_msg(dig_port, + ret = shim->read_2_2_msg(connector, HDCP_2_2_AKE_SEND_PAIRING_INFO, &msgs.pairing_info, sizeof(msgs.pairing_info)); @@ -1504,7 +1496,6 @@ static int hdcp2_authentication_key_exchange(struct intel_connector *connector) static int hdcp2_locality_check(struct intel_connector *connector) { - struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct intel_hdcp *hdcp = &connector->hdcp; union { struct hdcp2_lc_init lc_init; @@ -1518,12 +1509,12 @@ static int hdcp2_locality_check(struct intel_connector *connector) if (ret < 0) continue; - ret = shim->write_2_2_msg(dig_port, &msgs.lc_init, + ret = shim->write_2_2_msg(connector, &msgs.lc_init, sizeof(msgs.lc_init)); if (ret < 0) continue; - ret = shim->read_2_2_msg(dig_port, + ret = shim->read_2_2_msg(connector, HDCP_2_2_LC_SEND_LPRIME, &msgs.send_lprime, sizeof(msgs.send_lprime)); @@ -1540,7 +1531,6 @@ static int hdcp2_locality_check(struct intel_connector *connector) static int hdcp2_session_key_exchange(struct intel_connector *connector) { - struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct intel_hdcp *hdcp = &connector->hdcp; struct hdcp2_ske_send_eks send_eks; int ret; @@ -1549,7 +1539,7 @@ static int hdcp2_session_key_exchange(struct intel_connector *connector) if (ret < 0) return ret; - ret = hdcp->shim->write_2_2_msg(dig_port, &send_eks, + ret = hdcp->shim->write_2_2_msg(connector, &send_eks, sizeof(send_eks)); if (ret < 0) return ret; @@ -1587,12 +1577,12 @@ int _hdcp2_propagate_stream_management_info(struct intel_connector *connector) streams_size_delta = (HDCP_2_2_MAX_CONTENT_STREAMS_CNT - data->k) * sizeof(struct hdcp2_streamid_type); /* Send it to Repeater */ - ret = shim->write_2_2_msg(dig_port, &msgs.stream_manage, + ret = shim->write_2_2_msg(connector, &msgs.stream_manage, sizeof(msgs.stream_manage) - streams_size_delta); if (ret < 0) goto out; - ret = shim->read_2_2_msg(dig_port, HDCP_2_2_REP_STREAM_READY, + ret = shim->read_2_2_msg(connector, HDCP_2_2_REP_STREAM_READY, &msgs.stream_ready, sizeof(msgs.stream_ready)); if (ret < 0) goto out; @@ -1622,7 +1612,7 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector) u8 *rx_info; int ret; - ret = shim->read_2_2_msg(dig_port, HDCP_2_2_REP_SEND_RECVID_LIST, + ret = shim->read_2_2_msg(connector, HDCP_2_2_REP_SEND_RECVID_LIST, &msgs.recvid_list, sizeof(msgs.recvid_list)); if (ret < 0) return ret; @@ -1675,7 +1665,7 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector) return ret; hdcp->seq_num_v = seq_num_v; - ret = shim->write_2_2_msg(dig_port, &msgs.rep_ack, + ret = shim->write_2_2_msg(connector, &msgs.rep_ack, sizeof(msgs.rep_ack)); if (ret < 0) return ret; @@ -1685,7 +1675,6 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector) static int hdcp2_authenticate_sink(struct intel_connector *connector) { - struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_hdcp *hdcp = &connector->hdcp; const struct intel_hdcp_shim *shim = hdcp->shim; @@ -1711,7 +1700,7 @@ static int hdcp2_authenticate_sink(struct intel_connector *connector) } if (shim->config_stream_type) { - ret = shim->config_stream_type(dig_port, + ret = shim->config_stream_type(connector, hdcp->is_repeater, hdcp->content_type); if (ret < 0) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c index d753db3eef..18117b789b 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.c @@ -11,610 +11,27 @@ #include "i915_drv.h" #include "i915_utils.h" #include "intel_hdcp_gsc.h" +#include "intel_hdcp_gsc_message.h" bool intel_hdcp_gsc_cs_required(struct drm_i915_private *i915) { return DISPLAY_VER(i915) >= 14; } -static int -gsc_hdcp_initiate_session(struct device *dev, struct hdcp_port_data *data, - struct hdcp2_ake_init *ake_data) +bool intel_hdcp_gsc_check_status(struct drm_i915_private *i915) { - struct wired_cmd_initiate_hdcp2_session_in session_init_in = { { 0 } }; - struct wired_cmd_initiate_hdcp2_session_out - session_init_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !ake_data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - session_init_in.header.api_version = HDCP_API_VERSION; - session_init_in.header.command_id = WIRED_INITIATE_HDCP2_SESSION; - session_init_in.header.status = FW_HDCP_STATUS_SUCCESS; - session_init_in.header.buffer_len = - WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN; - - session_init_in.port.integrated_port_type = data->port_type; - session_init_in.port.physical_port = (u8)data->hdcp_ddi; - session_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - session_init_in.protocol = data->protocol; - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&session_init_in, - sizeof(session_init_in), - (u8 *)&session_init_out, - sizeof(session_init_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (session_init_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", - WIRED_INITIATE_HDCP2_SESSION, - session_init_out.header.status); - return -EIO; - } - - ake_data->msg_id = HDCP_2_2_AKE_INIT; - ake_data->tx_caps = session_init_out.tx_caps; - memcpy(ake_data->r_tx, session_init_out.r_tx, HDCP_2_2_RTX_LEN); - - return 0; -} - -static int -gsc_hdcp_verify_receiver_cert_prepare_km(struct device *dev, - struct hdcp_port_data *data, - struct hdcp2_ake_send_cert *rx_cert, - bool *km_stored, - struct hdcp2_ake_no_stored_km - *ek_pub_km, - size_t *msg_sz) -{ - struct wired_cmd_verify_receiver_cert_in verify_rxcert_in = { { 0 } }; - struct wired_cmd_verify_receiver_cert_out verify_rxcert_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - verify_rxcert_in.header.api_version = HDCP_API_VERSION; - verify_rxcert_in.header.command_id = WIRED_VERIFY_RECEIVER_CERT; - verify_rxcert_in.header.status = FW_HDCP_STATUS_SUCCESS; - verify_rxcert_in.header.buffer_len = - WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN; - - verify_rxcert_in.port.integrated_port_type = data->port_type; - verify_rxcert_in.port.physical_port = (u8)data->hdcp_ddi; - verify_rxcert_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - verify_rxcert_in.cert_rx = rx_cert->cert_rx; - memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, HDCP_2_2_RRX_LEN); - memcpy(verify_rxcert_in.rx_caps, rx_cert->rx_caps, HDCP_2_2_RXCAPS_LEN); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_rxcert_in, - sizeof(verify_rxcert_in), - (u8 *)&verify_rxcert_out, - sizeof(verify_rxcert_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed: %zd\n", byte); - return byte; - } - - if (verify_rxcert_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", - WIRED_VERIFY_RECEIVER_CERT, - verify_rxcert_out.header.status); - return -EIO; - } - - *km_stored = !!verify_rxcert_out.km_stored; - if (verify_rxcert_out.km_stored) { - ek_pub_km->msg_id = HDCP_2_2_AKE_STORED_KM; - *msg_sz = sizeof(struct hdcp2_ake_stored_km); - } else { - ek_pub_km->msg_id = HDCP_2_2_AKE_NO_STORED_KM; - *msg_sz = sizeof(struct hdcp2_ake_no_stored_km); - } - - memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff, - sizeof(verify_rxcert_out.ekm_buff)); - - return 0; -} - -static int -gsc_hdcp_verify_hprime(struct device *dev, struct hdcp_port_data *data, - struct hdcp2_ake_send_hprime *rx_hprime) -{ - struct wired_cmd_ake_send_hprime_in send_hprime_in = { { 0 } }; - struct wired_cmd_ake_send_hprime_out send_hprime_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !rx_hprime) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - send_hprime_in.header.api_version = HDCP_API_VERSION; - send_hprime_in.header.command_id = WIRED_AKE_SEND_HPRIME; - send_hprime_in.header.status = FW_HDCP_STATUS_SUCCESS; - send_hprime_in.header.buffer_len = WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN; - - send_hprime_in.port.integrated_port_type = data->port_type; - send_hprime_in.port.physical_port = (u8)data->hdcp_ddi; - send_hprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - memcpy(send_hprime_in.h_prime, rx_hprime->h_prime, - HDCP_2_2_H_PRIME_LEN); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&send_hprime_in, - sizeof(send_hprime_in), - (u8 *)&send_hprime_out, - sizeof(send_hprime_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (send_hprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", - WIRED_AKE_SEND_HPRIME, send_hprime_out.header.status); - return -EIO; - } - - return 0; -} - -static int -gsc_hdcp_store_pairing_info(struct device *dev, struct hdcp_port_data *data, - struct hdcp2_ake_send_pairing_info *pairing_info) -{ - struct wired_cmd_ake_send_pairing_info_in pairing_info_in = { { 0 } }; - struct wired_cmd_ake_send_pairing_info_out pairing_info_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !pairing_info) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - pairing_info_in.header.api_version = HDCP_API_VERSION; - pairing_info_in.header.command_id = WIRED_AKE_SEND_PAIRING_INFO; - pairing_info_in.header.status = FW_HDCP_STATUS_SUCCESS; - pairing_info_in.header.buffer_len = - WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN; - - pairing_info_in.port.integrated_port_type = data->port_type; - pairing_info_in.port.physical_port = (u8)data->hdcp_ddi; - pairing_info_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - memcpy(pairing_info_in.e_kh_km, pairing_info->e_kh_km, - HDCP_2_2_E_KH_KM_LEN); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&pairing_info_in, - sizeof(pairing_info_in), - (u8 *)&pairing_info_out, - sizeof(pairing_info_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (pairing_info_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. Status: 0x%X\n", - WIRED_AKE_SEND_PAIRING_INFO, - pairing_info_out.header.status); - return -EIO; - } - - return 0; -} - -static int -gsc_hdcp_initiate_locality_check(struct device *dev, - struct hdcp_port_data *data, - struct hdcp2_lc_init *lc_init_data) -{ - struct wired_cmd_init_locality_check_in lc_init_in = { { 0 } }; - struct wired_cmd_init_locality_check_out lc_init_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !lc_init_data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - lc_init_in.header.api_version = HDCP_API_VERSION; - lc_init_in.header.command_id = WIRED_INIT_LOCALITY_CHECK; - lc_init_in.header.status = FW_HDCP_STATUS_SUCCESS; - lc_init_in.header.buffer_len = WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN; - - lc_init_in.port.integrated_port_type = data->port_type; - lc_init_in.port.physical_port = (u8)data->hdcp_ddi; - lc_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&lc_init_in, sizeof(lc_init_in), - (u8 *)&lc_init_out, sizeof(lc_init_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (lc_init_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. status: 0x%X\n", - WIRED_INIT_LOCALITY_CHECK, lc_init_out.header.status); - return -EIO; - } - - lc_init_data->msg_id = HDCP_2_2_LC_INIT; - memcpy(lc_init_data->r_n, lc_init_out.r_n, HDCP_2_2_RN_LEN); - - return 0; -} - -static int -gsc_hdcp_verify_lprime(struct device *dev, struct hdcp_port_data *data, - struct hdcp2_lc_send_lprime *rx_lprime) -{ - struct wired_cmd_validate_locality_in verify_lprime_in = { { 0 } }; - struct wired_cmd_validate_locality_out verify_lprime_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !rx_lprime) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - verify_lprime_in.header.api_version = HDCP_API_VERSION; - verify_lprime_in.header.command_id = WIRED_VALIDATE_LOCALITY; - verify_lprime_in.header.status = FW_HDCP_STATUS_SUCCESS; - verify_lprime_in.header.buffer_len = - WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN; - - verify_lprime_in.port.integrated_port_type = data->port_type; - verify_lprime_in.port.physical_port = (u8)data->hdcp_ddi; - verify_lprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - memcpy(verify_lprime_in.l_prime, rx_lprime->l_prime, - HDCP_2_2_L_PRIME_LEN); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_lprime_in, - sizeof(verify_lprime_in), - (u8 *)&verify_lprime_out, - sizeof(verify_lprime_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (verify_lprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", - WIRED_VALIDATE_LOCALITY, - verify_lprime_out.header.status); - return -EIO; - } - - return 0; -} - -static int gsc_hdcp_get_session_key(struct device *dev, - struct hdcp_port_data *data, - struct hdcp2_ske_send_eks *ske_data) -{ - struct wired_cmd_get_session_key_in get_skey_in = { { 0 } }; - struct wired_cmd_get_session_key_out get_skey_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data || !ske_data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - get_skey_in.header.api_version = HDCP_API_VERSION; - get_skey_in.header.command_id = WIRED_GET_SESSION_KEY; - get_skey_in.header.status = FW_HDCP_STATUS_SUCCESS; - get_skey_in.header.buffer_len = WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN; - - get_skey_in.port.integrated_port_type = data->port_type; - get_skey_in.port.physical_port = (u8)data->hdcp_ddi; - get_skey_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&get_skey_in, sizeof(get_skey_in), - (u8 *)&get_skey_out, sizeof(get_skey_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (get_skey_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", - WIRED_GET_SESSION_KEY, get_skey_out.header.status); - return -EIO; - } - - ske_data->msg_id = HDCP_2_2_SKE_SEND_EKS; - memcpy(ske_data->e_dkey_ks, get_skey_out.e_dkey_ks, - HDCP_2_2_E_DKEY_KS_LEN); - memcpy(ske_data->riv, get_skey_out.r_iv, HDCP_2_2_RIV_LEN); - - return 0; -} - -static int -gsc_hdcp_repeater_check_flow_prepare_ack(struct device *dev, - struct hdcp_port_data *data, - struct hdcp2_rep_send_receiverid_list - *rep_topology, - struct hdcp2_rep_send_ack - *rep_send_ack) -{ - struct wired_cmd_verify_repeater_in verify_repeater_in = { { 0 } }; - struct wired_cmd_verify_repeater_out verify_repeater_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !rep_topology || !rep_send_ack || !data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - verify_repeater_in.header.api_version = HDCP_API_VERSION; - verify_repeater_in.header.command_id = WIRED_VERIFY_REPEATER; - verify_repeater_in.header.status = FW_HDCP_STATUS_SUCCESS; - verify_repeater_in.header.buffer_len = - WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN; - - verify_repeater_in.port.integrated_port_type = data->port_type; - verify_repeater_in.port.physical_port = (u8)data->hdcp_ddi; - verify_repeater_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - memcpy(verify_repeater_in.rx_info, rep_topology->rx_info, - HDCP_2_2_RXINFO_LEN); - memcpy(verify_repeater_in.seq_num_v, rep_topology->seq_num_v, - HDCP_2_2_SEQ_NUM_LEN); - memcpy(verify_repeater_in.v_prime, rep_topology->v_prime, - HDCP_2_2_V_PRIME_HALF_LEN); - memcpy(verify_repeater_in.receiver_ids, rep_topology->receiver_ids, - HDCP_2_2_RECEIVER_IDS_MAX_LEN); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_repeater_in, - sizeof(verify_repeater_in), - (u8 *)&verify_repeater_out, - sizeof(verify_repeater_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (verify_repeater_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", - WIRED_VERIFY_REPEATER, - verify_repeater_out.header.status); - return -EIO; - } - - memcpy(rep_send_ack->v, verify_repeater_out.v, - HDCP_2_2_V_PRIME_HALF_LEN); - rep_send_ack->msg_id = HDCP_2_2_REP_SEND_ACK; - - return 0; -} - -static int gsc_hdcp_verify_mprime(struct device *dev, - struct hdcp_port_data *data, - struct hdcp2_rep_stream_ready *stream_ready) -{ - struct wired_cmd_repeater_auth_stream_req_in *verify_mprime_in; - struct wired_cmd_repeater_auth_stream_req_out - verify_mprime_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - size_t cmd_size; - - if (!dev || !stream_ready || !data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - cmd_size = struct_size(verify_mprime_in, streams, data->k); - if (cmd_size == SIZE_MAX) - return -EINVAL; - - verify_mprime_in = kzalloc(cmd_size, GFP_KERNEL); - if (!verify_mprime_in) - return -ENOMEM; - - verify_mprime_in->header.api_version = HDCP_API_VERSION; - verify_mprime_in->header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ; - verify_mprime_in->header.status = FW_HDCP_STATUS_SUCCESS; - verify_mprime_in->header.buffer_len = cmd_size - sizeof(verify_mprime_in->header); - - verify_mprime_in->port.integrated_port_type = data->port_type; - verify_mprime_in->port.physical_port = (u8)data->hdcp_ddi; - verify_mprime_in->port.attached_transcoder = (u8)data->hdcp_transcoder; - - memcpy(verify_mprime_in->m_prime, stream_ready->m_prime, HDCP_2_2_MPRIME_LEN); - drm_hdcp_cpu_to_be24(verify_mprime_in->seq_num_m, data->seq_num_m); - - memcpy(verify_mprime_in->streams, data->streams, - array_size(data->k, sizeof(*data->streams))); - - verify_mprime_in->k = cpu_to_be16(data->k); - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)verify_mprime_in, cmd_size, - (u8 *)&verify_mprime_out, - sizeof(verify_mprime_out)); - kfree(verify_mprime_in); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (verify_mprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", - WIRED_REPEATER_AUTH_STREAM_REQ, - verify_mprime_out.header.status); - return -EIO; - } - - return 0; -} - -static int gsc_hdcp_enable_authentication(struct device *dev, - struct hdcp_port_data *data) -{ - struct wired_cmd_enable_auth_in enable_auth_in = { { 0 } }; - struct wired_cmd_enable_auth_out enable_auth_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - enable_auth_in.header.api_version = HDCP_API_VERSION; - enable_auth_in.header.command_id = WIRED_ENABLE_AUTH; - enable_auth_in.header.status = FW_HDCP_STATUS_SUCCESS; - enable_auth_in.header.buffer_len = WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN; - - enable_auth_in.port.integrated_port_type = data->port_type; - enable_auth_in.port.physical_port = (u8)data->hdcp_ddi; - enable_auth_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - enable_auth_in.stream_type = data->streams[0].stream_type; - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&enable_auth_in, - sizeof(enable_auth_in), - (u8 *)&enable_auth_out, - sizeof(enable_auth_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } - - if (enable_auth_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", - WIRED_ENABLE_AUTH, enable_auth_out.header.status); - return -EIO; - } - - return 0; -} - -static int -gsc_hdcp_close_session(struct device *dev, struct hdcp_port_data *data) -{ - struct wired_cmd_close_session_in session_close_in = { { 0 } }; - struct wired_cmd_close_session_out session_close_out = { { 0 } }; - struct drm_i915_private *i915; - ssize_t byte; - - if (!dev || !data) - return -EINVAL; - - i915 = kdev_to_i915(dev); - if (!i915) { - dev_err(dev, "DRM not initialized, aborting HDCP.\n"); - return -ENODEV; - } - - session_close_in.header.api_version = HDCP_API_VERSION; - session_close_in.header.command_id = WIRED_CLOSE_SESSION; - session_close_in.header.status = FW_HDCP_STATUS_SUCCESS; - session_close_in.header.buffer_len = - WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN; - - session_close_in.port.integrated_port_type = data->port_type; - session_close_in.port.physical_port = (u8)data->hdcp_ddi; - session_close_in.port.attached_transcoder = (u8)data->hdcp_transcoder; - - byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&session_close_in, - sizeof(session_close_in), - (u8 *)&session_close_out, - sizeof(session_close_out)); - if (byte < 0) { - drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); - return byte; - } + struct intel_gt *gt = i915->media_gt; + struct intel_gsc_uc *gsc = gt ? >->uc.gsc : NULL; - if (session_close_out.header.status != FW_HDCP_STATUS_SUCCESS) { - drm_dbg_kms(&i915->drm, "Session Close Failed. status: 0x%X\n", - session_close_out.header.status); - return -EIO; + if (!gsc || !intel_uc_fw_is_running(&gsc->fw)) { + drm_dbg_kms(&i915->drm, + "GSC components required for HDCP2.2 are not ready\n"); + return false; } - return 0; + return true; } -static const struct i915_hdcp_ops gsc_hdcp_ops = { - .initiate_hdcp2_session = gsc_hdcp_initiate_session, - .verify_receiver_cert_prepare_km = - gsc_hdcp_verify_receiver_cert_prepare_km, - .verify_hprime = gsc_hdcp_verify_hprime, - .store_pairing_info = gsc_hdcp_store_pairing_info, - .initiate_locality_check = gsc_hdcp_initiate_locality_check, - .verify_lprime = gsc_hdcp_verify_lprime, - .get_session_key = gsc_hdcp_get_session_key, - .repeater_check_flow_prepare_ack = - gsc_hdcp_repeater_check_flow_prepare_ack, - .verify_mprime = gsc_hdcp_verify_mprime, - .enable_hdcp_authentication = gsc_hdcp_enable_authentication, - .close_hdcp_session = gsc_hdcp_close_session, -}; - /*This function helps allocate memory for the command that we will send to gsc cs */ static int intel_hdcp_gsc_initialize_message(struct drm_i915_private *i915, struct intel_hdcp_gsc_message *hdcp_message) @@ -667,6 +84,22 @@ out_unpin: return err; } +static const struct i915_hdcp_ops gsc_hdcp_ops = { + .initiate_hdcp2_session = intel_hdcp_gsc_initiate_session, + .verify_receiver_cert_prepare_km = + intel_hdcp_gsc_verify_receiver_cert_prepare_km, + .verify_hprime = intel_hdcp_gsc_verify_hprime, + .store_pairing_info = intel_hdcp_gsc_store_pairing_info, + .initiate_locality_check = intel_hdcp_gsc_initiate_locality_check, + .verify_lprime = intel_hdcp_gsc_verify_lprime, + .get_session_key = intel_hdcp_gsc_get_session_key, + .repeater_check_flow_prepare_ack = + intel_hdcp_gsc_repeater_check_flow_prepare_ack, + .verify_mprime = intel_hdcp_gsc_verify_mprime, + .enable_hdcp_authentication = intel_hdcp_gsc_enable_authentication, + .close_hdcp_session = intel_hdcp_gsc_close_session, +}; + static int intel_hdcp_gsc_hdcp2_init(struct drm_i915_private *i915) { struct intel_hdcp_gsc_message *hdcp_message; diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h index cbf96551e5..eba2057c5a 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h +++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc.h @@ -23,5 +23,6 @@ ssize_t intel_hdcp_gsc_msg_send(struct drm_i915_private *i915, u8 *msg_in, size_t msg_out_len); int intel_hdcp_gsc_init(struct drm_i915_private *i915); void intel_hdcp_gsc_fini(struct drm_i915_private *i915); +bool intel_hdcp_gsc_check_status(struct drm_i915_private *i915); #endif /* __INTEL_HDCP_GCS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c b/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c new file mode 100644 index 0000000000..240b00849f --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.c @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2023, Intel Corporation. + */ + +#include <linux/err.h> +#include <drm/i915_hdcp_interface.h> + +#include "i915_drv.h" +#include "intel_hdcp_gsc_message.h" + +int +intel_hdcp_gsc_initiate_session(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_init *ake_data) +{ + struct wired_cmd_initiate_hdcp2_session_in session_init_in = {}; + struct wired_cmd_initiate_hdcp2_session_out session_init_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !ake_data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + session_init_in.header.api_version = HDCP_API_VERSION; + session_init_in.header.command_id = WIRED_INITIATE_HDCP2_SESSION; + session_init_in.header.status = FW_HDCP_STATUS_SUCCESS; + session_init_in.header.buffer_len = + WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN; + + session_init_in.port.integrated_port_type = data->port_type; + session_init_in.port.physical_port = (u8)data->hdcp_ddi; + session_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + session_init_in.protocol = data->protocol; + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&session_init_in, + sizeof(session_init_in), + (u8 *)&session_init_out, + sizeof(session_init_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (session_init_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", + WIRED_INITIATE_HDCP2_SESSION, + session_init_out.header.status); + return -EIO; + } + + ake_data->msg_id = HDCP_2_2_AKE_INIT; + ake_data->tx_caps = session_init_out.tx_caps; + memcpy(ake_data->r_tx, session_init_out.r_tx, HDCP_2_2_RTX_LEN); + + return 0; +} + +int +intel_hdcp_gsc_verify_receiver_cert_prepare_km(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_ake_send_cert *rx_cert, + bool *km_stored, + struct hdcp2_ake_no_stored_km + *ek_pub_km, + size_t *msg_sz) +{ + struct wired_cmd_verify_receiver_cert_in verify_rxcert_in = {}; + struct wired_cmd_verify_receiver_cert_out verify_rxcert_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + verify_rxcert_in.header.api_version = HDCP_API_VERSION; + verify_rxcert_in.header.command_id = WIRED_VERIFY_RECEIVER_CERT; + verify_rxcert_in.header.status = FW_HDCP_STATUS_SUCCESS; + verify_rxcert_in.header.buffer_len = + WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN; + + verify_rxcert_in.port.integrated_port_type = data->port_type; + verify_rxcert_in.port.physical_port = (u8)data->hdcp_ddi; + verify_rxcert_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + verify_rxcert_in.cert_rx = rx_cert->cert_rx; + memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, HDCP_2_2_RRX_LEN); + memcpy(verify_rxcert_in.rx_caps, rx_cert->rx_caps, HDCP_2_2_RXCAPS_LEN); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_rxcert_in, + sizeof(verify_rxcert_in), + (u8 *)&verify_rxcert_out, + sizeof(verify_rxcert_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed: %zd\n", byte); + return byte; + } + + if (verify_rxcert_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", + WIRED_VERIFY_RECEIVER_CERT, + verify_rxcert_out.header.status); + return -EIO; + } + + *km_stored = !!verify_rxcert_out.km_stored; + if (verify_rxcert_out.km_stored) { + ek_pub_km->msg_id = HDCP_2_2_AKE_STORED_KM; + *msg_sz = sizeof(struct hdcp2_ake_stored_km); + } else { + ek_pub_km->msg_id = HDCP_2_2_AKE_NO_STORED_KM; + *msg_sz = sizeof(struct hdcp2_ake_no_stored_km); + } + + memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff, + sizeof(verify_rxcert_out.ekm_buff)); + + return 0; +} + +int +intel_hdcp_gsc_verify_hprime(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_send_hprime *rx_hprime) +{ + struct wired_cmd_ake_send_hprime_in send_hprime_in = {}; + struct wired_cmd_ake_send_hprime_out send_hprime_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !rx_hprime) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + send_hprime_in.header.api_version = HDCP_API_VERSION; + send_hprime_in.header.command_id = WIRED_AKE_SEND_HPRIME; + send_hprime_in.header.status = FW_HDCP_STATUS_SUCCESS; + send_hprime_in.header.buffer_len = WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN; + + send_hprime_in.port.integrated_port_type = data->port_type; + send_hprime_in.port.physical_port = (u8)data->hdcp_ddi; + send_hprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + memcpy(send_hprime_in.h_prime, rx_hprime->h_prime, + HDCP_2_2_H_PRIME_LEN); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&send_hprime_in, + sizeof(send_hprime_in), + (u8 *)&send_hprime_out, + sizeof(send_hprime_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (send_hprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. Status: 0x%X\n", + WIRED_AKE_SEND_HPRIME, send_hprime_out.header.status); + return -EIO; + } + + return 0; +} + +int +intel_hdcp_gsc_store_pairing_info(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_send_pairing_info *pairing_info) +{ + struct wired_cmd_ake_send_pairing_info_in pairing_info_in = {}; + struct wired_cmd_ake_send_pairing_info_out pairing_info_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !pairing_info) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + pairing_info_in.header.api_version = HDCP_API_VERSION; + pairing_info_in.header.command_id = WIRED_AKE_SEND_PAIRING_INFO; + pairing_info_in.header.status = FW_HDCP_STATUS_SUCCESS; + pairing_info_in.header.buffer_len = + WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN; + + pairing_info_in.port.integrated_port_type = data->port_type; + pairing_info_in.port.physical_port = (u8)data->hdcp_ddi; + pairing_info_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + memcpy(pairing_info_in.e_kh_km, pairing_info->e_kh_km, + HDCP_2_2_E_KH_KM_LEN); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&pairing_info_in, + sizeof(pairing_info_in), + (u8 *)&pairing_info_out, + sizeof(pairing_info_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (pairing_info_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. Status: 0x%X\n", + WIRED_AKE_SEND_PAIRING_INFO, + pairing_info_out.header.status); + return -EIO; + } + + return 0; +} + +int +intel_hdcp_gsc_initiate_locality_check(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_lc_init *lc_init_data) +{ + struct wired_cmd_init_locality_check_in lc_init_in = {}; + struct wired_cmd_init_locality_check_out lc_init_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !lc_init_data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + lc_init_in.header.api_version = HDCP_API_VERSION; + lc_init_in.header.command_id = WIRED_INIT_LOCALITY_CHECK; + lc_init_in.header.status = FW_HDCP_STATUS_SUCCESS; + lc_init_in.header.buffer_len = WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN; + + lc_init_in.port.integrated_port_type = data->port_type; + lc_init_in.port.physical_port = (u8)data->hdcp_ddi; + lc_init_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&lc_init_in, sizeof(lc_init_in), + (u8 *)&lc_init_out, sizeof(lc_init_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (lc_init_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X Failed. status: 0x%X\n", + WIRED_INIT_LOCALITY_CHECK, lc_init_out.header.status); + return -EIO; + } + + lc_init_data->msg_id = HDCP_2_2_LC_INIT; + memcpy(lc_init_data->r_n, lc_init_out.r_n, HDCP_2_2_RN_LEN); + + return 0; +} + +int +intel_hdcp_gsc_verify_lprime(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_lc_send_lprime *rx_lprime) +{ + struct wired_cmd_validate_locality_in verify_lprime_in = {}; + struct wired_cmd_validate_locality_out verify_lprime_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !rx_lprime) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + verify_lprime_in.header.api_version = HDCP_API_VERSION; + verify_lprime_in.header.command_id = WIRED_VALIDATE_LOCALITY; + verify_lprime_in.header.status = FW_HDCP_STATUS_SUCCESS; + verify_lprime_in.header.buffer_len = + WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN; + + verify_lprime_in.port.integrated_port_type = data->port_type; + verify_lprime_in.port.physical_port = (u8)data->hdcp_ddi; + verify_lprime_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + memcpy(verify_lprime_in.l_prime, rx_lprime->l_prime, + HDCP_2_2_L_PRIME_LEN); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_lprime_in, + sizeof(verify_lprime_in), + (u8 *)&verify_lprime_out, + sizeof(verify_lprime_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (verify_lprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", + WIRED_VALIDATE_LOCALITY, + verify_lprime_out.header.status); + return -EIO; + } + + return 0; +} + +int intel_hdcp_gsc_get_session_key(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_ske_send_eks *ske_data) +{ + struct wired_cmd_get_session_key_in get_skey_in = {}; + struct wired_cmd_get_session_key_out get_skey_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data || !ske_data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + get_skey_in.header.api_version = HDCP_API_VERSION; + get_skey_in.header.command_id = WIRED_GET_SESSION_KEY; + get_skey_in.header.status = FW_HDCP_STATUS_SUCCESS; + get_skey_in.header.buffer_len = WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN; + + get_skey_in.port.integrated_port_type = data->port_type; + get_skey_in.port.physical_port = (u8)data->hdcp_ddi; + get_skey_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&get_skey_in, sizeof(get_skey_in), + (u8 *)&get_skey_out, sizeof(get_skey_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (get_skey_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", + WIRED_GET_SESSION_KEY, get_skey_out.header.status); + return -EIO; + } + + ske_data->msg_id = HDCP_2_2_SKE_SEND_EKS; + memcpy(ske_data->e_dkey_ks, get_skey_out.e_dkey_ks, + HDCP_2_2_E_DKEY_KS_LEN); + memcpy(ske_data->riv, get_skey_out.r_iv, HDCP_2_2_RIV_LEN); + + return 0; +} + +int +intel_hdcp_gsc_repeater_check_flow_prepare_ack(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_rep_send_receiverid_list + *rep_topology, + struct hdcp2_rep_send_ack + *rep_send_ack) +{ + struct wired_cmd_verify_repeater_in verify_repeater_in = {}; + struct wired_cmd_verify_repeater_out verify_repeater_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !rep_topology || !rep_send_ack || !data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + verify_repeater_in.header.api_version = HDCP_API_VERSION; + verify_repeater_in.header.command_id = WIRED_VERIFY_REPEATER; + verify_repeater_in.header.status = FW_HDCP_STATUS_SUCCESS; + verify_repeater_in.header.buffer_len = + WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN; + + verify_repeater_in.port.integrated_port_type = data->port_type; + verify_repeater_in.port.physical_port = (u8)data->hdcp_ddi; + verify_repeater_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + memcpy(verify_repeater_in.rx_info, rep_topology->rx_info, + HDCP_2_2_RXINFO_LEN); + memcpy(verify_repeater_in.seq_num_v, rep_topology->seq_num_v, + HDCP_2_2_SEQ_NUM_LEN); + memcpy(verify_repeater_in.v_prime, rep_topology->v_prime, + HDCP_2_2_V_PRIME_HALF_LEN); + memcpy(verify_repeater_in.receiver_ids, rep_topology->receiver_ids, + HDCP_2_2_RECEIVER_IDS_MAX_LEN); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&verify_repeater_in, + sizeof(verify_repeater_in), + (u8 *)&verify_repeater_out, + sizeof(verify_repeater_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (verify_repeater_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", + WIRED_VERIFY_REPEATER, + verify_repeater_out.header.status); + return -EIO; + } + + memcpy(rep_send_ack->v, verify_repeater_out.v, + HDCP_2_2_V_PRIME_HALF_LEN); + rep_send_ack->msg_id = HDCP_2_2_REP_SEND_ACK; + + return 0; +} + +int intel_hdcp_gsc_verify_mprime(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_rep_stream_ready *stream_ready) +{ + struct wired_cmd_repeater_auth_stream_req_in *verify_mprime_in; + struct wired_cmd_repeater_auth_stream_req_out verify_mprime_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + size_t cmd_size; + + if (!dev || !stream_ready || !data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + cmd_size = struct_size(verify_mprime_in, streams, data->k); + if (cmd_size == SIZE_MAX) + return -EINVAL; + + verify_mprime_in = kzalloc(cmd_size, GFP_KERNEL); + if (!verify_mprime_in) + return -ENOMEM; + + verify_mprime_in->header.api_version = HDCP_API_VERSION; + verify_mprime_in->header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ; + verify_mprime_in->header.status = FW_HDCP_STATUS_SUCCESS; + verify_mprime_in->header.buffer_len = cmd_size - sizeof(verify_mprime_in->header); + + verify_mprime_in->port.integrated_port_type = data->port_type; + verify_mprime_in->port.physical_port = (u8)data->hdcp_ddi; + verify_mprime_in->port.attached_transcoder = (u8)data->hdcp_transcoder; + + memcpy(verify_mprime_in->m_prime, stream_ready->m_prime, HDCP_2_2_MPRIME_LEN); + drm_hdcp_cpu_to_be24(verify_mprime_in->seq_num_m, data->seq_num_m); + + memcpy(verify_mprime_in->streams, data->streams, + array_size(data->k, sizeof(*data->streams))); + + verify_mprime_in->k = cpu_to_be16(data->k); + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)verify_mprime_in, cmd_size, + (u8 *)&verify_mprime_out, + sizeof(verify_mprime_out)); + kfree(verify_mprime_in); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (verify_mprime_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", + WIRED_REPEATER_AUTH_STREAM_REQ, + verify_mprime_out.header.status); + return -EIO; + } + + return 0; +} + +int intel_hdcp_gsc_enable_authentication(struct device *dev, + struct hdcp_port_data *data) +{ + struct wired_cmd_enable_auth_in enable_auth_in = {}; + struct wired_cmd_enable_auth_out enable_auth_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + enable_auth_in.header.api_version = HDCP_API_VERSION; + enable_auth_in.header.command_id = WIRED_ENABLE_AUTH; + enable_auth_in.header.status = FW_HDCP_STATUS_SUCCESS; + enable_auth_in.header.buffer_len = WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN; + + enable_auth_in.port.integrated_port_type = data->port_type; + enable_auth_in.port.physical_port = (u8)data->hdcp_ddi; + enable_auth_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + enable_auth_in.stream_type = data->streams[0].stream_type; + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&enable_auth_in, + sizeof(enable_auth_in), + (u8 *)&enable_auth_out, + sizeof(enable_auth_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (enable_auth_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "FW cmd 0x%08X failed. status: 0x%X\n", + WIRED_ENABLE_AUTH, enable_auth_out.header.status); + return -EIO; + } + + return 0; +} + +int +intel_hdcp_gsc_close_session(struct device *dev, struct hdcp_port_data *data) +{ + struct wired_cmd_close_session_in session_close_in = {}; + struct wired_cmd_close_session_out session_close_out = {}; + struct drm_i915_private *i915; + ssize_t byte; + + if (!dev || !data) + return -EINVAL; + + i915 = kdev_to_i915(dev); + if (!i915) { + dev_err(dev, "DRM not initialized, aborting HDCP.\n"); + return -ENODEV; + } + + session_close_in.header.api_version = HDCP_API_VERSION; + session_close_in.header.command_id = WIRED_CLOSE_SESSION; + session_close_in.header.status = FW_HDCP_STATUS_SUCCESS; + session_close_in.header.buffer_len = + WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN; + + session_close_in.port.integrated_port_type = data->port_type; + session_close_in.port.physical_port = (u8)data->hdcp_ddi; + session_close_in.port.attached_transcoder = (u8)data->hdcp_transcoder; + + byte = intel_hdcp_gsc_msg_send(i915, (u8 *)&session_close_in, + sizeof(session_close_in), + (u8 *)&session_close_out, + sizeof(session_close_out)); + if (byte < 0) { + drm_dbg_kms(&i915->drm, "intel_hdcp_gsc_msg_send failed. %zd\n", byte); + return byte; + } + + if (session_close_out.header.status != FW_HDCP_STATUS_SUCCESS) { + drm_dbg_kms(&i915->drm, "Session Close Failed. status: 0x%X\n", + session_close_out.header.status); + return -EIO; + } + + return 0; +} diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.h b/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.h new file mode 100644 index 0000000000..ce199d6f62 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_hdcp_gsc_message.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_HDCP_GSC_MESSAGE_H__ +#define __INTEL_HDCP_GSC_MESSAGE_H__ + +#include <linux/types.h> + +struct device; +struct drm_i915_private; +struct hdcp_port_data; +struct hdcp2_ake_init; +struct hdcp2_ake_send_cert; +struct hdcp2_ake_no_stored_km; +struct hdcp2_ake_send_hprime; +struct hdcp2_ake_send_pairing_info; +struct hdcp2_lc_init; +struct hdcp2_lc_send_lprime; +struct hdcp2_ske_send_eks; +struct hdcp2_rep_send_receiverid_list; +struct hdcp2_rep_send_ack; +struct hdcp2_rep_stream_ready; + +ssize_t intel_hdcp_gsc_msg_send(struct drm_i915_private *i915, u8 *msg_in, + size_t msg_in_len, u8 *msg_out, + size_t msg_out_len); +bool intel_hdcp_gsc_check_status(struct drm_i915_private *i915); +int +intel_hdcp_gsc_initiate_session(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_init *ake_data); +int +intel_hdcp_gsc_verify_receiver_cert_prepare_km(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_ake_send_cert *rx_cert, + bool *km_stored, + struct hdcp2_ake_no_stored_km + *ek_pub_km, + size_t *msg_sz); +int +intel_hdcp_gsc_verify_hprime(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_send_hprime *rx_hprime); +int +intel_hdcp_gsc_store_pairing_info(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_ake_send_pairing_info *pairing_info); +int +intel_hdcp_gsc_initiate_locality_check(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_lc_init *lc_init_data); +int +intel_hdcp_gsc_verify_lprime(struct device *dev, struct hdcp_port_data *data, + struct hdcp2_lc_send_lprime *rx_lprime); +int intel_hdcp_gsc_get_session_key(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_ske_send_eks *ske_data); +int +intel_hdcp_gsc_repeater_check_flow_prepare_ack(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_rep_send_receiverid_list + *rep_topology, + struct hdcp2_rep_send_ack + *rep_send_ack); +int intel_hdcp_gsc_verify_mprime(struct device *dev, + struct hdcp_port_data *data, + struct hdcp2_rep_stream_ready *stream_ready); +int intel_hdcp_gsc_enable_authentication(struct device *dev, + struct hdcp_port_data *data); +int +intel_hdcp_gsc_close_session(struct device *dev, struct hdcp_port_data *data); + +#endif /* __INTEL_HDCP_GSC_MESSAGE_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index bc975918e0..bfa456fa7d 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -1240,26 +1240,23 @@ static void hsw_set_infoframes(struct intel_encoder *encoder, void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable) { struct drm_i915_private *dev_priv = intel_hdmi_to_i915(hdmi); - struct i2c_adapter *adapter; + struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; if (hdmi->dp_dual_mode.type < DRM_DP_DUAL_MODE_TYPE2_DVI) return; - adapter = intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus); - drm_dbg_kms(&dev_priv->drm, "%s DP dual mode adaptor TMDS output\n", enable ? "Enabling" : "Disabling"); - drm_dp_dual_mode_set_tmds_output(&dev_priv->drm, hdmi->dp_dual_mode.type, adapter, enable); + drm_dp_dual_mode_set_tmds_output(&dev_priv->drm, + hdmi->dp_dual_mode.type, ddc, enable); } static int intel_hdmi_hdcp_read(struct intel_digital_port *dig_port, unsigned int offset, void *buffer, size_t size) { - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_hdmi *hdmi = &dig_port->hdmi; - struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915, - hdmi->ddc_bus); + struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; int ret; u8 start = offset & 0xff; struct i2c_msg msgs[] = { @@ -1276,7 +1273,7 @@ static int intel_hdmi_hdcp_read(struct intel_digital_port *dig_port, .buf = buffer } }; - ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs)); + ret = i2c_transfer(ddc, msgs, ARRAY_SIZE(msgs)); if (ret == ARRAY_SIZE(msgs)) return 0; return ret >= 0 ? -EIO : ret; @@ -1285,10 +1282,8 @@ static int intel_hdmi_hdcp_read(struct intel_digital_port *dig_port, static int intel_hdmi_hdcp_write(struct intel_digital_port *dig_port, unsigned int offset, void *buffer, size_t size) { - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_hdmi *hdmi = &dig_port->hdmi; - struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915, - hdmi->ddc_bus); + struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; int ret; u8 *write_buf; struct i2c_msg msg; @@ -1305,7 +1300,7 @@ static int intel_hdmi_hdcp_write(struct intel_digital_port *dig_port, msg.len = size + 1, msg.buf = write_buf; - ret = i2c_transfer(adapter, &msg, 1); + ret = i2c_transfer(ddc, &msg, 1); if (ret == 1) ret = 0; else if (ret >= 0) @@ -1321,8 +1316,7 @@ int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port, { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_hdmi *hdmi = &dig_port->hdmi; - struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915, - hdmi->ddc_bus); + struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; int ret; ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an, @@ -1333,7 +1327,7 @@ int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port, return ret; } - ret = intel_gmbus_output_aksv(adapter); + ret = intel_gmbus_output_aksv(ddc); if (ret < 0) { drm_dbg_kms(&i915->drm, "Failed to output aksv (%d)\n", ret); return ret; @@ -1665,9 +1659,10 @@ intel_hdmi_hdcp2_wait_for_msg(struct intel_digital_port *dig_port, } static -int intel_hdmi_hdcp2_write_msg(struct intel_digital_port *dig_port, +int intel_hdmi_hdcp2_write_msg(struct intel_connector *connector, void *buf, size_t size) { + struct intel_digital_port *dig_port = intel_attached_dig_port(connector); unsigned int offset; offset = HDCP_2_2_HDMI_REG_WR_MSG_OFFSET; @@ -1675,9 +1670,10 @@ int intel_hdmi_hdcp2_write_msg(struct intel_digital_port *dig_port, } static -int intel_hdmi_hdcp2_read_msg(struct intel_digital_port *dig_port, +int intel_hdmi_hdcp2_read_msg(struct intel_connector *connector, u8 msg_id, void *buf, size_t size) { + struct intel_digital_port *dig_port = intel_attached_dig_port(connector); struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_hdmi *hdmi = &dig_port->hdmi; struct intel_hdcp *hdcp = &hdmi->attached_connector->hdcp; @@ -1733,9 +1729,10 @@ int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port, } static -int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port, +int intel_hdmi_hdcp2_capable(struct intel_connector *connector, bool *capable) { + struct intel_digital_port *dig_port = intel_attached_dig_port(connector); u8 hdcp2_version; int ret; @@ -2404,9 +2401,10 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector) struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector)); struct intel_encoder *encoder = &hdmi_to_dig_port(hdmi)->base; - struct i2c_adapter *adapter = - intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus); - enum drm_dp_dual_mode_type type = drm_dp_dual_mode_detect(&dev_priv->drm, adapter); + struct i2c_adapter *ddc = connector->ddc; + enum drm_dp_dual_mode_type type; + + type = drm_dp_dual_mode_detect(&dev_priv->drm, ddc); /* * Type 1 DVI adaptors are not required to implement any @@ -2433,7 +2431,7 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector) hdmi->dp_dual_mode.type = type; hdmi->dp_dual_mode.max_tmds_clock = - drm_dp_dual_mode_max_tmds_clock(&dev_priv->drm, type, adapter); + drm_dp_dual_mode_max_tmds_clock(&dev_priv->drm, type, ddc); drm_dbg_kms(&dev_priv->drm, "DP dual mode adaptor (%s) detected (max TMDS clock: %d kHz)\n", @@ -2454,24 +2452,21 @@ intel_hdmi_set_edid(struct drm_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_hdmi *intel_hdmi = intel_attached_hdmi(to_intel_connector(connector)); + struct i2c_adapter *ddc = connector->ddc; intel_wakeref_t wakeref; const struct drm_edid *drm_edid; - const struct edid *edid; bool connected = false; - struct i2c_adapter *i2c; wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); - i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); + drm_edid = drm_edid_read_ddc(connector, ddc); - drm_edid = drm_edid_read_ddc(connector, i2c); - - if (!drm_edid && !intel_gmbus_is_forced_bit(i2c)) { + if (!drm_edid && !intel_gmbus_is_forced_bit(ddc)) { drm_dbg_kms(&dev_priv->drm, "HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n"); - intel_gmbus_force_bit(i2c, true); - drm_edid = drm_edid_read_ddc(connector, i2c); - intel_gmbus_force_bit(i2c, false); + intel_gmbus_force_bit(ddc, true); + drm_edid = drm_edid_read_ddc(connector, ddc); + intel_gmbus_force_bit(ddc, false); } /* Below we depend on display info having been updated */ @@ -2479,9 +2474,7 @@ intel_hdmi_set_edid(struct drm_connector *connector) to_intel_connector(connector)->detect_edid = drm_edid; - /* FIXME: Get rid of drm_edid_raw() */ - edid = drm_edid_raw(drm_edid); - if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { + if (drm_edid_is_digital(drm_edid)) { intel_hdmi_dp_dual_mode_detect(connector); connected = true; @@ -2489,7 +2482,8 @@ intel_hdmi_set_edid(struct drm_connector *connector) intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref); - cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid); + cec_notifier_set_phys_addr(intel_hdmi->cec_notifier, + connector->display_info.source_physical_address); return connected; } @@ -2506,7 +2500,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); - if (!INTEL_DISPLAY_ENABLED(dev_priv)) + if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); @@ -2526,12 +2520,6 @@ out: if (status != connector_status_connected) cec_notifier_phys_addr_invalidate(intel_hdmi->cec_notifier); - /* - * Make sure the refs for power wells enabled during detect are - * dropped to avoid a new detect cycle triggered by HPD polling. - */ - intel_display_power_flush_work(dev_priv); - return status; } @@ -2557,37 +2545,6 @@ static int intel_hdmi_get_modes(struct drm_connector *connector) return drm_edid_connector_add_modes(connector); } -static struct i2c_adapter * -intel_hdmi_get_i2c_adapter(struct drm_connector *connector) -{ - struct drm_i915_private *dev_priv = to_i915(connector->dev); - struct intel_hdmi *intel_hdmi = intel_attached_hdmi(to_intel_connector(connector)); - - return intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); -} - -static void intel_hdmi_create_i2c_symlink(struct drm_connector *connector) -{ - struct drm_i915_private *i915 = to_i915(connector->dev); - struct i2c_adapter *adapter = intel_hdmi_get_i2c_adapter(connector); - struct kobject *i2c_kobj = &adapter->dev.kobj; - struct kobject *connector_kobj = &connector->kdev->kobj; - int ret; - - ret = sysfs_create_link(connector_kobj, i2c_kobj, i2c_kobj->name); - if (ret) - drm_err(&i915->drm, "Failed to create i2c symlink (%d)\n", ret); -} - -static void intel_hdmi_remove_i2c_symlink(struct drm_connector *connector) -{ - struct i2c_adapter *adapter = intel_hdmi_get_i2c_adapter(connector); - struct kobject *i2c_kobj = &adapter->dev.kobj; - struct kobject *connector_kobj = &connector->kdev->kobj; - - sysfs_remove_link(connector_kobj, i2c_kobj->name); -} - static int intel_hdmi_connector_register(struct drm_connector *connector) { @@ -2597,8 +2554,6 @@ intel_hdmi_connector_register(struct drm_connector *connector) if (ret) return ret; - intel_hdmi_create_i2c_symlink(connector); - return ret; } @@ -2608,7 +2563,6 @@ static void intel_hdmi_connector_unregister(struct drm_connector *connector) cec_notifier_conn_unregister(n); - intel_hdmi_remove_i2c_symlink(connector); intel_connector_unregister(connector); } @@ -2922,13 +2876,17 @@ get_encoder_by_ddc_pin(struct intel_encoder *encoder, u8 ddc_pin) struct intel_encoder *other; for_each_intel_encoder(&i915->drm, other) { + struct intel_connector *connector; + if (other == encoder) continue; if (!intel_encoder_is_dig_port(other)) continue; - if (enc_to_dig_port(other)->hdmi.ddc_bus == ddc_pin) + connector = enc_to_dig_port(other)->hdmi.attached_connector; + + if (connector && connector->base.ddc == intel_gmbus_get_adapter(i915, ddc_pin)) return other; } @@ -3020,9 +2978,9 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, struct intel_encoder *intel_encoder = &dig_port->base; struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - struct i2c_adapter *ddc; enum port port = intel_encoder->port; struct cec_connector_info conn_info; + u8 ddc_pin; drm_dbg_kms(&dev_priv->drm, "Adding HDMI connector on [ENCODER:%d:%s]\n", @@ -3037,16 +2995,15 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, intel_encoder->base.name)) return; - intel_hdmi->ddc_bus = intel_hdmi_ddc_pin(intel_encoder); - if (!intel_hdmi->ddc_bus) + ddc_pin = intel_hdmi_ddc_pin(intel_encoder); + if (!ddc_pin) return; - ddc = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); - drm_connector_init_with_ddc(dev, connector, &intel_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA, - ddc); + intel_gmbus_get_adapter(dev_priv, ddc_pin)); + drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); if (DISPLAY_VER(dev_priv) < 12) diff --git a/drivers/gpu/drm/i915/display/intel_hotplug.c b/drivers/gpu/drm/i915/display/intel_hotplug.c index 69a83dcc19..0c0700c6ec 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug.c @@ -25,6 +25,7 @@ #include "i915_drv.h" #include "i915_irq.h" +#include "intel_display_power.h" #include "intel_display_types.h" #include "intel_hotplug.h" #include "intel_hotplug_irq.h" @@ -259,21 +260,22 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); } -enum intel_hotplug_state -intel_encoder_hotplug(struct intel_encoder *encoder, - struct intel_connector *connector) +static enum intel_hotplug_state +intel_hotplug_detect_connector(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; enum drm_connector_status old_status; u64 old_epoch_counter; + int status; bool ret = false; drm_WARN_ON(dev, !mutex_is_locked(&dev->mode_config.mutex)); old_status = connector->base.status; old_epoch_counter = connector->base.epoch_counter; - connector->base.status = - drm_helper_probe_detect(&connector->base, NULL, false); + status = drm_helper_probe_detect(&connector->base, NULL, false); + if (!connector->base.force) + connector->base.status = status; if (old_epoch_counter != connector->base.epoch_counter) ret = true; @@ -291,6 +293,13 @@ intel_encoder_hotplug(struct intel_encoder *encoder, return INTEL_HOTPLUG_UNCHANGED; } +enum intel_hotplug_state +intel_encoder_hotplug(struct intel_encoder *encoder, + struct intel_connector *connector) +{ + return intel_hotplug_detect_connector(connector); +} + static bool intel_encoder_has_hpd_pulse(struct intel_encoder *encoder) { return intel_encoder_is_dig_port(encoder) && @@ -631,6 +640,49 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } +static void i915_hpd_poll_detect_connectors(struct drm_i915_private *i915) +{ + struct drm_connector_list_iter conn_iter; + struct intel_connector *connector; + struct intel_connector *first_changed_connector = NULL; + int changed = 0; + + mutex_lock(&i915->drm.mode_config.mutex); + + if (!i915->drm.mode_config.poll_enabled) + goto out; + + drm_connector_list_iter_begin(&i915->drm, &conn_iter); + for_each_intel_connector_iter(connector, &conn_iter) { + if (!(connector->base.polled & DRM_CONNECTOR_POLL_HPD)) + continue; + + if (intel_hotplug_detect_connector(connector) != INTEL_HOTPLUG_CHANGED) + continue; + + changed++; + + if (changed == 1) { + drm_connector_get(&connector->base); + first_changed_connector = connector; + } + } + drm_connector_list_iter_end(&conn_iter); + +out: + mutex_unlock(&i915->drm.mode_config.mutex); + + if (!changed) + return; + + if (changed == 1) + drm_kms_helper_connector_hotplug_event(&first_changed_connector->base); + else + drm_kms_helper_hotplug_event(&i915->drm); + + drm_connector_put(&first_changed_connector->base); +} + static void i915_hpd_poll_init_work(struct work_struct *work) { struct drm_i915_private *dev_priv = @@ -638,11 +690,25 @@ static void i915_hpd_poll_init_work(struct work_struct *work) display.hotplug.poll_init_work); struct drm_connector_list_iter conn_iter; struct intel_connector *connector; + intel_wakeref_t wakeref; bool enabled; mutex_lock(&dev_priv->drm.mode_config.mutex); enabled = READ_ONCE(dev_priv->display.hotplug.poll_enabled); + /* + * Prevent taking a power reference from this sequence of + * i915_hpd_poll_init_work() -> drm_helper_hpd_irq_event() -> + * connector detect which would requeue i915_hpd_poll_init_work() + * and so risk an endless loop of this same sequence. + */ + if (!enabled) { + wakeref = intel_display_power_get(dev_priv, + POWER_DOMAIN_DISPLAY_CORE); + drm_WARN_ON(&dev_priv->drm, + READ_ONCE(dev_priv->display.hotplug.poll_enabled)); + cancel_work(&dev_priv->display.hotplug.poll_init_work); + } drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { @@ -669,8 +735,13 @@ static void i915_hpd_poll_init_work(struct work_struct *work) * We might have missed any hotplugs that happened while we were * in the middle of disabling polling */ - if (!enabled) - drm_helper_hpd_irq_event(&dev_priv->drm); + if (!enabled) { + i915_hpd_poll_detect_connectors(dev_priv); + + intel_display_power_put(dev_priv, + POWER_DOMAIN_DISPLAY_CORE, + wakeref); + } } /** @@ -692,7 +763,7 @@ static void i915_hpd_poll_init_work(struct work_struct *work) void intel_hpd_poll_enable(struct drm_i915_private *dev_priv) { if (!HAS_DISPLAY(dev_priv) || - !INTEL_DISPLAY_ENABLED(dev_priv)) + !intel_display_device_enabled(dev_priv)) return; WRITE_ONCE(dev_priv->display.hotplug.poll_enabled, true); diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c index 95a7ea94f4..f07047e9cb 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -163,7 +163,9 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv))) return; - if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) + if (INTEL_PCH_TYPE(dev_priv) >= PCH_LNL) + hpd->pch_hpd = hpd_mtp; + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) hpd->pch_hpd = hpd_sde_dg1; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTP) hpd->pch_hpd = hpd_mtp; @@ -514,6 +516,9 @@ void xelpdp_pica_irq_handler(struct drm_i915_private *i915, u32 iir) u32 trigger_aux = iir & XELPDP_AUX_TC_MASK; u32 pin_mask = 0, long_mask = 0; + if (DISPLAY_VER(i915) >= 20) + trigger_aux |= iir & XE2LPD_AUX_DDI_MASK; + for (pin = HPD_PORT_TC1; pin <= HPD_PORT_TC4; pin++) { u32 val; @@ -1060,6 +1065,19 @@ static void mtp_hpd_irq_setup(struct drm_i915_private *i915) mtp_tc_hpd_detection_setup(i915); } +static void xe2lpd_sde_hpd_irq_setup(struct drm_i915_private *i915) +{ + u32 hotplug_irqs, enabled_irqs; + + enabled_irqs = intel_hpd_enabled_irqs(i915, i915->display.hotplug.pch_hpd); + hotplug_irqs = intel_hpd_hotplug_irqs(i915, i915->display.hotplug.pch_hpd); + + ibx_display_interrupt_update(i915, hotplug_irqs, enabled_irqs); + + mtp_ddi_hpd_detection_setup(i915); + mtp_tc_hpd_detection_setup(i915); +} + static bool is_xelpdp_pica_hpd_pin(enum hpd_pin hpd_pin) { return hpd_pin >= HPD_PORT_TC1 && hpd_pin <= HPD_PORT_TC4; @@ -1119,7 +1137,9 @@ static void xelpdp_hpd_irq_setup(struct drm_i915_private *i915) xelpdp_pica_hpd_detection_setup(i915); - if (INTEL_PCH_TYPE(i915) >= PCH_MTP) + if (INTEL_PCH_TYPE(i915) >= PCH_LNL) + xe2lpd_sde_hpd_irq_setup(i915); + else if (INTEL_PCH_TYPE(i915) >= PCH_MTP) mtp_hpd_irq_setup(i915); } diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c new file mode 100644 index 0000000000..c5eb5f2425 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_link_bw.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "i915_drv.h" + +#include "intel_atomic.h" +#include "intel_display_types.h" +#include "intel_fdi.h" +#include "intel_link_bw.h" + +/** + * intel_link_bw_init_limits - initialize BW limits + * @i915: device instance + * @limits: link BW limits + * + * Initialize @limits. + */ +void intel_link_bw_init_limits(struct drm_i915_private *i915, struct intel_link_bw_limits *limits) +{ + enum pipe pipe; + + limits->bpp_limit_reached_pipes = 0; + for_each_pipe(i915, pipe) + limits->max_bpp_x16[pipe] = INT_MAX; +} + +/** + * intel_link_bw_reduce_bpp - reduce maximum link bpp for a selected pipe + * @state: atomic state + * @limits: link BW limits + * @pipe_mask: mask of pipes to select from + * @reason: explanation of why bpp reduction is needed + * + * Select the pipe from @pipe_mask with the biggest link bpp value and set the + * maximum of link bpp in @limits below this value. Modeset the selected pipe, + * so that its state will get recomputed. + * + * This function can be called to resolve a link's BW overallocation by reducing + * the link bpp of one pipe on the link and hence reducing the total link BW. + * + * Returns + * - 0 in case of success + * - %-ENOSPC if no pipe can further reduce its link bpp + * - Other negative error, if modesetting the selected pipe failed + */ +int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits, + u8 pipe_mask, + const char *reason) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + enum pipe max_bpp_pipe = INVALID_PIPE; + struct intel_crtc *crtc; + int max_bpp = 0; + + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) { + struct intel_crtc_state *crtc_state; + int link_bpp; + + if (limits->bpp_limit_reached_pipes & BIT(crtc->pipe)) + continue; + + crtc_state = intel_atomic_get_crtc_state(&state->base, + crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (crtc_state->dsc.compression_enable) + link_bpp = crtc_state->dsc.compressed_bpp; + else + /* + * TODO: for YUV420 the actual link bpp is only half + * of the pipe bpp value. The MST encoder's BW allocation + * is based on the pipe bpp value, set the actual link bpp + * limit here once the MST BW allocation is fixed. + */ + link_bpp = crtc_state->pipe_bpp; + + if (link_bpp > max_bpp) { + max_bpp = link_bpp; + max_bpp_pipe = crtc->pipe; + } + } + + if (max_bpp_pipe == INVALID_PIPE) + return -ENOSPC; + + limits->max_bpp_x16[max_bpp_pipe] = to_bpp_x16(max_bpp) - 1; + + return intel_modeset_pipes_in_mask_early(state, reason, + BIT(max_bpp_pipe)); +} + +/** + * intel_link_bw_set_bpp_limit_for_pipe - set link bpp limit for a pipe to its minimum + * @state: atomic state + * @old_limits: link BW limits + * @new_limits: link BW limits + * @pipe: pipe + * + * Set the link bpp limit for @pipe in @new_limits to its value in + * @old_limits and mark this limit as the minimum. This function must be + * called after a pipe's compute config function failed, @old_limits + * containing the bpp limit with which compute config previously passed. + * + * The function will fail if setting a minimum is not possible, either + * because the old and new limits match (and so would lead to a pipe compute + * config failure) or the limit is already at the minimum. + * + * Returns %true in case of success. + */ +bool +intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state *state, + const struct intel_link_bw_limits *old_limits, + struct intel_link_bw_limits *new_limits, + enum pipe pipe) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + + if (pipe == INVALID_PIPE) + return false; + + if (new_limits->max_bpp_x16[pipe] == + old_limits->max_bpp_x16[pipe]) + return false; + + if (drm_WARN_ON(&i915->drm, + new_limits->bpp_limit_reached_pipes & BIT(pipe))) + return false; + + new_limits->max_bpp_x16[pipe] = + old_limits->max_bpp_x16[pipe]; + new_limits->bpp_limit_reached_pipes |= BIT(pipe); + + return true; +} + +static int check_all_link_config(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits) +{ + /* TODO: Check additional shared display link configurations like MST */ + int ret; + + ret = intel_fdi_atomic_check_link(state, limits); + if (ret) + return ret; + + return 0; +} + +static bool +assert_link_limit_change_valid(struct drm_i915_private *i915, + const struct intel_link_bw_limits *old_limits, + const struct intel_link_bw_limits *new_limits) +{ + bool bpps_changed = false; + enum pipe pipe; + + for_each_pipe(i915, pipe) { + /* The bpp limit can only decrease. */ + if (drm_WARN_ON(&i915->drm, + new_limits->max_bpp_x16[pipe] > + old_limits->max_bpp_x16[pipe])) + return false; + + if (new_limits->max_bpp_x16[pipe] < + old_limits->max_bpp_x16[pipe]) + bpps_changed = true; + } + + /* At least one limit must change. */ + if (drm_WARN_ON(&i915->drm, + !bpps_changed)) + return false; + + return true; +} + +/** + * intel_link_bw_atomic_check - check display link states and set a fallback config if needed + * @state: atomic state + * @new_limits: link BW limits + * + * Check the configuration of all shared display links in @state and set new BW + * limits in @new_limits if there is a BW limitation. + * + * Returns: + * - 0 if the confugration is valid + * - %-EAGAIN, if the configuration is invalid and @new_limits got updated + * with fallback values with which the configuration of all CRTCs + * in @state must be recomputed + * - Other negative error, if the configuration is invalid without a + * fallback possibility, or the check failed for another reason + */ +int intel_link_bw_atomic_check(struct intel_atomic_state *state, + struct intel_link_bw_limits *new_limits) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_link_bw_limits old_limits = *new_limits; + int ret; + + ret = check_all_link_config(state, new_limits); + if (ret != -EAGAIN) + return ret; + + if (!assert_link_limit_change_valid(i915, &old_limits, new_limits)) + return -EINVAL; + + return -EAGAIN; +} diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.h b/drivers/gpu/drm/i915/display/intel_link_bw.h new file mode 100644 index 0000000000..e07df22a77 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_link_bw.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_LINK_BW_H__ +#define __INTEL_LINK_BW_H__ + +#include <linux/types.h> + +#include "intel_display_limits.h" + +struct drm_i915_private; + +struct intel_atomic_state; +struct intel_crtc_state; + +struct intel_link_bw_limits { + u8 bpp_limit_reached_pipes; + /* in 1/16 bpp units */ + int max_bpp_x16[I915_MAX_PIPES]; +}; + +void intel_link_bw_init_limits(struct drm_i915_private *i915, + struct intel_link_bw_limits *limits); +int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits, + u8 pipe_mask, + const char *reason); +bool intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state *state, + const struct intel_link_bw_limits *old_limits, + struct intel_link_bw_limits *new_limits, + enum pipe pipe); +int intel_link_bw_atomic_check(struct intel_atomic_state *state, + struct intel_link_bw_limits *new_limits); + +#endif diff --git a/drivers/gpu/drm/i915/display/intel_lpe_audio.h b/drivers/gpu/drm/i915/display/intel_lpe_audio.h index 0beecac267..2c5fcb6e1f 100644 --- a/drivers/gpu/drm/i915/display/intel_lpe_audio.h +++ b/drivers/gpu/drm/i915/display/intel_lpe_audio.h @@ -12,11 +12,29 @@ enum port; enum transcoder; struct drm_i915_private; +#ifdef I915 int intel_lpe_audio_init(struct drm_i915_private *dev_priv); void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv); void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv); void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder, enum port port, const void *eld, int ls_clock, bool dp_output); +#else +static inline int intel_lpe_audio_init(struct drm_i915_private *dev_priv) +{ + return -ENODEV; +} +static inline void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv) +{ +} +static inline void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv) +{ +} +static inline void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder, enum port port, + const void *eld, int ls_clock, bool dp_output) +{ +} +#endif #endif /* __INTEL_LPE_AUDIO_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.c b/drivers/gpu/drm/i915/display/intel_lspcon.c index bb3b5355a0..1d048fa985 100644 --- a/drivers/gpu/drm/i915/display/intel_lspcon.c +++ b/drivers/gpu/drm/i915/display/intel_lspcon.c @@ -144,15 +144,27 @@ static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon) struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon); struct drm_i915_private *i915 = dp_to_i915(intel_dp); enum drm_lspcon_mode current_mode; - struct i2c_adapter *adapter = &intel_dp->aux.ddc; + struct i2c_adapter *ddc = &intel_dp->aux.ddc; - if (drm_lspcon_get_mode(intel_dp->aux.drm_dev, adapter, ¤t_mode)) { + if (drm_lspcon_get_mode(intel_dp->aux.drm_dev, ddc, ¤t_mode)) { drm_dbg_kms(&i915->drm, "Error reading LSPCON mode\n"); return DRM_LSPCON_MODE_INVALID; } return current_mode; } +static int lspcon_get_mode_settle_timeout(struct intel_lspcon *lspcon) +{ + /* + * On some CometLake-based device designs the Parade PS175 takes more + * than 400ms to settle in PCON mode. 100 reboot trials on one device + * resulted in a median settle time of 440ms and a maximum of 444ms. + * Even after increasing the timeout to 500ms, 2% of devices still had + * this error. So this sets the timeout to 800ms. + */ + return lspcon->vendor == LSPCON_VENDOR_PARADE ? 800 : 400; +} + static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon, enum drm_lspcon_mode mode) { @@ -167,7 +179,8 @@ static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon, drm_dbg_kms(&i915->drm, "Waiting for LSPCON mode %s to settle\n", lspcon_mode_name(mode)); - wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode, 400); + wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode, + lspcon_get_mode_settle_timeout(lspcon)); if (current_mode != mode) drm_err(&i915->drm, "LSPCON mode hasn't settled\n"); @@ -185,9 +198,9 @@ static int lspcon_change_mode(struct intel_lspcon *lspcon, struct drm_i915_private *i915 = dp_to_i915(intel_dp); int err; enum drm_lspcon_mode current_mode; - struct i2c_adapter *adapter = &intel_dp->aux.ddc; + struct i2c_adapter *ddc = &intel_dp->aux.ddc; - err = drm_lspcon_get_mode(intel_dp->aux.drm_dev, adapter, ¤t_mode); + err = drm_lspcon_get_mode(intel_dp->aux.drm_dev, ddc, ¤t_mode); if (err) { drm_err(&i915->drm, "Error reading LSPCON mode\n"); return err; @@ -198,7 +211,7 @@ static int lspcon_change_mode(struct intel_lspcon *lspcon, return 0; } - err = drm_lspcon_set_mode(intel_dp->aux.drm_dev, adapter, mode); + err = drm_lspcon_set_mode(intel_dp->aux.drm_dev, ddc, mode); if (err < 0) { drm_err(&i915->drm, "LSPCON mode change failed\n"); return err; @@ -233,7 +246,7 @@ static bool lspcon_probe(struct intel_lspcon *lspcon) enum drm_dp_dual_mode_type adaptor_type; struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon); struct drm_i915_private *i915 = dp_to_i915(intel_dp); - struct i2c_adapter *adapter = &intel_dp->aux.ddc; + struct i2c_adapter *ddc = &intel_dp->aux.ddc; enum drm_lspcon_mode expected_mode; expected_mode = lspcon_wake_native_aux_ch(lspcon) ? @@ -244,7 +257,7 @@ static bool lspcon_probe(struct intel_lspcon *lspcon) if (retry) usleep_range(500, 1000); - adaptor_type = drm_dp_dual_mode_detect(intel_dp->aux.drm_dev, adapter); + adaptor_type = drm_dp_dual_mode_detect(intel_dp->aux.drm_dev, ddc); if (adaptor_type == DRM_DP_DUAL_MODE_LSPCON) break; } diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index dcb07d9a73..bcbdd1984f 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -430,11 +430,18 @@ static int intel_lvds_compute_config(struct intel_encoder *encoder, return -EINVAL; } + if (HAS_PCH_SPLIT(i915)) { + crtc_state->has_pch_encoder = true; + if (!intel_fdi_compute_pipe_bpp(crtc_state)) + return -EINVAL; + } + if (lvds_encoder->a3_power == LVDS_A3_POWER_UP) lvds_bpp = 8*3; else lvds_bpp = 6*3; + /* TODO: Check crtc_state->max_link_bpp_x16 instead of bw_constrained */ if (lvds_bpp != crtc_state->pipe_bpp && !crtc_state->bw_constrained) { drm_dbg_kms(&i915->drm, "forcing display bpp (was %d) to LVDS (%d)\n", @@ -458,9 +465,6 @@ static int intel_lvds_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL; - if (HAS_PCH_SPLIT(i915)) - crtc_state->has_pch_encoder = true; - ret = intel_panel_fitting(crtc_state, conn_state); if (ret) return ret; @@ -842,7 +846,7 @@ void intel_lvds_init(struct drm_i915_private *i915) struct intel_encoder *encoder; i915_reg_t lvds_reg; u32 lvds; - u8 pin; + u8 ddc_pin; /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) { @@ -869,8 +873,8 @@ void intel_lvds_init(struct drm_i915_private *i915) return; } - pin = GMBUS_PIN_PANEL; - if (!intel_bios_is_lvds_present(i915, &pin)) { + ddc_pin = GMBUS_PIN_PANEL; + if (!intel_bios_is_lvds_present(i915, &ddc_pin)) { if ((lvds & LVDS_PORT_EN) == 0) { drm_dbg_kms(&i915->drm, "LVDS is not present in VBT\n"); @@ -893,8 +897,10 @@ void intel_lvds_init(struct drm_i915_private *i915) lvds_encoder->attached_connector = connector; encoder = &lvds_encoder->base; - drm_connector_init(&i915->drm, &connector->base, &intel_lvds_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + drm_connector_init_with_ddc(&i915->drm, &connector->base, + &intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS, + intel_gmbus_get_adapter(i915, ddc_pin)); drm_encoder_init(&i915->drm, &encoder->base, &intel_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS, "LVDS"); @@ -948,13 +954,10 @@ void intel_lvds_init(struct drm_i915_private *i915) * preferred mode is the right one. */ mutex_lock(&i915->drm.mode_config.mutex); - if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC) { - drm_edid = drm_edid_read_switcheroo(&connector->base, - intel_gmbus_get_adapter(i915, pin)); - } else { - drm_edid = drm_edid_read_ddc(&connector->base, - intel_gmbus_get_adapter(i915, pin)); - } + if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC) + drm_edid = drm_edid_read_switcheroo(&connector->base, connector->base.ddc); + else + drm_edid = drm_edid_read_ddc(&connector->base, connector->base.ddc); if (drm_edid) { if (drm_edid_connector_update(&connector->base, drm_edid) || !drm_edid_connector_add_modes(&connector->base)) { diff --git a/drivers/gpu/drm/i915/display/intel_lvds.h b/drivers/gpu/drm/i915/display/intel_lvds.h index 9d3372dc50..7ad5fa9c04 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.h +++ b/drivers/gpu/drm/i915/display/intel_lvds.h @@ -13,10 +13,29 @@ enum pipe; struct drm_i915_private; +#ifdef I915 bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv, i915_reg_t lvds_reg, enum pipe *pipe); void intel_lvds_init(struct drm_i915_private *dev_priv); struct intel_encoder *intel_get_lvds_encoder(struct drm_i915_private *dev_priv); bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv); +#else +static inline bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t lvds_reg, enum pipe *pipe) +{ + return false; +} +static inline void intel_lvds_init(struct drm_i915_private *dev_priv) +{ +} +static inline struct intel_encoder *intel_get_lvds_encoder(struct drm_i915_private *dev_priv) +{ + return NULL; +} +static inline bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv) +{ + return false; +} +#endif #endif /* __INTEL_LVDS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c index 138144a65a..5e1c2c7804 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c @@ -23,8 +23,8 @@ * Cross check the actual hw state with our own modeset state tracking (and its * internal consistency). */ -static void intel_connector_verify_state(struct intel_crtc_state *crtc_state, - struct drm_connector_state *conn_state) +static void intel_connector_verify_state(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) { struct intel_connector *connector = to_intel_connector(conn_state->connector); struct drm_i915_private *i915 = to_i915(connector->base.dev); @@ -66,12 +66,12 @@ verify_connector_state(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_connector *connector; - struct drm_connector_state *new_conn_state; + const struct drm_connector_state *new_conn_state; int i; for_each_new_connector_in_state(&state->base, connector, new_conn_state, i) { struct drm_encoder *encoder = connector->encoder; - struct intel_crtc_state *crtc_state = NULL; + const struct intel_crtc_state *crtc_state = NULL; if (new_conn_state->crtc != &crtc->base) continue; @@ -86,38 +86,40 @@ verify_connector_state(struct intel_atomic_state *state, } } -static void intel_pipe_config_sanity_check(struct drm_i915_private *dev_priv, - const struct intel_crtc_state *pipe_config) +static void intel_pipe_config_sanity_check(const struct intel_crtc_state *crtc_state) { - 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->hw.adjusted_mode.crtc_clock; + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + + if (crtc_state->has_pch_encoder) { + int fdi_dotclock = intel_dotclock_calculate(intel_fdi_link_freq(i915, crtc_state), + &crtc_state->fdi_m_n); + int dotclock = crtc_state->hw.adjusted_mode.crtc_clock; /* * FDI already provided one idea for the dotclock. * Yell if the encoder disagrees. Allow for slight * rounding differences. */ - drm_WARN(&dev_priv->drm, abs(fdi_dotclock - dotclock) > 1, + drm_WARN(&i915->drm, abs(fdi_dotclock - dotclock) > 1, "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n", fdi_dotclock, dotclock); } } static void -verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_state *state) +verify_encoder_state(struct intel_atomic_state *state) { + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_encoder *encoder; struct drm_connector *connector; - struct drm_connector_state *old_conn_state, *new_conn_state; + const struct drm_connector_state *old_conn_state, *new_conn_state; int i; - for_each_intel_encoder(&dev_priv->drm, encoder) { + for_each_intel_encoder(&i915->drm, encoder) { bool enabled = false, found = false; enum pipe pipe; - drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s]\n", + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s]\n", encoder->base.base.id, encoder->base.name); @@ -132,7 +134,7 @@ verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_stat found = true; enabled = true; - I915_STATE_WARN(dev_priv, + I915_STATE_WARN(i915, new_conn_state->crtc != encoder->base.crtc, "connector's crtc doesn't match encoder crtc\n"); } @@ -140,7 +142,7 @@ verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_stat if (!found) continue; - I915_STATE_WARN(dev_priv, !!encoder->base.crtc != enabled, + I915_STATE_WARN(i915, !!encoder->base.crtc != enabled, "encoder's enabled state mismatch (expected %i, found %i)\n", !!encoder->base.crtc, enabled); @@ -148,7 +150,7 @@ verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_stat bool active; active = encoder->get_hw_state(encoder, &pipe); - I915_STATE_WARN(dev_priv, active, + I915_STATE_WARN(i915, active, "encoder detached but still enabled on pipe %c.\n", pipe_name(pipe)); } @@ -156,96 +158,98 @@ verify_encoder_state(struct drm_i915_private *dev_priv, struct intel_atomic_stat } static void -verify_crtc_state(struct intel_crtc *crtc, - struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *new_crtc_state) +verify_crtc_state(struct intel_atomic_state *state, + struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_encoder *encoder; - struct intel_crtc_state *pipe_config = old_crtc_state; - struct drm_atomic_state *state = old_crtc_state->uapi.state; + struct drm_i915_private *i915 = to_i915(dev); + const struct intel_crtc_state *sw_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + struct intel_crtc_state *hw_crtc_state; struct intel_crtc *master_crtc; + struct intel_encoder *encoder; - __drm_atomic_helper_crtc_destroy_state(&old_crtc_state->uapi); - intel_crtc_free_hw_state(old_crtc_state); - intel_crtc_state_reset(old_crtc_state, crtc); - old_crtc_state->uapi.state = state; + hw_crtc_state = intel_crtc_state_alloc(crtc); + if (!hw_crtc_state) + return; - drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s]\n", crtc->base.base.id, + drm_dbg_kms(&i915->drm, "[CRTC:%d:%s]\n", crtc->base.base.id, crtc->base.name); - pipe_config->hw.enable = new_crtc_state->hw.enable; + hw_crtc_state->hw.enable = sw_crtc_state->hw.enable; - intel_crtc_get_pipe_config(pipe_config); + intel_crtc_get_pipe_config(hw_crtc_state); /* we keep both pipes enabled on 830 */ - if (IS_I830(dev_priv) && pipe_config->hw.active) - pipe_config->hw.active = new_crtc_state->hw.active; + if (IS_I830(i915) && hw_crtc_state->hw.active) + hw_crtc_state->hw.active = sw_crtc_state->hw.active; - I915_STATE_WARN(dev_priv, - new_crtc_state->hw.active != pipe_config->hw.active, + I915_STATE_WARN(i915, + sw_crtc_state->hw.active != hw_crtc_state->hw.active, "crtc active state doesn't match with hw state (expected %i, found %i)\n", - new_crtc_state->hw.active, pipe_config->hw.active); + sw_crtc_state->hw.active, hw_crtc_state->hw.active); - I915_STATE_WARN(dev_priv, crtc->active != new_crtc_state->hw.active, + I915_STATE_WARN(i915, crtc->active != sw_crtc_state->hw.active, "transitional active state does not match atomic hw state (expected %i, found %i)\n", - new_crtc_state->hw.active, crtc->active); + sw_crtc_state->hw.active, crtc->active); - master_crtc = intel_master_crtc(new_crtc_state); + master_crtc = intel_master_crtc(sw_crtc_state); for_each_encoder_on_crtc(dev, &master_crtc->base, encoder) { enum pipe pipe; bool active; active = encoder->get_hw_state(encoder, &pipe); - I915_STATE_WARN(dev_priv, active != new_crtc_state->hw.active, + I915_STATE_WARN(i915, active != sw_crtc_state->hw.active, "[ENCODER:%i] active %i with crtc active %i\n", encoder->base.base.id, active, - new_crtc_state->hw.active); + sw_crtc_state->hw.active); - I915_STATE_WARN(dev_priv, active && master_crtc->pipe != pipe, + I915_STATE_WARN(i915, active && master_crtc->pipe != pipe, "Encoder connected to wrong pipe %c\n", pipe_name(pipe)); if (active) - intel_encoder_get_config(encoder, pipe_config); + intel_encoder_get_config(encoder, hw_crtc_state); } - if (!new_crtc_state->hw.active) - return; + if (!sw_crtc_state->hw.active) + goto destroy_state; - intel_pipe_config_sanity_check(dev_priv, pipe_config); + intel_pipe_config_sanity_check(hw_crtc_state); - if (!intel_pipe_config_compare(new_crtc_state, - pipe_config, false)) { - I915_STATE_WARN(dev_priv, 1, "pipe state doesn't match!\n"); - intel_crtc_state_dump(pipe_config, NULL, "hw state"); - intel_crtc_state_dump(new_crtc_state, NULL, "sw state"); + if (!intel_pipe_config_compare(sw_crtc_state, + hw_crtc_state, false)) { + I915_STATE_WARN(i915, 1, "pipe state doesn't match!\n"); + intel_crtc_state_dump(hw_crtc_state, NULL, "hw state"); + intel_crtc_state_dump(sw_crtc_state, NULL, "sw state"); } + +destroy_state: + intel_crtc_destroy_state(&crtc->base, &hw_crtc_state->uapi); } -void intel_modeset_verify_crtc(struct intel_crtc *crtc, - struct intel_atomic_state *state, - struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *new_crtc_state) +void intel_modeset_verify_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) { + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + if (!intel_crtc_needs_modeset(new_crtc_state) && !intel_crtc_needs_fastset(new_crtc_state)) return; - intel_wm_state_verify(crtc, new_crtc_state); + intel_wm_state_verify(state, crtc); verify_connector_state(state, crtc); - verify_crtc_state(crtc, old_crtc_state, new_crtc_state); - intel_shared_dpll_state_verify(crtc, old_crtc_state, new_crtc_state); - intel_mpllb_state_verify(state, new_crtc_state); - intel_c10pll_state_verify(state, new_crtc_state); + verify_crtc_state(state, crtc); + intel_shared_dpll_state_verify(state, crtc); + intel_mpllb_state_verify(state, crtc); + intel_c10pll_state_verify(state, crtc); } -void intel_modeset_verify_disabled(struct drm_i915_private *dev_priv, - struct intel_atomic_state *state) +void intel_modeset_verify_disabled(struct intel_atomic_state *state) { - verify_encoder_state(dev_priv, state); + verify_encoder_state(state); verify_connector_state(state, NULL); - intel_shared_dpll_verify_disabled(dev_priv); + intel_shared_dpll_verify_disabled(state); } diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.h b/drivers/gpu/drm/i915/display/intel_modeset_verify.h index 2d6fbe4f78..3bef8735cb 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.h +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.h @@ -6,16 +6,11 @@ #ifndef __INTEL_MODESET_VERIFY_H__ #define __INTEL_MODESET_VERIFY_H__ -struct drm_i915_private; struct intel_atomic_state; struct intel_crtc; -struct intel_crtc_state; -void intel_modeset_verify_crtc(struct intel_crtc *crtc, - struct intel_atomic_state *state, - struct intel_crtc_state *old_crtc_state, - struct intel_crtc_state *new_crtc_state); -void intel_modeset_verify_disabled(struct drm_i915_private *dev_priv, - struct intel_atomic_state *state); +void intel_modeset_verify_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc); +void intel_modeset_verify_disabled(struct intel_atomic_state *state); #endif /* __INTEL_MODESET_VERIFY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index 09c1aa1427..2b1392d5a9 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -29,12 +29,14 @@ #include <drm/drm_fourcc.h> #include "gem/i915_gem_internal.h" +#include "gem/i915_gem_object_frontbuffer.h" #include "gem/i915_gem_pm.h" #include "gt/intel_gpu_commands.h" #include "gt/intel_ring.h" #include "i915_drv.h" #include "i915_reg.h" +#include "intel_color_regs.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_frontbuffer.h" diff --git a/drivers/gpu/drm/i915/display/intel_overlay.h b/drivers/gpu/drm/i915/display/intel_overlay.h index a167c28acd..c3f68fce6f 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.h +++ b/drivers/gpu/drm/i915/display/intel_overlay.h @@ -13,6 +13,7 @@ struct drm_i915_private; struct intel_overlay; struct intel_overlay_error_state; +#ifdef I915 void intel_overlay_setup(struct drm_i915_private *dev_priv); void intel_overlay_cleanup(struct drm_i915_private *dev_priv); int intel_overlay_switch_off(struct intel_overlay *overlay); @@ -25,5 +26,39 @@ struct intel_overlay_error_state * intel_overlay_capture_error_state(struct drm_i915_private *dev_priv); void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e, struct intel_overlay_error_state *error); +#else +static inline void intel_overlay_setup(struct drm_i915_private *dev_priv) +{ +} +static inline void intel_overlay_cleanup(struct drm_i915_private *dev_priv) +{ +} +static inline int intel_overlay_switch_off(struct intel_overlay *overlay) +{ + return 0; +} +static inline int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} +static inline int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} +static inline void intel_overlay_reset(struct drm_i915_private *dev_priv) +{ +} +static inline struct intel_overlay_error_state * +intel_overlay_capture_error_state(struct drm_i915_private *dev_priv) +{ + return NULL; +} +static inline void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e, + struct intel_overlay_error_state *error) +{ +} +#endif #endif /* __INTEL_OVERLAY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 9232a305b1..483beedac5 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -59,15 +59,6 @@ intel_panel_preferred_fixed_mode(struct intel_connector *connector) struct drm_display_mode, head); } -static bool is_in_vrr_range(struct intel_connector *connector, int vrefresh) -{ - const struct drm_display_info *info = &connector->base.display_info; - - return intel_vrr_is_capable(connector) && - vrefresh >= info->monitor_range.min_vfreq && - vrefresh <= info->monitor_range.max_vfreq; -} - static bool is_best_fixed_mode(struct intel_connector *connector, int vrefresh, int fixed_mode_vrefresh, const struct drm_display_mode *best_mode) @@ -81,8 +72,8 @@ static bool is_best_fixed_mode(struct intel_connector *connector, * vrefresh, which we can then reduce to match the requested * vrefresh by extending the vblank length. */ - if (is_in_vrr_range(connector, vrefresh) && - is_in_vrr_range(connector, fixed_mode_vrefresh) && + if (intel_vrr_is_in_range(connector, vrefresh) && + intel_vrr_is_in_range(connector, fixed_mode_vrefresh) && fixed_mode_vrefresh < vrefresh) return false; @@ -224,8 +215,8 @@ int intel_panel_compute_config(struct intel_connector *connector, * Assume that we shouldn't muck about with the * timings if they don't land in the VRR range. */ - is_vrr = is_in_vrr_range(connector, vrefresh) && - is_in_vrr_range(connector, fixed_mode_vrefresh); + is_vrr = intel_vrr_is_in_range(connector, vrefresh) && + intel_vrr_is_in_range(connector, fixed_mode_vrefresh); if (!is_vrr) { /* @@ -689,7 +680,7 @@ intel_panel_detect(struct drm_connector *connector, bool force) { struct drm_i915_private *i915 = to_i915(connector->dev); - if (!INTEL_DISPLAY_ENABLED(i915)) + if (!intel_display_device_enabled(i915)) return connector_status_disconnected; return connector_status_connected; diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.h b/drivers/gpu/drm/i915/display/intel_pch_display.h index 41a63413cb..35f8288af3 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_display.h +++ b/drivers/gpu/drm/i915/display/intel_pch_display.h @@ -15,6 +15,7 @@ struct intel_crtc; struct intel_crtc_state; struct intel_link_m_n; +#ifdef I915 bool intel_has_pch_trancoder(struct drm_i915_private *i915, enum pipe pch_transcoder); enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc); @@ -41,5 +42,57 @@ void intel_pch_transcoder_get_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n); void intel_pch_sanitize(struct drm_i915_private *i915); +#else +static inline bool intel_has_pch_trancoder(struct drm_i915_private *i915, + enum pipe pch_transcoder) +{ + return false; +} +static inline int intel_crtc_pch_transcoder(struct intel_crtc *crtc) +{ + return 0; +} +static inline void ilk_pch_pre_enable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void ilk_pch_enable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void ilk_pch_disable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void ilk_pch_post_disable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void ilk_pch_get_config(struct intel_crtc_state *crtc_state) +{ +} +static inline void lpt_pch_enable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void lpt_pch_disable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ +} +static inline void lpt_pch_get_config(struct intel_crtc_state *crtc_state) +{ +} +static inline void intel_pch_transcoder_get_m1_n1(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) +{ +} +static inline void intel_pch_transcoder_get_m2_n2(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) +{ +} +static inline void intel_pch_sanitize(struct drm_i915_private *i915) +{ +} +#endif #endif diff --git a/drivers/gpu/drm/i915/display/intel_pch_refclk.c b/drivers/gpu/drm/i915/display/intel_pch_refclk.c index 9583e86b60..713cfba714 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_refclk.c +++ b/drivers/gpu/drm/i915/display/intel_pch_refclk.c @@ -492,6 +492,7 @@ static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv) static void ilk_init_pch_refclk(struct drm_i915_private *dev_priv) { struct intel_encoder *encoder; + struct intel_shared_dpll *pll; int i; u32 val, final; bool has_lvds = false; @@ -527,8 +528,10 @@ static void ilk_init_pch_refclk(struct drm_i915_private *dev_priv) } /* Check if any DPLLs are using the SSC source */ - for (i = 0; i < dev_priv->display.dpll.num_shared_dpll; i++) { - u32 temp = intel_de_read(dev_priv, PCH_DPLL(i)); + for_each_shared_dpll(dev_priv, pll, i) { + u32 temp; + + temp = intel_de_read(dev_priv, PCH_DPLL(pll->info->id)); if (!(temp & DPLL_VCO_ENABLE)) continue; diff --git a/drivers/gpu/drm/i915/display/intel_pch_refclk.h b/drivers/gpu/drm/i915/display/intel_pch_refclk.h index 9bcf56629f..ae3403c0ce 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_refclk.h +++ b/drivers/gpu/drm/i915/display/intel_pch_refclk.h @@ -11,6 +11,7 @@ struct drm_i915_private; struct intel_crtc_state; +#ifdef I915 void lpt_program_iclkip(const struct intel_crtc_state *crtc_state); void lpt_disable_iclkip(struct drm_i915_private *dev_priv); int lpt_get_iclkip(struct drm_i915_private *dev_priv); @@ -18,5 +19,27 @@ int lpt_iclkip(const struct intel_crtc_state *crtc_state); void intel_init_pch_refclk(struct drm_i915_private *dev_priv); void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv); +#else +static inline void lpt_program_iclkip(const struct intel_crtc_state *crtc_state) +{ +} +static inline void lpt_disable_iclkip(struct drm_i915_private *dev_priv) +{ +} +static inline int lpt_get_iclkip(struct drm_i915_private *dev_priv) +{ + return 0; +} +static inline int lpt_iclkip(const struct intel_crtc_state *crtc_state) +{ + return 0; +} +static inline void intel_init_pch_refclk(struct drm_i915_private *dev_priv) +{ +} +static inline void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv) +{ +} +#endif #endif diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index 736072a8b2..a55c09cbd0 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -9,6 +9,7 @@ #include "intel_display.h" #include "intel_display_types.h" #include "intel_fb.h" +#include "intel_frontbuffer.h" #include "intel_plane_initial.h" static bool @@ -165,7 +166,7 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_mode_fb_cmd2 mode_cmd = { 0 }; + struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_framebuffer *fb = &plane_config->fb->base; struct i915_vma *vma; diff --git a/drivers/gpu/drm/i915/display/intel_pmdemand.c b/drivers/gpu/drm/i915/display/intel_pmdemand.c index f7608d3636..744e332fa2 100644 --- a/drivers/gpu/drm/i915/display/intel_pmdemand.c +++ b/drivers/gpu/drm/i915/display/intel_pmdemand.c @@ -92,7 +92,7 @@ int intel_pmdemand_init(struct drm_i915_private *i915) &pmdemand_state->base, &intel_pmdemand_funcs); - if (IS_MTL_DISPLAY_STEP(i915, STEP_A0, STEP_C0)) + if (IS_DISPLAY_IP_STEP(i915, IP_VER(14, 0), STEP_A0, STEP_C0)) /* Wa_14016740474 */ intel_de_rmw(i915, XELPD_CHICKEN_DCPR_3, 0, DMD_RSP_TIMEOUT_DISABLE); diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 5cf3db7058..614b4534ef 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -23,6 +23,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> +#include <drm/drm_debugfs.h> #include "i915_drv.h" #include "i915_reg.h" @@ -32,6 +33,7 @@ #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_aux.h" +#include "intel_frontbuffer.h" #include "intel_hdmi.h" #include "intel_psr.h" #include "intel_psr_regs.h" @@ -1362,8 +1364,7 @@ static void wm_optimization_wa(struct intel_dp *intel_dp, bool set_wa_bit = false; /* Wa_14015648006 */ - if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0) || - IS_DISPLAY_VER(dev_priv, 11, 13)) + if (IS_DISPLAY_VER(dev_priv, 11, 14)) set_wa_bit |= crtc_state->wm_level_disabled; /* Wa_16013835468 */ @@ -1461,7 +1462,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, * All supported adlp panels have 1-based X granularity, this may * cause issues if non-supported panels are used. */ - if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) + if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0)) intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(cpu_transcoder), 0, ADLP_1_BASED_X_GRANULARITY); else if (IS_ALDERLAKE_P(dev_priv)) @@ -1469,7 +1470,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, ADLP_1_BASED_X_GRANULARITY); /* Wa_16012604467:adlp,mtl[a0,b0] */ - if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) + if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0)) intel_de_rmw(dev_priv, MTL_CLKGATE_DIS_TRANS(cpu_transcoder), 0, MTL_CLKGATE_DIS_TRANS_DMASC_GATING_DIS); @@ -1627,7 +1628,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) if (intel_dp->psr.psr2_enabled) { /* Wa_16012604467:adlp,mtl[a0,b0] */ - if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) + if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0)) intel_de_rmw(dev_priv, MTL_CLKGATE_DIS_TRANS(cpu_transcoder), MTL_CLKGATE_DIS_TRANS_DMASC_GATING_DIS, 0); @@ -2101,7 +2102,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, goto skip_sel_fetch_set_loop; /* Wa_14014971492 */ - if ((IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0) || + if ((IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0) || IS_ALDERLAKE_P(dev_priv) || IS_TIGERLAKE(dev_priv)) && crtc_state->splitter.enable) pipe_clip.y1 = 0; @@ -2208,10 +2209,12 @@ void intel_psr_pre_plane_update(struct intel_atomic_state *state, } } -static void _intel_psr_post_plane_update(const struct intel_atomic_state *state, - const struct intel_crtc_state *crtc_state) +void intel_psr_post_plane_update(struct intel_atomic_state *state, + struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); + const struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); struct intel_encoder *encoder; if (!crtc_state->has_psr) @@ -2244,24 +2247,16 @@ static void _intel_psr_post_plane_update(const struct intel_atomic_state *state, if (crtc_state->crc_enabled && psr->enabled) psr_force_hw_tracking_exit(intel_dp); + /* + * Clear possible busy bits in case we have + * invalidate -> flip -> flush sequence. + */ + intel_dp->psr.busy_frontbuffer_bits = 0; + mutex_unlock(&psr->lock); } } -void intel_psr_post_plane_update(const struct intel_atomic_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - struct intel_crtc_state *crtc_state; - struct intel_crtc *crtc; - int i; - - if (!HAS_PSR(dev_priv)) - return; - - for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) - _intel_psr_post_plane_update(state, crtc_state); -} - static int _psr2_ready_for_pipe_update_locked(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); @@ -3167,7 +3162,7 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) }; const char *str; int ret; - u8 val; + u8 status, error_status; if (!CAN_PSR(intel_dp)) { seq_puts(m, "PSR Unsupported\n"); @@ -3177,19 +3172,34 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) if (connector->base.status != connector_status_connected) return -ENODEV; - ret = drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_STATUS, &val); - if (ret != 1) - return ret < 0 ? ret : -EIO; + ret = psr_get_status_and_error_status(intel_dp, &status, &error_status); + if (ret) + return ret; - val &= DP_PSR_SINK_STATE_MASK; - if (val < ARRAY_SIZE(sink_status)) - str = sink_status[val]; + status &= DP_PSR_SINK_STATE_MASK; + if (status < ARRAY_SIZE(sink_status)) + str = sink_status[status]; else str = "unknown"; - seq_printf(m, "Sink PSR status: 0x%x [%s]\n", val, str); + seq_printf(m, "Sink PSR status: 0x%x [%s]\n", status, str); - return 0; + seq_printf(m, "Sink PSR error status: 0x%x", error_status); + + if (error_status & (DP_PSR_RFB_STORAGE_ERROR | + DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR | + DP_PSR_LINK_CRC_ERROR)) + seq_puts(m, ":\n"); + else + seq_puts(m, "\n"); + if (error_status & DP_PSR_RFB_STORAGE_ERROR) + seq_puts(m, "\tPSR RFB storage error\n"); + if (error_status & DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR) + seq_puts(m, "\tPSR VSC SDP uncorrectable error\n"); + if (error_status & DP_PSR_LINK_CRC_ERROR) + seq_puts(m, "\tPSR Link CRC error\n"); + + return ret; } DEFINE_SHOW_ATTRIBUTE(i915_psr_sink_status); diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 0b95e8aa61..bf35f42df6 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -24,7 +24,8 @@ struct intel_plane_state; void intel_psr_init_dpcd(struct intel_dp *intel_dp); void intel_psr_pre_plane_update(struct intel_atomic_state *state, struct intel_crtc *crtc); -void intel_psr_post_plane_update(const struct intel_atomic_state *state); +void intel_psr_post_plane_update(struct intel_atomic_state *state, + struct intel_crtc *crtc); void intel_psr_disable(struct intel_dp *intel_dp, const struct intel_crtc_state *old_crtc_state); int intel_psr_debug_set(struct intel_dp *intel_dp, u64 value); diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 0ce935efe5..312f88d90a 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -44,6 +44,7 @@ #include "intel_crtc.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_fdi.h" #include "intel_fifo_underrun.h" #include "intel_gmbus.h" #include "intel_hdmi.h" @@ -57,15 +58,16 @@ #define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1) #define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0) -#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\ - SDVO_TV_MASK) +#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK | SDVO_TV_MASK) -#define IS_TV(c) (c->output_flag & SDVO_TV_MASK) -#define IS_TMDS(c) (c->output_flag & SDVO_TMDS_MASK) -#define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK) -#define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) -#define IS_DIGITAL(c) (c->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK)) +#define IS_TV(c) ((c)->output_flag & SDVO_TV_MASK) +#define IS_TMDS(c) ((c)->output_flag & SDVO_TMDS_MASK) +#define IS_LVDS(c) ((c)->output_flag & SDVO_LVDS_MASK) +#define IS_TV_OR_LVDS(c) ((c)->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) +#define IS_DIGITAL(c) ((c)->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK)) +#define HAS_DDC(c) ((c)->output_flag & (SDVO_RGB_MASK | SDVO_TMDS_MASK | \ + SDVO_LVDS_MASK)) static const char * const tv_format_names[] = { "NTSC_M" , "NTSC_J" , "NTSC_443", @@ -79,20 +81,25 @@ static const char * const tv_format_names[] = { #define TV_FORMAT_NUM ARRAY_SIZE(tv_format_names) +struct intel_sdvo; + +struct intel_sdvo_ddc { + struct i2c_adapter ddc; + struct intel_sdvo *sdvo; + u8 ddc_bus; +}; + struct intel_sdvo { struct intel_encoder base; struct i2c_adapter *i2c; u8 slave_addr; - struct i2c_adapter ddc; + struct intel_sdvo_ddc ddc[3]; /* Register for the SDVO device: SDVOB or SDVOC */ i915_reg_t sdvo_reg; - /* Active outputs controlled by this SDVO output */ - u16 controlled_output; - /* * Capabilities of the SDVO device returned by * intel_sdvo_get_capabilities() @@ -105,21 +112,10 @@ struct intel_sdvo { int pixel_clock_min, pixel_clock_max; /* - * For multiple function SDVO device, - * this is for current attached outputs. - */ - u16 attached_output; - - /* * Hotplug activation bits for this device */ u16 hotplug_active; - enum port port; - - /* DDC bus used by this SDVO encoder */ - u8 ddc_bus; - /* * the sdvo flag gets lost in round trip: dtd->adjusted_mode->dtd */ @@ -233,7 +229,7 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) return; } - if (intel_sdvo->port == PORT_B) + if (intel_sdvo->base.port == PORT_B) cval = intel_de_read(dev_priv, GEN3_SDVOC); else bval = intel_de_read(dev_priv, GEN3_SDVOB); @@ -410,7 +406,7 @@ static const char *sdvo_cmd_name(u8 cmd) return NULL; } -#define SDVO_NAME(svdo) ((svdo)->port == PORT_B ? "SDVOB" : "SDVOC") +#define SDVO_NAME(svdo) ((svdo)->base.port == PORT_B ? "SDVOB" : "SDVOC") static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, const void *args, int args_len) @@ -653,7 +649,7 @@ intel_sdvo_get_value(struct intel_sdvo *intel_sdvo, u8 cmd, void *value, int len static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo) { - struct intel_sdvo_set_target_input_args targets = {0}; + struct intel_sdvo_set_target_input_args targets = {}; return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_TARGET_INPUT, &targets, sizeof(targets)); @@ -1212,7 +1208,7 @@ static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo, struct intel_sdvo_tv_format format; u32 format_map; - format_map = 1 << conn_state->tv.mode; + format_map = 1 << conn_state->tv.legacy_mode; memset(&format, 0, sizeof(format)); memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map))); @@ -1224,12 +1220,13 @@ static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, const struct drm_display_mode *mode) { struct intel_sdvo_dtd output_dtd; if (!intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output)) + intel_sdvo_connector->output_flag)) return false; intel_sdvo_get_dtd_from_mode(&output_dtd, mode); @@ -1270,10 +1267,10 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo, return true; } -static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config) +static int i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config) { struct drm_i915_private *dev_priv = to_i915(pipe_config->uapi.crtc->dev); - unsigned dotclock = pipe_config->port_clock; + unsigned int dotclock = pipe_config->hw.adjusted_mode.crtc_clock; struct dpll *clock = &pipe_config->dpll; /* @@ -1293,11 +1290,14 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config) clock->m1 = 12; clock->m2 = 8; } else { - drm_WARN(&dev_priv->drm, 1, - "SDVO TV clock out of range: %i\n", dotclock); + drm_dbg_kms(&dev_priv->drm, + "SDVO TV clock out of range: %i\n", dotclock); + return -EINVAL; } pipe_config->clock_set = true; + + return 0; } static bool intel_has_hdmi_sink(struct intel_sdvo_connector *intel_sdvo_connector, @@ -1352,14 +1352,18 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct drm_display_mode *mode = &pipe_config->hw.mode; + if (HAS_PCH_SPLIT(to_i915(encoder->base.dev))) { + pipe_config->has_pch_encoder = true; + if (!intel_fdi_compute_pipe_bpp(pipe_config)) + return -EINVAL; + } + DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n"); + /* FIXME: Don't increase pipe_bpp */ pipe_config->pipe_bpp = 8*3; pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - if (HAS_PCH_SPLIT(to_i915(encoder->base.dev))) - pipe_config->has_pch_encoder = true; - /* * We need to construct preferred input timings based on our * output timings. To do that, we have to set the output @@ -1367,7 +1371,9 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, * the sequence to do it. Oh well. */ if (IS_TV(intel_sdvo_connector)) { - if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, + intel_sdvo_connector, + mode)) return -EINVAL; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, @@ -1385,7 +1391,9 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, if (ret) return ret; - if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, fixed_mode)) + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, + intel_sdvo_connector, + fixed_mode)) return -EINVAL; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, @@ -1415,8 +1423,13 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, conn_state); /* Clock computation needs to happen after pixel multiplier. */ - if (IS_TV(intel_sdvo_connector)) - i9xx_adjust_sdvo_tv_clock(pipe_config); + if (IS_TV(intel_sdvo_connector)) { + int ret; + + ret = i9xx_adjust_sdvo_tv_clock(pipe_config); + if (ret) + return ret; + } if (conn_state->picture_aspect_ratio) adjusted_mode->picture_aspect_ratio = @@ -1521,7 +1534,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state, * channel on the motherboard. In a two-input device, the first input * will be SDVOB and the second SDVOC. */ - in_out.in0 = intel_sdvo->attached_output; + in_out.in0 = intel_sdvo_connector->output_flag; in_out.in1 = 0; intel_sdvo_set_value(intel_sdvo, @@ -1530,7 +1543,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state, /* Set the output timings to the screen */ if (!intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output)) + intel_sdvo_connector->output_flag)) return; /* lvds has a special fixed output timing. */ @@ -1598,7 +1611,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state, sdvox |= SDVO_BORDER_ENABLE; } else { sdvox = intel_de_read(dev_priv, intel_sdvo->sdvo_reg); - if (intel_sdvo->port == PORT_B) + if (intel_sdvo->base.port == PORT_B) sdvox &= SDVOB_PRESERVE_MASK; else sdvox &= SDVOC_PRESERVE_MASK; @@ -1867,6 +1880,8 @@ static void intel_enable_sdvo(struct intel_atomic_state *state, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + struct intel_sdvo_connector *intel_sdvo_connector = + to_intel_sdvo_connector(conn_state->connector); struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); u32 temp; bool input1, input2; @@ -1896,7 +1911,7 @@ static void intel_enable_sdvo(struct intel_atomic_state *state, if (0) intel_sdvo_set_encoder_power_state(intel_sdvo, DRM_MODE_DPMS_ON); - intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); + intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo_connector->output_flag); if (pipe_config->has_audio) intel_sdvo_enable_audio(intel_sdvo, pipe_config, conn_state); @@ -1962,7 +1977,7 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in " device_rev_id: %d\n" " sdvo_version_major: %d\n" " sdvo_version_minor: %d\n" - " sdvo_inputs_mask: %d\n" + " sdvo_num_inputs: %d\n" " smooth_scaling: %d\n" " sharp_scaling: %d\n" " up_scaling: %d\n" @@ -1974,7 +1989,7 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in caps->device_rev_id, caps->sdvo_version_major, caps->sdvo_version_minor, - caps->sdvo_inputs_mask, + caps->sdvo_num_inputs, caps->smooth_scaling, caps->sharp_scaling, caps->up_scaling, @@ -2035,18 +2050,15 @@ intel_sdvo_hotplug(struct intel_encoder *encoder, return intel_encoder_hotplug(encoder, connector); } -static bool -intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) -{ - /* Is there more than one type of output? */ - return hweight16(intel_sdvo->caps.output_flags) > 1; -} - static const struct drm_edid * intel_sdvo_get_edid(struct drm_connector *connector) { - struct intel_sdvo *sdvo = intel_attached_sdvo(to_intel_connector(connector)); - return drm_edid_read_ddc(connector, &sdvo->ddc); + struct i2c_adapter *ddc = connector->ddc; + + if (!ddc) + return NULL; + + return drm_edid_read_ddc(connector, ddc); } /* Mac mini hack -- use the same DDC as the analog connector */ @@ -2054,43 +2066,23 @@ static const struct drm_edid * intel_sdvo_get_analog_edid(struct drm_connector *connector) { struct drm_i915_private *i915 = to_i915(connector->dev); - struct i2c_adapter *i2c; + struct i2c_adapter *ddc; - i2c = intel_gmbus_get_adapter(i915, i915->display.vbt.crt_ddc_pin); + ddc = intel_gmbus_get_adapter(i915, i915->display.vbt.crt_ddc_pin); + if (!ddc) + return NULL; - return drm_edid_read_ddc(connector, i2c); + return drm_edid_read_ddc(connector, ddc); } static enum drm_connector_status intel_sdvo_tmds_sink_detect(struct drm_connector *connector) { - struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector)); enum drm_connector_status status; const struct drm_edid *drm_edid; drm_edid = intel_sdvo_get_edid(connector); - if (!drm_edid && intel_sdvo_multifunc_encoder(intel_sdvo)) { - u8 ddc, saved_ddc = intel_sdvo->ddc_bus; - - /* - * Don't use the 1 as the argument of DDC bus switch to get - * the EDID. It is used for SDVO SPD ROM. - */ - for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) { - intel_sdvo->ddc_bus = ddc; - drm_edid = intel_sdvo_get_edid(connector); - if (drm_edid) - break; - } - /* - * If we found the EDID on the other bus, - * assume that is the correct DDC bus. - */ - if (!drm_edid) - intel_sdvo->ddc_bus = saved_ddc; - } - /* * When there is no edid and no monitor is connected with VGA * port, try to use the CRT ddc to read the EDID for DVI-connector. @@ -2100,10 +2092,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) status = connector_status_unknown; if (drm_edid) { - const struct edid *edid = drm_edid_raw(drm_edid); - /* DDC bus is shared, match EDID to connector type */ - if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) + if (drm_edid_is_digital(drm_edid)) status = connector_status_connected; else status = connector_status_disconnected; @@ -2117,8 +2107,7 @@ static bool intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo, const struct drm_edid *drm_edid) { - const struct edid *edid = drm_edid_raw(drm_edid); - bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); + bool monitor_is_digital = drm_edid_is_digital(drm_edid); bool connector_is_digital = !!IS_DIGITAL(sdvo); DRM_DEBUG_KMS("connector_is_digital? %d, monitor_is_digital? %d\n", @@ -2138,9 +2127,13 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); - if (!INTEL_DISPLAY_ENABLED(i915)) + if (!intel_display_device_enabled(i915)) return connector_status_disconnected; + if (!intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo_connector->output_flag)) + return connector_status_unknown; + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ATTACHED_DISPLAYS, &response, 2)) @@ -2153,8 +2146,6 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) if (response == 0) return connector_status_disconnected; - intel_sdvo->attached_output = response; - if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; else if (IS_TMDS(intel_sdvo_connector)) @@ -2282,6 +2273,8 @@ static const struct drm_display_mode sdvo_tv_modes[] = { static int intel_sdvo_get_tv_modes(struct drm_connector *connector) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector)); + struct intel_sdvo_connector *intel_sdvo_connector = + to_intel_sdvo_connector(connector); const struct drm_connector_state *conn_state = connector->state; struct intel_sdvo_sdtv_resolution_request tv_res; u32 reply = 0, format_map = 0; @@ -2295,11 +2288,11 @@ static int intel_sdvo_get_tv_modes(struct drm_connector *connector) * Read the list of supported input resolutions for the selected TV * format. */ - format_map = 1 << conn_state->tv.mode; + format_map = 1 << conn_state->tv.legacy_mode; memcpy(&tv_res, &format_map, min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request))); - if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output)) + if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo_connector->output_flag)) return 0; BUILD_BUG_ON(sizeof(tv_res) != 3); @@ -2360,7 +2353,7 @@ intel_sdvo_connector_atomic_get_property(struct drm_connector *connector, int i; for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) - if (state->tv.mode == intel_sdvo_connector->tv_format_supported[i]) { + if (state->tv.legacy_mode == intel_sdvo_connector->tv_format_supported[i]) { *val = i; return 0; @@ -2416,7 +2409,7 @@ intel_sdvo_connector_atomic_set_property(struct drm_connector *connector, struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state(state); if (property == intel_sdvo_connector->tv_format) { - state->tv.mode = intel_sdvo_connector->tv_format_supported[val]; + state->tv.legacy_mode = intel_sdvo_connector->tv_format_supported[val]; if (state->crtc) { struct drm_crtc_state *crtc_state = @@ -2464,31 +2457,6 @@ intel_sdvo_connector_atomic_set_property(struct drm_connector *connector, return 0; } -static int -intel_sdvo_connector_register(struct drm_connector *connector) -{ - struct intel_sdvo *sdvo = intel_attached_sdvo(to_intel_connector(connector)); - int ret; - - ret = intel_connector_register(connector); - if (ret) - return ret; - - return sysfs_create_link(&connector->kdev->kobj, - &sdvo->ddc.dev.kobj, - sdvo->ddc.dev.kobj.name); -} - -static void -intel_sdvo_connector_unregister(struct drm_connector *connector) -{ - struct intel_sdvo *sdvo = intel_attached_sdvo(to_intel_connector(connector)); - - sysfs_remove_link(&connector->kdev->kobj, - sdvo->ddc.dev.kobj.name); - intel_connector_unregister(connector); -} - static struct drm_connector_state * intel_sdvo_connector_duplicate_state(struct drm_connector *connector) { @@ -2507,8 +2475,8 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .atomic_get_property = intel_sdvo_connector_atomic_get_property, .atomic_set_property = intel_sdvo_connector_atomic_set_property, - .late_register = intel_sdvo_connector_register, - .early_unregister = intel_sdvo_connector_unregister, + .late_register = intel_connector_register, + .early_unregister = intel_connector_unregister, .destroy = intel_connector_destroy, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_duplicate_state = intel_sdvo_connector_duplicate_state, @@ -2545,29 +2513,37 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs .atomic_check = intel_sdvo_atomic_check, }; -static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) +static void intel_sdvo_encoder_destroy(struct drm_encoder *_encoder) { - struct intel_sdvo *intel_sdvo = to_sdvo(to_intel_encoder(encoder)); + struct intel_encoder *encoder = to_intel_encoder(_encoder); + struct intel_sdvo *sdvo = to_sdvo(encoder); + int i; - i2c_del_adapter(&intel_sdvo->ddc); - intel_encoder_destroy(encoder); -} + for (i = 0; i < ARRAY_SIZE(sdvo->ddc); i++) { + if (sdvo->ddc[i].ddc_bus) + i2c_del_adapter(&sdvo->ddc[i].ddc); + } + + drm_encoder_cleanup(&encoder->base); + kfree(sdvo); +}; static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { - .destroy = intel_sdvo_enc_destroy, + .destroy = intel_sdvo_encoder_destroy, }; -static void -intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) +static int +intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo, + struct intel_sdvo_connector *connector) { u16 mask = 0; - unsigned int num_bits; + int num_bits; /* * Make a mask of outputs less than or equal to our own priority in the * list. */ - switch (sdvo->controlled_output) { + switch (connector->output_flag) { case SDVO_OUTPUT_LVDS1: mask |= SDVO_OUTPUT_LVDS1; fallthrough; @@ -2596,7 +2572,7 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) num_bits = 3; /* Corresponds to SDVO_CONTROL_BUS_DDCx */ - sdvo->ddc_bus = 1 << num_bits; + return num_bits; } /* @@ -2606,31 +2582,38 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) * DDC bus number assignment is in a priority order of RGB outputs, then TMDS * outputs, then LVDS outputs. */ -static void -intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, - struct intel_sdvo *sdvo) +static struct intel_sdvo_ddc * +intel_sdvo_select_ddc_bus(struct intel_sdvo *sdvo, + struct intel_sdvo_connector *connector) { - struct sdvo_device_mapping *mapping; + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); + const struct sdvo_device_mapping *mapping; + int ddc_bus; - if (sdvo->port == PORT_B) + if (sdvo->base.port == PORT_B) mapping = &dev_priv->display.vbt.sdvo_mappings[0]; else mapping = &dev_priv->display.vbt.sdvo_mappings[1]; if (mapping->initialized) - sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4); + ddc_bus = (mapping->ddc_pin & 0xf0) >> 4; else - intel_sdvo_guess_ddc_bus(sdvo); + ddc_bus = intel_sdvo_guess_ddc_bus(sdvo, connector); + + if (ddc_bus < 1 || ddc_bus > 3) + return NULL; + + return &sdvo->ddc[ddc_bus - 1]; } static void -intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, - struct intel_sdvo *sdvo) +intel_sdvo_select_i2c_bus(struct intel_sdvo *sdvo) { - struct sdvo_device_mapping *mapping; + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); + const struct sdvo_device_mapping *mapping; u8 pin; - if (sdvo->port == PORT_B) + if (sdvo->base.port == PORT_B) mapping = &dev_priv->display.vbt.sdvo_mappings[0]; else mapping = &dev_priv->display.vbt.sdvo_mappings[1]; @@ -2641,6 +2624,10 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, else pin = GMBUS_PIN_DPB; + drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] I2C pin %d, slave addr 0x%x\n", + sdvo->base.base.base.id, sdvo->base.base.name, + pin, sdvo->slave_addr); + sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); /* @@ -2665,12 +2652,12 @@ intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo) } static u8 -intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv, - struct intel_sdvo *sdvo) +intel_sdvo_get_slave_addr(struct intel_sdvo *sdvo) { - struct sdvo_device_mapping *my_mapping, *other_mapping; + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); + const struct sdvo_device_mapping *my_mapping, *other_mapping; - if (sdvo->port == PORT_B) { + if (sdvo->base.port == PORT_B) { my_mapping = &dev_priv->display.vbt.sdvo_mappings[0]; other_mapping = &dev_priv->display.vbt.sdvo_mappings[1]; } else { @@ -2697,28 +2684,36 @@ intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv, * No SDVO device info is found for another DVO port, * so use mapping assumption we had before BIOS parsing. */ - if (sdvo->port == PORT_B) + if (sdvo->base.port == PORT_B) return 0x70; else return 0x72; } static int +intel_sdvo_init_ddc_proxy(struct intel_sdvo_ddc *ddc, + struct intel_sdvo *sdvo, int bit); + +static int intel_sdvo_connector_init(struct intel_sdvo_connector *connector, struct intel_sdvo *encoder) { - struct drm_connector *drm_connector; + struct drm_i915_private *i915 = to_i915(encoder->base.base.dev); + struct intel_sdvo_ddc *ddc = NULL; int ret; - drm_connector = &connector->base.base; - ret = drm_connector_init(encoder->base.base.dev, - drm_connector, - &intel_sdvo_connector_funcs, - connector->base.base.connector_type); + if (HAS_DDC(connector)) + ddc = intel_sdvo_select_ddc_bus(encoder, connector); + + ret = drm_connector_init_with_ddc(encoder->base.base.dev, + &connector->base.base, + &intel_sdvo_connector_funcs, + connector->base.base.connector_type, + ddc ? &ddc->ddc : NULL); if (ret < 0) return ret; - drm_connector_helper_add(drm_connector, + drm_connector_helper_add(&connector->base.base, &intel_sdvo_connector_helper_funcs); connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; @@ -2727,6 +2722,11 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector, intel_connector_attach_encoder(&connector->base, &encoder->base); + if (ddc) + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] using %s\n", + connector->base.base.base.id, connector->base.base.name, + ddc->ddc.name); + return 0; } @@ -2924,7 +2924,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type) if (!intel_panel_preferred_fixed_mode(intel_connector)) { mutex_lock(&i915->drm.mode_config.mutex); - intel_ddc_get_modes(connector, &intel_sdvo->ddc); + intel_ddc_get_modes(connector, connector->ddc); intel_panel_add_edid_fixed_modes(intel_connector, false); mutex_unlock(&i915->drm.mode_config.mutex); @@ -2988,7 +2988,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) SDVO_OUTPUT_LVDS0, SDVO_OUTPUT_LVDS1, }; - struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev); u16 flags; int i; @@ -3000,10 +2999,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo) return false; } - intel_sdvo->controlled_output = flags; - - intel_sdvo_select_ddc_bus(i915, intel_sdvo); - for (i = 0; i < ARRAY_SIZE(probe_order); i++) { u16 type = flags & probe_order[i]; @@ -3071,7 +3066,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, drm_property_add_enum(intel_sdvo_connector->tv_format, i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]); - intel_sdvo_connector->base.base.state->tv.mode = intel_sdvo_connector->tv_format_supported[0]; + intel_sdvo_connector->base.base.state->tv.legacy_mode = intel_sdvo_connector->tv_format_supported[0]; drm_object_attach_property(&intel_sdvo_connector->base.base.base, intel_sdvo_connector->tv_format, 0); return true; @@ -3256,9 +3251,10 @@ static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; - if (!__intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus)) + if (!__intel_sdvo_set_control_bus_switch(sdvo, 1 << ddc->ddc_bus)) return -EIO; return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num); @@ -3266,7 +3262,9 @@ static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter, static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + return sdvo->i2c->algo->functionality(sdvo->i2c); } @@ -3278,21 +3276,27 @@ static const struct i2c_algorithm intel_sdvo_ddc_proxy = { static void proxy_lock_bus(struct i2c_adapter *adapter, unsigned int flags) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + sdvo->i2c->lock_ops->lock_bus(sdvo->i2c, flags); } static int proxy_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + return sdvo->i2c->lock_ops->trylock_bus(sdvo->i2c, flags); } static void proxy_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) { - struct intel_sdvo *sdvo = adapter->algo_data; + struct intel_sdvo_ddc *ddc = adapter->algo_data; + struct intel_sdvo *sdvo = ddc->sdvo; + sdvo->i2c->lock_ops->unlock_bus(sdvo->i2c, flags); } @@ -3302,21 +3306,26 @@ static const struct i2c_lock_operations proxy_lock_ops = { .unlock_bus = proxy_unlock_bus, }; -static bool -intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo, - struct drm_i915_private *dev_priv) +static int +intel_sdvo_init_ddc_proxy(struct intel_sdvo_ddc *ddc, + struct intel_sdvo *sdvo, int ddc_bus) { + struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev); struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - sdvo->ddc.owner = THIS_MODULE; - sdvo->ddc.class = I2C_CLASS_DDC; - snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy"); - sdvo->ddc.dev.parent = &pdev->dev; - sdvo->ddc.algo_data = sdvo; - sdvo->ddc.algo = &intel_sdvo_ddc_proxy; - sdvo->ddc.lock_ops = &proxy_lock_ops; + ddc->sdvo = sdvo; + ddc->ddc_bus = ddc_bus; - return i2c_add_adapter(&sdvo->ddc) == 0; + ddc->ddc.owner = THIS_MODULE; + ddc->ddc.class = I2C_CLASS_DDC; + snprintf(ddc->ddc.name, I2C_NAME_SIZE, "SDVO %c DDC%d", + port_name(sdvo->base.port), ddc_bus); + ddc->ddc.dev.parent = &pdev->dev; + ddc->ddc.algo_data = ddc; + ddc->ddc.algo = &intel_sdvo_ddc_proxy; + ddc->ddc.lock_ops = &proxy_lock_ops; + + return i2c_add_adapter(&ddc->ddc); } static bool is_sdvo_port_valid(struct drm_i915_private *dev_priv, enum port port) @@ -3351,23 +3360,21 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, if (!intel_sdvo) return false; - intel_sdvo->sdvo_reg = sdvo_reg; - intel_sdvo->port = port; - intel_sdvo->slave_addr = - intel_sdvo_get_slave_addr(dev_priv, intel_sdvo) >> 1; - intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo); - if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev_priv)) - goto err_i2c_bus; - /* encoder type will be decided later */ intel_encoder = &intel_sdvo->base; intel_encoder->type = INTEL_OUTPUT_SDVO; intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER; intel_encoder->port = port; + drm_encoder_init(&dev_priv->drm, &intel_encoder->base, &intel_sdvo_enc_funcs, 0, "SDVO %c", port_name(port)); + intel_sdvo->sdvo_reg = sdvo_reg; + intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(intel_sdvo) >> 1; + + intel_sdvo_select_i2c_bus(intel_sdvo); + /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { u8 byte; @@ -3399,6 +3406,15 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, intel_sdvo->colorimetry_cap = intel_sdvo_get_colorimetry_cap(intel_sdvo); + for (i = 0; i < ARRAY_SIZE(intel_sdvo->ddc); i++) { + int ret; + + ret = intel_sdvo_init_ddc_proxy(&intel_sdvo->ddc[i], + intel_sdvo, i + 1); + if (ret) + goto err; + } + if (!intel_sdvo_output_setup(intel_sdvo)) { drm_dbg_kms(&dev_priv->drm, "SDVO output failed to setup on %s\n", @@ -3412,7 +3428,7 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, * hotplug lines. */ if (intel_sdvo->hotplug_active) { - if (intel_sdvo->port == PORT_B) + if (intel_sdvo->base.port == PORT_B) intel_encoder->hpd_pin = HPD_SDVO_B; else intel_encoder->hpd_pin = HPD_SDVO_C; @@ -3439,15 +3455,14 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, drm_dbg_kms(&dev_priv->drm, "%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " - "input 1: %c, input 2: %c, " + "num inputs: %d, " "output 1: %c, output 2: %c\n", SDVO_NAME(intel_sdvo), intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id, intel_sdvo->caps.device_rev_id, intel_sdvo->pixel_clock_min / 1000, intel_sdvo->pixel_clock_max / 1000, - (intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', - (intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', + intel_sdvo->caps.sdvo_num_inputs, /* check currently supported outputs */ intel_sdvo->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0 | @@ -3460,13 +3475,9 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, err_output: intel_sdvo_output_cleanup(intel_sdvo); - err: - drm_encoder_cleanup(&intel_encoder->base); - i2c_del_adapter(&intel_sdvo->ddc); -err_i2c_bus: intel_sdvo_unselect_i2c_bus(intel_sdvo); - kfree(intel_sdvo); + intel_sdvo_encoder_destroy(&intel_encoder->base); return false; } diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.h b/drivers/gpu/drm/i915/display/intel_sdvo.h index 2868852c85..d1815b4103 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.h +++ b/drivers/gpu/drm/i915/display/intel_sdvo.h @@ -14,9 +14,22 @@ struct drm_i915_private; enum pipe; enum port; +#ifdef I915 bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv, i915_reg_t sdvo_reg, enum pipe *pipe); bool intel_sdvo_init(struct drm_i915_private *dev_priv, i915_reg_t reg, enum port port); +#else +static inline bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t sdvo_reg, enum pipe *pipe) +{ + return false; +} +static inline bool intel_sdvo_init(struct drm_i915_private *dev_priv, + i915_reg_t reg, enum port port) +{ + return false; +} +#endif #endif /* __INTEL_SDVO_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_sdvo_regs.h b/drivers/gpu/drm/i915/display/intel_sdvo_regs.h index 74dc6c042b..54f099abef 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/display/intel_sdvo_regs.h @@ -57,7 +57,7 @@ struct intel_sdvo_caps { u8 device_rev_id; u8 sdvo_version_major; u8 sdvo_version_minor; - unsigned int sdvo_inputs_mask:2; + unsigned int sdvo_num_inputs:2; unsigned int smooth_scaling:1; unsigned int sharp_scaling:1; unsigned int up_scaling:1; diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c index 88ef56b6e0..ce5a73a4cc 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c @@ -1993,12 +1993,13 @@ int intel_snps_phy_check_hdmi_link_rate(int clock) } void intel_mpllb_state_verify(struct intel_atomic_state *state, - struct intel_crtc_state *new_crtc_state) + struct intel_crtc *crtc) { struct drm_i915_private *i915 = to_i915(state->base.dev); - struct intel_mpllb_state mpllb_hw_state = { 0 }; - struct intel_mpllb_state *mpllb_sw_state = &new_crtc_state->mpllb_state; - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + struct intel_mpllb_state mpllb_hw_state = {}; + const struct intel_mpllb_state *mpllb_sw_state = &new_crtc_state->mpllb_state; struct intel_encoder *encoder; if (!IS_DG2(i915)) diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.h b/drivers/gpu/drm/i915/display/intel_snps_phy.h index 557ef820bc..515abf7c59 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.h +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.h @@ -10,6 +10,7 @@ struct drm_i915_private; struct intel_atomic_state; +struct intel_crtc; struct intel_crtc_state; struct intel_encoder; struct intel_mpllb_state; @@ -33,6 +34,6 @@ int intel_snps_phy_check_hdmi_link_rate(int clock); void intel_snps_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_mpllb_state_verify(struct intel_atomic_state *state, - struct intel_crtc_state *new_crtc_state); + struct intel_crtc *crtc); #endif /* __INTEL_SNPS_PHY_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 25034bbf14..1fb16510f7 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -45,6 +45,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_fb.h" +#include "intel_frontbuffer.h" #include "intel_sprite.h" static void i9xx_plane_linear_gamma(u16 gamma[8]) diff --git a/drivers/gpu/drm/i915/display/intel_sprite.h b/drivers/gpu/drm/i915/display/intel_sprite.h index 91c6dca342..044a032e41 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.h +++ b/drivers/gpu/drm/i915/display/intel_sprite.h @@ -16,6 +16,7 @@ struct intel_crtc_state; struct intel_plane_state; enum pipe; +#ifdef I915 struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe, int plane); int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, @@ -29,5 +30,12 @@ int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); int vlv_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); +#else +static inline struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv, + int pipe, int plane) +{ + return NULL; +} +#endif #endif /* __INTEL_SPRITE_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index cdf2455440..f64d348a96 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -260,7 +260,7 @@ assert_tc_port_power_enabled(struct intel_tc_port *tc) !intel_display_power_is_enabled(i915, tc_port_power_domain(tc))); } -u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) +static u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); struct intel_tc_port *tc = to_tc_port(dig_port); @@ -290,7 +290,32 @@ u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port) DP_PIN_ASSIGNMENT_SHIFT(tc->phy_fia_idx); } -static int mtl_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port) +static int lnl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port); + intel_wakeref_t wakeref; + u32 val, pin_assignment; + + with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref) + val = intel_de_read(i915, TCSS_DDI_STATUS(tc_port)); + + pin_assignment = + REG_FIELD_GET(TCSS_DDI_STATUS_PIN_ASSIGNMENT_MASK, val); + + switch (pin_assignment) { + default: + MISSING_CASE(pin_assignment); + fallthrough; + case DP_PIN_ASSIGNMENT_D: + return 2; + case DP_PIN_ASSIGNMENT_C: + case DP_PIN_ASSIGNMENT_E: + return 4; + } +} + +static int mtl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); intel_wakeref_t wakeref; @@ -311,23 +336,12 @@ static int mtl_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_po } } -int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) +static int intel_tc_port_get_max_lane_count(struct intel_digital_port *dig_port) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - struct intel_tc_port *tc = to_tc_port(dig_port); - enum phy phy = intel_port_to_phy(i915, dig_port->base.port); intel_wakeref_t wakeref; - u32 lane_mask; - - if (!intel_phy_is_tc(i915, phy) || tc->mode != TC_PORT_DP_ALT) - return 4; - - assert_tc_cold_blocked(tc); - - if (DISPLAY_VER(i915) >= 14) - return mtl_tc_port_get_pin_assignment_mask(dig_port); + u32 lane_mask = 0; - lane_mask = 0; with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref) lane_mask = intel_tc_port_get_lane_mask(dig_port); @@ -348,6 +362,26 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) } } +int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + struct intel_tc_port *tc = to_tc_port(dig_port); + enum phy phy = intel_port_to_phy(i915, dig_port->base.port); + + if (!intel_phy_is_tc(i915, phy) || tc->mode != TC_PORT_DP_ALT) + return 4; + + assert_tc_cold_blocked(tc); + + if (DISPLAY_VER(i915) >= 20) + return lnl_tc_port_get_max_lane_count(dig_port); + + if (DISPLAY_VER(i915) >= 14) + return mtl_tc_port_get_max_lane_count(dig_port); + + return intel_tc_port_get_max_lane_count(dig_port); +} + void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, int required_lanes) { @@ -583,7 +617,7 @@ static bool tc_phy_verify_legacy_or_dp_alt_mode(struct intel_tc_port *tc, struct intel_digital_port *dig_port = tc->dig_port; int max_lanes; - max_lanes = intel_tc_port_fia_max_lane_count(dig_port); + max_lanes = intel_tc_port_max_lane_count(dig_port); if (tc->mode == TC_PORT_LEGACY) { drm_WARN_ON(&i915->drm, max_lanes != 4); return true; diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 3b16491925..80a61e5285 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -19,9 +19,8 @@ bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_encoder *encoder); bool intel_tc_port_connected_locked(struct intel_encoder *encoder); -u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port); u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port); -int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port); +int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port); void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port, int required_lanes); diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index d84a79491d..f790fd10ba 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -949,7 +949,7 @@ intel_disable_tv(struct intel_atomic_state *state, static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state) { - int format = conn_state->tv.mode; + int format = conn_state->tv.legacy_mode; return &tv_modes[format]; } @@ -1710,7 +1710,7 @@ static void intel_tv_find_better_format(struct drm_connector *connector) break; } - connector->state->tv.mode = i; + connector->state->tv.legacy_mode = i; } static int @@ -1726,7 +1726,7 @@ intel_tv_detect(struct drm_connector *connector, drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] force=%d\n", connector->base.id, connector->name, force); - if (!INTEL_DISPLAY_ENABLED(i915)) + if (!intel_display_device_enabled(i915)) return connector_status_disconnected; if (force) { @@ -1865,7 +1865,7 @@ static int intel_tv_atomic_check(struct drm_connector *connector, old_state = drm_atomic_get_old_connector_state(state, connector); new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); - if (old_state->tv.mode != new_state->tv.mode || + if (old_state->tv.legacy_mode != new_state->tv.legacy_mode || old_state->tv.margins.left != new_state->tv.margins.left || old_state->tv.margins.right != new_state->tv.margins.right || old_state->tv.margins.top != new_state->tv.margins.top || @@ -1902,7 +1902,7 @@ static void intel_tv_add_properties(struct drm_connector *connector) conn_state->tv.margins.right = 46; conn_state->tv.margins.bottom = 37; - conn_state->tv.mode = 0; + conn_state->tv.legacy_mode = 0; /* Create TV properties then attach current values */ for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { @@ -1916,7 +1916,7 @@ static void intel_tv_add_properties(struct drm_connector *connector) drm_object_attach_property(&connector->base, i915->drm.mode_config.legacy_tv_mode_property, - conn_state->tv.mode); + conn_state->tv.legacy_mode); drm_object_attach_property(&connector->base, i915->drm.mode_config.tv_left_margin_property, conn_state->tv.margins.left); diff --git a/drivers/gpu/drm/i915/display/intel_tv.h b/drivers/gpu/drm/i915/display/intel_tv.h index 44518575ec..f08827b8bf 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.h +++ b/drivers/gpu/drm/i915/display/intel_tv.h @@ -8,6 +8,12 @@ struct drm_i915_private; +#ifdef I915 void intel_tv_init(struct drm_i915_private *dev_priv); +#else +static inline void intel_tv_init(struct drm_i915_private *dev_priv) +{ +} +#endif #endif /* __INTEL_TV_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c index f5659ebd08..2cec2abf97 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c @@ -251,6 +251,20 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) return (position + crtc->scanline_offset) % vtotal; } +int intel_crtc_scanline_to_hw(struct intel_crtc *crtc, int scanline) +{ + const struct drm_vblank_crtc *vblank = + &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)]; + const struct drm_display_mode *mode = &vblank->hwmode; + int vtotal; + + vtotal = mode->crtc_vtotal; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vtotal /= 2; + + return (scanline + vtotal - crtc->scanline_offset) % vtotal; +} + static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, bool in_vblank_irq, int *vpos, int *hpos, diff --git a/drivers/gpu/drm/i915/display/intel_vblank.h b/drivers/gpu/drm/i915/display/intel_vblank.h index 08e706b291..17636f140c 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.h +++ b/drivers/gpu/drm/i915/display/intel_vblank.h @@ -22,5 +22,6 @@ void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc); void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc); void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state, bool vrr_enable); +int intel_crtc_scanline_to_hw(struct intel_crtc *crtc, int scanline); #endif /* __INTEL_VBLANK_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 9d76c27567..6757dbae9e 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -80,13 +80,19 @@ calculate_rc_params(struct drm_dsc_config *vdsc_cfg) int bpc = vdsc_cfg->bits_per_component; int bpp = vdsc_cfg->bits_per_pixel >> 4; int qp_bpc_modifier = (bpc - 8) * 2; + int uncompressed_bpg_rate; + int first_line_bpg_offset; u32 res, buf_i, bpp_i; if (vdsc_cfg->slice_height >= 8) - vdsc_cfg->first_line_bpg_offset = - 12 + DIV_ROUND_UP((9 * min(34, vdsc_cfg->slice_height - 8)), 100); + first_line_bpg_offset = + 12 + (9 * min(34, vdsc_cfg->slice_height - 8)) / 100; else - vdsc_cfg->first_line_bpg_offset = 2 * (vdsc_cfg->slice_height - 1); + first_line_bpg_offset = 2 * (vdsc_cfg->slice_height - 1); + + uncompressed_bpg_rate = (3 * bpc + (vdsc_cfg->convert_rgb ? 0 : 2)) * 3; + vdsc_cfg->first_line_bpg_offset = clamp(first_line_bpg_offset, 0, + uncompressed_bpg_rate - 3 * bpp); /* * According to DSC 1.2 spec in Section 4.1 if native_420 is set: @@ -350,9 +356,14 @@ intel_dsc_power_domain(struct intel_crtc *crtc, enum transcoder cpu_transcoder) return POWER_DOMAIN_TRANSCODER_VDSC_PW2; } +static int intel_dsc_get_vdsc_per_pipe(const struct intel_crtc_state *crtc_state) +{ + return crtc_state->dsc.dsc_split ? 2 : 1; +} + int intel_dsc_get_num_vdsc_instances(const struct intel_crtc_state *crtc_state) { - int num_vdsc_instances = (crtc_state->dsc.dsc_split) ? 2 : 1; + int num_vdsc_instances = intel_dsc_get_vdsc_per_pipe(crtc_state); if (crtc_state->bigjoiner_pipes) num_vdsc_instances *= 2; @@ -360,6 +371,43 @@ int intel_dsc_get_num_vdsc_instances(const struct intel_crtc_state *crtc_state) return num_vdsc_instances; } +static void intel_dsc_get_pps_reg(const struct intel_crtc_state *crtc_state, int pps, + i915_reg_t *dsc_reg, int dsc_reg_num) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + enum pipe pipe = crtc->pipe; + bool pipe_dsc; + + pipe_dsc = is_pipe_dsc(crtc, cpu_transcoder); + + if (dsc_reg_num >= 3) + MISSING_CASE(dsc_reg_num); + if (dsc_reg_num >= 2) + dsc_reg[1] = pipe_dsc ? ICL_DSC1_PPS(pipe, pps) : DSCC_PPS(pps); + if (dsc_reg_num >= 1) + dsc_reg[0] = pipe_dsc ? ICL_DSC0_PPS(pipe, pps) : DSCA_PPS(pps); +} + +static void intel_dsc_pps_write(const struct intel_crtc_state *crtc_state, + int pps, u32 pps_val) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + i915_reg_t dsc_reg[2]; + int i, vdsc_per_pipe, dsc_reg_num; + + vdsc_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state); + dsc_reg_num = min_t(int, ARRAY_SIZE(dsc_reg), vdsc_per_pipe); + + drm_WARN_ON_ONCE(&i915->drm, dsc_reg_num < vdsc_per_pipe); + + intel_dsc_get_pps_reg(crtc_state, pps, dsc_reg, dsc_reg_num); + + for (i = 0; i < dsc_reg_num; i++) + intel_de_write(i915, dsc_reg[i], pps_val); +} + static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -367,359 +415,119 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; enum pipe pipe = crtc->pipe; - u32 pps_val = 0; + u32 pps_val; u32 rc_buf_thresh_dword[4]; u32 rc_range_params_dword[8]; int i = 0; int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state); + int vdsc_instances_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state); - /* Populate PICTURE_PARAMETER_SET_0 registers */ - pps_val = DSC_VER_MAJ | vdsc_cfg->dsc_version_minor << - DSC_VER_MIN_SHIFT | - vdsc_cfg->bits_per_component << DSC_BPC_SHIFT | - vdsc_cfg->line_buf_depth << DSC_LINE_BUF_DEPTH_SHIFT; + /* PPS 0 */ + pps_val = DSC_PPS0_VER_MAJOR(1) | + DSC_PPS0_VER_MINOR(vdsc_cfg->dsc_version_minor) | + DSC_PPS0_BPC(vdsc_cfg->bits_per_component) | + DSC_PPS0_LINE_BUF_DEPTH(vdsc_cfg->line_buf_depth); if (vdsc_cfg->dsc_version_minor == 2) { - pps_val |= DSC_ALT_ICH_SEL; + pps_val |= DSC_PPS0_ALT_ICH_SEL; if (vdsc_cfg->native_420) - pps_val |= DSC_NATIVE_420_ENABLE; + pps_val |= DSC_PPS0_NATIVE_420_ENABLE; if (vdsc_cfg->native_422) - pps_val |= DSC_NATIVE_422_ENABLE; + pps_val |= DSC_PPS0_NATIVE_422_ENABLE; } if (vdsc_cfg->block_pred_enable) - pps_val |= DSC_BLOCK_PREDICTION; + pps_val |= DSC_PPS0_BLOCK_PREDICTION; if (vdsc_cfg->convert_rgb) - pps_val |= DSC_COLOR_SPACE_CONVERSION; + pps_val |= DSC_PPS0_COLOR_SPACE_CONVERSION; if (vdsc_cfg->simple_422) - pps_val |= DSC_422_ENABLE; + pps_val |= DSC_PPS0_422_ENABLE; if (vdsc_cfg->vbr_enable) - pps_val |= DSC_VBR_ENABLE; + pps_val |= DSC_PPS0_VBR_ENABLE; drm_dbg_kms(&dev_priv->drm, "PPS0 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_0, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_0, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_0(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_0(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 0, pps_val); - /* Populate PICTURE_PARAMETER_SET_1 registers */ - pps_val = 0; - pps_val |= DSC_BPP(vdsc_cfg->bits_per_pixel); + /* PPS 1 */ + pps_val = DSC_PPS1_BPP(vdsc_cfg->bits_per_pixel); drm_dbg_kms(&dev_priv->drm, "PPS1 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_1, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_1, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_1(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 1, pps_val); - /* Populate PICTURE_PARAMETER_SET_2 registers */ - pps_val = 0; - pps_val |= DSC_PIC_HEIGHT(vdsc_cfg->pic_height) | - DSC_PIC_WIDTH(vdsc_cfg->pic_width / num_vdsc_instances); + /* PPS 2 */ + pps_val = DSC_PPS2_PIC_HEIGHT(vdsc_cfg->pic_height) | + DSC_PPS2_PIC_WIDTH(vdsc_cfg->pic_width / num_vdsc_instances); drm_dbg_kms(&dev_priv->drm, "PPS2 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_2, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_2, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_2(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_2(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 2, pps_val); - /* Populate PICTURE_PARAMETER_SET_3 registers */ - pps_val = 0; - pps_val |= DSC_SLICE_HEIGHT(vdsc_cfg->slice_height) | - DSC_SLICE_WIDTH(vdsc_cfg->slice_width); + /* PPS 3 */ + pps_val = DSC_PPS3_SLICE_HEIGHT(vdsc_cfg->slice_height) | + DSC_PPS3_SLICE_WIDTH(vdsc_cfg->slice_width); drm_dbg_kms(&dev_priv->drm, "PPS3 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_3, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_3, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_3(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_3(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 3, pps_val); - /* Populate PICTURE_PARAMETER_SET_4 registers */ - pps_val = 0; - pps_val |= DSC_INITIAL_XMIT_DELAY(vdsc_cfg->initial_xmit_delay) | - DSC_INITIAL_DEC_DELAY(vdsc_cfg->initial_dec_delay); + /* PPS 4 */ + pps_val = DSC_PPS4_INITIAL_XMIT_DELAY(vdsc_cfg->initial_xmit_delay) | + DSC_PPS4_INITIAL_DEC_DELAY(vdsc_cfg->initial_dec_delay); drm_dbg_kms(&dev_priv->drm, "PPS4 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_4, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_4, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_4(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_4(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 4, pps_val); - /* Populate PICTURE_PARAMETER_SET_5 registers */ - pps_val = 0; - pps_val |= DSC_SCALE_INC_INT(vdsc_cfg->scale_increment_interval) | - DSC_SCALE_DEC_INT(vdsc_cfg->scale_decrement_interval); + /* PPS 5 */ + pps_val = DSC_PPS5_SCALE_INC_INT(vdsc_cfg->scale_increment_interval) | + DSC_PPS5_SCALE_DEC_INT(vdsc_cfg->scale_decrement_interval); drm_dbg_kms(&dev_priv->drm, "PPS5 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_5, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_5, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_5(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_5(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 5, pps_val); - /* Populate PICTURE_PARAMETER_SET_6 registers */ - pps_val = 0; - pps_val |= DSC_INITIAL_SCALE_VALUE(vdsc_cfg->initial_scale_value) | - DSC_FIRST_LINE_BPG_OFFSET(vdsc_cfg->first_line_bpg_offset) | - DSC_FLATNESS_MIN_QP(vdsc_cfg->flatness_min_qp) | - DSC_FLATNESS_MAX_QP(vdsc_cfg->flatness_max_qp); + /* PPS 6 */ + pps_val = DSC_PPS6_INITIAL_SCALE_VALUE(vdsc_cfg->initial_scale_value) | + DSC_PPS6_FIRST_LINE_BPG_OFFSET(vdsc_cfg->first_line_bpg_offset) | + DSC_PPS6_FLATNESS_MIN_QP(vdsc_cfg->flatness_min_qp) | + DSC_PPS6_FLATNESS_MAX_QP(vdsc_cfg->flatness_max_qp); drm_dbg_kms(&dev_priv->drm, "PPS6 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_6, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_6, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_6(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_6(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 6, pps_val); - /* Populate PICTURE_PARAMETER_SET_7 registers */ - pps_val = 0; - pps_val |= DSC_SLICE_BPG_OFFSET(vdsc_cfg->slice_bpg_offset) | - DSC_NFL_BPG_OFFSET(vdsc_cfg->nfl_bpg_offset); + /* PPS 7 */ + pps_val = DSC_PPS7_SLICE_BPG_OFFSET(vdsc_cfg->slice_bpg_offset) | + DSC_PPS7_NFL_BPG_OFFSET(vdsc_cfg->nfl_bpg_offset); drm_dbg_kms(&dev_priv->drm, "PPS7 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_7, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_7, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_7(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_7(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 7, pps_val); - /* Populate PICTURE_PARAMETER_SET_8 registers */ - pps_val = 0; - pps_val |= DSC_FINAL_OFFSET(vdsc_cfg->final_offset) | - DSC_INITIAL_OFFSET(vdsc_cfg->initial_offset); + /* PPS 8 */ + pps_val = DSC_PPS8_FINAL_OFFSET(vdsc_cfg->final_offset) | + DSC_PPS8_INITIAL_OFFSET(vdsc_cfg->initial_offset); drm_dbg_kms(&dev_priv->drm, "PPS8 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_8, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_8, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_8(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_8(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 8, pps_val); - /* Populate PICTURE_PARAMETER_SET_9 registers */ - pps_val = 0; - pps_val |= DSC_RC_MODEL_SIZE(vdsc_cfg->rc_model_size) | - DSC_RC_EDGE_FACTOR(DSC_RC_EDGE_FACTOR_CONST); + /* PPS 9 */ + pps_val = DSC_PPS9_RC_MODEL_SIZE(vdsc_cfg->rc_model_size) | + DSC_PPS9_RC_EDGE_FACTOR(DSC_RC_EDGE_FACTOR_CONST); drm_dbg_kms(&dev_priv->drm, "PPS9 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_9, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, DSCC_PICTURE_PARAMETER_SET_9, - pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_9(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_9(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 9, pps_val); - /* Populate PICTURE_PARAMETER_SET_10 registers */ - pps_val = 0; - pps_val |= DSC_RC_QUANT_INC_LIMIT0(vdsc_cfg->rc_quant_incr_limit0) | - DSC_RC_QUANT_INC_LIMIT1(vdsc_cfg->rc_quant_incr_limit1) | - DSC_RC_TARGET_OFF_HIGH(DSC_RC_TGT_OFFSET_HI_CONST) | - DSC_RC_TARGET_OFF_LOW(DSC_RC_TGT_OFFSET_LO_CONST); + /* PPS 10 */ + pps_val = DSC_PPS10_RC_QUANT_INC_LIMIT0(vdsc_cfg->rc_quant_incr_limit0) | + DSC_PPS10_RC_QUANT_INC_LIMIT1(vdsc_cfg->rc_quant_incr_limit1) | + DSC_PPS10_RC_TARGET_OFF_HIGH(DSC_RC_TGT_OFFSET_HI_CONST) | + DSC_PPS10_RC_TARGET_OFF_LOW(DSC_RC_TGT_OFFSET_LO_CONST); drm_dbg_kms(&dev_priv->drm, "PPS10 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_10, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - DSCC_PICTURE_PARAMETER_SET_10, pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_10(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_10(pipe), - pps_val); - } - - /* Populate Picture parameter set 16 */ - pps_val = 0; - pps_val |= DSC_SLICE_CHUNK_SIZE(vdsc_cfg->slice_chunk_size) | - DSC_SLICE_PER_LINE((vdsc_cfg->pic_width / num_vdsc_instances) / - vdsc_cfg->slice_width) | - DSC_SLICE_ROW_PER_FRAME(vdsc_cfg->pic_height / - vdsc_cfg->slice_height); + intel_dsc_pps_write(crtc_state, 10, pps_val); + + /* PPS 16 */ + pps_val = DSC_PPS16_SLICE_CHUNK_SIZE(vdsc_cfg->slice_chunk_size) | + DSC_PPS16_SLICE_PER_LINE((vdsc_cfg->pic_width / num_vdsc_instances) / + vdsc_cfg->slice_width) | + DSC_PPS16_SLICE_ROW_PER_FRAME(vdsc_cfg->pic_height / + vdsc_cfg->slice_height); drm_dbg_kms(&dev_priv->drm, "PPS16 = 0x%08x\n", pps_val); - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - intel_de_write(dev_priv, DSCA_PICTURE_PARAMETER_SET_16, - pps_val); - /* - * If 2 VDSC instances are needed, configure PPS for second - * VDSC - */ - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - DSCC_PICTURE_PARAMETER_SET_16, pps_val); - } else { - intel_de_write(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_16(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - ICL_DSC1_PICTURE_PARAMETER_SET_16(pipe), - pps_val); - } + intel_dsc_pps_write(crtc_state, 16, pps_val); if (DISPLAY_VER(dev_priv) >= 14) { - /* Populate PICTURE_PARAMETER_SET_17 registers */ - pps_val = 0; - pps_val |= DSC_SL_BPG_OFFSET(vdsc_cfg->second_line_bpg_offset); + /* PPS 17 */ + pps_val = DSC_PPS17_SL_BPG_OFFSET(vdsc_cfg->second_line_bpg_offset); drm_dbg_kms(&dev_priv->drm, "PPS17 = 0x%08x\n", pps_val); - intel_de_write(dev_priv, - MTL_DSC0_PICTURE_PARAMETER_SET_17(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - MTL_DSC1_PICTURE_PARAMETER_SET_17(pipe), - pps_val); + intel_dsc_pps_write(crtc_state, 17, pps_val); - /* Populate PICTURE_PARAMETER_SET_18 registers */ - pps_val = 0; - pps_val |= DSC_NSL_BPG_OFFSET(vdsc_cfg->nsl_bpg_offset) | - DSC_SL_OFFSET_ADJ(vdsc_cfg->second_line_offset_adj); + /* PPS 18 */ + pps_val = DSC_PPS18_NSL_BPG_OFFSET(vdsc_cfg->nsl_bpg_offset) | + DSC_PPS18_SL_OFFSET_ADJ(vdsc_cfg->second_line_offset_adj); drm_dbg_kms(&dev_priv->drm, "PPS18 = 0x%08x\n", pps_val); - intel_de_write(dev_priv, - MTL_DSC0_PICTURE_PARAMETER_SET_18(pipe), - pps_val); - if (crtc_state->dsc.dsc_split) - intel_de_write(dev_priv, - MTL_DSC1_PICTURE_PARAMETER_SET_18(pipe), - pps_val); + intel_dsc_pps_write(crtc_state, 18, pps_val); } /* Populate the RC_BUF_THRESH registers */ @@ -740,7 +548,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) rc_buf_thresh_dword[2]); intel_de_write(dev_priv, DSCA_RC_BUF_THRESH_1_UDW, rc_buf_thresh_dword[3]); - if (crtc_state->dsc.dsc_split) { + if (vdsc_instances_per_pipe > 1) { intel_de_write(dev_priv, DSCC_RC_BUF_THRESH_0, rc_buf_thresh_dword[0]); intel_de_write(dev_priv, DSCC_RC_BUF_THRESH_0_UDW, @@ -759,7 +567,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) rc_buf_thresh_dword[2]); intel_de_write(dev_priv, ICL_DSC0_RC_BUF_THRESH_1_UDW(pipe), rc_buf_thresh_dword[3]); - if (crtc_state->dsc.dsc_split) { + if (vdsc_instances_per_pipe > 1) { intel_de_write(dev_priv, ICL_DSC1_RC_BUF_THRESH_0(pipe), rc_buf_thresh_dword[0]); @@ -805,7 +613,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) rc_range_params_dword[6]); intel_de_write(dev_priv, DSCA_RC_RANGE_PARAMETERS_3_UDW, rc_range_params_dword[7]); - if (crtc_state->dsc.dsc_split) { + if (vdsc_instances_per_pipe > 1) { intel_de_write(dev_priv, DSCC_RC_RANGE_PARAMETERS_0, rc_range_params_dword[0]); intel_de_write(dev_priv, @@ -848,7 +656,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) intel_de_write(dev_priv, ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW(pipe), rc_range_params_dword[7]); - if (crtc_state->dsc.dsc_split) { + if (vdsc_instances_per_pipe > 1) { intel_de_write(dev_priv, ICL_DSC1_RC_RANGE_PARAMETERS_0(pipe), rc_range_params_dword[0]); @@ -954,6 +762,7 @@ void intel_dsc_enable(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 dss_ctl1_val = 0; u32 dss_ctl2_val = 0; + int vdsc_instances_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state); if (!crtc_state->dsc.compression_enable) return; @@ -961,7 +770,7 @@ void intel_dsc_enable(const struct intel_crtc_state *crtc_state) intel_dsc_pps_configure(crtc_state); dss_ctl2_val |= LEFT_BRANCH_VDSC_ENABLE; - if (crtc_state->dsc.dsc_split) { + if (vdsc_instances_per_pipe > 1) { dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE; dss_ctl1_val |= JOINER_ENABLE; } @@ -987,16 +796,168 @@ void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state) } } +static u32 intel_dsc_pps_read(struct intel_crtc_state *crtc_state, int pps, + bool *check_equal) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + i915_reg_t dsc_reg[2]; + int i, vdsc_per_pipe, dsc_reg_num; + u32 val = 0; + + vdsc_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state); + dsc_reg_num = min_t(int, ARRAY_SIZE(dsc_reg), vdsc_per_pipe); + + drm_WARN_ON_ONCE(&i915->drm, dsc_reg_num < vdsc_per_pipe); + + intel_dsc_get_pps_reg(crtc_state, pps, dsc_reg, dsc_reg_num); + + if (check_equal) + *check_equal = true; + + for (i = 0; i < dsc_reg_num; i++) { + u32 tmp; + + tmp = intel_de_read(i915, dsc_reg[i]); + + if (i == 0) { + val = tmp; + } else if (check_equal && tmp != val) { + *check_equal = false; + break; + } else if (!check_equal) { + break; + } + } + + return val; +} + +static u32 intel_dsc_pps_read_and_verify(struct intel_crtc_state *crtc_state, int pps) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + u32 val; + bool all_equal; + + val = intel_dsc_pps_read(crtc_state, pps, &all_equal); + drm_WARN_ON(&i915->drm, !all_equal); + + return val; +} + +static void intel_dsc_get_pps_config(struct intel_crtc_state *crtc_state) +{ + struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state); + u32 pps_temp; + + /* PPS 0 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 0); + + vdsc_cfg->bits_per_component = REG_FIELD_GET(DSC_PPS0_BPC_MASK, pps_temp); + vdsc_cfg->line_buf_depth = REG_FIELD_GET(DSC_PPS0_LINE_BUF_DEPTH_MASK, pps_temp); + vdsc_cfg->block_pred_enable = pps_temp & DSC_PPS0_BLOCK_PREDICTION; + vdsc_cfg->convert_rgb = pps_temp & DSC_PPS0_COLOR_SPACE_CONVERSION; + vdsc_cfg->simple_422 = pps_temp & DSC_PPS0_422_ENABLE; + vdsc_cfg->native_422 = pps_temp & DSC_PPS0_NATIVE_422_ENABLE; + vdsc_cfg->native_420 = pps_temp & DSC_PPS0_NATIVE_420_ENABLE; + vdsc_cfg->vbr_enable = pps_temp & DSC_PPS0_VBR_ENABLE; + + /* PPS 1 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 1); + + vdsc_cfg->bits_per_pixel = REG_FIELD_GET(DSC_PPS1_BPP_MASK, pps_temp); + + if (vdsc_cfg->native_420) + vdsc_cfg->bits_per_pixel >>= 1; + + crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4; + + /* PPS 2 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 2); + + vdsc_cfg->pic_width = REG_FIELD_GET(DSC_PPS2_PIC_WIDTH_MASK, pps_temp) * num_vdsc_instances; + vdsc_cfg->pic_height = REG_FIELD_GET(DSC_PPS2_PIC_HEIGHT_MASK, pps_temp); + + /* PPS 3 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 3); + + vdsc_cfg->slice_width = REG_FIELD_GET(DSC_PPS3_SLICE_WIDTH_MASK, pps_temp); + vdsc_cfg->slice_height = REG_FIELD_GET(DSC_PPS3_SLICE_HEIGHT_MASK, pps_temp); + + /* PPS 4 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 4); + + vdsc_cfg->initial_dec_delay = REG_FIELD_GET(DSC_PPS4_INITIAL_DEC_DELAY_MASK, pps_temp); + vdsc_cfg->initial_xmit_delay = REG_FIELD_GET(DSC_PPS4_INITIAL_XMIT_DELAY_MASK, pps_temp); + + /* PPS 5 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 5); + + vdsc_cfg->scale_decrement_interval = REG_FIELD_GET(DSC_PPS5_SCALE_DEC_INT_MASK, pps_temp); + vdsc_cfg->scale_increment_interval = REG_FIELD_GET(DSC_PPS5_SCALE_INC_INT_MASK, pps_temp); + + /* PPS 6 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 6); + + vdsc_cfg->initial_scale_value = REG_FIELD_GET(DSC_PPS6_INITIAL_SCALE_VALUE_MASK, pps_temp); + vdsc_cfg->first_line_bpg_offset = REG_FIELD_GET(DSC_PPS6_FIRST_LINE_BPG_OFFSET_MASK, pps_temp); + vdsc_cfg->flatness_min_qp = REG_FIELD_GET(DSC_PPS6_FLATNESS_MIN_QP_MASK, pps_temp); + vdsc_cfg->flatness_max_qp = REG_FIELD_GET(DSC_PPS6_FLATNESS_MAX_QP_MASK, pps_temp); + + /* PPS 7 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 7); + + vdsc_cfg->nfl_bpg_offset = REG_FIELD_GET(DSC_PPS7_NFL_BPG_OFFSET_MASK, pps_temp); + vdsc_cfg->slice_bpg_offset = REG_FIELD_GET(DSC_PPS7_SLICE_BPG_OFFSET_MASK, pps_temp); + + /* PPS 8 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 8); + + vdsc_cfg->initial_offset = REG_FIELD_GET(DSC_PPS8_INITIAL_OFFSET_MASK, pps_temp); + vdsc_cfg->final_offset = REG_FIELD_GET(DSC_PPS8_FINAL_OFFSET_MASK, pps_temp); + + /* PPS 9 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 9); + + vdsc_cfg->rc_model_size = REG_FIELD_GET(DSC_PPS9_RC_MODEL_SIZE_MASK, pps_temp); + + /* PPS 10 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 10); + + vdsc_cfg->rc_quant_incr_limit0 = REG_FIELD_GET(DSC_PPS10_RC_QUANT_INC_LIMIT0_MASK, pps_temp); + vdsc_cfg->rc_quant_incr_limit1 = REG_FIELD_GET(DSC_PPS10_RC_QUANT_INC_LIMIT1_MASK, pps_temp); + + /* PPS 16 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 16); + + vdsc_cfg->slice_chunk_size = REG_FIELD_GET(DSC_PPS16_SLICE_CHUNK_SIZE_MASK, pps_temp); + + if (DISPLAY_VER(i915) >= 14) { + /* PPS 17 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 17); + + vdsc_cfg->second_line_bpg_offset = REG_FIELD_GET(DSC_PPS17_SL_BPG_OFFSET_MASK, pps_temp); + + /* PPS 18 */ + pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 18); + + vdsc_cfg->nsl_bpg_offset = REG_FIELD_GET(DSC_PPS18_NSL_BPG_OFFSET_MASK, pps_temp); + vdsc_cfg->second_line_offset_adj = REG_FIELD_GET(DSC_PPS18_SL_OFFSET_ADJ_MASK, pps_temp); + } +} + void intel_dsc_get_config(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); - struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - enum pipe pipe = crtc->pipe; enum intel_display_power_domain power_domain; intel_wakeref_t wakeref; - u32 dss_ctl1, dss_ctl2, pps0 = 0, pps1 = 0; + u32 dss_ctl1, dss_ctl2; if (!intel_dsc_source_support(crtc_state)) return; @@ -1017,24 +978,7 @@ void intel_dsc_get_config(struct intel_crtc_state *crtc_state) crtc_state->dsc.dsc_split = (dss_ctl2 & RIGHT_BRANCH_VDSC_ENABLE) && (dss_ctl1 & JOINER_ENABLE); - /* FIXME: add more state readout as needed */ - - /* PPS0 & PPS1 */ - if (!is_pipe_dsc(crtc, cpu_transcoder)) { - pps1 = intel_de_read(dev_priv, DSCA_PICTURE_PARAMETER_SET_1); - } else { - pps0 = intel_de_read(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_0(pipe)); - pps1 = intel_de_read(dev_priv, - ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe)); - } - - vdsc_cfg->bits_per_pixel = pps1; - - if (pps0 & DSC_NATIVE_420_ENABLE) - vdsc_cfg->bits_per_pixel >>= 1; - - crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4; + intel_dsc_get_pps_config(crtc_state); out: intel_display_power_put(dev_priv, power_domain, wakeref); } diff --git a/drivers/gpu/drm/i915/display/intel_vdsc_regs.h b/drivers/gpu/drm/i915/display/intel_vdsc_regs.h index b71f00b5c7..8b21dc8e26 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc_regs.h +++ b/drivers/gpu/drm/i915/display/intel_vdsc_regs.h @@ -46,35 +46,13 @@ _ICL_PIPE_DSS_CTL2_PB, \ _ICL_PIPE_DSS_CTL2_PC) -/* MTL Display Stream Compression registers */ -#define _MTL_DSC0_PICTURE_PARAMETER_SET_17_PB 0x782B4 -#define _MTL_DSC1_PICTURE_PARAMETER_SET_17_PB 0x783B4 -#define _MTL_DSC0_PICTURE_PARAMETER_SET_17_PC 0x784B4 -#define _MTL_DSC1_PICTURE_PARAMETER_SET_17_PC 0x785B4 -#define MTL_DSC0_PICTURE_PARAMETER_SET_17(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _MTL_DSC0_PICTURE_PARAMETER_SET_17_PB, \ - _MTL_DSC0_PICTURE_PARAMETER_SET_17_PC) -#define MTL_DSC1_PICTURE_PARAMETER_SET_17(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _MTL_DSC1_PICTURE_PARAMETER_SET_17_PB, \ - _MTL_DSC1_PICTURE_PARAMETER_SET_17_PC) -#define DSC_SL_BPG_OFFSET(offset) ((offset) << 27) - -#define _MTL_DSC0_PICTURE_PARAMETER_SET_18_PB 0x782B8 -#define _MTL_DSC1_PICTURE_PARAMETER_SET_18_PB 0x783B8 -#define _MTL_DSC0_PICTURE_PARAMETER_SET_18_PC 0x784B8 -#define _MTL_DSC1_PICTURE_PARAMETER_SET_18_PC 0x785B8 -#define MTL_DSC0_PICTURE_PARAMETER_SET_18(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _MTL_DSC0_PICTURE_PARAMETER_SET_18_PB, \ - _MTL_DSC0_PICTURE_PARAMETER_SET_18_PC) -#define MTL_DSC1_PICTURE_PARAMETER_SET_18(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _MTL_DSC1_PICTURE_PARAMETER_SET_18_PB, \ - _MTL_DSC1_PICTURE_PARAMETER_SET_18_PC) -#define DSC_NSL_BPG_OFFSET(offset) ((offset) << 16) -#define DSC_SL_OFFSET_ADJ(offset) ((offset) << 0) - /* Icelake Display Stream Compression Registers */ #define DSCA_PICTURE_PARAMETER_SET_0 _MMIO(0x6B200) #define DSCC_PICTURE_PARAMETER_SET_0 _MMIO(0x6BA00) +#define _DSCA_PPS_0 0x6B200 +#define _DSCC_PPS_0 0x6BA00 +#define DSCA_PPS(pps) _MMIO(_DSCA_PPS_0 + ((pps) < 12 ? (pps) : (pps) + 12) * 4) +#define DSCC_PPS(pps) _MMIO(_DSCC_PPS_0 + ((pps) < 12 ? (pps) : (pps) + 12) * 4) #define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PB 0x78270 #define _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB 0x78370 #define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PC 0x78470 @@ -85,251 +63,128 @@ #define ICL_DSC1_PICTURE_PARAMETER_SET_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB, \ _ICL_DSC1_PICTURE_PARAMETER_SET_0_PC) -#define DSC_NATIVE_422_ENABLE BIT(23) -#define DSC_NATIVE_420_ENABLE BIT(22) -#define DSC_ALT_ICH_SEL (1 << 20) -#define DSC_VBR_ENABLE (1 << 19) -#define DSC_422_ENABLE (1 << 18) -#define DSC_COLOR_SPACE_CONVERSION (1 << 17) -#define DSC_BLOCK_PREDICTION (1 << 16) -#define DSC_LINE_BUF_DEPTH_SHIFT 12 -#define DSC_BPC_SHIFT 8 -#define DSC_VER_MIN_SHIFT 4 -#define DSC_VER_MAJ (0x1 << 0) - -#define DSCA_PICTURE_PARAMETER_SET_1 _MMIO(0x6B204) -#define DSCC_PICTURE_PARAMETER_SET_1 _MMIO(0x6BA04) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_1_PB 0x78274 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_1_PB 0x78374 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_1_PC 0x78474 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_1_PC 0x78574 -#define ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_1_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_1_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_1_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_1_PC) -#define DSC_BPP(bpp) ((bpp) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_2 _MMIO(0x6B208) -#define DSCC_PICTURE_PARAMETER_SET_2 _MMIO(0x6BA08) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_2_PB 0x78278 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_2_PB 0x78378 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_2_PC 0x78478 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_2_PC 0x78578 -#define ICL_DSC0_PICTURE_PARAMETER_SET_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_2_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_2_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_2_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_2_PC) -#define DSC_PIC_WIDTH(pic_width) ((pic_width) << 16) -#define DSC_PIC_HEIGHT(pic_height) ((pic_height) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_3 _MMIO(0x6B20C) -#define DSCC_PICTURE_PARAMETER_SET_3 _MMIO(0x6BA0C) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_3_PB 0x7827C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_3_PB 0x7837C -#define _ICL_DSC0_PICTURE_PARAMETER_SET_3_PC 0x7847C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_3_PC 0x7857C -#define ICL_DSC0_PICTURE_PARAMETER_SET_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_3_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_3_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_3_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_3_PC) -#define DSC_SLICE_WIDTH(slice_width) ((slice_width) << 16) -#define DSC_SLICE_HEIGHT(slice_height) ((slice_height) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_4 _MMIO(0x6B210) -#define DSCC_PICTURE_PARAMETER_SET_4 _MMIO(0x6BA10) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_4_PB 0x78280 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_4_PB 0x78380 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_4_PC 0x78480 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_4_PC 0x78580 -#define ICL_DSC0_PICTURE_PARAMETER_SET_4(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_4_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_4_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_4(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_4_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_4_PC) -#define DSC_INITIAL_DEC_DELAY(dec_delay) ((dec_delay) << 16) -#define DSC_INITIAL_XMIT_DELAY(xmit_delay) ((xmit_delay) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_5 _MMIO(0x6B214) -#define DSCC_PICTURE_PARAMETER_SET_5 _MMIO(0x6BA14) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_5_PB 0x78284 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_5_PB 0x78384 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_5_PC 0x78484 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_5_PC 0x78584 -#define ICL_DSC0_PICTURE_PARAMETER_SET_5(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_5_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_5_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_5(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_5_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_5_PC) -#define DSC_SCALE_DEC_INT(scale_dec) ((scale_dec) << 16) -#define DSC_SCALE_INC_INT(scale_inc) ((scale_inc) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_6 _MMIO(0x6B218) -#define DSCC_PICTURE_PARAMETER_SET_6 _MMIO(0x6BA18) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_6_PB 0x78288 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_6_PB 0x78388 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_6_PC 0x78488 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_6_PC 0x78588 -#define ICL_DSC0_PICTURE_PARAMETER_SET_6(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_6_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_6_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_6(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_6_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_6_PC) -#define DSC_FLATNESS_MAX_QP(max_qp) ((max_qp) << 24) -#define DSC_FLATNESS_MIN_QP(min_qp) ((min_qp) << 16) -#define DSC_FIRST_LINE_BPG_OFFSET(offset) ((offset) << 8) -#define DSC_INITIAL_SCALE_VALUE(value) ((value) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_7 _MMIO(0x6B21C) -#define DSCC_PICTURE_PARAMETER_SET_7 _MMIO(0x6BA1C) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_7_PB 0x7828C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_7_PB 0x7838C -#define _ICL_DSC0_PICTURE_PARAMETER_SET_7_PC 0x7848C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_7_PC 0x7858C -#define ICL_DSC0_PICTURE_PARAMETER_SET_7(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_7_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_7_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_7(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_7_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_7_PC) -#define DSC_NFL_BPG_OFFSET(bpg_offset) ((bpg_offset) << 16) -#define DSC_SLICE_BPG_OFFSET(bpg_offset) ((bpg_offset) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_8 _MMIO(0x6B220) -#define DSCC_PICTURE_PARAMETER_SET_8 _MMIO(0x6BA20) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_8_PB 0x78290 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_8_PB 0x78390 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_8_PC 0x78490 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_8_PC 0x78590 -#define ICL_DSC0_PICTURE_PARAMETER_SET_8(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_8_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_8_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_8(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_8_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_8_PC) -#define DSC_INITIAL_OFFSET(initial_offset) ((initial_offset) << 16) -#define DSC_FINAL_OFFSET(final_offset) ((final_offset) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_9 _MMIO(0x6B224) -#define DSCC_PICTURE_PARAMETER_SET_9 _MMIO(0x6BA24) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_9_PB 0x78294 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_9_PB 0x78394 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_9_PC 0x78494 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_9_PC 0x78594 -#define ICL_DSC0_PICTURE_PARAMETER_SET_9(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_9_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_9_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_9(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_9_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_9_PC) -#define DSC_RC_EDGE_FACTOR(rc_edge_fact) ((rc_edge_fact) << 16) -#define DSC_RC_MODEL_SIZE(rc_model_size) ((rc_model_size) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_10 _MMIO(0x6B228) -#define DSCC_PICTURE_PARAMETER_SET_10 _MMIO(0x6BA28) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_10_PB 0x78298 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_10_PB 0x78398 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_10_PC 0x78498 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_10_PC 0x78598 -#define ICL_DSC0_PICTURE_PARAMETER_SET_10(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_10_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_10_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_10(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_10_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_10_PC) -#define DSC_RC_TARGET_OFF_LOW(rc_tgt_off_low) ((rc_tgt_off_low) << 20) -#define DSC_RC_TARGET_OFF_HIGH(rc_tgt_off_high) ((rc_tgt_off_high) << 16) -#define DSC_RC_QUANT_INC_LIMIT1(lim) ((lim) << 8) -#define DSC_RC_QUANT_INC_LIMIT0(lim) ((lim) << 0) - -#define DSCA_PICTURE_PARAMETER_SET_11 _MMIO(0x6B22C) -#define DSCC_PICTURE_PARAMETER_SET_11 _MMIO(0x6BA2C) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_11_PB 0x7829C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_11_PB 0x7839C -#define _ICL_DSC0_PICTURE_PARAMETER_SET_11_PC 0x7849C -#define _ICL_DSC1_PICTURE_PARAMETER_SET_11_PC 0x7859C -#define ICL_DSC0_PICTURE_PARAMETER_SET_11(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_11_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_11_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_11(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_11_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_11_PC) - -#define DSCA_PICTURE_PARAMETER_SET_12 _MMIO(0x6B260) -#define DSCC_PICTURE_PARAMETER_SET_12 _MMIO(0x6BA60) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_12_PB 0x782A0 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_12_PB 0x783A0 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_12_PC 0x784A0 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_12_PC 0x785A0 -#define ICL_DSC0_PICTURE_PARAMETER_SET_12(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_12_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_12_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_12(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_12_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_12_PC) - -#define DSCA_PICTURE_PARAMETER_SET_13 _MMIO(0x6B264) -#define DSCC_PICTURE_PARAMETER_SET_13 _MMIO(0x6BA64) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_13_PB 0x782A4 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_13_PB 0x783A4 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_13_PC 0x784A4 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_13_PC 0x785A4 -#define ICL_DSC0_PICTURE_PARAMETER_SET_13(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_13_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_13_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_13(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_13_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_13_PC) - -#define DSCA_PICTURE_PARAMETER_SET_14 _MMIO(0x6B268) -#define DSCC_PICTURE_PARAMETER_SET_14 _MMIO(0x6BA68) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_14_PB 0x782A8 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_14_PB 0x783A8 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_14_PC 0x784A8 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_14_PC 0x785A8 -#define ICL_DSC0_PICTURE_PARAMETER_SET_14(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_14_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_14_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_14(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_14_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_14_PC) - -#define DSCA_PICTURE_PARAMETER_SET_15 _MMIO(0x6B26C) -#define DSCC_PICTURE_PARAMETER_SET_15 _MMIO(0x6BA6C) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_15_PB 0x782AC -#define _ICL_DSC1_PICTURE_PARAMETER_SET_15_PB 0x783AC -#define _ICL_DSC0_PICTURE_PARAMETER_SET_15_PC 0x784AC -#define _ICL_DSC1_PICTURE_PARAMETER_SET_15_PC 0x785AC -#define ICL_DSC0_PICTURE_PARAMETER_SET_15(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_15_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_15_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_15(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_15_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_15_PC) - -#define DSCA_PICTURE_PARAMETER_SET_16 _MMIO(0x6B270) -#define DSCC_PICTURE_PARAMETER_SET_16 _MMIO(0x6BA70) -#define _ICL_DSC0_PICTURE_PARAMETER_SET_16_PB 0x782B0 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_16_PB 0x783B0 -#define _ICL_DSC0_PICTURE_PARAMETER_SET_16_PC 0x784B0 -#define _ICL_DSC1_PICTURE_PARAMETER_SET_16_PC 0x785B0 -#define ICL_DSC0_PICTURE_PARAMETER_SET_16(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_16_PB, \ - _ICL_DSC0_PICTURE_PARAMETER_SET_16_PC) -#define ICL_DSC1_PICTURE_PARAMETER_SET_16(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_16_PB, \ - _ICL_DSC1_PICTURE_PARAMETER_SET_16_PC) -#define DSC_SLICE_ROW_PER_FRAME(slice_row_per_frame) ((slice_row_per_frame) << 20) -#define DSC_SLICE_PER_LINE(slice_per_line) ((slice_per_line) << 16) -#define DSC_SLICE_CHUNK_SIZE(slice_chunk_size) ((slice_chunk_size) << 0) +#define _ICL_DSC0_PPS_0(pipe) _PICK_EVEN((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_0_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_0_PC) +#define _ICL_DSC1_PPS_0(pipe) _PICK_EVEN((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_0_PC) +#define ICL_DSC0_PPS(pipe, pps) _MMIO(_ICL_DSC0_PPS_0(pipe) + ((pps) * 4)) +#define ICL_DSC1_PPS(pipe, pps) _MMIO(_ICL_DSC1_PPS_0(pipe) + ((pps) * 4)) + +/* PPS 0 */ +#define DSC_PPS0_NATIVE_422_ENABLE REG_BIT(23) +#define DSC_PPS0_NATIVE_420_ENABLE REG_BIT(22) +#define DSC_PPS0_ALT_ICH_SEL REG_BIT(20) +#define DSC_PPS0_VBR_ENABLE REG_BIT(19) +#define DSC_PPS0_422_ENABLE REG_BIT(18) +#define DSC_PPS0_COLOR_SPACE_CONVERSION REG_BIT(17) +#define DSC_PPS0_BLOCK_PREDICTION REG_BIT(16) +#define DSC_PPS0_LINE_BUF_DEPTH_MASK REG_GENMASK(15, 12) +#define DSC_PPS0_LINE_BUF_DEPTH(depth) REG_FIELD_PREP(DSC_PPS0_LINE_BUF_DEPTH_MASK, depth) +#define DSC_PPS0_BPC_MASK REG_GENMASK(11, 8) +#define DSC_PPS0_BPC(bpc) REG_FIELD_PREP(DSC_PPS0_BPC_MASK, bpc) +#define DSC_PPS0_VER_MINOR_MASK REG_GENMASK(7, 4) +#define DSC_PPS0_VER_MINOR(minor) REG_FIELD_PREP(DSC_PPS0_VER_MINOR_MASK, minor) +#define DSC_PPS0_VER_MAJOR_MASK REG_GENMASK(3, 0) +#define DSC_PPS0_VER_MAJOR(major) REG_FIELD_PREP(DSC_PPS0_VER_MAJOR_MASK, major) + +/* PPS 1 */ +#define DSC_PPS1_BPP_MASK REG_GENMASK(9, 0) +#define DSC_PPS1_BPP(bpp) REG_FIELD_PREP(DSC_PPS1_BPP_MASK, bpp) + +/* PPS 2 */ +#define DSC_PPS2_PIC_WIDTH_MASK REG_GENMASK(31, 16) +#define DSC_PPS2_PIC_HEIGHT_MASK REG_GENMASK(15, 0) +#define DSC_PPS2_PIC_WIDTH(pic_width) REG_FIELD_PREP(DSC_PPS2_PIC_WIDTH_MASK, pic_width) +#define DSC_PPS2_PIC_HEIGHT(pic_height) REG_FIELD_PREP(DSC_PPS2_PIC_HEIGHT_MASK, pic_height) + +/* PPS 3 */ +#define DSC_PPS3_SLICE_WIDTH_MASK REG_GENMASK(31, 16) +#define DSC_PPS3_SLICE_HEIGHT_MASK REG_GENMASK(15, 0) +#define DSC_PPS3_SLICE_WIDTH(slice_width) REG_FIELD_PREP(DSC_PPS3_SLICE_WIDTH_MASK, slice_width) +#define DSC_PPS3_SLICE_HEIGHT(slice_height) REG_FIELD_PREP(DSC_PPS3_SLICE_HEIGHT_MASK, slice_height) + +/* PPS 4 */ +#define DSC_PPS4_INITIAL_DEC_DELAY_MASK REG_GENMASK(31, 16) +#define DSC_PPS4_INITIAL_XMIT_DELAY_MASK REG_GENMASK(9, 0) +#define DSC_PPS4_INITIAL_DEC_DELAY(dec_delay) REG_FIELD_PREP(DSC_PPS4_INITIAL_DEC_DELAY_MASK, \ + dec_delay) +#define DSC_PPS4_INITIAL_XMIT_DELAY(xmit_delay) REG_FIELD_PREP(DSC_PPS4_INITIAL_XMIT_DELAY_MASK, \ + xmit_delay) + +/* PPS 5 */ +#define DSC_PPS5_SCALE_DEC_INT_MASK REG_GENMASK(27, 16) +#define DSC_PPS5_SCALE_INC_INT_MASK REG_GENMASK(15, 0) +#define DSC_PPS5_SCALE_DEC_INT(scale_dec) REG_FIELD_PREP(DSC_PPS5_SCALE_DEC_INT_MASK, scale_dec) +#define DSC_PPS5_SCALE_INC_INT(scale_inc) REG_FIELD_PREP(DSC_PPS5_SCALE_INC_INT_MASK, scale_inc) + +/* PPS 6 */ +#define DSC_PPS6_FLATNESS_MAX_QP_MASK REG_GENMASK(28, 24) +#define DSC_PPS6_FLATNESS_MIN_QP_MASK REG_GENMASK(20, 16) +#define DSC_PPS6_FIRST_LINE_BPG_OFFSET_MASK REG_GENMASK(12, 8) +#define DSC_PPS6_INITIAL_SCALE_VALUE_MASK REG_GENMASK(5, 0) +#define DSC_PPS6_FLATNESS_MAX_QP(max_qp) REG_FIELD_PREP(DSC_PPS6_FLATNESS_MAX_QP_MASK, max_qp) +#define DSC_PPS6_FLATNESS_MIN_QP(min_qp) REG_FIELD_PREP(DSC_PPS6_FLATNESS_MIN_QP_MASK, min_qp) +#define DSC_PPS6_FIRST_LINE_BPG_OFFSET(offset) REG_FIELD_PREP(DSC_PPS6_FIRST_LINE_BPG_OFFSET_MASK, \ + offset) +#define DSC_PPS6_INITIAL_SCALE_VALUE(value) REG_FIELD_PREP(DSC_PPS6_INITIAL_SCALE_VALUE_MASK, \ + value) + +/* PPS 7 */ +#define DSC_PPS7_NFL_BPG_OFFSET_MASK REG_GENMASK(31, 16) +#define DSC_PPS7_SLICE_BPG_OFFSET_MASK REG_GENMASK(15, 0) +#define DSC_PPS7_NFL_BPG_OFFSET(bpg_offset) REG_FIELD_PREP(DSC_PPS7_NFL_BPG_OFFSET_MASK, bpg_offset) +#define DSC_PPS7_SLICE_BPG_OFFSET(bpg_offset) REG_FIELD_PREP(DSC_PPS7_SLICE_BPG_OFFSET_MASK, \ + bpg_offset) +/* PPS 8 */ +#define DSC_PPS8_INITIAL_OFFSET_MASK REG_GENMASK(31, 16) +#define DSC_PPS8_FINAL_OFFSET_MASK REG_GENMASK(15, 0) +#define DSC_PPS8_INITIAL_OFFSET(initial_offset) REG_FIELD_PREP(DSC_PPS8_INITIAL_OFFSET_MASK, \ + initial_offset) +#define DSC_PPS8_FINAL_OFFSET(final_offset) REG_FIELD_PREP(DSC_PPS8_FINAL_OFFSET_MASK, \ + final_offset) + +/* PPS 9 */ +#define DSC_PPS9_RC_EDGE_FACTOR_MASK REG_GENMASK(19, 16) +#define DSC_PPS9_RC_MODEL_SIZE_MASK REG_GENMASK(15, 0) +#define DSC_PPS9_RC_EDGE_FACTOR(rc_edge_fact) REG_FIELD_PREP(DSC_PPS9_RC_EDGE_FACTOR_MASK, \ + rc_edge_fact) +#define DSC_PPS9_RC_MODEL_SIZE(rc_model_size) REG_FIELD_PREP(DSC_PPS9_RC_MODEL_SIZE_MASK, \ + rc_model_size) + +/* PPS 10 */ +#define DSC_PPS10_RC_TGT_OFF_LOW_MASK REG_GENMASK(23, 20) +#define DSC_PPS10_RC_TGT_OFF_HIGH_MASK REG_GENMASK(19, 16) +#define DSC_PPS10_RC_QUANT_INC_LIMIT1_MASK REG_GENMASK(12, 8) +#define DSC_PPS10_RC_QUANT_INC_LIMIT0_MASK REG_GENMASK(4, 0) +#define DSC_PPS10_RC_TARGET_OFF_LOW(rc_tgt_off_low) REG_FIELD_PREP(DSC_PPS10_RC_TGT_OFF_LOW_MASK, \ + rc_tgt_off_low) +#define DSC_PPS10_RC_TARGET_OFF_HIGH(rc_tgt_off_high) REG_FIELD_PREP(DSC_PPS10_RC_TGT_OFF_HIGH_MASK, \ + rc_tgt_off_high) +#define DSC_PPS10_RC_QUANT_INC_LIMIT1(lim) REG_FIELD_PREP(DSC_PPS10_RC_QUANT_INC_LIMIT1_MASK, lim) +#define DSC_PPS10_RC_QUANT_INC_LIMIT0(lim) REG_FIELD_PREP(DSC_PPS10_RC_QUANT_INC_LIMIT0_MASK, lim) + +/* PPS 16 */ +#define DSC_PPS16_SLICE_ROW_PR_FRME_MASK REG_GENMASK(31, 20) +#define DSC_PPS16_SLICE_PER_LINE_MASK REG_GENMASK(18, 16) +#define DSC_PPS16_SLICE_CHUNK_SIZE_MASK REG_GENMASK(15, 0) +#define DSC_PPS16_SLICE_ROW_PER_FRAME(slice_row_per_frame) REG_FIELD_PREP(DSC_PPS16_SLICE_ROW_PR_FRME_MASK, \ + slice_row_per_frame) +#define DSC_PPS16_SLICE_PER_LINE(slice_per_line) REG_FIELD_PREP(DSC_PPS16_SLICE_PER_LINE_MASK, \ + slice_per_line) +#define DSC_PPS16_SLICE_CHUNK_SIZE(slice_chunk_size) REG_FIELD_PREP(DSC_PPS16_SLICE_CHUNK_SIZE_MASK, \ + slice_chunk_size) + +/* PPS 17 (MTL+) */ +#define DSC_PPS17_SL_BPG_OFFSET_MASK REG_GENMASK(31, 27) +#define DSC_PPS17_SL_BPG_OFFSET(offset) REG_FIELD_PREP(DSC_PPS17_SL_BPG_OFFSET_MASK, offset) + +/* PPS 18 (MTL+) */ +#define DSC_PPS18_NSL_BPG_OFFSET_MASK REG_GENMASK(31, 16) +#define DSC_PPS18_SL_OFFSET_ADJ_MASK REG_GENMASK(15, 0) +#define DSC_PPS18_NSL_BPG_OFFSET(offset) REG_FIELD_PREP(DSC_PPS18_NSL_BPG_OFFSET_MASK, offset) +#define DSC_PPS18_SL_OFFSET_ADJ(offset) REG_FIELD_PREP(DSC_PPS18_SL_OFFSET_ADJ_MASK, offset) /* Icelake Rate Control Buffer Threshold Registers */ #define DSCA_RC_BUF_THRESH_0 _MMIO(0x6B230) diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index 286a0bdd28..4b98833bfa 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -3,11 +3,9 @@ * Copyright © 2019 Intel Corporation */ -#include <linux/pci.h> #include <linux/vgaarb.h> #include <video/vga.h> - #include "soc/intel_gmch.h" #include "i915_drv.h" @@ -99,20 +97,6 @@ void intel_vga_reset_io_mem(struct drm_i915_private *i915) vga_put(pdev, VGA_RSRC_LEGACY_IO); } -static unsigned int -intel_vga_set_decode(struct pci_dev *pdev, bool enable_decode) -{ - struct drm_i915_private *i915 = pdev_to_i915(pdev); - - intel_gmch_vga_set_state(i915, enable_decode); - - if (enable_decode) - return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; - else - return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; -} - int intel_vga_register(struct drm_i915_private *i915) { @@ -127,7 +111,7 @@ int intel_vga_register(struct drm_i915_private *i915) * then we do not take part in VGA arbitration and the * vga_client_register() fails with -ENODEV. */ - ret = vga_client_register(pdev, intel_vga_set_decode); + ret = vga_client_register(pdev, intel_gmch_vga_set_decode); if (ret && ret != -ENODEV) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 88e4759b53..5d905f932c 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -42,6 +42,15 @@ bool intel_vrr_is_capable(struct intel_connector *connector) info->monitor_range.max_vfreq - info->monitor_range.min_vfreq > 10; } +bool intel_vrr_is_in_range(struct intel_connector *connector, int vrefresh) +{ + const struct drm_display_info *info = &connector->base.display_info; + + return intel_vrr_is_capable(connector) && + vrefresh >= info->monitor_range.min_vfreq && + vrefresh <= info->monitor_range.max_vfreq; +} + void intel_vrr_check_modeset(struct intel_atomic_state *state) { @@ -108,12 +117,17 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state, const struct drm_display_info *info = &connector->base.display_info; int vmin, vmax; - if (!intel_vrr_is_capable(connector)) + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) return; - if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + crtc_state->vrr.in_range = + intel_vrr_is_in_range(connector, drm_mode_vrefresh(adjusted_mode)); + if (!crtc_state->vrr.in_range) return; + if (HAS_LRR(i915)) + crtc_state->update_lrr = true; + vmin = DIV_ROUND_UP(adjusted_mode->crtc_clock * 1000, adjusted_mode->crtc_htotal * info->monitor_range.max_vfreq); vmax = adjusted_mode->crtc_clock * 1000 / diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h b/drivers/gpu/drm/i915/display/intel_vrr.h index de16960c49..8993785820 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.h +++ b/drivers/gpu/drm/i915/display/intel_vrr.h @@ -14,6 +14,7 @@ struct intel_connector; struct intel_crtc_state; bool intel_vrr_is_capable(struct intel_connector *connector); +bool intel_vrr_is_in_range(struct intel_connector *connector, int vrefresh); void intel_vrr_check_modeset(struct intel_atomic_state *state); void intel_vrr_compute_config(struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_wm.c b/drivers/gpu/drm/i915/display/intel_wm.c index b615449e70..82c4933ad5 100644 --- a/drivers/gpu/drm/i915/display/intel_wm.c +++ b/drivers/gpu/drm/i915/display/intel_wm.c @@ -290,7 +290,7 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, { struct seq_file *m = file->private_data; struct drm_i915_private *dev_priv = m->private; - u16 new[8] = { 0 }; + u16 new[8] = {}; int level; int ret; char tmp[32]; diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index ffc15d278a..245a64332c 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -16,10 +16,12 @@ #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fbc.h" +#include "intel_frontbuffer.h" #include "intel_psr.h" #include "skl_scaler.h" #include "skl_universal_plane.h" #include "skl_watermark.h" +#include "gt/intel_gt.h" #include "pxp/intel_pxp.h" static const u32 skl_plane_formats[] = { @@ -1245,7 +1247,7 @@ icl_plane_update_noarm(struct intel_plane *plane, } /* FLAT CCS doesn't need to program AUX_DIST */ - if (!HAS_FLAT_CCS(dev_priv)) + if (!HAS_FLAT_CCS(dev_priv) && DISPLAY_VER(dev_priv) < 20) intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), skl_plane_aux_dist(plane_state, color_plane)); @@ -1941,13 +1943,16 @@ static enum intel_fbc_id skl_fbc_id_for_pipe(enum pipe pipe) return pipe - PIPE_A + INTEL_FBC_A; } -static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv, +static bool skl_plane_has_fbc(struct drm_i915_private *i915, enum intel_fbc_id fbc_id, enum plane_id plane_id) { - if ((DISPLAY_RUNTIME_INFO(dev_priv)->fbc_mask & BIT(fbc_id)) == 0) + if ((DISPLAY_RUNTIME_INFO(i915)->fbc_mask & BIT(fbc_id)) == 0) return false; - return plane_id == PLANE_PRIMARY; + if (DISPLAY_VER(i915) >= 20) + return icl_is_hdr_plane(i915, plane_id); + else + return plane_id == PLANE_PRIMARY; } static struct intel_fbc *skl_plane_fbc(struct drm_i915_private *dev_priv, @@ -2168,11 +2173,6 @@ skl_plane_disable_flip_done(struct intel_plane *plane) static bool skl_plane_has_rc_ccs(struct drm_i915_private *i915, enum pipe pipe, enum plane_id plane_id) { - /* Wa_14017240301 */ - if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) || - IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) - return false; - /* Wa_22011186057 */ if (IS_ALDERLAKE_P(i915) && IS_DISPLAY_STEP(i915, STEP_A0, STEP_B0)) return false; @@ -2203,10 +2203,6 @@ static bool gen12_plane_has_mc_ccs(struct drm_i915_private *i915, if (IS_ALDERLAKE_P(i915) && IS_DISPLAY_STEP(i915, STEP_A0, STEP_B0)) return false; - /* Wa_14013215631 */ - if (IS_DG2_DISPLAY_STEP(i915, STEP_A0, STEP_C0)) - return false; - return plane_id < PLANE_SPRITE4; } diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 063929a42a..99b8ccdc3d 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1367,7 +1367,7 @@ skl_total_relative_data_rate(const struct intel_crtc_state *crtc_state) u64 data_rate = 0; for_each_plane_id_on_crtc(crtc, plane_id) { - if (plane_id == PLANE_CURSOR) + if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20) continue; data_rate += crtc_state->rel_data_rate[plane_id]; @@ -1514,10 +1514,12 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, return 0; /* Allocate fixed number of blocks for cursor. */ - cursor_size = skl_cursor_allocation(crtc_state, num_active); - iter.size -= cursor_size; - skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[PLANE_CURSOR], - alloc->end - cursor_size, alloc->end); + if (DISPLAY_VER(i915) < 20) { + cursor_size = skl_cursor_allocation(crtc_state, num_active); + iter.size -= cursor_size; + skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[PLANE_CURSOR], + alloc->end - cursor_size, alloc->end); + } iter.data_rate = skl_total_relative_data_rate(crtc_state); @@ -1531,7 +1533,7 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (plane_id == PLANE_CURSOR) { + if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20) { const struct skl_ddb_entry *ddb = &crtc_state->wm.skl.plane_ddb[plane_id]; @@ -1579,7 +1581,7 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (plane_id == PLANE_CURSOR) + if (plane_id == PLANE_CURSOR && DISPLAY_VER(i915) < 20) continue; if (DISPLAY_VER(i915) < 11 && @@ -2616,7 +2618,7 @@ skl_compute_ddb(struct intel_atomic_state *state) if (old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) { /* TODO: Implement vblank synchronized MBUS joining changes */ - ret = intel_modeset_all_pipes(state, "MBUS joining change"); + ret = intel_modeset_all_pipes_late(state, "MBUS joining change"); if (ret) return ret; } @@ -3132,10 +3134,12 @@ static void skl_wm_get_hw_state_and_sanitize(struct drm_i915_private *i915) skl_wm_sanitize(i915); } -void intel_wm_state_verify(struct intel_crtc *crtc, - struct intel_crtc_state *new_crtc_state) +void intel_wm_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc) { - struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); struct skl_hw_state { struct skl_ddb_entry ddb[I915_MAX_PLANES]; struct skl_ddb_entry ddb_y[I915_MAX_PLANES]; @@ -3719,3 +3723,17 @@ void skl_watermark_debugfs_register(struct drm_i915_private *i915) debugfs_create_file("i915_sagv_status", 0444, minor->debugfs_root, i915, &intel_sagv_status_fops); } + +unsigned int skl_watermark_max_latency(struct drm_i915_private *i915) +{ + int level; + + for (level = i915->display.wm.num_levels - 1; level >= 0; level--) { + unsigned int latency = skl_wm_latency(i915, level, NULL); + + if (latency) + return latency; + } + + return 0; +} diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h index f91a3d4ddc..fb0da36fd3 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.h +++ b/drivers/gpu/drm/i915/display/skl_watermark.h @@ -38,14 +38,16 @@ bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb, const struct skl_ddb_entry *entries, int num_entries, int ignore_idx); -void intel_wm_state_verify(struct intel_crtc *crtc, - struct intel_crtc_state *new_crtc_state); +void intel_wm_state_verify(struct intel_atomic_state *state, + struct intel_crtc *crtc); void skl_watermark_ipc_init(struct drm_i915_private *i915); void skl_watermark_ipc_update(struct drm_i915_private *i915); bool skl_watermark_ipc_enabled(struct drm_i915_private *i915); void skl_watermark_debugfs_register(struct drm_i915_private *i915); +unsigned int skl_watermark_max_latency(struct drm_i915_private *i915); + void skl_wm_init(struct drm_i915_private *i915); struct intel_dbuf_state { diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index d778b88413..f488394d31 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -23,6 +23,7 @@ * Author: Jani Nikula <jani.nikula@intel.com> */ +#include <linux/dmi.h> #include <linux/slab.h> #include <drm/drm_atomic_helper.h> @@ -1760,6 +1761,126 @@ static void vlv_dphy_param_init(struct intel_dsi *intel_dsi) intel_dsi_log_params(intel_dsi); } +typedef void (*vlv_dsi_dmi_quirk_func)(struct intel_dsi *intel_dsi); + +/* + * Vtotal is wrong on the Asus TF103C leading to the last line of the display + * being shown as the first line. The factory installed Android has a hardcoded + * modeline, causing it to not suffer from this BIOS bug. + * + * Original mode: "1280x800": 60 67700 1280 1312 1328 1376 800 808 812 820 0x8 0xa + * Fixed mode: "1280x800": 60 67700 1280 1312 1328 1376 800 808 812 816 0x8 0xa + * + * https://gitlab.freedesktop.org/drm/intel/-/issues/9381 + */ +static void vlv_dsi_asus_tf103c_mode_fixup(struct intel_dsi *intel_dsi) +{ + /* Cast away the const as we want to fixup the mode */ + struct drm_display_mode *fixed_mode = (struct drm_display_mode *) + intel_panel_preferred_fixed_mode(intel_dsi->attached_connector); + + if (fixed_mode->vtotal == 820) + fixed_mode->vtotal -= 4; +} + +/* + * On the Lenovo Yoga Tablet 2 830 / 1050 there are 2 problems: + * 1. The I2C MIPI sequence elements reference bus 3. ACPI has I2C1 - I2C7 + * which under Linux become bus 0 - 6. And the MIPI sequence reference + * to bus 3 is indented for I2C3 which is bus 2 under Linux. + * + * Note mipi_exec_i2c() cannot just subtract 1 from the bus + * given in the I2C MIPI sequence element. Since on other + * devices the I2C bus-numbers used in the MIPI sequences do + * actually start at 0. + * + * 2. width_/height_mm contain a bogus 192mm x 120mm size. This is + * especially a problem on the 8" 830 version which uses a 10:16 + * portrait screen where as the bogus size is 16:10. + * + * https://gitlab.freedesktop.org/drm/intel/-/issues/9379 + */ +static void vlv_dsi_lenovo_yoga_tab2_size_fixup(struct intel_dsi *intel_dsi) +{ + const struct drm_display_mode *fixed_mode = + intel_panel_preferred_fixed_mode(intel_dsi->attached_connector); + struct drm_display_info *info = &intel_dsi->attached_connector->base.display_info; + + intel_dsi->i2c_bus_num = 2; + + /* + * The 10" 1050 uses a 1920x1200 landscape screen, where as the 8" 830 + * uses a 1200x1920 portrait screen. + */ + if (fixed_mode->hdisplay == 1920) { + info->width_mm = 216; + info->height_mm = 135; + } else { + info->width_mm = 107; + info->height_mm = 171; + } +} + +/* + * On the Lenovo Yoga Tab 3 Pro YT3-X90F there are 2 problems: + * 1. i2c_acpi_find_adapter() picks the wrong adapter causing mipi_exec_i2c() + * to not work. Fix this by setting i2c_bus_num. + * 2. There is no backlight off MIPI sequence, causing the backlight to stay on. + * Add a backlight off sequence mirroring the existing backlight on sequence. + * + * https://gitlab.freedesktop.org/drm/intel/-/issues/9380 + */ +static void vlv_dsi_lenovo_yoga_tab3_backlight_fixup(struct intel_dsi *intel_dsi) +{ + static const u8 backlight_off_sequence[16] = { + /* Header Seq-id 7, length after header 11 bytes */ + 0x07, 0x0b, 0x00, 0x00, 0x00, + /* MIPI_SEQ_ELEM_I2C bus 0 addr 0x2c reg 0x00 data-len 1 data 0x00 */ + 0x04, 0x08, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x01, 0x00, + /* MIPI_SEQ_ELEM_END */ + 0x00 + }; + struct intel_connector *connector = intel_dsi->attached_connector; + + intel_dsi->i2c_bus_num = 0; + connector->panel.vbt.dsi.sequence[MIPI_SEQ_BACKLIGHT_OFF] = backlight_off_sequence; +} + +static const struct dmi_system_id vlv_dsi_dmi_quirk_table[] = { + { + /* Asus Transformer Pad TF103C */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), + }, + .driver_data = (void *)vlv_dsi_asus_tf103c_mode_fixup, + }, + { + /* + * Lenovo Yoga Tablet 2 830F/L or 1050F/L (The 8" and 10" + * Lenovo Yoga Tablet 2 use the same mainboard) + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."), + DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"), + DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"), + /* Partial match on beginning of BIOS version */ + DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"), + }, + .driver_data = (void *)vlv_dsi_lenovo_yoga_tab2_size_fixup, + }, + { + /* Lenovo Yoga Tab 3 Pro YT3-X90F */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"), + }, + .driver_data = (void *)vlv_dsi_lenovo_yoga_tab3_backlight_fixup, + }, + { } +}; + void vlv_dsi_init(struct drm_i915_private *dev_priv) { struct intel_dsi *intel_dsi; @@ -1768,6 +1889,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) struct intel_connector *intel_connector; struct drm_connector *connector; struct drm_display_mode *current_mode; + const struct dmi_system_id *dmi_id; enum port port; enum pipe pipe; @@ -1899,6 +2021,14 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) goto err_cleanup_connector; } + dmi_id = dmi_first_match(vlv_dsi_dmi_quirk_table); + if (dmi_id) { + vlv_dsi_dmi_quirk_func quirk_func = + (vlv_dsi_dmi_quirk_func)dmi_id->driver_data; + + quirk_func(intel_dsi); + } + intel_panel_init(intel_connector, NULL); intel_backlight_setup(intel_connector, INVALID_PIPE); diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.h b/drivers/gpu/drm/i915/display/vlv_dsi.h index 0c2b279df9..cf9d7b82f2 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.h +++ b/drivers/gpu/drm/i915/display/vlv_dsi.h @@ -12,8 +12,21 @@ enum port; struct drm_i915_private; struct intel_dsi; +#ifdef I915 void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port); enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt); void vlv_dsi_init(struct drm_i915_private *dev_priv); +#else +static inline void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port) +{ +} +static inline enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt) +{ + return 0; +} +static inline void vlv_dsi_init(struct drm_i915_private *dev_priv) +{ +} +#endif #endif /* __VLV_DSI_H__ */ diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_pll.h b/drivers/gpu/drm/i915/display/vlv_dsi_pll.h index ab9291ad1e..fbe5113dbe 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi_pll.h +++ b/drivers/gpu/drm/i915/display/vlv_dsi_pll.h @@ -32,7 +32,16 @@ u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, struct intel_crtc_state *config); void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port); +#ifdef I915 void assert_dsi_pll_enabled(struct drm_i915_private *i915); void assert_dsi_pll_disabled(struct drm_i915_private *i915); +#else +static inline void assert_dsi_pll_enabled(struct drm_i915_private *i915) +{ +} +static inline void assert_dsi_pll_disabled(struct drm_i915_private *i915) +{ +} +#endif #endif /* __VLV_DSI_PLL_H__ */ |