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 "core_types.h"
0027 #include "clk_mgr_internal.h"
0028 #include "reg_helper.h"
0029 #include "dm_helpers.h"
0030 #include "dcn316_smu.h"
0031 #include "mp/mp_13_0_8_offset.h"
0032 #include "mp/mp_13_0_8_sh_mask.h"
0033
0034 #define MAX_INSTANCE 7
0035 #define MAX_SEGMENT 6
0036
0037 struct IP_BASE_INSTANCE
0038 {
0039 unsigned int segment[MAX_SEGMENT];
0040 };
0041
0042 struct IP_BASE
0043 {
0044 struct IP_BASE_INSTANCE instance[MAX_INSTANCE];
0045 };
0046
0047 static const struct IP_BASE MP0_BASE = { { { { 0x00016000, 0x00DC0000, 0x00E00000, 0x00E40000, 0x0243FC00, 0 } },
0048 { { 0, 0, 0, 0, 0, 0 } },
0049 { { 0, 0, 0, 0, 0, 0 } },
0050 { { 0, 0, 0, 0, 0, 0 } },
0051 { { 0, 0, 0, 0, 0, 0 } },
0052 { { 0, 0, 0, 0, 0, 0 } },
0053 { { 0, 0, 0, 0, 0, 0 } } } };
0054
0055 #define REG(reg_name) \
0056 (MP0_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
0057
0058 #define FN(reg_name, field) \
0059 FD(reg_name##__##field)
0060
0061 #include "logger_types.h"
0062 #undef DC_LOGGER
0063 #define DC_LOGGER \
0064 CTX->logger
0065 #define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
0066
0067 #define VBIOSSMC_MSG_TestMessage 0x01
0068 #define VBIOSSMC_MSG_GetPmfwVersion 0x02
0069 #define VBIOSSMC_MSG_Spare0 0x03
0070 #define VBIOSSMC_MSG_SetDispclkFreq 0x04
0071 #define VBIOSSMC_MSG_Spare1 0x05
0072 #define VBIOSSMC_MSG_SetDppclkFreq 0x06
0073 #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x07
0074 #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x08
0075 #define VBIOSSMC_MSG_SetPhyclkVoltageByFreq 0x09
0076 #define VBIOSSMC_MSG_GetFclkFrequency 0x0A
0077 #define VBIOSSMC_MSG_SetDisplayCount 0x0B
0078 #define VBIOSSMC_MSG_SPARE 0x0C
0079 #define VBIOSSMC_MSG_UpdatePmeRestore 0x0D
0080 #define VBIOSSMC_MSG_SetVbiosDramAddrHigh 0x0E
0081 #define VBIOSSMC_MSG_SetVbiosDramAddrLow 0x0F
0082 #define VBIOSSMC_MSG_TransferTableSmu2Dram 0x10
0083 #define VBIOSSMC_MSG_TransferTableDram2Smu 0x11
0084 #define VBIOSSMC_MSG_SetDisplayIdleOptimizations 0x12
0085 #define VBIOSSMC_MSG_GetDprefclkFreq 0x13
0086 #define VBIOSSMC_MSG_GetDtbclkFreq 0x14
0087 #define VBIOSSMC_MSG_SetDtbclkFreq 0x15
0088 #define VBIOSSMC_Message_Count 0x16
0089
0090 #define VBIOSSMC_Status_BUSY 0x0
0091 #define VBIOSSMC_Result_OK 0x01
0092 #define VBIOSSMC_Result_Failed 0xFF
0093 #define VBIOSSMC_Result_UnknownCmd 0xFE
0094 #define VBIOSSMC_Result_CmdRejectedPrereq 0xFD
0095 #define VBIOSSMC_Result_CmdRejectedBusy 0xFC
0096
0097
0098
0099
0100
0101
0102 static uint32_t dcn316_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
0103 {
0104 uint32_t res_val = VBIOSSMC_Status_BUSY;
0105
0106 do {
0107 res_val = REG_READ(MP1_SMN_C2PMSG_91);
0108 if (res_val != VBIOSSMC_Status_BUSY)
0109 break;
0110
0111 if (delay_us >= 1000)
0112 msleep(delay_us/1000);
0113 else if (delay_us > 0)
0114 udelay(delay_us);
0115 } while (max_retries--);
0116
0117 return res_val;
0118 }
0119
0120 static int dcn316_smu_send_msg_with_param(
0121 struct clk_mgr_internal *clk_mgr,
0122 unsigned int msg_id, unsigned int param)
0123 {
0124 uint32_t result;
0125
0126 result = dcn316_smu_wait_for_response(clk_mgr, 10, 200000);
0127
0128 if (result != VBIOSSMC_Result_OK)
0129 smu_print("SMU Response was not OK. SMU response after wait received is: %d\n", result);
0130
0131 if (result == VBIOSSMC_Status_BUSY) {
0132 return -1;
0133 }
0134
0135
0136 REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
0137
0138
0139 REG_WRITE(MP1_SMN_C2PMSG_83, param);
0140
0141
0142 REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
0143
0144 result = dcn316_smu_wait_for_response(clk_mgr, 10, 200000);
0145
0146 if (result == VBIOSSMC_Status_BUSY) {
0147 ASSERT(0);
0148 dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
0149 }
0150
0151 return REG_READ(MP1_SMN_C2PMSG_83);
0152 }
0153
0154 int dcn316_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
0155 {
0156 return dcn316_smu_send_msg_with_param(
0157 clk_mgr,
0158 VBIOSSMC_MSG_GetPmfwVersion,
0159 0);
0160 }
0161
0162
0163 int dcn316_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
0164 {
0165 int actual_dispclk_set_mhz = -1;
0166
0167 if (!clk_mgr->smu_present)
0168 return requested_dispclk_khz;
0169
0170
0171 actual_dispclk_set_mhz = dcn316_smu_send_msg_with_param(
0172 clk_mgr,
0173 VBIOSSMC_MSG_SetDispclkFreq,
0174 khz_to_mhz_ceil(requested_dispclk_khz));
0175
0176 return actual_dispclk_set_mhz * 1000;
0177 }
0178
0179 int dcn316_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
0180 {
0181 int actual_dcfclk_set_mhz = -1;
0182
0183 if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
0184 return -1;
0185
0186 if (!clk_mgr->smu_present)
0187 return requested_dcfclk_khz;
0188
0189 actual_dcfclk_set_mhz = dcn316_smu_send_msg_with_param(
0190 clk_mgr,
0191 VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
0192 khz_to_mhz_ceil(requested_dcfclk_khz));
0193
0194 #ifdef DBG
0195 smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", actual_dcfclk_set_mhz, actual_dcfclk_set_mhz * 1000);
0196 #endif
0197
0198 return actual_dcfclk_set_mhz * 1000;
0199 }
0200
0201 int dcn316_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
0202 {
0203 int actual_min_ds_dcfclk_mhz = -1;
0204
0205 if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
0206 return -1;
0207
0208 if (!clk_mgr->smu_present)
0209 return requested_min_ds_dcfclk_khz;
0210
0211 actual_min_ds_dcfclk_mhz = dcn316_smu_send_msg_with_param(
0212 clk_mgr,
0213 VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
0214 khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
0215
0216 return actual_min_ds_dcfclk_mhz * 1000;
0217 }
0218
0219 int dcn316_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
0220 {
0221 int actual_dppclk_set_mhz = -1;
0222
0223 if (!clk_mgr->smu_present)
0224 return requested_dpp_khz;
0225
0226 actual_dppclk_set_mhz = dcn316_smu_send_msg_with_param(
0227 clk_mgr,
0228 VBIOSSMC_MSG_SetDppclkFreq,
0229 khz_to_mhz_ceil(requested_dpp_khz));
0230
0231 return actual_dppclk_set_mhz * 1000;
0232 }
0233
0234 void dcn316_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
0235 {
0236 if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
0237 return;
0238
0239 if (!clk_mgr->smu_present)
0240 return;
0241
0242
0243 dcn316_smu_send_msg_with_param(
0244 clk_mgr,
0245 VBIOSSMC_MSG_SetDisplayIdleOptimizations,
0246 idle_info);
0247 }
0248
0249 void dcn316_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
0250 {
0251 union display_idle_optimization_u idle_info = { 0 };
0252
0253 if (!clk_mgr->smu_present)
0254 return;
0255
0256 if (enable) {
0257 idle_info.idle_info.df_request_disabled = 1;
0258 idle_info.idle_info.phy_ref_clk_off = 1;
0259 }
0260
0261 dcn316_smu_send_msg_with_param(
0262 clk_mgr,
0263 VBIOSSMC_MSG_SetDisplayIdleOptimizations,
0264 idle_info.data);
0265 }
0266
0267 void dcn316_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
0268 {
0269 if (!clk_mgr->smu_present)
0270 return;
0271
0272 dcn316_smu_send_msg_with_param(clk_mgr,
0273 VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
0274 }
0275
0276 void dcn316_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
0277 {
0278 if (!clk_mgr->smu_present)
0279 return;
0280
0281 dcn316_smu_send_msg_with_param(clk_mgr,
0282 VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
0283 }
0284
0285 void dcn316_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
0286 {
0287 if (!clk_mgr->smu_present)
0288 return;
0289
0290 dcn316_smu_send_msg_with_param(clk_mgr,
0291 VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
0292 }
0293
0294 void dcn316_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
0295 {
0296 if (!clk_mgr->smu_present)
0297 return;
0298
0299 dcn316_smu_send_msg_with_param(clk_mgr,
0300 VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
0301 }
0302
0303 void dcn316_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
0304 {
0305 if (!clk_mgr->smu_present)
0306 return;
0307
0308 dcn316_smu_send_msg_with_param(
0309 clk_mgr,
0310 VBIOSSMC_MSG_UpdatePmeRestore,
0311 0);
0312 }
0313
0314
0315 void dcn316_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
0316 {
0317 if (!clk_mgr->smu_present)
0318 return;
0319
0320 dcn316_smu_send_msg_with_param(
0321 clk_mgr,
0322 VBIOSSMC_MSG_SetDtbclkFreq,
0323 enable);
0324 }
0325
0326 int dcn316_smu_get_dpref_clk(struct clk_mgr_internal *clk_mgr)
0327 {
0328 int dprefclk_get_mhz = -1;
0329
0330 if (clk_mgr->smu_present) {
0331 dprefclk_get_mhz = dcn316_smu_send_msg_with_param(
0332 clk_mgr,
0333 VBIOSSMC_MSG_GetDprefclkFreq,
0334 0);
0335 }
0336 return (dprefclk_get_mhz * 1000);
0337 }
0338
0339 int dcn316_smu_get_smu_fclk(struct clk_mgr_internal *clk_mgr)
0340 {
0341 int fclk_get_mhz = -1;
0342
0343 if (clk_mgr->smu_present) {
0344 fclk_get_mhz = dcn316_smu_send_msg_with_param(
0345 clk_mgr,
0346 VBIOSSMC_MSG_GetFclkFrequency,
0347 0);
0348 }
0349 return (fclk_get_mhz * 1000);
0350 }