1095 lines · 33.2 KB · C
RawDownload
/* * Copyright 2012-15 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: AMD * */ #include "dm_services.h" #include "ObjectID.h" #include "atomfirmware.h"#include "atom.h"#include "include/bios_parser_interface.h" #include "command_table2.h"#include "command_table_helper2.h"#include "bios_parser_helper.h"#include "bios_parser_types_internal2.h"#include "amdgpu.h" #include "dc_dmub_srv.h"#include "dc.h" #define DC_LOGGER \	bp->base.ctx->logger #define GET_INDEX_INTO_MASTER_TABLE(MasterOrData, FieldName)\	(offsetof(struct atom_master_list_of_##MasterOrData##_functions_v2_1, FieldName) / sizeof(uint16_t)) #define EXEC_BIOS_CMD_TABLE(fname, params)\	(amdgpu_atom_execute_table(((struct amdgpu_device *)bp->base.ctx->driver_context)->mode_info.atom_context, \		GET_INDEX_INTO_MASTER_TABLE(command, fname), \		(uint32_t *)&params, sizeof(params)) == 0) #define BIOS_CMD_TABLE_REVISION(fname, frev, crev)\	amdgpu_atom_parse_cmd_header(((struct amdgpu_device *)bp->base.ctx->driver_context)->mode_info.atom_context, \		GET_INDEX_INTO_MASTER_TABLE(command, fname), &frev, &crev) #define BIOS_CMD_TABLE_PARA_REVISION(fname)\	bios_cmd_table_para_revision(bp->base.ctx->driver_context, \			GET_INDEX_INTO_MASTER_TABLE(command, fname))   static uint32_t bios_cmd_table_para_revision(void *dev,					     uint32_t index){	struct amdgpu_device *adev = dev;	uint8_t frev, crev; 	if (amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context,					index,					&frev, &crev))		return crev;	else		return 0;} /****************************************************************************** ****************************************************************************** ** **                  D I G E N C O D E R C O N T R O L ** ****************************************************************************** *****************************************************************************/ static enum bp_result encoder_control_digx_v1_5(	struct bios_parser *bp,	struct bp_encoder_control *cntl); static enum bp_result encoder_control_fallback(	struct bios_parser *bp,	struct bp_encoder_control *cntl); static void init_dig_encoder_control(struct bios_parser *bp){	uint32_t version =		BIOS_CMD_TABLE_PARA_REVISION(digxencodercontrol); 	switch (version) {	case 5:		bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v1_5;		break;	default:		bp->cmd_tbl.dig_encoder_control = encoder_control_fallback;		break;	}} static void encoder_control_dmcub(		struct dc_dmub_srv *dmcub,		struct dig_encoder_stream_setup_parameters_v1_5 *dig){	union dmub_rb_cmd cmd; 	memset(&cmd, 0, sizeof(cmd)); 	cmd.digx_encoder_control.header.type = DMUB_CMD__VBIOS;	cmd.digx_encoder_control.header.sub_type =		DMUB_CMD__VBIOS_DIGX_ENCODER_CONTROL;	cmd.digx_encoder_control.header.payload_bytes =		sizeof(cmd.digx_encoder_control) -		sizeof(cmd.digx_encoder_control.header);	cmd.digx_encoder_control.encoder_control.dig.stream_param = *dig; 	dc_wake_and_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);} static enum bp_result encoder_control_digx_v1_5(	struct bios_parser *bp,	struct bp_encoder_control *cntl){	enum bp_result result = BP_RESULT_FAILURE;	struct dig_encoder_stream_setup_parameters_v1_5 params = {0}; 	params.digid = (uint8_t)(cntl->engine_id);	params.action = bp->cmd_helper->encoder_action_to_atom(cntl->action); 	params.pclk_10khz = cntl->pixel_clock / 10;	params.digmode =			(uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom(					cntl->signal,					cntl->enable_dp_audio));	params.lanenum = (uint8_t)(cntl->lanes_number); 	switch (cntl->color_depth) {	case COLOR_DEPTH_888:		params.bitpercolor = PANEL_8BIT_PER_COLOR;		break;	case COLOR_DEPTH_101010:		params.bitpercolor = PANEL_10BIT_PER_COLOR;		break;	case COLOR_DEPTH_121212:		params.bitpercolor = PANEL_12BIT_PER_COLOR;		break;	case COLOR_DEPTH_161616:		params.bitpercolor = PANEL_16BIT_PER_COLOR;		break;	default:		break;	} 	if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A)		switch (cntl->color_depth) {		case COLOR_DEPTH_101010:			params.pclk_10khz =				(params.pclk_10khz * 30) / 24;			break;		case COLOR_DEPTH_121212:			params.pclk_10khz =				(params.pclk_10khz * 36) / 24;			break;		case COLOR_DEPTH_161616:			params.pclk_10khz =				(params.pclk_10khz * 48) / 24;			break;		default:			break;		} 	if (bp->base.ctx->dc->ctx->dmub_srv &&	    bp->base.ctx->dc->debug.dmub_command_table) {		encoder_control_dmcub(bp->base.ctx->dmub_srv, &params);		return BP_RESULT_OK;	} 	if (EXEC_BIOS_CMD_TABLE(digxencodercontrol, params))		result = BP_RESULT_OK; 	return result;} static enum bp_result encoder_control_fallback(	struct bios_parser *bp,	struct bp_encoder_control *cntl){	if (bp->base.ctx->dc->ctx->dmub_srv &&	    bp->base.ctx->dc->debug.dmub_command_table) {		return encoder_control_digx_v1_5(bp, cntl);	} 	return BP_RESULT_FAILURE;} /***************************************************************************** ****************************************************************************** ** **                  TRANSMITTER CONTROL ** ****************************************************************************** *****************************************************************************/  static enum bp_result transmitter_control_v1_6(	struct bios_parser *bp,	struct bp_transmitter_control *cntl); static enum bp_result transmitter_control_v1_7(	struct bios_parser *bp,	struct bp_transmitter_control *cntl); static enum bp_result transmitter_control_fallback(	struct bios_parser *bp,	struct bp_transmitter_control *cntl); static void init_transmitter_control(struct bios_parser *bp){	uint8_t frev;	uint8_t crev = 0; 	if (!BIOS_CMD_TABLE_REVISION(dig1transmittercontrol, frev, crev) && (bp->base.ctx->dc->ctx->dce_version <= DCN_VERSION_2_0))		BREAK_TO_DEBUGGER(); 	switch (crev) {	case 6:		bp->cmd_tbl.transmitter_control = transmitter_control_v1_6;		break;	case 7:		bp->cmd_tbl.transmitter_control = transmitter_control_v1_7;		break;	default:		bp->cmd_tbl.transmitter_control = transmitter_control_fallback;		break;	}} static void transmitter_control_dmcub(		struct dc_dmub_srv *dmcub,		struct dig_transmitter_control_parameters_v1_6 *dig){	union dmub_rb_cmd cmd; 	memset(&cmd, 0, sizeof(cmd)); 	cmd.dig1_transmitter_control.header.type = DMUB_CMD__VBIOS;	cmd.dig1_transmitter_control.header.sub_type =		DMUB_CMD__VBIOS_DIG1_TRANSMITTER_CONTROL;	cmd.dig1_transmitter_control.header.payload_bytes =		sizeof(cmd.dig1_transmitter_control) -		sizeof(cmd.dig1_transmitter_control.header);	cmd.dig1_transmitter_control.transmitter_control.dig = *dig; 	dc_wake_and_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);} static enum bp_result transmitter_control_v1_6(	struct bios_parser *bp,	struct bp_transmitter_control *cntl){	enum bp_result result = BP_RESULT_FAILURE;	const struct command_table_helper *cmd = bp->cmd_helper;	struct dig_transmitter_control_ps_allocation_v1_6 ps = { { 0 } }; 	ps.param.phyid = cmd->phy_id_to_atom(cntl->transmitter);	ps.param.action = (uint8_t)cntl->action; 	if (cntl->action == TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS)		ps.param.mode_laneset.dplaneset = (uint8_t)cntl->lane_settings;	else		ps.param.mode_laneset.digmode =				cmd->signal_type_to_atom_dig_mode(cntl->signal); 	ps.param.lanenum = (uint8_t)cntl->lanes_number;	ps.param.hpdsel = cmd->hpd_sel_to_atom(cntl->hpd_sel);	ps.param.digfe_sel = cmd->dig_encoder_sel_to_atom(cntl->engine_id);	ps.param.connobj_id = (uint8_t)cntl->connector_obj_id.id;	ps.param.symclk_10khz = cntl->pixel_clock/10;  	if (cntl->action == TRANSMITTER_CONTROL_ENABLE ||		cntl->action == TRANSMITTER_CONTROL_ACTIAVATE ||		cntl->action == TRANSMITTER_CONTROL_DEACTIVATE) {		DC_LOG_BIOS("%s:ps.param.symclk_10khz = %d\n",\		__func__, ps.param.symclk_10khz);	} 	if (bp->base.ctx->dc->ctx->dmub_srv &&	    bp->base.ctx->dc->debug.dmub_command_table) {		transmitter_control_dmcub(bp->base.ctx->dmub_srv, &ps.param);		return BP_RESULT_OK;	} /*color_depth not used any more, driver has deep color factor in the Phyclk*/	if (EXEC_BIOS_CMD_TABLE(dig1transmittercontrol, ps))		result = BP_RESULT_OK;	return result;} static void transmitter_control_dmcub_v1_7(		struct dc_dmub_srv *dmcub,		struct dmub_dig_transmitter_control_data_v1_7 *dig){	union dmub_rb_cmd cmd; 	memset(&cmd, 0, sizeof(cmd)); 	cmd.dig1_transmitter_control.header.type = DMUB_CMD__VBIOS;	cmd.dig1_transmitter_control.header.sub_type =		DMUB_CMD__VBIOS_DIG1_TRANSMITTER_CONTROL;	cmd.dig1_transmitter_control.header.payload_bytes =		sizeof(cmd.dig1_transmitter_control) -		sizeof(cmd.dig1_transmitter_control.header);	cmd.dig1_transmitter_control.transmitter_control.dig_v1_7 = *dig; 	dc_wake_and_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);} static struct dc_link *get_link_by_phy_id(struct dc *p_dc, uint32_t phy_id){	struct dc_link *link = NULL; 	// Get Transition Bitmask from dc_link structure associated with PHY	for (uint8_t link_id = 0; link_id < MAX_LINKS; link_id++) {		if (phy_id == p_dc->links[link_id]->link_enc->transmitter) {			link = p_dc->links[link_id];			break;		}	} 	return link;} static enum bp_result transmitter_control_v1_7(	struct bios_parser *bp,	struct bp_transmitter_control *cntl){	enum bp_result result = BP_RESULT_FAILURE;	const struct command_table_helper *cmd = bp->cmd_helper;	struct dmub_dig_transmitter_control_data_v1_7 dig_v1_7 = {0}; 	uint8_t hpo_instance = (uint8_t)cntl->hpo_engine_id - ENGINE_ID_HPO_0; 	if (dc_is_dp_signal(cntl->signal))		hpo_instance = (uint8_t)cntl->hpo_engine_id - ENGINE_ID_HPO_DP_0; 	dig_v1_7.phyid = cmd->phy_id_to_atom(cntl->transmitter);	dig_v1_7.action = (uint8_t)cntl->action; 	if (cntl->action == TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS)		dig_v1_7.mode_laneset.dplaneset = (uint8_t)cntl->lane_settings;	else		dig_v1_7.mode_laneset.digmode =				cmd->signal_type_to_atom_dig_mode(cntl->signal); 	dig_v1_7.lanenum = (uint8_t)cntl->lanes_number;	dig_v1_7.hpdsel = cmd->hpd_sel_to_atom(cntl->hpd_sel);	dig_v1_7.digfe_sel = cmd->dig_encoder_sel_to_atom(cntl->engine_id);	dig_v1_7.connobj_id = (uint8_t)cntl->connector_obj_id.id;	dig_v1_7.HPO_instance = hpo_instance;	dig_v1_7.symclk_units.symclk_10khz = cntl->pixel_clock/10; 	if (cntl->action == TRANSMITTER_CONTROL_ENABLE ||		cntl->action == TRANSMITTER_CONTROL_ACTIAVATE ||		cntl->action == TRANSMITTER_CONTROL_DEACTIVATE) {		if (dc_is_hdmi_frl_signal(cntl->signal))			DC_LOG_BIOS("%s:dig_v1_7.symclk_units.symclk_Hz = %d\n",			__func__, dig_v1_7.symclk_units.symclk_Hz);		else			DC_LOG_BIOS("%s:dig_v1_7.symclk_units.symclk_10khz = %d\n",			__func__, dig_v1_7.symclk_units.symclk_10khz);	} 	if (bp->base.ctx->dc->ctx->dmub_srv &&		bp->base.ctx->dc->debug.dmub_command_table) {		struct dm_process_phy_transition_init_params process_phy_transition_init_params = {0};		struct dc_link *link = get_link_by_phy_id(bp->base.ctx->dc, dig_v1_7.phyid);		bool is_phy_transition_interlock_allowed = false;		uint8_t action = dig_v1_7.action; 		if (link) {			if (link->phy_transition_bitmask &&				(action == TRANSMITTER_CONTROL_ENABLE || action == TRANSMITTER_CONTROL_DISABLE)) {				is_phy_transition_interlock_allowed = true; 				// Prepare input parameters for processing ACPI retimers				process_phy_transition_init_params.action                   = action;				process_phy_transition_init_params.display_port_lanes_count = cntl->lanes_number;				process_phy_transition_init_params.phy_id                   = dig_v1_7.phyid;				process_phy_transition_init_params.signal                   = cntl->signal;				process_phy_transition_init_params.sym_clock_10khz          = dig_v1_7.symclk_units.symclk_10khz;				process_phy_transition_init_params.display_port_link_rate   = link->cur_link_settings.link_rate;				process_phy_transition_init_params.transition_bitmask       = link->phy_transition_bitmask;				process_phy_transition_init_params.hdmi_frl_num_lanes       = link->frl_link_settings.frl_num_lanes;				process_phy_transition_init_params.hdmi_frl_link_rate       = link->frl_link_settings.frl_link_rate;			}			dig_v1_7.skip_phy_ssc_reduction = link->wa_flags.skip_phy_ssc_reduction;		} 		// Handle PRE_OFF_TO_ON: Process ACPI PHY Transition Interlock		if (is_phy_transition_interlock_allowed && action == TRANSMITTER_CONTROL_ENABLE)			dm_acpi_process_phy_transition_interlock(bp->base.ctx, process_phy_transition_init_params); 		transmitter_control_dmcub_v1_7(bp->base.ctx->dmub_srv, &dig_v1_7); 		// Handle POST_ON_TO_OFF: Process ACPI PHY Transition Interlock		if (is_phy_transition_interlock_allowed && action == TRANSMITTER_CONTROL_DISABLE)			dm_acpi_process_phy_transition_interlock(bp->base.ctx, process_phy_transition_init_params); 		return BP_RESULT_OK;	} /*color_depth not used any more, driver has deep color factor in the Phyclk*/	if (EXEC_BIOS_CMD_TABLE(dig1transmittercontrol, dig_v1_7))		result = BP_RESULT_OK;	return result;} static enum bp_result transmitter_control_fallback(	struct bios_parser *bp,	struct bp_transmitter_control *cntl){	if (bp->base.ctx->dc->ctx->dmub_srv &&	    bp->base.ctx->dc->debug.dmub_command_table) {		return transmitter_control_v1_7(bp, cntl);	} 	return BP_RESULT_FAILURE;} /****************************************************************************** ****************************************************************************** ** **                  SET PIXEL CLOCK ** ****************************************************************************** *****************************************************************************/ static enum bp_result set_pixel_clock_v7(	struct bios_parser *bp,	struct bp_pixel_clock_parameters *bp_params); static enum bp_result set_pixel_clock_fallback(	struct bios_parser *bp,	struct bp_pixel_clock_parameters *bp_params); static void init_set_pixel_clock(struct bios_parser *bp){	switch (BIOS_CMD_TABLE_PARA_REVISION(setpixelclock)) {	case 7:		bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v7;		break;	default:		bp->cmd_tbl.set_pixel_clock = set_pixel_clock_fallback;		break;	}} static void set_pixel_clock_dmcub(		struct dc_dmub_srv *dmcub,		struct set_pixel_clock_parameter_v1_7 *clk){	union dmub_rb_cmd cmd; 	memset(&cmd, 0, sizeof(cmd)); 	cmd.set_pixel_clock.header.type = DMUB_CMD__VBIOS;	cmd.set_pixel_clock.header.sub_type = DMUB_CMD__VBIOS_SET_PIXEL_CLOCK;	cmd.set_pixel_clock.header.payload_bytes =		sizeof(cmd.set_pixel_clock) -		sizeof(cmd.set_pixel_clock.header);	cmd.set_pixel_clock.pixel_clock.clk = *clk; 	dc_wake_and_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);} static enum bp_result set_pixel_clock_v7(	struct bios_parser *bp,	struct bp_pixel_clock_parameters *bp_params){	enum bp_result result = BP_RESULT_FAILURE;	struct set_pixel_clock_parameter_v1_7 clk;	uint8_t controller_id;	uint32_t pll_id; 	memset(&clk, 0, sizeof(clk)); 	if (bp->cmd_helper->clock_source_id_to_atom(bp_params->pll_id, &pll_id)			&& bp->cmd_helper->controller_id_to_atom(bp_params->					controller_id, &controller_id)) {		/* Note: VBIOS still wants to use ucCRTC name which is now		 * 1 byte in ULONG

Lines 1–500 of 1095.