File Index
Files and directories
Sign in
FILE

dcn31_smu.c

File preview with syntax highlighting.

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