Commit 14b25846 authored by Dingchen Zhang's avatar Dingchen Zhang Committed by Alex Deucher
Browse files

drm/amd/display: add functionality to grab DPRX CRC entries.



[Why]
We need to compare DPRX CRCs with framebuffer CRCs for digital bypass mode.

[How]
Hook into DRM to grab DP receiver CRCs through drm_dp_start_crc.

Signed-off-by: default avatarDingchen Zhang <dingchen.zhang@amd.com>
Reviewed-by: default avatarHarry Wentland <Harry.Wentland@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 24253476
Loading
Loading
Loading
Loading
+11 −6
Original line number Diff line number Diff line
@@ -3665,7 +3665,7 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
	state->abm_level = cur->abm_level;
	state->vrr_supported = cur->vrr_supported;
	state->freesync_config = cur->freesync_config;
	state->crc_enabled = cur->crc_enabled;
	state->crc_src = cur->crc_src;
	state->cm_has_degamma = cur->cm_has_degamma;
	state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;

@@ -5975,6 +5975,7 @@ static void amdgpu_dm_enable_crtc_interrupts(struct drm_device *dev,
	struct drm_crtc *crtc;
	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
	int i;
	enum amdgpu_dm_pipe_crc_source source;

	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
				      new_crtc_state, i) {
@@ -6000,9 +6001,13 @@ static void amdgpu_dm_enable_crtc_interrupts(struct drm_device *dev,

#ifdef CONFIG_DEBUG_FS
		/* The stream has changed so CRC capture needs to re-enabled. */
		if (dm_new_crtc_state->crc_enabled) {
			dm_new_crtc_state->crc_enabled = false;
			amdgpu_dm_crtc_set_crc_source(crtc, "auto");
		source = dm_new_crtc_state->crc_src;
		if (amdgpu_dm_is_valid_crc_source(source)) {
			dm_new_crtc_state->crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
			if (source == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC)
				amdgpu_dm_crtc_set_crc_source(crtc, "crtc");
			else if (source == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX)
				amdgpu_dm_crtc_set_crc_source(crtc, "dprx");
		}
#endif
	}
@@ -6058,7 +6063,7 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
			 * Drop the extra vblank reference added by CRC
			 * capture if applicable.
			 */
			if (dm_new_crtc_state->crc_enabled)
			if (amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src))
				drm_crtc_vblank_put(crtc);

			/*
@@ -6066,7 +6071,7 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
			 * still a stream for the CRTC.
			 */
			if (!dm_new_crtc_state->stream)
				dm_new_crtc_state->crc_enabled = false;
				dm_new_crtc_state->crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_NONE;

			manage_dm_interrupts(adev, acrtc, false);
		}
+2 −14
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@

#include "irq_types.h"
#include "signal_types.h"
#include "amdgpu_dm_crc.h"

/* Forward declarations */
struct amdgpu_device;
@@ -313,7 +314,7 @@ struct dm_crtc_state {
	bool interrupts_enabled;

	int crc_skip_count;
	bool crc_enabled;
	enum amdgpu_dm_pipe_crc_source crc_src;

	bool freesync_timing_changed;
	bool freesync_vrr_info_changed;
@@ -380,19 +381,6 @@ void dm_restore_drm_connector_state(struct drm_device *dev,
void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
					struct edid *edid);

/* amdgpu_dm_crc.c */
#ifdef CONFIG_DEBUG_FS
int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name);
int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc,
				     const char *src_name,
				     size_t *values_cnt);
void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc);
#else
#define amdgpu_dm_crtc_set_crc_source NULL
#define amdgpu_dm_crtc_verify_crc_source NULL
#define amdgpu_dm_crtc_handle_crc_irq(x)
#endif

#define MAX_COLOR_LUT_ENTRIES 4096
/* Legacy gamm LUT users such as X doesn't like large LUT sizes */
#define MAX_COLOR_LEGACY_LUT_ENTRIES 256
+67 −24
Original line number Diff line number Diff line
@@ -30,19 +30,14 @@
#include "amdgpu_dm.h"
#include "dc.h"

enum amdgpu_dm_pipe_crc_source {
	AMDGPU_DM_PIPE_CRC_SOURCE_NONE = 0,
	AMDGPU_DM_PIPE_CRC_SOURCE_AUTO,
	AMDGPU_DM_PIPE_CRC_SOURCE_MAX,
	AMDGPU_DM_PIPE_CRC_SOURCE_INVALID = -1,
};

static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
{
	if (!source || !strcmp(source, "none"))
		return AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
	if (!strcmp(source, "auto"))
		return AMDGPU_DM_PIPE_CRC_SOURCE_AUTO;
	if (!strcmp(source, "auto") || !strcmp(source, "crtc"))
		return AMDGPU_DM_PIPE_CRC_SOURCE_CRTC;
	if (!strcmp(source, "dprx"))
		return AMDGPU_DM_PIPE_CRC_SOURCE_DPRX;

	return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID;
}
@@ -68,7 +63,10 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
	struct amdgpu_device *adev = crtc->dev->dev_private;
	struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state);
	struct dc_stream_state *stream_state = crtc_state->stream;
	bool enable;
	struct amdgpu_dm_connector *aconn;
	struct drm_dp_aux *aux = NULL;
	bool enable = false;
	bool enabled = false;

	enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);

@@ -83,14 +81,43 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
		return -EINVAL;
	}

	enable = (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO);
	enable = amdgpu_dm_is_valid_crc_source(source);

	mutex_lock(&adev->dm.dc_lock);
	/*
	 * USER REQ SRC | CURRENT SRC | BEHAVIOR
	 * -----------------------------
	 * None         | None        | Do nothing
	 * None         | CRTC        | Disable CRTC CRC
	 * None         | DPRX        | Disable DPRX CRC, need 'aux'
	 * CRTC         | XXXX        | Enable CRTC CRC, configure DC strm
	 * DPRX         | XXXX        | Enable DPRX CRC, need 'aux'
	 */
	if (source == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX ||
		(source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE &&
		 crtc_state->crc_src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX)) {
		aconn = stream_state->link->priv;

		if (!aconn) {
			DRM_DEBUG_DRIVER("No amd connector matching CRTC-%d\n", crtc->index);
			mutex_unlock(&adev->dm.dc_lock);
			return -EINVAL;
		}

		aux = &aconn->dm_dp_aux.aux;

		if (!aux) {
			DRM_DEBUG_DRIVER("No dp aux for amd connector\n");
			mutex_unlock(&adev->dm.dc_lock);
			return -EINVAL;
		}
	} else if (source == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC) {
		if (!dc_stream_configure_crc(stream_state->ctx->dc, stream_state,
					     enable, enable)) {
			mutex_unlock(&adev->dm.dc_lock);
			return -EINVAL;
		}
	}

	/* When enabling CRC, we should also disable dithering. */
	dc_stream_set_dither_option(stream_state,
@@ -103,12 +130,26 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
	 * Reading the CRC requires the vblank interrupt handler to be
	 * enabled. Keep a reference until CRC capture stops.
	 */
	if (!crtc_state->crc_enabled && enable)
	enabled = amdgpu_dm_is_valid_crc_source(crtc_state->crc_src);
	if (!enabled && enable) {
		drm_crtc_vblank_get(crtc);
	else if (crtc_state->crc_enabled && !enable)
		if (source == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX) {
			if (drm_dp_start_crc(aux, crtc)) {
				DRM_DEBUG_DRIVER("dp start crc failed\n");
				return -EINVAL;
			}
		}
	} else if (enabled && !enable) {
		drm_crtc_vblank_put(crtc);
		if (crtc_state->crc_src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX) {
			if (drm_dp_stop_crc(aux)) {
				DRM_DEBUG_DRIVER("dp stop crc failed\n");
				return -EINVAL;
			}
		}
	}

	crtc_state->crc_enabled = enable;
	crtc_state->crc_src = source;

	/* Reset crc_skipped on dm state */
	crtc_state->crc_skip_count = 0;
@@ -135,7 +176,7 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
	stream_state = crtc_state->stream;

	/* Early return if CRC capture is not enabled. */
	if (!crtc_state->crc_enabled)
	if (!amdgpu_dm_is_valid_crc_source(crtc_state->crc_src))
		return;

	/*
@@ -149,6 +190,7 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
		return;
	}

	if (crtc_state->crc_src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC) {
		if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state,
				       &crcs[0], &crcs[1], &crcs[2]))
			return;
@@ -156,3 +198,4 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
		drm_crtc_add_crc_entry(crtc, true,
				       drm_crtc_accurate_vblank_count(crtc), crcs);
	}
}
+56 −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
 *
 */

#ifndef AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_
#define AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_

enum amdgpu_dm_pipe_crc_source {
	AMDGPU_DM_PIPE_CRC_SOURCE_NONE = 0,
	AMDGPU_DM_PIPE_CRC_SOURCE_CRTC,
	AMDGPU_DM_PIPE_CRC_SOURCE_DPRX,
	AMDGPU_DM_PIPE_CRC_SOURCE_MAX,
	AMDGPU_DM_PIPE_CRC_SOURCE_INVALID = -1,
};

static inline bool amdgpu_dm_is_valid_crc_source(enum amdgpu_dm_pipe_crc_source source)
{
	return (source == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC) ||
		   (source == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX);
}

/* amdgpu_dm_crc.c */
#ifdef CONFIG_DEBUG_FS
int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name);
int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc,
				     const char *src_name,
				     size_t *values_cnt);
void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc);
#else
#define amdgpu_dm_crtc_set_crc_source NULL
#define amdgpu_dm_crtc_verify_crc_source NULL
#define amdgpu_dm_crtc_handle_crc_irq(x)
#endif

#endif /* AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ */