diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index f9805f47ef62..80eebdc4c670 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -14084,13 +14084,13 @@ static void verify_wm_state(struct intel_crtc *crtc, skl_pipe_ddb_get_hw_state(crtc, hw->ddb_y, hw->ddb_uv); - hw_enabled_slices = intel_enabled_dbuf_slices_num(dev_priv); + hw_enabled_slices = intel_enabled_dbuf_slices_mask(dev_priv); if (INTEL_GEN(dev_priv) >= 11 && - hw_enabled_slices != dev_priv->enabled_dbuf_slices_num) + hw_enabled_slices != dev_priv->enabled_dbuf_slices_mask) drm_err(&dev_priv->drm, - "mismatch in DBUF Slices (expected %u, got %u)\n", - dev_priv->enabled_dbuf_slices_num, + "mismatch in DBUF Slices (expected 0x%x, got 0x%x)\n", + dev_priv->enabled_dbuf_slices_mask, hw_enabled_slices); /* planes */ @@ -15448,22 +15448,23 @@ static void intel_update_trans_port_sync_crtcs(struct intel_crtc *crtc, static void icl_dbuf_slice_pre_update(struct intel_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - u8 hw_enabled_slices = dev_priv->enabled_dbuf_slices_num; - u8 required_slices = state->enabled_dbuf_slices_num; + u8 hw_enabled_slices = dev_priv->enabled_dbuf_slices_mask; + u8 required_slices = state->enabled_dbuf_slices_mask; + u8 slices_union = hw_enabled_slices | required_slices; /* If 2nd DBuf slice required, enable it here */ - if (INTEL_GEN(dev_priv) >= 11 && required_slices > hw_enabled_slices) - icl_dbuf_slices_update(dev_priv, required_slices); + if (INTEL_GEN(dev_priv) >= 11 && slices_union != hw_enabled_slices) + icl_dbuf_slices_update(dev_priv, slices_union); } static void icl_dbuf_slice_post_update(struct intel_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); - u8 hw_enabled_slices = dev_priv->enabled_dbuf_slices_num; - u8 required_slices = state->enabled_dbuf_slices_num; + u8 hw_enabled_slices = dev_priv->enabled_dbuf_slices_mask; + u8 required_slices = state->enabled_dbuf_slices_mask; /* If 2nd DBuf slice is no more required disable it */ - if (INTEL_GEN(dev_priv) >= 11 && required_slices < hw_enabled_slices) + if (INTEL_GEN(dev_priv) >= 11 && required_slices != hw_enabled_slices) icl_dbuf_slices_update(dev_priv, required_slices); } diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index a41dee385f8e..53056def5414 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -15,6 +15,7 @@ #include "intel_display_types.h" #include "intel_dpio_phy.h" #include "intel_hotplug.h" +#include "intel_pm.h" #include "intel_sideband.h" #include "intel_tc.h" #include "intel_vga.h" @@ -1041,11 +1042,13 @@ static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv, static void gen9_assert_dbuf_enabled(struct drm_i915_private *dev_priv) { - u32 tmp = intel_de_read(dev_priv, DBUF_CTL_S(0)); + u8 hw_enabled_dbuf_slices = intel_enabled_dbuf_slices_mask(dev_priv); + u8 enabled_dbuf_slices = dev_priv->enabled_dbuf_slices_mask; - WARN((tmp & (DBUF_POWER_STATE | DBUF_POWER_REQUEST)) != - (DBUF_POWER_STATE | DBUF_POWER_REQUEST), - "Unexpected DBuf power power state (0x%08x)\n", tmp); + WARN(hw_enabled_dbuf_slices != enabled_dbuf_slices, + "Unexpected DBuf power power state (0x%08x, expected 0x%08x)\n", + hw_enabled_dbuf_slices, + enabled_dbuf_slices); } static void gen9_disable_dc_states(struct drm_i915_private *dev_priv) @@ -4425,87 +4428,58 @@ bool intel_dbuf_slice_set(struct drm_i915_private *dev_priv, static void gen9_dbuf_enable(struct drm_i915_private *dev_priv) { - intel_dbuf_slice_set(dev_priv, DBUF_CTL_S(0), true); + icl_dbuf_slices_update(dev_priv, BIT(DBUF_S1)); } static void gen9_dbuf_disable(struct drm_i915_private *dev_priv) { - intel_dbuf_slice_set(dev_priv, DBUF_CTL_S(0), false); -} - -static u8 intel_dbuf_max_slices(struct drm_i915_private *dev_priv) -{ - if (INTEL_GEN(dev_priv) < 11) - return 1; - return 2; + icl_dbuf_slices_update(dev_priv, 0); } void icl_dbuf_slices_update(struct drm_i915_private *dev_priv, u8 req_slices) { - const u8 hw_enabled_slices = dev_priv->enabled_dbuf_slices_num; - bool ret; + int i; + int max_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices; + struct i915_power_domains *power_domains = &dev_priv->power_domains; - if (req_slices > intel_dbuf_max_slices(dev_priv)) { - drm_err(&dev_priv->drm, - "Invalid number of dbuf slices requested\n"); - return; + WARN(hweight8(req_slices) > max_slices, + "Invalid number of dbuf slices requested\n"); + + DRM_DEBUG_KMS("Updating dbuf slices to 0x%x\n", req_slices); + + /* + * Might be running this in parallel to gen9_dc_off_power_well_enable + * being called from intel_dp_detect for instance, + * which causes assertion triggered by race condition, + * as gen9_assert_dbuf_enabled might preempt this when registers + * were already updated, while dev_priv was not. + */ + mutex_lock(&power_domains->lock); + + for (i = 0; i < max_slices; i++) { + intel_dbuf_slice_set(dev_priv, + DBUF_CTL_S(i), + (req_slices & BIT(i)) != 0); } - if (req_slices == hw_enabled_slices || req_slices == 0) - return; + dev_priv->enabled_dbuf_slices_mask = req_slices; - if (req_slices > hw_enabled_slices) - ret = intel_dbuf_slice_set(dev_priv, - DBUF_CTL_S(DBUF_S2), true); - else - ret = intel_dbuf_slice_set(dev_priv, - DBUF_CTL_S(DBUF_S2), false); - - if (ret) - dev_priv->enabled_dbuf_slices_num = req_slices; + mutex_unlock(&power_domains->lock); } static void icl_dbuf_enable(struct drm_i915_private *dev_priv) { - intel_de_write(dev_priv, DBUF_CTL_S(0), - intel_de_read(dev_priv, DBUF_CTL_S(0)) | DBUF_POWER_REQUEST); - intel_de_write(dev_priv, DBUF_CTL_S(1), - intel_de_read(dev_priv, DBUF_CTL_S(1)) | DBUF_POWER_REQUEST); - intel_de_posting_read(dev_priv, DBUF_CTL_S(1)); - - udelay(10); - - if (!(intel_de_read(dev_priv, DBUF_CTL_S(0)) & DBUF_POWER_STATE) || - !(intel_de_read(dev_priv, DBUF_CTL_S(1)) & DBUF_POWER_STATE)) - drm_err(&dev_priv->drm, "DBuf power enable timeout\n"); - else - /* - * FIXME: for now pretend that we only have 1 slice, see - * intel_enabled_dbuf_slices_num(). - */ - dev_priv->enabled_dbuf_slices_num = 1; + /* + * Just power up 1 slice, we will + * figure out later which slices we have and what we need. + */ + icl_dbuf_slices_update(dev_priv, BIT(DBUF_S1)); } static void icl_dbuf_disable(struct drm_i915_private *dev_priv) { - intel_de_write(dev_priv, DBUF_CTL_S(0), - intel_de_read(dev_priv, DBUF_CTL_S(0)) & ~DBUF_POWER_REQUEST); - intel_de_write(dev_priv, DBUF_CTL_S(1), - intel_de_read(dev_priv, DBUF_CTL_S(1)) & ~DBUF_POWER_REQUEST); - intel_de_posting_read(dev_priv, DBUF_CTL_S(1)); - - udelay(10); - - if ((intel_de_read(dev_priv, DBUF_CTL_S(0)) & DBUF_POWER_STATE) || - (intel_de_read(dev_priv, DBUF_CTL_S(1)) & DBUF_POWER_STATE)) - drm_err(&dev_priv->drm, "DBuf power disable timeout!\n"); - else - /* - * FIXME: for now pretend that the first slice is always - * enabled, see intel_enabled_dbuf_slices_num(). - */ - dev_priv->enabled_dbuf_slices_num = 1; + icl_dbuf_slices_update(dev_priv, 0); } static void icl_mbus_init(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 91267063cf27..ceabb4d23892 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -496,7 +496,7 @@ struct intel_atomic_state { bool global_state_changed; /* Number of enabled DBuf slices */ - u8 enabled_dbuf_slices_num; + u8 enabled_dbuf_slices_mask; struct i915_sw_fence commit_ready; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ebebc4246e6c..3452926d7b77 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1186,7 +1186,7 @@ struct drm_i915_private { bool distrust_bios_wm; } wm; - u8 enabled_dbuf_slices_num; /* GEN11 has configurable 2 slices */ + u8 enabled_dbuf_slices_mask; /* GEN11 has configurable 2 slices */ struct dram_info { bool valid; diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 6413f22356ae..da337aee632e 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -615,7 +615,8 @@ static const struct intel_device_info chv_info = { .has_gt_uc = 1, \ .display.has_hdcp = 1, \ .display.has_ipc = 1, \ - .ddb_size = 896 + .ddb_size = 896, \ + .num_supported_dbuf_slices = 1 #define SKL_PLATFORM \ GEN9_FEATURES, \ @@ -650,6 +651,7 @@ static const struct intel_device_info skl_gt4_info = { #define GEN9_LP_FEATURES \ GEN(9), \ .is_lp = 1, \ + .num_supported_dbuf_slices = 1, \ .display.has_hotplug = 1, \ .engine_mask = BIT(RCS0) | BIT(VCS0) | BIT(BCS0) | BIT(VECS0), \ .pipe_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C), \ @@ -774,6 +776,7 @@ static const struct intel_device_info cnl_info = { }, \ GEN(11), \ .ddb_size = 2048, \ + .num_supported_dbuf_slices = 2, \ .has_logical_ring_elsq = 1, \ .color = { .degamma_lut_size = 33, .gamma_lut_size = 262145 } diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 2725cb7fc169..7d4d122d2182 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -180,6 +180,7 @@ struct intel_device_info { } display; u16 ddb_size; /* in blocks */ + u8 num_supported_dbuf_slices; /* number of DBuf slices */ /* Register offsets for the various display pipes and transcoders */ int pipe_offsets[I915_MAX_TRANSCODERS]; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f9e00ca61302..4c87abcdb622 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3597,26 +3597,18 @@ bool ilk_disable_lp_wm(struct drm_i915_private *dev_priv) return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL); } -u8 intel_enabled_dbuf_slices_num(struct drm_i915_private *dev_priv) +u8 intel_enabled_dbuf_slices_mask(struct drm_i915_private *dev_priv) { - u8 enabled_dbuf_slices_num; + int i; + int max_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices; + u8 enabled_slices_mask = 0; - /* Slice 1 will always be enabled */ - enabled_dbuf_slices_num = 1; + for (i = 0; i < max_slices; i++) { + if (I915_READ(DBUF_CTL_S(i)) & DBUF_POWER_STATE) + enabled_slices_mask |= BIT(i); + } - /* Gen prior to GEN11 have only one DBuf slice */ - if (INTEL_GEN(dev_priv) < 11) - return enabled_dbuf_slices_num; - - /* - * FIXME: for now we'll only ever use 1 slice; pretend that we have - * only that 1 slice enabled until we have a proper way for on-demand - * toggling of the second slice. - */ - if (0 && I915_READ(DBUF_CTL_S(DBUF_S2)) & DBUF_POWER_STATE) - enabled_dbuf_slices_num++; - - return enabled_dbuf_slices_num; + return enabled_slices_mask; } /* @@ -3824,8 +3816,6 @@ static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv, { struct drm_atomic_state *state = crtc_state->uapi.state; struct intel_atomic_state *intel_state = to_intel_atomic_state(state); - const struct drm_display_mode *adjusted_mode; - u64 total_data_bw; u16 ddb_size = INTEL_INFO(dev_priv)->ddb_size; drm_WARN_ON(&dev_priv->drm, ddb_size == 0); @@ -3833,23 +3823,8 @@ static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv, if (INTEL_GEN(dev_priv) < 11) return ddb_size - 4; /* 4 blocks for bypass path allocation */ - adjusted_mode = &crtc_state->hw.adjusted_mode; - total_data_bw = total_data_rate * drm_mode_vrefresh(adjusted_mode); - - /* - * 12GB/s is maximum BW supported by single DBuf slice. - * - * FIXME dbuf slice code is broken: - * - must wait for planes to stop using the slice before powering it off - * - plane straddling both slices is illegal in multi-pipe scenarios - * - should validate we stay within the hw bandwidth limits - */ - if (0 && (num_active > 1 || total_data_bw >= GBps(12))) { - intel_state->enabled_dbuf_slices_num = 2; - } else { - intel_state->enabled_dbuf_slices_num = 1; - ddb_size /= 2; - } + intel_state->enabled_dbuf_slices_mask = BIT(DBUF_S1); + ddb_size /= 2; return ddb_size; } @@ -4046,8 +4021,8 @@ void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc, void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv) { - dev_priv->enabled_dbuf_slices_num = - intel_enabled_dbuf_slices_num(dev_priv); + dev_priv->enabled_dbuf_slices_mask = + intel_enabled_dbuf_slices_mask(dev_priv); } /* @@ -5155,7 +5130,7 @@ skl_compute_ddb(struct intel_atomic_state *state) struct intel_crtc *crtc; int ret, i; - state->enabled_dbuf_slices_num = dev_priv->enabled_dbuf_slices_num; + state->enabled_dbuf_slices_mask = dev_priv->enabled_dbuf_slices_mask; for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h index 22fd2daf608e..d60a85421c5a 100644 --- a/drivers/gpu/drm/i915/intel_pm.h +++ b/drivers/gpu/drm/i915/intel_pm.h @@ -32,7 +32,7 @@ void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv); void vlv_wm_get_hw_state(struct drm_i915_private *dev_priv); void ilk_wm_get_hw_state(struct drm_i915_private *dev_priv); void skl_wm_get_hw_state(struct drm_i915_private *dev_priv); -u8 intel_enabled_dbuf_slices_num(struct drm_i915_private *dev_priv); +u8 intel_enabled_dbuf_slices_mask(struct drm_i915_private *dev_priv); void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc, struct skl_ddb_entry *ddb_y, struct skl_ddb_entry *ddb_uv);