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