Commit 1a77ecec authored by Chenyu Chen's avatar Chenyu Chen Committed by Alex Deucher
Browse files

drm/amd/display: Add CRC 32-bit mode support for DCN3.6+



[Why]
DCN 3.6+ hardware supports CRC-32 polynomial in addition to the
legacy CRC-16. Enable 32-bit CRC values per color component for
improvement of precision in display validation.

[How]
When userspace sets crc_poly_mode (0=CRC-16, 1=CRC-32) via the debugfs
interface, the value is stored in dm_irq_params.crc_poly_mode. When CRC
source configuration triggers amdgpu_dm_crtc_configure_crc_source(),
crc_poly_mode is retrieved from dm_irq_params and passed to
dc_stream_configure_crc().

In the DC layer, dc_stream_configure_crc() sets crc_poly_mode into the
crc_params structure and passes it to optc35_configure_crc(). If the
hardware supports the OTG_CRC_POLY_SEL register, the register is
programmed to select CRC-16 or CRC-32 polynomial.

When reading CRC values, optc35_get_crc() checks whether CRC32 register
masks are available. If present, it reads 32-bit CRC values from
OTG_CRC0/1_DATA_R32/G32/B32 registers; otherwise, it falls back
to reading 16-bit CRC values from legacy OTG_CRC0/1_DATA_RG/B
registers.

Reviewed-by: default avatarChiaHsuan Chung <chiahsuan.chung@amd.com>
Signed-off-by: default avatarChenyu Chen <chen-yu.chen@amd.com>
Signed-off-by: default avatarWayne Lin <wayne.lin@amd.com>
Tested-by: default avatarDan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 0b39cb14
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -506,6 +506,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
	struct amdgpu_dm_connector *aconnector = NULL;
	bool enable = amdgpu_dm_is_valid_crc_source(source);
	int ret = 0;
	enum crc_poly_mode crc_poly_mode = CRC_POLY_MODE_16;

	/* Configuration will be deferred to stream enable. */
	if (!stream_state)
@@ -528,10 +529,18 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
		amdgpu_dm_replay_disable(stream_state);
	}

	/* CRC polynomial selection only support for DCN3.6+ except DCN4.0.1 */
	if ((amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 6, 0)) &&
		(amdgpu_ip_version(adev, DCE_HWIP, 0) != IP_VERSION(4, 0, 1))) {
		struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);

		crc_poly_mode = acrtc->dm_irq_params.crc_poly_mode;
	}

	/* Enable or disable CRTC CRC generation */
	if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) {
		if (!dc_stream_configure_crc(stream_state->ctx->dc,
					     stream_state, NULL, enable, enable, 0, true)) {
					     stream_state, NULL, enable, enable, 0, true, crc_poly_mode)) {
			ret = -EINVAL;
			goto unlock;
		}
@@ -877,7 +886,7 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
			else if (adev->dm.secure_display_ctx.op_mode == DISPLAY_CRC_MODE)
				/* update ROI via dm*/
				dc_stream_configure_crc(stream_state->ctx->dc, stream_state,
					&crc_window, true, true, i, false);
					&crc_window, true, true, i, false, (enum crc_poly_mode)acrtc->dm_irq_params.crc_poly_mode);

			reset_crc_frame_count[i] = true;

@@ -901,7 +910,7 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
			else if (adev->dm.secure_display_ctx.op_mode == DISPLAY_CRC_MODE)
				/* Avoid ROI window get changed, keep overwriting. */
				dc_stream_configure_crc(stream_state->ctx->dc, stream_state,
						&crc_window, true, true, i, false);
						&crc_window, true, true, i, false, (enum crc_poly_mode)acrtc->dm_irq_params.crc_poly_mode);

			/* crc ready for psp to read out */
			crtc_ctx->crc_info.crc[i].crc_ready = true;
+46 −0
Original line number Diff line number Diff line
@@ -3839,6 +3839,50 @@ static int crc_win_update_get(void *data, u64 *val)

DEFINE_DEBUGFS_ATTRIBUTE(crc_win_update_fops, crc_win_update_get,
			 crc_win_update_set, "%llu\n");

/*
 * Trigger to set crc polynomial mode
 * 0: 16-bit CRC, 1: 32-bit CRC
 * only accepts 0 or 1 for supported hwip versions
 */
static int crc_poly_mode_set(void *data, u64 val)
{
	struct drm_crtc *crtc = data;
	struct amdgpu_crtc *acrtc;
	struct amdgpu_device *adev = drm_to_adev(crtc->dev);

	if ((amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 6, 0)) &&
		(amdgpu_ip_version(adev, DCE_HWIP, 0) != IP_VERSION(4, 0, 1)) &&
		(val < 2)) {
		acrtc = to_amdgpu_crtc(crtc);
		mutex_lock(&adev->dm.dc_lock);
		spin_lock_irq(&adev_to_drm(adev)->event_lock);
		acrtc->dm_irq_params.crc_poly_mode = val;
		spin_unlock_irq(&adev_to_drm(adev)->event_lock);
		mutex_unlock(&adev->dm.dc_lock);
	}

	return 0;
}

/*
 * Get crc polynomial mode (0: 16-bit CRC, 1: 32-bit CRC)
 */
static int crc_poly_mode_get(void *data, u64 *val)
{
	struct drm_crtc *crtc = data;
	struct drm_device *drm_dev = crtc->dev;
	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);

	spin_lock_irq(&drm_dev->event_lock);
	*val = acrtc->dm_irq_params.crc_poly_mode;
	spin_unlock_irq(&drm_dev->event_lock);

	return 0;
}

DEFINE_DEBUGFS_ATTRIBUTE(crc_poly_mode_fops, crc_poly_mode_get,
			 crc_poly_mode_set, "%llu\n");
#endif
void crtc_debugfs_init(struct drm_crtc *crtc)
{
@@ -3858,6 +3902,8 @@ void crtc_debugfs_init(struct drm_crtc *crtc)
				   &crc_win_y_end_fops);
	debugfs_create_file_unsafe("crc_win_update", 0644, dir, crtc,
				   &crc_win_update_fops);
	debugfs_create_file_unsafe("crc_poly_mode", 0644, dir, crtc,
				   &crc_poly_mode_fops);
	dput(dir);
#endif
	debugfs_create_file("amdgpu_current_bpc", 0644, crtc->debugfs_entry,
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ struct dm_irq_params {

#ifdef CONFIG_DEBUG_FS
	enum amdgpu_dm_pipe_crc_source crc_src;
	int crc_poly_mode; /* enum crc_poly_mode from timing_generator.h */
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
	struct crc_window_param window_param[MAX_CRC_WINDOW_NUM];
	/* At least one CRC window is activated or not*/
+3 −1
Original line number Diff line number Diff line
@@ -701,6 +701,7 @@ dc_stream_forward_multiple_crc_window(struct dc_stream_state *stream,
 *              once.
 * @idx: Capture CRC on which CRC engine instance
 * @reset: Reset CRC engine before the configuration
 * @crc_poly_mode: CRC polynomial mode
 *
 * By default, the entire frame is used to calculate the CRC.
 *
@@ -709,7 +710,7 @@ dc_stream_forward_multiple_crc_window(struct dc_stream_state *stream,
 */
bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream,
			     struct crc_params *crc_window, bool enable, bool continuous,
			     uint8_t idx, bool reset)
			     uint8_t idx, bool reset, enum crc_poly_mode crc_poly_mode)
{
	struct pipe_ctx *pipe;
	struct crc_params param;
@@ -733,6 +734,7 @@ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream,
	param.windowb_y_start = 0;
	param.windowb_x_end = pipe->stream->timing.h_addressable;
	param.windowb_y_end = pipe->stream->timing.v_addressable;
	param.crc_poly_mode = crc_poly_mode;

	if (crc_window) {
		param.windowa_x_start = crc_window->windowa_x_start;
+2 −1
Original line number Diff line number Diff line
@@ -584,7 +584,8 @@ bool dc_stream_configure_crc(struct dc *dc,
			     bool enable,
			     bool continuous,
			     uint8_t idx,
			     bool reset);
			     bool reset,
			     enum crc_poly_mode crc_poly_mode);

bool dc_stream_get_crc(struct dc *dc,
		       struct dc_stream_state *stream,
Loading