brintos

brintos / linux-shallow public Read only

0
0
Text · 16.7 KiB · cae18f8 Raw
508 lines · c
1/*2 * Copyright 2019 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: AMD23 *24 */25 26#include "dmub_psr.h"27#include "dc.h"28#include "dc_dmub_srv.h"29#include "dmub/dmub_srv.h"30#include "core_types.h"31 32#define DC_TRACE_LEVEL_MESSAGE(...)	do {} while (0) /* do nothing */33 34#define MAX_PIPES 635 36static const uint8_t DP_SINK_DEVICE_STR_ID_1[] = {7, 1, 8, 7, 3};37static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5};38static const uint8_t DP_SINK_DEVICE_STR_ID_3[] = {0x42, 0x61, 0x6c, 0x73, 0x61};39 40/*41 * Convert dmcub psr state to dmcu psr state.42 */43static enum dc_psr_state convert_psr_state(uint32_t raw_state)44{45	enum dc_psr_state state = PSR_STATE0;46 47	if (raw_state == 0)48		state = PSR_STATE0;49	else if (raw_state == 0x10)50		state = PSR_STATE1;51	else if (raw_state == 0x11)52		state = PSR_STATE1a;53	else if (raw_state == 0x20)54		state = PSR_STATE2;55	else if (raw_state == 0x21)56		state = PSR_STATE2a;57	else if (raw_state == 0x22)58		state = PSR_STATE2b;59	else if (raw_state == 0x30)60		state = PSR_STATE3;61	else if (raw_state == 0x31)62		state = PSR_STATE3Init;63	else if (raw_state == 0x40)64		state = PSR_STATE4;65	else if (raw_state == 0x41)66		state = PSR_STATE4a;67	else if (raw_state == 0x42)68		state = PSR_STATE4b;69	else if (raw_state == 0x43)70		state = PSR_STATE4c;71	else if (raw_state == 0x44)72		state = PSR_STATE4d;73	else if (raw_state == 0x50)74		state = PSR_STATE5;75	else if (raw_state == 0x51)76		state = PSR_STATE5a;77	else if (raw_state == 0x52)78		state = PSR_STATE5b;79	else if (raw_state == 0x53)80		state = PSR_STATE5c;81	else if (raw_state == 0x4A)82		state = PSR_STATE4_FULL_FRAME;83	else if (raw_state == 0x4B)84		state = PSR_STATE4a_FULL_FRAME;85	else if (raw_state == 0x4C)86		state = PSR_STATE4b_FULL_FRAME;87	else if (raw_state == 0x4D)88		state = PSR_STATE4c_FULL_FRAME;89	else if (raw_state == 0x4E)90		state = PSR_STATE4_FULL_FRAME_POWERUP;91	else if (raw_state == 0x4F)92		state = PSR_STATE4_FULL_FRAME_HW_LOCK;93	else if (raw_state == 0x60)94		state = PSR_STATE_HWLOCK_MGR;95	else if (raw_state == 0x61)96		state = PSR_STATE_POLLVUPDATE;97	else if (raw_state == 0x62)98		state = PSR_STATE_RELEASE_HWLOCK_MGR_FULL_FRAME;99	else100		state = PSR_STATE_INVALID;101 102	return state;103}104 105/*106 * Get PSR state from firmware.107 */108static void dmub_psr_get_state(struct dmub_psr *dmub, enum dc_psr_state *state, uint8_t panel_inst)109{110	uint32_t raw_state = 0;111	uint32_t retry_count = 0;112 113	do {114		// Send gpint command and wait for ack115		if (dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__GET_PSR_STATE, panel_inst, &raw_state,116					      DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) {117			*state = convert_psr_state(raw_state);118		} else {119			// Return invalid state when GPINT times out120			*state = PSR_STATE_INVALID;121		}122	} while (++retry_count <= 1000 && *state == PSR_STATE_INVALID);123 124	// Assert if max retry hit125	if (retry_count >= 1000 && *state == PSR_STATE_INVALID) {126		ASSERT(0);127		DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,128				WPP_BIT_FLAG_Firmware_PsrState,129				"Unable to get PSR state from FW.");130	} else131		DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_VERBOSE,132				WPP_BIT_FLAG_Firmware_PsrState,133				"Got PSR state from FW. PSR state: %d, Retry count: %d",134				*state, retry_count);135}136 137/*138 * Set PSR version.139 */140static bool dmub_psr_set_version(struct dmub_psr *dmub, struct dc_stream_state *stream, uint8_t panel_inst)141{142	union dmub_rb_cmd cmd;143	struct dc_context *dc = dmub->ctx;144 145	if (stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED)146		return false;147 148	memset(&cmd, 0, sizeof(cmd));149	cmd.psr_set_version.header.type = DMUB_CMD__PSR;150	cmd.psr_set_version.header.sub_type = DMUB_CMD__PSR_SET_VERSION;151	switch (stream->link->psr_settings.psr_version) {152	case DC_PSR_VERSION_1:153		cmd.psr_set_version.psr_set_version_data.version = PSR_VERSION_1;154		break;155	case DC_PSR_VERSION_SU_1:156		cmd.psr_set_version.psr_set_version_data.version = PSR_VERSION_SU_1;157		break;158	case DC_PSR_VERSION_UNSUPPORTED:159	default:160		cmd.psr_set_version.psr_set_version_data.version = PSR_VERSION_UNSUPPORTED;161		break;162	}163 164	if (cmd.psr_set_version.psr_set_version_data.version == PSR_VERSION_UNSUPPORTED)165		return false;166 167	cmd.psr_set_version.psr_set_version_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;168	cmd.psr_set_version.psr_set_version_data.panel_inst = panel_inst;169	cmd.psr_set_version.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_version_data);170 171	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);172 173	return true;174}175 176/*177 * Enable/Disable PSR.178 */179static void dmub_psr_enable(struct dmub_psr *dmub, bool enable, bool wait, uint8_t panel_inst)180{181	union dmub_rb_cmd cmd;182	struct dc_context *dc = dmub->ctx;183	uint32_t retry_count;184	enum dc_psr_state state = PSR_STATE0;185 186	memset(&cmd, 0, sizeof(cmd));187	cmd.psr_enable.header.type = DMUB_CMD__PSR;188 189	cmd.psr_enable.data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;190	cmd.psr_enable.data.panel_inst = panel_inst;191 192	if (enable)193		cmd.psr_enable.header.sub_type = DMUB_CMD__PSR_ENABLE;194	else195		cmd.psr_enable.header.sub_type = DMUB_CMD__PSR_DISABLE;196 197	cmd.psr_enable.header.payload_bytes = 0; // Send header only198 199	dc_wake_and_execute_dmub_cmd(dc->dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);200 201	/* Below loops 1000 x 500us = 500 ms.202	 *  Exit PSR may need to wait 1-2 frames to power up. Timeout after at203	 *  least a few frames. Should never hit the max retry assert below.204	 */205	if (wait) {206		for (retry_count = 0; retry_count <= 1000; retry_count++) {207			dmub_psr_get_state(dmub, &state, panel_inst);208 209			if (enable) {210				if (state != PSR_STATE0)211					break;212			} else {213				if (state == PSR_STATE0)214					break;215			}216 217			/* must *not* be fsleep - this can be called from high irq levels */218			udelay(500);219		}220 221		/* assert if max retry hit */222		if (retry_count >= 1000)223			ASSERT(0);224	}225}226 227/*228 * Set PSR level.229 */230static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level, uint8_t panel_inst)231{232	union dmub_rb_cmd cmd;233	enum dc_psr_state state = PSR_STATE0;234	struct dc_context *dc = dmub->ctx;235 236	dmub_psr_get_state(dmub, &state, panel_inst);237 238	if (state == PSR_STATE0)239		return;240 241	memset(&cmd, 0, sizeof(cmd));242	cmd.psr_set_level.header.type = DMUB_CMD__PSR;243	cmd.psr_set_level.header.sub_type = DMUB_CMD__PSR_SET_LEVEL;244	cmd.psr_set_level.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_level_data);245	cmd.psr_set_level.psr_set_level_data.psr_level = psr_level;246	cmd.psr_set_level.psr_set_level_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;247	cmd.psr_set_level.psr_set_level_data.panel_inst = panel_inst;248	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);249}250 251/*252 * Set PSR vtotal requirement for FreeSync PSR.253 */254static void dmub_psr_set_sink_vtotal_in_psr_active(struct dmub_psr *dmub,255		uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su)256{257	union dmub_rb_cmd cmd;258	struct dc_context *dc = dmub->ctx;259 260	memset(&cmd, 0, sizeof(cmd));261	cmd.psr_set_vtotal.header.type = DMUB_CMD__PSR;262	cmd.psr_set_vtotal.header.sub_type = DMUB_CMD__SET_SINK_VTOTAL_IN_PSR_ACTIVE;263	cmd.psr_set_vtotal.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_vtotal_data);264	cmd.psr_set_vtotal.psr_set_vtotal_data.psr_vtotal_idle = psr_vtotal_idle;265	cmd.psr_set_vtotal.psr_set_vtotal_data.psr_vtotal_su = psr_vtotal_su;266 267	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);268}269 270/*271 * Set PSR power optimization flags.272 */273static void dmub_psr_set_power_opt(struct dmub_psr *dmub, unsigned int power_opt, uint8_t panel_inst)274{275	union dmub_rb_cmd cmd;276	struct dc_context *dc = dmub->ctx;277 278	memset(&cmd, 0, sizeof(cmd));279	cmd.psr_set_power_opt.header.type = DMUB_CMD__PSR;280	cmd.psr_set_power_opt.header.sub_type = DMUB_CMD__SET_PSR_POWER_OPT;281	cmd.psr_set_power_opt.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_power_opt_data);282	cmd.psr_set_power_opt.psr_set_power_opt_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;283	cmd.psr_set_power_opt.psr_set_power_opt_data.power_opt = power_opt;284	cmd.psr_set_power_opt.psr_set_power_opt_data.panel_inst = panel_inst;285 286	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);287}288 289/*290 * Setup PSR by programming phy registers and sending psr hw context values to firmware.291 */292static bool dmub_psr_copy_settings(struct dmub_psr *dmub,293		struct dc_link *link,294		struct psr_context *psr_context,295		uint8_t panel_inst)296{297	union dmub_rb_cmd cmd = { 0 };298	struct dc_context *dc = dmub->ctx;299	struct dmub_cmd_psr_copy_settings_data *copy_settings_data300		= &cmd.psr_copy_settings.psr_copy_settings_data;301	struct pipe_ctx *pipe_ctx = NULL;302	struct resource_context *res_ctx = &link->ctx->dc->current_state->res_ctx;303	int i = 0;304 305	for (i = 0; i < MAX_PIPES; i++) {306		if (res_ctx->pipe_ctx[i].stream &&307		    res_ctx->pipe_ctx[i].stream->link == link &&308		    res_ctx->pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) {309			pipe_ctx = &res_ctx->pipe_ctx[i];310			//TODO: refactor for multi edp support311			break;312		}313	}314 315	if (!pipe_ctx)316		return false;317 318	// First, set the psr version319	if (!dmub_psr_set_version(dmub, pipe_ctx->stream, panel_inst))320		return false;321 322	// Program DP DPHY fast training registers323	link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc,324			psr_context->psrExitLinkTrainingRequired);325 326	// Program DP_SEC_CNTL1 register to set transmission GPS0 line num and priority to high327	link->link_enc->funcs->psr_program_secondary_packet(link->link_enc,328			psr_context->sdpTransmitLineNumDeadline);329 330	memset(&cmd, 0, sizeof(cmd));331	cmd.psr_copy_settings.header.type = DMUB_CMD__PSR;332	cmd.psr_copy_settings.header.sub_type = DMUB_CMD__PSR_COPY_SETTINGS;333	cmd.psr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_psr_copy_settings_data);334 335	// Hw insts336	copy_settings_data->dpphy_inst				= psr_context->transmitterId;337	copy_settings_data->aux_inst				= psr_context->channel;338	copy_settings_data->digfe_inst				= psr_context->engineId;339	copy_settings_data->digbe_inst				= psr_context->transmitterId;340 341	copy_settings_data->mpcc_inst				= pipe_ctx->plane_res.mpcc_inst;342 343	if (pipe_ctx->plane_res.dpp)344		copy_settings_data->dpp_inst			= pipe_ctx->plane_res.dpp->inst;345	else346		copy_settings_data->dpp_inst			= 0;347	if (pipe_ctx->stream_res.opp)348		copy_settings_data->opp_inst			= pipe_ctx->stream_res.opp->inst;349	else350		copy_settings_data->opp_inst			= 0;351	if (pipe_ctx->stream_res.tg)352		copy_settings_data->otg_inst			= pipe_ctx->stream_res.tg->inst;353	else354		copy_settings_data->otg_inst			= 0;355 356	// Misc357	copy_settings_data->use_phy_fsm             = link->ctx->dc->debug.psr_power_use_phy_fsm;358	copy_settings_data->psr_level				= psr_context->psr_level.u32all;359	copy_settings_data->smu_optimizations_en		= psr_context->allow_smu_optimizations;360	copy_settings_data->multi_disp_optimizations_en	= psr_context->allow_multi_disp_optimizations;361	copy_settings_data->frame_delay				= psr_context->frame_delay;362	copy_settings_data->frame_cap_ind			= psr_context->psrFrameCaptureIndicationReq;363	copy_settings_data->init_sdp_deadline			= psr_context->sdpTransmitLineNumDeadline;364	copy_settings_data->debug.u32All = 0;365	copy_settings_data->debug.bitfields.visual_confirm	= dc->dc->debug.visual_confirm == VISUAL_CONFIRM_PSR;366	copy_settings_data->debug.bitfields.use_hw_lock_mgr		= 1;367	copy_settings_data->debug.bitfields.force_full_frame_update	= 0;368	copy_settings_data->debug.bitfields.enable_ips_visual_confirm = dc->dc->debug.enable_ips_visual_confirm;369 370	if (psr_context->su_granularity_required == 0)371		copy_settings_data->su_y_granularity = 0;372	else373		copy_settings_data->su_y_granularity = psr_context->su_y_granularity;374 375	copy_settings_data->line_capture_indication = 0;376	copy_settings_data->line_time_in_us = psr_context->line_time_in_us;377	copy_settings_data->rate_control_caps = psr_context->rate_control_caps;378	copy_settings_data->fec_enable_status = (link->fec_state == dc_link_fec_enabled);379	copy_settings_data->fec_enable_delay_in100us = link->dc->debug.fec_enable_delay_in100us;380	copy_settings_data->cmd_version =  DMUB_CMD_PSR_CONTROL_VERSION_1;381	copy_settings_data->panel_inst = panel_inst;382	copy_settings_data->dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1);383 384	/**385	 * WA for PSRSU+DSC on specific TCON, if DSC is enabled, force PSRSU as ffu mode(full frame update)386	 * Note that PSRSU+DSC is still under development.387	 */388	if (copy_settings_data->dsc_enable_status &&389		link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 &&390		!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1,391			sizeof(DP_SINK_DEVICE_STR_ID_1)))392		link->psr_settings.force_ffu_mode = 1;393	else394		link->psr_settings.force_ffu_mode = 0;395	copy_settings_data->force_ffu_mode = link->psr_settings.force_ffu_mode;396 397	if (((link->dpcd_caps.fec_cap.bits.FEC_CAPABLE &&398		!link->dc->debug.disable_fec) &&399		(link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT &&400		!link->panel_config.dsc.disable_dsc_edp &&401		link->dc->caps.edp_dsc_support)) &&402		link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 &&403		(!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1,404			sizeof(DP_SINK_DEVICE_STR_ID_1)) ||405		!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_2,406			sizeof(DP_SINK_DEVICE_STR_ID_2))))407		copy_settings_data->debug.bitfields.force_wakeup_by_tps3 = 1;408	else409		copy_settings_data->debug.bitfields.force_wakeup_by_tps3 = 0;410 411	if (link->psr_settings.psr_version == DC_PSR_VERSION_1 &&412		link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_0022B9 &&413		!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_3,414			sizeof(DP_SINK_DEVICE_STR_ID_3))) {415		copy_settings_data->poweroff_before_vertical_line = 16;416	}417 418	//WA for PSR1 on specific TCON, require frame delay for frame re-lock419	copy_settings_data->relock_delay_frame_cnt = 0;420	if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8)421		copy_settings_data->relock_delay_frame_cnt = 2;422	copy_settings_data->dsc_slice_height = psr_context->dsc_slice_height;423 424	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);425 426	return true;427}428 429/*430 * Send command to PSR to force static ENTER and ignore all state changes until exit431 */432static void dmub_psr_force_static(struct dmub_psr *dmub, uint8_t panel_inst)433{434	union dmub_rb_cmd cmd;435	struct dc_context *dc = dmub->ctx;436 437	memset(&cmd, 0, sizeof(cmd));438 439	cmd.psr_force_static.psr_force_static_data.panel_inst = panel_inst;440	cmd.psr_force_static.psr_force_static_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;441	cmd.psr_force_static.header.type = DMUB_CMD__PSR;442	cmd.psr_force_static.header.sub_type = DMUB_CMD__PSR_FORCE_STATIC;443	cmd.psr_enable.header.payload_bytes = 0;444 445	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);446}447 448/*449 * Get PSR residency from firmware.450 */451static void dmub_psr_get_residency(struct dmub_psr *dmub, uint32_t *residency,452	uint8_t panel_inst, enum psr_residency_mode mode)453{454	uint16_t param = (uint16_t)(panel_inst << 8);455 456	param |= mode;457 458	/* Send gpint command and wait for ack */459	dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__PSR_RESIDENCY, param, residency,460				  DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY);461}462 463static const struct dmub_psr_funcs psr_funcs = {464	.psr_copy_settings		= dmub_psr_copy_settings,465	.psr_enable			= dmub_psr_enable,466	.psr_get_state			= dmub_psr_get_state,467	.psr_set_level			= dmub_psr_set_level,468	.psr_force_static		= dmub_psr_force_static,469	.psr_get_residency		= dmub_psr_get_residency,470	.psr_set_sink_vtotal_in_psr_active	= dmub_psr_set_sink_vtotal_in_psr_active,471	.psr_set_power_opt		= dmub_psr_set_power_opt,472};473 474/*475 * Construct PSR object.476 */477static void dmub_psr_construct(struct dmub_psr *psr, struct dc_context *ctx)478{479	psr->ctx = ctx;480	psr->funcs = &psr_funcs;481}482 483/*484 * Allocate and initialize PSR object.485 */486struct dmub_psr *dmub_psr_create(struct dc_context *ctx)487{488	struct dmub_psr *psr = kzalloc(sizeof(struct dmub_psr), GFP_KERNEL);489 490	if (psr == NULL) {491		BREAK_TO_DEBUGGER();492		return NULL;493	}494 495	dmub_psr_construct(psr, ctx);496 497	return psr;498}499 500/*501 * Deallocate PSR object.502 */503void dmub_psr_destroy(struct dmub_psr **dmub)504{505	kfree(*dmub);506	*dmub = NULL;507}508