AMD-GFX Archive on lore.kernel.org
 help / color / Atom feed
From: Aurabindo Pillai <aurabindo.pillai@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: Dingchen Zhang <Dingchen.Zhang@amd.com>,
	Eryk.Brol@amd.com, Sunpeng.Li@amd.com, Harry.Wentland@amd.com,
	Qingqing.Zhuo@amd.com, Rodrigo.Siqueira@amd.com,
	Anson.Jacob@amd.com, Aurabindo.Pillai@amd.com,
	Bhawanpreet.Lakha@amd.com, bindu.r@amd.com
Subject: [PATCH 14/19] drm/amd/display: fix HDCP drm prop update for MST
Date: Fri, 16 Apr 2021 10:34:12 -0400
Message-ID: <20210416143417.611019-15-aurabindo.pillai@amd.com> (raw)
In-Reply-To: <20210416143417.611019-1-aurabindo.pillai@amd.com>

From: "Dingchen (David) Zhang" <dingchen.zhang@amd.com>

[why]
For MST topology with 1 physical link and multiple connectors (>=2),
e.g. daisy cahined MST + SST, or 1-to-multi MST hub, if userspace
set to enable the HDCP simultaneously on all connected outputs, the
commit tail iteratively call the hdcp_update_display() for each
display (connector). However, the hdcp workqueue data structure for
each link has only one DM connector and encryption status members,
which means the work queue of property_validate/update() would only
be triggered for the last connector within this physical link, and
therefore the HDCP property value of other connectors would stay on
DESIRED instead of switching to ENABLED, which is NOT as expected.

[how]
Use array of MAX_NUM_OF_DISPLAY for both aconnector and encryption
status in hdcp workqueue data structure for each physical link.
For property validate/update work queue, we iterates over the array
and do similar operation/check for each connected display.

Signed-off-by: Dingchen (David) Zhang <dingchen.zhang@amd.com>
Reviewed-by: Dingchen Zhang <Dingchen.Zhang@amd.com>
Acked-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c    | 109 +++++++++++++-----
 .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.h    |   6 +-
 2 files changed, 81 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
index 50f6b3a86931..2ec076af9e89 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
@@ -171,9 +171,10 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
 	struct mod_hdcp_display *display = &hdcp_work[link_index].display;
 	struct mod_hdcp_link *link = &hdcp_work[link_index].link;
 	struct mod_hdcp_display_query query;
+	unsigned int conn_index = aconnector->base.index;
 
 	mutex_lock(&hdcp_w->mutex);
-	hdcp_w->aconnector = aconnector;
+	hdcp_w->aconnector[conn_index] = aconnector;
 
 	query.display = NULL;
 	mod_hdcp_query_display(&hdcp_w->hdcp, aconnector->base.index, &query);
@@ -205,7 +206,7 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
 					      msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS));
 		} else {
 			display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
-			hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+			hdcp_w->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
 			cancel_delayed_work(&hdcp_w->property_validate_dwork);
 		}
 
@@ -224,9 +225,10 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
 {
 	struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
 	struct drm_connector_state *conn_state = aconnector->base.state;
+	unsigned int conn_index = aconnector->base.index;
 
 	mutex_lock(&hdcp_w->mutex);
-	hdcp_w->aconnector = aconnector;
+	hdcp_w->aconnector[conn_index] = aconnector;
 
 	/* the removal of display will invoke auth reset -> hdcp destroy and
 	 * we'd expect the CP prop changed back to DESIRED if at the time ENABLED.
@@ -247,13 +249,16 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
 void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
 {
 	struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
+	unsigned int conn_index;
 
 	mutex_lock(&hdcp_w->mutex);
 
 	mod_hdcp_reset_connection(&hdcp_w->hdcp,  &hdcp_w->output);
 
 	cancel_delayed_work(&hdcp_w->property_validate_dwork);
-	hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+
+	for (conn_index = 0; conn_index < MAX_NUM_OF_DISPLAYS; ++conn_index)
+		hdcp_w->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
 
 	process_output(hdcp_w);
 
@@ -290,38 +295,67 @@ static void event_callback(struct work_struct *work)
 
 
 }
+
+static struct amdgpu_dm_connector *find_first_connected_output(struct hdcp_workqueue *hdcp_work)
+{
+	unsigned int conn_index;
+
+	for (conn_index = 0; conn_index < MAX_NUM_OF_DISPLAYS; ++conn_index) {
+		if (hdcp_work->aconnector[conn_index])
+			return hdcp_work->aconnector[conn_index];
+	}
+
+	return NULL;
+}
+
 static void event_property_update(struct work_struct *work)
 {
 
 	struct hdcp_workqueue *hdcp_work = container_of(work, struct hdcp_workqueue, property_update_work);
-	struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector;
-	struct drm_device *dev = hdcp_work->aconnector->base.dev;
+	struct amdgpu_dm_connector *aconnector = find_first_connected_output(hdcp_work);
+	struct drm_device *dev;
 	long ret;
+	unsigned int conn_index;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+
+	if (!aconnector)
+		return;
+
+	dev = aconnector->base.dev;
 
 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
 	mutex_lock(&hdcp_work->mutex);
 
+	for (conn_index = 0; conn_index < MAX_NUM_OF_DISPLAYS; ++conn_index) {
+		aconnector = hdcp_work->aconnector[conn_index];
+
+		if (!aconnector)
+			continue;
 
-	if (aconnector->base.state->commit) {
-		ret = wait_for_completion_interruptible_timeout(&aconnector->base.state->commit->hw_done, 10 * HZ);
+		connector = &aconnector->base;
+		conn_state = aconnector->base.state;
+		if (conn_state->commit) {
+			ret = wait_for_completion_interruptible_timeout(&conn_state->commit->hw_done, 10 * HZ);
 
-		if (ret == 0) {
-			DRM_ERROR("HDCP state unknown! Setting it to DESIRED");
-			hdcp_work->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+			if (ret == 0) {
+				DRM_ERROR("HDCP state unknown! Setting it to DESIRED");
+				hdcp_work->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+			}
 		}
-	}
 
-	if (hdcp_work->encryption_status != MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) {
-		if (aconnector->base.state->hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE0 &&
-		    hdcp_work->encryption_status <= MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON)
-			drm_hdcp_update_content_protection(&aconnector->base, DRM_MODE_CONTENT_PROTECTION_ENABLED);
-		else if (aconnector->base.state->hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE1 &&
-			 hdcp_work->encryption_status == MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON)
-			drm_hdcp_update_content_protection(&aconnector->base, DRM_MODE_CONTENT_PROTECTION_ENABLED);
-	} else {
-		drm_hdcp_update_content_protection(&aconnector->base, DRM_MODE_CONTENT_PROTECTION_DESIRED);
-	}
+		if (hdcp_work->encryption_status[conn_index] != MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) {
+			if (conn_state->hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE0 &&
+			    hdcp_work->encryption_status[conn_index] <= MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON)
+				drm_hdcp_update_content_protection(connector, DRM_MODE_CONTENT_PROTECTION_ENABLED);
+			else if (conn_state->hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE1 &&
+				 hdcp_work->encryption_status[conn_index] == MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON)
+				drm_hdcp_update_content_protection(connector, DRM_MODE_CONTENT_PROTECTION_ENABLED);
+		} else {
+			drm_hdcp_update_content_protection(connector, DRM_MODE_CONTENT_PROTECTION_DESIRED);
+		}
 
+	}
 
 	mutex_unlock(&hdcp_work->mutex);
 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
@@ -332,19 +366,28 @@ static void event_property_validate(struct work_struct *work)
 	struct hdcp_workqueue *hdcp_work =
 		container_of(to_delayed_work(work), struct hdcp_workqueue, property_validate_dwork);
 	struct mod_hdcp_display_query query;
-	struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector;
-
-	if (!aconnector)
-		return;
+	struct amdgpu_dm_connector *aconnector;
+	unsigned int conn_index;
 
 	mutex_lock(&hdcp_work->mutex);
 
-	query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
-	mod_hdcp_query_display(&hdcp_work->hdcp, aconnector->base.index, &query);
+	for (conn_index = 0; conn_index < MAX_NUM_OF_DISPLAYS; ++conn_index) {
+		aconnector = hdcp_work->aconnector[conn_index];
+
+		if (!aconnector)
+			continue;
+
+		query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+		mod_hdcp_query_display(&hdcp_work->hdcp, aconnector->base.index, &query);
 
-	if (query.encryption_status != hdcp_work->encryption_status) {
-		hdcp_work->encryption_status = query.encryption_status;
-		schedule_work(&hdcp_work->property_update_work);
+		pr_debug("[HDCP_DM] display %d, CP %u, (query->enc_st, work->enc_st): (%d, %d)\n",
+			 aconnector->base.index, aconnector->base.state->content_protection,
+			 query.encryption_status, hdcp_work->encryption_status[conn_index]);
+
+		if (query.encryption_status != hdcp_work->encryption_status[conn_index]) {
+			hdcp_work->encryption_status[conn_index] = query.encryption_status;
+			schedule_work(&hdcp_work->property_update_work);
+		}
 	}
 
 	mutex_unlock(&hdcp_work->mutex);
@@ -655,6 +698,10 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
 		hdcp_work[i].hdcp.config.ddc.funcs.read_i2c = lp_read_i2c;
 		hdcp_work[i].hdcp.config.ddc.funcs.write_dpcd = lp_write_dpcd;
 		hdcp_work[i].hdcp.config.ddc.funcs.read_dpcd = lp_read_dpcd;
+
+		memset(hdcp_work[i].aconnector, 0, sizeof(struct amdgpu_dm_connector *) * MAX_NUM_OF_DISPLAYS);
+		memset(hdcp_work[i].encryption_status, 0,
+			sizeof(enum mod_hdcp_encryption_status) * MAX_NUM_OF_DISPLAYS);
 	}
 
 	cp_psp->funcs.update_stream_config = update_config;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
index 09294ff122fe..570863160d60 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 Advanced Micro Devices, Inc.
+ * Copyright (C) 2019-2020 Advanced Micro Devices, Inc. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -43,7 +43,7 @@ struct hdcp_workqueue {
 	struct delayed_work callback_dwork;
 	struct delayed_work watchdog_timer_dwork;
 	struct delayed_work property_validate_dwork;
-	struct amdgpu_dm_connector *aconnector;
+	struct amdgpu_dm_connector *aconnector[MAX_NUM_OF_DISPLAYS];
 	struct mutex mutex;
 
 	struct mod_hdcp hdcp;
@@ -51,7 +51,7 @@ struct hdcp_workqueue {
 	struct mod_hdcp_display display;
 	struct mod_hdcp_link link;
 
-	enum mod_hdcp_encryption_status encryption_status;
+	enum mod_hdcp_encryption_status encryption_status[MAX_NUM_OF_DISPLAYS];
 	uint8_t max_link;
 
 	uint8_t *srm;
-- 
2.31.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

  parent reply index

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-16 14:33 [PATCH 00/19] DC Patches for 2021 April 19 Aurabindo Pillai
2021-04-16 14:33 ` [PATCH 01/19] drm/amd/display: fixed divide by zero kernel crash during dsc enablement Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 02/19] drm/amd/display: Add DSC check to seamless boot validation Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 03/19] drm/amd/display: update hdcp display using correct CP type Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 04/19] drm/amd/display: add handling for hdcp2 rx id list validation Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 05/19] drm/amd/display: disable seamless boot for external DP Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 06/19] drm/amd/display: removed unused function dc_link_reallocate_mst_payload Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 07/19] drm/amd/display: treat memory as a single-channel for asymmetric memory v2 Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 08/19] drm/amd/display: Fix FreeSync when RGB MPO in use Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 09/19] drm/amd/display: Unconditionally clear training pattern set after lt Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 10/19] drm/amd/display: Add link rate optimization logs for ILR Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 11/19] drm/amd/display: Always poll for rxstatus in authenticate Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 12/19] drm/amd/display: Fixed typo in function name Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 13/19] drm/amd/display: force CP to DESIRED when removing display Aurabindo Pillai
2021-04-19 15:42   ` Pillai, Aurabindo
2021-04-16 14:34 ` Aurabindo Pillai [this message]
2021-04-19 15:42   ` [PATCH 14/19] drm/amd/display: fix HDCP drm prop update for MST Pillai, Aurabindo
2021-04-16 14:34 ` [PATCH 15/19] drm/amd/display: Fix call to pass bpp in 16ths of a bit Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 16/19] drm/amd/display: Report Proper Quantization Range in AVI Infoframe Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 17/19] drm/amd/display: add helper for enabling mst stream features Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 18/19] drm/amd/display: [FW Promotion] Release 0.0.62 Aurabindo Pillai
2021-04-16 14:34 ` [PATCH 19/19] drm/amd/display: 3.2.132 Aurabindo Pillai
2021-04-19 15:45 ` [PATCH 00/19] DC Patches for 2021 April 19 Wheeler, Daniel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210416143417.611019-15-aurabindo.pillai@amd.com \
    --to=aurabindo.pillai@amd.com \
    --cc=Anson.Jacob@amd.com \
    --cc=Bhawanpreet.Lakha@amd.com \
    --cc=Dingchen.Zhang@amd.com \
    --cc=Eryk.Brol@amd.com \
    --cc=Harry.Wentland@amd.com \
    --cc=Qingqing.Zhuo@amd.com \
    --cc=Rodrigo.Siqueira@amd.com \
    --cc=Sunpeng.Li@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=bindu.r@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

AMD-GFX Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/amd-gfx/0 amd-gfx/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 amd-gfx amd-gfx/ https://lore.kernel.org/amd-gfx \
		amd-gfx@lists.freedesktop.org
	public-inbox-index amd-gfx

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.freedesktop.lists.amd-gfx


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git