1f7c1ed34SMikita Lipski /* 2f7c1ed34SMikita Lipski * Copyright 2018 Advanced Micro Devices, Inc. 3f7c1ed34SMikita Lipski * 4f7c1ed34SMikita Lipski * Permission is hereby granted, free of charge, to any person obtaining a 5f7c1ed34SMikita Lipski * copy of this software and associated documentation files (the "Software"), 6f7c1ed34SMikita Lipski * to deal in the Software without restriction, including without limitation 7f7c1ed34SMikita Lipski * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8f7c1ed34SMikita Lipski * and/or sell copies of the Software, and to permit persons to whom the 9f7c1ed34SMikita Lipski * Software is furnished to do so, subject to the following conditions: 10f7c1ed34SMikita Lipski * 11f7c1ed34SMikita Lipski * The above copyright notice and this permission notice shall be included in 12f7c1ed34SMikita Lipski * all copies or substantial portions of the Software. 13f7c1ed34SMikita Lipski * 14f7c1ed34SMikita Lipski * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15f7c1ed34SMikita Lipski * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16f7c1ed34SMikita Lipski * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17f7c1ed34SMikita Lipski * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18f7c1ed34SMikita Lipski * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19f7c1ed34SMikita Lipski * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20f7c1ed34SMikita Lipski * OTHER DEALINGS IN THE SOFTWARE. 21f7c1ed34SMikita Lipski * 22f7c1ed34SMikita Lipski * Authors: AMD 23f7c1ed34SMikita Lipski */ 24f7c1ed34SMikita Lipski #include <linux/string.h> 25f7c1ed34SMikita Lipski #include <linux/acpi.h> 26f7c1ed34SMikita Lipski 27f7c1ed34SMikita Lipski #include <drm/drmP.h> 28fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 29f7c1ed34SMikita Lipski #include <drm/amdgpu_drm.h> 30f7c1ed34SMikita Lipski #include "dm_services.h" 31f7c1ed34SMikita Lipski #include "amdgpu.h" 32f7c1ed34SMikita Lipski #include "amdgpu_dm.h" 33f7c1ed34SMikita Lipski #include "amdgpu_dm_irq.h" 34f7c1ed34SMikita Lipski #include "amdgpu_pm.h" 35f7c1ed34SMikita Lipski #include "dm_pp_smu.h" 3694ed6d0cSHuang Rui #include "amdgpu_smu.h" 37f7c1ed34SMikita Lipski 38f7c1ed34SMikita Lipski 39f7c1ed34SMikita Lipski bool dm_pp_apply_display_requirements( 40f7c1ed34SMikita Lipski const struct dc_context *ctx, 41f7c1ed34SMikita Lipski const struct dm_pp_display_configuration *pp_display_cfg) 42f7c1ed34SMikita Lipski { 43f7c1ed34SMikita Lipski struct amdgpu_device *adev = ctx->driver_context; 4494ed6d0cSHuang Rui struct smu_context *smu = &adev->smu; 45d4d5eaceSrex zhu int i; 46f7c1ed34SMikita Lipski 47f7c1ed34SMikita Lipski if (adev->pm.dpm_enabled) { 48f7c1ed34SMikita Lipski 49f7c1ed34SMikita Lipski memset(&adev->pm.pm_display_cfg, 0, 50f7c1ed34SMikita Lipski sizeof(adev->pm.pm_display_cfg)); 51f7c1ed34SMikita Lipski 52f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.cpu_cc6_disable = 53f7c1ed34SMikita Lipski pp_display_cfg->cpu_cc6_disable; 54f7c1ed34SMikita Lipski 55f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.cpu_pstate_disable = 56f7c1ed34SMikita Lipski pp_display_cfg->cpu_pstate_disable; 57f7c1ed34SMikita Lipski 58f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.cpu_pstate_separation_time = 59f7c1ed34SMikita Lipski pp_display_cfg->cpu_pstate_separation_time; 60f7c1ed34SMikita Lipski 61f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.nb_pstate_switch_disable = 62f7c1ed34SMikita Lipski pp_display_cfg->nb_pstate_switch_disable; 63f7c1ed34SMikita Lipski 64f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.num_display = 65f7c1ed34SMikita Lipski pp_display_cfg->display_count; 66f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.num_path_including_non_display = 67f7c1ed34SMikita Lipski pp_display_cfg->display_count; 68f7c1ed34SMikita Lipski 69f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.min_core_set_clock = 70f7c1ed34SMikita Lipski pp_display_cfg->min_engine_clock_khz/10; 71f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.min_core_set_clock_in_sr = 72f7c1ed34SMikita Lipski pp_display_cfg->min_engine_clock_deep_sleep_khz/10; 73f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.min_mem_set_clock = 74f7c1ed34SMikita Lipski pp_display_cfg->min_memory_clock_khz/10; 75f7c1ed34SMikita Lipski 763180fb67Srex zhu adev->pm.pm_display_cfg.min_dcef_deep_sleep_set_clk = 773180fb67Srex zhu pp_display_cfg->min_engine_clock_deep_sleep_khz/10; 783180fb67Srex zhu adev->pm.pm_display_cfg.min_dcef_set_clk = 793180fb67Srex zhu pp_display_cfg->min_dcfclock_khz/10; 803180fb67Srex zhu 81f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.multi_monitor_in_sync = 82f7c1ed34SMikita Lipski pp_display_cfg->all_displays_in_sync; 83f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.min_vblank_time = 84f7c1ed34SMikita Lipski pp_display_cfg->avail_mclk_switch_time_us; 85f7c1ed34SMikita Lipski 86f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.display_clk = 87f7c1ed34SMikita Lipski pp_display_cfg->disp_clk_khz/10; 88f7c1ed34SMikita Lipski 89f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency = 90f7c1ed34SMikita Lipski pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; 91f7c1ed34SMikita Lipski 92f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index; 93f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.line_time_in_us = 94f7c1ed34SMikita Lipski pp_display_cfg->line_time_in_us; 95f7c1ed34SMikita Lipski 96f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh; 97f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.crossfire_display_index = -1; 98f7c1ed34SMikita Lipski adev->pm.pm_display_cfg.min_bus_bandwidth = 0; 99f7c1ed34SMikita Lipski 100d4d5eaceSrex zhu for (i = 0; i < pp_display_cfg->display_count; i++) { 101d4d5eaceSrex zhu const struct dm_pp_single_disp_config *dc_cfg = 102d4d5eaceSrex zhu &pp_display_cfg->disp_configs[i]; 103d4d5eaceSrex zhu adev->pm.pm_display_cfg.displays[i].controller_id = dc_cfg->pipe_idx + 1; 104d4d5eaceSrex zhu } 105d4d5eaceSrex zhu 1066f059c64SRex Zhu if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->display_configuration_change) 107f7c1ed34SMikita Lipski adev->powerplay.pp_funcs->display_configuration_change( 108f7c1ed34SMikita Lipski adev->powerplay.pp_handle, 109f7c1ed34SMikita Lipski &adev->pm.pm_display_cfg); 11094ed6d0cSHuang Rui else 11194ed6d0cSHuang Rui smu_display_configuration_change(smu, 11294ed6d0cSHuang Rui &adev->pm.pm_display_cfg); 11340d0ebd9SRex Zhu 11440d0ebd9SRex Zhu amdgpu_pm_compute_clocks(adev); 115f7c1ed34SMikita Lipski } 116f7c1ed34SMikita Lipski 117f7c1ed34SMikita Lipski return true; 118f7c1ed34SMikita Lipski } 119f7c1ed34SMikita Lipski 120f7c1ed34SMikita Lipski static void get_default_clock_levels( 121f7c1ed34SMikita Lipski enum dm_pp_clock_type clk_type, 122f7c1ed34SMikita Lipski struct dm_pp_clock_levels *clks) 123f7c1ed34SMikita Lipski { 124f7c1ed34SMikita Lipski uint32_t disp_clks_in_khz[6] = { 125f7c1ed34SMikita Lipski 300000, 400000, 496560, 626090, 685720, 757900 }; 126f7c1ed34SMikita Lipski uint32_t sclks_in_khz[6] = { 127f7c1ed34SMikita Lipski 300000, 360000, 423530, 514290, 626090, 720000 }; 128f7c1ed34SMikita Lipski uint32_t mclks_in_khz[2] = { 333000, 800000 }; 129f7c1ed34SMikita Lipski 130f7c1ed34SMikita Lipski switch (clk_type) { 131f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_DISPLAY_CLK: 132f7c1ed34SMikita Lipski clks->num_levels = 6; 133f7c1ed34SMikita Lipski memmove(clks->clocks_in_khz, disp_clks_in_khz, 134f7c1ed34SMikita Lipski sizeof(disp_clks_in_khz)); 135f7c1ed34SMikita Lipski break; 136f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_ENGINE_CLK: 137f7c1ed34SMikita Lipski clks->num_levels = 6; 138f7c1ed34SMikita Lipski memmove(clks->clocks_in_khz, sclks_in_khz, 139f7c1ed34SMikita Lipski sizeof(sclks_in_khz)); 140f7c1ed34SMikita Lipski break; 141f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_MEMORY_CLK: 142f7c1ed34SMikita Lipski clks->num_levels = 2; 143f7c1ed34SMikita Lipski memmove(clks->clocks_in_khz, mclks_in_khz, 144f7c1ed34SMikita Lipski sizeof(mclks_in_khz)); 145f7c1ed34SMikita Lipski break; 146f7c1ed34SMikita Lipski default: 147f7c1ed34SMikita Lipski clks->num_levels = 0; 148f7c1ed34SMikita Lipski break; 149f7c1ed34SMikita Lipski } 150f7c1ed34SMikita Lipski } 151f7c1ed34SMikita Lipski 152a43913eaSKevin Wang static enum smu_clk_type dc_to_smu_clock_type( 153a43913eaSKevin Wang enum dm_pp_clock_type dm_pp_clk_type) 154a43913eaSKevin Wang { 155a43913eaSKevin Wang #define DCCLK_MAP_SMUCLK(dcclk, smuclk) \ 156a43913eaSKevin Wang [dcclk] = smuclk 157a43913eaSKevin Wang 158a43913eaSKevin Wang static int dc_clk_type_map[] = { 159a43913eaSKevin Wang DCCLK_MAP_SMUCLK(DM_PP_CLOCK_TYPE_DISPLAY_CLK, SMU_DISPCLK), 160a43913eaSKevin Wang DCCLK_MAP_SMUCLK(DM_PP_CLOCK_TYPE_ENGINE_CLK, SMU_GFXCLK), 161a43913eaSKevin Wang DCCLK_MAP_SMUCLK(DM_PP_CLOCK_TYPE_MEMORY_CLK, SMU_MCLK), 162a43913eaSKevin Wang DCCLK_MAP_SMUCLK(DM_PP_CLOCK_TYPE_DCEFCLK, SMU_DCEFCLK), 163a43913eaSKevin Wang DCCLK_MAP_SMUCLK(DM_PP_CLOCK_TYPE_SOCCLK, SMU_SOCCLK), 164a43913eaSKevin Wang }; 165a43913eaSKevin Wang 166a43913eaSKevin Wang return dc_clk_type_map[dm_pp_clk_type]; 167a43913eaSKevin Wang } 168a43913eaSKevin Wang 169f7c1ed34SMikita Lipski static enum amd_pp_clock_type dc_to_pp_clock_type( 170f7c1ed34SMikita Lipski enum dm_pp_clock_type dm_pp_clk_type) 171f7c1ed34SMikita Lipski { 172f7c1ed34SMikita Lipski enum amd_pp_clock_type amd_pp_clk_type = 0; 173f7c1ed34SMikita Lipski 174f7c1ed34SMikita Lipski switch (dm_pp_clk_type) { 175f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_DISPLAY_CLK: 176f7c1ed34SMikita Lipski amd_pp_clk_type = amd_pp_disp_clock; 177f7c1ed34SMikita Lipski break; 178f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_ENGINE_CLK: 179f7c1ed34SMikita Lipski amd_pp_clk_type = amd_pp_sys_clock; 180f7c1ed34SMikita Lipski break; 181f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_MEMORY_CLK: 182f7c1ed34SMikita Lipski amd_pp_clk_type = amd_pp_mem_clock; 183f7c1ed34SMikita Lipski break; 184f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_DCEFCLK: 185f7c1ed34SMikita Lipski amd_pp_clk_type = amd_pp_dcef_clock; 186f7c1ed34SMikita Lipski break; 187f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_DCFCLK: 188f7c1ed34SMikita Lipski amd_pp_clk_type = amd_pp_dcf_clock; 189f7c1ed34SMikita Lipski break; 190f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_PIXELCLK: 191f7c1ed34SMikita Lipski amd_pp_clk_type = amd_pp_pixel_clock; 192f7c1ed34SMikita Lipski break; 193f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_FCLK: 194f7c1ed34SMikita Lipski amd_pp_clk_type = amd_pp_f_clock; 195f7c1ed34SMikita Lipski break; 196f7c1ed34SMikita Lipski case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: 19766917e56Srex zhu amd_pp_clk_type = amd_pp_phy_clock; 19866917e56Srex zhu break; 19966917e56Srex zhu case DM_PP_CLOCK_TYPE_DPPCLK: 200f7c1ed34SMikita Lipski amd_pp_clk_type = amd_pp_dpp_clock; 201f7c1ed34SMikita Lipski break; 202f7c1ed34SMikita Lipski default: 203f7c1ed34SMikita Lipski DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", 204f7c1ed34SMikita Lipski dm_pp_clk_type); 205f7c1ed34SMikita Lipski break; 206f7c1ed34SMikita Lipski } 207f7c1ed34SMikita Lipski 208f7c1ed34SMikita Lipski return amd_pp_clk_type; 209f7c1ed34SMikita Lipski } 210f7c1ed34SMikita Lipski 211c2c09ed5SMikita Lipski static enum dm_pp_clocks_state pp_to_dc_powerlevel_state( 212c2c09ed5SMikita Lipski enum PP_DAL_POWERLEVEL max_clocks_state) 213c2c09ed5SMikita Lipski { 214c2c09ed5SMikita Lipski switch (max_clocks_state) { 215c2c09ed5SMikita Lipski case PP_DAL_POWERLEVEL_0: 216c2c09ed5SMikita Lipski return DM_PP_CLOCKS_DPM_STATE_LEVEL_0; 217c2c09ed5SMikita Lipski case PP_DAL_POWERLEVEL_1: 218c2c09ed5SMikita Lipski return DM_PP_CLOCKS_DPM_STATE_LEVEL_1; 219c2c09ed5SMikita Lipski case PP_DAL_POWERLEVEL_2: 220c2c09ed5SMikita Lipski return DM_PP_CLOCKS_DPM_STATE_LEVEL_2; 221c2c09ed5SMikita Lipski case PP_DAL_POWERLEVEL_3: 222c2c09ed5SMikita Lipski return DM_PP_CLOCKS_DPM_STATE_LEVEL_3; 223c2c09ed5SMikita Lipski case PP_DAL_POWERLEVEL_4: 224c2c09ed5SMikita Lipski return DM_PP_CLOCKS_DPM_STATE_LEVEL_4; 225c2c09ed5SMikita Lipski case PP_DAL_POWERLEVEL_5: 226c2c09ed5SMikita Lipski return DM_PP_CLOCKS_DPM_STATE_LEVEL_5; 227c2c09ed5SMikita Lipski case PP_DAL_POWERLEVEL_6: 228c2c09ed5SMikita Lipski return DM_PP_CLOCKS_DPM_STATE_LEVEL_6; 229c2c09ed5SMikita Lipski case PP_DAL_POWERLEVEL_7: 230c2c09ed5SMikita Lipski return DM_PP_CLOCKS_DPM_STATE_LEVEL_7; 231c2c09ed5SMikita Lipski default: 232c2c09ed5SMikita Lipski DRM_ERROR("DM_PPLIB: invalid powerlevel state: %d!\n", 233c2c09ed5SMikita Lipski max_clocks_state); 234c2c09ed5SMikita Lipski return DM_PP_CLOCKS_STATE_INVALID; 235c2c09ed5SMikita Lipski } 236c2c09ed5SMikita Lipski } 237c2c09ed5SMikita Lipski 238f7c1ed34SMikita Lipski static void pp_to_dc_clock_levels( 239f7c1ed34SMikita Lipski const struct amd_pp_clocks *pp_clks, 240f7c1ed34SMikita Lipski struct dm_pp_clock_levels *dc_clks, 241f7c1ed34SMikita Lipski enum dm_pp_clock_type dc_clk_type) 242f7c1ed34SMikita Lipski { 243f7c1ed34SMikita Lipski uint32_t i; 244f7c1ed34SMikita Lipski 245f7c1ed34SMikita Lipski if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) { 246f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", 247f7c1ed34SMikita Lipski DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), 248f7c1ed34SMikita Lipski pp_clks->count, 249f7c1ed34SMikita Lipski DM_PP_MAX_CLOCK_LEVELS); 250f7c1ed34SMikita Lipski 251f7c1ed34SMikita Lipski dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS; 252f7c1ed34SMikita Lipski } else 253f7c1ed34SMikita Lipski dc_clks->num_levels = pp_clks->count; 254f7c1ed34SMikita Lipski 255f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: values for %s clock\n", 256f7c1ed34SMikita Lipski DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); 257f7c1ed34SMikita Lipski 258f7c1ed34SMikita Lipski for (i = 0; i < dc_clks->num_levels; i++) { 259f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); 26023ec3d14SRex Zhu dc_clks->clocks_in_khz[i] = pp_clks->clock[i]; 261f7c1ed34SMikita Lipski } 262f7c1ed34SMikita Lipski } 263f7c1ed34SMikita Lipski 264f7c1ed34SMikita Lipski static void pp_to_dc_clock_levels_with_latency( 265f7c1ed34SMikita Lipski const struct pp_clock_levels_with_latency *pp_clks, 266f7c1ed34SMikita Lipski struct dm_pp_clock_levels_with_latency *clk_level_info, 267f7c1ed34SMikita Lipski enum dm_pp_clock_type dc_clk_type) 268f7c1ed34SMikita Lipski { 269f7c1ed34SMikita Lipski uint32_t i; 270f7c1ed34SMikita Lipski 271f7c1ed34SMikita Lipski if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { 272f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", 273f7c1ed34SMikita Lipski DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), 274f7c1ed34SMikita Lipski pp_clks->num_levels, 275f7c1ed34SMikita Lipski DM_PP_MAX_CLOCK_LEVELS); 276f7c1ed34SMikita Lipski 277f7c1ed34SMikita Lipski clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; 278f7c1ed34SMikita Lipski } else 279f7c1ed34SMikita Lipski clk_level_info->num_levels = pp_clks->num_levels; 280f7c1ed34SMikita Lipski 281f7c1ed34SMikita Lipski DRM_DEBUG("DM_PPLIB: values for %s clock\n", 282f7c1ed34SMikita Lipski DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); 283f7c1ed34SMikita Lipski 284f7c1ed34SMikita Lipski for (i = 0; i < clk_level_info->num_levels; i++) { 28523ec3d14SRex Zhu DRM_DEBUG("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); 28623ec3d14SRex Zhu clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; 287f7c1ed34SMikita Lipski clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; 288f7c1ed34SMikita Lipski } 289f7c1ed34SMikita Lipski } 290f7c1ed34SMikita Lipski 291f7c1ed34SMikita Lipski static void pp_to_dc_clock_levels_with_voltage( 292f7c1ed34SMikita Lipski const struct pp_clock_levels_with_voltage *pp_clks, 293f7c1ed34SMikita Lipski struct dm_pp_clock_levels_with_voltage *clk_level_info, 294f7c1ed34SMikita Lipski enum dm_pp_clock_type dc_clk_type) 295f7c1ed34SMikita Lipski { 296f7c1ed34SMikita Lipski uint32_t i; 297f7c1ed34SMikita Lipski 298f7c1ed34SMikita Lipski if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { 299f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", 300f7c1ed34SMikita Lipski DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), 301f7c1ed34SMikita Lipski pp_clks->num_levels, 302f7c1ed34SMikita Lipski DM_PP_MAX_CLOCK_LEVELS); 303f7c1ed34SMikita Lipski 304f7c1ed34SMikita Lipski clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; 305f7c1ed34SMikita Lipski } else 306f7c1ed34SMikita Lipski clk_level_info->num_levels = pp_clks->num_levels; 307f7c1ed34SMikita Lipski 308f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: values for %s clock\n", 309f7c1ed34SMikita Lipski DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); 310f7c1ed34SMikita Lipski 311f7c1ed34SMikita Lipski for (i = 0; i < clk_level_info->num_levels; i++) { 31223ec3d14SRex Zhu DRM_INFO("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); 31323ec3d14SRex Zhu clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; 314f7c1ed34SMikita Lipski clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; 315f7c1ed34SMikita Lipski } 316f7c1ed34SMikita Lipski } 317f7c1ed34SMikita Lipski 318f7c1ed34SMikita Lipski bool dm_pp_get_clock_levels_by_type( 319f7c1ed34SMikita Lipski const struct dc_context *ctx, 320f7c1ed34SMikita Lipski enum dm_pp_clock_type clk_type, 321f7c1ed34SMikita Lipski struct dm_pp_clock_levels *dc_clks) 322f7c1ed34SMikita Lipski { 323f7c1ed34SMikita Lipski struct amdgpu_device *adev = ctx->driver_context; 324f7c1ed34SMikita Lipski void *pp_handle = adev->powerplay.pp_handle; 325f7c1ed34SMikita Lipski struct amd_pp_clocks pp_clks = { 0 }; 326f7c1ed34SMikita Lipski struct amd_pp_simple_clock_info validation_clks = { 0 }; 327f7c1ed34SMikita Lipski uint32_t i; 328f7c1ed34SMikita Lipski 3296f059c64SRex Zhu if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_clock_by_type) { 330f7c1ed34SMikita Lipski if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle, 331f7c1ed34SMikita Lipski dc_to_pp_clock_type(clk_type), &pp_clks)) { 332f7c1ed34SMikita Lipski /* Error in pplib. Provide default values. */ 333b3ea88feSHuang Rui return true; 334b3ea88feSHuang Rui } 335b3ea88feSHuang Rui } else if (adev->smu.funcs && adev->smu.funcs->get_clock_by_type) { 336b3ea88feSHuang Rui if (smu_get_clock_by_type(&adev->smu, 337a43913eaSKevin Wang dc_to_smu_clock_type(clk_type), 338b3ea88feSHuang Rui &pp_clks)) { 339f7c1ed34SMikita Lipski get_default_clock_levels(clk_type, dc_clks); 340f7c1ed34SMikita Lipski return true; 341f7c1ed34SMikita Lipski } 342f7c1ed34SMikita Lipski } 343f7c1ed34SMikita Lipski 344f7c1ed34SMikita Lipski pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); 345f7c1ed34SMikita Lipski 3466f059c64SRex Zhu if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_display_mode_validation_clocks) { 347f7c1ed34SMikita Lipski if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks( 348f7c1ed34SMikita Lipski pp_handle, &validation_clks)) { 349f7c1ed34SMikita Lipski /* Error in pplib. Provide default values. */ 350f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); 351f7c1ed34SMikita Lipski validation_clks.engine_max_clock = 72000; 352f7c1ed34SMikita Lipski validation_clks.memory_max_clock = 80000; 353f7c1ed34SMikita Lipski validation_clks.level = 0; 354f7c1ed34SMikita Lipski } 3556ec82684SHuang Rui } else if (adev->smu.funcs && adev->smu.funcs->get_max_high_clocks) { 3566ec82684SHuang Rui if (smu_get_max_high_clocks(&adev->smu, &validation_clks)) { 3576ec82684SHuang Rui DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); 3586ec82684SHuang Rui validation_clks.engine_max_clock = 72000; 3596ec82684SHuang Rui validation_clks.memory_max_clock = 80000; 3606ec82684SHuang Rui validation_clks.level = 0; 3616ec82684SHuang Rui } 362f7c1ed34SMikita Lipski } 363f7c1ed34SMikita Lipski 364f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: Validation clocks:\n"); 365f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: engine_max_clock: %d\n", 366f7c1ed34SMikita Lipski validation_clks.engine_max_clock); 367f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: memory_max_clock: %d\n", 368f7c1ed34SMikita Lipski validation_clks.memory_max_clock); 369f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: level : %d\n", 370f7c1ed34SMikita Lipski validation_clks.level); 371f7c1ed34SMikita Lipski 372f7c1ed34SMikita Lipski /* Translate 10 kHz to kHz. */ 373f7c1ed34SMikita Lipski validation_clks.engine_max_clock *= 10; 374f7c1ed34SMikita Lipski validation_clks.memory_max_clock *= 10; 375f7c1ed34SMikita Lipski 376f7c1ed34SMikita Lipski /* Determine the highest non-boosted level from the Validation Clocks */ 377f7c1ed34SMikita Lipski if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { 378f7c1ed34SMikita Lipski for (i = 0; i < dc_clks->num_levels; i++) { 379f7c1ed34SMikita Lipski if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { 380f7c1ed34SMikita Lipski /* This clock is higher the validation clock. 381f7c1ed34SMikita Lipski * Than means the previous one is the highest 382f7c1ed34SMikita Lipski * non-boosted one. */ 383f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", 384f7c1ed34SMikita Lipski dc_clks->num_levels, i); 385f7c1ed34SMikita Lipski dc_clks->num_levels = i > 0 ? i : 1; 386f7c1ed34SMikita Lipski break; 387f7c1ed34SMikita Lipski } 388f7c1ed34SMikita Lipski } 389f7c1ed34SMikita Lipski } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { 390f7c1ed34SMikita Lipski for (i = 0; i < dc_clks->num_levels; i++) { 391f7c1ed34SMikita Lipski if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { 392f7c1ed34SMikita Lipski DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", 393f7c1ed34SMikita Lipski dc_clks->num_levels, i); 394f7c1ed34SMikita Lipski dc_clks->num_levels = i > 0 ? i : 1; 395f7c1ed34SMikita Lipski break; 396f7c1ed34SMikita Lipski } 397f7c1ed34SMikita Lipski } 398f7c1ed34SMikita Lipski } 399f7c1ed34SMikita Lipski 400f7c1ed34SMikita Lipski return true; 401f7c1ed34SMikita Lipski } 402f7c1ed34SMikita Lipski 403f7c1ed34SMikita Lipski bool dm_pp_get_clock_levels_by_type_with_latency( 404f7c1ed34SMikita Lipski const struct dc_context *ctx, 405f7c1ed34SMikita Lipski enum dm_pp_clock_type clk_type, 406f7c1ed34SMikita Lipski struct dm_pp_clock_levels_with_latency *clk_level_info) 407f7c1ed34SMikita Lipski { 408f7c1ed34SMikita Lipski struct amdgpu_device *adev = ctx->driver_context; 409f7c1ed34SMikita Lipski void *pp_handle = adev->powerplay.pp_handle; 410f7c1ed34SMikita Lipski struct pp_clock_levels_with_latency pp_clks = { 0 }; 411f7c1ed34SMikita Lipski const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 412e5e4e223SHuang Rui int ret; 413f7c1ed34SMikita Lipski 414e5e4e223SHuang Rui if (pp_funcs && pp_funcs->get_clock_by_type_with_latency) { 415e5e4e223SHuang Rui ret = pp_funcs->get_clock_by_type_with_latency(pp_handle, 416e5e4e223SHuang Rui dc_to_pp_clock_type(clk_type), 417e5e4e223SHuang Rui &pp_clks); 418e5e4e223SHuang Rui if (ret) 419f7c1ed34SMikita Lipski return false; 420e5e4e223SHuang Rui } else if (adev->smu.ppt_funcs && adev->smu.ppt_funcs->get_clock_by_type_with_latency) { 421e5e4e223SHuang Rui if (smu_get_clock_by_type_with_latency(&adev->smu, 422f7c1ed34SMikita Lipski dc_to_pp_clock_type(clk_type), 423f7c1ed34SMikita Lipski &pp_clks)) 424f7c1ed34SMikita Lipski return false; 425e5e4e223SHuang Rui } 426e5e4e223SHuang Rui 427f7c1ed34SMikita Lipski 428f7c1ed34SMikita Lipski pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); 429f7c1ed34SMikita Lipski 430f7c1ed34SMikita Lipski return true; 431f7c1ed34SMikita Lipski } 432f7c1ed34SMikita Lipski 433f7c1ed34SMikita Lipski bool dm_pp_get_clock_levels_by_type_with_voltage( 434f7c1ed34SMikita Lipski const struct dc_context *ctx, 435f7c1ed34SMikita Lipski enum dm_pp_clock_type clk_type, 436f7c1ed34SMikita Lipski struct dm_pp_clock_levels_with_voltage *clk_level_info) 437f7c1ed34SMikita Lipski { 438f7c1ed34SMikita Lipski struct amdgpu_device *adev = ctx->driver_context; 439f7c1ed34SMikita Lipski void *pp_handle = adev->powerplay.pp_handle; 440f7c1ed34SMikita Lipski struct pp_clock_levels_with_voltage pp_clk_info = {0}; 441f7c1ed34SMikita Lipski const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 4421e33d4d4SHuang Rui int ret; 443f7c1ed34SMikita Lipski 4441e33d4d4SHuang Rui if (pp_funcs && pp_funcs->get_clock_by_type_with_voltage) { 4451e33d4d4SHuang Rui ret = pp_funcs->get_clock_by_type_with_voltage(pp_handle, 4461e33d4d4SHuang Rui dc_to_pp_clock_type(clk_type), 4471e33d4d4SHuang Rui &pp_clk_info); 4481e33d4d4SHuang Rui if (ret) 4496f059c64SRex Zhu return false; 4501e33d4d4SHuang Rui } else if (adev->smu.ppt_funcs && adev->smu.ppt_funcs->get_clock_by_type_with_voltage) { 4511e33d4d4SHuang Rui if (smu_get_clock_by_type_with_voltage(&adev->smu, 452f7c1ed34SMikita Lipski dc_to_pp_clock_type(clk_type), 453f7c1ed34SMikita Lipski &pp_clk_info)) 454f7c1ed34SMikita Lipski return false; 4551e33d4d4SHuang Rui } 456f7c1ed34SMikita Lipski 457f7c1ed34SMikita Lipski pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type); 458f7c1ed34SMikita Lipski 459f7c1ed34SMikita Lipski return true; 460f7c1ed34SMikita Lipski } 461f7c1ed34SMikita Lipski 462f7c1ed34SMikita Lipski bool dm_pp_notify_wm_clock_changes( 463f7c1ed34SMikita Lipski const struct dc_context *ctx, 464f7c1ed34SMikita Lipski struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) 465f7c1ed34SMikita Lipski { 466f7c1ed34SMikita Lipski /* TODO: to be implemented */ 467f7c1ed34SMikita Lipski return false; 468f7c1ed34SMikita Lipski } 469f7c1ed34SMikita Lipski 470f7c1ed34SMikita Lipski bool dm_pp_apply_power_level_change_request( 471f7c1ed34SMikita Lipski const struct dc_context *ctx, 472f7c1ed34SMikita Lipski struct dm_pp_power_level_change_request *level_change_req) 473f7c1ed34SMikita Lipski { 474f7c1ed34SMikita Lipski /* TODO: to be implemented */ 475f7c1ed34SMikita Lipski return false; 476f7c1ed34SMikita Lipski } 477f7c1ed34SMikita Lipski 478f7c1ed34SMikita Lipski bool dm_pp_apply_clock_for_voltage_request( 479f7c1ed34SMikita Lipski const struct dc_context *ctx, 480f7c1ed34SMikita Lipski struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) 481f7c1ed34SMikita Lipski { 482f7c1ed34SMikita Lipski struct amdgpu_device *adev = ctx->driver_context; 483f7c1ed34SMikita Lipski struct pp_display_clock_request pp_clock_request = {0}; 484f7c1ed34SMikita Lipski int ret = 0; 485f7c1ed34SMikita Lipski 486f7c1ed34SMikita Lipski pp_clock_request.clock_type = dc_to_pp_clock_type(clock_for_voltage_req->clk_type); 487f7c1ed34SMikita Lipski pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; 488f7c1ed34SMikita Lipski 489f7c1ed34SMikita Lipski if (!pp_clock_request.clock_type) 490f7c1ed34SMikita Lipski return false; 491f7c1ed34SMikita Lipski 4926f059c64SRex Zhu if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->display_clock_voltage_request) 493f7c1ed34SMikita Lipski ret = adev->powerplay.pp_funcs->display_clock_voltage_request( 494f7c1ed34SMikita Lipski adev->powerplay.pp_handle, 495f7c1ed34SMikita Lipski &pp_clock_request); 49604885368SHuang Rui else if (adev->smu.funcs && 49704885368SHuang Rui adev->smu.funcs->display_clock_voltage_request) 49804885368SHuang Rui ret = smu_display_clock_voltage_request(&adev->smu, 49904885368SHuang Rui &pp_clock_request); 500f7c1ed34SMikita Lipski if (ret) 501f7c1ed34SMikita Lipski return false; 502f7c1ed34SMikita Lipski return true; 503f7c1ed34SMikita Lipski } 504f7c1ed34SMikita Lipski 505f7c1ed34SMikita Lipski bool dm_pp_get_static_clocks( 506f7c1ed34SMikita Lipski const struct dc_context *ctx, 507f7c1ed34SMikita Lipski struct dm_pp_static_clock_info *static_clk_info) 508f7c1ed34SMikita Lipski { 509f7c1ed34SMikita Lipski struct amdgpu_device *adev = ctx->driver_context; 510f7c1ed34SMikita Lipski struct amd_pp_clock_info pp_clk_info = {0}; 511f7c1ed34SMikita Lipski int ret = 0; 512f7c1ed34SMikita Lipski 5136f059c64SRex Zhu if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_current_clocks) 514f7c1ed34SMikita Lipski ret = adev->powerplay.pp_funcs->get_current_clocks( 515f7c1ed34SMikita Lipski adev->powerplay.pp_handle, 516f7c1ed34SMikita Lipski &pp_clk_info); 5175e2d3881SHuang Rui else if (adev->smu.funcs) 5185e2d3881SHuang Rui ret = smu_get_current_clocks(&adev->smu, &pp_clk_info); 519f7c1ed34SMikita Lipski if (ret) 520f7c1ed34SMikita Lipski return false; 521f7c1ed34SMikita Lipski 522c2c09ed5SMikita Lipski static_clk_info->max_clocks_state = pp_to_dc_powerlevel_state(pp_clk_info.max_clocks_state); 5233dbd823eSRex Zhu static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock * 10; 5243dbd823eSRex Zhu static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock * 10; 525f7c1ed34SMikita Lipski 526f7c1ed34SMikita Lipski return true; 527f7c1ed34SMikita Lipski } 528f7c1ed34SMikita Lipski 529f7c1ed34SMikita Lipski void pp_rv_set_wm_ranges(struct pp_smu *pp, 530f7c1ed34SMikita Lipski struct pp_smu_wm_range_sets *ranges) 531f7c1ed34SMikita Lipski { 532265f5ba6SJun Lei const struct dc_context *ctx = pp->dm; 533b0a634acSRex Zhu struct amdgpu_device *adev = ctx->driver_context; 534b0a634acSRex Zhu void *pp_handle = adev->powerplay.pp_handle; 535b0a634acSRex Zhu const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 536b0a634acSRex Zhu struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; 537b0a634acSRex Zhu struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = wm_with_clock_ranges.wm_dmif_clocks_ranges; 538b0a634acSRex Zhu struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = wm_with_clock_ranges.wm_mcif_clocks_ranges; 539b0a634acSRex Zhu int32_t i; 540f7c1ed34SMikita Lipski 541b0a634acSRex Zhu wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets; 542b0a634acSRex Zhu wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets; 543f7c1ed34SMikita Lipski 544b0a634acSRex Zhu for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) { 545f7c1ed34SMikita Lipski if (ranges->reader_wm_sets[i].wm_inst > 3) 546b0a634acSRex Zhu wm_dce_clocks[i].wm_set_id = WM_SET_A; 547f7c1ed34SMikita Lipski else 548b0a634acSRex Zhu wm_dce_clocks[i].wm_set_id = 549f7c1ed34SMikita Lipski ranges->reader_wm_sets[i].wm_inst; 550b0a634acSRex Zhu wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz = 551ba7b267aSFatemeh Darbehani ranges->reader_wm_sets[i].max_drain_clk_mhz * 1000; 552b0a634acSRex Zhu wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz = 553ba7b267aSFatemeh Darbehani ranges->reader_wm_sets[i].min_drain_clk_mhz * 1000; 554b0a634acSRex Zhu wm_dce_clocks[i].wm_max_mem_clk_in_khz = 555ba7b267aSFatemeh Darbehani ranges->reader_wm_sets[i].max_fill_clk_mhz * 1000; 556b0a634acSRex Zhu wm_dce_clocks[i].wm_min_mem_clk_in_khz = 557ba7b267aSFatemeh Darbehani ranges->reader_wm_sets[i].min_fill_clk_mhz * 1000; 558f7c1ed34SMikita Lipski } 559f7c1ed34SMikita Lipski 560b0a634acSRex Zhu for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) { 561f7c1ed34SMikita Lipski if (ranges->writer_wm_sets[i].wm_inst > 3) 562b0a634acSRex Zhu wm_soc_clocks[i].wm_set_id = WM_SET_A; 563f7c1ed34SMikita Lipski else 564b0a634acSRex Zhu wm_soc_clocks[i].wm_set_id = 565f7c1ed34SMikita Lipski ranges->writer_wm_sets[i].wm_inst; 566b0a634acSRex Zhu wm_soc_clocks[i].wm_max_socclk_clk_in_khz = 567ba7b267aSFatemeh Darbehani ranges->writer_wm_sets[i].max_fill_clk_mhz * 1000; 568b0a634acSRex Zhu wm_soc_clocks[i].wm_min_socclk_clk_in_khz = 569ba7b267aSFatemeh Darbehani ranges->writer_wm_sets[i].min_fill_clk_mhz * 1000; 570b0a634acSRex Zhu wm_soc_clocks[i].wm_max_mem_clk_in_khz = 571ba7b267aSFatemeh Darbehani ranges->writer_wm_sets[i].max_drain_clk_mhz * 1000; 572b0a634acSRex Zhu wm_soc_clocks[i].wm_min_mem_clk_in_khz = 573ba7b267aSFatemeh Darbehani ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000; 574f7c1ed34SMikita Lipski } 575f7c1ed34SMikita Lipski 5762e069391SHuang Rui if (pp_funcs && pp_funcs->set_watermarks_for_clocks_ranges) 5772e069391SHuang Rui pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, 5782e069391SHuang Rui &wm_with_clock_ranges); 5792e069391SHuang Rui else if (adev->smu.funcs && 5802e069391SHuang Rui adev->smu.funcs->set_watermarks_for_clock_ranges) 5812e069391SHuang Rui smu_set_watermarks_for_clock_ranges(&adev->smu, 5822e069391SHuang Rui &wm_with_clock_ranges); 583f7c1ed34SMikita Lipski } 584f7c1ed34SMikita Lipski 585f7c1ed34SMikita Lipski void pp_rv_set_pme_wa_enable(struct pp_smu *pp) 586f7c1ed34SMikita Lipski { 587265f5ba6SJun Lei const struct dc_context *ctx = pp->dm; 588b0a634acSRex Zhu struct amdgpu_device *adev = ctx->driver_context; 589b0a634acSRex Zhu void *pp_handle = adev->powerplay.pp_handle; 590b0a634acSRex Zhu const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 591f7c1ed34SMikita Lipski 592367eeed4SHuang Rui if (pp_funcs && pp_funcs->notify_smu_enable_pwe) 593b0a634acSRex Zhu pp_funcs->notify_smu_enable_pwe(pp_handle); 594367eeed4SHuang Rui else if (adev->smu.funcs) 595367eeed4SHuang Rui smu_notify_smu_enable_pwe(&adev->smu); 596f7c1ed34SMikita Lipski } 597f7c1ed34SMikita Lipski 598588715bdShersen wu void pp_rv_set_active_display_count(struct pp_smu *pp, int count) 599588715bdShersen wu { 600588715bdShersen wu const struct dc_context *ctx = pp->dm; 601588715bdShersen wu struct amdgpu_device *adev = ctx->driver_context; 602588715bdShersen wu void *pp_handle = adev->powerplay.pp_handle; 603588715bdShersen wu const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 604588715bdShersen wu 605588715bdShersen wu if (!pp_funcs || !pp_funcs->set_active_display_count) 606588715bdShersen wu return; 607588715bdShersen wu 608588715bdShersen wu pp_funcs->set_active_display_count(pp_handle, count); 609588715bdShersen wu } 610588715bdShersen wu 611588715bdShersen wu void pp_rv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int clock) 612588715bdShersen wu { 613588715bdShersen wu const struct dc_context *ctx = pp->dm; 614588715bdShersen wu struct amdgpu_device *adev = ctx->driver_context; 615588715bdShersen wu void *pp_handle = adev->powerplay.pp_handle; 616588715bdShersen wu const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 617588715bdShersen wu 618588715bdShersen wu if (!pp_funcs || !pp_funcs->set_min_deep_sleep_dcefclk) 619588715bdShersen wu return; 620588715bdShersen wu 621588715bdShersen wu pp_funcs->set_min_deep_sleep_dcefclk(pp_handle, clock); 622588715bdShersen wu } 623588715bdShersen wu 624588715bdShersen wu void pp_rv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int clock) 625588715bdShersen wu { 626588715bdShersen wu const struct dc_context *ctx = pp->dm; 627588715bdShersen wu struct amdgpu_device *adev = ctx->driver_context; 628588715bdShersen wu void *pp_handle = adev->powerplay.pp_handle; 629588715bdShersen wu const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 630588715bdShersen wu 631588715bdShersen wu if (!pp_funcs || !pp_funcs->set_hard_min_dcefclk_by_freq) 632588715bdShersen wu return; 633588715bdShersen wu 634588715bdShersen wu pp_funcs->set_hard_min_dcefclk_by_freq(pp_handle, clock); 635588715bdShersen wu } 636588715bdShersen wu 637588715bdShersen wu void pp_rv_set_hard_min_fclk_by_freq(struct pp_smu *pp, int mhz) 638588715bdShersen wu { 639588715bdShersen wu const struct dc_context *ctx = pp->dm; 640588715bdShersen wu struct amdgpu_device *adev = ctx->driver_context; 641588715bdShersen wu void *pp_handle = adev->powerplay.pp_handle; 642588715bdShersen wu const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 643588715bdShersen wu 644588715bdShersen wu if (!pp_funcs || !pp_funcs->set_hard_min_fclk_by_freq) 645588715bdShersen wu return; 646588715bdShersen wu 647588715bdShersen wu pp_funcs->set_hard_min_fclk_by_freq(pp_handle, mhz); 648588715bdShersen wu } 649588715bdShersen wu 65079a7b060Shersen wu enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp, 65179a7b060Shersen wu struct pp_smu_wm_range_sets *ranges) 65279a7b060Shersen wu { 65379a7b060Shersen wu const struct dc_context *ctx = pp->dm; 65479a7b060Shersen wu struct amdgpu_device *adev = ctx->driver_context; 65579a7b060Shersen wu struct smu_context *smu = &adev->smu; 65679a7b060Shersen wu struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; 65779a7b060Shersen wu struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = 65879a7b060Shersen wu wm_with_clock_ranges.wm_dmif_clocks_ranges; 65979a7b060Shersen wu struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = 66079a7b060Shersen wu wm_with_clock_ranges.wm_mcif_clocks_ranges; 66179a7b060Shersen wu int32_t i; 66279a7b060Shersen wu 66379a7b060Shersen wu wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets; 66479a7b060Shersen wu wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets; 66579a7b060Shersen wu 66679a7b060Shersen wu for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) { 66779a7b060Shersen wu if (ranges->reader_wm_sets[i].wm_inst > 3) 66879a7b060Shersen wu wm_dce_clocks[i].wm_set_id = WM_SET_A; 66979a7b060Shersen wu else 67079a7b060Shersen wu wm_dce_clocks[i].wm_set_id = 67179a7b060Shersen wu ranges->reader_wm_sets[i].wm_inst; 67279a7b060Shersen wu wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz = 67379a7b060Shersen wu ranges->reader_wm_sets[i].max_drain_clk_mhz * 1000; 67479a7b060Shersen wu wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz = 67579a7b060Shersen wu ranges->reader_wm_sets[i].min_drain_clk_mhz * 1000; 67679a7b060Shersen wu wm_dce_clocks[i].wm_max_mem_clk_in_khz = 67779a7b060Shersen wu ranges->reader_wm_sets[i].max_fill_clk_mhz * 1000; 67879a7b060Shersen wu wm_dce_clocks[i].wm_min_mem_clk_in_khz = 67979a7b060Shersen wu ranges->reader_wm_sets[i].min_fill_clk_mhz * 1000; 68079a7b060Shersen wu } 68179a7b060Shersen wu 68279a7b060Shersen wu for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) { 68379a7b060Shersen wu if (ranges->writer_wm_sets[i].wm_inst > 3) 68479a7b060Shersen wu wm_soc_clocks[i].wm_set_id = WM_SET_A; 68579a7b060Shersen wu else 68679a7b060Shersen wu wm_soc_clocks[i].wm_set_id = 68779a7b060Shersen wu ranges->writer_wm_sets[i].wm_inst; 68879a7b060Shersen wu wm_soc_clocks[i].wm_max_socclk_clk_in_khz = 68979a7b060Shersen wu ranges->writer_wm_sets[i].max_fill_clk_mhz * 1000; 69079a7b060Shersen wu wm_soc_clocks[i].wm_min_socclk_clk_in_khz = 69179a7b060Shersen wu ranges->writer_wm_sets[i].min_fill_clk_mhz * 1000; 69279a7b060Shersen wu wm_soc_clocks[i].wm_max_mem_clk_in_khz = 69379a7b060Shersen wu ranges->writer_wm_sets[i].max_drain_clk_mhz * 1000; 69479a7b060Shersen wu wm_soc_clocks[i].wm_min_mem_clk_in_khz = 69579a7b060Shersen wu ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000; 69679a7b060Shersen wu } 69779a7b060Shersen wu 69879a7b060Shersen wu if (!smu->funcs) 69979a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 70079a7b060Shersen wu 70179a7b060Shersen wu /* 0: successful or smu.funcs->set_watermarks_for_clock_ranges = NULL; 70279a7b060Shersen wu * 1: fail 70379a7b060Shersen wu */ 70479a7b060Shersen wu if (smu_set_watermarks_for_clock_ranges(&adev->smu, 70579a7b060Shersen wu &wm_with_clock_ranges)) 70679a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 70779a7b060Shersen wu 70879a7b060Shersen wu return PP_SMU_RESULT_OK; 70979a7b060Shersen wu } 71079a7b060Shersen wu 71179a7b060Shersen wu enum pp_smu_status pp_nv_set_pme_wa_enable(struct pp_smu *pp) 71279a7b060Shersen wu { 71379a7b060Shersen wu const struct dc_context *ctx = pp->dm; 71479a7b060Shersen wu struct amdgpu_device *adev = ctx->driver_context; 71579a7b060Shersen wu struct smu_context *smu = &adev->smu; 71679a7b060Shersen wu 71779a7b060Shersen wu if (!smu->funcs) 71879a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 71979a7b060Shersen wu 72079a7b060Shersen wu /* 0: successful or smu.funcs->set_azalia_d3_pme = NULL; 1: fail */ 72179a7b060Shersen wu if (smu_set_azalia_d3_pme(smu)) 72279a7b060Shersen wu return PP_SMU_RESULT_FAIL; 72379a7b060Shersen wu 72479a7b060Shersen wu return PP_SMU_RESULT_OK; 72579a7b060Shersen wu } 72679a7b060Shersen wu 72779a7b060Shersen wu enum pp_smu_status pp_nv_set_display_count(struct pp_smu *pp, int count) 72879a7b060Shersen wu { 72979a7b060Shersen wu const struct dc_context *ctx = pp->dm; 73079a7b060Shersen wu struct amdgpu_device *adev = ctx->driver_context; 73179a7b060Shersen wu struct smu_context *smu = &adev->smu; 73279a7b060Shersen wu 73379a7b060Shersen wu if (!smu->funcs) 73479a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 73579a7b060Shersen wu 73679a7b060Shersen wu /* 0: successful or smu.funcs->set_display_count = NULL; 1: fail */ 73779a7b060Shersen wu if (smu_set_display_count(smu, count)) 73879a7b060Shersen wu return PP_SMU_RESULT_FAIL; 73979a7b060Shersen wu 74079a7b060Shersen wu return PP_SMU_RESULT_OK; 74179a7b060Shersen wu } 74279a7b060Shersen wu 74379a7b060Shersen wu enum pp_smu_status pp_nv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int mhz) 74479a7b060Shersen wu { 74579a7b060Shersen wu const struct dc_context *ctx = pp->dm; 74679a7b060Shersen wu struct amdgpu_device *adev = ctx->driver_context; 74779a7b060Shersen wu struct smu_context *smu = &adev->smu; 74879a7b060Shersen wu 74979a7b060Shersen wu if (!smu->funcs) 75079a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 75179a7b060Shersen wu 75279a7b060Shersen wu /* 0: successful or smu.funcs->set_deep_sleep_dcefclk = NULL;1: fail */ 75379a7b060Shersen wu if (smu_set_deep_sleep_dcefclk(smu, mhz)) 75479a7b060Shersen wu return PP_SMU_RESULT_FAIL; 75579a7b060Shersen wu 75679a7b060Shersen wu return PP_SMU_RESULT_OK; 75779a7b060Shersen wu } 75879a7b060Shersen wu 75979a7b060Shersen wu enum pp_smu_status pp_nv_set_hard_min_dcefclk_by_freq( 76079a7b060Shersen wu struct pp_smu *pp, int mhz) 76179a7b060Shersen wu { 76279a7b060Shersen wu const struct dc_context *ctx = pp->dm; 76379a7b060Shersen wu struct amdgpu_device *adev = ctx->driver_context; 76479a7b060Shersen wu struct smu_context *smu = &adev->smu; 76579a7b060Shersen wu struct pp_display_clock_request clock_req; 76679a7b060Shersen wu 76779a7b060Shersen wu if (!smu->funcs) 76879a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 76979a7b060Shersen wu 77079a7b060Shersen wu clock_req.clock_type = amd_pp_dcef_clock; 77179a7b060Shersen wu clock_req.clock_freq_in_khz = mhz * 1000; 77279a7b060Shersen wu 77379a7b060Shersen wu /* 0: successful or smu.funcs->display_clock_voltage_request = NULL 77479a7b060Shersen wu * 1: fail 77579a7b060Shersen wu */ 77679a7b060Shersen wu if (smu_display_clock_voltage_request(smu, &clock_req)) 77779a7b060Shersen wu return PP_SMU_RESULT_FAIL; 77879a7b060Shersen wu 77979a7b060Shersen wu return PP_SMU_RESULT_OK; 78079a7b060Shersen wu } 78179a7b060Shersen wu 78279a7b060Shersen wu enum pp_smu_status pp_nv_set_hard_min_uclk_by_freq(struct pp_smu *pp, int mhz) 78379a7b060Shersen wu { 78479a7b060Shersen wu const struct dc_context *ctx = pp->dm; 78579a7b060Shersen wu struct amdgpu_device *adev = ctx->driver_context; 78679a7b060Shersen wu struct smu_context *smu = &adev->smu; 78779a7b060Shersen wu struct pp_display_clock_request clock_req; 78879a7b060Shersen wu 78979a7b060Shersen wu if (!smu->funcs) 79079a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 79179a7b060Shersen wu 79279a7b060Shersen wu clock_req.clock_type = amd_pp_mem_clock; 79379a7b060Shersen wu clock_req.clock_freq_in_khz = mhz * 1000; 79479a7b060Shersen wu 79579a7b060Shersen wu /* 0: successful or smu.funcs->display_clock_voltage_request = NULL 79679a7b060Shersen wu * 1: fail 79779a7b060Shersen wu */ 79879a7b060Shersen wu if (smu_display_clock_voltage_request(smu, &clock_req)) 79979a7b060Shersen wu return PP_SMU_RESULT_FAIL; 80079a7b060Shersen wu 80179a7b060Shersen wu return PP_SMU_RESULT_OK; 80279a7b060Shersen wu } 80379a7b060Shersen wu 80479a7b060Shersen wu enum pp_smu_status pp_nv_set_voltage_by_freq(struct pp_smu *pp, 80579a7b060Shersen wu enum pp_smu_nv_clock_id clock_id, int mhz) 80679a7b060Shersen wu { 80779a7b060Shersen wu const struct dc_context *ctx = pp->dm; 80879a7b060Shersen wu struct amdgpu_device *adev = ctx->driver_context; 80979a7b060Shersen wu struct smu_context *smu = &adev->smu; 81079a7b060Shersen wu struct pp_display_clock_request clock_req; 81179a7b060Shersen wu 81279a7b060Shersen wu if (!smu->funcs) 81379a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 81479a7b060Shersen wu 81579a7b060Shersen wu switch (clock_id) { 81679a7b060Shersen wu case PP_SMU_NV_DISPCLK: 81779a7b060Shersen wu clock_req.clock_type = amd_pp_disp_clock; 81879a7b060Shersen wu break; 81979a7b060Shersen wu case PP_SMU_NV_PHYCLK: 82079a7b060Shersen wu clock_req.clock_type = amd_pp_phy_clock; 82179a7b060Shersen wu break; 82279a7b060Shersen wu case PP_SMU_NV_PIXELCLK: 82379a7b060Shersen wu clock_req.clock_type = amd_pp_pixel_clock; 82479a7b060Shersen wu break; 82579a7b060Shersen wu default: 82679a7b060Shersen wu break; 82779a7b060Shersen wu } 82879a7b060Shersen wu clock_req.clock_freq_in_khz = mhz * 1000; 82979a7b060Shersen wu 83079a7b060Shersen wu /* 0: successful or smu.funcs->display_clock_voltage_request = NULL 83179a7b060Shersen wu * 1: fail 83279a7b060Shersen wu */ 83379a7b060Shersen wu if (smu_display_clock_voltage_request(smu, &clock_req)) 83479a7b060Shersen wu return PP_SMU_RESULT_FAIL; 83579a7b060Shersen wu 83679a7b060Shersen wu return PP_SMU_RESULT_OK; 83779a7b060Shersen wu } 83879a7b060Shersen wu 83979a7b060Shersen wu enum pp_smu_status pp_nv_get_maximum_sustainable_clocks( 84079a7b060Shersen wu struct pp_smu *pp, struct pp_smu_nv_clock_table *max_clocks) 84179a7b060Shersen wu { 84279a7b060Shersen wu const struct dc_context *ctx = pp->dm; 84379a7b060Shersen wu struct amdgpu_device *adev = ctx->driver_context; 84479a7b060Shersen wu struct smu_context *smu = &adev->smu; 84579a7b060Shersen wu 84679a7b060Shersen wu if (!smu->funcs) 84779a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 84879a7b060Shersen wu 84979a7b060Shersen wu if (!smu->funcs->get_max_sustainable_clocks_by_dc) 85079a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 85179a7b060Shersen wu 85279a7b060Shersen wu if (!smu->funcs->get_max_sustainable_clocks_by_dc(smu, max_clocks)) 85379a7b060Shersen wu return PP_SMU_RESULT_OK; 85479a7b060Shersen wu 85579a7b060Shersen wu return PP_SMU_RESULT_FAIL; 85679a7b060Shersen wu } 85779a7b060Shersen wu 85879a7b060Shersen wu enum pp_smu_status pp_nv_get_uclk_dpm_states(struct pp_smu *pp, 85979a7b060Shersen wu unsigned int *clock_values_in_khz, unsigned int *num_states) 86079a7b060Shersen wu { 86179a7b060Shersen wu const struct dc_context *ctx = pp->dm; 86279a7b060Shersen wu struct amdgpu_device *adev = ctx->driver_context; 86379a7b060Shersen wu struct smu_context *smu = &adev->smu; 86479a7b060Shersen wu 86579a7b060Shersen wu if (!smu->ppt_funcs) 86679a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 86779a7b060Shersen wu 86879a7b060Shersen wu if (!smu->ppt_funcs->get_uclk_dpm_states) 86979a7b060Shersen wu return PP_SMU_RESULT_UNSUPPORTED; 87079a7b060Shersen wu 87179a7b060Shersen wu if (!smu->ppt_funcs->get_uclk_dpm_states(smu, 87279a7b060Shersen wu clock_values_in_khz, num_states)) 87379a7b060Shersen wu return PP_SMU_RESULT_OK; 87479a7b060Shersen wu 87579a7b060Shersen wu return PP_SMU_RESULT_FAIL; 87679a7b060Shersen wu } 87779a7b060Shersen wu 8780f1a6ad7SJun Lei void dm_pp_get_funcs( 879f7c1ed34SMikita Lipski struct dc_context *ctx, 8800f1a6ad7SJun Lei struct pp_smu_funcs *funcs) 881f7c1ed34SMikita Lipski { 88279a7b060Shersen wu switch (ctx->dce_version) { 88379a7b060Shersen wu case DCN_VERSION_1_0: 88479a7b060Shersen wu case DCN_VERSION_1_01: 88579a7b060Shersen wu funcs->ctx.ver = PP_SMU_VER_RV; 8860f1a6ad7SJun Lei funcs->rv_funcs.pp_smu.dm = ctx; 8870f1a6ad7SJun Lei funcs->rv_funcs.set_wm_ranges = pp_rv_set_wm_ranges; 8880f1a6ad7SJun Lei funcs->rv_funcs.set_pme_wa_enable = pp_rv_set_pme_wa_enable; 88979a7b060Shersen wu funcs->rv_funcs.set_display_count = 89079a7b060Shersen wu pp_rv_set_active_display_count; 89179a7b060Shersen wu funcs->rv_funcs.set_min_deep_sleep_dcfclk = 89279a7b060Shersen wu pp_rv_set_min_deep_sleep_dcfclk; 89379a7b060Shersen wu funcs->rv_funcs.set_hard_min_dcfclk_by_freq = 89479a7b060Shersen wu pp_rv_set_hard_min_dcefclk_by_freq; 89579a7b060Shersen wu funcs->rv_funcs.set_hard_min_fclk_by_freq = 89679a7b060Shersen wu pp_rv_set_hard_min_fclk_by_freq; 89779a7b060Shersen wu break; 89879a7b060Shersen wu #ifdef CONFIG_DRM_AMD_DC_DCN2_0 89979a7b060Shersen wu case DCN_VERSION_2_0: 90079a7b060Shersen wu funcs->ctx.ver = PP_SMU_VER_NV; 90179a7b060Shersen wu funcs->nv_funcs.pp_smu.dm = ctx; 90279a7b060Shersen wu funcs->nv_funcs.set_display_count = pp_nv_set_display_count; 90379a7b060Shersen wu funcs->nv_funcs.set_hard_min_dcfclk_by_freq = 90479a7b060Shersen wu pp_nv_set_hard_min_dcefclk_by_freq; 90579a7b060Shersen wu funcs->nv_funcs.set_min_deep_sleep_dcfclk = 90679a7b060Shersen wu pp_nv_set_min_deep_sleep_dcfclk; 90779a7b060Shersen wu funcs->nv_funcs.set_voltage_by_freq = 90879a7b060Shersen wu pp_nv_set_voltage_by_freq; 90979a7b060Shersen wu funcs->nv_funcs.set_wm_ranges = pp_nv_set_wm_ranges; 910588715bdShersen wu 91179a7b060Shersen wu /* todo set_pme_wa_enable cause 4k@6ohz display not light up */ 91279a7b060Shersen wu funcs->nv_funcs.set_pme_wa_enable = NULL; 91379a7b060Shersen wu /* todo debug waring message */ 91479a7b060Shersen wu funcs->nv_funcs.set_hard_min_uclk_by_freq = NULL; 91579a7b060Shersen wu /* todo compare data with window driver*/ 91679a7b060Shersen wu funcs->nv_funcs.get_maximum_sustainable_clocks = NULL; 91779a7b060Shersen wu /*todo compare data with window driver */ 91879a7b060Shersen wu funcs->nv_funcs.get_uclk_dpm_states = NULL; 91979a7b060Shersen wu break; 92079a7b060Shersen wu #endif 92179a7b060Shersen wu default: 92279a7b060Shersen wu DRM_ERROR("smu version is not supported !\n"); 92379a7b060Shersen wu break; 92479a7b060Shersen wu } 92579a7b060Shersen wu } 926