]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/amd/pm: Use pm_display_cfg in legacy DPM (v2)
authorTimur Kristóf <timur.kristof@gmail.com>
Tue, 9 Sep 2025 14:17:51 +0000 (16:17 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 15 Sep 2025 20:52:46 +0000 (16:52 -0400)
This commit is necessary for DC to function well with chips
that use the legacy power management code, ie. SI and KV.
Communicate display information from DC to the legacy PM code.

Currently DC uses pm_display_cfg to communicate power management
requirements from the display code to the DPM code.
However, the legacy (non-DC) code path used different fields
and therefore could not take into account anything from DC.

Change the legacy display code to fill the same pm_display_cfg
struct as DC and use the same in the legacy DPM code.

To ease review and reduce churn, this commit does not yet
delete the now unneeded code, that is done in the next commit.

v2:
Rebase.
Fix single_display in amdgpu_dpm_pick_power_state.

Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h
drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c
drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c

index 2d2d2d5e6763411e3f1c1880a3d1e40e5aa33368..9ef965e4a92ed1221657e112d748a88205c90956 100644 (file)
@@ -100,3 +100,70 @@ u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev)
 
        return vrefresh;
 }
+
+void amdgpu_dpm_get_display_cfg(struct amdgpu_device *adev)
+{
+       struct drm_device *ddev = adev_to_drm(adev);
+       struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg;
+       struct single_display_configuration *display_cfg;
+       struct drm_crtc *crtc;
+       struct amdgpu_crtc *amdgpu_crtc;
+       struct amdgpu_connector *conn;
+       int num_crtcs = 0;
+       int vrefresh;
+       u32 vblank_in_pixels, vblank_time_us;
+
+       cfg->min_vblank_time = 0xffffffff; /* if the displays are off, vblank time is max */
+
+       if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
+               list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) {
+                       amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+                       /* The array should only contain active displays. */
+                       if (!amdgpu_crtc->enabled)
+                               continue;
+
+                       conn = to_amdgpu_connector(amdgpu_crtc->connector);
+                       display_cfg = &adev->pm.pm_display_cfg.displays[num_crtcs++];
+
+                       if (amdgpu_crtc->hw_mode.clock) {
+                               vrefresh = drm_mode_vrefresh(&amdgpu_crtc->hw_mode);
+
+                               vblank_in_pixels =
+                                       amdgpu_crtc->hw_mode.crtc_htotal *
+                                       (amdgpu_crtc->hw_mode.crtc_vblank_end -
+                                       amdgpu_crtc->hw_mode.crtc_vdisplay +
+                                       (amdgpu_crtc->v_border * 2));
+
+                               vblank_time_us =
+                                       vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock;
+
+                               /* The legacy (non-DC) code has issues with mclk switching
+                                * with refresh rates over 120 Hz. Disable mclk switching.
+                                */
+                               if (vrefresh > 120)
+                                       vblank_time_us = 0;
+
+                               /* Find minimum vblank time. */
+                               if (vblank_time_us < cfg->min_vblank_time)
+                                       cfg->min_vblank_time = vblank_time_us;
+
+                               /* Find vertical refresh rate of first active display. */
+                               if (!cfg->vrefresh)
+                                       cfg->vrefresh = vrefresh;
+                       }
+
+                       if (amdgpu_crtc->crtc_id < cfg->crtc_index) {
+                               /* Find first active CRTC and its line time. */
+                               cfg->crtc_index = amdgpu_crtc->crtc_id;
+                               cfg->line_time_in_us = amdgpu_crtc->line_time;
+                       }
+
+                       display_cfg->controller_id = amdgpu_crtc->crtc_id;
+                       display_cfg->pixel_clock = conn->pixelclock_for_modeset;
+               }
+       }
+
+       cfg->display_clk = adev->clock.default_dispclk;
+       cfg->num_display = num_crtcs;
+}
index 5c2a89f0d5d5d3150530f8a65c7af51a67b9ba94..8be11510cd923657f72eb982a7750c4cb306b6bf 100644 (file)
@@ -29,4 +29,6 @@ u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev);
 
 u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev);
 
+void amdgpu_dpm_get_display_cfg(struct amdgpu_device *adev);
+
 #endif
index 307ebf7e32267b79dadf3d59d4a5568ad290fad0..33eb85dd68e9c49518507af7b11c9227ec684ae0 100644 (file)
@@ -2299,7 +2299,7 @@ static void kv_apply_state_adjust_rules(struct amdgpu_device *adev,
 
                if (pi->sys_info.nb_dpm_enable) {
                        force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) ||
-                               pi->video_start || (adev->pm.dpm.new_active_crtc_count >= 3) ||
+                               pi->video_start || (adev->pm.pm_display_cfg.num_display >= 3) ||
                                pi->disable_nb_ps3_in_battery;
                        ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3;
                        ps->dpm0_pg_nb_ps_hi = 0x2;
@@ -2358,7 +2358,7 @@ static int kv_calculate_nbps_level_settings(struct amdgpu_device *adev)
                        return 0;
 
                force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) ||
-                             (adev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start);
+                             (adev->pm.pm_display_cfg.num_display >= 3) || pi->video_start);
 
                if (force_high) {
                        for (i = pi->lowest_valid; i <= pi->highest_valid; i++)
index 52dbf6d0469df7b22d7e35eff3231474150d419e..6ebe3d0f5b8779de6be10f6660d176ba53316693 100644 (file)
@@ -771,7 +771,7 @@ static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev,
        int i;
        struct amdgpu_ps *ps;
        u32 ui_class;
-       bool single_display = adev->pm.dpm.new_active_crtc_count < 2;
+       bool single_display = adev->pm.pm_display_cfg.num_display < 2;
 
        /* check if the vblank period is too short to adjust the mclk */
        if (single_display && adev->powerplay.pp_funcs->vblank_too_short) {
@@ -967,7 +967,8 @@ void amdgpu_legacy_dpm_compute_clocks(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       amdgpu_dpm_get_active_displays(adev);
+       if (!adev->dc_enabled)
+               amdgpu_dpm_get_display_cfg(adev);
 
        amdgpu_dpm_change_power_state_locked(adev);
 }
index 6595a611ce6e5240fbc4b6436f284e36d8e514f4..cf9932e68055f9df8c5809f4dda95064158e87f6 100644 (file)
@@ -3081,7 +3081,7 @@ static int si_get_vce_clock_voltage(struct amdgpu_device *adev,
 static bool si_dpm_vblank_too_short(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-       u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
+       u32 vblank_time = adev->pm.pm_display_cfg.min_vblank_time;
        /* we never hit the non-gddr5 limit so disable it */
        u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0;
 
@@ -3447,9 +3447,10 @@ static void rv770_get_engine_memory_ss(struct amdgpu_device *adev)
 static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
                                        struct amdgpu_ps *rps)
 {
+       const struct amd_pp_display_configuration *display_cfg =
+               &adev->pm.pm_display_cfg;
        struct  si_ps *ps = si_get_ps(rps);
        struct amdgpu_clock_and_voltage_limits *max_limits;
-       struct amdgpu_connector *conn;
        bool disable_mclk_switching = false;
        bool disable_sclk_switching = false;
        u32 mclk, sclk;
@@ -3488,14 +3489,9 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
         * For example, 4K 60Hz and 1080p 144Hz fall into this category.
         * Find number of such displays connected.
         */
-       for (i = 0; i < adev->mode_info.num_crtc; i++) {
-               if (!(adev->pm.dpm.new_active_crtcs & (1 << i)) ||
-                       !adev->mode_info.crtcs[i]->enabled)
-                       continue;
-
-               conn = to_amdgpu_connector(adev->mode_info.crtcs[i]->connector);
-
-               if (conn->pixelclock_for_modeset > 297000)
+       for (i = 0; i < display_cfg->num_display; i++) {
+               /* The array only contains active displays. */
+               if (display_cfg->displays[i].pixel_clock > 297000)
                        high_pixelclock_count++;
        }
 
@@ -3523,7 +3519,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
                rps->ecclk = 0;
        }
 
-       if ((adev->pm.dpm.new_active_crtc_count > 1) ||
+       if ((adev->pm.pm_display_cfg.num_display > 1) ||
            si_dpm_vblank_too_short(adev))
                disable_mclk_switching = true;
 
@@ -3671,7 +3667,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
                                                   ps->performance_levels[i].mclk,
                                                   max_limits->vddc,  &ps->performance_levels[i].vddc);
                btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk,
-                                                  adev->clock.current_dispclk,
+                                                  display_cfg->display_clk,
                                                   max_limits->vddc,  &ps->performance_levels[i].vddc);
        }
 
@@ -4196,16 +4192,16 @@ static void si_program_ds_registers(struct amdgpu_device *adev)
 
 static void si_program_display_gap(struct amdgpu_device *adev)
 {
+       const struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg;
        u32 tmp, pipe;
-       int i;
 
        tmp = RREG32(mmCG_DISPLAY_GAP_CNTL) & ~(CG_DISPLAY_GAP_CNTL__DISP1_GAP_MASK | CG_DISPLAY_GAP_CNTL__DISP2_GAP_MASK);
-       if (adev->pm.dpm.new_active_crtc_count > 0)
+       if (cfg->num_display > 0)
                tmp |= R600_PM_DISPLAY_GAP_VBLANK_OR_WM << CG_DISPLAY_GAP_CNTL__DISP1_GAP__SHIFT;
        else
                tmp |= R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP1_GAP__SHIFT;
 
-       if (adev->pm.dpm.new_active_crtc_count > 1)
+       if (cfg->num_display > 1)
                tmp |= R600_PM_DISPLAY_GAP_VBLANK_OR_WM << CG_DISPLAY_GAP_CNTL__DISP2_GAP__SHIFT;
        else
                tmp |= R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP2_GAP__SHIFT;
@@ -4215,17 +4211,8 @@ static void si_program_display_gap(struct amdgpu_device *adev)
        tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG);
        pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT;
 
-       if ((adev->pm.dpm.new_active_crtc_count > 0) &&
-           (!(adev->pm.dpm.new_active_crtcs & (1 << pipe)))) {
-               /* find the first active crtc */
-               for (i = 0; i < adev->mode_info.num_crtc; i++) {
-                       if (adev->pm.dpm.new_active_crtcs & (1 << i))
-                               break;
-               }
-               if (i == adev->mode_info.num_crtc)
-                       pipe = 0;
-               else
-                       pipe = i;
+       if (cfg->num_display > 0 && pipe != cfg->crtc_index) {
+               pipe = cfg->crtc_index;
 
                tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK;
                tmp |= DCCG_DISP1_SLOW_SELECT(pipe);
@@ -4236,7 +4223,7 @@ static void si_program_display_gap(struct amdgpu_device *adev)
         * This can be a problem on PowerXpress systems or if you want to use the card
         * for offscreen rendering or compute if there are no crtcs enabled.
         */
-       si_notify_smc_display_change(adev, adev->pm.dpm.new_active_crtc_count > 0);
+       si_notify_smc_display_change(adev, cfg->num_display > 0);
 }
 
 static void si_enable_spread_spectrum(struct amdgpu_device *adev, bool enable)
@@ -5545,7 +5532,7 @@ static int si_convert_power_level_to_smc(struct amdgpu_device *adev,
            (pl->mclk <= pi->mclk_stutter_mode_threshold) &&
            !eg_pi->uvd_enabled &&
            (RREG32(mmDPG_PIPE_STUTTER_CONTROL) & DPG_PIPE_STUTTER_CONTROL__STUTTER_ENABLE_MASK) &&
-           (adev->pm.dpm.new_active_crtc_count <= 2)) {
+           (adev->pm.pm_display_cfg.num_display <= 2)) {
                level->mcFlags |= SISLANDS_SMC_MC_STUTTER_EN;
        }
 
@@ -5694,7 +5681,7 @@ static bool si_is_state_ulv_compatible(struct amdgpu_device *adev,
        /* XXX validate against display requirements! */
 
        for (i = 0; i < adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count; i++) {
-               if (adev->clock.current_dispclk <=
+               if (adev->pm.pm_display_cfg.display_clk <=
                    adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].clk) {
                        if (ulv->pl.vddc <
                            adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].v)
@@ -5848,30 +5835,22 @@ static int si_upload_ulv_state(struct amdgpu_device *adev)
 
 static int si_upload_smc_data(struct amdgpu_device *adev)
 {
-       struct amdgpu_crtc *amdgpu_crtc = NULL;
-       int i;
+       const struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg;
        u32 crtc_index = 0;
        u32 mclk_change_block_cp_min = 0;
        u32 mclk_change_block_cp_max = 0;
 
-       for (i = 0; i < adev->mode_info.num_crtc; i++) {
-               if (adev->pm.dpm.new_active_crtcs & (1 << i)) {
-                       amdgpu_crtc = adev->mode_info.crtcs[i];
-                       break;
-               }
-       }
-
        /* When a display is plugged in, program these so that the SMC
         * performs MCLK switching when it doesn't cause flickering.
         * When no display is plugged in, there is no need to restrict
         * MCLK switching, so program them to zero.
         */
-       if (adev->pm.dpm.new_active_crtc_count && amdgpu_crtc) {
-               crtc_index = amdgpu_crtc->crtc_id;
+       if (cfg->num_display) {
+               crtc_index = cfg->crtc_index;
 
-               if (amdgpu_crtc->line_time) {
-                       mclk_change_block_cp_min = 200 / amdgpu_crtc->line_time;
-                       mclk_change_block_cp_max = 100 / amdgpu_crtc->line_time;
+               if (cfg->line_time_in_us) {
+                       mclk_change_block_cp_min = 200 / cfg->line_time_in_us;
+                       mclk_change_block_cp_max = 100 / cfg->line_time_in_us;
                }
        }
 
index b48a031cbba083a9be3e1f24946fc02da51da8bc..554492dfa3c00b585c3df1ffadc979c40887defb 100644 (file)
@@ -1554,16 +1554,7 @@ static void pp_pm_compute_clocks(void *handle)
        struct amdgpu_device *adev = hwmgr->adev;
 
        if (!adev->dc_enabled) {
-               amdgpu_dpm_get_active_displays(adev);
-               adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count;
-               adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev);
-               adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev);
-               /* we have issues with mclk switching with
-                * refresh rates over 120 hz on the non-DC code.
-                */
-               if (adev->pm.pm_display_cfg.vrefresh > 120)
-                       adev->pm.pm_display_cfg.min_vblank_time = 0;
-
+               amdgpu_dpm_get_display_cfg(adev);
                pp_display_configuration_change(handle,
                                                &adev->pm.pm_display_cfg);
        }