brintos

brintos / linux-shallow public Read only

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