From: Nicholas Kazlauskas <nicholas.kazlaus...@amd.com>

[Why]
We can hang in IPS2 checking DMCUB_SCRATCH0 for link detection state.

[How]
Replace the HW access with a check on the shared state bit. This will
work the same way as the SCRATCH0 but won't require a wake in the case
where link detection isn't required.

Reviewed-by: Duncan Ma <duncan...@amd.com>
Acked-by: Wayne Lin <wayne....@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlaus...@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c  | 30 +++++++++++++++++++
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h  | 10 +++++++
 drivers/gpu/drm/amd/display/dmub/dmub_srv.h   |  1 +
 .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h   | 15 +++++++++-
 .../gpu/drm/amd/display/dmub/src/dmub_srv.c   |  2 ++
 5 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c 
b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index 33d3307f5c1c..364ef9ae32f1 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -1460,6 +1460,36 @@ void dc_dmub_srv_set_power_state(struct dc_dmub_srv 
*dc_dmub_srv, enum dc_acpi_c
                dmub_srv_set_power_state(dmub, DMUB_POWER_STATE_D3);
 }
 
+bool dc_dmub_srv_should_detect(struct dc_dmub_srv *dc_dmub_srv)
+{
+       volatile const struct dmub_shared_state_ips_fw *ips_fw;
+       bool reallow_idle = false, should_detect = false;
+
+       if (!dc_dmub_srv || !dc_dmub_srv->dmub)
+               return false;
+
+       if (dc_dmub_srv->dmub->shared_state &&
+           
dc_dmub_srv->dmub->meta_info.feature_bits.bits.shared_state_link_detection) {
+               ips_fw = 
&dc_dmub_srv->dmub->shared_state[DMUB_SHARED_SHARE_FEATURE__IPS_FW].data.ips_fw;
+               return ips_fw->signals.bits.detection_required;
+       }
+
+       /* Detection may require reading scratch 0 - exit out of idle prior to 
the read. */
+       if (dc_dmub_srv->idle_allowed) {
+               
dc_dmub_srv_apply_idle_power_optimizations(dc_dmub_srv->ctx->dc, false);
+               reallow_idle = true;
+       }
+
+       should_detect = dmub_srv_should_detect(dc_dmub_srv->dmub);
+
+       /* Re-enter idle if we're not about to immediately redetect links. */
+       if (!should_detect && reallow_idle && dc_dmub_srv->idle_exit_counter == 
0 &&
+           !dc_dmub_srv->ctx->dc->debug.disable_dmub_reallow_idle)
+               
dc_dmub_srv_apply_idle_power_optimizations(dc_dmub_srv->ctx->dc, true);
+
+       return should_detect;
+}
+
 void dc_dmub_srv_apply_idle_power_optimizations(const struct dc *dc, bool 
allow_idle)
 {
        struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h 
b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
index 3297c5b33265..580940222777 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
@@ -111,6 +111,16 @@ void dc_dmub_srv_apply_idle_power_optimizations(const 
struct dc *dc, bool allow_
 
 void dc_dmub_srv_set_power_state(struct dc_dmub_srv *dc_dmub_srv, enum 
dc_acpi_cm_power_state powerState);
 
+/**
+ * @dc_dmub_srv_should_detect() - Checks if link detection is required.
+ *
+ * While in idle power states we may need driver to manually redetect in
+ * the case of a missing hotplug. Should be called from a polling timer.
+ *
+ * Return: true if redetection is required.
+ */
+bool dc_dmub_srv_should_detect(struct dc_dmub_srv *dc_dmub_srv);
+
 /**
  * dc_wake_and_execute_dmub_cmd() - Wrapper for DMUB command execution.
  *
diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h 
b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
index cec8aa1face5..cd51c91a822b 100644
--- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
@@ -529,6 +529,7 @@ struct dmub_srv {
        uint32_t psp_version;
 
        /* Feature capabilities reported by fw */
+       struct dmub_fw_meta_info meta_info;
        struct dmub_feature_caps feature_caps;
        struct dmub_visual_confirm_color visual_confirm_color;
 
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h 
b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index 7a0574e6c129..35096aa3d85b 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -496,6 +496,17 @@ struct dmub_visual_confirm_color {
 /* Offset from the end of the file to the dmub_fw_meta_info */
 #define DMUB_FW_META_OFFSET 0x24
 
+/**
+ * union dmub_fw_meta_feature_bits - Static feature bits for pre-initialization
+ */
+union dmub_fw_meta_feature_bits {
+       struct {
+               uint32_t shared_state_link_detection : 1; /**< 1 supports link 
detection via shared state */
+               uint32_t reserved : 31;
+       } bits; /**< status bits */
+       uint32_t all; /**< 32-bit access to status bits */
+};
+
 /**
  * struct dmub_fw_meta_info - metadata associated with fw binary
  *
@@ -521,6 +532,7 @@ struct dmub_fw_meta_info {
        uint32_t shared_state_size; /**< size of the shared state region in 
bytes */
        uint16_t shared_state_features; /**< number of shared state features */
        uint16_t reserved2; /**< padding bytes */
+       union dmub_fw_meta_feature_bits feature_bits; /**< static feature bits 
*/
 };
 
 /**
@@ -698,7 +710,8 @@ union dmub_shared_state_ips_fw_signals {
                uint32_t ips1_commit : 1;  /**< 1 if in IPS1 */
                uint32_t ips2_commit : 1; /**< 1 if in IPS2 */
                uint32_t in_idle : 1; /**< 1 if DMCUB is in idle */
-               uint32_t reserved_bits : 29; /**< Reversed */
+               uint32_t detection_required : 1; /**< 1 if detection is 
required */
+               uint32_t reserved_bits : 28; /**< Reversed */
        } bits;
        uint32_t all;
 };
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c 
b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
index 9bb4c51b1f5b..db16066bc893 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
@@ -510,6 +510,8 @@ enum dmub_status
        fw_info = dmub_get_fw_meta_info(params);
 
        if (fw_info) {
+               memcpy(&dmub->meta_info, fw_info, sizeof(*fw_info));
+
                fw_state_size = fw_info->fw_region_size;
                trace_buffer_size = fw_info->trace_buffer_size;
 
-- 
2.37.3

Reply via email to