forked from Minki/linux
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: Dingchen Zhang <dingchen.zhang@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
2425347697
commit
14b2584636
@ -3665,7 +3665,7 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
|
|||||||
state->abm_level = cur->abm_level;
|
state->abm_level = cur->abm_level;
|
||||||
state->vrr_supported = cur->vrr_supported;
|
state->vrr_supported = cur->vrr_supported;
|
||||||
state->freesync_config = cur->freesync_config;
|
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_has_degamma = cur->cm_has_degamma;
|
||||||
state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;
|
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 *crtc;
|
||||||
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
||||||
int i;
|
int i;
|
||||||
|
enum amdgpu_dm_pipe_crc_source source;
|
||||||
|
|
||||||
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
|
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
|
||||||
new_crtc_state, i) {
|
new_crtc_state, i) {
|
||||||
@ -6000,9 +6001,13 @@ static void amdgpu_dm_enable_crtc_interrupts(struct drm_device *dev,
|
|||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
/* The stream has changed so CRC capture needs to re-enabled. */
|
/* The stream has changed so CRC capture needs to re-enabled. */
|
||||||
if (dm_new_crtc_state->crc_enabled) {
|
source = dm_new_crtc_state->crc_src;
|
||||||
dm_new_crtc_state->crc_enabled = false;
|
if (amdgpu_dm_is_valid_crc_source(source)) {
|
||||||
amdgpu_dm_crtc_set_crc_source(crtc, "auto");
|
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
|
#endif
|
||||||
}
|
}
|
||||||
@ -6058,7 +6063,7 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
|
|||||||
* Drop the extra vblank reference added by CRC
|
* Drop the extra vblank reference added by CRC
|
||||||
* capture if applicable.
|
* 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);
|
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.
|
* still a stream for the CRTC.
|
||||||
*/
|
*/
|
||||||
if (!dm_new_crtc_state->stream)
|
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);
|
manage_dm_interrupts(adev, acrtc, false);
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
|
|
||||||
#include "irq_types.h"
|
#include "irq_types.h"
|
||||||
#include "signal_types.h"
|
#include "signal_types.h"
|
||||||
|
#include "amdgpu_dm_crc.h"
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
struct amdgpu_device;
|
struct amdgpu_device;
|
||||||
@ -313,7 +314,7 @@ struct dm_crtc_state {
|
|||||||
bool interrupts_enabled;
|
bool interrupts_enabled;
|
||||||
|
|
||||||
int crc_skip_count;
|
int crc_skip_count;
|
||||||
bool crc_enabled;
|
enum amdgpu_dm_pipe_crc_source crc_src;
|
||||||
|
|
||||||
bool freesync_timing_changed;
|
bool freesync_timing_changed;
|
||||||
bool freesync_vrr_info_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,
|
void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
|
||||||
struct edid *edid);
|
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
|
#define MAX_COLOR_LUT_ENTRIES 4096
|
||||||
/* Legacy gamm LUT users such as X doesn't like large LUT sizes */
|
/* Legacy gamm LUT users such as X doesn't like large LUT sizes */
|
||||||
#define MAX_COLOR_LEGACY_LUT_ENTRIES 256
|
#define MAX_COLOR_LEGACY_LUT_ENTRIES 256
|
||||||
|
@ -30,19 +30,14 @@
|
|||||||
#include "amdgpu_dm.h"
|
#include "amdgpu_dm.h"
|
||||||
#include "dc.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)
|
static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
|
||||||
{
|
{
|
||||||
if (!source || !strcmp(source, "none"))
|
if (!source || !strcmp(source, "none"))
|
||||||
return AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
|
return AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
|
||||||
if (!strcmp(source, "auto"))
|
if (!strcmp(source, "auto") || !strcmp(source, "crtc"))
|
||||||
return AMDGPU_DM_PIPE_CRC_SOURCE_AUTO;
|
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;
|
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 amdgpu_device *adev = crtc->dev->dev_private;
|
||||||
struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state);
|
struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state);
|
||||||
struct dc_stream_state *stream_state = crtc_state->stream;
|
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);
|
enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);
|
||||||
|
|
||||||
@ -83,13 +81,42 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
enable = (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO);
|
enable = amdgpu_dm_is_valid_crc_source(source);
|
||||||
|
|
||||||
mutex_lock(&adev->dm.dc_lock);
|
mutex_lock(&adev->dm.dc_lock);
|
||||||
if (!dc_stream_configure_crc(stream_state->ctx->dc, stream_state,
|
/*
|
||||||
enable, enable)) {
|
* USER REQ SRC | CURRENT SRC | BEHAVIOR
|
||||||
mutex_unlock(&adev->dm.dc_lock);
|
* -----------------------------
|
||||||
return -EINVAL;
|
* 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. */
|
/* When enabling CRC, we should also disable dithering. */
|
||||||
@ -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
|
* Reading the CRC requires the vblank interrupt handler to be
|
||||||
* enabled. Keep a reference until CRC capture stops.
|
* 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);
|
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);
|
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 */
|
/* Reset crc_skipped on dm state */
|
||||||
crtc_state->crc_skip_count = 0;
|
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;
|
stream_state = crtc_state->stream;
|
||||||
|
|
||||||
/* Early return if CRC capture is not enabled. */
|
/* 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;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -149,10 +190,12 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state,
|
if (crtc_state->crc_src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC) {
|
||||||
&crcs[0], &crcs[1], &crcs[2]))
|
if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state,
|
||||||
return;
|
&crcs[0], &crcs[1], &crcs[2]))
|
||||||
|
return;
|
||||||
|
|
||||||
drm_crtc_add_crc_entry(crtc, true,
|
drm_crtc_add_crc_entry(crtc, true,
|
||||||
drm_crtc_accurate_vblank_count(crtc), crcs);
|
drm_crtc_accurate_vblank_count(crtc), crcs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
56
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
Normal file
56
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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_ */
|
Loading…
Reference in New Issue
Block a user