FILE
dcn31_smu.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
1/* 2 * Copyright 2012-16 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26#include "core_types.h" 27#include "clk_mgr_internal.h" 28#include "reg_helper.h" 29#include "dm_helpers.h" 30#include "dcn31_smu.h" 31 32#include "yellow_carp_offset.h" 33#include "mp/mp_13_0_2_offset.h" 34#include "mp/mp_13_0_2_sh_mask.h" 35 36#define REG(reg_name) \ 37 (MP0_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name) 38 39#define FN(reg_name, field) \ 40 FD(reg_name##__##field) 41 42#include "logger_types.h" 43#undef DC_LOGGER 44#define DC_LOGGER \ 45 CTX->logger 46#define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); } 47 48#define VBIOSSMC_MSG_TestMessage 0x1 49#define VBIOSSMC_MSG_GetSmuVersion 0x2 50#define VBIOSSMC_MSG_PowerUpGfx 0x3 51#define VBIOSSMC_MSG_SetDispclkFreq 0x4 52#define VBIOSSMC_MSG_SetDprefclkFreq 0x5 //Not used. DPRef is constant 53#define VBIOSSMC_MSG_SetDppclkFreq 0x6 54#define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x7 55#define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x8 56#define VBIOSSMC_MSG_SetPhyclkVoltageByFreq 0x9 //Keep it in case VMIN dees not support phy clk 57#define VBIOSSMC_MSG_GetFclkFrequency 0xA 58#define VBIOSSMC_MSG_SetDisplayCount 0xB //Not used anymore 59#define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xC //Not used anymore 60#define VBIOSSMC_MSG_UpdatePmeRestore 0xD 61#define VBIOSSMC_MSG_SetVbiosDramAddrHigh 0xE //Used for WM table txfr 62#define VBIOSSMC_MSG_SetVbiosDramAddrLow 0xF 63#define VBIOSSMC_MSG_TransferTableSmu2Dram 0x10 64#define VBIOSSMC_MSG_TransferTableDram2Smu 0x11 65#define VBIOSSMC_MSG_SetDisplayIdleOptimizations 0x12 66#define VBIOSSMC_MSG_GetDprefclkFreq 0x13 67#define VBIOSSMC_MSG_GetDtbclkFreq 0x14 68#define VBIOSSMC_MSG_AllowZstatesEntry 0x15 69#define VBIOSSMC_MSG_DisallowZstatesEntry 0x16 70#define VBIOSSMC_MSG_SetDtbClk 0x17 71#define VBIOSSMC_Message_Count 0x18 72 73#define VBIOSSMC_Status_BUSY 0x0 74#define VBIOSSMC_Result_OK 0x1 75#define VBIOSSMC_Result_Failed 0xFF 76#define VBIOSSMC_Result_UnknownCmd 0xFE 77#define VBIOSSMC_Result_CmdRejectedPrereq 0xFD 78#define VBIOSSMC_Result_CmdRejectedBusy 0xFC 79 80/* 81 * Function to be used instead of REG_WAIT macro because the wait ends when 82 * the register is NOT EQUAL to zero, and because the translation in msg_if.h 83 * won't work with REG_WAIT. 84 */ 85static uint32_t dcn31_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries) 86{ 87 uint32_t res_val = VBIOSSMC_Status_BUSY; 88 89 do { 90 res_val = REG_READ(MP1_SMN_C2PMSG_91); 91 if (res_val != VBIOSSMC_Status_BUSY) 92 break; 93 94 if (delay_us >= 1000) 95 msleep(delay_us/1000); 96 else if (delay_us > 0) 97 udelay(delay_us); 98 } while (max_retries--); 99 100 return res_val; 101} 102 103static int dcn31_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, 104 unsigned int msg_id, 105 unsigned int param) 106{ 107 uint32_t result; 108 109 result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000); 110 111 if (result != VBIOSSMC_Result_OK) 112 smu_print("SMU Response was not OK. SMU response after wait received is: %d\n", result); 113 114 if (result == VBIOSSMC_Status_BUSY) { 115 return -1; 116 } 117 118 /* First clear response register */ 119 REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY); 120 121 /* Set the parameter register for the SMU message, unit is Mhz */ 122 REG_WRITE(MP1_SMN_C2PMSG_83, param); 123 124 /* Trigger the message transaction by writing the message ID */ 125 REG_WRITE(MP1_SMN_C2PMSG_67, msg_id); 126 127 result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000); 128 129 if (result == VBIOSSMC_Result_Failed) { 130 if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu && 131 param == TABLE_WATERMARKS) 132 DC_LOG_DEBUG("Watermarks table not configured properly by SMU"); 133 else 134 ASSERT(0); 135 REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK); 136 return -1; 137 } 138 139 if (IS_SMU_TIMEOUT(result)) { 140 ASSERT(0); 141 dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000); 142 } 143 144 return REG_READ(MP1_SMN_C2PMSG_83); 145} 146 147int dcn31_smu_get_smu_version(struct clk_mgr_internal *clk_mgr) 148{ 149 return dcn31_smu_send_msg_with_param( 150 clk_mgr, 151 VBIOSSMC_MSG_GetSmuVersion, 152 0); 153} 154 155 156int dcn31_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz) 157{ 158 int actual_dispclk_set_mhz = -1; 159 160 if (!clk_mgr->smu_present) 161 return requested_dispclk_khz; 162 163 /* Unit of SMU msg parameter is Mhz */ 164 actual_dispclk_set_mhz = dcn31_smu_send_msg_with_param( 165 clk_mgr, 166 VBIOSSMC_MSG_SetDispclkFreq, 167 khz_to_mhz_ceil(requested_dispclk_khz)); 168 169 return actual_dispclk_set_mhz * 1000; 170} 171 172int dcn31_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr) 173{ 174 int actual_dprefclk_set_mhz = -1; 175 176 if (!clk_mgr->smu_present) 177 return clk_mgr->base.dprefclk_khz; 178 179 actual_dprefclk_set_mhz = dcn31_smu_send_msg_with_param( 180 clk_mgr, 181 VBIOSSMC_MSG_SetDprefclkFreq, 182 khz_to_mhz_ceil(clk_mgr->base.dprefclk_khz)); 183 184 /* TODO: add code for programing DP DTO, currently this is down by command table */ 185 186 return actual_dprefclk_set_mhz * 1000; 187} 188 189int dcn31_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz) 190{ 191 int actual_dcfclk_set_mhz = -1; 192 193 if (!clk_mgr->base.ctx->dc->debug.pstate_enabled) 194 return -1; 195 196 if (!clk_mgr->smu_present) 197 return requested_dcfclk_khz; 198 199 actual_dcfclk_set_mhz = dcn31_smu_send_msg_with_param( 200 clk_mgr, 201 VBIOSSMC_MSG_SetHardMinDcfclkByFreq, 202 khz_to_mhz_ceil(requested_dcfclk_khz)); 203 204 return actual_dcfclk_set_mhz * 1000; 205} 206 207int dcn31_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz) 208{ 209 int actual_min_ds_dcfclk_mhz = -1; 210 211 if (!clk_mgr->base.ctx->dc->debug.pstate_enabled) 212 return -1; 213 214 if (!clk_mgr->smu_present) 215 return requested_min_ds_dcfclk_khz; 216 217 actual_min_ds_dcfclk_mhz = dcn31_smu_send_msg_with_param( 218 clk_mgr, 219 VBIOSSMC_MSG_SetMinDeepSleepDcfclk, 220 khz_to_mhz_ceil(requested_min_ds_dcfclk_khz)); 221 222 return actual_min_ds_dcfclk_mhz * 1000; 223} 224 225int dcn31_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz) 226{ 227 int actual_dppclk_set_mhz = -1; 228 229 if (!clk_mgr->smu_present) 230 return requested_dpp_khz; 231 232 actual_dppclk_set_mhz = dcn31_smu_send_msg_with_param( 233 clk_mgr, 234 VBIOSSMC_MSG_SetDppclkFreq, 235 khz_to_mhz_ceil(requested_dpp_khz)); 236 237 return actual_dppclk_set_mhz * 1000; 238} 239 240void dcn31_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info) 241{ 242 if (!clk_mgr->base.ctx->dc->debug.pstate_enabled) 243 return; 244 245 if (!clk_mgr->smu_present) 246 return; 247 248 //TODO: Work with smu team to define optimization options. 249 dcn31_smu_send_msg_with_param( 250 clk_mgr, 251 VBIOSSMC_MSG_SetDisplayIdleOptimizations, 252 idle_info); 253} 254 255void dcn31_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable) 256{ 257 union display_idle_optimization_u idle_info = { 0 }; 258 259 if (!clk_mgr->smu_present) 260 return; 261 262 if (enable) { 263 idle_info.idle_info.df_request_disabled = 1; 264 idle_info.idle_info.phy_ref_clk_off = 1; 265 } 266 267 dcn31_smu_send_msg_with_param( 268 clk_mgr, 269 VBIOSSMC_MSG_SetDisplayIdleOptimizations, 270 idle_info.data); 271} 272 273void dcn31_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr) 274{ 275 if (!clk_mgr->smu_present) 276 return; 277 278 dcn31_smu_send_msg_with_param( 279 clk_mgr, 280 VBIOSSMC_MSG_UpdatePmeRestore, 281 0); 282} 283 284void dcn31_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high) 285{ 286 if (!clk_mgr->smu_present) 287 return; 288 289 dcn31_smu_send_msg_with_param(clk_mgr, 290 VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high); 291} 292 293void dcn31_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low) 294{ 295 if (!clk_mgr->smu_present) 296 return; 297 298 dcn31_smu_send_msg_with_param(clk_mgr, 299 VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low); 300} 301 302void dcn31_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr) 303{ 304 if (!clk_mgr->smu_present) 305 return; 306 307 dcn31_smu_send_msg_with_param(clk_mgr, 308 VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS); 309} 310 311void dcn31_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr) 312{ 313 if (!clk_mgr->smu_present) 314 return; 315 316 dcn31_smu_send_msg_with_param(clk_mgr, 317 VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS); 318} 319 320void dcn31_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zstate_support_state support) 321{ 322 unsigned int msg_id, param; 323 324 if (!clk_mgr->smu_present) 325 return; 326 327 if (!clk_mgr->base.ctx->dc->debug.enable_z9_disable_interface && 328 (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY)) 329 support = DCN_ZSTATE_SUPPORT_DISALLOW; 330 331 if (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY || 332 support == DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY) 333 param = 1; 334 else 335 param = 0; 336 337 if (support == DCN_ZSTATE_SUPPORT_DISALLOW) 338 msg_id = VBIOSSMC_MSG_DisallowZstatesEntry; 339 else 340 msg_id = VBIOSSMC_MSG_AllowZstatesEntry; 341 342 dcn31_smu_send_msg_with_param( 343 clk_mgr, 344 msg_id, 345 param); 346 347} 348 349/* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */ 350void dcn31_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable) 351{ 352 if (!clk_mgr->smu_present) 353 return; 354 355 dcn31_smu_send_msg_with_param( 356 clk_mgr, 357 VBIOSSMC_MSG_SetDtbClk, 358 enable); 359}
~/
Read-only file preview.