Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012-16 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 <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   //Not used. DPRef is constant
0054 #define VBIOSSMC_MSG_SetDppclkFreq                0x6
0055 #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq       0x7
0056 #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk        0x8
0057 #define VBIOSSMC_MSG_SetPhyclkVoltageByFreq       0x9   //Keep it in case VMIN dees not support phy clk
0058 #define VBIOSSMC_MSG_GetFclkFrequency             0xA
0059 #define VBIOSSMC_MSG_SetDisplayCount              0xB   //Not used anymore
0060 #define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xC   //Not used anymore
0061 #define VBIOSSMC_MSG_UpdatePmeRestore             0xD
0062 #define VBIOSSMC_MSG_SetVbiosDramAddrHigh         0xE   //Used for WM table txfr
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  * Function to be used instead of REG_WAIT macro because the wait ends when
0083  * the register is NOT EQUAL to zero, and because the translation in msg_if.h
0084  * won't work with REG_WAIT.
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     /* First clear response register */
0120     REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
0121 
0122     /* Set the parameter register for the SMU message, unit is Mhz */
0123     REG_WRITE(MP1_SMN_C2PMSG_83, param);
0124 
0125     /* Trigger the message transaction by writing the message ID */
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     /*  Unit of SMU msg parameter is Mhz */
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     /* TODO: add code for programing DP DTO, currently this is down by command table */
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     //TODO: Work with smu team to define optimization options.
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 /* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */
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 }