From: Nicholas Kazlauskas <nicholas.kazlauskas@xxxxxxx> [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.ma@xxxxxxx> Acked-by: Wayne Lin <wayne.lin@xxxxxxx> Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@xxxxxxx> --- 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