/* * 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 *)¶ms, 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, ¶ms); 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 ULONGLines 1–500 of 1095. Load more
/* * 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 *)¶ms, 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, ¶ms); 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