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: Jerry Zuo <Jerry.Zuo@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: hersen wu <hersenxs.wu@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Qingqing Zhuo 2022-10-03 17:14:13 -04:00 committed by Alex Deucher
parent 31769ce954
commit 028c4ccfb8
5 changed files with 209 additions and 121 deletions

View file

@ -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);

View file

@ -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,

View file

@ -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

View file

@ -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) {

View file

@ -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);