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 <linux/delay.h>
0030
0031 #include "dcn301_smu.h"
0032
0033 #include "vangogh_ip_offset.h"
0034
0035 #include "mp/mp_11_5_0_offset.h"
0036 #include "mp/mp_11_5_0_sh_mask.h"
0037
0038 #define REG(reg_name) \
0039 (MP0_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
0040
0041 #define FN(reg_name, field) \
0042 FD(reg_name##__##field)
0043
0044 #include "logger_types.h"
0045 #undef DC_LOGGER
0046 #define DC_LOGGER \
0047 CTX->logger
0048 #define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
0049
0050 #define VBIOSSMC_MSG_GetSmuVersion 0x2
0051 #define VBIOSSMC_MSG_SetDispclkFreq 0x4
0052 #define VBIOSSMC_MSG_SetDprefclkFreq 0x5
0053 #define VBIOSSMC_MSG_SetDppclkFreq 0x6
0054 #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x7
0055 #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x8
0056
0057 #define VBIOSSMC_MSG_GetFclkFrequency 0xA
0058
0059
0060 #define VBIOSSMC_MSG_UpdatePmeRestore 0xD
0061 #define VBIOSSMC_MSG_SetVbiosDramAddrHigh 0xE
0062 #define VBIOSSMC_MSG_SetVbiosDramAddrLow 0xF
0063 #define VBIOSSMC_MSG_TransferTableSmu2Dram 0x10
0064 #define VBIOSSMC_MSG_TransferTableDram2Smu 0x11
0065 #define VBIOSSMC_MSG_SetDisplayIdleOptimizations 0x12
0066
0067 #define VBIOSSMC_Status_BUSY 0x0
0068 #define VBIOSSMC_Result_OK 0x1
0069 #define VBIOSSMC_Result_Failed 0xFF
0070 #define VBIOSSMC_Result_UnknownCmd 0xFE
0071 #define VBIOSSMC_Result_CmdRejectedPrereq 0xFD
0072 #define VBIOSSMC_Result_CmdRejectedBusy 0xFC
0073
0074
0075
0076
0077
0078
0079 static uint32_t dcn301_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
0080 {
0081 uint32_t res_val = VBIOSSMC_Status_BUSY;
0082
0083 do {
0084 res_val = REG_READ(MP1_SMN_C2PMSG_91);
0085 if (res_val != VBIOSSMC_Status_BUSY)
0086 break;
0087
0088 if (delay_us >= 1000)
0089 msleep(delay_us/1000);
0090 else if (delay_us > 0)
0091 udelay(delay_us);
0092 } while (max_retries--);
0093
0094 return res_val;
0095 }
0096
0097 static int dcn301_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
0098 unsigned int msg_id,
0099 unsigned int param)
0100 {
0101 uint32_t result;
0102
0103 result = dcn301_smu_wait_for_response(clk_mgr, 10, 200000);
0104
0105 if (result != VBIOSSMC_Result_OK)
0106 smu_print("SMU Response was not OK. SMU response after wait received is: %d\n", result);
0107
0108 if (result == VBIOSSMC_Status_BUSY) {
0109 return -1;
0110 }
0111
0112
0113 REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
0114
0115
0116 REG_WRITE(MP1_SMN_C2PMSG_83, param);
0117
0118
0119 REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
0120
0121 result = dcn301_smu_wait_for_response(clk_mgr, 10, 200000);
0122
0123 ASSERT(result == VBIOSSMC_Result_OK);
0124
0125
0126 return REG_READ(MP1_SMN_C2PMSG_83);
0127 }
0128
0129 int dcn301_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
0130 {
0131 int smu_version = dcn301_smu_send_msg_with_param(clk_mgr,
0132 VBIOSSMC_MSG_GetSmuVersion,
0133 0);
0134
0135 DC_LOG_DEBUG("%s %x\n", __func__, smu_version);
0136
0137 return smu_version;
0138 }
0139
0140
0141 int dcn301_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
0142 {
0143 int actual_dispclk_set_mhz = -1;
0144
0145 DC_LOG_DEBUG("%s(%d)\n", __func__, requested_dispclk_khz);
0146
0147
0148 actual_dispclk_set_mhz = dcn301_smu_send_msg_with_param(
0149 clk_mgr,
0150 VBIOSSMC_MSG_SetDispclkFreq,
0151 khz_to_mhz_ceil(requested_dispclk_khz));
0152
0153 return actual_dispclk_set_mhz * 1000;
0154 }
0155
0156 int dcn301_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
0157 {
0158 int actual_dprefclk_set_mhz = -1;
0159
0160 DC_LOG_DEBUG("%s %d\n", __func__, clk_mgr->base.dprefclk_khz / 1000);
0161
0162 actual_dprefclk_set_mhz = dcn301_smu_send_msg_with_param(
0163 clk_mgr,
0164 VBIOSSMC_MSG_SetDprefclkFreq,
0165 khz_to_mhz_ceil(clk_mgr->base.dprefclk_khz));
0166
0167
0168
0169 return actual_dprefclk_set_mhz * 1000;
0170 }
0171
0172 int dcn301_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
0173 {
0174 int actual_dcfclk_set_mhz = -1;
0175
0176 DC_LOG_DEBUG("%s(%d)\n", __func__, requested_dcfclk_khz);
0177
0178 actual_dcfclk_set_mhz = dcn301_smu_send_msg_with_param(
0179 clk_mgr,
0180 VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
0181 khz_to_mhz_ceil(requested_dcfclk_khz));
0182
0183 #ifdef DBG
0184 smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", actual_dcfclk_set_mhz, actual_dcfclk_set_mhz * 1000);
0185 #endif
0186
0187 return actual_dcfclk_set_mhz * 1000;
0188 }
0189
0190 int dcn301_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
0191 {
0192 int actual_min_ds_dcfclk_mhz = -1;
0193
0194 DC_LOG_DEBUG("%s(%d)\n", __func__, requested_min_ds_dcfclk_khz);
0195
0196 actual_min_ds_dcfclk_mhz = dcn301_smu_send_msg_with_param(
0197 clk_mgr,
0198 VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
0199 khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
0200
0201 return actual_min_ds_dcfclk_mhz * 1000;
0202 }
0203
0204 int dcn301_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
0205 {
0206 int actual_dppclk_set_mhz = -1;
0207
0208 DC_LOG_DEBUG("%s(%d)\n", __func__, requested_dpp_khz);
0209
0210 actual_dppclk_set_mhz = dcn301_smu_send_msg_with_param(
0211 clk_mgr,
0212 VBIOSSMC_MSG_SetDppclkFreq,
0213 khz_to_mhz_ceil(requested_dpp_khz));
0214
0215 return actual_dppclk_set_mhz * 1000;
0216 }
0217
0218 void dcn301_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
0219 {
0220
0221
0222 DC_LOG_DEBUG("%s(%x)\n", __func__, idle_info);
0223
0224 dcn301_smu_send_msg_with_param(
0225 clk_mgr,
0226 VBIOSSMC_MSG_SetDisplayIdleOptimizations,
0227 idle_info);
0228 }
0229
0230 void dcn301_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
0231 {
0232 union display_idle_optimization_u idle_info = { 0 };
0233
0234 if (enable) {
0235 idle_info.idle_info.df_request_disabled = 1;
0236 idle_info.idle_info.phy_ref_clk_off = 1;
0237 }
0238
0239 DC_LOG_DEBUG("%s(%d)\n", __func__, enable);
0240
0241 dcn301_smu_send_msg_with_param(
0242 clk_mgr,
0243 VBIOSSMC_MSG_SetDisplayIdleOptimizations,
0244 idle_info.data);
0245 }
0246
0247 void dcn301_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
0248 {
0249 dcn301_smu_send_msg_with_param(
0250 clk_mgr,
0251 VBIOSSMC_MSG_UpdatePmeRestore,
0252 0);
0253 }
0254
0255 void dcn301_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
0256 {
0257 DC_LOG_DEBUG("%s(%x)\n", __func__, addr_high);
0258
0259 dcn301_smu_send_msg_with_param(clk_mgr,
0260 VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
0261 }
0262
0263 void dcn301_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
0264 {
0265 DC_LOG_DEBUG("%s(%x)\n", __func__, addr_low);
0266
0267 dcn301_smu_send_msg_with_param(clk_mgr,
0268 VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
0269 }
0270
0271 void dcn301_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
0272 {
0273 dcn301_smu_send_msg_with_param(clk_mgr,
0274 VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
0275 }
0276
0277 void dcn301_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
0278 {
0279 dcn301_smu_send_msg_with_param(clk_mgr,
0280 VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
0281 }