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

dcn301_smu.c (8089B)


      1/*
      2 * Copyright 2020 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 <linux/delay.h>
     30
     31#include "dcn301_smu.h"
     32
     33#include "vangogh_ip_offset.h"
     34
     35#include "mp/mp_11_5_0_offset.h"
     36#include "mp/mp_11_5_0_sh_mask.h"
     37
     38#define REG(reg_name) \
     39	(MP0_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
     40
     41#define FN(reg_name, field) \
     42	FD(reg_name##__##field)
     43
     44#define VBIOSSMC_MSG_GetSmuVersion                0x2
     45#define VBIOSSMC_MSG_SetDispclkFreq               0x4
     46#define VBIOSSMC_MSG_SetDprefclkFreq              0x5
     47#define VBIOSSMC_MSG_SetDppclkFreq                0x6
     48#define VBIOSSMC_MSG_SetHardMinDcfclkByFreq       0x7
     49#define VBIOSSMC_MSG_SetMinDeepSleepDcfclk        0x8
     50//#define VBIOSSMC_MSG_SetPhyclkVoltageByFreq       0xA
     51#define VBIOSSMC_MSG_GetFclkFrequency             0xA
     52//#define VBIOSSMC_MSG_SetDisplayCount              0xC
     53//#define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xD
     54#define VBIOSSMC_MSG_UpdatePmeRestore			  0xD
     55#define VBIOSSMC_MSG_SetVbiosDramAddrHigh         0xE   //Used for WM table txfr
     56#define VBIOSSMC_MSG_SetVbiosDramAddrLow          0xF
     57#define VBIOSSMC_MSG_TransferTableSmu2Dram        0x10
     58#define VBIOSSMC_MSG_TransferTableDram2Smu        0x11
     59#define VBIOSSMC_MSG_SetDisplayIdleOptimizations  0x12
     60
     61#define VBIOSSMC_Status_BUSY                      0x0
     62#define VBIOSSMC_Result_OK                        0x1
     63#define VBIOSSMC_Result_Failed                    0xFF
     64#define VBIOSSMC_Result_UnknownCmd                0xFE
     65#define VBIOSSMC_Result_CmdRejectedPrereq         0xFD
     66#define VBIOSSMC_Result_CmdRejectedBusy           0xFC
     67
     68/*
     69 * Function to be used instead of REG_WAIT macro because the wait ends when
     70 * the register is NOT EQUAL to zero, and because the translation in msg_if.h
     71 * won't work with REG_WAIT.
     72 */
     73static uint32_t dcn301_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
     74{
     75	uint32_t res_val = VBIOSSMC_Status_BUSY;
     76
     77	do {
     78		res_val = REG_READ(MP1_SMN_C2PMSG_91);
     79		if (res_val != VBIOSSMC_Status_BUSY)
     80			break;
     81
     82		if (delay_us >= 1000)
     83			msleep(delay_us/1000);
     84		else if (delay_us > 0)
     85			udelay(delay_us);
     86	} while (max_retries--);
     87
     88	return res_val;
     89}
     90
     91static int dcn301_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
     92					  unsigned int msg_id,
     93					  unsigned int param)
     94{
     95	uint32_t result;
     96
     97	result = dcn301_smu_wait_for_response(clk_mgr, 10, 200000);
     98
     99	/* First clear response register */
    100	REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
    101
    102	/* Set the parameter register for the SMU message, unit is Mhz */
    103	REG_WRITE(MP1_SMN_C2PMSG_83, param);
    104
    105	/* Trigger the message transaction by writing the message ID */
    106	REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
    107
    108	result = dcn301_smu_wait_for_response(clk_mgr, 10, 200000);
    109
    110	ASSERT(result == VBIOSSMC_Result_OK);
    111
    112	/* Actual dispclk set is returned in the parameter register */
    113	return REG_READ(MP1_SMN_C2PMSG_83);
    114}
    115
    116int dcn301_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
    117{
    118	int smu_version = dcn301_smu_send_msg_with_param(clk_mgr,
    119							 VBIOSSMC_MSG_GetSmuVersion,
    120							 0);
    121
    122	DC_LOG_DEBUG("%s %x\n", __func__, smu_version);
    123
    124	return smu_version;
    125}
    126
    127
    128int dcn301_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
    129{
    130	int actual_dispclk_set_mhz = -1;
    131
    132	DC_LOG_DEBUG("%s(%d)\n", __func__, requested_dispclk_khz);
    133
    134	/*  Unit of SMU msg parameter is Mhz */
    135	actual_dispclk_set_mhz = dcn301_smu_send_msg_with_param(
    136			clk_mgr,
    137			VBIOSSMC_MSG_SetDispclkFreq,
    138			khz_to_mhz_ceil(requested_dispclk_khz));
    139
    140	return actual_dispclk_set_mhz * 1000;
    141}
    142
    143int dcn301_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
    144{
    145	int actual_dprefclk_set_mhz = -1;
    146
    147	DC_LOG_DEBUG("%s %d\n", __func__, clk_mgr->base.dprefclk_khz / 1000);
    148
    149	actual_dprefclk_set_mhz = dcn301_smu_send_msg_with_param(
    150			clk_mgr,
    151			VBIOSSMC_MSG_SetDprefclkFreq,
    152			khz_to_mhz_ceil(clk_mgr->base.dprefclk_khz));
    153
    154	/* TODO: add code for programing DP DTO, currently this is down by command table */
    155
    156	return actual_dprefclk_set_mhz * 1000;
    157}
    158
    159int dcn301_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
    160{
    161	int actual_dcfclk_set_mhz = -1;
    162
    163	DC_LOG_DEBUG("%s(%d)\n", __func__, requested_dcfclk_khz);
    164
    165	actual_dcfclk_set_mhz = dcn301_smu_send_msg_with_param(
    166			clk_mgr,
    167			VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
    168			khz_to_mhz_ceil(requested_dcfclk_khz));
    169
    170	return actual_dcfclk_set_mhz * 1000;
    171}
    172
    173int dcn301_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
    174{
    175	int actual_min_ds_dcfclk_mhz = -1;
    176
    177	DC_LOG_DEBUG("%s(%d)\n", __func__, requested_min_ds_dcfclk_khz);
    178
    179	actual_min_ds_dcfclk_mhz = dcn301_smu_send_msg_with_param(
    180			clk_mgr,
    181			VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
    182			khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
    183
    184	return actual_min_ds_dcfclk_mhz * 1000;
    185}
    186
    187int dcn301_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
    188{
    189	int actual_dppclk_set_mhz = -1;
    190
    191	DC_LOG_DEBUG("%s(%d)\n", __func__, requested_dpp_khz);
    192
    193	actual_dppclk_set_mhz = dcn301_smu_send_msg_with_param(
    194			clk_mgr,
    195			VBIOSSMC_MSG_SetDppclkFreq,
    196			khz_to_mhz_ceil(requested_dpp_khz));
    197
    198	return actual_dppclk_set_mhz * 1000;
    199}
    200
    201void dcn301_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
    202{
    203	//TODO: Work with smu team to define optimization options.
    204
    205	DC_LOG_DEBUG("%s(%x)\n", __func__, idle_info);
    206
    207	dcn301_smu_send_msg_with_param(
    208		clk_mgr,
    209		VBIOSSMC_MSG_SetDisplayIdleOptimizations,
    210		idle_info);
    211}
    212
    213void dcn301_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
    214{
    215	union display_idle_optimization_u idle_info = { 0 };
    216
    217	if (enable) {
    218		idle_info.idle_info.df_request_disabled = 1;
    219		idle_info.idle_info.phy_ref_clk_off = 1;
    220	}
    221
    222	DC_LOG_DEBUG("%s(%d)\n", __func__, enable);
    223
    224	dcn301_smu_send_msg_with_param(
    225			clk_mgr,
    226			VBIOSSMC_MSG_SetDisplayIdleOptimizations,
    227			idle_info.data);
    228}
    229
    230void dcn301_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
    231{
    232	dcn301_smu_send_msg_with_param(
    233			clk_mgr,
    234			VBIOSSMC_MSG_UpdatePmeRestore,
    235			0);
    236}
    237
    238void dcn301_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
    239{
    240	DC_LOG_DEBUG("%s(%x)\n", __func__, addr_high);
    241
    242	dcn301_smu_send_msg_with_param(clk_mgr,
    243			VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
    244}
    245
    246void dcn301_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
    247{
    248	DC_LOG_DEBUG("%s(%x)\n", __func__, addr_low);
    249
    250	dcn301_smu_send_msg_with_param(clk_mgr,
    251			VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
    252}
    253
    254void dcn301_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
    255{
    256	dcn301_smu_send_msg_with_param(clk_mgr,
    257			VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
    258}
    259
    260void dcn301_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
    261{
    262	dcn301_smu_send_msg_with_param(clk_mgr,
    263			VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
    264}