Commit 028c4ccf authored by Qingqing Zhuo's avatar Qingqing Zhuo Committed by Alex Deucher
Browse files

drm/amd/display: force connector state when bpc changes during compliance



[Why]
During DP DSC compliance tests, bpc requested would
change between sub-tests, which requires stream
to be recommited.

[How]
Force connector to disconnect and reconnect whenever
there is a bpc change in automated test.

Reviewed-by: default avatarJerry Zuo <Jerry.Zuo@amd.com>
Acked-by: default avatarAlan Liu <HaoPing.Liu@amd.com>
Signed-off-by: default avatarQingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: default avatarhersen wu <hersenxs.wu@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 31769ce9
Loading
Loading
Loading
Loading
+54 −1
Original line number Diff line number Diff line
@@ -39,6 +39,9 @@
#include "dc/dc_edid_parser.h"
#include "dc/dc_stat.h"
#include "amdgpu_dm_trace.h"
#include "dpcd_defs.h"
#include "link/link_dpcd.h"
#include "link_service_types.h"

#include "vid.h"
#include "amdgpu.h"
@@ -1228,6 +1231,21 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_

}

static void force_connector_state(
	struct amdgpu_dm_connector *aconnector,
	enum drm_connector_force force_state)
{
	struct drm_connector *connector = &aconnector->base;

	mutex_lock(&connector->dev->mode_config.mutex);
	aconnector->base.force = force_state;
	mutex_unlock(&connector->dev->mode_config.mutex);

	mutex_lock(&aconnector->hpd_lock);
	drm_kms_helper_connector_hotplug_event(connector);
	mutex_unlock(&aconnector->hpd_lock);
}

static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
{
	struct hpd_rx_irq_offload_work *offload_work;
@@ -1236,6 +1254,9 @@ static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
	struct amdgpu_device *adev;
	enum dc_connection_type new_connection_type = dc_connection_none;
	unsigned long flags;
	union test_response test_response;

	memset(&test_response, 0, sizeof(test_response));

	offload_work = container_of(work, struct hpd_rx_irq_offload_work, work);
	aconnector = offload_work->offload_wq->aconnector;
@@ -1260,8 +1281,24 @@ static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
		goto skip;

	mutex_lock(&adev->dm.dc_lock);
	if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST)
	if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
		dc_link_dp_handle_automated_test(dc_link);

		if (aconnector->timing_changed) {
			/* force connector disconnect and reconnect */
			force_connector_state(aconnector, DRM_FORCE_OFF);
			msleep(100);
			force_connector_state(aconnector, DRM_FORCE_UNSPECIFIED);
		}

		test_response.bits.ACK = 1;

		core_link_write_dpcd(
		dc_link,
		DP_TEST_RESPONSE,
		&test_response.raw,
		sizeof(test_response));
	}
	else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) &&
			hpd_rx_irq_check_link_loss_status(dc_link, &offload_work->data) &&
			dc_link_dp_allow_hpd_rx_irq(dc_link)) {
@@ -2986,6 +3023,10 @@ void amdgpu_dm_update_connector_after_detect(
						    aconnector->edid);
		}

		aconnector->timing_requested = kzalloc(sizeof(struct dc_crtc_timing), GFP_KERNEL);
		if (!aconnector->timing_requested)
			dm_error("%s: failed to create aconnector->requested_timing\n", __func__);

		drm_connector_update_edid_property(connector, aconnector->edid);
		amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
		update_connector_ext_caps(aconnector);
@@ -2997,6 +3038,8 @@ void amdgpu_dm_update_connector_after_detect(
		dc_sink_release(aconnector->dc_sink);
		aconnector->dc_sink = NULL;
		aconnector->edid = NULL;
		kfree(aconnector->timing_requested);
		aconnector->timing_requested = NULL;
#ifdef CONFIG_DRM_AMD_DC_HDCP
		/* Set CP to DESIRED if it was ENABLED, so we can re-enable it again on hotplug */
		if (connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
@@ -3041,6 +3084,8 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
	if (aconnector->fake_enable)
		aconnector->fake_enable = false;

	aconnector->timing_changed = false;

	if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
		DRM_ERROR("KMS: Failed to detect connector\n");

@@ -5883,6 +5928,14 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
			stream, &mode, &aconnector->base, con_state, old_stream,
			requested_bpc);

	if (aconnector->timing_changed) {
		DC_LOG_DEBUG("%s: overriding timing for automated test, bpc %d, changing to %d\n",
				__func__,
				stream->timing.display_color_depth,
				aconnector->timing_requested->display_color_depth);
		stream->timing = *aconnector->timing_requested;
	}

#if defined(CONFIG_DRM_AMD_DC_DCN)
	/* SST DSC determination policy */
	update_dsc_caps(aconnector, sink, stream, &dsc_caps);
+5 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_plane.h>
#include "link_service_types.h"

/*
 * This file contains the definition for amdgpu_display_manager
@@ -644,6 +645,10 @@ struct amdgpu_dm_connector {

	/* Record progress status of mst*/
	uint8_t mst_status;

	/* Automated testing */
	bool timing_changed;
	struct dc_crtc_timing *timing_requested;
};

static inline void amdgpu_dm_set_mst_status(uint8_t *status,
+125 −0
Original line number Diff line number Diff line
@@ -38,6 +38,9 @@
#include "amdgpu_dm.h"
#include "amdgpu_dm_irq.h"
#include "amdgpu_dm_mst_types.h"
#include "dpcd_defs.h"
#include "dc/inc/core_types.h"
#include "dc_link_dp.h"

#include "dm_helpers.h"
#include "ddc_service_types.h"
@@ -960,6 +963,128 @@ void dm_helpers_mst_enable_stream_features(const struct dc_stream_state *stream)
					 sizeof(new_downspread));
}

bool dm_helpers_dp_handle_test_pattern_request(
		struct dc_context *ctx,
		const struct dc_link *link,
		union link_test_pattern dpcd_test_pattern,
		union test_misc dpcd_test_params)
{
	enum dp_test_pattern test_pattern;
	enum dp_test_pattern_color_space test_pattern_color_space =
			DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED;
	enum dc_color_depth requestColorDepth = COLOR_DEPTH_UNDEFINED;
	enum dc_pixel_encoding requestPixelEncoding = PIXEL_ENCODING_UNDEFINED;
	struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
	struct pipe_ctx *pipe_ctx = NULL;
	struct amdgpu_dm_connector *aconnector = link->priv;
	int i;

	for (i = 0; i < MAX_PIPES; i++) {
		if (pipes[i].stream == NULL)
			continue;

		if (pipes[i].stream->link == link && !pipes[i].top_pipe &&
			!pipes[i].prev_odm_pipe) {
			pipe_ctx = &pipes[i];
			break;
		}
	}

	if (pipe_ctx == NULL)
		return false;

	switch (dpcd_test_pattern.bits.PATTERN) {
	case LINK_TEST_PATTERN_COLOR_RAMP:
		test_pattern = DP_TEST_PATTERN_COLOR_RAMP;
	break;
	case LINK_TEST_PATTERN_VERTICAL_BARS:
		test_pattern = DP_TEST_PATTERN_VERTICAL_BARS;
	break; /* black and white */
	case LINK_TEST_PATTERN_COLOR_SQUARES:
		test_pattern = (dpcd_test_params.bits.DYN_RANGE ==
				TEST_DYN_RANGE_VESA ?
				DP_TEST_PATTERN_COLOR_SQUARES :
				DP_TEST_PATTERN_COLOR_SQUARES_CEA);
	break;
	default:
		test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
	break;
	}

	if (dpcd_test_params.bits.CLR_FORMAT == 0)
		test_pattern_color_space = DP_TEST_PATTERN_COLOR_SPACE_RGB;
	else
		test_pattern_color_space = dpcd_test_params.bits.YCBCR_COEFS ?
				DP_TEST_PATTERN_COLOR_SPACE_YCBCR709 :
				DP_TEST_PATTERN_COLOR_SPACE_YCBCR601;

	switch (dpcd_test_params.bits.BPC) {
	case 0: // 6 bits
		requestColorDepth = COLOR_DEPTH_666;
		break;
	case 1: // 8 bits
		requestColorDepth = COLOR_DEPTH_888;
		break;
	case 2: // 10 bits
		requestColorDepth = COLOR_DEPTH_101010;
		break;
	case 3: // 12 bits
		requestColorDepth = COLOR_DEPTH_121212;
		break;
	default:
		break;
	}

	switch (dpcd_test_params.bits.CLR_FORMAT) {
	case 0:
		requestPixelEncoding = PIXEL_ENCODING_RGB;
		break;
	case 1:
		requestPixelEncoding = PIXEL_ENCODING_YCBCR422;
		break;
	case 2:
		requestPixelEncoding = PIXEL_ENCODING_YCBCR444;
		break;
	default:
		requestPixelEncoding = PIXEL_ENCODING_RGB;
		break;
	}

	if ((requestColorDepth != COLOR_DEPTH_UNDEFINED
		&& pipe_ctx->stream->timing.display_color_depth != requestColorDepth)
		|| (requestPixelEncoding != PIXEL_ENCODING_UNDEFINED
		&& pipe_ctx->stream->timing.pixel_encoding != requestPixelEncoding)) {
		DC_LOG_DEBUG("%s: original bpc %d pix encoding %d, changing to %d  %d\n",
				__func__,
				pipe_ctx->stream->timing.display_color_depth,
				pipe_ctx->stream->timing.pixel_encoding,
				requestColorDepth,
				requestPixelEncoding);
		pipe_ctx->stream->timing.display_color_depth = requestColorDepth;
		pipe_ctx->stream->timing.pixel_encoding = requestPixelEncoding;

		dp_update_dsc_config(pipe_ctx);

		aconnector->timing_changed = true;
		/* store current timing */
		if (aconnector->timing_requested)
			*aconnector->timing_requested = pipe_ctx->stream->timing;
		else
			DC_LOG_ERROR("%s: timing storage failed\n", __func__);

	}

	dc_link_dp_set_test_pattern(
		(struct dc_link *) link,
		test_pattern,
		test_pattern_color_space,
		NULL,
		NULL,
		0);

	return false;
}

void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz)
{
       // TODO
+19 −120
Original line number Diff line number Diff line
@@ -573,124 +573,6 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
		test_pattern_size);
}

static void dp_test_send_link_test_pattern(struct dc_link *link)
{
	union link_test_pattern dpcd_test_pattern;
	union test_misc dpcd_test_params;
	enum dp_test_pattern test_pattern;
	enum dp_test_pattern_color_space test_pattern_color_space =
			DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED;
	enum dc_color_depth requestColorDepth = COLOR_DEPTH_UNDEFINED;
	struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
	struct pipe_ctx *pipe_ctx = NULL;
	int i;

	memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern));
	memset(&dpcd_test_params, 0, sizeof(dpcd_test_params));

	for (i = 0; i < MAX_PIPES; i++) {
		if (pipes[i].stream == NULL)
			continue;

		if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
			pipe_ctx = &pipes[i];
			break;
		}
	}

	if (pipe_ctx == NULL)
		return;

	/* get link test pattern and pattern parameters */
	core_link_read_dpcd(
			link,
			DP_TEST_PATTERN,
			&dpcd_test_pattern.raw,
			sizeof(dpcd_test_pattern));
	core_link_read_dpcd(
			link,
			DP_TEST_MISC0,
			&dpcd_test_params.raw,
			sizeof(dpcd_test_params));

	switch (dpcd_test_pattern.bits.PATTERN) {
	case LINK_TEST_PATTERN_COLOR_RAMP:
		test_pattern = DP_TEST_PATTERN_COLOR_RAMP;
	break;
	case LINK_TEST_PATTERN_VERTICAL_BARS:
		test_pattern = DP_TEST_PATTERN_VERTICAL_BARS;
	break; /* black and white */
	case LINK_TEST_PATTERN_COLOR_SQUARES:
		test_pattern = (dpcd_test_params.bits.DYN_RANGE ==
				TEST_DYN_RANGE_VESA ?
				DP_TEST_PATTERN_COLOR_SQUARES :
				DP_TEST_PATTERN_COLOR_SQUARES_CEA);
	break;
	default:
		test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
	break;
	}

	if (dpcd_test_params.bits.CLR_FORMAT == 0)
		test_pattern_color_space = DP_TEST_PATTERN_COLOR_SPACE_RGB;
	else
		test_pattern_color_space = dpcd_test_params.bits.YCBCR_COEFS ?
				DP_TEST_PATTERN_COLOR_SPACE_YCBCR709 :
				DP_TEST_PATTERN_COLOR_SPACE_YCBCR601;

	switch (dpcd_test_params.bits.BPC) {
	case 0: // 6 bits
		requestColorDepth = COLOR_DEPTH_666;
		break;
	case 1: // 8 bits
		requestColorDepth = COLOR_DEPTH_888;
		break;
	case 2: // 10 bits
		requestColorDepth = COLOR_DEPTH_101010;
		break;
	case 3: // 12 bits
		requestColorDepth = COLOR_DEPTH_121212;
		break;
	default:
		break;
	}

	switch (dpcd_test_params.bits.CLR_FORMAT) {
	case 0:
		pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_RGB;
		break;
	case 1:
		pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_YCBCR422;
		break;
	case 2:
		pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_YCBCR444;
		break;
	default:
		pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_RGB;
		break;
	}


	if (requestColorDepth != COLOR_DEPTH_UNDEFINED
			&& pipe_ctx->stream->timing.display_color_depth != requestColorDepth) {
		DC_LOG_DEBUG("%s: original bpc %d, changing to %d\n",
				__func__,
				pipe_ctx->stream->timing.display_color_depth,
				requestColorDepth);
		pipe_ctx->stream->timing.display_color_depth = requestColorDepth;
	}

	dp_update_dsc_config(pipe_ctx);

	dc_link_dp_set_test_pattern(
			link,
			test_pattern,
			test_pattern_color_space,
			NULL,
			NULL,
			0);
}

static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video)
{
	union audio_test_mode            dpcd_test_mode = {0};
@@ -803,8 +685,25 @@ void dc_link_dp_handle_automated_test(struct dc_link *link)
		test_response.bits.ACK = 0;
	}
	if (test_request.bits.LINK_TEST_PATTRN) {
		dp_test_send_link_test_pattern(link);
		test_response.bits.ACK = 1;
		union test_misc dpcd_test_params;
		union link_test_pattern dpcd_test_pattern;

		memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern));
		memset(&dpcd_test_params, 0, sizeof(dpcd_test_params));

		/* get link test pattern and pattern parameters */
		core_link_read_dpcd(
				link,
				DP_TEST_PATTERN,
				&dpcd_test_pattern.raw,
				sizeof(dpcd_test_pattern));
		core_link_read_dpcd(
				link,
				DP_TEST_MISC0,
				&dpcd_test_params.raw,
				sizeof(dpcd_test_params));
		test_response.bits.ACK = dm_helpers_dp_handle_test_pattern_request(link->ctx, link,
				dpcd_test_pattern, dpcd_test_params) ? 1 : 0;
	}

	if (test_request.bits.AUDIO_TEST_PATTERN) {
+6 −0
Original line number Diff line number Diff line
@@ -161,6 +161,12 @@ enum dc_edid_status dm_helpers_read_local_edid(
		struct dc_link *link,
		struct dc_sink *sink);

bool dm_helpers_dp_handle_test_pattern_request(
		struct dc_context *ctx,
		const struct dc_link *link,
		union link_test_pattern dpcd_test_pattern,
		union test_misc dpcd_test_params);

void dm_set_dcn_clocks(
		struct dc_context *ctx,
		struct dc_clocks *clks);