drm/amd/display: add functionality to grab DPRX CRC entries.
authorDingchen Zhang <dingchen.zhang@amd.com>
Wed, 15 May 2019 21:15:05 +0000 (17:15 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 18 Jul 2019 19:18:09 +0000 (14:18 -0500)
[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>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h [new file with mode: 0644]

index e1871ad..d0d52c3 100644 (file)
@@ -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);
                }
index b89cbbf..35bee77 100644 (file)
@@ -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
index bc67e65..9af2701 100644 (file)
 #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,13 +81,42 @@ 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);
-       if (!dc_stream_configure_crc(stream_state->ctx->dc, stream_state,
-                                    enable, enable)) {
-               mutex_unlock(&adev->dm.dc_lock);
-               return -EINVAL;
+       /*
+        * 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. */
@@ -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,10 +190,12 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
                return;
        }
 
-       if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state,
-                              &crcs[0], &crcs[1], &crcs[2]))
-               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;
 
-       drm_crtc_add_crc_entry(crtc, true,
-                              drm_crtc_accurate_vblank_count(crtc), crcs);
+               drm_crtc_add_crc_entry(crtc, true,
+                                      drm_crtc_accurate_vblank_count(crtc), crcs);
+       }
 }
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
new file mode 100644 (file)
index 0000000..3793dc8
--- /dev/null
@@ -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_ */