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

          Line data    Source code
       1             : /*
       2             :  * Copyright 2021 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 "core_types.h"
      27             : #include "clk_mgr_internal.h"
      28             : #include "reg_helper.h"
      29             : #include "dm_helpers.h"
      30             : #include "dcn316_smu.h"
      31             : #include "mp/mp_13_0_8_offset.h"
      32             : #include "mp/mp_13_0_8_sh_mask.h"
      33             : 
      34             : #define MAX_INSTANCE                                        7
      35             : #define MAX_SEGMENT                                         6
      36             : 
      37             : struct IP_BASE_INSTANCE
      38             : {
      39             :     unsigned int segment[MAX_SEGMENT];
      40             : };
      41             : 
      42             : struct IP_BASE
      43             : {
      44             :     struct IP_BASE_INSTANCE instance[MAX_INSTANCE];
      45             : };
      46             : 
      47             : static const struct IP_BASE MP0_BASE = { { { { 0x00016000, 0x00DC0000, 0x00E00000, 0x00E40000, 0x0243FC00, 0 } },
      48             :                                         { { 0, 0, 0, 0, 0, 0 } },
      49             :                                         { { 0, 0, 0, 0, 0, 0 } },
      50             :                                         { { 0, 0, 0, 0, 0, 0 } },
      51             :                                         { { 0, 0, 0, 0, 0, 0 } },
      52             :                                         { { 0, 0, 0, 0, 0, 0 } },
      53             :                                         { { 0, 0, 0, 0, 0, 0 } } } };
      54             : 
      55             : #define REG(reg_name) \
      56             :         (MP0_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
      57             : 
      58             : #define FN(reg_name, field) \
      59             :         FD(reg_name##__##field)
      60             : 
      61             : #include "logger_types.h"
      62             : #undef DC_LOGGER
      63             : #define DC_LOGGER \
      64             :         CTX->logger
      65             : #define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
      66             : 
      67             : #define VBIOSSMC_MSG_TestMessage                  0x01 ///< To check if PMFW is alive and responding. Requirement specified by PMFW team
      68             : #define VBIOSSMC_MSG_GetPmfwVersion               0x02 ///< Get PMFW version
      69             : #define VBIOSSMC_MSG_Spare0                       0x03 ///< Spare0
      70             : #define VBIOSSMC_MSG_SetDispclkFreq               0x04 ///< Set display clock frequency in MHZ
      71             : #define VBIOSSMC_MSG_Spare1                       0x05 ///< Spare1
      72             : #define VBIOSSMC_MSG_SetDppclkFreq                0x06 ///< Set DPP clock frequency in MHZ
      73             : #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq       0x07 ///< Set DCF clock frequency hard min in MHZ
      74             : #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk        0x08 ///< Set DCF clock minimum frequency in deep sleep in MHZ
      75             : #define VBIOSSMC_MSG_SetPhyclkVoltageByFreq       0x09 ///< Set display phy clock frequency in MHZ in case VMIN does not support phy frequency
      76             : #define VBIOSSMC_MSG_GetFclkFrequency             0x0A ///< Get FCLK frequency, return frequemcy in MHZ
      77             : #define VBIOSSMC_MSG_SetDisplayCount              0x0B ///< Inform PMFW of number of display connected
      78             : #define VBIOSSMC_MSG_SPARE                                                0x0C ///< SPARE
      79             : #define VBIOSSMC_MSG_UpdatePmeRestore             0x0D ///< To ask PMFW to write into Azalia for PME wake up event
      80             : #define VBIOSSMC_MSG_SetVbiosDramAddrHigh         0x0E ///< Set DRAM address high 32 bits for WM table transfer
      81             : #define VBIOSSMC_MSG_SetVbiosDramAddrLow          0x0F ///< Set DRAM address low 32 bits for WM table transfer
      82             : #define VBIOSSMC_MSG_TransferTableSmu2Dram        0x10 ///< Transfer table from PMFW SRAM to system DRAM
      83             : #define VBIOSSMC_MSG_TransferTableDram2Smu        0x11 ///< Transfer table from system DRAM to PMFW
      84             : #define VBIOSSMC_MSG_SetDisplayIdleOptimizations  0x12 ///< Set Idle state optimization for display off
      85             : #define VBIOSSMC_MSG_GetDprefclkFreq              0x13 ///< Get DPREF clock frequency. Return in MHZ
      86             : #define VBIOSSMC_MSG_GetDtbclkFreq                0x14 ///< Get DPREF clock frequency. Return in MHZ
      87             : #define VBIOSSMC_MSG_SetDtbclkFreq                0x15 ///< Inform PMFW to turn on/off DTB clock arg = 1, turn DTB clock on 600MHz/ arg = 0 turn DTB clock off
      88             : #define VBIOSSMC_Message_Count                    0x16 ///< Total number of VBIS and DAL messages
      89             : 
      90             : #define VBIOSSMC_Status_BUSY                      0x0
      91             : #define VBIOSSMC_Result_OK                        0x01 ///< Message Response OK
      92             : #define VBIOSSMC_Result_Failed                    0xFF ///< Message Response Failed
      93             : #define VBIOSSMC_Result_UnknownCmd                0xFE ///< Message Response Unknown Command
      94             : #define VBIOSSMC_Result_CmdRejectedPrereq         0xFD ///< Message Response Command Failed Prerequisite
      95             : #define VBIOSSMC_Result_CmdRejectedBusy           0xFC ///< Message Response Command Rejected due to PMFW is busy. Sender should retry sending this message
      96             : 
      97             : /*
      98             :  * Function to be used instead of REG_WAIT macro because the wait ends when
      99             :  * the register is NOT EQUAL to zero, and because the translation in msg_if.h
     100             :  * won't work with REG_WAIT.
     101             :  */
     102           0 : static uint32_t dcn316_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
     103             : {
     104           0 :         uint32_t res_val = VBIOSSMC_Status_BUSY;
     105             : 
     106             :         do {
     107           0 :                 res_val = REG_READ(MP1_SMN_C2PMSG_91);
     108           0 :                 if (res_val != VBIOSSMC_Status_BUSY)
     109             :                         break;
     110             : 
     111           0 :                 if (delay_us >= 1000)
     112           0 :                         msleep(delay_us/1000);
     113           0 :                 else if (delay_us > 0)
     114           0 :                         udelay(delay_us);
     115           0 :         } while (max_retries--);
     116             : 
     117           0 :         return res_val;
     118             : }
     119             : 
     120           0 : static int dcn316_smu_send_msg_with_param(
     121             :                 struct clk_mgr_internal *clk_mgr,
     122             :                 unsigned int msg_id, unsigned int param)
     123             : {
     124             :         uint32_t result;
     125             : 
     126           0 :         result = dcn316_smu_wait_for_response(clk_mgr, 10, 200000);
     127             : 
     128             :         if (result != VBIOSSMC_Result_OK)
     129             :                 smu_print("SMU Response was not OK. SMU response after wait received is: %d\n", result);
     130             : 
     131           0 :         if (result == VBIOSSMC_Status_BUSY) {
     132             :                 return -1;
     133             :         }
     134             : 
     135             :         /* First clear response register */
     136           0 :         REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
     137             : 
     138             :         /* Set the parameter register for the SMU message, unit is Mhz */
     139           0 :         REG_WRITE(MP1_SMN_C2PMSG_83, param);
     140             : 
     141             :         /* Trigger the message transaction by writing the message ID */
     142           0 :         REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
     143             : 
     144           0 :         result = dcn316_smu_wait_for_response(clk_mgr, 10, 200000);
     145             : 
     146           0 :         if (result == VBIOSSMC_Status_BUSY) {
     147           0 :                 ASSERT(0);
     148           0 :                 dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
     149             :         }
     150             : 
     151           0 :         return REG_READ(MP1_SMN_C2PMSG_83);
     152             : }
     153             : 
     154           0 : int dcn316_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
     155             : {
     156           0 :         return dcn316_smu_send_msg_with_param(
     157             :                         clk_mgr,
     158             :                         VBIOSSMC_MSG_GetPmfwVersion,
     159             :                         0);
     160             : }
     161             : 
     162             : 
     163           0 : int dcn316_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
     164             : {
     165           0 :         int actual_dispclk_set_mhz = -1;
     166             : 
     167           0 :         if (!clk_mgr->smu_present)
     168             :                 return requested_dispclk_khz;
     169             : 
     170             :         /*  Unit of SMU msg parameter is Mhz */
     171           0 :         actual_dispclk_set_mhz = dcn316_smu_send_msg_with_param(
     172             :                         clk_mgr,
     173             :                         VBIOSSMC_MSG_SetDispclkFreq,
     174           0 :                         khz_to_mhz_ceil(requested_dispclk_khz));
     175             : 
     176           0 :         return actual_dispclk_set_mhz * 1000;
     177             : }
     178             : 
     179           0 : int dcn316_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
     180             : {
     181           0 :         int actual_dcfclk_set_mhz = -1;
     182             : 
     183           0 :         if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
     184             :                 return -1;
     185             : 
     186           0 :         if (!clk_mgr->smu_present)
     187             :                 return requested_dcfclk_khz;
     188             : 
     189           0 :         actual_dcfclk_set_mhz = dcn316_smu_send_msg_with_param(
     190             :                         clk_mgr,
     191             :                         VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
     192           0 :                         khz_to_mhz_ceil(requested_dcfclk_khz));
     193             : 
     194             : #ifdef DBG
     195             :         smu_print("actual_dcfclk_set_mhz %d is set to : %d\n", actual_dcfclk_set_mhz, actual_dcfclk_set_mhz * 1000);
     196             : #endif
     197             : 
     198           0 :         return actual_dcfclk_set_mhz * 1000;
     199             : }
     200             : 
     201           0 : int dcn316_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
     202             : {
     203           0 :         int actual_min_ds_dcfclk_mhz = -1;
     204             : 
     205           0 :         if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
     206             :                 return -1;
     207             : 
     208           0 :         if (!clk_mgr->smu_present)
     209             :                 return requested_min_ds_dcfclk_khz;
     210             : 
     211           0 :         actual_min_ds_dcfclk_mhz = dcn316_smu_send_msg_with_param(
     212             :                         clk_mgr,
     213             :                         VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
     214           0 :                         khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
     215             : 
     216           0 :         return actual_min_ds_dcfclk_mhz * 1000;
     217             : }
     218             : 
     219           0 : int dcn316_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
     220             : {
     221           0 :         int actual_dppclk_set_mhz = -1;
     222             : 
     223           0 :         if (!clk_mgr->smu_present)
     224             :                 return requested_dpp_khz;
     225             : 
     226           0 :         actual_dppclk_set_mhz = dcn316_smu_send_msg_with_param(
     227             :                         clk_mgr,
     228             :                         VBIOSSMC_MSG_SetDppclkFreq,
     229           0 :                         khz_to_mhz_ceil(requested_dpp_khz));
     230             : 
     231           0 :         return actual_dppclk_set_mhz * 1000;
     232             : }
     233             : 
     234           0 : void dcn316_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
     235             : {
     236           0 :         if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
     237             :                 return;
     238             : 
     239           0 :         if (!clk_mgr->smu_present)
     240             :                 return;
     241             : 
     242             :         //TODO: Work with smu team to define optimization options.
     243           0 :         dcn316_smu_send_msg_with_param(
     244             :                 clk_mgr,
     245             :                 VBIOSSMC_MSG_SetDisplayIdleOptimizations,
     246             :                 idle_info);
     247             : }
     248             : 
     249           0 : void dcn316_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
     250             : {
     251           0 :         union display_idle_optimization_u idle_info = { 0 };
     252             : 
     253           0 :         if (!clk_mgr->smu_present)
     254           0 :                 return;
     255             : 
     256           0 :         if (enable) {
     257           0 :                 idle_info.idle_info.df_request_disabled = 1;
     258           0 :                 idle_info.idle_info.phy_ref_clk_off = 1;
     259             :         }
     260             : 
     261           0 :         dcn316_smu_send_msg_with_param(
     262             :                         clk_mgr,
     263             :                         VBIOSSMC_MSG_SetDisplayIdleOptimizations,
     264             :                         idle_info.data);
     265             : }
     266             : 
     267           0 : void dcn316_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
     268             : {
     269           0 :         if (!clk_mgr->smu_present)
     270             :                 return;
     271             : 
     272           0 :         dcn316_smu_send_msg_with_param(clk_mgr,
     273             :                         VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
     274             : }
     275             : 
     276           0 : void dcn316_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
     277             : {
     278           0 :         if (!clk_mgr->smu_present)
     279             :                 return;
     280             : 
     281           0 :         dcn316_smu_send_msg_with_param(clk_mgr,
     282             :                         VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
     283             : }
     284             : 
     285           0 : void dcn316_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
     286             : {
     287           0 :         if (!clk_mgr->smu_present)
     288             :                 return;
     289             : 
     290           0 :         dcn316_smu_send_msg_with_param(clk_mgr,
     291             :                         VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
     292             : }
     293             : 
     294           0 : void dcn316_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
     295             : {
     296           0 :         if (!clk_mgr->smu_present)
     297             :                 return;
     298             : 
     299           0 :         dcn316_smu_send_msg_with_param(clk_mgr,
     300             :                         VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
     301             : }
     302             : 
     303           0 : void dcn316_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
     304             : {
     305           0 :         if (!clk_mgr->smu_present)
     306             :                 return;
     307             : 
     308           0 :         dcn316_smu_send_msg_with_param(
     309             :                         clk_mgr,
     310             :                         VBIOSSMC_MSG_UpdatePmeRestore,
     311             :                         0);
     312             : }
     313             : 
     314             : /* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */
     315           0 : void dcn316_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
     316             : {
     317           0 :         if (!clk_mgr->smu_present)
     318             :                 return;
     319             : 
     320           0 :         dcn316_smu_send_msg_with_param(
     321             :                         clk_mgr,
     322             :                         VBIOSSMC_MSG_SetDtbclkFreq,
     323             :                         enable);
     324             : }
     325             : 
     326           0 : int dcn316_smu_get_dpref_clk(struct clk_mgr_internal *clk_mgr)
     327             : {
     328           0 :         int dprefclk_get_mhz = -1;
     329             : 
     330           0 :         if (clk_mgr->smu_present) {
     331           0 :                 dprefclk_get_mhz = dcn316_smu_send_msg_with_param(
     332             :                         clk_mgr,
     333             :                         VBIOSSMC_MSG_GetDprefclkFreq,
     334             :                         0);
     335             :         }
     336           0 :         return (dprefclk_get_mhz * 1000);
     337             : }
     338             : 
     339           0 : int dcn316_smu_get_smu_fclk(struct clk_mgr_internal *clk_mgr)
     340             : {
     341           0 :         int fclk_get_mhz = -1;
     342             : 
     343           0 :         if (clk_mgr->smu_present) {
     344           0 :                 fclk_get_mhz = dcn316_smu_send_msg_with_param(
     345             :                         clk_mgr,
     346             :                         VBIOSSMC_MSG_GetFclkFrequency,
     347             :                         0);
     348             :         }
     349           0 :         return (fclk_get_mhz * 1000);
     350             : }

Generated by: LCOV version 1.14