LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31 - dcn31_smu.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 102 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 17 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012-16 Advanced Micro Devices, Inc.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      17             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      18             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      19             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      20             :  * OTHER DEALINGS IN THE SOFTWARE.
      21             :  *
      22             :  * Authors: AMD
      23             :  *
      24             :  */
      25             : 
      26             : #include <linux/delay.h>
      27             : #include "core_types.h"
      28             : #include "clk_mgr_internal.h"
      29             : #include "reg_helper.h"
      30             : #include "dm_helpers.h"
      31             : #include "dcn31_smu.h"
      32             : 
      33             : #include "yellow_carp_offset.h"
      34             : #include "mp/mp_13_0_2_offset.h"
      35             : #include "mp/mp_13_0_2_sh_mask.h"
      36             : 
      37             : #define REG(reg_name) \
      38             :         (MP0_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
      39             : 
      40             : #define FN(reg_name, field) \
      41             :         FD(reg_name##__##field)
      42             : 
      43             : #include "logger_types.h"
      44             : #undef DC_LOGGER
      45             : #define DC_LOGGER \
      46             :         CTX->logger
      47             : #define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
      48             : 
      49             : #define VBIOSSMC_MSG_TestMessage                  0x1
      50             : #define VBIOSSMC_MSG_GetSmuVersion                0x2
      51             : #define VBIOSSMC_MSG_PowerUpGfx                   0x3
      52             : #define VBIOSSMC_MSG_SetDispclkFreq               0x4
      53             : #define VBIOSSMC_MSG_SetDprefclkFreq              0x5   //Not used. DPRef is constant
      54             : #define VBIOSSMC_MSG_SetDppclkFreq                0x6
      55             : #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq       0x7
      56             : #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk        0x8
      57             : #define VBIOSSMC_MSG_SetPhyclkVoltageByFreq       0x9   //Keep it in case VMIN dees not support phy clk
      58             : #define VBIOSSMC_MSG_GetFclkFrequency             0xA
      59             : #define VBIOSSMC_MSG_SetDisplayCount              0xB   //Not used anymore
      60             : #define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xC   //Not used anymore
      61             : #define VBIOSSMC_MSG_UpdatePmeRestore             0xD
      62             : #define VBIOSSMC_MSG_SetVbiosDramAddrHigh         0xE   //Used for WM table txfr
      63             : #define VBIOSSMC_MSG_SetVbiosDramAddrLow          0xF
      64             : #define VBIOSSMC_MSG_TransferTableSmu2Dram        0x10
      65             : #define VBIOSSMC_MSG_TransferTableDram2Smu        0x11
      66             : #define VBIOSSMC_MSG_SetDisplayIdleOptimizations  0x12
      67             : #define VBIOSSMC_MSG_GetDprefclkFreq              0x13
      68             : #define VBIOSSMC_MSG_GetDtbclkFreq                0x14
      69             : #define VBIOSSMC_MSG_AllowZstatesEntry            0x15
      70             : #define VBIOSSMC_MSG_DisallowZstatesEntry         0x16
      71             : #define VBIOSSMC_MSG_SetDtbClk                    0x17
      72             : #define VBIOSSMC_Message_Count                    0x18
      73             : 
      74             : #define VBIOSSMC_Status_BUSY                      0x0
      75             : #define VBIOSSMC_Result_OK                        0x1
      76             : #define VBIOSSMC_Result_Failed                    0xFF
      77             : #define VBIOSSMC_Result_UnknownCmd                0xFE
      78             : #define VBIOSSMC_Result_CmdRejectedPrereq         0xFD
      79             : #define VBIOSSMC_Result_CmdRejectedBusy           0xFC
      80             : 
      81             : /*
      82             :  * Function to be used instead of REG_WAIT macro because the wait ends when
      83             :  * the register is NOT EQUAL to zero, and because the translation in msg_if.h
      84             :  * won't work with REG_WAIT.
      85             :  */
      86           0 : static uint32_t dcn31_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
      87             : {
      88           0 :         uint32_t res_val = VBIOSSMC_Status_BUSY;
      89             : 
      90             :         do {
      91           0 :                 res_val = REG_READ(MP1_SMN_C2PMSG_91);
      92           0 :                 if (res_val != VBIOSSMC_Status_BUSY)
      93             :                         break;
      94             : 
      95           0 :                 if (delay_us >= 1000)
      96           0 :                         msleep(delay_us/1000);
      97           0 :                 else if (delay_us > 0)
      98           0 :                         udelay(delay_us);
      99           0 :         } while (max_retries--);
     100             : 
     101           0 :         return res_val;
     102             : }
     103             : 
     104           0 : static int dcn31_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
     105             :                                          unsigned int msg_id,
     106             :                                          unsigned int param)
     107             : {
     108             :         uint32_t result;
     109             : 
     110           0 :         result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000);
     111             : 
     112             :         if (result != VBIOSSMC_Result_OK)
     113             :                 smu_print("SMU Response was not OK. SMU response after wait received is: %d\n", result);
     114             : 
     115           0 :         if (result == VBIOSSMC_Status_BUSY) {
     116             :                 return -1;
     117             :         }
     118             : 
     119             :         /* First clear response register */
     120           0 :         REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
     121             : 
     122             :         /* Set the parameter register for the SMU message, unit is Mhz */
     123           0 :         REG_WRITE(MP1_SMN_C2PMSG_83, param);
     124             : 
     125             :         /* Trigger the message transaction by writing the message ID */
     126           0 :         REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
     127             : 
     128           0 :         result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000);
     129             : 
     130           0 :         if (result == VBIOSSMC_Result_Failed) {
     131           0 :                 if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu &&
     132           0 :                     param == TABLE_WATERMARKS)
     133           0 :                         DC_LOG_WARNING("Watermarks table not configured properly by SMU");
     134             :                 else
     135           0 :                         ASSERT(0);
     136           0 :                 REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK);
     137           0 :                 return -1;
     138             :         }
     139             : 
     140           0 :         if (IS_SMU_TIMEOUT(result)) {
     141           0 :                 ASSERT(0);
     142           0 :                 dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
     143             :         }
     144             : 
     145           0 :         return REG_READ(MP1_SMN_C2PMSG_83);
     146             : }
     147             : 
     148           0 : int dcn31_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
     149             : {
     150           0 :         return dcn31_smu_send_msg_with_param(
     151             :                         clk_mgr,
     152             :                         VBIOSSMC_MSG_GetSmuVersion,
     153             :                         0);
     154             : }
     155             : 
     156             : 
     157           0 : int dcn31_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
     158             : {
     159           0 :         int actual_dispclk_set_mhz = -1;
     160             : 
     161           0 :         if (!clk_mgr->smu_present)
     162             :                 return requested_dispclk_khz;
     163             : 
     164             :         /*  Unit of SMU msg parameter is Mhz */
     165           0 :         actual_dispclk_set_mhz = dcn31_smu_send_msg_with_param(
     166             :                         clk_mgr,
     167             :                         VBIOSSMC_MSG_SetDispclkFreq,
     168           0 :                         khz_to_mhz_ceil(requested_dispclk_khz));
     169             : 
     170           0 :         return actual_dispclk_set_mhz * 1000;
     171             : }
     172             : 
     173           0 : int dcn31_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
     174             : {
     175           0 :         int actual_dprefclk_set_mhz = -1;
     176             : 
     177           0 :         if (!clk_mgr->smu_present)
     178           0 :                 return clk_mgr->base.dprefclk_khz;
     179             : 
     180           0 :         actual_dprefclk_set_mhz = dcn31_smu_send_msg_with_param(
     181             :                         clk_mgr,
     182             :                         VBIOSSMC_MSG_SetDprefclkFreq,
     183           0 :                         khz_to_mhz_ceil(clk_mgr->base.dprefclk_khz));
     184             : 
     185             :         /* TODO: add code for programing DP DTO, currently this is down by command table */
     186             : 
     187           0 :         return actual_dprefclk_set_mhz * 1000;
     188             : }
     189             : 
     190           0 : int dcn31_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
     191             : {
     192           0 :         int actual_dcfclk_set_mhz = -1;
     193             : 
     194           0 :         if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
     195             :                 return -1;
     196             : 
     197           0 :         if (!clk_mgr->smu_present)
     198             :                 return requested_dcfclk_khz;
     199             : 
     200           0 :         actual_dcfclk_set_mhz = dcn31_smu_send_msg_with_param(
     201             :                         clk_mgr,
     202             :                         VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
     203           0 :                         khz_to_mhz_ceil(requested_dcfclk_khz));
     204             : 
     205             : #ifdef DBG
     206             :         smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", actual_dcfclk_set_mhz, actual_dcfclk_set_mhz * 1000);
     207             : #endif
     208             : 
     209           0 :         return actual_dcfclk_set_mhz * 1000;
     210             : }
     211             : 
     212           0 : int dcn31_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
     213             : {
     214           0 :         int actual_min_ds_dcfclk_mhz = -1;
     215             : 
     216           0 :         if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
     217             :                 return -1;
     218             : 
     219           0 :         if (!clk_mgr->smu_present)
     220             :                 return requested_min_ds_dcfclk_khz;
     221             : 
     222           0 :         actual_min_ds_dcfclk_mhz = dcn31_smu_send_msg_with_param(
     223             :                         clk_mgr,
     224             :                         VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
     225           0 :                         khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
     226             : 
     227           0 :         return actual_min_ds_dcfclk_mhz * 1000;
     228             : }
     229             : 
     230           0 : int dcn31_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
     231             : {
     232           0 :         int actual_dppclk_set_mhz = -1;
     233             : 
     234           0 :         if (!clk_mgr->smu_present)
     235             :                 return requested_dpp_khz;
     236             : 
     237           0 :         actual_dppclk_set_mhz = dcn31_smu_send_msg_with_param(
     238             :                         clk_mgr,
     239             :                         VBIOSSMC_MSG_SetDppclkFreq,
     240           0 :                         khz_to_mhz_ceil(requested_dpp_khz));
     241             : 
     242           0 :         return actual_dppclk_set_mhz * 1000;
     243             : }
     244             : 
     245           0 : void dcn31_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
     246             : {
     247           0 :         if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
     248             :                 return;
     249             : 
     250           0 :         if (!clk_mgr->smu_present)
     251             :                 return;
     252             : 
     253             :         //TODO: Work with smu team to define optimization options.
     254           0 :         dcn31_smu_send_msg_with_param(
     255             :                 clk_mgr,
     256             :                 VBIOSSMC_MSG_SetDisplayIdleOptimizations,
     257             :                 idle_info);
     258             : }
     259             : 
     260           0 : void dcn31_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
     261             : {
     262           0 :         union display_idle_optimization_u idle_info = { 0 };
     263             : 
     264           0 :         if (!clk_mgr->smu_present)
     265           0 :                 return;
     266             : 
     267           0 :         if (enable) {
     268           0 :                 idle_info.idle_info.df_request_disabled = 1;
     269           0 :                 idle_info.idle_info.phy_ref_clk_off = 1;
     270             :         }
     271             : 
     272           0 :         dcn31_smu_send_msg_with_param(
     273             :                         clk_mgr,
     274             :                         VBIOSSMC_MSG_SetDisplayIdleOptimizations,
     275             :                         idle_info.data);
     276             : }
     277             : 
     278           0 : void dcn31_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
     279             : {
     280           0 :         if (!clk_mgr->smu_present)
     281             :                 return;
     282             : 
     283           0 :         dcn31_smu_send_msg_with_param(
     284             :                         clk_mgr,
     285             :                         VBIOSSMC_MSG_UpdatePmeRestore,
     286             :                         0);
     287             : }
     288             : 
     289           0 : void dcn31_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
     290             : {
     291           0 :         if (!clk_mgr->smu_present)
     292             :                 return;
     293             : 
     294           0 :         dcn31_smu_send_msg_with_param(clk_mgr,
     295             :                         VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
     296             : }
     297             : 
     298           0 : void dcn31_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
     299             : {
     300           0 :         if (!clk_mgr->smu_present)
     301             :                 return;
     302             : 
     303           0 :         dcn31_smu_send_msg_with_param(clk_mgr,
     304             :                         VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
     305             : }
     306             : 
     307           0 : void dcn31_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
     308             : {
     309           0 :         if (!clk_mgr->smu_present)
     310             :                 return;
     311             : 
     312           0 :         dcn31_smu_send_msg_with_param(clk_mgr,
     313             :                         VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
     314             : }
     315             : 
     316           0 : void dcn31_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
     317             : {
     318           0 :         if (!clk_mgr->smu_present)
     319             :                 return;
     320             : 
     321           0 :         dcn31_smu_send_msg_with_param(clk_mgr,
     322             :                         VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
     323             : }
     324             : 
     325           0 : void dcn31_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zstate_support_state support)
     326             : {
     327             :         unsigned int msg_id, param;
     328             : 
     329           0 :         if (!clk_mgr->smu_present)
     330             :                 return;
     331             : 
     332           0 :         if (!clk_mgr->base.ctx->dc->debug.enable_z9_disable_interface &&
     333             :                         (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY))
     334           0 :                 support = DCN_ZSTATE_SUPPORT_DISALLOW;
     335             : 
     336             : 
     337           0 :         if (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY)
     338             :                 param = 1;
     339             :         else
     340           0 :                 param = 0;
     341             : 
     342           0 :         if (support == DCN_ZSTATE_SUPPORT_DISALLOW)
     343             :                 msg_id = VBIOSSMC_MSG_DisallowZstatesEntry;
     344             :         else
     345           0 :                 msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
     346             : 
     347           0 :         dcn31_smu_send_msg_with_param(
     348             :                 clk_mgr,
     349             :                 msg_id,
     350             :                 param);
     351             : 
     352             : }
     353             : 
     354             : /* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */
     355           0 : void dcn31_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
     356             : {
     357           0 :         if (!clk_mgr->smu_present)
     358             :                 return;
     359             : 
     360           0 :         dcn31_smu_send_msg_with_param(
     361             :                         clk_mgr,
     362             :                         VBIOSSMC_MSG_SetDtbClk,
     363             :                         enable);
     364             : }

Generated by: LCOV version 1.14