cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dcn316_smu.c (11078B)


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