File Index
Files and directories
Sign in
FILE

dcn314_smu.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c C
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright 2022 Advanced Micro Devices, Inc.
  4 *
  5 * Permission is hereby granted, free of charge, to any person obtaining a
  6 * copy of this software and associated documentation files (the "Software"),
  7 * to deal in the Software without restriction, including without limitation
  8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9 * and/or sell copies of the Software, and to permit persons to whom the
 10 * Software is furnished to do so, subject to the following conditions:
 11 *
 12 * The above copyright notice and this permission notice shall be included in
 13 * all copies or substantial portions of the Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 21 * OTHER DEALINGS IN THE SOFTWARE.
 22 *
 23 * Authors: AMD
 24 *
 25 */
 26
 27
 28
 29#include "core_types.h"
 30#include "clk_mgr_internal.h"
 31#include "reg_helper.h"
 32#include "dm_helpers.h"
 33#include "dcn314_smu.h"
 34
 35#include "mp/mp_13_0_5_offset.h"
 36
 37/* TODO: Use the real headers when they're correct */
 38#define MP1_BASE__INST0_SEG0                       0x00016000
 39#define MP1_BASE__INST0_SEG1                       0x0243FC00
 40#define MP1_BASE__INST0_SEG2                       0x00DC0000
 41#define MP1_BASE__INST0_SEG3                       0x00E00000
 42#define MP1_BASE__INST0_SEG4                       0x00E40000
 43#define MP1_BASE__INST0_SEG5                       0
 44
 45#ifdef BASE_INNER
 46#undef BASE_INNER
 47#endif
 48
 49#define BASE_INNER(seg) MP1_BASE__INST0_SEG ## seg
 50
 51#define BASE(seg) BASE_INNER(seg)
 52
 53#define REG(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name)
 54
 55#define FN(reg_name, field) \
 56	FD(reg_name##__##field)
 57
 58#include "logger_types.h"
 59#undef DC_LOGGER
 60#define DC_LOGGER \
 61	CTX->logger
 62#define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
 63
 64#define VBIOSSMC_MSG_TestMessage                  0x1
 65#define VBIOSSMC_MSG_GetSmuVersion                0x2
 66#define VBIOSSMC_MSG_PowerUpGfx                   0x3
 67#define VBIOSSMC_MSG_SetDispclkFreq               0x4
 68#define VBIOSSMC_MSG_SetDprefclkFreq              0x5   //Not used. DPRef is constant
 69#define VBIOSSMC_MSG_SetDppclkFreq                0x6
 70#define VBIOSSMC_MSG_SetHardMinDcfclkByFreq       0x7
 71#define VBIOSSMC_MSG_SetMinDeepSleepDcfclk        0x8
 72#define VBIOSSMC_MSG_SetPhyclkVoltageByFreq       0x9	//Keep it in case VMIN dees not support phy clk
 73#define VBIOSSMC_MSG_GetFclkFrequency             0xA
 74#define VBIOSSMC_MSG_SetDisplayCount              0xB   //Not used anymore
 75#define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xC   //Not used anymore
 76#define VBIOSSMC_MSG_UpdatePmeRestore             0xD
 77#define VBIOSSMC_MSG_SetVbiosDramAddrHigh         0xE   //Used for WM table txfr
 78#define VBIOSSMC_MSG_SetVbiosDramAddrLow          0xF
 79#define VBIOSSMC_MSG_TransferTableSmu2Dram        0x10
 80#define VBIOSSMC_MSG_TransferTableDram2Smu        0x11
 81#define VBIOSSMC_MSG_SetDisplayIdleOptimizations  0x12
 82#define VBIOSSMC_MSG_GetDprefclkFreq              0x13
 83#define VBIOSSMC_MSG_GetDtbclkFreq                0x14
 84#define VBIOSSMC_MSG_AllowZstatesEntry            0x15
 85#define VBIOSSMC_MSG_DisallowZstatesEntry	  0x16
 86#define VBIOSSMC_MSG_SetDtbClk                    0x17
 87#define VBIOSSMC_Message_Count                    0x18
 88
 89#define VBIOSSMC_Status_BUSY                      0x0
 90#define VBIOSSMC_Result_OK                        0x1
 91#define VBIOSSMC_Result_Failed                    0xFF
 92#define VBIOSSMC_Result_UnknownCmd                0xFE
 93#define VBIOSSMC_Result_CmdRejectedPrereq         0xFD
 94#define VBIOSSMC_Result_CmdRejectedBusy           0xFC
 95
 96/*
 97 * Function to be used instead of REG_WAIT macro because the wait ends when
 98 * the register is NOT EQUAL to zero, and because the translation in msg_if.h
 99 * won't work with REG_WAIT.
100 */
101static uint32_t dcn314_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
102{
103	uint32_t res_val = VBIOSSMC_Status_BUSY;
104
105	do {
106		res_val = REG_READ(MP1_SMN_C2PMSG_91);
107		if (res_val != VBIOSSMC_Status_BUSY)
108			break;
109
110		if (delay_us >= 1000)
111			msleep(delay_us/1000);
112		else if (delay_us > 0)
113			udelay(delay_us);
114	} while (max_retries--);
115
116	return res_val;
117}
118
119static int dcn314_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
120					 unsigned int msg_id,
121					 unsigned int param)
122{
123	uint32_t result;
124
125	result = dcn314_smu_wait_for_response(clk_mgr, 10, 200000);
126
127	if (result != VBIOSSMC_Result_OK)
128		smu_print("SMU Response was not OK. SMU response after wait received is: %d\n",
129				result);
130
131	if (result == VBIOSSMC_Status_BUSY)
132		return -1;
133
134	/* First clear response register */
135	REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
136
137	/* Set the parameter register for the SMU message, unit is Mhz */
138	REG_WRITE(MP1_SMN_C2PMSG_83, param);
139
140	/* Trigger the message transaction by writing the message ID */
141	REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
142
143	result = dcn314_smu_wait_for_response(clk_mgr, 10, 200000);
144
145	if (result == VBIOSSMC_Result_Failed) {
146		if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu &&
147		    param == TABLE_WATERMARKS)
148			DC_LOG_DEBUG("Watermarks table not configured properly by SMU");
149		else if (msg_id == VBIOSSMC_MSG_SetHardMinDcfclkByFreq ||
150			 msg_id == VBIOSSMC_MSG_SetMinDeepSleepDcfclk)
151			DC_LOG_WARNING("DCFCLK_DPM is not enabled by BIOS");
152		else
153			ASSERT(0);
154		REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK);
155		return -1;
156	}
157
158	if (IS_SMU_TIMEOUT(result)) {
159		ASSERT(0);
160		dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
161	}
162
163	return REG_READ(MP1_SMN_C2PMSG_83);
164}
165
166int dcn314_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
167{
168	return dcn314_smu_send_msg_with_param(
169			clk_mgr,
170			VBIOSSMC_MSG_GetSmuVersion,
171			0);
172}
173
174
175int dcn314_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
176{
177	int actual_dispclk_set_mhz = -1;
178
179	if (!clk_mgr->smu_present)
180		return requested_dispclk_khz;
181
182	/*  Unit of SMU msg parameter is Mhz */
183	actual_dispclk_set_mhz = dcn314_smu_send_msg_with_param(
184			clk_mgr,
185			VBIOSSMC_MSG_SetDispclkFreq,
186			khz_to_mhz_ceil(requested_dispclk_khz));
187
188	return actual_dispclk_set_mhz * 1000;
189}
190
191int dcn314_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
192{
193	int actual_dprefclk_set_mhz = -1;
194
195	if (!clk_mgr->smu_present)
196		return clk_mgr->base.dprefclk_khz;
197
198	actual_dprefclk_set_mhz = dcn314_smu_send_msg_with_param(
199			clk_mgr,
200			VBIOSSMC_MSG_SetDprefclkFreq,
201			khz_to_mhz_ceil(clk_mgr->base.dprefclk_khz));
202
203	/* TODO: add code for programing DP DTO, currently this is down by command table */
204
205	return actual_dprefclk_set_mhz * 1000;
206}
207
208int dcn314_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
209{
210	int actual_dcfclk_set_mhz = -1;
211
212	if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
213		return -1;
214
215	if (!clk_mgr->smu_present)
216		return requested_dcfclk_khz;
217
218	actual_dcfclk_set_mhz = dcn314_smu_send_msg_with_param(
219			clk_mgr,
220			VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
221			khz_to_mhz_ceil(requested_dcfclk_khz));
222
223	return actual_dcfclk_set_mhz * 1000;
224}
225
226int dcn314_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
227{
228	int actual_min_ds_dcfclk_mhz = -1;
229
230	if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
231		return -1;
232
233	if (!clk_mgr->smu_present)
234		return requested_min_ds_dcfclk_khz;
235
236	actual_min_ds_dcfclk_mhz = dcn314_smu_send_msg_with_param(
237			clk_mgr,
238			VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
239			khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
240
241	return actual_min_ds_dcfclk_mhz * 1000;
242}
243
244int dcn314_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
245{
246	int actual_dppclk_set_mhz = -1;
247
248	if (!clk_mgr->smu_present)
249		return requested_dpp_khz;
250
251	actual_dppclk_set_mhz = dcn314_smu_send_msg_with_param(
252			clk_mgr,
253			VBIOSSMC_MSG_SetDppclkFreq,
254			khz_to_mhz_ceil(requested_dpp_khz));
255
256	return actual_dppclk_set_mhz * 1000;
257}
258
259void dcn314_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
260{
261	if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
262		return;
263
264	if (!clk_mgr->smu_present)
265		return;
266
267	//TODO: Work with smu team to define optimization options.
268	dcn314_smu_send_msg_with_param(
269		clk_mgr,
270		VBIOSSMC_MSG_SetDisplayIdleOptimizations,
271		idle_info);
272}
273
274void dcn314_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
275{
276	union display_idle_optimization_u idle_info = { 0 };
277
278	if (!clk_mgr->smu_present)
279		return;
280
281	if (enable) {
282		idle_info.idle_info.df_request_disabled = 1;
283		idle_info.idle_info.phy_ref_clk_off = 1;
284	}
285
286	dcn314_smu_send_msg_with_param(
287			clk_mgr,
288			VBIOSSMC_MSG_SetDisplayIdleOptimizations,
289			idle_info.data);
290}
291
292void dcn314_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
293{
294	if (!clk_mgr->smu_present)
295		return;
296
297	dcn314_smu_send_msg_with_param(
298			clk_mgr,
299			VBIOSSMC_MSG_UpdatePmeRestore,
300			0);
301}
302
303void dcn314_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
304{
305	if (!clk_mgr->smu_present)
306		return;
307
308	dcn314_smu_send_msg_with_param(clk_mgr,
309			VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
310}
311
312void dcn314_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
313{
314	if (!clk_mgr->smu_present)
315		return;
316
317	dcn314_smu_send_msg_with_param(clk_mgr,
318			VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
319}
320
321void dcn314_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
322{
323	if (!clk_mgr->smu_present)
324		return;
325
326	dcn314_smu_send_msg_with_param(clk_mgr,
327			VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
328}
329
330void dcn314_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
331{
332	if (!clk_mgr->smu_present)
333		return;
334
335	dcn314_smu_send_msg_with_param(clk_mgr,
336			VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
337}
338
339void dcn314_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zstate_support_state support)
340{
341	unsigned int msg_id, param;
342
343	if (!clk_mgr->smu_present)
344		return;
345
346	switch (support) {
347
348	case DCN_ZSTATE_SUPPORT_ALLOW:
349		msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
350		param = (1 << 10) | (1 << 9) | (1 << 8);
351		break;
352
353	case DCN_ZSTATE_SUPPORT_DISALLOW:
354		msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
355		param = 0;
356		break;
357
358
359	case DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY:
360		msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
361		param = (1 << 10);
362		break;
363
364	case DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY:
365		msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
366		param = (1 << 10) | (1 << 8);
367		break;
368
369	case DCN_ZSTATE_SUPPORT_ALLOW_Z8_ONLY:
370		msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
371		param = (1 << 8);
372		break;
373
374	default: //DCN_ZSTATE_SUPPORT_UNKNOWN
375		msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
376		param = 0;
377		break;
378	}
379
380
381	dcn314_smu_send_msg_with_param(
382		clk_mgr,
383		msg_id,
384		param);
385
386}
387
388/* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */
389void dcn314_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
390{
391	if (!clk_mgr->smu_present)
392		return;
393
394	dcn314_smu_send_msg_with_param(
395			clk_mgr,
396			VBIOSSMC_MSG_SetDtbClk,
397			enable);
398}
~/ Read-only file preview.