File Index
Files and directories
Sign in
FILE

dmub_replay.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c C
  1// SPDX-License-Identifier: MIT
  2//
  3// Copyright 2024 Advanced Micro Devices, Inc.
  4
  5#include "dc.h"
  6#include "link_service.h"
  7#include "dc_dmub_srv.h"
  8#include "dmub/dmub_srv.h"
  9#include "core_types.h"
 10#include "dmub_replay.h"
 11
 12#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */
 13
 14#define MAX_PIPES 6
 15
 16#define GPINT_RETRY_NUM 20
 17
 18static const uint8_t DP_SINK_DEVICE_STR_ID_1[] = {7, 1, 8, 7, 3};
 19static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5};
 20
 21/*
 22 * Get Replay state from firmware.
 23 */
 24static void dmub_replay_get_state(struct dmub_replay *dmub, enum replay_state *state, uint8_t panel_inst)
 25{
 26	uint32_t retry_count = 0;
 27
 28	do {
 29		// Send gpint command and wait for ack
 30		if (!dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__GET_REPLAY_STATE, panel_inst,
 31					       (uint32_t *)state, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) {
 32			// Return invalid state when GPINT times out
 33			*state = REPLAY_STATE_INVALID;
 34		}
 35	} while (++retry_count <= 1000 && *state == REPLAY_STATE_INVALID);
 36
 37	// Assert if max retry hit
 38	if (retry_count >= 1000 && *state == REPLAY_STATE_INVALID) {
 39		ASSERT(0);
 40		/* To-do: Add retry fail log */
 41	}
 42}
 43
 44/*
 45 * Enable/Disable Replay.
 46 */
 47static void dmub_replay_enable(struct dmub_replay *dmub, bool enable, bool wait, uint8_t panel_inst)
 48{
 49	union dmub_rb_cmd cmd;
 50	struct dc_context *dc = dmub->ctx;
 51	uint32_t retry_count;
 52	enum replay_state state = REPLAY_STATE_0;
 53
 54	memset(&cmd, 0, sizeof(cmd));
 55	cmd.replay_enable.header.type = DMUB_CMD__REPLAY;
 56	cmd.replay_enable.data.panel_inst = panel_inst;
 57
 58	cmd.replay_enable.header.sub_type = DMUB_CMD__REPLAY_ENABLE;
 59	if (enable)
 60		cmd.replay_enable.data.enable = REPLAY_ENABLE;
 61	else
 62		cmd.replay_enable.data.enable = REPLAY_DISABLE;
 63
 64	cmd.replay_enable.header.payload_bytes = sizeof(struct dmub_rb_cmd_replay_enable_data);
 65
 66	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
 67
 68	/* Below loops 1000 x 500us = 500 ms.
 69	 *  Exit REPLAY may need to wait 1-2 frames to power up. Timeout after at
 70	 *  least a few frames. Should never hit the max retry assert below.
 71	 */
 72	if (wait) {
 73		for (retry_count = 0; retry_count <= 1000; retry_count++) {
 74			dmub_replay_get_state(dmub, &state, panel_inst);
 75
 76			if (enable) {
 77				if (state != REPLAY_STATE_0)
 78					break;
 79			} else {
 80				if (state == REPLAY_STATE_0)
 81					break;
 82			}
 83
 84			/* must *not* be fsleep - this can be called from high irq levels */
 85			udelay(500);
 86		}
 87
 88		/* assert if max retry hit */
 89		if (retry_count >= 1000)
 90			ASSERT(0);
 91	}
 92}
 93
 94/*
 95 * Set REPLAY power optimization flags.
 96 */
 97static void dmub_replay_set_power_opt(struct dmub_replay *dmub, unsigned int power_opt, uint8_t panel_inst)
 98{
 99	union dmub_rb_cmd cmd;
100	struct dc_context *dc = dmub->ctx;
101
102	memset(&cmd, 0, sizeof(cmd));
103	cmd.replay_set_power_opt.header.type = DMUB_CMD__REPLAY;
104	cmd.replay_set_power_opt.header.sub_type = DMUB_CMD__SET_REPLAY_POWER_OPT;
105	cmd.replay_set_power_opt.header.payload_bytes = sizeof(struct dmub_cmd_replay_set_power_opt_data);
106	cmd.replay_set_power_opt.replay_set_power_opt_data.power_opt = power_opt;
107	cmd.replay_set_power_opt.replay_set_power_opt_data.panel_inst = panel_inst;
108
109	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
110}
111
112/*
113 * Setup Replay by programming phy registers and sending replay hw context values to firmware.
114 */
115static bool dmub_replay_copy_settings(struct dmub_replay *dmub,
116	struct dc_link *link,
117	struct replay_context *replay_context,
118	uint8_t panel_inst)
119{
120	union dmub_rb_cmd cmd;
121	struct dc_context *dc = dmub->ctx;
122	struct dmub_cmd_replay_copy_settings_data *copy_settings_data
123		= &cmd.replay_copy_settings.replay_copy_settings_data;
124	struct pipe_ctx *pipe_ctx = NULL;
125	struct resource_context *res_ctx = &link->ctx->dc->current_state->res_ctx;
126	int i = 0;
127
128	for (i = 0; i < MAX_PIPES; i++) {
129		if (res_ctx &&
130			res_ctx->pipe_ctx[i].stream &&
131			res_ctx->pipe_ctx[i].stream->link &&
132			res_ctx->pipe_ctx[i].stream->link == link &&
133			res_ctx->pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) {
134			pipe_ctx = &res_ctx->pipe_ctx[i];
135			//TODO: refactor for multi edp support
136			break;
137		}
138	}
139
140	if (!pipe_ctx)
141		return false;
142
143	memset(&cmd, 0, sizeof(cmd));
144	cmd.replay_copy_settings.header.type = DMUB_CMD__REPLAY;
145	cmd.replay_copy_settings.header.sub_type = DMUB_CMD__REPLAY_COPY_SETTINGS;
146	cmd.replay_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_replay_copy_settings_data);
147
148	// HW insts
149	copy_settings_data->aux_inst				= replay_context->aux_inst;
150	copy_settings_data->digbe_inst				= replay_context->digbe_inst;
151	copy_settings_data->digfe_inst				= replay_context->digfe_inst;
152
153	if (pipe_ctx->plane_res.dpp)
154		copy_settings_data->dpp_inst			= pipe_ctx->plane_res.dpp->inst;
155	else
156		copy_settings_data->dpp_inst			= 0;
157	if (pipe_ctx->stream_res.tg)
158		copy_settings_data->otg_inst			= pipe_ctx->stream_res.tg->inst;
159	else
160		copy_settings_data->otg_inst			= 0;
161
162	copy_settings_data->dpphy_inst				= link->link_enc->transmitter;
163
164	// Misc
165	copy_settings_data->line_time_in_ns			= replay_context->line_time_in_ns;
166	copy_settings_data->panel_inst				= panel_inst;
167	copy_settings_data->debug.u32All			= link->replay_settings.config.debug_flags;
168	copy_settings_data->pixel_deviation_per_line		= link->dpcd_caps.pr_info.pixel_deviation_per_line;
169	copy_settings_data->max_deviation_line			= link->dpcd_caps.pr_info.max_deviation_line;
170	copy_settings_data->smu_optimizations_en		= link->replay_settings.replay_smu_opt_enable;
171	copy_settings_data->replay_timing_sync_supported = link->replay_settings.config.replay_timing_sync_supported;
172	copy_settings_data->replay_support_fast_resync_in_ultra_sleep_mode = link->replay_settings.config.replay_support_fast_resync_in_ultra_sleep_mode;
173
174	copy_settings_data->debug.bitfields.enable_ips_visual_confirm = dc->dc->debug.enable_ips_visual_confirm;
175
176	copy_settings_data->flags.u32All = 0;
177	copy_settings_data->flags.bitfields.fec_enable_status = (link->fec_state == dc_link_fec_enabled);
178	copy_settings_data->flags.bitfields.dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1);
179	// WA for PSRSU+DSC on specific TCON, if DSC is enabled, force PSRSU as ffu mode(full frame update)
180	if (((link->dpcd_caps.fec_cap.bits.FEC_CAPABLE &&
181		!link->dc->debug.disable_fec) &&
182		(link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT &&
183		!link->panel_config.dsc.disable_dsc_edp &&
184		link->dc->caps.edp_dsc_support)) &&
185		link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 &&
186		(!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1,
187			sizeof(DP_SINK_DEVICE_STR_ID_1)) ||
188		!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_2,
189			sizeof(DP_SINK_DEVICE_STR_ID_2))))
190		copy_settings_data->flags.bitfields.force_wakeup_by_tps3 = 1;
191	else
192		copy_settings_data->flags.bitfields.force_wakeup_by_tps3 = 0;
193
194	copy_settings_data->flags.bitfields.alpm_mode = (enum dmub_alpm_mode)link->replay_settings.config.alpm_mode;
195	if (link->replay_settings.config.alpm_mode == DC_ALPM_AUXLESS) {
196		copy_settings_data->auxless_alpm_data.lfps_setup_ns = dc->dc->debug.auxless_alpm_lfps_setup_ns;
197		copy_settings_data->auxless_alpm_data.lfps_period_ns = dc->dc->debug.auxless_alpm_lfps_period_ns;
198		copy_settings_data->auxless_alpm_data.lfps_silence_ns = dc->dc->debug.auxless_alpm_lfps_silence_ns;
199		copy_settings_data->auxless_alpm_data.lfps_t1_t2_override_us =
200			dc->dc->debug.auxless_alpm_lfps_t1t2_us;
201		copy_settings_data->auxless_alpm_data.lfps_t1_t2_offset_us =
202			dc->dc->debug.auxless_alpm_lfps_t1t2_offset_us;
203		copy_settings_data->auxless_alpm_data.lttpr_count = link->dc->link_srv->dp_get_lttpr_count(link);
204	}
205
206	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
207
208	return true;
209}
210
211/*
212 * Set coasting vtotal.
213 */
214static void dmub_replay_set_coasting_vtotal(struct dmub_replay *dmub,
215		uint32_t coasting_vtotal,
216		uint8_t panel_inst,
217		uint16_t frame_skip_number)
218{
219	union dmub_rb_cmd cmd;
220	struct dc_context *dc = dmub->ctx;
221	struct dmub_rb_cmd_replay_set_coasting_vtotal *pCmd = NULL;
222
223	pCmd = &(cmd.replay_set_coasting_vtotal);
224
225	memset(&cmd, 0, sizeof(cmd));
226	pCmd->header.type = DMUB_CMD__REPLAY;
227	pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_COASTING_VTOTAL;
228	pCmd->header.payload_bytes = sizeof(struct dmub_cmd_replay_set_coasting_vtotal_data);
229	pCmd->replay_set_coasting_vtotal_data.coasting_vtotal = (coasting_vtotal & 0xFFFF);
230	pCmd->replay_set_coasting_vtotal_data.coasting_vtotal_high = (coasting_vtotal & 0xFFFF0000) >> 16;
231	pCmd->replay_set_coasting_vtotal_data.frame_skip_number = frame_skip_number;
232
233	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
234}
235
236/*
237 * Get Replay residency from firmware.
238 */
239static void dmub_replay_residency(struct dmub_replay *dmub, uint8_t panel_inst,
240	uint32_t *residency, const bool is_start, enum pr_residency_mode mode)
241{
242	uint16_t param = (uint16_t)(panel_inst << 8);
243	uint32_t i = 0;
244
245	switch (mode) {
246	case PR_RESIDENCY_MODE_PHY:
247		param |= REPLAY_RESIDENCY_FIELD_MODE_PHY;
248		break;
249	case PR_RESIDENCY_MODE_ALPM:
250		param |= REPLAY_RESIDENCY_FIELD_MODE_ALPM;
251		break;
252	case PR_RESIDENCY_MODE_IPS2:
253		param |= REPLAY_RESIDENCY_REVISION_1;
254		param |= REPLAY_RESIDENCY_FIELD_MODE2_IPS;
255		break;
256	case PR_RESIDENCY_MODE_FRAME_CNT:
257		param |= REPLAY_RESIDENCY_REVISION_1;
258		param |= REPLAY_RESIDENCY_FIELD_MODE2_FRAME_CNT;
259		break;
260	case PR_RESIDENCY_MODE_ENABLEMENT_PERIOD:
261		param |= REPLAY_RESIDENCY_REVISION_1;
262		param |= REPLAY_RESIDENCY_FIELD_MODE2_EN_PERIOD;
263		break;
264	default:
265		break;
266	}
267
268	if (is_start)
269		param |= REPLAY_RESIDENCY_ENABLE;
270
271	for (i = 0; i < GPINT_RETRY_NUM; i++) {
272		// Send gpint command and wait for ack
273		if (dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__REPLAY_RESIDENCY, param,
274			residency, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
275			return;
276
277		udelay(100);
278	}
279
280	// it means gpint retry many times
281	*residency = 0;
282}
283
284/*
285 * Set REPLAY power optimization flags and coasting vtotal.
286 */
287static void dmub_replay_set_power_opt_and_coasting_vtotal(struct dmub_replay *dmub,
288		unsigned int power_opt, uint8_t panel_inst, uint32_t coasting_vtotal, uint16_t frame_skip_number)
289{
290	union dmub_rb_cmd cmd;
291	struct dc_context *dc = dmub->ctx;
292	struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal *pCmd = NULL;
293
294	pCmd = &(cmd.replay_set_power_opt_and_coasting_vtotal);
295
296	memset(&cmd, 0, sizeof(cmd));
297	pCmd->header.type = DMUB_CMD__REPLAY;
298	pCmd->header.sub_type = DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL;
299	pCmd->header.payload_bytes =
300			sizeof(struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal) -
301			sizeof(struct dmub_cmd_header);
302	pCmd->replay_set_power_opt_data.power_opt = power_opt;
303	pCmd->replay_set_power_opt_data.panel_inst = panel_inst;
304	pCmd->replay_set_coasting_vtotal_data.coasting_vtotal = (coasting_vtotal & 0xFFFF);
305	pCmd->replay_set_coasting_vtotal_data.coasting_vtotal_high = (coasting_vtotal & 0xFFFF0000) >> 16;
306	pCmd->replay_set_coasting_vtotal_data.frame_skip_number = frame_skip_number;
307
308	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
309}
310
311/*
312 * send Replay general cmd to DMUB.
313 */
314static void dmub_replay_send_cmd(struct dmub_replay *dmub,
315		enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_element)
316{
317	union dmub_rb_cmd cmd;
318	struct dc_context *ctx = NULL;
319
320	if (dmub == NULL || cmd_element == NULL)
321		return;
322
323	ctx = dmub->ctx;
324	if (ctx != NULL) {
325
326		if (msg != Replay_Msg_Not_Support) {
327			memset(&cmd, 0, sizeof(cmd));
328			//Header
329			cmd.replay_set_timing_sync.header.type = DMUB_CMD__REPLAY;
330		} else
331			return;
332	} else
333		return;
334
335	switch (msg) {
336	case Replay_Set_Timing_Sync_Supported:
337		//Header
338		cmd.replay_set_timing_sync.header.sub_type =
339			DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED;
340		cmd.replay_set_timing_sync.header.payload_bytes =
341			sizeof(struct dmub_rb_cmd_replay_set_timing_sync) -
342			sizeof(struct dmub_cmd_header);
343		//Cmd Body
344		cmd.replay_set_timing_sync.replay_set_timing_sync_data.panel_inst =
345						cmd_element->sync_data.panel_inst;
346		cmd.replay_set_timing_sync.replay_set_timing_sync_data.timing_sync_supported =
347						cmd_element->sync_data.timing_sync_supported;
348		break;
349	case Replay_Set_Residency_Frameupdate_Timer:
350		//Header
351		cmd.replay_set_frameupdate_timer.header.sub_type =
352			DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER;
353		cmd.replay_set_frameupdate_timer.header.payload_bytes =
354			sizeof(struct dmub_rb_cmd_replay_set_frameupdate_timer) -
355			sizeof(struct dmub_cmd_header);
356		//Cmd Body
357		cmd.replay_set_frameupdate_timer.data.panel_inst =
358						cmd_element->panel_inst;
359		cmd.replay_set_frameupdate_timer.data.enable =
360						cmd_element->timer_data.enable;
361		cmd.replay_set_frameupdate_timer.data.frameupdate_count =
362						cmd_element->timer_data.frameupdate_count;
363		break;
364	case Replay_Set_Pseudo_VTotal:
365		//Header
366		cmd.replay_set_pseudo_vtotal.header.sub_type =
367			DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL;
368		cmd.replay_set_pseudo_vtotal.header.payload_bytes =
369			sizeof(struct dmub_rb_cmd_replay_set_pseudo_vtotal) -
370			sizeof(struct dmub_cmd_header);
371		//Cmd Body
372		cmd.replay_set_pseudo_vtotal.data.panel_inst =
373			cmd_element->pseudo_vtotal_data.panel_inst;
374		cmd.replay_set_pseudo_vtotal.data.vtotal =
375			cmd_element->pseudo_vtotal_data.vtotal;
376		break;
377	case Replay_Disabled_Adaptive_Sync_SDP:
378		//Header
379		cmd.replay_disabled_adaptive_sync_sdp.header.sub_type =
380			DMUB_CMD__REPLAY_DISABLED_ADAPTIVE_SYNC_SDP;
381		cmd.replay_disabled_adaptive_sync_sdp.header.payload_bytes =
382			sizeof(struct dmub_rb_cmd_replay_disabled_adaptive_sync_sdp) -
383			sizeof(struct dmub_cmd_header);
384		//Cmd Body
385		cmd.replay_disabled_adaptive_sync_sdp.data.panel_inst =
386			cmd_element->disabled_adaptive_sync_sdp_data.panel_inst;
387		cmd.replay_disabled_adaptive_sync_sdp.data.force_disabled =
388			cmd_element->disabled_adaptive_sync_sdp_data.force_disabled;
389		break;
390	case Replay_Set_Version:
391		//Header
392		cmd.replay_set_version.header.sub_type =
393			DMUB_CMD__REPLAY_SET_VERSION;
394		cmd.replay_set_version.header.payload_bytes =
395			sizeof(struct dmub_rb_cmd_replay_set_version) -
396			sizeof(struct dmub_cmd_header);
397		//Cmd Body
398		cmd.replay_set_version.replay_set_version_data.panel_inst =
399			cmd_element->version_data.panel_inst;
400		cmd.replay_set_version.replay_set_version_data.version =
401			cmd_element->version_data.version;
402		break;
403	case Replay_Set_General_Cmd:
404		//Header
405		cmd.replay_set_general_cmd.header.sub_type =
406			DMUB_CMD__REPLAY_SET_GENERAL_CMD;
407		cmd.replay_set_general_cmd.header.payload_bytes =
408			sizeof(struct dmub_rb_cmd_replay_set_general_cmd) -
409			sizeof(struct dmub_cmd_header);
410		//Cmd Body
411		cmd.replay_set_general_cmd.data.panel_inst =
412			cmd_element->set_general_cmd_data.panel_inst;
413		cmd.replay_set_general_cmd.data.subtype =
414			cmd_element->set_general_cmd_data.subtype;
415		cmd.replay_set_general_cmd.data.param1 =
416			cmd_element->set_general_cmd_data.param1;
417		cmd.replay_set_general_cmd.data.param2 =
418			cmd_element->set_general_cmd_data.param2;
419		break;
420	case Replay_Msg_Not_Support:
421	default:
422		return;
423		break;
424	}
425
426	dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
427}
428
429static const struct dmub_replay_funcs replay_funcs = {
430	.replay_copy_settings				= dmub_replay_copy_settings,
431	.replay_enable					= dmub_replay_enable,
432	.replay_get_state				= dmub_replay_get_state,
433	.replay_set_power_opt				= dmub_replay_set_power_opt,
434	.replay_set_coasting_vtotal			= dmub_replay_set_coasting_vtotal,
435	.replay_residency				= dmub_replay_residency,
436	.replay_set_power_opt_and_coasting_vtotal	= dmub_replay_set_power_opt_and_coasting_vtotal,
437	.replay_send_cmd				= dmub_replay_send_cmd,
438};
439
440/*
441 * Construct Replay object.
442 */
443static void dmub_replay_construct(struct dmub_replay *replay, struct dc_context *ctx)
444{
445	replay->ctx = ctx;
446	replay->funcs = &replay_funcs;
447}
448
449/*
450 * Allocate and initialize Replay object.
451 */
452struct dmub_replay *dmub_replay_create(struct dc_context *ctx)
453{
454	struct dmub_replay *replay = kzalloc(sizeof(struct dmub_replay), GFP_KERNEL);
455
456	if (replay == NULL) {
457		BREAK_TO_DEBUGGER();
458		return NULL;
459	}
460
461	dmub_replay_construct(replay, ctx);
462
463	return replay;
464}
465
466/*
467 * Deallocate Replay object.
468 */
469void dmub_replay_destroy(struct dmub_replay **dmub)
470{
471	kfree(*dmub);
472	*dmub = NULL;
473}
~/ Read-only file preview.