Commit 3a1627b0 authored by Nicholas Kazlauskas's avatar Nicholas Kazlauskas Committed by Alex Deucher
Browse files

drm/amd/display: Add DMUB support to DC



DC will use DMUB for command submission and flow control during
initialization.

Register offloading as well as submitting some BIOS commands are part
of the DC internal interface but are guarded behind debug options.

It won't be functional in amdgpu_dm yet since we don't pass the
DMUB service to DC for use.

Signed-off-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Reviewed-by: default avatarHersen Wu <hersenxs.wu@amd.com>
Acked-by: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 976e51a7
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -70,5 +70,9 @@ AMD_DM_REG_UPDATE = $(addprefix $(AMDDALPATH)/dc/,dc_helper.o)
AMD_DISPLAY_FILES += $(AMD_DISPLAY_CORE)
AMD_DISPLAY_FILES += $(AMD_DM_REG_UPDATE)


ifdef CONFIG_DRM_AMD_DC_DMUB
DC_DMUB += dc_dmub_srv.o
AMD_DISPLAY_DMUB = $(addprefix $(AMDDALPATH)/dc/,$(DC_DMUB))
AMD_DISPLAY_FILES += $(AMD_DISPLAY_DMUB)
endif
+91 −0
Original line number Diff line number Diff line
@@ -37,6 +37,10 @@
#include "bios_parser_types_internal2.h"
#include "amdgpu.h"

#ifdef CONFIG_DRM_AMD_DC_DMUB
#include "dc_dmub_srv.h"
#include "dc.h"
#endif

#define DC_LOGGER \
	bp->base.ctx->logger
@@ -103,6 +107,21 @@ static void init_dig_encoder_control(struct bios_parser *bp)
	}
}

#ifdef CONFIG_DRM_AMD_DC_DMUB
static void encoder_control_dmcub(
		struct dc_dmub_srv *dmcub,
		struct dig_encoder_stream_setup_parameters_v1_5 *dig)
{
	struct dmub_rb_cmd_digx_encoder_control encoder_control = { 0 };

	encoder_control.header.type = DMUB_CMD__DIGX_ENCODER_CONTROL;
	encoder_control.encoder_control.dig.stream_param = *dig;

	dc_dmub_srv_cmd_queue(dmcub, &encoder_control.header);
	dc_dmub_srv_cmd_execute(dmcub);
	dc_dmub_srv_wait_idle(dmcub);
}
#endif
static enum bp_result encoder_control_digx_v1_5(
	struct bios_parser *bp,
	struct bp_encoder_control *cntl)
@@ -154,6 +173,13 @@ static enum bp_result encoder_control_digx_v1_5(
		default:
			break;
		}
#ifdef CONFIG_DRM_AMD_DC_DMUB
	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;
	}
#endif

	if (EXEC_BIOS_CMD_TABLE(digxencodercontrol, params))
		result = BP_RESULT_OK;
@@ -190,7 +216,21 @@ static void init_transmitter_control(struct bios_parser *bp)
		break;
	}
}
#ifdef CONFIG_DRM_AMD_DC_DMUB
static void transmitter_control_dmcub(
		struct dc_dmub_srv *dmcub,
		struct dig_transmitter_control_parameters_v1_6 *dig)
{
	struct dmub_rb_cmd_dig1_transmitter_control transmitter_control;

	transmitter_control.header.type = DMUB_CMD__DIG1_TRANSMITTER_CONTROL;
	transmitter_control.transmitter_control.dig = *dig;

	dc_dmub_srv_cmd_queue(dmcub, &transmitter_control.header);
	dc_dmub_srv_cmd_execute(dmcub);
	dc_dmub_srv_wait_idle(dmcub);
}
#endif
static enum bp_result transmitter_control_v1_6(
	struct bios_parser *bp,
	struct bp_transmitter_control *cntl)
@@ -223,6 +263,14 @@ static enum bp_result transmitter_control_v1_6(
	}


#ifdef CONFIG_DRM_AMD_DC_DMUB
	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;
	}
#endif

/*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;
@@ -255,7 +303,21 @@ static void init_set_pixel_clock(struct bios_parser *bp)
	}
}

#ifdef CONFIG_DRM_AMD_DC_DMUB
static void set_pixel_clock_dmcub(
		struct dc_dmub_srv *dmcub,
		struct set_pixel_clock_parameter_v1_7 *clk)
{
	struct dmub_rb_cmd_set_pixel_clock pixel_clock = { 0 };

	pixel_clock.header.type     = DMUB_CMD__SET_PIXEL_CLOCK;
	pixel_clock.pixel_clock.clk = *clk;

	dc_dmub_srv_cmd_queue(dmcub, &pixel_clock.header);
	dc_dmub_srv_cmd_execute(dmcub);
	dc_dmub_srv_wait_idle(dmcub);
}
#endif

static enum bp_result set_pixel_clock_v7(
	struct bios_parser *bp,
@@ -331,6 +393,13 @@ static enum bp_result set_pixel_clock_v7(
		if (bp_params->signal_type == SIGNAL_TYPE_DVI_DUAL_LINK)
			clk.miscinfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN;

#ifdef CONFIG_DRM_AMD_DC_DMUB
		if (bp->base.ctx->dc->ctx->dmub_srv &&
		    bp->base.ctx->dc->debug.dmub_command_table) {
			set_pixel_clock_dmcub(bp->base.ctx->dmub_srv, &clk);
			return BP_RESULT_OK;
		}
#endif
		if (EXEC_BIOS_CMD_TABLE(setpixelclock, clk))
			result = BP_RESULT_OK;
	}
@@ -584,7 +653,21 @@ static void init_enable_disp_power_gating(
		break;
	}
}
#ifdef CONFIG_DRM_AMD_DC_DMUB
static void enable_disp_power_gating_dmcub(
	struct dc_dmub_srv *dmcub,
	struct enable_disp_power_gating_parameters_v2_1 *pwr)
{
	struct dmub_rb_cmd_enable_disp_power_gating power_gating;

	power_gating.header.type      = DMUB_CMD__ENABLE_DISP_POWER_GATING;
	power_gating.power_gating.pwr = *pwr;

	dc_dmub_srv_cmd_queue(dmcub, &power_gating.header);
	dc_dmub_srv_cmd_execute(dmcub);
	dc_dmub_srv_wait_idle(dmcub);
}
#endif
static enum bp_result enable_disp_power_gating_v2_1(
	struct bios_parser *bp,
	enum controller_id crtc_id,
@@ -604,6 +687,14 @@ static enum bp_result enable_disp_power_gating_v2_1(
	ps.param.enable =
		bp->cmd_helper->disp_power_gating_action_to_atom(action);

#ifdef CONFIG_DRM_AMD_DC_DMUB
	if (bp->base.ctx->dc->ctx->dmub_srv &&
	    bp->base.ctx->dc->debug.dmub_command_table) {
		enable_disp_power_gating_dmcub(bp->base.ctx->dmub_srv,
					       &ps.param);
		return BP_RESULT_OK;
	}
#endif
	if (EXEC_BIOS_CMD_TABLE(enabledisppowergating, ps.param))
		result = BP_RESULT_OK;

+8 −0
Original line number Diff line number Diff line
@@ -59,6 +59,10 @@

#include "dc_link_dp.h"

#ifdef CONFIG_DRM_AMD_DC_DMUB
#include "dc_dmub_srv.h"
#endif

#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
#include "dsc.h"
#endif
@@ -2406,6 +2410,10 @@ void dc_set_power_state(
	switch (power_state) {
	case DC_ACPI_CM_POWER_STATE_D0:
		dc_resource_state_construct(dc, dc->current_state);
#ifdef CONFIG_DRM_AMD_DC_DMUB
		if (dc->ctx->dmub_srv)
			dc_dmub_srv_wait_phy_init(dc->ctx->dmub_srv);
#endif

		dc->hwss.init_hw(dc);

+12 −0
Original line number Diff line number Diff line
@@ -112,6 +112,9 @@ struct dc_caps {
	bool disable_dp_clk_share;
	bool psp_setup_panel_mode;
	bool extended_aux_timeout_support;
#ifdef CONFIG_DRM_AMD_DC_DMUB
	bool dmcub_support;
#endif
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
	bool hw_3d_lut;
#endif
@@ -401,6 +404,11 @@ struct dc_debug_options {
	unsigned int force_odm_combine; //bit vector based on otg inst
	unsigned int force_fclk_khz;
	bool disable_tri_buf;
#ifdef CONFIG_DRM_AMD_DC_DMUB
	bool dmub_offload_enabled;
	bool dmcub_emulation;
	bool dmub_command_table; /* for testing only */
#endif
	struct dc_bw_validation_profile bw_val_profile;
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
	bool disable_fec;
@@ -558,6 +566,10 @@ struct dc_init_data {
	struct dc_bios *vbios_override;
	enum dce_environment dce_environment;

#ifdef CONFIG_DRM_AMD_DC_DMUB
	struct dmub_offload_funcs *dmub_if;
	struct dc_reg_helper_state *dmub_offload;
#endif
	struct dc_config flags;
	uint32_t log_mask;
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
+119 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 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 "dc.h"
#include "dc_dmub_srv.h"
#include "../dmub/inc/dmub_srv.h"

static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc,
				  struct dmub_srv *dmub)
{
	dc_srv->dmub = dmub;
	dc_srv->ctx = dc->ctx;
}

struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub)
{
	struct dc_dmub_srv *dc_srv =
		kzalloc(sizeof(struct dc_dmub_srv), GFP_KERNEL);

	if (dc_srv == NULL) {
		BREAK_TO_DEBUGGER();
		return NULL;
	}

	dc_dmub_srv_construct(dc_srv, dc, dmub);

	return dc_srv;
}

void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv)
{
	if (*dmub_srv) {
		kfree(*dmub_srv);
		*dmub_srv = NULL;
	}
}

void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv,
			   struct dmub_cmd_header *cmd)
{
	struct dmub_srv *dmub = dc_dmub_srv->dmub;
	struct dc_context *dc_ctx = dc_dmub_srv->ctx;
	enum dmub_status status;

	status = dmub_srv_cmd_queue(dmub, cmd);
	if (status == DMUB_STATUS_OK)
		return;

	if (status != DMUB_STATUS_QUEUE_FULL)
		goto error;

	/* Execute and wait for queue to become empty again. */
	dc_dmub_srv_cmd_execute(dc_dmub_srv);
	dc_dmub_srv_wait_idle(dc_dmub_srv);

	/* Requeue the command. */
	status = dmub_srv_cmd_queue(dmub, cmd);
	if (status == DMUB_STATUS_OK)
		return;

error:
	DC_ERROR("Error queuing DMUB command: status=%d\n", status);
}

void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv)
{
	struct dmub_srv *dmub = dc_dmub_srv->dmub;
	struct dc_context *dc_ctx = dc_dmub_srv->ctx;
	enum dmub_status status;

	status = dmub_srv_cmd_execute(dmub);
	if (status != DMUB_STATUS_OK)
		DC_ERROR("Error starting DMUB exeuction: status=%d\n", status);
}

void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv)
{
	struct dmub_srv *dmub = dc_dmub_srv->dmub;
	struct dc_context *dc_ctx = dc_dmub_srv->ctx;
	enum dmub_status status;

	status = dmub_srv_wait_for_idle(dmub, 100000);
	if (status != DMUB_STATUS_OK)
		DC_ERROR("Error waiting for DMUB idle: status=%d\n", status);
}

void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv)
{
	struct dmub_srv *dmub = dc_dmub_srv->dmub;
	struct dc_context *dc_ctx = dc_dmub_srv->ctx;
	enum dmub_status status;

	status = dmub_srv_wait_for_phy_init(dmub, 1000000);
	if (status != DMUB_STATUS_OK)
		DC_ERROR("Error waiting for DMUB phy init: status=%d\n",
			 status);
}
Loading