File Index
Files and directories
Sign in
FILE

dcn315_smu.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c C
  1/*
  2 * Copyright 2021 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 "dcn315_smu.h"
 31#include "mp/mp_13_0_5_offset.h"
 32#include "logger_types.h"
 33
 34#define MAX_INSTANCE                                        6
 35#define MAX_SEGMENT                                         6
 36#define SMU_REGISTER_WRITE_RETRY_COUNT                      5
 37
 38struct IP_BASE_INSTANCE {
 39    unsigned int segment[MAX_SEGMENT];
 40};
 41
 42struct IP_BASE {
 43    struct IP_BASE_INSTANCE instance[MAX_INSTANCE];
 44};
 45
 46static const struct IP_BASE MP0_BASE = { { { { 0x00016000, 0x00DC0000, 0x00E00000, 0x00E40000, 0x0243FC00, 0 } },
 47					{ { 0, 0, 0, 0, 0, 0 } },
 48					{ { 0, 0, 0, 0, 0, 0 } },
 49					{ { 0, 0, 0, 0, 0, 0 } },
 50					{ { 0, 0, 0, 0, 0, 0 } },
 51					{ { 0, 0, 0, 0, 0, 0 } } } };
 52
 53#define CTX clk_mgr->base.ctx
 54#define IND_REG(offset)	offset
 55
 56#define regBIF_BX_PF2_RSMU_INDEX                                                                        0x0000
 57#define regBIF_BX_PF2_RSMU_INDEX_BASE_IDX                                                               1
 58#define regBIF_BX_PF2_RSMU_DATA                                                                         0x0001
 59#define regBIF_BX_PF2_RSMU_DATA_BASE_IDX                                                                1
 60
 61#define REG(reg_name) \
 62	(MP0_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
 63
 64#define FN(reg_name, field) \
 65	FD(reg_name##__##field)
 66
 67#undef DC_LOGGER
 68#define DC_LOGGER \
 69	CTX->logger
 70#define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
 71
 72#define mmMP1_C2PMSG_3                            0x3B1050C
 73
 74#define reg__MP1_C2PMSG_3_MASK					(0xFFFFFFFF)
 75#define reg__MP1_C2PMSG_3__SHIFT					(0)
 76
 77
 78#define data_reg_name__MP1_C2PMSG_3_MASK		(0xFFFFFFFF)
 79#define data_reg_name__MP1_C2PMSG_3__SHIFT		(0)
 80
 81#define VBIOSSMC_MSG_TestMessage                  0x01 ///< To check if PMFW is alive and responding. Requirement specified by PMFW team
 82#define VBIOSSMC_MSG_GetPmfwVersion               0x02 ///< Get PMFW version
 83#define VBIOSSMC_MSG_Spare0                       0x03 ///< Spare0
 84#define VBIOSSMC_MSG_SetDispclkFreq               0x04 ///< Set display clock frequency in MHZ
 85#define VBIOSSMC_MSG_Spare1                       0x05 ///< Spare1
 86#define VBIOSSMC_MSG_SetDppclkFreq                0x06 ///< Set DPP clock frequency in MHZ
 87#define VBIOSSMC_MSG_SetHardMinDcfclkByFreq       0x07 ///< Set DCF clock frequency hard min in MHZ
 88#define VBIOSSMC_MSG_SetMinDeepSleepDcfclk        0x08 ///< Set DCF clock minimum frequency in deep sleep in MHZ
 89#define VBIOSSMC_MSG_GetDtbclkFreq                0x09 ///< Get display dtb clock frequency in MHZ in case VMIN does not support phy frequency
 90#define VBIOSSMC_MSG_SetDtbClk                    0x0A ///< Set dtb clock frequency, return frequemcy in MHZ
 91#define VBIOSSMC_MSG_SetDisplayCount              0x0B ///< Inform PMFW of number of display connected
 92#define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0x0C ///< To ask PMFW turn off TMDP 48MHz refclk during display off to save power
 93#define VBIOSSMC_MSG_UpdatePmeRestore             0x0D ///< To ask PMFW to write into Azalia for PME wake up event
 94#define VBIOSSMC_MSG_SetVbiosDramAddrHigh         0x0E ///< Set DRAM address high 32 bits for WM table transfer
 95#define VBIOSSMC_MSG_SetVbiosDramAddrLow          0x0F ///< Set DRAM address low 32 bits for WM table transfer
 96#define VBIOSSMC_MSG_TransferTableSmu2Dram        0x10 ///< Transfer table from PMFW SRAM to system DRAM
 97#define VBIOSSMC_MSG_TransferTableDram2Smu        0x11 ///< Transfer table from system DRAM to PMFW
 98#define VBIOSSMC_MSG_SetDisplayIdleOptimizations  0x12 ///< Set Idle state optimization for display off
 99#define VBIOSSMC_MSG_GetDprefclkFreq              0x13 ///< Get DPREF clock frequency. Return in MHZ
100#define VBIOSSMC_Message_Count                    0x14 ///< Total number of VBIS and DAL messages
101
102#define VBIOSSMC_Status_BUSY                      0x0
103#define VBIOSSMC_Result_OK                        0x01 ///< Message Response OK
104#define VBIOSSMC_Result_Failed                    0xFF ///< Message Response Failed
105#define VBIOSSMC_Result_UnknownCmd                0xFE ///< Message Response Unknown Command
106#define VBIOSSMC_Result_CmdRejectedPrereq         0xFD ///< Message Response Command Failed Prerequisite
107#define VBIOSSMC_Result_CmdRejectedBusy           0xFC ///< Message Response Command Rejected due to PMFW is busy. Sender should retry sending this message
108
109/*
110 * Function to be used instead of REG_WAIT macro because the wait ends when
111 * the register is NOT EQUAL to zero, and because the translation in msg_if.h
112 * won't work with REG_WAIT.
113 */
114static uint32_t dcn315_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
115{
116	uint32_t res_val = VBIOSSMC_Status_BUSY;
117
118	do {
119		res_val = REG_READ(MP1_SMN_C2PMSG_38);
120		if (res_val != VBIOSSMC_Status_BUSY)
121			break;
122
123		if (delay_us >= 1000)
124			msleep(delay_us/1000);
125		else if (delay_us > 0)
126			udelay(delay_us);
127	} while (max_retries--);
128
129	return res_val;
130}
131
132static int dcn315_smu_send_msg_with_param(
133		struct clk_mgr_internal *clk_mgr,
134		unsigned int msg_id, unsigned int param)
135{
136	uint32_t result;
137	uint32_t i = 0;
138	uint32_t read_back_data;
139
140	result = dcn315_smu_wait_for_response(clk_mgr, 10, 200000);
141
142	if (result != VBIOSSMC_Result_OK)
143		smu_print("SMU Response was not OK. SMU response after wait received is: %d\n", result);
144
145	if (result == VBIOSSMC_Status_BUSY) {
146		return -1;
147	}
148
149	/* First clear response register */
150	REG_WRITE(MP1_SMN_C2PMSG_38, VBIOSSMC_Status_BUSY);
151
152	/* Set the parameter register for the SMU message, unit is Mhz */
153	REG_WRITE(MP1_SMN_C2PMSG_37, param);
154
155	for (i = 0; i < SMU_REGISTER_WRITE_RETRY_COUNT; i++) {
156		/* Trigger the message transaction by writing the message ID */
157		IX_REG_SET_SYNC(mmMP1_C2PMSG_3, 0,
158			MP1_C2PMSG_3, msg_id);
159		IX_REG_GET_SYNC(mmMP1_C2PMSG_3,
160			MP1_C2PMSG_3, &read_back_data);
161		if (read_back_data == msg_id)
162			break;
163		udelay(2);
164		smu_print("SMU msg id write fail %x times. \n", i + 1);
165	}
166
167	result = dcn315_smu_wait_for_response(clk_mgr, 10, 200000);
168
169	if (result == VBIOSSMC_Status_BUSY) {
170		ASSERT(0);
171		dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
172	}
173
174	return REG_READ(MP1_SMN_C2PMSG_37);
175}
176
177int dcn315_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
178{
179	return dcn315_smu_send_msg_with_param(
180			clk_mgr,
181			VBIOSSMC_MSG_GetPmfwVersion,
182			0);
183}
184
185
186int dcn315_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
187{
188	int actual_dispclk_set_mhz = -1;
189
190	if (!clk_mgr->smu_present)
191		return requested_dispclk_khz;
192
193	/*  Unit of SMU msg parameter is Mhz */
194	actual_dispclk_set_mhz = dcn315_smu_send_msg_with_param(
195			clk_mgr,
196			VBIOSSMC_MSG_SetDispclkFreq,
197			khz_to_mhz_ceil(requested_dispclk_khz));
198
199	return actual_dispclk_set_mhz * 1000;
200}
201
202int dcn315_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
203{
204	int actual_dcfclk_set_mhz = -1;
205
206	if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
207		return -1;
208
209	if (!clk_mgr->smu_present)
210		return requested_dcfclk_khz;
211
212	actual_dcfclk_set_mhz = dcn315_smu_send_msg_with_param(
213			clk_mgr,
214			VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
215			khz_to_mhz_ceil(requested_dcfclk_khz));
216
217	return actual_dcfclk_set_mhz * 1000;
218}
219
220int dcn315_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
221{
222	int actual_min_ds_dcfclk_mhz = -1;
223
224	if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
225		return -1;
226
227	if (!clk_mgr->smu_present)
228		return requested_min_ds_dcfclk_khz;
229
230	actual_min_ds_dcfclk_mhz = dcn315_smu_send_msg_with_param(
231			clk_mgr,
232			VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
233			khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
234
235	return actual_min_ds_dcfclk_mhz * 1000;
236}
237
238int dcn315_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
239{
240	int actual_dppclk_set_mhz = -1;
241
242	if (!clk_mgr->smu_present)
243		return requested_dpp_khz;
244
245	actual_dppclk_set_mhz = dcn315_smu_send_msg_with_param(
246			clk_mgr,
247			VBIOSSMC_MSG_SetDppclkFreq,
248			khz_to_mhz_ceil(requested_dpp_khz));
249
250	return actual_dppclk_set_mhz * 1000;
251}
252
253void dcn315_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
254{
255	if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
256		return;
257
258	if (!clk_mgr->smu_present)
259		return;
260
261	//TODO: Work with smu team to define optimization options.
262	dcn315_smu_send_msg_with_param(
263		clk_mgr,
264		VBIOSSMC_MSG_SetDisplayIdleOptimizations,
265		idle_info);
266}
267
268void dcn315_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
269{
270	union display_idle_optimization_u idle_info = { 0 };
271
272	if (!clk_mgr->smu_present)
273		return;
274
275	if (enable) {
276		idle_info.idle_info.df_request_disabled = 1;
277		idle_info.idle_info.phy_ref_clk_off = 1;
278	}
279
280	dcn315_smu_send_msg_with_param(
281			clk_mgr,
282			VBIOSSMC_MSG_SetDisplayIdleOptimizations,
283			idle_info.data);
284}
285
286void dcn315_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
287{
288	if (!clk_mgr->smu_present)
289		return;
290
291	dcn315_smu_send_msg_with_param(
292			clk_mgr,
293			VBIOSSMC_MSG_UpdatePmeRestore,
294			0);
295}
296void dcn315_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
297{
298	if (!clk_mgr->smu_present)
299		return;
300
301	dcn315_smu_send_msg_with_param(clk_mgr,
302			VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
303}
304
305void dcn315_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
306{
307	if (!clk_mgr->smu_present)
308		return;
309
310	dcn315_smu_send_msg_with_param(clk_mgr,
311			VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
312}
313
314void dcn315_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
315{
316	if (!clk_mgr->smu_present)
317		return;
318
319	dcn315_smu_send_msg_with_param(clk_mgr,
320			VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
321}
322
323void dcn315_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
324{
325	if (!clk_mgr->smu_present)
326		return;
327
328	dcn315_smu_send_msg_with_param(clk_mgr,
329			VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
330}
331
332int dcn315_smu_get_dpref_clk(struct clk_mgr_internal *clk_mgr)
333{
334	int dprefclk_get_mhz = -1;
335	if (clk_mgr->smu_present) {
336		dprefclk_get_mhz = dcn315_smu_send_msg_with_param(
337			clk_mgr,
338			VBIOSSMC_MSG_GetDprefclkFreq,
339			0);
340	}
341	return (dprefclk_get_mhz * 1000);
342}
343
344int dcn315_smu_get_dtbclk(struct clk_mgr_internal *clk_mgr)
345{
346	int fclk_get_mhz = -1;
347
348	if (clk_mgr->smu_present) {
349		fclk_get_mhz = dcn315_smu_send_msg_with_param(
350			clk_mgr,
351			VBIOSSMC_MSG_GetDtbclkFreq,
352			0);
353	}
354	return (fclk_get_mhz * 1000);
355}
356
357void dcn315_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
358{
359	if (!clk_mgr->smu_present)
360		return;
361
362	dcn315_smu_send_msg_with_param(
363			clk_mgr,
364			VBIOSSMC_MSG_SetDtbClk,
365			enable);
366}
~/ Read-only file preview.