diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 0c8e8fc31f4e..28764ce3edee 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -38,6 +38,8 @@ #include "intel_pcode.h" #include "intel_psr.h" #include "intel_vdsc.h" +#include "skl_watermark.h" +#include "skl_watermark_regs.h" #include "vlv_sideband.h" /** @@ -1580,6 +1582,8 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv, } out: + if (DISPLAY_VER(dev_priv) >= 20) + cdclk_config->joined_mbus = intel_de_read(dev_priv, MBUS_CTL) & MBUS_JOIN; /* * Can't read this out :( Let's assume it's * at least what the CDCLK frequency requires. @@ -1779,6 +1783,29 @@ static int cdclk_squash_divider(u16 waveform) return hweight16(waveform ?: 0xffff); } +static bool mdclk_source_is_cdclk_pll(struct drm_i915_private *i915) +{ + return DISPLAY_VER(i915) >= 20; +} + +int intel_mdclk_cdclk_ratio(struct drm_i915_private *i915, + const struct intel_cdclk_config *cdclk_config) +{ + if (mdclk_source_is_cdclk_pll(i915)) + return DIV_ROUND_UP(cdclk_config->vco, cdclk_config->cdclk); + + /* Otherwise, source for MDCLK is CD2XCLK. */ + return 2; +} + +static void xe2lpd_mdclk_cdclk_ratio_program(struct drm_i915_private *i915, + const struct intel_cdclk_config *cdclk_config) +{ + intel_dbuf_mdclk_cdclk_ratio_update(i915, + intel_mdclk_cdclk_ratio(i915, cdclk_config), + cdclk_config->joined_mbus); +} + static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i915, const struct intel_cdclk_config *old_cdclk_config, const struct intel_cdclk_config *new_cdclk_config, @@ -1932,6 +1959,9 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, return; } + if (DISPLAY_VER(dev_priv) >= 20 && cdclk < dev_priv->display.cdclk.hw.cdclk) + xe2lpd_mdclk_cdclk_ratio_program(dev_priv, cdclk_config); + if (cdclk_compute_crawl_and_squash_midpoint(dev_priv, &dev_priv->display.cdclk.hw, cdclk_config, &mid_cdclk_config)) { _bxt_set_cdclk(dev_priv, &mid_cdclk_config, pipe); @@ -1940,6 +1970,9 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, _bxt_set_cdclk(dev_priv, cdclk_config, pipe); } + if (DISPLAY_VER(dev_priv) >= 20 && cdclk > dev_priv->display.cdclk.hw.cdclk) + xe2lpd_mdclk_cdclk_ratio_program(dev_priv, cdclk_config); + if (DISPLAY_VER(dev_priv) >= 14) /* * NOOP - No Pcode communication needed for @@ -2438,6 +2471,17 @@ static void intel_cdclk_pcode_post_notify(struct intel_atomic_state *state) update_cdclk, update_pipe_count); } +bool intel_cdclk_is_decreasing_later(struct intel_atomic_state *state) +{ + const struct intel_cdclk_state *old_cdclk_state = + intel_atomic_get_old_cdclk_state(state); + const struct intel_cdclk_state *new_cdclk_state = + intel_atomic_get_new_cdclk_state(state); + + return new_cdclk_state && !new_cdclk_state->disable_pipes && + new_cdclk_state->actual.cdclk < old_cdclk_state->actual.cdclk; +} + /** * intel_set_cdclk_pre_plane_update - Push the CDCLK state to the hardware * @state: intel atomic state @@ -2479,6 +2523,12 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state) old_cdclk_state->actual.voltage_level); } + /* + * mbus joining will be changed later by + * intel_dbuf_mbus_{pre,post}_ddb_update() + */ + cdclk_config.joined_mbus = old_cdclk_state->actual.joined_mbus; + drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed); intel_set_cdclk(i915, &cdclk_config, pipe); @@ -3027,6 +3077,20 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state, return 0; } +int intel_cdclk_state_set_joined_mbus(struct intel_atomic_state *state, bool joined_mbus) +{ + struct intel_cdclk_state *cdclk_state; + + cdclk_state = intel_atomic_get_cdclk_state(state); + if (IS_ERR(cdclk_state)) + return PTR_ERR(cdclk_state); + + cdclk_state->actual.joined_mbus = joined_mbus; + cdclk_state->logical.joined_mbus = joined_mbus; + + return intel_atomic_lock_global_state(&cdclk_state->base); +} + int intel_cdclk_init(struct drm_i915_private *dev_priv) { struct intel_cdclk_state *cdclk_state; @@ -3148,6 +3212,15 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) "Modeset required for cdclk change\n"); } + if (intel_mdclk_cdclk_ratio(dev_priv, &old_cdclk_state->actual) != + intel_mdclk_cdclk_ratio(dev_priv, &new_cdclk_state->actual)) { + int ratio = intel_mdclk_cdclk_ratio(dev_priv, &new_cdclk_state->actual); + + ret = intel_dbuf_state_set_mdclk_cdclk_ratio(state, ratio); + if (ret) + return ret; + } + drm_dbg_kms(&dev_priv->drm, "New cdclk calculated to be logical %u kHz, actual %u kHz\n", new_cdclk_state->logical.cdclk, diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.h b/drivers/gpu/drm/i915/display/intel_cdclk.h index 71bc032bfef1..6c97b61c569c 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.h +++ b/drivers/gpu/drm/i915/display/intel_cdclk.h @@ -18,6 +18,8 @@ struct intel_crtc_state; struct intel_cdclk_config { unsigned int cdclk, vco, ref, bypass; u8 voltage_level; + /* This field is only valid for Xe2LPD and above. */ + bool joined_mbus; }; struct intel_cdclk_state { @@ -65,6 +67,9 @@ void intel_update_cdclk(struct drm_i915_private *dev_priv); u32 intel_read_rawclk(struct drm_i915_private *dev_priv); bool intel_cdclk_needs_modeset(const struct intel_cdclk_config *a, const struct intel_cdclk_config *b); +int intel_mdclk_cdclk_ratio(struct drm_i915_private *i915, + const struct intel_cdclk_config *cdclk_config); +bool intel_cdclk_is_decreasing_later(struct intel_atomic_state *state); void intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state); void intel_set_cdclk_post_plane_update(struct intel_atomic_state *state); void intel_cdclk_dump_config(struct drm_i915_private *i915, @@ -75,6 +80,7 @@ void intel_cdclk_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config); int intel_cdclk_atomic_check(struct intel_atomic_state *state, bool *need_cdclk_calc); +int intel_cdclk_state_set_joined_mbus(struct intel_atomic_state *state, bool joined_mbus); struct intel_cdclk_state * intel_atomic_get_cdclk_state(struct intel_atomic_state *state); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 978b6c83ba20..5d346a9eac58 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6555,8 +6555,8 @@ static void intel_enable_crtc(struct intel_atomic_state *state, intel_crtc_enable_pipe_crc(crtc); } -static void intel_update_crtc(struct intel_atomic_state *state, - struct intel_crtc *crtc) +static void intel_pre_update_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) { struct drm_i915_private *i915 = to_i915(state->base.dev); const struct intel_crtc_state *old_crtc_state = @@ -6598,6 +6598,15 @@ static void intel_update_crtc(struct intel_atomic_state *state, intel_color_commit_noarm(new_crtc_state); intel_crtc_planes_update_noarm(state, crtc); +} + +static void intel_update_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); /* Perform vblank evasion around commit operation */ intel_pipe_update_start(state, crtc); @@ -6626,7 +6635,7 @@ static void intel_update_crtc(struct intel_atomic_state *state, * valid pipe configuration from the BIOS we need to take care * of enabling them on the CRTC's first fastset. */ - if (intel_crtc_needs_fastset(new_crtc_state) && !modeset && + if (intel_crtc_needs_fastset(new_crtc_state) && old_crtc_state->inherited) intel_crtc_arm_fifo_underrun(crtc, new_crtc_state); } @@ -6654,9 +6663,10 @@ static void intel_old_crtc_state_disables(struct intel_atomic_state *state, static void intel_commit_modeset_disables(struct intel_atomic_state *state) { + struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_crtc_state *new_crtc_state, *old_crtc_state; struct intel_crtc *crtc; - u32 handled = 0; + u8 disable_pipes = 0; int i; for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, @@ -6664,21 +6674,29 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state) if (!intel_crtc_needs_modeset(new_crtc_state)) continue; + /* + * Needs to be done even for pipes + * that weren't enabled previously. + */ intel_pre_plane_update(state, crtc); if (!old_crtc_state->hw.active) continue; + disable_pipes |= BIT(crtc->pipe); + } + + for_each_old_intel_crtc_in_state(state, crtc, old_crtc_state, i) { + if ((disable_pipes & BIT(crtc->pipe)) == 0) + continue; + intel_crtc_disable_planes(state, crtc); } /* Only disable port sync and MST slaves */ 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; - - if (!old_crtc_state->hw.active) + if ((disable_pipes & BIT(crtc->pipe)) == 0) continue; /* In case of Transcoder port Sync master slave CRTCs can be @@ -6693,22 +6711,23 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state) intel_old_crtc_state_disables(state, old_crtc_state, new_crtc_state, crtc); - handled |= BIT(crtc->pipe); + + disable_pipes &= ~BIT(crtc->pipe); } /* Disable everything else left on */ for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - if (!intel_crtc_needs_modeset(new_crtc_state) || - (handled & BIT(crtc->pipe))) - continue; - - if (!old_crtc_state->hw.active) + if ((disable_pipes & BIT(crtc->pipe)) == 0) continue; intel_old_crtc_state_disables(state, old_crtc_state, new_crtc_state, crtc); + + disable_pipes &= ~BIT(crtc->pipe); } + + drm_WARN_ON(&i915->drm, disable_pipes); } static void intel_commit_modeset_enables(struct intel_atomic_state *state) @@ -6722,6 +6741,13 @@ static void intel_commit_modeset_enables(struct intel_atomic_state *state) continue; intel_enable_crtc(state, crtc); + intel_pre_update_crtc(state, crtc); + } + + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + if (!new_crtc_state->hw.active) + continue; + intel_update_crtc(state, crtc); } } @@ -6759,6 +6785,17 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) * So first lets enable all pipes that do not need a fullmodeset as * those don't have any external dependency. */ + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + enum pipe pipe = crtc->pipe; + + if ((update_pipes & BIT(pipe)) == 0) + continue; + + intel_pre_update_crtc(state, crtc); + } + + intel_dbuf_mbus_pre_ddb_update(state); + while (update_pipes) { for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { @@ -6789,6 +6826,8 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) } } + intel_dbuf_mbus_post_ddb_update(state); + update_pipes = modeset_pipes; /* @@ -6829,6 +6868,15 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) /* * Finally we do the plane updates/etc. for all pipes that got enabled. */ + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + enum pipe pipe = crtc->pipe; + + if ((update_pipes & BIT(pipe)) == 0) + continue; + + intel_pre_update_crtc(state, crtc); + } + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { enum pipe pipe = crtc->pipe; @@ -7050,7 +7098,6 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_encoders_update_prepare(state); intel_dbuf_pre_plane_update(state); - intel_mbus_dbox_update(state); for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { if (new_crtc_state->do_async_flip) diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index e48369983eb1..480fddc0bdfd 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -12,6 +12,7 @@ #include "intel_atomic.h" #include "intel_atomic_plane.h" #include "intel_bw.h" +#include "intel_cdclk.h" #include "intel_crtc.h" #include "intel_de.h" #include "intel_display.h" @@ -2587,10 +2588,17 @@ skl_compute_ddb(struct intel_atomic_state *state) return ret; } - if (HAS_MBUS_JOINING(i915)) + if (HAS_MBUS_JOINING(i915)) { new_dbuf_state->joined_mbus = adlp_check_mbus_joined(new_dbuf_state->active_pipes); + if (old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) { + ret = intel_cdclk_state_set_joined_mbus(state, new_dbuf_state->joined_mbus); + if (ret) + return ret; + } + } + for_each_intel_crtc(&i915->drm, crtc) { enum pipe pipe = crtc->pipe; @@ -2614,13 +2622,6 @@ skl_compute_ddb(struct intel_atomic_state *state) if (ret) return ret; - if (old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) { - /* TODO: Implement vblank synchronized MBUS joining changes */ - ret = intel_modeset_all_pipes_late(state, "MBUS joining change"); - if (ret) - return ret; - } - drm_dbg_kms(&i915->drm, "Enabled dbuf slices 0x%x -> 0x%x (total dbuf slices 0x%x), mbus joined? %s->%s\n", old_dbuf_state->enabled_slices, @@ -2999,6 +3000,8 @@ static void skl_wm_get_hw_state(struct drm_i915_private *i915) if (HAS_MBUS_JOINING(i915)) dbuf_state->joined_mbus = intel_de_read(i915, MBUS_CTL) & MBUS_JOIN; + dbuf_state->mdclk_cdclk_ratio = intel_mdclk_cdclk_ratio(i915, &i915->display.cdclk.hw); + for_each_intel_crtc(&i915->drm, crtc) { struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); @@ -3472,93 +3475,6 @@ int intel_dbuf_init(struct drm_i915_private *i915) return 0; } -static void intel_dbuf_mdclk_cdclk_ratio_update(struct drm_i915_private *i915, - u8 ratio, - bool joined_mbus) -{ - enum dbuf_slice slice; - - if (joined_mbus) - ratio *= 2; - - for_each_dbuf_slice(i915, slice) - intel_de_rmw(i915, DBUF_CTL_S(slice), - DBUF_MIN_TRACKER_STATE_SERVICE_MASK, - DBUF_MIN_TRACKER_STATE_SERVICE(ratio - 1)); -} - -/* - * Configure MBUS_CTL and all DBUF_CTL_S of each slice to join_mbus state before - * update the request state of all DBUS slices. - */ -static void update_mbus_pre_enable(struct intel_atomic_state *state) -{ - struct drm_i915_private *i915 = to_i915(state->base.dev); - u32 mbus_ctl; - const struct intel_dbuf_state *dbuf_state = - intel_atomic_get_new_dbuf_state(state); - - if (!HAS_MBUS_JOINING(i915)) - return; - - /* - * TODO: Implement vblank synchronized MBUS joining changes. - * Must be properly coordinated with dbuf reprogramming. - */ - if (dbuf_state->joined_mbus) - mbus_ctl = MBUS_HASHING_MODE_1x4 | MBUS_JOIN | - MBUS_JOIN_PIPE_SELECT_NONE; - else - mbus_ctl = MBUS_HASHING_MODE_2x2 | - MBUS_JOIN_PIPE_SELECT_NONE; - - intel_de_rmw(i915, MBUS_CTL, - MBUS_HASHING_MODE_MASK | MBUS_JOIN | - MBUS_JOIN_PIPE_SELECT_MASK, mbus_ctl); - - intel_dbuf_mdclk_cdclk_ratio_update(i915, 2, dbuf_state->joined_mbus); -} - -void intel_dbuf_pre_plane_update(struct intel_atomic_state *state) -{ - struct drm_i915_private *i915 = to_i915(state->base.dev); - const struct intel_dbuf_state *new_dbuf_state = - intel_atomic_get_new_dbuf_state(state); - const struct intel_dbuf_state *old_dbuf_state = - intel_atomic_get_old_dbuf_state(state); - - if (!new_dbuf_state || - (new_dbuf_state->enabled_slices == old_dbuf_state->enabled_slices && - new_dbuf_state->joined_mbus == old_dbuf_state->joined_mbus)) - return; - - WARN_ON(!new_dbuf_state->base.changed); - - update_mbus_pre_enable(state); - gen9_dbuf_slices_update(i915, - old_dbuf_state->enabled_slices | - new_dbuf_state->enabled_slices); -} - -void intel_dbuf_post_plane_update(struct intel_atomic_state *state) -{ - struct drm_i915_private *i915 = to_i915(state->base.dev); - const struct intel_dbuf_state *new_dbuf_state = - intel_atomic_get_new_dbuf_state(state); - const struct intel_dbuf_state *old_dbuf_state = - intel_atomic_get_old_dbuf_state(state); - - if (!new_dbuf_state || - (new_dbuf_state->enabled_slices == old_dbuf_state->enabled_slices && - new_dbuf_state->joined_mbus == old_dbuf_state->joined_mbus)) - return; - - WARN_ON(!new_dbuf_state->base.changed); - - gen9_dbuf_slices_update(i915, - new_dbuf_state->enabled_slices); -} - static bool xelpdp_is_only_pipe_per_dbuf_bank(enum pipe pipe, u8 active_pipes) { switch (pipe) { @@ -3578,7 +3494,7 @@ static bool xelpdp_is_only_pipe_per_dbuf_bank(enum pipe pipe, u8 active_pipes) return false; } -void intel_mbus_dbox_update(struct intel_atomic_state *state) +static void intel_mbus_dbox_update(struct intel_atomic_state *state) { struct drm_i915_private *i915 = to_i915(state->base.dev); const struct intel_dbuf_state *new_dbuf_state, *old_dbuf_state; @@ -3642,6 +3558,217 @@ void intel_mbus_dbox_update(struct intel_atomic_state *state) } } +int intel_dbuf_state_set_mdclk_cdclk_ratio(struct intel_atomic_state *state, + int ratio) +{ + struct intel_dbuf_state *dbuf_state; + + dbuf_state = intel_atomic_get_dbuf_state(state); + if (IS_ERR(dbuf_state)) + return PTR_ERR(dbuf_state); + + dbuf_state->mdclk_cdclk_ratio = ratio; + + return intel_atomic_lock_global_state(&dbuf_state->base); +} + +void intel_dbuf_mdclk_cdclk_ratio_update(struct drm_i915_private *i915, + int ratio, bool joined_mbus) +{ + enum dbuf_slice slice; + + if (!HAS_MBUS_JOINING(i915)) + return; + + if (DISPLAY_VER(i915) >= 20) + intel_de_rmw(i915, MBUS_CTL, MBUS_TRANSLATION_THROTTLE_MIN_MASK, + MBUS_TRANSLATION_THROTTLE_MIN(ratio - 1)); + + if (joined_mbus) + ratio *= 2; + + drm_dbg_kms(&i915->drm, "Updating dbuf ratio to %d (mbus joined: %s)\n", + ratio, str_yes_no(joined_mbus)); + + for_each_dbuf_slice(i915, slice) + intel_de_rmw(i915, DBUF_CTL_S(slice), + DBUF_MIN_TRACKER_STATE_SERVICE_MASK, + DBUF_MIN_TRACKER_STATE_SERVICE(ratio - 1)); +} + +static void intel_dbuf_mdclk_min_tracker_update(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dbuf_state *old_dbuf_state = + intel_atomic_get_old_dbuf_state(state); + const struct intel_dbuf_state *new_dbuf_state = + intel_atomic_get_new_dbuf_state(state); + int mdclk_cdclk_ratio; + + if (intel_cdclk_is_decreasing_later(state)) { + /* cdclk/mdclk will be changed later by intel_set_cdclk_post_plane_update() */ + mdclk_cdclk_ratio = old_dbuf_state->mdclk_cdclk_ratio; + } else { + /* cdclk/mdclk already changed by intel_set_cdclk_pre_plane_update() */ + mdclk_cdclk_ratio = new_dbuf_state->mdclk_cdclk_ratio; + } + + intel_dbuf_mdclk_cdclk_ratio_update(i915, mdclk_cdclk_ratio, + new_dbuf_state->joined_mbus); +} + +static enum pipe intel_mbus_joined_pipe(struct intel_atomic_state *state, + const struct intel_dbuf_state *dbuf_state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + enum pipe pipe = ffs(dbuf_state->active_pipes) - 1; + const struct intel_crtc_state *new_crtc_state; + struct intel_crtc *crtc; + + drm_WARN_ON(&i915->drm, !dbuf_state->joined_mbus); + drm_WARN_ON(&i915->drm, !is_power_of_2(dbuf_state->active_pipes)); + + crtc = intel_crtc_for_pipe(i915, pipe); + new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); + + if (new_crtc_state && !intel_crtc_needs_modeset(new_crtc_state)) + return pipe; + else + return INVALID_PIPE; +} + +static void intel_dbuf_mbus_join_update(struct intel_atomic_state *state, + enum pipe pipe) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dbuf_state *old_dbuf_state = + intel_atomic_get_old_dbuf_state(state); + const struct intel_dbuf_state *new_dbuf_state = + intel_atomic_get_new_dbuf_state(state); + u32 mbus_ctl; + + drm_dbg_kms(&i915->drm, "Changing mbus joined: %s -> %s (pipe: %c)\n", + str_yes_no(old_dbuf_state->joined_mbus), + str_yes_no(new_dbuf_state->joined_mbus), + pipe != INVALID_PIPE ? pipe_name(pipe) : '*'); + + if (new_dbuf_state->joined_mbus) + mbus_ctl = MBUS_HASHING_MODE_1x4 | MBUS_JOIN; + else + mbus_ctl = MBUS_HASHING_MODE_2x2; + + if (pipe != INVALID_PIPE) + mbus_ctl |= MBUS_JOIN_PIPE_SELECT(pipe); + else + mbus_ctl |= MBUS_JOIN_PIPE_SELECT_NONE; + + intel_de_rmw(i915, MBUS_CTL, + MBUS_HASHING_MODE_MASK | MBUS_JOIN | + MBUS_JOIN_PIPE_SELECT_MASK, mbus_ctl); +} + +void intel_dbuf_mbus_pre_ddb_update(struct intel_atomic_state *state) +{ + const struct intel_dbuf_state *new_dbuf_state = + intel_atomic_get_new_dbuf_state(state); + const struct intel_dbuf_state *old_dbuf_state = + intel_atomic_get_old_dbuf_state(state); + + if (!new_dbuf_state) + return; + + if (!old_dbuf_state->joined_mbus && new_dbuf_state->joined_mbus) { + enum pipe pipe = intel_mbus_joined_pipe(state, new_dbuf_state); + + WARN_ON(!new_dbuf_state->base.changed); + + intel_dbuf_mbus_join_update(state, pipe); + intel_mbus_dbox_update(state); + intel_dbuf_mdclk_min_tracker_update(state); + } +} + +void intel_dbuf_mbus_post_ddb_update(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dbuf_state *new_dbuf_state = + intel_atomic_get_new_dbuf_state(state); + const struct intel_dbuf_state *old_dbuf_state = + intel_atomic_get_old_dbuf_state(state); + + if (!new_dbuf_state) + return; + + if (old_dbuf_state->joined_mbus && !new_dbuf_state->joined_mbus) { + enum pipe pipe = intel_mbus_joined_pipe(state, old_dbuf_state); + + WARN_ON(!new_dbuf_state->base.changed); + + intel_dbuf_mdclk_min_tracker_update(state); + intel_mbus_dbox_update(state); + intel_dbuf_mbus_join_update(state, pipe); + + if (pipe != INVALID_PIPE) { + struct intel_crtc *crtc = intel_crtc_for_pipe(i915, pipe); + + intel_crtc_wait_for_next_vblank(crtc); + } + } else if (old_dbuf_state->joined_mbus == new_dbuf_state->joined_mbus && + old_dbuf_state->active_pipes != new_dbuf_state->active_pipes) { + WARN_ON(!new_dbuf_state->base.changed); + + intel_dbuf_mdclk_min_tracker_update(state); + intel_mbus_dbox_update(state); + } + +} + +void intel_dbuf_pre_plane_update(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dbuf_state *new_dbuf_state = + intel_atomic_get_new_dbuf_state(state); + const struct intel_dbuf_state *old_dbuf_state = + intel_atomic_get_old_dbuf_state(state); + u8 old_slices, new_slices; + + if (!new_dbuf_state) + return; + + old_slices = old_dbuf_state->enabled_slices; + new_slices = old_dbuf_state->enabled_slices | new_dbuf_state->enabled_slices; + + if (old_slices == new_slices) + return; + + WARN_ON(!new_dbuf_state->base.changed); + + gen9_dbuf_slices_update(i915, new_slices); +} + +void intel_dbuf_post_plane_update(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dbuf_state *new_dbuf_state = + intel_atomic_get_new_dbuf_state(state); + const struct intel_dbuf_state *old_dbuf_state = + intel_atomic_get_old_dbuf_state(state); + u8 old_slices, new_slices; + + if (!new_dbuf_state) + return; + + old_slices = old_dbuf_state->enabled_slices | new_dbuf_state->enabled_slices; + new_slices = new_dbuf_state->enabled_slices; + + if (old_slices == new_slices) + return; + + WARN_ON(!new_dbuf_state->base.changed); + + gen9_dbuf_slices_update(i915, new_slices); +} + static int skl_watermark_ipc_status_show(struct seq_file *m, void *data) { struct drm_i915_private *i915 = m->private; diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h index fb0da36fd3ec..032eeffe65c4 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.h +++ b/drivers/gpu/drm/i915/display/skl_watermark.h @@ -58,6 +58,7 @@ struct intel_dbuf_state { u8 slices[I915_MAX_PIPES]; u8 enabled_slices; u8 active_pipes; + u8 mdclk_cdclk_ratio; bool joined_mbus; }; @@ -71,9 +72,15 @@ intel_atomic_get_dbuf_state(struct intel_atomic_state *state); to_intel_dbuf_state(intel_atomic_get_new_global_obj_state(state, &to_i915(state->base.dev)->display.dbuf.obj)) int intel_dbuf_init(struct drm_i915_private *i915); +int intel_dbuf_state_set_mdclk_cdclk_ratio(struct intel_atomic_state *state, + int ratio); + void intel_dbuf_pre_plane_update(struct intel_atomic_state *state); void intel_dbuf_post_plane_update(struct intel_atomic_state *state); -void intel_mbus_dbox_update(struct intel_atomic_state *state); +void intel_dbuf_mdclk_cdclk_ratio_update(struct drm_i915_private *i915, + int ratio, bool joined_mbus); +void intel_dbuf_mbus_pre_ddb_update(struct intel_atomic_state *state); +void intel_dbuf_mbus_post_ddb_update(struct intel_atomic_state *state); #endif /* __SKL_WATERMARK_H__ */ diff --git a/drivers/gpu/drm/i915/display/skl_watermark_regs.h b/drivers/gpu/drm/i915/display/skl_watermark_regs.h index 20b30c9a6613..269163fa3350 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark_regs.h +++ b/drivers/gpu/drm/i915/display/skl_watermark_regs.h @@ -32,14 +32,16 @@ #define MBUS_BBOX_CTL_S1 _MMIO(0x45040) #define MBUS_BBOX_CTL_S2 _MMIO(0x45044) -#define MBUS_CTL _MMIO(0x4438C) -#define MBUS_JOIN REG_BIT(31) -#define MBUS_HASHING_MODE_MASK REG_BIT(30) -#define MBUS_HASHING_MODE_2x2 REG_FIELD_PREP(MBUS_HASHING_MODE_MASK, 0) -#define MBUS_HASHING_MODE_1x4 REG_FIELD_PREP(MBUS_HASHING_MODE_MASK, 1) -#define MBUS_JOIN_PIPE_SELECT_MASK REG_GENMASK(28, 26) -#define MBUS_JOIN_PIPE_SELECT(pipe) REG_FIELD_PREP(MBUS_JOIN_PIPE_SELECT_MASK, pipe) -#define MBUS_JOIN_PIPE_SELECT_NONE MBUS_JOIN_PIPE_SELECT(7) +#define MBUS_CTL _MMIO(0x4438C) +#define MBUS_JOIN REG_BIT(31) +#define MBUS_HASHING_MODE_MASK REG_BIT(30) +#define MBUS_HASHING_MODE_2x2 REG_FIELD_PREP(MBUS_HASHING_MODE_MASK, 0) +#define MBUS_HASHING_MODE_1x4 REG_FIELD_PREP(MBUS_HASHING_MODE_MASK, 1) +#define MBUS_JOIN_PIPE_SELECT_MASK REG_GENMASK(28, 26) +#define MBUS_JOIN_PIPE_SELECT(pipe) REG_FIELD_PREP(MBUS_JOIN_PIPE_SELECT_MASK, pipe) +#define MBUS_JOIN_PIPE_SELECT_NONE MBUS_JOIN_PIPE_SELECT(7) +#define MBUS_TRANSLATION_THROTTLE_MIN_MASK REG_GENMASK(15, 13) +#define MBUS_TRANSLATION_THROTTLE_MIN(val) REG_FIELD_PREP(MBUS_TRANSLATION_THROTTLE_MIN_MASK, val) /* Watermark register definitions for SKL */ #define _CUR_WM_A_0 0x70140