Commit c4849f88 authored by Mario Limonciello's avatar Mario Limonciello Committed by Alex Deucher
Browse files

drm/amd/display: Revert W/A for hard hangs on DCN20/DCN21



The WA from commit 2a50edbf ("drm/amd/display: Apply w/a for hard hang
on HPD") and commit 1bd3bc74 ("drm/amd/display: Extend w/a for hard
hang on HPD to dcn20") causes a regression in s0ix where the system will
fail to resume properly on many laptops.  Pull the workarounds out to
avoid that s0ix regression in the common case.  This HPD hang happens with
an external device in special circumstances and a new W/A will need to be
developed for this in the future.

Cc: stable@vger.kernel.org
Cc: Qingqing Zhuo <qingqing.zhuo@amd.com>
Reported-by: default avatarScott Bruce <smbruce@gmail.com>
Reported-by: default avatarChris Hixon <linux-kernel-bugs@hixontech.com>
Reported-by: default avatar <spasswolf@web.de>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=215436
Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1821
Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1852


Fixes: 2a50edbf ("drm/amd/display: Apply w/a for hard hang on HPD")
Fixes: 1bd3bc74 ("drm/amd/display: Extend w/a for hard hang on HPD to dcn20")
Reviewed-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: default avatarMario Limonciello <mario.limonciello@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent d82ce3cd
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@
#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) \
@@ -223,8 +222,6 @@ 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;
@@ -242,13 +239,7 @@ 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;

	for (irq_src = DC_IRQ_SOURCE_HPD1; irq_src <= DC_IRQ_SOURCE_HPD6; irq_src++) {
		hpd_state = dc_get_hpd_state_dcn20(dc->res_pool->irqs, irq_src);
		if (hpd_state)
			break;
	}

	if (display_count == 0 && !hpd_state)
	if (display_count == 0)
		enter_display_off = true;

	if (enter_display_off == safe_to_lower) {
+1 −10
Original line number Diff line number Diff line
@@ -42,7 +42,6 @@
#include "clk/clk_10_0_2_sh_mask.h"
#include "renoir_ip_offset.h"

#include "irq/dcn21/irq_service_dcn21.h"

/* Constants */

@@ -129,11 +128,9 @@ static void rn_update_clocks(struct clk_mgr *clk_mgr_base,
	struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
	struct dc *dc = clk_mgr_base->ctx->dc;
	int display_count;
	int irq_src;
	bool update_dppclk = false;
	bool update_dispclk = false;
	bool dpp_clock_lowered = false;
	uint32_t hpd_state;

	struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;

@@ -150,14 +147,8 @@ static void rn_update_clocks(struct clk_mgr *clk_mgr_base,

			display_count = rn_get_active_display_cnt_wa(dc, context);

			for (irq_src = DC_IRQ_SOURCE_HPD1; irq_src <= DC_IRQ_SOURCE_HPD5; irq_src++) {
				hpd_state = dc_get_hpd_state_dcn21(dc->res_pool->irqs, irq_src);
				if (hpd_state)
					break;
			}

			/* if we can go lower, go lower */
			if (display_count == 0 && !hpd_state) {
			if (display_count == 0) {
				rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER);
				/* update power state */
				clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
+0 −25
Original line number Diff line number Diff line
@@ -132,31 +132,6 @@ enum dc_irq_source to_dal_irq_source_dcn20(
	}
}

uint32_t dc_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)
+0 −2
Original line number Diff line number Diff line
@@ -31,6 +31,4 @@
struct irq_service *dal_irq_service_dcn20_create(
	struct irq_service_init_data *init_data);

uint32_t dc_get_hpd_state_dcn20(struct irq_service *irq_service, enum dc_irq_source source);

#endif
+0 −25
Original line number Diff line number Diff line
@@ -134,31 +134,6 @@ static enum dc_irq_source to_dal_irq_source_dcn21(struct irq_service *irq_servic
	return DC_IRQ_SOURCE_INVALID;
}

uint32_t dc_get_hpd_state_dcn21(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)
Loading