drm/amd/display: refactor hpd logic from dc_link to link_hpd
authorWenjing Liu <wenjing.liu@amd.com>
Sat, 10 Dec 2022 16:40:18 +0000 (11:40 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 13 Jan 2023 19:57:33 +0000 (14:57 -0500)
[why]
Factor out hpd handling logic from generic dc link file.

Tested-by: Daniel Wheeler <Daniel.Wheeler@amd.com>
Reviewed-by: Jun Lei <Jun.Lei@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/inc/link.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/Makefile
drivers/gpu/drm/amd/display/dc/link/link_hpd.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/link/link_hpd.h [new file with mode: 0644]

index ee20b4d..13e33f5 100644 (file)
@@ -36,6 +36,7 @@
 #include "dc_link_dpia.h"
 #include "dc_link_ddc.h"
 #include "link_hwss.h"
+#include "link.h"
 #include "opp.h"
 
 #include "link_encoder.h"
@@ -52,6 +53,7 @@
 #include "inc/link_enc_cfg.h"
 #include "inc/link_dpcd.h"
 #include "link/link_dp_trace.h"
+#include "link/link_hpd.h"
 
 #include "dc/dcn30/dcn30_vpg.h"
 
@@ -102,108 +104,6 @@ static void dc_link_destruct(struct dc_link *link)
                dc_sink_release(link->remote_sinks[i]);
 }
 
-struct gpio *get_hpd_gpio(struct dc_bios *dcb,
-                         struct graphics_object_id link_id,
-                         struct gpio_service *gpio_service)
-{
-       enum bp_result bp_result;
-       struct graphics_object_hpd_info hpd_info;
-       struct gpio_pin_info pin_info;
-
-       if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK)
-               return NULL;
-
-       bp_result = dcb->funcs->get_gpio_pin_info(dcb,
-               hpd_info.hpd_int_gpio_uid, &pin_info);
-
-       if (bp_result != BP_RESULT_OK) {
-               ASSERT(bp_result == BP_RESULT_NORECORD);
-               return NULL;
-       }
-
-       return dal_gpio_service_create_irq(gpio_service,
-                                          pin_info.offset,
-                                          pin_info.mask);
-}
-
-/*
- *  Function: program_hpd_filter
- *
- *  @brief
- *     Programs HPD filter on associated HPD line
- *
- *  @param [in] delay_on_connect_in_ms: Connect filter timeout
- *  @param [in] delay_on_disconnect_in_ms: Disconnect filter timeout
- *
- *  @return
- *     true on success, false otherwise
- */
-static bool program_hpd_filter(const struct dc_link *link)
-{
-       bool result = false;
-       struct gpio *hpd;
-       int delay_on_connect_in_ms = 0;
-       int delay_on_disconnect_in_ms = 0;
-
-       if (link->is_hpd_filter_disabled)
-               return false;
-       /* Verify feature is supported */
-       switch (link->connector_signal) {
-       case SIGNAL_TYPE_DVI_SINGLE_LINK:
-       case SIGNAL_TYPE_DVI_DUAL_LINK:
-       case SIGNAL_TYPE_HDMI_TYPE_A:
-               /* Program hpd filter */
-               delay_on_connect_in_ms = 500;
-               delay_on_disconnect_in_ms = 100;
-               break;
-       case SIGNAL_TYPE_DISPLAY_PORT:
-       case SIGNAL_TYPE_DISPLAY_PORT_MST:
-               /* Program hpd filter to allow DP signal to settle */
-               /* 500: not able to detect MST <-> SST switch as HPD is low for
-                * only 100ms on DELL U2413
-                * 0: some passive dongle still show aux mode instead of i2c
-                * 20-50: not enough to hide bouncing HPD with passive dongle.
-                * also see intermittent i2c read issues.
-                */
-               delay_on_connect_in_ms = 80;
-               delay_on_disconnect_in_ms = 0;
-               break;
-       case SIGNAL_TYPE_LVDS:
-       case SIGNAL_TYPE_EDP:
-       default:
-               /* Don't program hpd filter */
-               return false;
-       }
-
-       /* Obtain HPD handle */
-       hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id,
-                          link->ctx->gpio_service);
-
-       if (!hpd)
-               return result;
-
-       /* Setup HPD filtering */
-       if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
-               struct gpio_hpd_config config;
-
-               config.delay_on_connect = delay_on_connect_in_ms;
-               config.delay_on_disconnect = delay_on_disconnect_in_ms;
-
-               dal_irq_setup_hpd_filter(hpd, &config);
-
-               dal_gpio_close(hpd);
-
-               result = true;
-       } else {
-               ASSERT_CRITICAL(false);
-       }
-
-       /* Release HPD handle */
-       dal_gpio_destroy_irq(&hpd);
-
-       return result;
-}
-
 bool dc_link_wait_for_t12(struct dc_link *link)
 {
        if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->hwss.edp_wait_for_T12) {
@@ -226,7 +126,6 @@ bool dc_link_wait_for_t12(struct dc_link *link)
 bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type)
 {
        uint32_t is_hpd_high = 0;
-       struct gpio *hpd_pin;
 
        if (link->connector_signal == SIGNAL_TYPE_LVDS) {
                *type = dc_connection_single;
@@ -250,17 +149,9 @@ bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type)
                return true;
        }
 
-       /* todo: may need to lock gpio access */
-       hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id,
-                              link->ctx->gpio_service);
-       if (!hpd_pin)
+       if (!query_hpd_status(link, &is_hpd_high))
                goto hpd_gpio_failure;
 
-       dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT);
-       dal_gpio_get_value(hpd_pin, &is_hpd_high);
-       dal_gpio_close(hpd_pin);
-       dal_gpio_destroy_irq(&hpd_pin);
-
        if (is_hpd_high) {
                *type = dc_connection_single;
                /* TODO: need to do the actual detection */
@@ -1367,58 +1258,6 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
        return is_local_sink_detect_success && !is_delegated_to_mst_top_mgr;
 }
 
-bool dc_link_get_hpd_state(struct dc_link *dc_link)
-{
-       uint32_t state;
-
-       dal_gpio_lock_pin(dc_link->hpd_gpio);
-       dal_gpio_get_value(dc_link->hpd_gpio, &state);
-       dal_gpio_unlock_pin(dc_link->hpd_gpio);
-
-       return state;
-}
-
-static enum hpd_source_id get_hpd_line(struct dc_link *link)
-{
-       struct gpio *hpd;
-       enum hpd_source_id hpd_id;
-
-       hpd_id = HPD_SOURCEID_UNKNOWN;
-
-       hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id,
-                          link->ctx->gpio_service);
-
-       if (hpd) {
-               switch (dal_irq_get_source(hpd)) {
-               case DC_IRQ_SOURCE_HPD1:
-                       hpd_id = HPD_SOURCEID1;
-               break;
-               case DC_IRQ_SOURCE_HPD2:
-                       hpd_id = HPD_SOURCEID2;
-               break;
-               case DC_IRQ_SOURCE_HPD3:
-                       hpd_id = HPD_SOURCEID3;
-               break;
-               case DC_IRQ_SOURCE_HPD4:
-                       hpd_id = HPD_SOURCEID4;
-               break;
-               case DC_IRQ_SOURCE_HPD5:
-                       hpd_id = HPD_SOURCEID5;
-               break;
-               case DC_IRQ_SOURCE_HPD6:
-                       hpd_id = HPD_SOURCEID6;
-               break;
-               default:
-                       BREAK_TO_DEBUGGER();
-               break;
-               }
-
-               dal_gpio_destroy_irq(&hpd);
-       }
-
-       return hpd_id;
-}
-
 static enum channel_id get_ddc_line(struct dc_link *link)
 {
        struct ddc *ddc;
@@ -1583,7 +1422,7 @@ static bool dc_link_construct_legacy(struct dc_link *link,
        if (link->dc->res_pool->funcs->link_init)
                link->dc->res_pool->funcs->link_init(link);
 
-       link->hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id,
+       link->hpd_gpio = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
                                      link->ctx->gpio_service);
 
        if (link->hpd_gpio) {
@@ -4531,51 +4370,6 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
        dc->hwss.set_avmute(pipe_ctx, enable);
 }
 
-/**
- *  dc_link_enable_hpd_filter:
- *     If enable is true, programs HPD filter on associated HPD line using
- *     delay_on_disconnect/delay_on_connect values dependent on
- *     link->connector_signal
- *
- *     If enable is false, programs HPD filter on associated HPD line with no
- *     delays on connect or disconnect
- *
- *  @link:   pointer to the dc link
- *  @enable: boolean specifying whether to enable hbd
- */
-void dc_link_enable_hpd_filter(struct dc_link *link, bool enable)
-{
-       struct gpio *hpd;
-
-       if (enable) {
-               link->is_hpd_filter_disabled = false;
-               program_hpd_filter(link);
-       } else {
-               link->is_hpd_filter_disabled = true;
-               /* Obtain HPD handle */
-               hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
-
-               if (!hpd)
-                       return;
-
-               /* Setup HPD filtering */
-               if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
-                       struct gpio_hpd_config config;
-
-                       config.delay_on_connect = 0;
-                       config.delay_on_disconnect = 0;
-
-                       dal_irq_setup_hpd_filter(hpd, &config);
-
-                       dal_gpio_close(hpd);
-               } else {
-                       ASSERT_CRITICAL(false);
-               }
-               /* Release HPD handle */
-               dal_gpio_destroy_irq(&hpd);
-       }
-}
-
 void dc_link_set_drive_settings(struct dc *dc,
                                struct link_training_settings *lt_settings,
                                const struct dc_link *link)
@@ -4663,16 +4457,6 @@ void dc_link_set_preferred_training_settings(struct dc *dc,
                dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link);
 }
 
-void dc_link_enable_hpd(const struct dc_link *link)
-{
-       dc_link_dp_enable_hpd(link);
-}
-
-void dc_link_disable_hpd(const struct dc_link *link)
-{
-       dc_link_dp_disable_hpd(link);
-}
-
 void dc_link_set_test_pattern(struct dc_link *link,
                              enum dp_test_pattern test_pattern,
                              enum dp_test_pattern_color_space test_pattern_color_space,
index d74ffc8..5194559 100644 (file)
@@ -5866,22 +5866,6 @@ void detect_edp_sink_caps(struct dc_link *link)
                        sizeof(link->dpcd_caps.alpm_caps.raw));
 }
 
-void dc_link_dp_enable_hpd(const struct dc_link *link)
-{
-       struct link_encoder *encoder = link->link_enc;
-
-       if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
-               encoder->funcs->enable_hpd(encoder);
-}
-
-void dc_link_dp_disable_hpd(const struct dc_link *link)
-{
-       struct link_encoder *encoder = link->link_enc;
-
-       if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
-               encoder->funcs->disable_hpd(encoder);
-}
-
 static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern)
 {
        if ((DP_TEST_PATTERN_PHY_PATTERN_BEGIN <= test_pattern &&
index 1226ecb..fbd6f11 100644 (file)
@@ -479,10 +479,6 @@ enum link_training_result dc_link_dp_sync_lt_attempt(
 
 bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down);
 
-void dc_link_dp_enable_hpd(const struct dc_link *link);
-
-void dc_link_dp_disable_hpd(const struct dc_link *link);
-
 bool dc_link_dp_set_test_pattern(
        struct dc_link *link,
        enum dp_test_pattern test_pattern,
@@ -493,6 +489,21 @@ bool dc_link_dp_set_test_pattern(
 
 bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap);
 
+/**
+ *****************************************************************************
+ *  Function: dc_link_enable_hpd_filter
+ *
+ *  @brief
+ *     If enable is true, programs HPD filter on associated HPD line to default
+ *     values dependent on link->connector_signal
+ *
+ *     If enable is false, programs HPD filter on associated HPD line with no
+ *     delays on connect or disconnect
+ *
+ *  @param [in] link: pointer to the dc link
+ *  @param [in] enable: boolean specifying whether to enable hbd
+ *****************************************************************************
+ */
 void dc_link_enable_hpd_filter(struct dc_link *link, bool enable);
 
 bool dc_link_is_dp_sink_present(struct dc_link *link);
@@ -565,9 +576,6 @@ void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map);
 /* restore link resource allocation state from a snapshot */
 void dc_restore_link_res_map(const struct dc *dc, uint32_t *map);
 void dc_link_clear_dprx_states(struct dc_link *link);
-struct gpio *get_hpd_gpio(struct dc_bios *dcb,
-               struct graphics_object_id link_id,
-               struct gpio_service *gpio_service);
 void dp_trace_reset(struct dc_link *link);
 bool dc_dp_trace_is_initialized(struct dc_link *link);
 unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link,
index 16e3b07..358431f 100644 (file)
@@ -46,6 +46,7 @@
 #include "link_encoder.h"
 #include "link_enc_cfg.h"
 #include "link_hwss.h"
+#include "link.h"
 #include "dc_link_dp.h"
 #include "dccg.h"
 #include "clock_source.h"
@@ -737,7 +738,7 @@ void dce110_edp_wait_for_hpd_ready(
 
        /* obtain HPD */
        /* TODO what to do with this? */
-       hpd = get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service);
+       hpd = link_get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service);
 
        if (!hpd) {
                BREAK_TO_DEBUGGER();
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link.h b/drivers/gpu/drm/amd/display/dc/inc/link.h
new file mode 100644 (file)
index 0000000..51ddf7a
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2022 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 __DC_LINK_H__
+#define __DC_LINK_H__
+
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ * This header declares link functions exposed to dc. All functions must have
+ * "link_" as prefix. For example link_run_my_function. This header is strictly
+ * private in dc and should never be included in other header files. dc
+ * components should include this header in their .c files in order to access
+ * functions in link folder. This file should never include any header files in
+ * link folder. If there is a need to expose a function declared in one of
+ * header files in side link folder, you need to move the function declaration
+ * into this file and prefix it with "link_".
+ */
+#include "core_types.h"
+#include "dc_link.h"
+
+struct gpio *link_get_hpd_gpio(struct dc_bios *dcb,
+               struct graphics_object_id link_id,
+               struct gpio_service *gpio_service);
+
+#endif /* __DC_LINK_HPD_H__ */
index 054c2a7..835a2fe 100644 (file)
@@ -23,7 +23,8 @@
 # It abstracts the control and status of back end pipe such as DIO, HPO, DPIA,
 # PHY, HPD, DDC and etc).
 
-LINK = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o link_dp_trace.o
+LINK = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o link_dp_trace.o \
+link_hpd.o
 
 AMD_DAL_LINK = $(addprefix $(AMDDALPATH)/dc/link/,$(LINK))
 
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hpd.c b/drivers/gpu/drm/amd/display/dc/link/link_hpd.c
new file mode 100644 (file)
index 0000000..5f39dfe
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2022 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
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ * This file implements functions that manage basic HPD components such as gpio.
+ * It also provides wrapper functions to execute HPD related programming. This
+ * file only manages basic HPD functionality. It doesn't manage detection or
+ * feature or signal specific HPD behaviors.
+ */
+#include "link_hpd.h"
+#include "gpio_service_interface.h"
+
+bool dc_link_get_hpd_state(struct dc_link *dc_link)
+{
+       uint32_t state;
+
+       dal_gpio_lock_pin(dc_link->hpd_gpio);
+       dal_gpio_get_value(dc_link->hpd_gpio, &state);
+       dal_gpio_unlock_pin(dc_link->hpd_gpio);
+
+       return state;
+}
+
+void dc_link_enable_hpd(const struct dc_link *link)
+{
+       struct link_encoder *encoder = link->link_enc;
+
+       if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
+               encoder->funcs->enable_hpd(encoder);
+}
+
+void dc_link_disable_hpd(const struct dc_link *link)
+{
+       struct link_encoder *encoder = link->link_enc;
+
+       if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
+               encoder->funcs->disable_hpd(encoder);
+}
+
+void dc_link_enable_hpd_filter(struct dc_link *link, bool enable)
+{
+       struct gpio *hpd;
+
+       if (enable) {
+               link->is_hpd_filter_disabled = false;
+               program_hpd_filter(link);
+       } else {
+               link->is_hpd_filter_disabled = true;
+               /* Obtain HPD handle */
+               hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
+
+               if (!hpd)
+                       return;
+
+               /* Setup HPD filtering */
+               if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
+                       struct gpio_hpd_config config;
+
+                       config.delay_on_connect = 0;
+                       config.delay_on_disconnect = 0;
+
+                       dal_irq_setup_hpd_filter(hpd, &config);
+
+                       dal_gpio_close(hpd);
+               } else {
+                       ASSERT_CRITICAL(false);
+               }
+               /* Release HPD handle */
+               dal_gpio_destroy_irq(&hpd);
+       }
+}
+
+struct gpio *link_get_hpd_gpio(struct dc_bios *dcb,
+                         struct graphics_object_id link_id,
+                         struct gpio_service *gpio_service)
+{
+       enum bp_result bp_result;
+       struct graphics_object_hpd_info hpd_info;
+       struct gpio_pin_info pin_info;
+
+       if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK)
+               return NULL;
+
+       bp_result = dcb->funcs->get_gpio_pin_info(dcb,
+               hpd_info.hpd_int_gpio_uid, &pin_info);
+
+       if (bp_result != BP_RESULT_OK) {
+               ASSERT(bp_result == BP_RESULT_NORECORD);
+               return NULL;
+       }
+
+       return dal_gpio_service_create_irq(gpio_service,
+                                          pin_info.offset,
+                                          pin_info.mask);
+}
+
+bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high)
+{
+       struct gpio *hpd_pin = link_get_hpd_gpio(
+                       link->ctx->dc_bios, link->link_id,
+                       link->ctx->gpio_service);
+       if (!hpd_pin)
+               return false;
+
+       dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT);
+       dal_gpio_get_value(hpd_pin, is_hpd_high);
+       dal_gpio_close(hpd_pin);
+       dal_gpio_destroy_irq(&hpd_pin);
+       return true;
+}
+
+enum hpd_source_id get_hpd_line(struct dc_link *link)
+{
+       struct gpio *hpd;
+       enum hpd_source_id hpd_id;
+
+               hpd_id = HPD_SOURCEID_UNKNOWN;
+
+       hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
+                          link->ctx->gpio_service);
+
+       if (hpd) {
+               switch (dal_irq_get_source(hpd)) {
+               case DC_IRQ_SOURCE_HPD1:
+                       hpd_id = HPD_SOURCEID1;
+               break;
+               case DC_IRQ_SOURCE_HPD2:
+                       hpd_id = HPD_SOURCEID2;
+               break;
+               case DC_IRQ_SOURCE_HPD3:
+                       hpd_id = HPD_SOURCEID3;
+               break;
+               case DC_IRQ_SOURCE_HPD4:
+                       hpd_id = HPD_SOURCEID4;
+               break;
+               case DC_IRQ_SOURCE_HPD5:
+                       hpd_id = HPD_SOURCEID5;
+               break;
+               case DC_IRQ_SOURCE_HPD6:
+                       hpd_id = HPD_SOURCEID6;
+               break;
+               default:
+                       BREAK_TO_DEBUGGER();
+               break;
+               }
+
+               dal_gpio_destroy_irq(&hpd);
+       }
+
+       return hpd_id;
+}
+
+bool program_hpd_filter(const struct dc_link *link)
+{
+       bool result = false;
+       struct gpio *hpd;
+       int delay_on_connect_in_ms = 0;
+       int delay_on_disconnect_in_ms = 0;
+
+       if (link->is_hpd_filter_disabled)
+               return false;
+       /* Verify feature is supported */
+       switch (link->connector_signal) {
+       case SIGNAL_TYPE_DVI_SINGLE_LINK:
+       case SIGNAL_TYPE_DVI_DUAL_LINK:
+       case SIGNAL_TYPE_HDMI_TYPE_A:
+               /* Program hpd filter */
+               delay_on_connect_in_ms = 500;
+               delay_on_disconnect_in_ms = 100;
+               break;
+       case SIGNAL_TYPE_DISPLAY_PORT:
+       case SIGNAL_TYPE_DISPLAY_PORT_MST:
+               /* Program hpd filter to allow DP signal to settle */
+               /* 500: not able to detect MST <-> SST switch as HPD is low for
+                * only 100ms on DELL U2413
+                * 0: some passive dongle still show aux mode instead of i2c
+                * 20-50: not enough to hide bouncing HPD with passive dongle.
+                * also see intermittent i2c read issues.
+                */
+               delay_on_connect_in_ms = 80;
+               delay_on_disconnect_in_ms = 0;
+               break;
+       case SIGNAL_TYPE_LVDS:
+       case SIGNAL_TYPE_EDP:
+       default:
+               /* Don't program hpd filter */
+               return false;
+       }
+
+       /* Obtain HPD handle */
+       hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
+                          link->ctx->gpio_service);
+
+       if (!hpd)
+               return result;
+
+       /* Setup HPD filtering */
+       if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
+               struct gpio_hpd_config config;
+
+               config.delay_on_connect = delay_on_connect_in_ms;
+               config.delay_on_disconnect = delay_on_disconnect_in_ms;
+
+               dal_irq_setup_hpd_filter(hpd, &config);
+
+               dal_gpio_close(hpd);
+
+               result = true;
+       } else {
+               ASSERT_CRITICAL(false);
+       }
+
+       /* Release HPD handle */
+       dal_gpio_destroy_irq(&hpd);
+
+       return result;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hpd.h b/drivers/gpu/drm/amd/display/dc/link/link_hpd.h
new file mode 100644 (file)
index 0000000..3d122de
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2022 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 __DC_LINK_HPD_H__
+#define __DC_LINK_HPD_H__
+#include "link.h"
+
+enum hpd_source_id get_hpd_line(struct dc_link *link);
+/*
+ *  Function: program_hpd_filter
+ *
+ *  @brief
+ *     Programs HPD filter on associated HPD line to default values.
+ *
+ *  @return
+ *     true on success, false otherwise
+ */
+bool program_hpd_filter(const struct dc_link *link);
+/* Query hot plug status of USB4 DP tunnel.
+ * Returns true if HPD high.
+ */
+bool dpia_query_hpd_status(struct dc_link *link);
+bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high);
+#endif /* __DC_LINK_HPD_H__ */