On Tue, 07 Mar 2023, "Lisovskiy, Stanislav" <stanislav.lisovskiy@xxxxxxxxx> wrote: > On Mon, Mar 06, 2023 at 08:14:35PM +0200, Jani Nikula wrote: >> On Mon, 27 Feb 2023, Stanislav Lisovskiy <stanislav.lisovskiy@xxxxxxxxx> wrote: >> > Display to communicate display pipe count/CDCLK/voltage configuration >> > to Pcode for more accurate power accounting for gen >= 12. >> > Existing sequence is only sending the voltage value to the Pcode. >> > Adding new sequence with current cdclk associate with voltage value masking. >> > Adding pcode request when any pipe power well will disable or enable. >> > >> > v2: - Make intel_cdclk_need_serialize static to make CI compiler happy. >> > >> > Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@xxxxxxxxx> >> > --- >> > drivers/gpu/drm/i915/display/intel_cdclk.c | 174 +++++++++++++++++++-- >> > drivers/gpu/drm/i915/display/intel_cdclk.h | 2 + >> > drivers/gpu/drm/i915/i915_reg.h | 14 ++ >> > 3 files changed, 176 insertions(+), 14 deletions(-) >> > >> > diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c >> > index 084a483f9776..df5a21f6a393 100644 >> > --- a/drivers/gpu/drm/i915/display/intel_cdclk.c >> > +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c >> > @@ -1932,10 +1932,10 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, >> > * NOOP - No Pcode communication needed for >> > * Display versions 14 and beyond >> > */; >> > - else if (DISPLAY_VER(dev_priv) >= 11) >> > + else if (DISPLAY_VER(dev_priv) >= 11 && !IS_DG2(dev_priv)) >> > ret = snb_pcode_write(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL, >> > cdclk_config->voltage_level); >> > - else >> > + if (DISPLAY_VER(dev_priv) < 11) { >> > /* >> > * The timeout isn't specified, the 2ms used here is based on >> > * experiment. >> > @@ -1946,7 +1946,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, >> > HSW_PCODE_DE_WRITE_FREQ_REQ, >> > cdclk_config->voltage_level, >> > 150, 2); >> > - >> > + } >> > if (ret) { >> > drm_err(&dev_priv->drm, >> > "PCode CDCLK freq set failed, (err %d, freq %d)\n", >> > @@ -2242,6 +2242,40 @@ void intel_cdclk_dump_config(struct drm_i915_private *i915, >> > cdclk_config->voltage_level); >> > } >> > >> > +static void intel_pcode_notify(struct drm_i915_private *i915, >> > + u8 voltage_level, >> > + u8 active_pipe_count, >> > + u8 cdclk, How can that be u8? >> > + bool cdclk_update_valid, >> > + bool pipe_count_update_valid) Also not super happy about the flags arguments... could have cdclk == 0 means not valid and int active_pipe_count == -1 means not valid. Maybe. >> > +{ >> > + int ret; >> > + u32 update_mask = 0; >> > + >> > + if (DISPLAY_VER(i915) < 12) >> > + return; >> > + >> > + update_mask = DISPLAY_TO_PCODE_UPDATE_MASK(cdclk, active_pipe_count, voltage_level); >> > + >> > + if (cdclk_update_valid) >> > + update_mask |= DISPLAY_TO_PCODE_CDCLK_VALID; >> > + >> > + if (pipe_count_update_valid) >> > + update_mask |= DISPLAY_TO_PCODE_PIPE_COUNT_VALID; >> > + >> > + ret = skl_pcode_request(&i915->uncore, SKL_PCODE_CDCLK_CONTROL, >> > + SKL_CDCLK_PREPARE_FOR_CHANGE | >> > + update_mask, >> > + SKL_CDCLK_READY_FOR_CHANGE, >> > + SKL_CDCLK_READY_FOR_CHANGE, 3); >> > + if (ret) { >> > + drm_err(&i915->drm, >> > + "Failed to inform PCU about display config (err %d)\n", >> > + ret); >> > + return; >> >> Superfluous return. >> >> > + } >> > +} >> > + >> > /** >> > * intel_set_cdclk - Push the CDCLK configuration to the hardware >> > * @dev_priv: i915 device >> > @@ -2311,6 +2345,98 @@ static void intel_set_cdclk(struct drm_i915_private *dev_priv, >> > } >> > } >> > >> > +/** >> > + * intel_cdclk_power_usage_to_pcode_pre_notification: display to pcode notification This doesn't need to be a kernel-doc comment (and it's a malformed one at that). Ditto for the others. >> > + * before the enabling power wells. >> > + * send notification with cdclk, number of pipes, voltage_level. >> > + * @state: intel atomic state >> > + */ >> > +void intel_cdclk_power_usage_to_pcode_pre_notification(struct intel_atomic_state *state) >> >> This could be static? >> >> Not happy with the name, really, but at least it could use a >> verb. Notify instead of notification. > > Any hint for better naming? Maybe just intel_cdclk_pcode_pre_notify(), intel_cdclk_pcode_post_notify(), and then intel_cdclk_pcode_notify() as the shared thing? > >> >> > +{ >> > + struct drm_i915_private *dev_priv = to_i915(state->base.dev); >> >> No new dev_priv please. >> >> > + 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); >> > + unsigned int cdclk = 0; u8 voltage_level, num_active_pipes = 0; >> > + bool change_cdclk, update_pipe_count; >> > + >> > + if (!intel_cdclk_changed(&old_cdclk_state->actual, >> > + &new_cdclk_state->actual) && >> > + (new_cdclk_state->active_pipes == >> > + old_cdclk_state->active_pipes)) >> > + return; >> > + >> > + /* According to "Sequence Before Frequency Change", voltage level set to 0x3 */ >> > + voltage_level = DISPLAY_TO_PCODE_VOLTAGE_MAX; >> > + >> > + change_cdclk = new_cdclk_state->actual.cdclk != old_cdclk_state->actual.cdclk; >> > + update_pipe_count = hweight8(new_cdclk_state->active_pipes) > >> > + hweight8(old_cdclk_state->active_pipes); >> > + >> > + /* >> > + * According to "Sequence Before Frequency Change", >> > + * if CDCLK is increasing, set bits 25:16 to upcoming CDCLK, >> > + * if CDCLK is decreasing or not changing, set bits 25:16 to current CDCLK, >> > + * which basically means we choose the maximum of old and new CDCLK, if we know both >> > + */ >> > + if (change_cdclk) >> > + cdclk = max(new_cdclk_state->actual.cdclk, old_cdclk_state->actual.cdclk); >> > + >> > + /* >> > + * According to "Sequence For Pipe Count Change", >> > + * if pipe count is increasing, set bits 25:16 to upcoming pipe count >> > + * (power well is enabled) >> > + * no action if it is decreasing, before the change >> > + */ >> > + if (update_pipe_count) >> > + num_active_pipes = hweight8(new_cdclk_state->active_pipes); >> > + >> > + intel_pcode_notify(dev_priv, voltage_level, num_active_pipes, cdclk, >> > + change_cdclk, update_pipe_count); >> > +} >> > + >> > +/* intel_cdclk_power_usage_to_pcode_post_notification: after frequency change sending >> > + * voltage_level, active pipes, current CDCLK frequency. >> > + * @state: intel atomic state >> > + */ >> > +void intel_cdclk_power_usage_to_pcode_post_notification(struct intel_atomic_state *state) >> >> Ditto about static & naming. >> >> > +{ >> > + struct drm_i915_private *dev_priv = to_i915(state->base.dev); >> >> No new dev_priv please. >> >> > + const struct intel_cdclk_state *new_cdclk_state = >> > + intel_atomic_get_new_cdclk_state(state); >> > + const struct intel_cdclk_state *old_cdclk_state = >> > + intel_atomic_get_old_cdclk_state(state); >> > + unsigned int cdclk = 0; u8 voltage_level, num_active_pipes = 0; >> > + bool update_cdclk, update_pipe_count; >> > + >> > + /* According to "Sequence After Frequency Change", set voltage to used level */ >> > + voltage_level = new_cdclk_state->actual.voltage_level; >> > + >> > + update_cdclk = new_cdclk_state->actual.cdclk != old_cdclk_state->actual.cdclk; >> > + update_pipe_count = hweight8(new_cdclk_state->active_pipes) < >> > + hweight8(old_cdclk_state->active_pipes); >> > + >> > + /* >> > + * According to "Sequence After Frequency Change", >> > + * set bits 25:16 to current CDCLK >> > + */ >> > + if (update_cdclk) >> > + cdclk = new_cdclk_state->actual.cdclk; >> > + >> > + /* >> > + * According to "Sequence For Pipe Count Change", >> > + * if pipe count is decreasing, set bits 25:16 to current pipe count, >> > + * after the change(power well is disabled) >> > + * no action if it is increasing, after the change >> > + */ >> > + if (update_pipe_count) >> > + num_active_pipes = hweight8(new_cdclk_state->active_pipes); >> > + >> > + intel_pcode_notify(dev_priv, voltage_level, num_active_pipes, cdclk, >> > + update_cdclk, update_pipe_count); >> > +} >> > + >> > /** >> > * intel_set_cdclk_pre_plane_update - Push the CDCLK state to the hardware >> > * @state: intel atomic state >> > @@ -2321,7 +2447,7 @@ static void intel_set_cdclk(struct drm_i915_private *dev_priv, >> > void >> > intel_set_cdclk_pre_plane_update(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); >> > const struct intel_cdclk_state *old_cdclk_state = >> > intel_atomic_get_old_cdclk_state(state); >> > const struct intel_cdclk_state *new_cdclk_state = >> > @@ -2332,11 +2458,14 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state) >> > &new_cdclk_state->actual)) >> > return; >> > >> > + if (DISPLAY_VER(i915) >= 12) >> > + intel_cdclk_power_usage_to_pcode_pre_notification(state); >> > + >> > if (pipe == INVALID_PIPE || >> > old_cdclk_state->actual.cdclk <= new_cdclk_state->actual.cdclk) { >> > - drm_WARN_ON(&dev_priv->drm, !new_cdclk_state->base.changed); >> > + drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed); >> > >> > - intel_set_cdclk(dev_priv, &new_cdclk_state->actual, pipe); >> > + intel_set_cdclk(i915, &new_cdclk_state->actual, pipe); >> > } >> > } >> > >> > @@ -2350,7 +2479,7 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state) >> > void >> > intel_set_cdclk_post_plane_update(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); >> > const struct intel_cdclk_state *old_cdclk_state = >> > intel_atomic_get_old_cdclk_state(state); >> > const struct intel_cdclk_state *new_cdclk_state = >> > @@ -2361,11 +2490,14 @@ intel_set_cdclk_post_plane_update(struct intel_atomic_state *state) >> > &new_cdclk_state->actual)) >> > return; >> > >> > + if (DISPLAY_VER(i915) >= 12) >> > + intel_cdclk_power_usage_to_pcode_post_notification(state); >> > + >> > if (pipe != INVALID_PIPE && >> > old_cdclk_state->actual.cdclk > new_cdclk_state->actual.cdclk) { >> > - drm_WARN_ON(&dev_priv->drm, !new_cdclk_state->base.changed); >> > + drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed); >> > >> > - intel_set_cdclk(dev_priv, &new_cdclk_state->actual, pipe); >> > + intel_set_cdclk(i915, &new_cdclk_state->actual, pipe); >> > } >> > } >> > >> > @@ -2871,6 +3003,21 @@ int intel_cdclk_init(struct drm_i915_private *dev_priv) >> > return 0; >> > } >> > >> > +static bool intel_cdclk_need_serialize(struct drm_i915_private *i915, >> > + const struct intel_cdclk_state *old_cdclk_state, >> > + const struct intel_cdclk_state *new_cdclk_state) >> > +{ >> > + /* >> > + * We need to poke hw for gen >= 12, because we notify PCode if >> > + * pipe power well count changes. >> > + */ >> > + return intel_cdclk_changed(&old_cdclk_state->actual, >> > + &new_cdclk_state->actual) || >> > + ((DISPLAY_VER(i915) >= 12 && >> > + hweight8(old_cdclk_state->active_pipes) != >> > + hweight8(new_cdclk_state->active_pipes))); >> >> That's getting a bit unweildy for one expression. >> >> > +} >> > + >> > int intel_modeset_calc_cdclk(struct intel_atomic_state *state) >> > { >> > struct drm_i915_private *dev_priv = to_i915(state->base.dev); >> > @@ -2892,8 +3039,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) >> > if (ret) >> > return ret; >> > >> > - if (intel_cdclk_changed(&old_cdclk_state->actual, >> > - &new_cdclk_state->actual)) { >> > + if (intel_cdclk_need_serialize(dev_priv, old_cdclk_state, new_cdclk_state)) { >> > /* >> > * Also serialize commits across all crtcs >> > * if the actual hw needs to be poked. >> > @@ -2905,9 +3051,9 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) >> > old_cdclk_state->force_min_cdclk != new_cdclk_state->force_min_cdclk || >> > intel_cdclk_changed(&old_cdclk_state->logical, >> > &new_cdclk_state->logical)) { >> > - ret = intel_atomic_lock_global_state(&new_cdclk_state->base); >> > - if (ret) >> > - return ret; >> > + ret = intel_atomic_lock_global_state(&new_cdclk_state->base); >> > + if (ret) >> > + return ret; Accidental indentation change? >> > } else { >> > return 0; >> > } >> > diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.h b/drivers/gpu/drm/i915/display/intel_cdclk.h >> > index 51e2f6a11ce4..fa356adc61d9 100644 >> > --- a/drivers/gpu/drm/i915/display/intel_cdclk.h >> > +++ b/drivers/gpu/drm/i915/display/intel_cdclk.h >> > @@ -64,6 +64,8 @@ bool intel_cdclk_needs_modeset(const struct intel_cdclk_config *a, >> > const struct intel_cdclk_config *b); >> > 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_power_usage_to_pcode_pre_notification(struct intel_atomic_state *state); >> > +void intel_cdclk_power_usage_to_pcode_post_notification(struct intel_atomic_state *state); >> > void intel_cdclk_dump_config(struct drm_i915_private *i915, >> > const struct intel_cdclk_config *cdclk_config, >> > const char *context); >> > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h >> > index c1efa655fb68..9f786952585b 100644 >> > --- a/drivers/gpu/drm/i915/i915_reg.h >> > +++ b/drivers/gpu/drm/i915/i915_reg.h >> > @@ -6526,6 +6526,20 @@ >> > #define ICL_PCODE_MEM_SS_READ_GLOBAL_INFO (0x0 << 8) >> > #define ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point) (((point) << 16) | (0x1 << 8)) >> > #define ADL_PCODE_MEM_SS_READ_PSF_GV_INFO ((0) | (0x2 << 8)) >> > +#define DISPLAY_TO_PCODE_CDCLK_MAX 0x28D >> > +#define DISPLAY_TO_PCODE_VOLTAGE_MASK REG_GENMASK(1, 0) >> > +#define DISPLAY_TO_PCODE_VOLTAGE_MAX DISPLAY_TO_PCODE_VOLTAGE_MASK >> > +#define DISPLAY_TO_PCODE_CDCLK_VALID REG_BIT(27) >> > +#define DISPLAY_TO_PCODE_PIPE_COUNT_VALID REG_BIT(31) >> > +#define DISPLAY_TO_PCODE_CDCLK_MASK REG_GENMASK(25, 16) >> > +#define DISPLAY_TO_PCODE_PIPE_COUNT_MASK REG_GENMASK(30, 28) >> > +#define DISPLAY_TO_PCODE_CDCLK(x) REG_FIELD_PREP(DISPLAY_TO_PCODE_CDCLK_MASK, (x)) >> > +#define DISPLAY_TO_PCODE_PIPE_COUNT(x) REG_FIELD_PREP(DISPLAY_TO_PCODE_PIPE_COUNT_MASK, (x)) >> > +#define DISPLAY_TO_PCODE_VOLTAGE(x) REG_FIELD_PREP(DISPLAY_TO_PCODE_VOLTAGE_MASK, (x)) >> > +#define DISPLAY_TO_PCODE_UPDATE_MASK(cdclk, num_pipes, voltage_level) \ >> > + (DISPLAY_TO_PCODE_CDCLK(cdclk)) | \ >> > + (DISPLAY_TO_PCODE_PIPE_COUNT(num_pipes)) | \ >> > + (DISPLAY_TO_PCODE_VOLTAGE(voltage_level)) >> > #define ICL_PCODE_SAGV_DE_MEM_SS_CONFIG 0xe >> > #define ICL_PCODE_REP_QGV_MASK REG_GENMASK(1, 0) >> > #define ICL_PCODE_REP_QGV_SAFE REG_FIELD_PREP(ICL_PCODE_REP_QGV_MASK, 0) >> >> -- >> Jani Nikula, Intel Open Source Graphics Center -- Jani Nikula, Intel Open Source Graphics Center