0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include <linux/delay.h>
0027 #include "core_types.h"
0028 #include "clk_mgr_internal.h"
0029 #include "reg_helper.h"
0030 #include "dm_helpers.h"
0031 #include "dcn31_smu.h"
0032
0033 #include "yellow_carp_offset.h"
0034 #include "mp/mp_13_0_2_offset.h"
0035 #include "mp/mp_13_0_2_sh_mask.h"
0036
0037 #define REG(reg_name) \
0038 (MP0_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
0039
0040 #define FN(reg_name, field) \
0041 FD(reg_name##__##field)
0042
0043 #include "logger_types.h"
0044 #undef DC_LOGGER
0045 #define DC_LOGGER \
0046 CTX->logger
0047 #define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
0048
0049 #define VBIOSSMC_MSG_TestMessage 0x1
0050 #define VBIOSSMC_MSG_GetSmuVersion 0x2
0051 #define VBIOSSMC_MSG_PowerUpGfx 0x3
0052 #define VBIOSSMC_MSG_SetDispclkFreq 0x4
0053 #define VBIOSSMC_MSG_SetDprefclkFreq 0x5
0054 #define VBIOSSMC_MSG_SetDppclkFreq 0x6
0055 #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x7
0056 #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x8
0057 #define VBIOSSMC_MSG_SetPhyclkVoltageByFreq 0x9
0058 #define VBIOSSMC_MSG_GetFclkFrequency 0xA
0059 #define VBIOSSMC_MSG_SetDisplayCount 0xB
0060 #define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xC
0061 #define VBIOSSMC_MSG_UpdatePmeRestore 0xD
0062 #define VBIOSSMC_MSG_SetVbiosDramAddrHigh 0xE
0063 #define VBIOSSMC_MSG_SetVbiosDramAddrLow 0xF
0064 #define VBIOSSMC_MSG_TransferTableSmu2Dram 0x10
0065 #define VBIOSSMC_MSG_TransferTableDram2Smu 0x11
0066 #define VBIOSSMC_MSG_SetDisplayIdleOptimizations 0x12
0067 #define VBIOSSMC_MSG_GetDprefclkFreq 0x13
0068 #define VBIOSSMC_MSG_GetDtbclkFreq 0x14
0069 #define VBIOSSMC_MSG_AllowZstatesEntry 0x15
0070 #define VBIOSSMC_MSG_DisallowZstatesEntry 0x16
0071 #define VBIOSSMC_MSG_SetDtbClk 0x17
0072 #define VBIOSSMC_Message_Count 0x18
0073
0074 #define VBIOSSMC_Status_BUSY 0x0
0075 #define VBIOSSMC_Result_OK 0x1
0076 #define VBIOSSMC_Result_Failed 0xFF
0077 #define VBIOSSMC_Result_UnknownCmd 0xFE
0078 #define VBIOSSMC_Result_CmdRejectedPrereq 0xFD
0079 #define VBIOSSMC_Result_CmdRejectedBusy 0xFC
0080
0081
0082
0083
0084
0085
0086 static uint32_t dcn31_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
0087 {
0088 uint32_t res_val = VBIOSSMC_Status_BUSY;
0089
0090 do {
0091 res_val = REG_READ(MP1_SMN_C2PMSG_91);
0092 if (res_val != VBIOSSMC_Status_BUSY)
0093 break;
0094
0095 if (delay_us >= 1000)
0096 msleep(delay_us/1000);
0097 else if (delay_us > 0)
0098 udelay(delay_us);
0099 } while (max_retries--);
0100
0101 return res_val;
0102 }
0103
0104 static int dcn31_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
0105 unsigned int msg_id,
0106 unsigned int param)
0107 {
0108 uint32_t result;
0109
0110 result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000);
0111
0112 if (result != VBIOSSMC_Result_OK)
0113 smu_print("SMU Response was not OK. SMU response after wait received is: %d\n", result);
0114
0115 if (result == VBIOSSMC_Status_BUSY) {
0116 return -1;
0117 }
0118
0119
0120 REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
0121
0122
0123 REG_WRITE(MP1_SMN_C2PMSG_83, param);
0124
0125
0126 REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
0127
0128 result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000);
0129
0130 if (result == VBIOSSMC_Result_Failed) {
0131 if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu &&
0132 param == TABLE_WATERMARKS)
0133 DC_LOG_WARNING("Watermarks table not configured properly by SMU");
0134 else
0135 ASSERT(0);
0136 REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK);
0137 return -1;
0138 }
0139
0140 if (IS_SMU_TIMEOUT(result)) {
0141 ASSERT(0);
0142 dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
0143 }
0144
0145 return REG_READ(MP1_SMN_C2PMSG_83);
0146 }
0147
0148 int dcn31_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
0149 {
0150 return dcn31_smu_send_msg_with_param(
0151 clk_mgr,
0152 VBIOSSMC_MSG_GetSmuVersion,
0153 0);
0154 }
0155
0156
0157 int dcn31_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
0158 {
0159 int actual_dispclk_set_mhz = -1;
0160
0161 if (!clk_mgr->smu_present)
0162 return requested_dispclk_khz;
0163
0164
0165 actual_dispclk_set_mhz = dcn31_smu_send_msg_with_param(
0166 clk_mgr,
0167 VBIOSSMC_MSG_SetDispclkFreq,
0168 khz_to_mhz_ceil(requested_dispclk_khz));
0169
0170 return actual_dispclk_set_mhz * 1000;
0171 }
0172
0173 int dcn31_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
0174 {
0175 int actual_dprefclk_set_mhz = -1;
0176
0177 if (!clk_mgr->smu_present)
0178 return clk_mgr->base.dprefclk_khz;
0179
0180 actual_dprefclk_set_mhz = dcn31_smu_send_msg_with_param(
0181 clk_mgr,
0182 VBIOSSMC_MSG_SetDprefclkFreq,
0183 khz_to_mhz_ceil(clk_mgr->base.dprefclk_khz));
0184
0185
0186
0187 return actual_dprefclk_set_mhz * 1000;
0188 }
0189
0190 int dcn31_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
0191 {
0192 int actual_dcfclk_set_mhz = -1;
0193
0194 if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
0195 return -1;
0196
0197 if (!clk_mgr->smu_present)
0198 return requested_dcfclk_khz;
0199
0200 actual_dcfclk_set_mhz = dcn31_smu_send_msg_with_param(
0201 clk_mgr,
0202 VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
0203 khz_to_mhz_ceil(requested_dcfclk_khz));
0204
0205 #ifdef DBG
0206 smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", actual_dcfclk_set_mhz, actual_dcfclk_set_mhz * 1000);
0207 #endif
0208
0209 return actual_dcfclk_set_mhz * 1000;
0210 }
0211
0212 int dcn31_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
0213 {
0214 int actual_min_ds_dcfclk_mhz = -1;
0215
0216 if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
0217 return -1;
0218
0219 if (!clk_mgr->smu_present)
0220 return requested_min_ds_dcfclk_khz;
0221
0222 actual_min_ds_dcfclk_mhz = dcn31_smu_send_msg_with_param(
0223 clk_mgr,
0224 VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
0225 khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
0226
0227 return actual_min_ds_dcfclk_mhz * 1000;
0228 }
0229
0230 int dcn31_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
0231 {
0232 int actual_dppclk_set_mhz = -1;
0233
0234 if (!clk_mgr->smu_present)
0235 return requested_dpp_khz;
0236
0237 actual_dppclk_set_mhz = dcn31_smu_send_msg_with_param(
0238 clk_mgr,
0239 VBIOSSMC_MSG_SetDppclkFreq,
0240 khz_to_mhz_ceil(requested_dpp_khz));
0241
0242 return actual_dppclk_set_mhz * 1000;
0243 }
0244
0245 void dcn31_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
0246 {
0247 if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
0248 return;
0249
0250 if (!clk_mgr->smu_present)
0251 return;
0252
0253
0254 dcn31_smu_send_msg_with_param(
0255 clk_mgr,
0256 VBIOSSMC_MSG_SetDisplayIdleOptimizations,
0257 idle_info);
0258 }
0259
0260 void dcn31_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
0261 {
0262 union display_idle_optimization_u idle_info = { 0 };
0263
0264 if (!clk_mgr->smu_present)
0265 return;
0266
0267 if (enable) {
0268 idle_info.idle_info.df_request_disabled = 1;
0269 idle_info.idle_info.phy_ref_clk_off = 1;
0270 }
0271
0272 dcn31_smu_send_msg_with_param(
0273 clk_mgr,
0274 VBIOSSMC_MSG_SetDisplayIdleOptimizations,
0275 idle_info.data);
0276 }
0277
0278 void dcn31_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
0279 {
0280 if (!clk_mgr->smu_present)
0281 return;
0282
0283 dcn31_smu_send_msg_with_param(
0284 clk_mgr,
0285 VBIOSSMC_MSG_UpdatePmeRestore,
0286 0);
0287 }
0288
0289 void dcn31_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
0290 {
0291 if (!clk_mgr->smu_present)
0292 return;
0293
0294 dcn31_smu_send_msg_with_param(clk_mgr,
0295 VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
0296 }
0297
0298 void dcn31_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
0299 {
0300 if (!clk_mgr->smu_present)
0301 return;
0302
0303 dcn31_smu_send_msg_with_param(clk_mgr,
0304 VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
0305 }
0306
0307 void dcn31_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
0308 {
0309 if (!clk_mgr->smu_present)
0310 return;
0311
0312 dcn31_smu_send_msg_with_param(clk_mgr,
0313 VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
0314 }
0315
0316 void dcn31_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
0317 {
0318 if (!clk_mgr->smu_present)
0319 return;
0320
0321 dcn31_smu_send_msg_with_param(clk_mgr,
0322 VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
0323 }
0324
0325 void dcn31_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zstate_support_state support)
0326 {
0327 unsigned int msg_id, param;
0328
0329 if (!clk_mgr->smu_present)
0330 return;
0331
0332 if (!clk_mgr->base.ctx->dc->debug.enable_z9_disable_interface &&
0333 (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY))
0334 support = DCN_ZSTATE_SUPPORT_DISALLOW;
0335
0336
0337 if (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY)
0338 param = 1;
0339 else
0340 param = 0;
0341
0342 if (support == DCN_ZSTATE_SUPPORT_DISALLOW)
0343 msg_id = VBIOSSMC_MSG_DisallowZstatesEntry;
0344 else
0345 msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
0346
0347 dcn31_smu_send_msg_with_param(
0348 clk_mgr,
0349 msg_id,
0350 param);
0351
0352 }
0353
0354
0355 void dcn31_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
0356 {
0357 if (!clk_mgr->smu_present)
0358 return;
0359
0360 dcn31_smu_send_msg_with_param(
0361 clk_mgr,
0362 VBIOSSMC_MSG_SetDtbClk,
0363 enable);
0364 }