Commit 1bd3bc74 authored by Qingqing Zhuo's avatar Qingqing Zhuo Committed by Alex Deucher
Browse files

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: default avatarHersen Wu <hersenxs.wu@amd.com>
Acked-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: default avatarQingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent a62427ef
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -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) {
+25 −0
Original line number Diff line number Diff line
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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