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

dcn31_smu.c (10115B)


      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#define VBIOSSMC_MSG_TestMessage                  0x1
     44#define VBIOSSMC_MSG_GetSmuVersion                0x2
     45#define VBIOSSMC_MSG_PowerUpGfx                   0x3
     46#define VBIOSSMC_MSG_SetDispclkFreq               0x4
     47#define VBIOSSMC_MSG_SetDprefclkFreq              0x5   //Not used. DPRef is constant
     48#define VBIOSSMC_MSG_SetDppclkFreq                0x6
     49#define VBIOSSMC_MSG_SetHardMinDcfclkByFreq       0x7
     50#define VBIOSSMC_MSG_SetMinDeepSleepDcfclk        0x8
     51#define VBIOSSMC_MSG_SetPhyclkVoltageByFreq       0x9	//Keep it in case VMIN dees not support phy clk
     52#define VBIOSSMC_MSG_GetFclkFrequency             0xA
     53#define VBIOSSMC_MSG_SetDisplayCount              0xB   //Not used anymore
     54#define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xC   //Not used anymore
     55#define VBIOSSMC_MSG_UpdatePmeRestore             0xD
     56#define VBIOSSMC_MSG_SetVbiosDramAddrHigh         0xE   //Used for WM table txfr
     57#define VBIOSSMC_MSG_SetVbiosDramAddrLow          0xF
     58#define VBIOSSMC_MSG_TransferTableSmu2Dram        0x10
     59#define VBIOSSMC_MSG_TransferTableDram2Smu        0x11
     60#define VBIOSSMC_MSG_SetDisplayIdleOptimizations  0x12
     61#define VBIOSSMC_MSG_GetDprefclkFreq              0x13
     62#define VBIOSSMC_MSG_GetDtbclkFreq                0x14
     63#define VBIOSSMC_MSG_AllowZstatesEntry            0x15
     64#define VBIOSSMC_MSG_DisallowZstatesEntry     	  0x16
     65#define VBIOSSMC_MSG_SetDtbClk                    0x17
     66#define VBIOSSMC_Message_Count                    0x18
     67
     68#define VBIOSSMC_Status_BUSY                      0x0
     69#define VBIOSSMC_Result_OK                        0x1
     70#define VBIOSSMC_Result_Failed                    0xFF
     71#define VBIOSSMC_Result_UnknownCmd                0xFE
     72#define VBIOSSMC_Result_CmdRejectedPrereq         0xFD
     73#define VBIOSSMC_Result_CmdRejectedBusy           0xFC
     74
     75/*
     76 * Function to be used instead of REG_WAIT macro because the wait ends when
     77 * the register is NOT EQUAL to zero, and because the translation in msg_if.h
     78 * won't work with REG_WAIT.
     79 */
     80static uint32_t dcn31_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
     81{
     82	uint32_t res_val = VBIOSSMC_Status_BUSY;
     83
     84	do {
     85		res_val = REG_READ(MP1_SMN_C2PMSG_91);
     86		if (res_val != VBIOSSMC_Status_BUSY)
     87			break;
     88
     89		if (delay_us >= 1000)
     90			msleep(delay_us/1000);
     91		else if (delay_us > 0)
     92			udelay(delay_us);
     93	} while (max_retries--);
     94
     95	return res_val;
     96}
     97
     98static int dcn31_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
     99					 unsigned int msg_id,
    100					 unsigned int param)
    101{
    102	uint32_t result;
    103
    104	result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000);
    105	ASSERT(result == VBIOSSMC_Result_OK);
    106
    107	if (result == VBIOSSMC_Status_BUSY) {
    108		return -1;
    109	}
    110
    111	/* First clear response register */
    112	REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
    113
    114	/* Set the parameter register for the SMU message, unit is Mhz */
    115	REG_WRITE(MP1_SMN_C2PMSG_83, param);
    116
    117	/* Trigger the message transaction by writing the message ID */
    118	REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
    119
    120	result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000);
    121
    122	if (result == VBIOSSMC_Result_Failed) {
    123		if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu &&
    124		    param == TABLE_WATERMARKS)
    125			DC_LOG_WARNING("Watermarks table not configured properly by SMU");
    126		else
    127			ASSERT(0);
    128		REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK);
    129		return -1;
    130	}
    131
    132	if (IS_SMU_TIMEOUT(result)) {
    133		ASSERT(0);
    134		dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
    135	}
    136
    137	return REG_READ(MP1_SMN_C2PMSG_83);
    138}
    139
    140int dcn31_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
    141{
    142	return dcn31_smu_send_msg_with_param(
    143			clk_mgr,
    144			VBIOSSMC_MSG_GetSmuVersion,
    145			0);
    146}
    147
    148
    149int dcn31_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
    150{
    151	int actual_dispclk_set_mhz = -1;
    152
    153	if (!clk_mgr->smu_present)
    154		return requested_dispclk_khz;
    155
    156	/*  Unit of SMU msg parameter is Mhz */
    157	actual_dispclk_set_mhz = dcn31_smu_send_msg_with_param(
    158			clk_mgr,
    159			VBIOSSMC_MSG_SetDispclkFreq,
    160			khz_to_mhz_ceil(requested_dispclk_khz));
    161
    162	return actual_dispclk_set_mhz * 1000;
    163}
    164
    165int dcn31_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
    166{
    167	int actual_dprefclk_set_mhz = -1;
    168
    169	if (!clk_mgr->smu_present)
    170		return clk_mgr->base.dprefclk_khz;
    171
    172	actual_dprefclk_set_mhz = dcn31_smu_send_msg_with_param(
    173			clk_mgr,
    174			VBIOSSMC_MSG_SetDprefclkFreq,
    175			khz_to_mhz_ceil(clk_mgr->base.dprefclk_khz));
    176
    177	/* TODO: add code for programing DP DTO, currently this is down by command table */
    178
    179	return actual_dprefclk_set_mhz * 1000;
    180}
    181
    182int dcn31_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
    183{
    184	int actual_dcfclk_set_mhz = -1;
    185
    186	if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
    187		return -1;
    188
    189	if (!clk_mgr->smu_present)
    190		return requested_dcfclk_khz;
    191
    192	actual_dcfclk_set_mhz = dcn31_smu_send_msg_with_param(
    193			clk_mgr,
    194			VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
    195			khz_to_mhz_ceil(requested_dcfclk_khz));
    196
    197	return actual_dcfclk_set_mhz * 1000;
    198}
    199
    200int dcn31_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
    201{
    202	int actual_min_ds_dcfclk_mhz = -1;
    203
    204	if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
    205		return -1;
    206
    207	if (!clk_mgr->smu_present)
    208		return requested_min_ds_dcfclk_khz;
    209
    210	actual_min_ds_dcfclk_mhz = dcn31_smu_send_msg_with_param(
    211			clk_mgr,
    212			VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
    213			khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
    214
    215	return actual_min_ds_dcfclk_mhz * 1000;
    216}
    217
    218int dcn31_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
    219{
    220	int actual_dppclk_set_mhz = -1;
    221
    222	if (!clk_mgr->smu_present)
    223		return requested_dpp_khz;
    224
    225	actual_dppclk_set_mhz = dcn31_smu_send_msg_with_param(
    226			clk_mgr,
    227			VBIOSSMC_MSG_SetDppclkFreq,
    228			khz_to_mhz_ceil(requested_dpp_khz));
    229
    230	return actual_dppclk_set_mhz * 1000;
    231}
    232
    233void dcn31_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
    234{
    235	if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
    236		return;
    237
    238	if (!clk_mgr->smu_present)
    239		return;
    240
    241	//TODO: Work with smu team to define optimization options.
    242	dcn31_smu_send_msg_with_param(
    243		clk_mgr,
    244		VBIOSSMC_MSG_SetDisplayIdleOptimizations,
    245		idle_info);
    246}
    247
    248void dcn31_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
    249{
    250	union display_idle_optimization_u idle_info = { 0 };
    251
    252	if (!clk_mgr->smu_present)
    253		return;
    254
    255	if (enable) {
    256		idle_info.idle_info.df_request_disabled = 1;
    257		idle_info.idle_info.phy_ref_clk_off = 1;
    258	}
    259
    260	dcn31_smu_send_msg_with_param(
    261			clk_mgr,
    262			VBIOSSMC_MSG_SetDisplayIdleOptimizations,
    263			idle_info.data);
    264}
    265
    266void dcn31_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
    267{
    268	if (!clk_mgr->smu_present)
    269		return;
    270
    271	dcn31_smu_send_msg_with_param(
    272			clk_mgr,
    273			VBIOSSMC_MSG_UpdatePmeRestore,
    274			0);
    275}
    276
    277void dcn31_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
    278{
    279	if (!clk_mgr->smu_present)
    280		return;
    281
    282	dcn31_smu_send_msg_with_param(clk_mgr,
    283			VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
    284}
    285
    286void dcn31_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
    287{
    288	if (!clk_mgr->smu_present)
    289		return;
    290
    291	dcn31_smu_send_msg_with_param(clk_mgr,
    292			VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
    293}
    294
    295void dcn31_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
    296{
    297	if (!clk_mgr->smu_present)
    298		return;
    299
    300	dcn31_smu_send_msg_with_param(clk_mgr,
    301			VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
    302}
    303
    304void dcn31_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
    305{
    306	if (!clk_mgr->smu_present)
    307		return;
    308
    309	dcn31_smu_send_msg_with_param(clk_mgr,
    310			VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
    311}
    312
    313void dcn31_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zstate_support_state support)
    314{
    315	unsigned int msg_id, param;
    316
    317	if (!clk_mgr->smu_present)
    318		return;
    319
    320	if (!clk_mgr->base.ctx->dc->debug.enable_z9_disable_interface &&
    321			(support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY))
    322		support = DCN_ZSTATE_SUPPORT_DISALLOW;
    323
    324
    325	if (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY)
    326		param = 1;
    327	else
    328		param = 0;
    329
    330	if (support == DCN_ZSTATE_SUPPORT_DISALLOW)
    331		msg_id = VBIOSSMC_MSG_DisallowZstatesEntry;
    332	else
    333		msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
    334
    335	dcn31_smu_send_msg_with_param(
    336		clk_mgr,
    337		msg_id,
    338		param);
    339
    340}
    341
    342/* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */
    343void dcn31_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
    344{
    345	if (!clk_mgr->smu_present)
    346		return;
    347
    348	dcn31_smu_send_msg_with_param(
    349			clk_mgr,
    350			VBIOSSMC_MSG_SetDtbClk,
    351			enable);
    352}