summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQingqing Zhuo <qingqing.zhuo@amd.com>2021-08-25 12:29:28 -0400
committerAlex Deucher <alexander.deucher@amd.com>2021-09-23 15:17:30 -0400
commit1bd3bc745e7f02f471fbf6e3f5f2ac5d788c9f39 (patch)
tree88325c2dddf290fd58778be4f78647f20918d36f
parenta62427ef9b55d4b5aec2b08dc9b2d9719572bf57 (diff)
downloadlinux-1bd3bc745e7f02f471fbf6e3f5f2ac5d788c9f39.tar.gz
linux-1bd3bc745e7f02f471fbf6e3f5f2ac5d788c9f39.tar.bz2
linux-1bd3bc745e7f02f471fbf6e3f5f2ac5d788c9f39.zip
drm/amd/display: Extend w/a for hard hang on HPD to dcn20
[Why] HPD disable and enable sequences are not mutually exclusive on Linux. For HPDs that spans under 1s (i.e. HPD low = 1s), part of the disable sequence (specifically, a request to SMU to lower refclk) could come right before the call to PHY enablement, causing DMUB to access an irresponsive PHY and thus a hard hang on the system. [How] Disable 48mhz refclk off when there is any HPD status in connected state for dcn20. Reviewed-by: Hersen Wu <hersenxs.wu@amd.com> Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com> Signed-off-by: Qingqing Zhuo <qingqing.zhuo@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c12
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c25
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h2
3 files changed, 38 insertions, 1 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
index 0d01aa9f15a6..315466f5aade 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
@@ -38,6 +38,8 @@
#include "clk/clk_11_0_0_offset.h"
#include "clk/clk_11_0_0_sh_mask.h"
+#include "irq/dcn20/irq_service_dcn20.h"
+
#undef FN
#define FN(reg_name, field_name) \
clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name
@@ -221,6 +223,8 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base,
bool force_reset = false;
bool p_state_change_support;
int total_plane_count;
+ int irq_src;
+ uint32_t hpd_state;
if (dc->work_arounds.skip_clock_update)
return;
@@ -238,7 +242,13 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base,
if (dc->res_pool->pp_smu)
pp_smu = &dc->res_pool->pp_smu->nv_funcs;
- if (display_count == 0)
+ for (irq_src = DC_IRQ_SOURCE_HPD1; irq_src <= DC_IRQ_SOURCE_HPD6; irq_src++) {
+ hpd_state = dal_get_hpd_state_dcn20(dc->res_pool->irqs, irq_src);
+ if (hpd_state)
+ break;
+ }
+
+ if (display_count == 0 && !hpd_state)
enter_display_off = true;
if (enter_display_off == safe_to_lower) {
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
index c4b067d01895..49d87fe5c167 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
@@ -132,6 +132,31 @@ enum dc_irq_source to_dal_irq_source_dcn20(
}
}
+uint32_t dal_get_hpd_state_dcn20(struct irq_service *irq_service, enum dc_irq_source source)
+{
+ const struct irq_source_info *info;
+ uint32_t addr;
+ uint32_t value;
+ uint32_t current_status;
+
+ info = find_irq_source_info(irq_service, source);
+ if (!info)
+ return 0;
+
+ addr = info->status_reg;
+ if (!addr)
+ return 0;
+
+ value = dm_read_reg(irq_service->ctx, addr);
+ current_status =
+ get_reg_field_value(
+ value,
+ HPD0_DC_HPD_INT_STATUS,
+ DC_HPD_SENSE);
+
+ return current_status;
+}
+
static bool hpd_ack(
struct irq_service *irq_service,
const struct irq_source_info *info)
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h
index aee4b37999f1..f60a203e7188 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h
@@ -31,4 +31,6 @@
struct irq_service *dal_irq_service_dcn20_create(
struct irq_service_init_data *init_data);
+uint32_t dal_get_hpd_state_dcn20(struct irq_service *irq_service, enum dc_irq_source source);
+
#endif