File Index
Files and directories
Sign in
FILE

dcn301_smu.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/dcn301_smu.c C
  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#include "dm_helpers.h"
 33
 34#include "vangogh_ip_offset.h"
 35
 36#include "mp/mp_11_5_0_offset.h"
 37#include "mp/mp_11_5_0_sh_mask.h"
 38
 39#define REG(reg_name) \
 40	(MP0_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
 41
 42#define FN(reg_name, field) \
 43	FD(reg_name##__##field)
 44
 45#include "logger_types.h"
 46#undef DC_LOGGER
 47#define DC_LOGGER \
 48	CTX->logger
 49#define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
 50
 51#define VBIOSSMC_MSG_GetSmuVersion                0x2
 52#define VBIOSSMC_MSG_SetDispclkFreq               0x4
 53#define VBIOSSMC_MSG_SetDprefclkFreq              0x5
 54#define VBIOSSMC_MSG_SetDppclkFreq                0x6
 55#define VBIOSSMC_MSG_SetHardMinDcfclkByFreq       0x7
 56#define VBIOSSMC_MSG_SetMinDeepSleepDcfclk        0x8
 57//#define VBIOSSMC_MSG_SetPhyclkVoltageByFreq       0xA
 58#define VBIOSSMC_MSG_GetFclkFrequency             0xA
 59//#define VBIOSSMC_MSG_SetDisplayCount              0xC
 60//#define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xD
 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
 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 dcn301_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 dcn301_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 = dcn301_smu_wait_for_response(clk_mgr, 10, 200000);
105
106	if (result != VBIOSSMC_Result_OK)
107		smu_print("SMU Response was not OK. SMU response after wait received is: %d\n", result);
108
109	if (result == VBIOSSMC_Status_BUSY) {
110		return -1;
111	}
112
113	/* First clear response register */
114	REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
115
116	/* Set the parameter register for the SMU message, unit is Mhz */
117	REG_WRITE(MP1_SMN_C2PMSG_83, param);
118
119	/* Trigger the message transaction by writing the message ID */
120	REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
121
122	result = dcn301_smu_wait_for_response(clk_mgr, 10, 200000);
123
124	if (IS_SMU_TIMEOUT(result)) {
125		ASSERT(0);
126		dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
127	}
128
129	/* Actual dispclk set is returned in the parameter register */
130	return REG_READ(MP1_SMN_C2PMSG_83);
131}
132
133int dcn301_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
134{
135	int smu_version = dcn301_smu_send_msg_with_param(clk_mgr,
136							 VBIOSSMC_MSG_GetSmuVersion,
137							 0);
138
139	DC_LOG_DEBUG("%s %x\n", __func__, smu_version);
140
141	return smu_version;
142}
143
144
145int dcn301_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
146{
147	int actual_dispclk_set_mhz = -1;
148
149	DC_LOG_DEBUG("%s(%d)\n", __func__, requested_dispclk_khz);
150
151	/*  Unit of SMU msg parameter is Mhz */
152	actual_dispclk_set_mhz = dcn301_smu_send_msg_with_param(
153			clk_mgr,
154			VBIOSSMC_MSG_SetDispclkFreq,
155			khz_to_mhz_ceil(requested_dispclk_khz));
156
157	return actual_dispclk_set_mhz * 1000;
158}
159
160int dcn301_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
161{
162	int actual_dprefclk_set_mhz = -1;
163
164	DC_LOG_DEBUG("%s %d\n", __func__, clk_mgr->base.dprefclk_khz / 1000);
165
166	actual_dprefclk_set_mhz = dcn301_smu_send_msg_with_param(
167			clk_mgr,
168			VBIOSSMC_MSG_SetDprefclkFreq,
169			khz_to_mhz_ceil(clk_mgr->base.dprefclk_khz));
170
171	/* TODO: add code for programing DP DTO, currently this is down by command table */
172
173	return actual_dprefclk_set_mhz * 1000;
174}
175
176int dcn301_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
177{
178	int actual_dcfclk_set_mhz = -1;
179
180	DC_LOG_DEBUG("%s(%d)\n", __func__, requested_dcfclk_khz);
181
182	actual_dcfclk_set_mhz = dcn301_smu_send_msg_with_param(
183			clk_mgr,
184			VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
185			khz_to_mhz_ceil(requested_dcfclk_khz));
186
187	return actual_dcfclk_set_mhz * 1000;
188}
189
190int dcn301_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
191{
192	int actual_min_ds_dcfclk_mhz = -1;
193
194	DC_LOG_DEBUG("%s(%d)\n", __func__, requested_min_ds_dcfclk_khz);
195
196	actual_min_ds_dcfclk_mhz = dcn301_smu_send_msg_with_param(
197			clk_mgr,
198			VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
199			khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
200
201	return actual_min_ds_dcfclk_mhz * 1000;
202}
203
204int dcn301_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
205{
206	int actual_dppclk_set_mhz = -1;
207
208	DC_LOG_DEBUG("%s(%d)\n", __func__, requested_dpp_khz);
209
210	actual_dppclk_set_mhz = dcn301_smu_send_msg_with_param(
211			clk_mgr,
212			VBIOSSMC_MSG_SetDppclkFreq,
213			khz_to_mhz_ceil(requested_dpp_khz));
214
215	return actual_dppclk_set_mhz * 1000;
216}
217
218void dcn301_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
219{
220	//TODO: Work with smu team to define optimization options.
221
222	DC_LOG_DEBUG("%s(%x)\n", __func__, idle_info);
223
224	dcn301_smu_send_msg_with_param(
225		clk_mgr,
226		VBIOSSMC_MSG_SetDisplayIdleOptimizations,
227		idle_info);
228}
229
230void dcn301_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
231{
232	union display_idle_optimization_u idle_info = { 0 };
233
234	if (enable) {
235		idle_info.idle_info.df_request_disabled = 1;
236		idle_info.idle_info.phy_ref_clk_off = 1;
237	}
238
239	DC_LOG_DEBUG("%s(%d)\n", __func__, enable);
240
241	dcn301_smu_send_msg_with_param(
242			clk_mgr,
243			VBIOSSMC_MSG_SetDisplayIdleOptimizations,
244			idle_info.data);
245}
246
247void dcn301_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
248{
249	dcn301_smu_send_msg_with_param(
250			clk_mgr,
251			VBIOSSMC_MSG_UpdatePmeRestore,
252			0);
253}
254
255void dcn301_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
256{
257	DC_LOG_DEBUG("%s(%x)\n", __func__, addr_high);
258
259	dcn301_smu_send_msg_with_param(clk_mgr,
260			VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
261}
262
263void dcn301_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
264{
265	DC_LOG_DEBUG("%s(%x)\n", __func__, addr_low);
266
267	dcn301_smu_send_msg_with_param(clk_mgr,
268			VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
269}
270
271void dcn301_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
272{
273	dcn301_smu_send_msg_with_param(clk_mgr,
274			VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
275}
276
277void dcn301_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
278{
279	dcn301_smu_send_msg_with_param(clk_mgr,
280			VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
281}
~/ Read-only file preview.