Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2021 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
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 ///< To check if PMFW is alive and responding. Requirement specified by PMFW team
0082 #define VBIOSSMC_MSG_GetPmfwVersion               0x02 ///< Get PMFW version
0083 #define VBIOSSMC_MSG_Spare0                       0x03 ///< Spare0
0084 #define VBIOSSMC_MSG_SetDispclkFreq               0x04 ///< Set display clock frequency in MHZ
0085 #define VBIOSSMC_MSG_Spare1                       0x05 ///< Spare1
0086 #define VBIOSSMC_MSG_SetDppclkFreq                0x06 ///< Set DPP clock frequency in MHZ
0087 #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq       0x07 ///< Set DCF clock frequency hard min in MHZ
0088 #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk        0x08 ///< Set DCF clock minimum frequency in deep sleep in MHZ
0089 #define VBIOSSMC_MSG_GetDtbclkFreq                0x09 ///< Get display dtb clock frequency in MHZ in case VMIN does not support phy frequency
0090 #define VBIOSSMC_MSG_SetDtbClk                    0x0A ///< Set dtb clock frequency, return frequemcy in MHZ
0091 #define VBIOSSMC_MSG_SetDisplayCount              0x0B ///< Inform PMFW of number of display connected
0092 #define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0x0C ///< To ask PMFW turn off TMDP 48MHz refclk during display off to save power
0093 #define VBIOSSMC_MSG_UpdatePmeRestore             0x0D ///< To ask PMFW to write into Azalia for PME wake up event
0094 #define VBIOSSMC_MSG_SetVbiosDramAddrHigh         0x0E ///< Set DRAM address high 32 bits for WM table transfer
0095 #define VBIOSSMC_MSG_SetVbiosDramAddrLow          0x0F ///< Set DRAM address low 32 bits for WM table transfer
0096 #define VBIOSSMC_MSG_TransferTableSmu2Dram        0x10 ///< Transfer table from PMFW SRAM to system DRAM
0097 #define VBIOSSMC_MSG_TransferTableDram2Smu        0x11 ///< Transfer table from system DRAM to PMFW
0098 #define VBIOSSMC_MSG_SetDisplayIdleOptimizations  0x12 ///< Set Idle state optimization for display off
0099 #define VBIOSSMC_MSG_GetDprefclkFreq              0x13 ///< Get DPREF clock frequency. Return in MHZ
0100 #define VBIOSSMC_Message_Count                    0x14 ///< Total number of VBIS and DAL messages
0101 
0102 #define VBIOSSMC_Status_BUSY                      0x0
0103 #define VBIOSSMC_Result_OK                        0x01 ///< Message Response OK
0104 #define VBIOSSMC_Result_Failed                    0xFF ///< Message Response Failed
0105 #define VBIOSSMC_Result_UnknownCmd                0xFE ///< Message Response Unknown Command
0106 #define VBIOSSMC_Result_CmdRejectedPrereq         0xFD ///< Message Response Command Failed Prerequisite
0107 #define VBIOSSMC_Result_CmdRejectedBusy           0xFC ///< Message Response Command Rejected due to PMFW is busy. Sender should retry sending this message
0108 
0109 /*
0110  * Function to be used instead of REG_WAIT macro because the wait ends when
0111  * the register is NOT EQUAL to zero, and because the translation in msg_if.h
0112  * won't work with REG_WAIT.
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     /* First clear response register */
0148     REG_WRITE(MP1_SMN_C2PMSG_38, VBIOSSMC_Status_BUSY);
0149 
0150     /* Set the parameter register for the SMU message, unit is Mhz */
0151     REG_WRITE(MP1_SMN_C2PMSG_37, param);
0152 
0153     /* Trigger the message transaction by writing the message ID */
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     /*  Unit of SMU msg parameter is Mhz */
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     //TODO: Work with smu team to define optimization options.
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 }