mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 18:30:06 +00:00
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:
parent
31769ce954
commit
028c4ccfb8
5 changed files with 209 additions and 121 deletions
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue