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