Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/pm: Use pm_display_cfg in legacy DPM (v2)

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>

authored by

Timur Kristóf and committed by
Alex Deucher
9d73b107 b515dcb0

+97 -57
+67
drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c
··· 100 100 101 101 return vrefresh; 102 102 } 103 + 104 + void amdgpu_dpm_get_display_cfg(struct amdgpu_device *adev) 105 + { 106 + struct drm_device *ddev = adev_to_drm(adev); 107 + struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg; 108 + struct single_display_configuration *display_cfg; 109 + struct drm_crtc *crtc; 110 + struct amdgpu_crtc *amdgpu_crtc; 111 + struct amdgpu_connector *conn; 112 + int num_crtcs = 0; 113 + int vrefresh; 114 + u32 vblank_in_pixels, vblank_time_us; 115 + 116 + cfg->min_vblank_time = 0xffffffff; /* if the displays are off, vblank time is max */ 117 + 118 + if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) { 119 + list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { 120 + amdgpu_crtc = to_amdgpu_crtc(crtc); 121 + 122 + /* The array should only contain active displays. */ 123 + if (!amdgpu_crtc->enabled) 124 + continue; 125 + 126 + conn = to_amdgpu_connector(amdgpu_crtc->connector); 127 + display_cfg = &adev->pm.pm_display_cfg.displays[num_crtcs++]; 128 + 129 + if (amdgpu_crtc->hw_mode.clock) { 130 + vrefresh = drm_mode_vrefresh(&amdgpu_crtc->hw_mode); 131 + 132 + vblank_in_pixels = 133 + amdgpu_crtc->hw_mode.crtc_htotal * 134 + (amdgpu_crtc->hw_mode.crtc_vblank_end - 135 + amdgpu_crtc->hw_mode.crtc_vdisplay + 136 + (amdgpu_crtc->v_border * 2)); 137 + 138 + vblank_time_us = 139 + vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock; 140 + 141 + /* The legacy (non-DC) code has issues with mclk switching 142 + * with refresh rates over 120 Hz. Disable mclk switching. 143 + */ 144 + if (vrefresh > 120) 145 + vblank_time_us = 0; 146 + 147 + /* Find minimum vblank time. */ 148 + if (vblank_time_us < cfg->min_vblank_time) 149 + cfg->min_vblank_time = vblank_time_us; 150 + 151 + /* Find vertical refresh rate of first active display. */ 152 + if (!cfg->vrefresh) 153 + cfg->vrefresh = vrefresh; 154 + } 155 + 156 + if (amdgpu_crtc->crtc_id < cfg->crtc_index) { 157 + /* Find first active CRTC and its line time. */ 158 + cfg->crtc_index = amdgpu_crtc->crtc_id; 159 + cfg->line_time_in_us = amdgpu_crtc->line_time; 160 + } 161 + 162 + display_cfg->controller_id = amdgpu_crtc->crtc_id; 163 + display_cfg->pixel_clock = conn->pixelclock_for_modeset; 164 + } 165 + } 166 + 167 + cfg->display_clk = adev->clock.default_dispclk; 168 + cfg->num_display = num_crtcs; 169 + }
+2
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h
··· 29 29 30 30 u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev); 31 31 32 + void amdgpu_dpm_get_display_cfg(struct amdgpu_device *adev); 33 + 32 34 #endif
+2 -2
drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
··· 2299 2299 2300 2300 if (pi->sys_info.nb_dpm_enable) { 2301 2301 force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) || 2302 - pi->video_start || (adev->pm.dpm.new_active_crtc_count >= 3) || 2302 + pi->video_start || (adev->pm.pm_display_cfg.num_display >= 3) || 2303 2303 pi->disable_nb_ps3_in_battery; 2304 2304 ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3; 2305 2305 ps->dpm0_pg_nb_ps_hi = 0x2; ··· 2358 2358 return 0; 2359 2359 2360 2360 force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) || 2361 - (adev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start); 2361 + (adev->pm.pm_display_cfg.num_display >= 3) || pi->video_start); 2362 2362 2363 2363 if (force_high) { 2364 2364 for (i = pi->lowest_valid; i <= pi->highest_valid; i++)
+3 -2
drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c
··· 771 771 int i; 772 772 struct amdgpu_ps *ps; 773 773 u32 ui_class; 774 - bool single_display = adev->pm.dpm.new_active_crtc_count < 2; 774 + bool single_display = adev->pm.pm_display_cfg.num_display < 2; 775 775 776 776 /* check if the vblank period is too short to adjust the mclk */ 777 777 if (single_display && adev->powerplay.pp_funcs->vblank_too_short) { ··· 967 967 { 968 968 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 969 969 970 - amdgpu_dpm_get_active_displays(adev); 970 + if (!adev->dc_enabled) 971 + amdgpu_dpm_get_display_cfg(adev); 971 972 972 973 amdgpu_dpm_change_power_state_locked(adev); 973 974 }
+22 -43
drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
··· 3081 3081 static bool si_dpm_vblank_too_short(void *handle) 3082 3082 { 3083 3083 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 3084 - u32 vblank_time = amdgpu_dpm_get_vblank_time(adev); 3084 + u32 vblank_time = adev->pm.pm_display_cfg.min_vblank_time; 3085 3085 /* we never hit the non-gddr5 limit so disable it */ 3086 3086 u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0; 3087 3087 ··· 3447 3447 static void si_apply_state_adjust_rules(struct amdgpu_device *adev, 3448 3448 struct amdgpu_ps *rps) 3449 3449 { 3450 + const struct amd_pp_display_configuration *display_cfg = 3451 + &adev->pm.pm_display_cfg; 3450 3452 struct si_ps *ps = si_get_ps(rps); 3451 3453 struct amdgpu_clock_and_voltage_limits *max_limits; 3452 - struct amdgpu_connector *conn; 3453 3454 bool disable_mclk_switching = false; 3454 3455 bool disable_sclk_switching = false; 3455 3456 u32 mclk, sclk; ··· 3489 3488 * For example, 4K 60Hz and 1080p 144Hz fall into this category. 3490 3489 * Find number of such displays connected. 3491 3490 */ 3492 - for (i = 0; i < adev->mode_info.num_crtc; i++) { 3493 - if (!(adev->pm.dpm.new_active_crtcs & (1 << i)) || 3494 - !adev->mode_info.crtcs[i]->enabled) 3495 - continue; 3496 - 3497 - conn = to_amdgpu_connector(adev->mode_info.crtcs[i]->connector); 3498 - 3499 - if (conn->pixelclock_for_modeset > 297000) 3491 + for (i = 0; i < display_cfg->num_display; i++) { 3492 + /* The array only contains active displays. */ 3493 + if (display_cfg->displays[i].pixel_clock > 297000) 3500 3494 high_pixelclock_count++; 3501 3495 } 3502 3496 ··· 3519 3523 rps->ecclk = 0; 3520 3524 } 3521 3525 3522 - if ((adev->pm.dpm.new_active_crtc_count > 1) || 3526 + if ((adev->pm.pm_display_cfg.num_display > 1) || 3523 3527 si_dpm_vblank_too_short(adev)) 3524 3528 disable_mclk_switching = true; 3525 3529 ··· 3667 3671 ps->performance_levels[i].mclk, 3668 3672 max_limits->vddc, &ps->performance_levels[i].vddc); 3669 3673 btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk, 3670 - adev->clock.current_dispclk, 3674 + display_cfg->display_clk, 3671 3675 max_limits->vddc, &ps->performance_levels[i].vddc); 3672 3676 } 3673 3677 ··· 4192 4196 4193 4197 static void si_program_display_gap(struct amdgpu_device *adev) 4194 4198 { 4199 + const struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg; 4195 4200 u32 tmp, pipe; 4196 - int i; 4197 4201 4198 4202 tmp = RREG32(mmCG_DISPLAY_GAP_CNTL) & ~(CG_DISPLAY_GAP_CNTL__DISP1_GAP_MASK | CG_DISPLAY_GAP_CNTL__DISP2_GAP_MASK); 4199 - if (adev->pm.dpm.new_active_crtc_count > 0) 4203 + if (cfg->num_display > 0) 4200 4204 tmp |= R600_PM_DISPLAY_GAP_VBLANK_OR_WM << CG_DISPLAY_GAP_CNTL__DISP1_GAP__SHIFT; 4201 4205 else 4202 4206 tmp |= R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP1_GAP__SHIFT; 4203 4207 4204 - if (adev->pm.dpm.new_active_crtc_count > 1) 4208 + if (cfg->num_display > 1) 4205 4209 tmp |= R600_PM_DISPLAY_GAP_VBLANK_OR_WM << CG_DISPLAY_GAP_CNTL__DISP2_GAP__SHIFT; 4206 4210 else 4207 4211 tmp |= R600_PM_DISPLAY_GAP_IGNORE << CG_DISPLAY_GAP_CNTL__DISP2_GAP__SHIFT; ··· 4211 4215 tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG); 4212 4216 pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT; 4213 4217 4214 - if ((adev->pm.dpm.new_active_crtc_count > 0) && 4215 - (!(adev->pm.dpm.new_active_crtcs & (1 << pipe)))) { 4216 - /* find the first active crtc */ 4217 - for (i = 0; i < adev->mode_info.num_crtc; i++) { 4218 - if (adev->pm.dpm.new_active_crtcs & (1 << i)) 4219 - break; 4220 - } 4221 - if (i == adev->mode_info.num_crtc) 4222 - pipe = 0; 4223 - else 4224 - pipe = i; 4218 + if (cfg->num_display > 0 && pipe != cfg->crtc_index) { 4219 + pipe = cfg->crtc_index; 4225 4220 4226 4221 tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK; 4227 4222 tmp |= DCCG_DISP1_SLOW_SELECT(pipe); ··· 4223 4236 * This can be a problem on PowerXpress systems or if you want to use the card 4224 4237 * for offscreen rendering or compute if there are no crtcs enabled. 4225 4238 */ 4226 - si_notify_smc_display_change(adev, adev->pm.dpm.new_active_crtc_count > 0); 4239 + si_notify_smc_display_change(adev, cfg->num_display > 0); 4227 4240 } 4228 4241 4229 4242 static void si_enable_spread_spectrum(struct amdgpu_device *adev, bool enable) ··· 5532 5545 (pl->mclk <= pi->mclk_stutter_mode_threshold) && 5533 5546 !eg_pi->uvd_enabled && 5534 5547 (RREG32(mmDPG_PIPE_STUTTER_CONTROL) & DPG_PIPE_STUTTER_CONTROL__STUTTER_ENABLE_MASK) && 5535 - (adev->pm.dpm.new_active_crtc_count <= 2)) { 5548 + (adev->pm.pm_display_cfg.num_display <= 2)) { 5536 5549 level->mcFlags |= SISLANDS_SMC_MC_STUTTER_EN; 5537 5550 } 5538 5551 ··· 5681 5694 /* XXX validate against display requirements! */ 5682 5695 5683 5696 for (i = 0; i < adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count; i++) { 5684 - if (adev->clock.current_dispclk <= 5697 + if (adev->pm.pm_display_cfg.display_clk <= 5685 5698 adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].clk) { 5686 5699 if (ulv->pl.vddc < 5687 5700 adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].v) ··· 5835 5848 5836 5849 static int si_upload_smc_data(struct amdgpu_device *adev) 5837 5850 { 5838 - struct amdgpu_crtc *amdgpu_crtc = NULL; 5839 - int i; 5851 + const struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg; 5840 5852 u32 crtc_index = 0; 5841 5853 u32 mclk_change_block_cp_min = 0; 5842 5854 u32 mclk_change_block_cp_max = 0; 5843 - 5844 - for (i = 0; i < adev->mode_info.num_crtc; i++) { 5845 - if (adev->pm.dpm.new_active_crtcs & (1 << i)) { 5846 - amdgpu_crtc = adev->mode_info.crtcs[i]; 5847 - break; 5848 - } 5849 - } 5850 5855 5851 5856 /* When a display is plugged in, program these so that the SMC 5852 5857 * performs MCLK switching when it doesn't cause flickering. 5853 5858 * When no display is plugged in, there is no need to restrict 5854 5859 * MCLK switching, so program them to zero. 5855 5860 */ 5856 - if (adev->pm.dpm.new_active_crtc_count && amdgpu_crtc) { 5857 - crtc_index = amdgpu_crtc->crtc_id; 5861 + if (cfg->num_display) { 5862 + crtc_index = cfg->crtc_index; 5858 5863 5859 - if (amdgpu_crtc->line_time) { 5860 - mclk_change_block_cp_min = 200 / amdgpu_crtc->line_time; 5861 - mclk_change_block_cp_max = 100 / amdgpu_crtc->line_time; 5864 + if (cfg->line_time_in_us) { 5865 + mclk_change_block_cp_min = 200 / cfg->line_time_in_us; 5866 + mclk_change_block_cp_max = 100 / cfg->line_time_in_us; 5862 5867 } 5863 5868 } 5864 5869
+1 -10
drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
··· 1554 1554 struct amdgpu_device *adev = hwmgr->adev; 1555 1555 1556 1556 if (!adev->dc_enabled) { 1557 - amdgpu_dpm_get_active_displays(adev); 1558 - adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count; 1559 - adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev); 1560 - adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev); 1561 - /* we have issues with mclk switching with 1562 - * refresh rates over 120 hz on the non-DC code. 1563 - */ 1564 - if (adev->pm.pm_display_cfg.vrefresh > 120) 1565 - adev->pm.pm_display_cfg.min_vblank_time = 0; 1566 - 1557 + amdgpu_dpm_get_display_cfg(adev); 1567 1558 pp_display_configuration_change(handle, 1568 1559 &adev->pm.pm_display_cfg); 1569 1560 }