linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers
@ 2023-01-18 19:30 Mark Yacoub
  2023-01-18 19:30 ` [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check() Mark Yacoub
                   ` (9 more replies)
  0 siblings, 10 replies; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul

From: Mark Yacoub <markyacoub@chromium.org>

Hello,

I rebased this series which is authored by Sean Paul.

A major rebase conflict was that drm/drm_hdcp was split to drm/display/drm_hdcp & drm/display/drm_hdcp_helper.

Another major one was in msm dp where drm_connector was no longer tracked, but it's replaced by msm_dp_bridge to carry over its functionalities.

The first 4 patches modify DRM. They've been reviewed.
Patches 5-7 are intel-only. Only patch 7 hasn't been reviewed.
Patches 8-10 are msm-only. Only patch 9 hasn't been reviewed.

Thanks,
Mark

Sean Paul (10):
  drm/hdcp: Add drm_hdcp_atomic_check()
  drm/hdcp: Avoid changing crtc state in hdcp atomic check
  drm/hdcp: Update property value on content type and user changes
  drm/hdcp: Expand HDCP helper library for enable/disable/check
  drm/i915/hdcp: Consolidate HDCP setup/state cache
  drm/i915/hdcp: Retain hdcp_capable return codes
  drm/i915/hdcp: Use HDCP helpers for i915
  dt-bindings: msm/dp: Add bindings for HDCP registers
  arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller
  drm/msm: Implement HDCP 1.x using the new drm HDCP helpers

 .../bindings/display/msm/dp-controller.yaml   |    8 +-
 arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi  |    8 +
 drivers/gpu/drm/display/drm_hdcp_helper.c     | 1202 +++++++++++++++++
 drivers/gpu/drm/i915/display/intel_atomic.c   |    8 +-
 drivers/gpu/drm/i915/display/intel_ddi.c      |   32 +-
 .../drm/i915/display/intel_display_debugfs.c  |   11 +-
 .../drm/i915/display/intel_display_types.h    |   60 +-
 drivers/gpu/drm/i915/display/intel_dp_hdcp.c  |  348 ++---
 drivers/gpu/drm/i915/display/intel_dp_mst.c   |   16 +-
 drivers/gpu/drm/i915/display/intel_hdcp.c     | 1028 +++-----------
 drivers/gpu/drm/i915/display/intel_hdcp.h     |   36 +-
 drivers/gpu/drm/i915/display/intel_hdmi.c     |  270 ++--
 drivers/gpu/drm/msm/Kconfig                   |    1 +
 drivers/gpu/drm/msm/Makefile                  |    1 +
 drivers/gpu/drm/msm/dp/dp_debug.c             |   48 +-
 drivers/gpu/drm/msm/dp/dp_debug.h             |    6 +-
 drivers/gpu/drm/msm/dp/dp_display.c           |   52 +-
 drivers/gpu/drm/msm/dp/dp_display.h           |    5 +
 drivers/gpu/drm/msm/dp/dp_drm.c               |  108 +-
 drivers/gpu/drm/msm/dp/dp_drm.h               |   16 +-
 drivers/gpu/drm/msm/dp/dp_hdcp.c              |  456 +++++++
 drivers/gpu/drm/msm/dp/dp_hdcp.h              |   29 +
 drivers/gpu/drm/msm/dp/dp_parser.c            |   20 +-
 drivers/gpu/drm/msm/dp/dp_parser.h            |    4 +
 drivers/gpu/drm/msm/dp/dp_reg.h               |   32 +-
 drivers/gpu/drm/msm/msm_atomic.c              |   15 +
 include/drm/display/drm_hdcp.h                |  168 ++-
 include/drm/display/drm_hdcp_helper.h         |   33 +-
 28 files changed, 2667 insertions(+), 1354 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.h

-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
  2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
@ 2023-01-18 19:30 ` Mark Yacoub
  2023-01-19 10:37   ` Krzysztof Kozlowski
                     ` (2 more replies)
  2023-01-18 19:30 ` [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic check Mark Yacoub
                   ` (8 subsequent siblings)
  9 siblings, 3 replies; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul, Jani Nikula

From: Sean Paul <seanpaul@chromium.org>

This patch moves the hdcp atomic check from i915 to drm_hdcp so other
drivers can use it. No functional changes, just cleaned up some of the
code when moving it over.

Acked-by: Jani Nikula <jani.nikula@intel.com>
Acked-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Reviewed-by: Abhinav Kumar <abhinavk@codeaurora.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-2-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-2-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-2-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-2-sean@poorly.run #v4
Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-2-sean@poorly.run #v5

Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in V6:
-Rebase: move helper from drm_hdcp.c to drm_hdcp_helper.c

---
 drivers/gpu/drm/display/drm_hdcp_helper.c   | 69 +++++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_atomic.c |  4 +-
 drivers/gpu/drm/i915/display/intel_hdcp.c   | 47 --------------
 drivers/gpu/drm/i915/display/intel_hdcp.h   |  3 -
 include/drm/display/drm_hdcp_helper.h       |  3 +
 5 files changed, 74 insertions(+), 52 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdcp_helper.c b/drivers/gpu/drm/display/drm_hdcp_helper.c
index e78999c72bd7..7d910523b05f 100644
--- a/drivers/gpu/drm/display/drm_hdcp_helper.c
+++ b/drivers/gpu/drm/display/drm_hdcp_helper.c
@@ -20,6 +20,7 @@
 #include <drm/drm_property.h>
 #include <drm/drm_mode_object.h>
 #include <drm/drm_connector.h>
+#include <drm/drm_atomic.h>
 
 static inline void drm_hdcp_print_ksv(const u8 *ksv)
 {
@@ -419,3 +420,71 @@ void drm_hdcp_update_content_protection(struct drm_connector *connector,
 				 dev->mode_config.content_protection_property);
 }
 EXPORT_SYMBOL(drm_hdcp_update_content_protection);
+
+/**
+ * drm_hdcp_atomic_check - Helper for drivers to call during connector->atomic_check
+ *
+ * @state: pointer to the atomic state being checked
+ * @connector: drm_connector on which content protection state needs an update
+ *
+ * This function can be used by display drivers to perform an atomic check on the
+ * hdcp state elements. If hdcp state has changed, this function will set
+ * mode_changed on the crtc driving the connector so it can update its hardware
+ * to match the hdcp state.
+ */
+void drm_hdcp_atomic_check(struct drm_connector *connector,
+			   struct drm_atomic_state *state)
+{
+	struct drm_connector_state *new_conn_state, *old_conn_state;
+	struct drm_crtc_state *new_crtc_state;
+	u64 old_hdcp, new_hdcp;
+
+	old_conn_state = drm_atomic_get_old_connector_state(state, connector);
+	old_hdcp = old_conn_state->content_protection;
+
+	new_conn_state = drm_atomic_get_new_connector_state(state, connector);
+	new_hdcp = new_conn_state->content_protection;
+
+	if (!new_conn_state->crtc) {
+		/*
+		 * If the connector is being disabled with CP enabled, mark it
+		 * desired so it's re-enabled when the connector is brought back
+		 */
+		if (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
+			new_conn_state->content_protection =
+				DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		return;
+	}
+
+	new_crtc_state =
+		drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
+	/*
+	* Fix the HDCP uapi content protection state in case of modeset.
+	* FIXME: As per HDCP content protection property uapi doc, an uevent()
+	* need to be sent if there is transition from ENABLED->DESIRED.
+	*/
+	if (drm_atomic_crtc_needs_modeset(new_crtc_state) &&
+	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
+	     new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED))
+		new_conn_state->content_protection =
+			DRM_MODE_CONTENT_PROTECTION_DESIRED;
+
+	/*
+	 * Nothing to do if content type is unchanged and one of:
+	 *  - state didn't change
+	 *  - HDCP was activated since the last commit
+	 *  - attempting to set to desired while already enabled
+	 */
+	if (old_hdcp == new_hdcp ||
+	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
+	     new_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED) ||
+	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
+	     new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED)) {
+		if (old_conn_state->hdcp_content_type ==
+		    new_conn_state->hdcp_content_type)
+			return;
+	}
+
+	new_crtc_state->mode_changed = true;
+}
+EXPORT_SYMBOL(drm_hdcp_atomic_check);
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
index 18f0a5ae3bac..8a473199c4bf 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -32,6 +32,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fourcc.h>
+#include <drm/display/drm_hdcp_helper.h>
 
 #include "i915_drv.h"
 #include "i915_reg.h"
@@ -39,7 +40,6 @@
 #include "intel_cdclk.h"
 #include "intel_display_types.h"
 #include "intel_global_state.h"
-#include "intel_hdcp.h"
 #include "intel_psr.h"
 #include "skl_universal_plane.h"
 
@@ -123,7 +123,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
 		to_intel_digital_connector_state(old_state);
 	struct drm_crtc_state *crtc_state;
 
-	intel_hdcp_atomic_check(conn, old_state, new_state);
+	drm_hdcp_atomic_check(conn, state);
 
 	if (!new_state->crtc)
 		return 0;
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c
index 6406fd487ee5..396d2cef000a 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
@@ -2524,53 +2524,6 @@ void intel_hdcp_cleanup(struct intel_connector *connector)
 	mutex_unlock(&hdcp->mutex);
 }
 
-void intel_hdcp_atomic_check(struct drm_connector *connector,
-			     struct drm_connector_state *old_state,
-			     struct drm_connector_state *new_state)
-{
-	u64 old_cp = old_state->content_protection;
-	u64 new_cp = new_state->content_protection;
-	struct drm_crtc_state *crtc_state;
-
-	if (!new_state->crtc) {
-		/*
-		 * If the connector is being disabled with CP enabled, mark it
-		 * desired so it's re-enabled when the connector is brought back
-		 */
-		if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
-			new_state->content_protection =
-				DRM_MODE_CONTENT_PROTECTION_DESIRED;
-		return;
-	}
-
-	crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
-						   new_state->crtc);
-	/*
-	 * Fix the HDCP uapi content protection state in case of modeset.
-	 * FIXME: As per HDCP content protection property uapi doc, an uevent()
-	 * need to be sent if there is transition from ENABLED->DESIRED.
-	 */
-	if (drm_atomic_crtc_needs_modeset(crtc_state) &&
-	    (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
-	    new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED))
-		new_state->content_protection =
-			DRM_MODE_CONTENT_PROTECTION_DESIRED;
-
-	/*
-	 * Nothing to do if the state didn't change, or HDCP was activated since
-	 * the last commit. And also no change in hdcp content type.
-	 */
-	if (old_cp == new_cp ||
-	    (old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
-	     new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)) {
-		if (old_state->hdcp_content_type ==
-				new_state->hdcp_content_type)
-			return;
-	}
-
-	crtc_state->mode_changed = true;
-}
-
 /* Handles the CP_IRQ raised from the DP HDCP sink */
 void intel_hdcp_handle_cp_irq(struct intel_connector *connector)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h b/drivers/gpu/drm/i915/display/intel_hdcp.h
index 8f53b0c7fe5c..7c5fd84a7b65 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.h
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
@@ -22,9 +22,6 @@ struct intel_digital_port;
 enum port;
 enum transcoder;
 
-void intel_hdcp_atomic_check(struct drm_connector *connector,
-			     struct drm_connector_state *old_state,
-			     struct drm_connector_state *new_state);
 int intel_hdcp_init(struct intel_connector *connector,
 		    struct intel_digital_port *dig_port,
 		    const struct intel_hdcp_shim *hdcp_shim);
diff --git a/include/drm/display/drm_hdcp_helper.h b/include/drm/display/drm_hdcp_helper.h
index 8aaf87bf2735..dd02b2e72a50 100644
--- a/include/drm/display/drm_hdcp_helper.h
+++ b/include/drm/display/drm_hdcp_helper.h
@@ -11,6 +11,7 @@
 
 #include <drm/display/drm_hdcp.h>
 
+struct drm_atomic_state;
 struct drm_device;
 struct drm_connector;
 
@@ -18,5 +19,7 @@ int drm_hdcp_check_ksvs_revoked(struct drm_device *dev, u8 *ksvs, u32 ksv_count)
 int drm_connector_attach_content_protection_property(struct drm_connector *connector,
 						     bool hdcp_content_type);
 void drm_hdcp_update_content_protection(struct drm_connector *connector, u64 val);
+void drm_hdcp_atomic_check(struct drm_connector *connector,
+			   struct drm_atomic_state *state);
 
 #endif
-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic check
  2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
  2023-01-18 19:30 ` [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check() Mark Yacoub
@ 2023-01-18 19:30 ` Mark Yacoub
  2023-01-19 11:45   ` Dmitry Baryshkov
  2023-03-10  6:00   ` [Intel-gfx] " Kandpal, Suraj
  2023-01-18 19:30 ` [PATCH v6 03/10] drm/hdcp: Update property value on content type and user changes Mark Yacoub
                   ` (7 subsequent siblings)
  9 siblings, 2 replies; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul, Jani Nikula

From: Sean Paul <seanpaul@chromium.org>

Instead of forcing a modeset in the hdcp atomic check, simply return
true if the content protection value is changing and let the driver
decide whether a modeset is required or not.

Acked-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-3-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-3-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-3-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-3-sean@poorly.run #v4
Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-3-sean@poorly.run #v5

Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in V6:
-Rebase: modifications in drm_hdcp_helper.c instead of drm_hdcp.c

---
 drivers/gpu/drm/display/drm_hdcp_helper.c   | 33 +++++++++++++++------
 drivers/gpu/drm/i915/display/intel_atomic.c |  6 ++--
 include/drm/display/drm_hdcp_helper.h       |  2 +-
 3 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdcp_helper.c b/drivers/gpu/drm/display/drm_hdcp_helper.c
index 7d910523b05f..a3896b0904b5 100644
--- a/drivers/gpu/drm/display/drm_hdcp_helper.c
+++ b/drivers/gpu/drm/display/drm_hdcp_helper.c
@@ -428,11 +428,14 @@ EXPORT_SYMBOL(drm_hdcp_update_content_protection);
  * @connector: drm_connector on which content protection state needs an update
  *
  * This function can be used by display drivers to perform an atomic check on the
- * hdcp state elements. If hdcp state has changed, this function will set
- * mode_changed on the crtc driving the connector so it can update its hardware
- * to match the hdcp state.
+ * hdcp state elements. If hdcp state has changed in a manner which requires the
+ * driver to enable or disable content protection, this function will return
+ * true.
+ *
+ * Returns:
+ * true if the driver must enable/disable hdcp, false otherwise
  */
-void drm_hdcp_atomic_check(struct drm_connector *connector,
+bool drm_hdcp_atomic_check(struct drm_connector *connector,
 			   struct drm_atomic_state *state)
 {
 	struct drm_connector_state *new_conn_state, *old_conn_state;
@@ -450,10 +453,12 @@ void drm_hdcp_atomic_check(struct drm_connector *connector,
 		 * If the connector is being disabled with CP enabled, mark it
 		 * desired so it's re-enabled when the connector is brought back
 		 */
-		if (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
+		if (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
 			new_conn_state->content_protection =
 				DRM_MODE_CONTENT_PROTECTION_DESIRED;
-		return;
+			return true;
+		}
+		return false;
 	}
 
 	new_crtc_state =
@@ -465,9 +470,19 @@ void drm_hdcp_atomic_check(struct drm_connector *connector,
 	*/
 	if (drm_atomic_crtc_needs_modeset(new_crtc_state) &&
 	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
-	     new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED))
+	     new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)) {
 		new_conn_state->content_protection =
 			DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		return true;
+	}
+
+	/*
+	 * Coming back from disable or changing CRTC with DESIRED state requires
+	 * that the driver try CP enable.
+	 */
+	if (new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
+	    new_conn_state->crtc != old_conn_state->crtc)
+		return true;
 
 	/*
 	 * Nothing to do if content type is unchanged and one of:
@@ -482,9 +497,9 @@ void drm_hdcp_atomic_check(struct drm_connector *connector,
 	     new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED)) {
 		if (old_conn_state->hdcp_content_type ==
 		    new_conn_state->hdcp_content_type)
-			return;
+			return false;
 	}
 
-	new_crtc_state->mode_changed = true;
+	return true;
 }
 EXPORT_SYMBOL(drm_hdcp_atomic_check);
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
index 8a473199c4bf..a2067cbae2d5 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -123,8 +123,6 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
 		to_intel_digital_connector_state(old_state);
 	struct drm_crtc_state *crtc_state;
 
-	drm_hdcp_atomic_check(conn, state);
-
 	if (!new_state->crtc)
 		return 0;
 
@@ -140,8 +138,8 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
 	    new_conn_state->base.picture_aspect_ratio != old_conn_state->base.picture_aspect_ratio ||
 	    new_conn_state->base.content_type != old_conn_state->base.content_type ||
 	    new_conn_state->base.scaling_mode != old_conn_state->base.scaling_mode ||
-	    new_conn_state->base.privacy_screen_sw_state != old_conn_state->base.privacy_screen_sw_state ||
-	    !drm_connector_atomic_hdr_metadata_equal(old_state, new_state))
+	    !drm_connector_atomic_hdr_metadata_equal(old_state, new_state) ||
+	    drm_hdcp_atomic_check(conn, state))
 		crtc_state->mode_changed = true;
 
 	return 0;
diff --git a/include/drm/display/drm_hdcp_helper.h b/include/drm/display/drm_hdcp_helper.h
index dd02b2e72a50..cb2cc5002f65 100644
--- a/include/drm/display/drm_hdcp_helper.h
+++ b/include/drm/display/drm_hdcp_helper.h
@@ -19,7 +19,7 @@ int drm_hdcp_check_ksvs_revoked(struct drm_device *dev, u8 *ksvs, u32 ksv_count)
 int drm_connector_attach_content_protection_property(struct drm_connector *connector,
 						     bool hdcp_content_type);
 void drm_hdcp_update_content_protection(struct drm_connector *connector, u64 val);
-void drm_hdcp_atomic_check(struct drm_connector *connector,
+bool drm_hdcp_atomic_check(struct drm_connector *connector,
 			   struct drm_atomic_state *state);
 
 #endif
-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v6 03/10] drm/hdcp: Update property value on content type and user changes
  2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
  2023-01-18 19:30 ` [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check() Mark Yacoub
  2023-01-18 19:30 ` [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic check Mark Yacoub
@ 2023-01-18 19:30 ` Mark Yacoub
  2023-01-18 19:30 ` [PATCH v6 04/10] drm/hdcp: Expand HDCP helper library for enable/disable/check Mark Yacoub
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul, Jani Nikula

From: Sean Paul <seanpaul@chromium.org>

This patch updates the connector's property value in 2 cases which were
previously missed:

1- Content type changes. The value should revert back to DESIRED from
   ENABLED in case the driver must re-authenticate the link due to the
   new content type.

2- Userspace sets value to DESIRED while ENABLED. In this case, the
   value should be reset immediately to ENABLED since the link is
   actively being encrypted.

To accommodate these changes, I've split up the conditionals to make
things a bit more clear (as much as one can with this mess of state).

Acked-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Reviewed-by: Abhinav Kumar <abhinavk@codeaurora.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-4-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-4-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-4-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-4-sean@poorly.run #v4
Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-4-sean@poorly.run

Changes in v2:
-None
Changes in v3:
-Fixed indentation issue identified by 0-day
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:
-Rebased: modifications in drm_hdcp_helper.c instead of drm_hdcp.c

---
 drivers/gpu/drm/display/drm_hdcp_helper.c | 29 +++++++++++++++--------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdcp_helper.c b/drivers/gpu/drm/display/drm_hdcp_helper.c
index a3896b0904b5..ce92f1cac251 100644
--- a/drivers/gpu/drm/display/drm_hdcp_helper.c
+++ b/drivers/gpu/drm/display/drm_hdcp_helper.c
@@ -485,21 +485,30 @@ bool drm_hdcp_atomic_check(struct drm_connector *connector,
 		return true;
 
 	/*
-	 * Nothing to do if content type is unchanged and one of:
-	 *  - state didn't change
-	 *  - HDCP was activated since the last commit
-	 *  - attempting to set to desired while already enabled
+	 * Content type changes require an HDCP disable/enable cycle.
 	 */
-	if (old_hdcp == new_hdcp ||
-	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
+	if (new_conn_state->hdcp_content_type !=
+	    old_conn_state->hdcp_content_type) {
+		new_conn_state->content_protection =
+			DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		return true;
+	}
+
+	/*
+	 * Ignore meaningless state changes:
+ 	 *  - HDCP was activated since the last commit
+	 *  - Attempting to set to desired while already enabled
+ 	 */
+	if ((old_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
 	     new_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED) ||
 	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
 	     new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED)) {
-		if (old_conn_state->hdcp_content_type ==
-		    new_conn_state->hdcp_content_type)
-			return false;
+		new_conn_state->content_protection =
+			DRM_MODE_CONTENT_PROTECTION_ENABLED;
+		return false;
 	}
 
-	return true;
+	/* Finally, if state changes, we need action */
+	return old_hdcp != new_hdcp;
 }
 EXPORT_SYMBOL(drm_hdcp_atomic_check);
-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v6 04/10] drm/hdcp: Expand HDCP helper library for enable/disable/check
  2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
                   ` (2 preceding siblings ...)
  2023-01-18 19:30 ` [PATCH v6 03/10] drm/hdcp: Update property value on content type and user changes Mark Yacoub
@ 2023-01-18 19:30 ` Mark Yacoub
  2023-01-19 12:54   ` Dmitry Baryshkov
  2023-01-18 19:30 ` [PATCH v6 05/10] drm/i915/hdcp: Consolidate HDCP setup/state cache Mark Yacoub
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul, Jani Nikula

From: Sean Paul <seanpaul@chromium.org>

This patch expands upon the HDCP helper library to manage HDCP
enable, disable, and check.

Previous to this patch, the majority of the state management and sink
interaction is tucked inside the Intel driver with the understanding
that once a new platform supported HDCP we could make good decisions
about what should be centralized. With the addition of HDCP support
for Qualcomm, it's time to migrate the protocol-specific bits of HDCP
authentication, key exchange, and link checks to the HDCP helper.

In terms of functionality, this migration is 1:1 with the Intel driver,
however things are laid out a bit differently than with intel_hdcp.c,
which is why this is a separate patch from the i915 transition to the
helper. On i915, the shim vtable is used to account for HDMI vs. DP
vs. DP-MST differences whereas the helper library uses a LUT to
account for the register offsets and a remote read function to route
the messages. On i915, storing the sink information in the source is
done inline whereas now we use the new drm_hdcp_helper_funcs vtable
to store and fetch information to/from source hw. Finally, instead of
calling enable/disable directly from the driver, we'll leave that
decision to the helper and by calling drm_hdcp_helper_atomic_commit()
from the driver. All told, this will centralize the protocol and state
handling in the helper, ensuring we collect all of our bugs^Wlogic
in one place.

Cc: Abhinav Kumar <abhinavk@codeaurora.org>
Acked-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Abhinav Kumar <abhinavk@codeaurora.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-5-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-5-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-5-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-5-sean@poorly.run #v4
Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-5-sean@poorly.run #v5

Changes in v2:
-Fixed set-but-unused variable identified by 0-day
Changes in v3:
-Fixed uninitialized variable warning identified by 0-day
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:
-Fixed typo in function descriptions
-Rebased: Moved the new code between drm_hdcp.h and drm_hdcp_helper.c/h
-Add missing headers. Reported-by: kernel test robot <lkp@intel.com>

---
 drivers/gpu/drm/display/drm_hdcp_helper.c | 1109 +++++++++++++++++++++
 include/drm/display/drm_hdcp.h            |  168 +++-
 include/drm/display/drm_hdcp_helper.h     |   30 +-
 3 files changed, 1305 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdcp_helper.c b/drivers/gpu/drm/display/drm_hdcp_helper.c
index ce92f1cac251..de8c006b9cda 100644
--- a/drivers/gpu/drm/display/drm_hdcp_helper.c
+++ b/drivers/gpu/drm/display/drm_hdcp_helper.c
@@ -6,13 +6,18 @@
  * Ramalingam C <ramalingam.c@intel.com>
  */
 
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/gfp.h>
+#include <linux/i2c.h>
+#include <linux/iopoll.h>
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/firmware.h>
+#include <linux/workqueue.h>
 
+#include <drm/display/drm_dp_helper.h>
 #include <drm/display/drm_hdcp_helper.h>
 #include <drm/drm_sysfs.h>
 #include <drm/drm_print.h>
@@ -512,3 +517,1107 @@ bool drm_hdcp_atomic_check(struct drm_connector *connector,
 	return old_hdcp != new_hdcp;
 }
 EXPORT_SYMBOL(drm_hdcp_atomic_check);
+
+struct drm_hdcp_helper_data {
+	struct mutex mutex;
+	struct mutex *driver_mutex;
+
+	struct drm_connector *connector;
+	const struct drm_hdcp_helper_funcs *funcs;
+
+	u64 value;
+	unsigned int enabled_type;
+
+	struct delayed_work check_work;
+	struct work_struct prop_work;
+
+	struct drm_dp_aux *aux;
+	const struct drm_hdcp_hdcp1_receiver_reg_lut *hdcp1_lut;
+};
+
+struct drm_hdcp_hdcp1_receiver_reg_lut {
+	unsigned int bksv;
+	unsigned int ri;
+	unsigned int aksv;
+	unsigned int an;
+	unsigned int ainfo;
+	unsigned int v[5];
+	unsigned int bcaps;
+	unsigned int bcaps_mask_repeater_present;
+	unsigned int bstatus;
+};
+
+static const struct drm_hdcp_hdcp1_receiver_reg_lut drm_hdcp_hdcp1_ddc_lut = {
+	.bksv = DRM_HDCP_DDC_BKSV,
+	.ri = DRM_HDCP_DDC_RI_PRIME,
+	.aksv = DRM_HDCP_DDC_AKSV,
+	.an = DRM_HDCP_DDC_AN,
+	.ainfo = DRM_HDCP_DDC_AINFO,
+	.v = { DRM_HDCP_DDC_V_PRIME(0), DRM_HDCP_DDC_V_PRIME(1),
+	       DRM_HDCP_DDC_V_PRIME(2), DRM_HDCP_DDC_V_PRIME(3),
+	       DRM_HDCP_DDC_V_PRIME(4) },
+	.bcaps = DRM_HDCP_DDC_BCAPS,
+	.bcaps_mask_repeater_present = DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT,
+	.bstatus = DRM_HDCP_DDC_BSTATUS,
+};
+
+static const struct drm_hdcp_hdcp1_receiver_reg_lut drm_hdcp_hdcp1_dpcd_lut = {
+	.bksv = DP_AUX_HDCP_BKSV,
+	.ri = DP_AUX_HDCP_RI_PRIME,
+	.aksv = DP_AUX_HDCP_AKSV,
+	.an = DP_AUX_HDCP_AN,
+	.ainfo = DP_AUX_HDCP_AINFO,
+	.v = { DP_AUX_HDCP_V_PRIME(0), DP_AUX_HDCP_V_PRIME(1),
+	       DP_AUX_HDCP_V_PRIME(2), DP_AUX_HDCP_V_PRIME(3),
+	       DP_AUX_HDCP_V_PRIME(4) },
+	.bcaps = DP_AUX_HDCP_BCAPS,
+	.bcaps_mask_repeater_present = DP_BCAPS_REPEATER_PRESENT,
+
+	/*
+	 * For some reason the HDMI and DP HDCP specs call this register
+	 * definition by different names. In the HDMI spec, it's called BSTATUS,
+	 * but in DP it's called BINFO.
+	 */
+	.bstatus = DP_AUX_HDCP_BINFO,
+};
+
+static int drm_hdcp_remote_ddc_read(struct i2c_adapter *i2c,
+				    unsigned int offset, u8 *value, size_t len)
+{
+	int ret;
+	u8 start = offset & 0xff;
+	struct i2c_msg msgs[] = { {
+					  .addr = DRM_HDCP_DDC_ADDR,
+					  .flags = 0,
+					  .len = 1,
+					  .buf = &start,
+				  },
+				  { .addr = DRM_HDCP_DDC_ADDR,
+				    .flags = I2C_M_RD,
+				    .len = len,
+				    .buf = value } };
+	ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs));
+	if (ret == ARRAY_SIZE(msgs))
+		return 0;
+	return ret >= 0 ? -EIO : ret;
+}
+
+static int drm_hdcp_remote_dpcd_read(struct drm_dp_aux *aux,
+				     unsigned int offset, u8 *value, size_t len)
+{
+	ssize_t ret;
+
+	ret = drm_dp_dpcd_read(aux, offset, value, len);
+	if (ret != len) {
+		if (ret >= 0)
+			return -EIO;
+		return ret;
+	}
+
+	return 0;
+}
+
+static int drm_hdcp_remote_read(struct drm_hdcp_helper_data *data,
+				unsigned int offset, u8 *value, u8 len)
+{
+	if (data->aux)
+		return drm_hdcp_remote_dpcd_read(data->aux, offset, value, len);
+	else
+		return drm_hdcp_remote_ddc_read(data->connector->ddc, offset,
+						value, len);
+}
+
+static int drm_hdcp_remote_ddc_write(struct i2c_adapter *i2c,
+				     unsigned int offset, u8 *buffer,
+				     size_t size)
+{
+	int ret;
+	u8 *write_buf;
+	struct i2c_msg msg;
+
+	write_buf = kzalloc(size + 1, GFP_KERNEL);
+	if (!write_buf)
+		return -ENOMEM;
+
+	write_buf[0] = offset & 0xff;
+	memcpy(&write_buf[1], buffer, size);
+
+	msg.addr = DRM_HDCP_DDC_ADDR;
+	msg.flags = 0, msg.len = size + 1, msg.buf = write_buf;
+
+	ret = i2c_transfer(i2c, &msg, 1);
+	if (ret == 1)
+		ret = 0;
+	else if (ret >= 0)
+		ret = -EIO;
+
+	kfree(write_buf);
+	return ret;
+}
+
+static int drm_hdcp_remote_dpcd_write(struct drm_dp_aux *aux,
+				      unsigned int offset, u8 *value,
+				      size_t len)
+{
+	ssize_t ret;
+
+	ret = drm_dp_dpcd_write(aux, offset, value, len);
+	if (ret != len) {
+		if (ret >= 0)
+			return -EIO;
+		return ret;
+	}
+
+	return 0;
+}
+
+static int drm_hdcp_remote_write(struct drm_hdcp_helper_data *data,
+				 unsigned int offset, u8 *value, u8 len)
+{
+	if (data->aux)
+		return drm_hdcp_remote_dpcd_write(data->aux, offset, value,
+						  len);
+	else
+		return drm_hdcp_remote_ddc_write(data->connector->ddc, offset,
+						 value, len);
+}
+
+static bool drm_hdcp_is_ksv_valid(struct drm_hdcp_ksv *ksv)
+{
+	/* Valid Ksv has 20 0's and 20 1's */
+	return hweight32(ksv->words[0]) + hweight32(ksv->words[1]) == 20;
+}
+
+static int drm_hdcp_read_valid_bksv(struct drm_hdcp_helper_data *data,
+				    struct drm_hdcp_ksv *bksv)
+{
+	int ret, i, tries = 2;
+
+	/* HDCP spec states that we must retry the bksv if it is invalid */
+	for (i = 0; i < tries; i++) {
+		ret = drm_hdcp_remote_read(data, data->hdcp1_lut->bksv,
+					   bksv->bytes, DRM_HDCP_KSV_LEN);
+		if (ret)
+			return ret;
+
+		if (drm_hdcp_is_ksv_valid(bksv))
+			break;
+	}
+	if (i == tries) {
+		drm_dbg_kms(data->connector->dev, "Bksv is invalid %*ph\n",
+			    DRM_HDCP_KSV_LEN, bksv->bytes);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * drm_hdcp_helper_hdcp1_capable - Checks if the sink is capable of HDCP 1.x.
+ *
+ * @data: pointer to the HDCP helper data.
+ * @capable: pointer to a bool which will contain true if the sink is capable.
+ *
+ * Returns:
+ * -errno if the transacation between source and sink fails.
+ */
+int drm_hdcp_helper_hdcp1_capable(struct drm_hdcp_helper_data *data,
+				  bool *capable)
+{
+	/*
+	 * DisplayPort has a dedicated bit for this in DPCD whereas HDMI spec
+	 * states that transmitters should use bksv to determine capability.
+	 */
+	if (data->aux) {
+		int ret;
+		u8 bcaps;
+
+		ret = drm_hdcp_remote_read(data, data->hdcp1_lut->bcaps, &bcaps,
+					   1);
+		*capable = !ret && (bcaps & DP_BCAPS_HDCP_CAPABLE);
+	} else {
+		struct drm_hdcp_ksv bksv;
+
+		*capable = drm_hdcp_read_valid_bksv(data, &bksv) == 0;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_hdcp_helper_hdcp1_capable);
+
+static void drm_hdcp_update_value(struct drm_hdcp_helper_data *data, u64 value,
+				  bool update_property)
+{
+	WARN_ON(!mutex_is_locked(&data->mutex));
+
+	data->value = value;
+	if (update_property) {
+		drm_connector_get(data->connector);
+		schedule_work(&data->prop_work);
+	}
+}
+
+static int
+drm_hdcp_helper_hdcp1_ksv_fifo_ready(struct drm_hdcp_helper_data *data)
+{
+	int ret;
+	u8 val, mask;
+
+	/* KSV FIFO ready bit is stored in different locations on DP v. HDMI */
+	if (data->aux) {
+		ret = drm_hdcp_remote_dpcd_read(data->aux, DP_AUX_HDCP_BSTATUS,
+						&val, 1);
+		mask = DP_BSTATUS_READY;
+	} else {
+		ret = drm_hdcp_remote_ddc_read(data->connector->ddc,
+					       DRM_HDCP_DDC_BCAPS, &val, 1);
+		mask = DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
+	}
+	if (ret)
+		return ret;
+	if (val & mask)
+		return 0;
+
+	return -EAGAIN;
+}
+
+static int
+drm_hdcp_helper_hdcp1_read_ksv_fifo(struct drm_hdcp_helper_data *data, u8 *fifo,
+				    u8 num_downstream)
+{
+	struct drm_device *dev = data->connector->dev;
+	int ret, i;
+
+	/* Over HDMI, read the whole thing at once */
+	if (data->connector->ddc) {
+		ret = drm_hdcp_remote_ddc_read(
+			data->connector->ddc, DRM_HDCP_DDC_KSV_FIFO, fifo,
+			num_downstream * DRM_HDCP_KSV_LEN);
+		if (ret)
+			drm_err(dev, "DDC ksv fifo read failed (%d)\n", ret);
+		return ret;
+	}
+
+	/* Over DP, read via 15 byte window (3 entries @ 5 bytes each) */
+	for (i = 0; i < num_downstream; i += 3) {
+		size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
+		ret = drm_hdcp_remote_dpcd_read(data->aux, DP_AUX_HDCP_KSV_FIFO,
+						fifo + i * DRM_HDCP_KSV_LEN,
+						len);
+		if (ret) {
+			drm_err(dev, "Read ksv[%d] from DP/AUX failed (%d)\n",
+				i, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int drm_hdcp_helper_hdcp1_read_v_prime(struct drm_hdcp_helper_data *data,
+					      u32 *v_prime)
+{
+	struct drm_device *dev = data->connector->dev;
+	int ret, i;
+
+	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
+		ret = drm_hdcp_remote_read(data, data->hdcp1_lut->v[i],
+					   (u8 *)&v_prime[i],
+					   DRM_HDCP_V_PRIME_PART_LEN);
+		if (ret) {
+			drm_dbg_kms(dev, "Read v'[%d] from failed (%d)\n", i,
+				    ret);
+			return ret >= 0 ? -EIO : ret;
+		}
+	}
+	return 0;
+}
+
+static int
+drm_hdcp_helper_hdcp1_authenticate_downstream(struct drm_hdcp_helper_data *data)
+{
+	struct drm_connector *connector = data->connector;
+	struct drm_device *dev = connector->dev;
+	u32 v_prime[DRM_HDCP_V_PRIME_NUM_PARTS];
+	u8 bstatus[DRM_HDCP_BSTATUS_LEN];
+	u8 num_downstream, *ksv_fifo;
+	int ret, i, tries = 3;
+
+	ret = read_poll_timeout(drm_hdcp_helper_hdcp1_ksv_fifo_ready, ret, !ret,
+				10 * 1000, 5 * 1000 * 1000, false, data);
+	if (ret) {
+		drm_err(dev, "Failed to poll ksv ready, %d\n", ret);
+		return ret;
+	}
+
+	ret = drm_hdcp_remote_read(data, data->hdcp1_lut->bstatus, bstatus,
+				   DRM_HDCP_BSTATUS_LEN);
+	if (ret)
+		return ret;
+
+	/*
+	 * When repeater reports 0 device count, HDCP1.4 spec allows disabling
+	 * the HDCP encryption. That implies that repeater can't have its own
+	 * display. As there is no consumption of encrypted content in the
+	 * repeater with 0 downstream devices, we are failing the
+	 * authentication.
+	 */
+	num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
+	if (num_downstream == 0) {
+		drm_err(dev, "Repeater with zero downstream devices, %*ph\n",
+			DRM_HDCP_BSTATUS_LEN, bstatus);
+		return -EINVAL;
+	}
+
+	ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream, GFP_KERNEL);
+	if (!ksv_fifo)
+		return -ENOMEM;
+
+	ret = drm_hdcp_helper_hdcp1_read_ksv_fifo(data, ksv_fifo,
+						  num_downstream);
+	if (ret) {
+		drm_err(dev, "Failed to read ksv fifo, %d/%d\n", num_downstream,
+			ret);
+		goto out;
+	}
+
+	if (drm_hdcp_check_ksvs_revoked(dev, ksv_fifo, num_downstream)) {
+		drm_err(dev, "Revoked Ksv(s) in ksv_fifo\n");
+		ret = -EPERM;
+		goto out;
+	}
+
+	/*
+	 * When V prime mismatches, DP Spec mandates re-read of
+	 * V prime at least twice.
+	 */
+	for (i = 0; i < tries; i++) {
+		ret = drm_hdcp_helper_hdcp1_read_v_prime(data, v_prime);
+		if (ret)
+			continue;
+
+		ret = data->funcs->hdcp1_store_ksv_fifo(
+			connector, ksv_fifo, num_downstream, bstatus, v_prime);
+		if (!ret)
+			break;
+	}
+	if (ret)
+		drm_err(dev, "Could not validate KSV FIFO with V' %d\n", ret);
+
+out:
+	if (!ret)
+		drm_dbg_kms(dev, "HDCP is enabled (%d downstream devices)\n",
+			    num_downstream);
+
+	kfree(ksv_fifo);
+	return ret;
+}
+
+static int drm_hdcp_helper_hdcp1_validate_ri(struct drm_hdcp_helper_data *data)
+{
+	union {
+		u32 word;
+		u8 bytes[DRM_HDCP_RI_LEN];
+	} ri_prime = { .word = 0 };
+	struct drm_connector *connector = data->connector;
+	struct drm_device *dev = connector->dev;
+	int ret;
+
+	ret = drm_hdcp_remote_read(data, data->hdcp1_lut->ri, ri_prime.bytes,
+				   DRM_HDCP_RI_LEN);
+	if (ret) {
+		drm_err(dev, "Failed to read R0' %d\n", ret);
+		return ret;
+	}
+
+	return data->funcs->hdcp1_match_ri(connector, ri_prime.word);
+}
+
+static int drm_hdcp_helper_hdcp1_authenticate(struct drm_hdcp_helper_data *data)
+{
+	union {
+		u32 word;
+		u8 bytes[DRM_HDCP_BSTATUS_LEN];
+	} bstatus;
+	const struct drm_hdcp_helper_funcs *funcs = data->funcs;
+	struct drm_connector *connector = data->connector;
+	struct drm_device *dev = connector->dev;
+	unsigned long r0_prime_timeout, r0_prime_remaining_us = 0, tmp_jiffies;
+	struct drm_hdcp_ksv aksv;
+	struct drm_hdcp_ksv bksv;
+	struct drm_hdcp_an an;
+	bool repeater_present;
+	int ret, i, tries = 3;
+	u8 bcaps;
+
+	if (funcs->hdcp1_read_an_aksv) {
+		ret = funcs->hdcp1_read_an_aksv(connector, an.words,
+						aksv.words);
+		if (ret) {
+			drm_err(dev, "Failed to read An/Aksv values, %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = drm_hdcp_remote_write(data, data->hdcp1_lut->an, an.bytes,
+					    DRM_HDCP_AN_LEN);
+		if (ret) {
+			drm_err(dev, "Failed to write An to receiver, %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = drm_hdcp_remote_write(data, data->hdcp1_lut->aksv,
+					    aksv.bytes, DRM_HDCP_KSV_LEN);
+		if (ret) {
+			drm_err(dev, "Failed to write Aksv to receiver, %d\n",
+				ret);
+			return ret;
+		}
+	} else {
+		ret = funcs->hdcp1_send_an_aksv(connector);
+		if (ret) {
+			drm_err(dev, "Failed to read An/Aksv values, %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	/*
+	 * Timeout for R0' to become available. The spec says 100ms from Aksv,
+	 * but some monitors can take longer than this. We'll set the timeout at
+	 * 300ms just to be sure.
+	 */
+	r0_prime_timeout = jiffies + msecs_to_jiffies(300);
+
+	memset(&bksv, 0, sizeof(bksv));
+
+	ret = drm_hdcp_read_valid_bksv(data, &bksv);
+	if (ret < 0)
+		return ret;
+
+	if (drm_hdcp_check_ksvs_revoked(dev, bksv.bytes, 1)) {
+		drm_err(dev, "BKSV is revoked\n");
+		return -EPERM;
+	}
+
+	ret = drm_hdcp_remote_read(data, data->hdcp1_lut->bcaps, &bcaps, 1);
+	if (ret)
+		return ret;
+
+	memset(&bstatus, 0, sizeof(bstatus));
+
+	ret = drm_hdcp_remote_read(data, data->hdcp1_lut->bstatus,
+				   bstatus.bytes, DRM_HDCP_BSTATUS_LEN);
+	if (ret)
+		return ret;
+
+	if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus.bytes[0]) ||
+	    DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus.bytes[1])) {
+		drm_err(dev, "Max Topology Limit Exceeded, bstatus=%*ph\n",
+			DRM_HDCP_BSTATUS_LEN, bstatus.bytes);
+		return -EPERM;
+	}
+
+	repeater_present = bcaps & data->hdcp1_lut->bcaps_mask_repeater_present;
+
+	ret = funcs->hdcp1_store_receiver_info(
+		connector, bksv.words, bstatus.word, bcaps, repeater_present);
+	if (ret) {
+		drm_err(dev, "Failed to store bksv, %d\n", ret);
+		return ret;
+	}
+
+	ret = funcs->hdcp1_enable_encryption(connector);
+	if (ret)
+		return ret;
+
+	ret = funcs->hdcp1_wait_for_r0(connector);
+	if (ret)
+		return ret;
+
+	tmp_jiffies = jiffies;
+	if (time_before(tmp_jiffies, r0_prime_timeout))
+		r0_prime_remaining_us =
+			jiffies_to_usecs(r0_prime_timeout - tmp_jiffies);
+
+	/*
+	 * Wait for R0' to become available.
+	 *
+	 * On DP, there's an R0_READY bit available but no such bit
+	 * exists on HDMI. So poll the ready bit for DP and just wait the
+	 * remainder of the 300 ms timeout for HDMI.
+	 */
+	if (data->aux) {
+		u8 val;
+		ret = read_poll_timeout(
+			drm_hdcp_remote_dpcd_read, ret,
+			!ret && (val & DP_BSTATUS_R0_PRIME_READY), 1000,
+			r0_prime_remaining_us, false, data->aux,
+			DP_AUX_HDCP_BSTATUS, &val, 1);
+		if (ret) {
+			drm_err(dev, "R0' did not become ready %d\n", ret);
+			return ret;
+		}
+	} else {
+		usleep_range(r0_prime_remaining_us,
+			     r0_prime_remaining_us + 1000);
+	}
+
+	/*
+	 * DP HDCP Spec mandates the two more reattempt to read R0, in case
+	 * of R0 mismatch.
+	 */
+	for (i = 0; i < tries; i++) {
+		ret = drm_hdcp_helper_hdcp1_validate_ri(data);
+		if (!ret)
+			break;
+	}
+	if (ret) {
+		drm_err(dev, "Failed to match R0/R0', aborting HDCP %d\n", ret);
+		return ret;
+	}
+
+	if (repeater_present)
+		return drm_hdcp_helper_hdcp1_authenticate_downstream(data);
+
+	drm_dbg_kms(dev, "HDCP is enabled (no repeater present)\n");
+	return 0;
+}
+
+static int drm_hdcp_helper_hdcp1_enable(struct drm_hdcp_helper_data *data)
+{
+	struct drm_connector *connector = data->connector;
+	struct drm_device *dev = connector->dev;
+	int i, ret, tries = 3;
+
+	drm_dbg_kms(dev, "[%s:%d] HDCP is being enabled...\n", connector->name,
+		    connector->base.id);
+
+	/* In case of authentication failures, HDCP spec expects reauth. */
+	for (i = 0; i < tries; i++) {
+		ret = drm_hdcp_helper_hdcp1_authenticate(data);
+		if (!ret)
+			return 0;
+
+		drm_dbg_kms(dev, "HDCP Auth failure (%d)\n", ret);
+
+		/* Ensuring HDCP encryption and signalling are stopped. */
+		data->funcs->hdcp1_disable(data->connector);
+	}
+
+	drm_err(dev, "HDCP authentication failed (%d tries/%d)\n", tries, ret);
+	return ret;
+}
+
+static inline void
+drm_hdcp_helper_driver_lock(struct drm_hdcp_helper_data *data)
+{
+	if (data->driver_mutex)
+		mutex_lock(data->driver_mutex);
+}
+
+static inline void
+drm_hdcp_helper_driver_unlock(struct drm_hdcp_helper_data *data)
+{
+	if (data->driver_mutex)
+		mutex_unlock(data->driver_mutex);
+}
+
+static int drm_hdcp_helper_enable_hdcp(struct drm_hdcp_helper_data *data,
+				       struct drm_atomic_state *state,
+				       struct mutex *driver_mutex)
+{
+	struct drm_connector *connector = data->connector;
+	struct drm_connector_state *conn_state;
+	struct drm_device *dev = connector->dev;
+	unsigned long check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
+	bool capable;
+	int ret = 0;
+
+	conn_state = drm_atomic_get_new_connector_state(state, connector);
+
+	mutex_lock(&data->mutex);
+
+	if (data->value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
+		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_ENABLED,
+				      true);
+		goto out_data_mutex;
+	}
+
+	drm_WARN_ON(dev, data->driver_mutex != NULL);
+	data->driver_mutex = driver_mutex;
+
+	drm_hdcp_helper_driver_lock(data);
+
+	if (data->funcs->setup) {
+		ret = data->funcs->setup(connector, state);
+		if (ret) {
+			drm_err(dev, "Failed to setup HDCP %d\n", ret);
+			goto out;
+		}
+	}
+
+	if (!data->funcs->are_keys_valid ||
+	    !data->funcs->are_keys_valid(connector)) {
+		if (data->funcs->load_keys) {
+			ret = data->funcs->load_keys(connector);
+			if (ret) {
+				drm_err(dev, "Failed to load HDCP keys %d\n",
+					ret);
+				goto out;
+			}
+		}
+	}
+
+	/*
+	 * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
+	 * is capable of HDCP2.2, it is preferred to use HDCP2.2.
+	 */
+	ret = data->funcs->hdcp2_capable(connector, &capable);
+	if (ret) {
+		drm_err(dev, "HDCP 2.x capability check failed %d\n", ret);
+		goto out;
+	}
+	if (capable) {
+		data->enabled_type = DRM_MODE_HDCP_CONTENT_TYPE1;
+		ret = data->funcs->hdcp2_enable(connector);
+		if (!ret) {
+			check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
+			goto out;
+		}
+	}
+
+	/*
+	 * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
+	 * be attempted.
+	 */
+	ret = drm_hdcp_helper_hdcp1_capable(data, &capable);
+	if (ret) {
+		drm_err(dev, "HDCP 1.x capability check failed %d\n", ret);
+		goto out;
+	}
+	if (capable &&
+	    conn_state->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) {
+		data->enabled_type = DRM_MODE_HDCP_CONTENT_TYPE0;
+		ret = drm_hdcp_helper_hdcp1_enable(data);
+		if (!ret)
+			check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
+	}
+
+out:
+	if (!ret) {
+		schedule_delayed_work(&data->check_work, check_link_interval);
+		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_ENABLED,
+				      true);
+	}
+
+	drm_hdcp_helper_driver_unlock(data);
+	if (ret)
+		data->driver_mutex = NULL;
+
+out_data_mutex:
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+
+static int drm_hdcp_helper_disable_hdcp(struct drm_hdcp_helper_data *data)
+{
+	int ret = 0;
+
+	mutex_lock(&data->mutex);
+	drm_hdcp_helper_driver_lock(data);
+
+	if (data->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+		goto out;
+
+	drm_dbg_kms(data->connector->dev, "[%s:%d] HDCP is being disabled...\n",
+		    data->connector->name, data->connector->base.id);
+
+	drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_UNDESIRED,
+			      true);
+
+	if (data->enabled_type == DRM_MODE_HDCP_CONTENT_TYPE1)
+		ret = data->funcs->hdcp2_disable(data->connector);
+	else
+		ret = data->funcs->hdcp1_disable(data->connector);
+
+	drm_dbg_kms(data->connector->dev, "HDCP is disabled\n");
+
+out:
+	drm_hdcp_helper_driver_unlock(data);
+	data->driver_mutex = NULL;
+	mutex_unlock(&data->mutex);
+	cancel_delayed_work_sync(&data->check_work);
+	return ret;
+}
+
+/**
+ * drm_hdcp_helper_atomic_commit - Helper for drivers to call during commit to
+ * enable/disable HDCP
+ *
+ * @data: pointer to the @drm_hdcp_helper_data for the connector
+ * @state: pointer to the atomic state being committed
+ * @driver_mutex: driver-provided lock to be used while interacting with the driver
+ *
+ * This function can be used by display drivers to determine when HDCP should be
+ * enabled or disabled based on the connector state. It should be called during
+ * steady-state commits as well as connector enable/disable. The function will
+ * handle the HDCP authentication/encryption logic, calling back into the driver
+ * when source operations are necessary.
+ *
+ * @driver_mutex will be retained and used for the duration of the HDCP session
+ * since it will be needed for link checks and retries. This mutex is useful if
+ * the driver has shared resources across connectors which must be serialized.
+ * For example, driver_mutex can be used for MST connectors sharing a common
+ * encoder which should not be accessed/changed concurrently. When the
+ * connector's session is torn down, the mutex will be forgotten by the helper
+ * for this connector until the next session.
+ */
+void drm_hdcp_helper_atomic_commit(struct drm_hdcp_helper_data *data,
+				   struct drm_atomic_state *state,
+				   struct mutex *driver_mutex)
+{
+	struct drm_connector *connector = data->connector;
+	struct drm_connector_state *conn_state;
+	bool type_changed;
+
+	conn_state = drm_atomic_get_new_connector_state(state, connector);
+
+	type_changed = conn_state->hdcp_content_type != data->enabled_type;
+
+	if (conn_state->content_protection ==
+	    DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+		drm_hdcp_helper_disable_hdcp(data);
+		return;
+	}
+
+	if (!conn_state->crtc) {
+		drm_hdcp_helper_disable_hdcp(data);
+
+		/* Restore property to DESIRED so it's retried later */
+		if (conn_state->content_protection ==
+		    DRM_MODE_CONTENT_PROTECTION_ENABLED) {
+			mutex_lock(&data->mutex);
+			drm_hdcp_update_value(
+				data, DRM_MODE_CONTENT_PROTECTION_DESIRED,
+				true);
+			mutex_unlock(&data->mutex);
+		}
+		return;
+	}
+
+	/* Already enabled */
+	if (conn_state->content_protection ==
+	    DRM_MODE_CONTENT_PROTECTION_ENABLED)
+		return;
+
+	/* Disable and re-enable HDCP on content type change */
+	if (type_changed)
+		drm_hdcp_helper_disable_hdcp(data);
+
+	drm_hdcp_helper_enable_hdcp(data, state, driver_mutex);
+}
+EXPORT_SYMBOL(drm_hdcp_helper_atomic_commit);
+
+static void drm_hdcp_helper_prop_work(struct work_struct *work)
+{
+	struct drm_hdcp_helper_data *data =
+		container_of(work, struct drm_hdcp_helper_data, prop_work);
+	struct drm_connector *connector = data->connector;
+	struct drm_device *dev = connector->dev;
+
+	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+	mutex_lock(&data->mutex);
+
+	/*
+	 * This worker is only used to flip between ENABLED/DESIRED. Either of
+	 * those to UNDESIRED is handled by core. If value == UNDESIRED,
+	 * we're running just after hdcp has been disabled, so just exit
+	 */
+	if (data->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+		drm_hdcp_update_content_protection(connector, data->value);
+
+	mutex_unlock(&data->mutex);
+	drm_modeset_unlock(&dev->mode_config.connection_mutex);
+}
+
+static int drm_hdcp_hdcp1_check_link(struct drm_hdcp_helper_data *data)
+{
+	struct drm_connector *connector = data->connector;
+	struct drm_device *dev = connector->dev;
+	int ret;
+
+	if (data->funcs->hdcp1_check_link) {
+		ret = data->funcs->hdcp1_check_link(connector);
+		if (ret)
+			goto retry;
+	}
+
+	/* The link is checked differently for DP and HDMI */
+	if (data->aux) {
+		u8 bstatus;
+		ret = drm_hdcp_remote_dpcd_read(data->aux, DP_AUX_HDCP_BSTATUS,
+						&bstatus, 1);
+		if (ret) {
+			drm_err(dev, "Failed to read dpcd bstatus, %d\n", ret);
+			return ret;
+		}
+		if (bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ))
+			ret = -EINVAL;
+	} else {
+		ret = drm_hdcp_helper_hdcp1_validate_ri(data);
+		if (ret)
+			drm_err(dev, "Ri' mismatch, check failed (%d)\n", ret);
+	}
+	if (!ret)
+		return 0;
+
+retry:
+	drm_err(dev, "[%s:%d] HDCP link failed, retrying authentication\n",
+		connector->name, connector->base.id);
+
+	ret = data->funcs->hdcp1_disable(connector);
+	if (ret) {
+		drm_err(dev, "Failed to disable hdcp (%d)\n", ret);
+		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_DESIRED,
+				      true);
+		return ret;
+	}
+
+	ret = drm_hdcp_helper_hdcp1_enable(data);
+	if (ret) {
+		drm_err(dev, "Failed to enable hdcp (%d)\n", ret);
+		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_DESIRED,
+				      true);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int drm_hdcp_hdcp2_check_link(struct drm_hdcp_helper_data *data)
+{
+	struct drm_connector *connector = data->connector;
+	struct drm_device *dev = connector->dev;
+	int ret;
+
+	ret = data->funcs->hdcp2_check_link(connector);
+	if (!ret)
+		return 0;
+
+	drm_err(dev, "[%s:%d] HDCP2 link failed, retrying authentication\n",
+		connector->name, connector->base.id);
+
+	ret = data->funcs->hdcp2_disable(connector);
+	if (ret) {
+		drm_err(dev, "Failed to disable hdcp2 (%d)\n", ret);
+		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_DESIRED,
+				      true);
+		return ret;
+	}
+
+	ret = data->funcs->hdcp2_enable(connector);
+	if (ret) {
+		drm_err(dev, "Failed to enable hdcp2 (%d)\n", ret);
+		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_DESIRED,
+				      true);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void drm_hdcp_helper_check_work(struct work_struct *work)
+{
+	struct drm_hdcp_helper_data *data = container_of(
+		to_delayed_work(work), struct drm_hdcp_helper_data, check_work);
+	unsigned long check_link_interval;
+
+	mutex_lock(&data->mutex);
+	if (data->value != DRM_MODE_CONTENT_PROTECTION_ENABLED)
+		goto out_data_mutex;
+
+	drm_hdcp_helper_driver_lock(data);
+
+	if (data->enabled_type == DRM_MODE_HDCP_CONTENT_TYPE1) {
+		if (drm_hdcp_hdcp2_check_link(data))
+			goto out;
+		check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
+	} else {
+		if (drm_hdcp_hdcp1_check_link(data))
+			goto out;
+		check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
+	}
+	schedule_delayed_work(&data->check_work, check_link_interval);
+
+out:
+	drm_hdcp_helper_driver_unlock(data);
+out_data_mutex:
+	mutex_unlock(&data->mutex);
+}
+
+/**
+ * drm_hdcp_helper_schedule_hdcp_check - Schedule a check link cycle.
+ *
+ * @data: Pointer to the HDCP helper data.
+ *
+ * This function will kick off a check link cycle on behalf of the caller. This
+ * can be used by DP short hpd interrupt handlers, where the driver must poke
+ * the helper to check the link is still valid.
+ */
+void drm_hdcp_helper_schedule_hdcp_check(struct drm_hdcp_helper_data *data)
+{
+	schedule_delayed_work(&data->check_work, 0);
+}
+EXPORT_SYMBOL(drm_hdcp_helper_schedule_hdcp_check);
+
+static struct drm_hdcp_helper_data *
+drm_hdcp_helper_initialize(struct drm_connector *connector,
+			   const struct drm_hdcp_helper_funcs *funcs,
+			   bool attach_content_type_property)
+{
+	struct drm_hdcp_helper_data *out;
+	int ret;
+
+	out = kzalloc(sizeof(*out), GFP_KERNEL);
+	if (!out)
+		return ERR_PTR(-ENOMEM);
+
+	out->connector = connector;
+	out->funcs = funcs;
+
+	mutex_init(&out->mutex);
+	out->value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+
+	INIT_DELAYED_WORK(&out->check_work, drm_hdcp_helper_check_work);
+	INIT_WORK(&out->prop_work, drm_hdcp_helper_prop_work);
+
+	ret = drm_connector_attach_content_protection_property(
+		connector, attach_content_type_property);
+	if (ret) {
+		drm_hdcp_helper_destroy(out);
+		return ERR_PTR(ret);
+	}
+
+	return out;
+}
+
+/**
+ * drm_hdcp_helper_initialize_dp - Initializes the HDCP helpers for a
+ * DisplayPort connector
+ *
+ * @connector: pointer to the DisplayPort connector.
+ * @funcs: pointer to the vtable of HDCP helper funcs for this connector.
+ * @attach_content_type_property: True if the content_type property should be
+ * attached.
+ *
+ * This function initializes the HDCP helper for the given DisplayPort connector.
+ * This involves creating the Content Protection property as well as the Content
+ * Type property (if desired). Upon success, it will return a pointer to the
+ * HDCP helper data. Ownership of the underlying memory is ttransferredto the
+ * caller and should be freed using drm_hdcp_helper_destroy().
+ *
+ * Returns:
+ * Pointer to newly created HDCP helper data. PTR_ERR on failure.
+ */
+struct drm_hdcp_helper_data *
+drm_hdcp_helper_initialize_dp(struct drm_connector *connector,
+			      struct drm_dp_aux *aux,
+			      const struct drm_hdcp_helper_funcs *funcs,
+			      bool attach_content_type_property)
+{
+	struct drm_hdcp_helper_data *out;
+
+	out = drm_hdcp_helper_initialize(connector, funcs,
+					 attach_content_type_property);
+	if (IS_ERR(out))
+		return out;
+
+	out->aux = aux;
+	out->hdcp1_lut = &drm_hdcp_hdcp1_dpcd_lut;
+
+	return out;
+}
+EXPORT_SYMBOL(drm_hdcp_helper_initialize_dp);
+
+/**
+ * drm_hdcp_helper_initialize_hdmi - Initializes the HDCP helpers for an HDMI
+ * connector
+ *
+ * @connector: pointer to the HDMI connector.
+ * @funcs: pointer to the vtable of HDCP helper funcs for this connector.
+ * @attach_content_type_property: True if the content_type property should be
+ * attached.
+ *
+ * This function initializes the HDCP helper for the given HDMI connector. This
+ * involves creating the Content Protection property as well as the Content Type
+ * property (if desired). Upon success, it will return a pointer to the HDCP
+ * helper data. Ownership of the underlying memory is transferred to the caller
+ * and should be freed using drm_hdcp_helper_destroy().
+ *
+ * Returns:
+ * Pointer to newly created HDCP helper data. PTR_ERR on failure.
+ */
+struct drm_hdcp_helper_data *
+drm_hdcp_helper_initialize_hdmi(struct drm_connector *connector,
+				const struct drm_hdcp_helper_funcs *funcs,
+				bool attach_content_type_property)
+{
+	struct drm_hdcp_helper_data *out;
+
+	out = drm_hdcp_helper_initialize(connector, funcs,
+					 attach_content_type_property);
+	if (IS_ERR(out))
+		return out;
+
+	out->hdcp1_lut = &drm_hdcp_hdcp1_ddc_lut;
+
+	return out;
+}
+EXPORT_SYMBOL(drm_hdcp_helper_initialize_hdmi);
+
+/**
+ * drm_hdcp_helper_destroy - Destroys the given HDCP helper data.
+ *
+ * @data: Pointer to the HDCP helper data.
+ *
+ * This function cleans up and destroys the HDCP helper data created by
+ * drm_hdcp_helper_initialize_dp() or drm_hdcp_helper_initialize_hdmi().
+ */
+void drm_hdcp_helper_destroy(struct drm_hdcp_helper_data *data)
+{
+	struct drm_connector *connector;
+
+	if (!data)
+		return;
+
+	connector = data->connector;
+
+	/*
+	 * If the connector is registered, it's possible userspace could kick
+	 * off another HDCP enable, which would re-spawn the workers.
+	 */
+	drm_WARN_ON(connector->dev,
+		    connector->registration_state == DRM_CONNECTOR_REGISTERED);
+
+	/*
+	 * Now that the connector is not registered, check_work won't be run,
+	 * but cancel any outstanding instances of it
+	 */
+	cancel_delayed_work_sync(&data->check_work);
+
+	/*
+	 * We don't cancel prop_work in the same way as check_work since it
+	 * requires connection_mutex which could be held while calling this
+	 * function. Instead, we rely on the connector references grabbed before
+	 * scheduling prop_work to ensure the connector is alive when prop_work
+	 * is run. So if we're in the destroy path (which is where this
+	 * function should be called), we're "guaranteed" that prop_work is not
+	 * active (tl;dr This Should Never Happen).
+	 */
+	drm_WARN_ON(connector->dev, work_pending(&data->prop_work));
+
+	kfree(data);
+}
+EXPORT_SYMBOL(drm_hdcp_helper_destroy);
diff --git a/include/drm/display/drm_hdcp.h b/include/drm/display/drm_hdcp.h
index 96a99b1377c0..75694baf72d4 100644
--- a/include/drm/display/drm_hdcp.h
+++ b/include/drm/display/drm_hdcp.h
@@ -36,6 +36,7 @@
 #define DRM_HDCP_DDC_BKSV			0x00
 #define DRM_HDCP_DDC_RI_PRIME			0x08
 #define DRM_HDCP_DDC_AKSV			0x10
+#define DRM_HDCP_DDC_AINFO			0x15
 #define DRM_HDCP_DDC_AN				0x18
 #define DRM_HDCP_DDC_V_PRIME(h)			(0x20 + h * 4)
 #define DRM_HDCP_DDC_BCAPS			0x40
@@ -123,6 +124,19 @@
 #define HDCP_2_2_DEV_COUNT_HI(x)		((x) & BIT(0))
 #define HDCP_2_2_DEPTH(x)			(((x) & (0x7 << 1)) >> 1)
 
+struct drm_hdcp_ksv {
+	union {
+		u32 words[2];
+		u8 bytes[DRM_HDCP_KSV_LEN];
+	};
+};
+struct drm_hdcp_an {
+	union {
+		u32 words[2];
+		u8 bytes[DRM_HDCP_AN_LEN];
+	};
+};
+
 struct hdcp2_cert_rx {
 	u8	receiver_id[HDCP_2_2_RECEIVER_ID_LEN];
 	u8	kpub_rx[HDCP_2_2_K_PUB_RX_LEN];
@@ -295,4 +309,156 @@ struct hdcp_srm_header {
 #define DRM_MODE_HDCP_CONTENT_TYPE0		0
 #define DRM_MODE_HDCP_CONTENT_TYPE1		1
 
-#endif
+struct drm_connector;
+struct drm_atomic_state;
+
+/**
+ * struct drm_hdcp_helper_funcs - A vtable of function hooks for the hdcp helper
+ *
+ * These hooks are used by the hdcp helper to call into the driver/connector
+ * code to read/write to hw.
+ */
+struct drm_hdcp_helper_funcs {
+	/**
+	 * @setup - Performs driver-specific setup before hdcp is enabled
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*setup)(struct drm_connector *connector,
+		     struct drm_atomic_state *state);
+
+	/**
+	 * @are_keys_valid - Checks if the HDCP transmitter keys are valid
+	 *
+	 * Returns: true if the display controller has valid keys loaded
+	 */
+	bool (*are_keys_valid)(struct drm_connector *connector);
+
+	/**
+	 * @load_keys - Instructs the driver to load its HDCP transmitter keys
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*load_keys)(struct drm_connector *connector);
+
+	/**
+	 * @hdcp2_capable - Checks if both source and sink support HDCP 2.x
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp2_capable)(struct drm_connector *connector, bool *capable);
+
+	/**
+	 * @hdcp2_enable - Enables HDCP 2.x on the specified connector
+	 *
+	 * Since we don't have multiple examples of HDCP 2.x enablement, we
+	 * provide the bare minimum support for HDCP 2.x help. Once we have
+	 * more examples, perhaps we can be more helpful.
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp2_enable)(struct drm_connector *connector);
+
+	/**
+	 * @hdcp2_check_link - Checks the HDCP 2.x link on a specified connector
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp2_check_link)(struct drm_connector *connector);
+
+	/**
+	 * @hdcp2_disable - Disables HDCP 2.x on the specified connector
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp2_disable)(struct drm_connector *connector);
+
+	/**
+	 * @hdcp1_read_an_aksv - Reads transmitter's An & Aksv from hardware
+	 *
+	 * Use this function if hardware allows reading the transmitter's An and
+	 * Aksv values from the kernel. If your hardware will not allow this,
+	 * use hdcp1_send_an_aksv() and implement the transmission in the
+	 * driver.
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp1_read_an_aksv)(struct drm_connector *connector, u32 *an,
+				  u32 *aksv);
+
+	/**
+	 * @hdcp1_send_an_aksv - Sends transmitter's An & Aksv to the receiver
+	 *
+	 * Only implement this on hardware where An or Aksv are not accessible
+	 * from the kernel. If these values can be read, use
+	 * hdcp1_read_an_aksv() instead.
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp1_send_an_aksv)(struct drm_connector *connector);
+
+	/**
+	 * @hdcp1_store_receiver_info - Stores the receiver's info in the transmitter
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp1_store_receiver_info)(struct drm_connector *connector,
+					 u32 *ksv, u32 status, u8 caps,
+					 bool repeater_present);
+
+	/**
+	 * @hdcp1_enable_encryption - Enables encryption of the outgoing signal
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp1_enable_encryption)(struct drm_connector *connector);
+
+	/**
+	 * @hdcp1_wait_for_r0 - Wait for transmitter to calculate R0
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp1_wait_for_r0)(struct drm_connector *connector);
+
+	/**
+	 * @hdcp1_match_ri - Matches the given Ri from the receiver with Ri in
+	 * the transmitter
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp1_match_ri)(struct drm_connector *connector, u32 ri_prime);
+
+	/**
+	 * @hdcp1_post_encryption - Allows the driver to confirm encryption and
+	 * perform any post-processing
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp1_post_encryption)(struct drm_connector *connector);
+
+	/**
+	 * @hdcp1_store_ksv_fifo - Write the receiver's KSV list to transmitter
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp1_store_ksv_fifo)(struct drm_connector *connector,
+				    u8 *ksv_fifo, u8 num_downstream,
+				    u8 *bstatus, u32 *vprime);
+
+	/**
+	 * @hdcp1_check_link - Allows the driver to check the HDCP 1.x status
+	 * on a specified connector
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp1_check_link)(struct drm_connector *connector);
+
+	/**
+	 * @hdcp1_disable - Disables HDCP 1.x on the specified connector
+	 *
+	 * Returns: 0 on success, -errno on failure
+	 */
+	int (*hdcp1_disable)(struct drm_connector *connector);
+};
+
+#endif  // INCLUDE_DRM_DISPLAY_DRM_HDCP_H_
diff --git a/include/drm/display/drm_hdcp_helper.h b/include/drm/display/drm_hdcp_helper.h
index cb2cc5002f65..dbbaced148f2 100644
--- a/include/drm/display/drm_hdcp_helper.h
+++ b/include/drm/display/drm_hdcp_helper.h
@@ -15,11 +15,39 @@ struct drm_atomic_state;
 struct drm_device;
 struct drm_connector;
 
+struct drm_hdcp_helper_data;
+struct drm_dp_aux;
+struct i2c_adapter;
+struct mutex;
+
 int drm_hdcp_check_ksvs_revoked(struct drm_device *dev, u8 *ksvs, u32 ksv_count);
 int drm_connector_attach_content_protection_property(struct drm_connector *connector,
 						     bool hdcp_content_type);
 void drm_hdcp_update_content_protection(struct drm_connector *connector, u64 val);
 bool drm_hdcp_atomic_check(struct drm_connector *connector,
 			   struct drm_atomic_state *state);
+void drm_hdcp_atomic_commit(struct drm_atomic_state *state,
+			    struct drm_connector *connector);
+
+struct drm_hdcp_helper_data *
+drm_hdcp_helper_initialize_dp(struct drm_connector *connector,
+			      struct drm_dp_aux *aux,
+			      const struct drm_hdcp_helper_funcs *funcs,
+			      bool attach_content_type_property);
+
+struct drm_hdcp_helper_data *
+drm_hdcp_helper_initialize_hdmi(struct drm_connector *connector,
+				const struct drm_hdcp_helper_funcs *funcs,
+				bool attach_content_type_property);
+
+void drm_hdcp_helper_destroy(struct drm_hdcp_helper_data *data);
+
+int drm_hdcp_helper_hdcp1_capable(struct drm_hdcp_helper_data *data,
+				  bool *capable);
+void drm_hdcp_helper_atomic_commit(struct drm_hdcp_helper_data *data,
+				   struct drm_atomic_state *state,
+				   struct mutex *driver_mutex);
+
+void drm_hdcp_helper_schedule_hdcp_check(struct drm_hdcp_helper_data *data);
 
-#endif
+#endif  // INCLUDE_DRM_DISPLAY_DRM_HDCP_HELPER_H_"
-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v6 05/10] drm/i915/hdcp: Consolidate HDCP setup/state cache
  2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
                   ` (3 preceding siblings ...)
  2023-01-18 19:30 ` [PATCH v6 04/10] drm/hdcp: Expand HDCP helper library for enable/disable/check Mark Yacoub
@ 2023-01-18 19:30 ` Mark Yacoub
  2023-01-18 19:30 ` [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes Mark Yacoub
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul, Jani Nikula

From: Sean Paul <seanpaul@chromium.org>

Stick all of the setup for HDCP into a dedicated function. No functional
change, but this will facilitate moving HDCP logic into helpers.

Acked-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-6-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-6-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-6-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-6-sean@poorly.run #v4
Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-6-sean@poorly.run #v5

Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:
-None

---
 drivers/gpu/drm/i915/display/intel_hdcp.c | 52 +++++++++++++++--------
 1 file changed, 35 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c
index 396d2cef000a..0a20bc41be55 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
@@ -2190,6 +2190,37 @@ static enum mei_fw_tc intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
 	}
 }
 
+static int
+_intel_hdcp_setup(struct intel_connector *connector,
+		  const struct intel_crtc_state *pipe_config, u8 content_type)
+{
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
+	struct intel_hdcp *hdcp = &connector->hdcp;
+	int ret = 0;
+
+	if (!connector->encoder) {
+		drm_err(&dev_priv->drm, "[%s:%d] encoder is not initialized\n",
+			connector->base.name, connector->base.base.id);
+		return -ENODEV;
+	}
+
+	hdcp->content_type = content_type;
+
+	if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
+		hdcp->cpu_transcoder = pipe_config->mst_master_transcoder;
+		hdcp->stream_transcoder = pipe_config->cpu_transcoder;
+	} else {
+		hdcp->cpu_transcoder = pipe_config->cpu_transcoder;
+		hdcp->stream_transcoder = INVALID_TRANSCODER;
+	}
+
+	if (DISPLAY_VER(dev_priv) >= 12)
+		dig_port->hdcp_port_data.fw_tc = intel_get_mei_fw_tc(hdcp->cpu_transcoder);
+
+	return ret;
+}
+
 static int initialize_hdcp_port_data(struct intel_connector *connector,
 				     struct intel_digital_port *dig_port,
 				     const struct intel_hdcp_shim *shim)
@@ -2329,28 +2360,14 @@ int intel_hdcp_enable(struct intel_connector *connector,
 	if (!hdcp->shim)
 		return -ENOENT;
 
-	if (!connector->encoder) {
-		drm_err(&dev_priv->drm, "[%s:%d] encoder is not initialized\n",
-			connector->base.name, connector->base.base.id);
-		return -ENODEV;
-	}
-
 	mutex_lock(&hdcp->mutex);
 	mutex_lock(&dig_port->hdcp_mutex);
 	drm_WARN_ON(&dev_priv->drm,
 		    hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
-	hdcp->content_type = content_type;
-
-	if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
-		hdcp->cpu_transcoder = pipe_config->mst_master_transcoder;
-		hdcp->stream_transcoder = pipe_config->cpu_transcoder;
-	} else {
-		hdcp->cpu_transcoder = pipe_config->cpu_transcoder;
-		hdcp->stream_transcoder = INVALID_TRANSCODER;
-	}
 
-	if (DISPLAY_VER(dev_priv) >= 12)
-		dig_port->hdcp_port_data.fw_tc = intel_get_mei_fw_tc(hdcp->cpu_transcoder);
+	ret = _intel_hdcp_setup(connector, pipe_config, content_type);
+	if (ret)
+		goto out;
 
 	/*
 	 * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
@@ -2378,6 +2395,7 @@ int intel_hdcp_enable(struct intel_connector *connector,
 					true);
 	}
 
+out:
 	mutex_unlock(&dig_port->hdcp_mutex);
 	mutex_unlock(&hdcp->mutex);
 	return ret;
-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes
  2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
                   ` (4 preceding siblings ...)
  2023-01-18 19:30 ` [PATCH v6 05/10] drm/i915/hdcp: Consolidate HDCP setup/state cache Mark Yacoub
@ 2023-01-18 19:30 ` Mark Yacoub
  2023-03-10  8:25   ` Kandpal, Suraj
  2023-01-18 19:30 ` [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915 Mark Yacoub
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul, Jani Nikula

From: Sean Paul <seanpaul@chromium.org>

The shim functions return error codes, but they are discarded in
intel_hdcp.c. This patch plumbs the return codes through so they are
properly handled.

Acked-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-7-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-7-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-7-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-7-sean@poorly.run #v4
Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-7-sean@poorly.run #v5

Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:
-Rebased

---
 .../drm/i915/display/intel_display_debugfs.c  |  9 +++-
 drivers/gpu/drm/i915/display/intel_hdcp.c     | 51 ++++++++++---------
 drivers/gpu/drm/i915/display/intel_hdcp.h     |  4 +-
 3 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 7c7253a2541c..13a4153bb76e 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -492,6 +492,7 @@ static void intel_panel_info(struct seq_file *m,
 static void intel_hdcp_info(struct seq_file *m,
 			    struct intel_connector *intel_connector)
 {
+	int ret;
 	bool hdcp_cap, hdcp2_cap;
 
 	if (!intel_connector->hdcp.shim) {
@@ -499,8 +500,12 @@ static void intel_hdcp_info(struct seq_file *m,
 		goto out;
 	}
 
-	hdcp_cap = intel_hdcp_capable(intel_connector);
-	hdcp2_cap = intel_hdcp2_capable(intel_connector);
+	ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
+	if (ret)
+		hdcp_cap = false;
+	ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
+	if (ret)
+		hdcp2_cap = false;
 
 	if (hdcp_cap)
 		seq_puts(m, "HDCP1.4 ");
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c
index 0a20bc41be55..61a862ae1f28 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
@@ -177,50 +177,49 @@ int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port,
 }
 
 /* Is HDCP1.4 capable on Platform and Sink */
-bool intel_hdcp_capable(struct intel_connector *connector)
+int intel_hdcp_capable(struct intel_connector *connector, bool *capable)
 {
 	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
 	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
-	bool capable = false;
 	u8 bksv[5];
 
+	*capable = false;
+
 	if (!shim)
-		return capable;
+		return 0;
 
-	if (shim->hdcp_capable) {
-		shim->hdcp_capable(dig_port, &capable);
-	} else {
-		if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
-			capable = true;
-	}
+	if (shim->hdcp_capable)
+		return shim->hdcp_capable(dig_port, capable);
+
+	if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
+		*capable = true;
 
-	return capable;
+	return 0;
 }
 
 /* Is HDCP2.2 capable on Platform and Sink */
-bool intel_hdcp2_capable(struct intel_connector *connector)
+int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
 {
 	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	struct intel_hdcp *hdcp = &connector->hdcp;
-	bool capable = false;
+
+	*capable = false;
 
 	/* I915 support for HDCP2.2 */
 	if (!hdcp->hdcp2_supported)
-		return false;
+		return 0;
 
 	/* MEI interface is solid */
 	mutex_lock(&dev_priv->display.hdcp.comp_mutex);
 	if (!dev_priv->display.hdcp.comp_added ||  !dev_priv->display.hdcp.master) {
 		mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
-		return false;
+		return 0;
 	}
 	mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
 
 	/* Sink's capability for HDCP2.2 */
-	hdcp->shim->hdcp_2_2_capable(dig_port, &capable);
-
-	return capable;
+	return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
 }
 
 static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv,
@@ -2355,6 +2354,7 @@ int intel_hdcp_enable(struct intel_connector *connector,
 	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
 	struct intel_hdcp *hdcp = &connector->hdcp;
 	unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
+	bool capable;
 	int ret = -EINVAL;
 
 	if (!hdcp->shim)
@@ -2373,21 +2373,27 @@ int intel_hdcp_enable(struct intel_connector *connector,
 	 * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
 	 * is capable of HDCP2.2, it is preferred to use HDCP2.2.
 	 */
-	if (intel_hdcp2_capable(connector)) {
+	ret = intel_hdcp2_capable(connector, &capable);
+	if (capable) {
 		ret = _intel_hdcp2_enable(connector);
-		if (!ret)
+		if (!ret) {
 			check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
+			goto out;
+		}
 	}
 
 	/*
 	 * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
 	 * be attempted.
 	 */
-	if (ret && intel_hdcp_capable(connector) &&
-	    hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) {
+	ret = intel_hdcp_capable(connector, &capable);
+	if (ret)
+		goto out;
+
+	if (capable && hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1)
 		ret = _intel_hdcp_enable(connector);
-	}
 
+out:
 	if (!ret) {
 		schedule_delayed_work(&hdcp->check_work, check_link_interval);
 		intel_hdcp_update_value(connector,
@@ -2395,7 +2401,6 @@ int intel_hdcp_enable(struct intel_connector *connector,
 					true);
 	}
 
-out:
 	mutex_unlock(&dig_port->hdcp_mutex);
 	mutex_unlock(&hdcp->mutex);
 	return ret;
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h b/drivers/gpu/drm/i915/display/intel_hdcp.h
index 7c5fd84a7b65..f06f6e5a2b1a 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.h
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
@@ -33,8 +33,8 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state,
 			    const struct intel_crtc_state *crtc_state,
 			    const struct drm_connector_state *conn_state);
 bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
-bool intel_hdcp_capable(struct intel_connector *connector);
-bool intel_hdcp2_capable(struct intel_connector *connector);
+int intel_hdcp_capable(struct intel_connector *connector, bool *capable);
+int intel_hdcp2_capable(struct intel_connector *connector, bool *capable);
 void intel_hdcp_component_init(struct drm_i915_private *dev_priv);
 void intel_hdcp_component_fini(struct drm_i915_private *dev_priv);
 void intel_hdcp_cleanup(struct intel_connector *connector);
-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915
  2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
                   ` (5 preceding siblings ...)
  2023-01-18 19:30 ` [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes Mark Yacoub
@ 2023-01-18 19:30 ` Mark Yacoub
  2023-01-31 17:16   ` [Intel-gfx] " Rodrigo Vivi
  2023-03-14  5:54   ` Kandpal, Suraj
  2023-01-18 19:30 ` [PATCH v6 08/10] dt-bindings: msm/dp: Add bindings for HDCP registers Mark Yacoub
                   ` (2 subsequent siblings)
  9 siblings, 2 replies; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul, Jani Nikula

From: Sean Paul <seanpaul@chromium.org>

Now that all of the HDCP 1.x logic has been migrated to the central HDCP
helpers, use it in the i915 driver.

The majority of the driver code for HDCP 1.x will live in intel_hdcp.c,
however there are a few helper hooks which are connector-specific and
need to be partially or fully implemented in the intel_dp_hdcp.c or
intel_hdmi.c.

We'll leave most of the HDCP 2.x code alone since we don't have another
implementation of HDCP 2.x to use as reference for what should and
should not live in the drm helpers. The helper will call the overly
general enable/disable/is_capable HDCP 2.x callbacks and leave the
interesting stuff for the driver. Once we have another HDCP 2.x
implementation, we should do a similar migration.

Acked-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-8-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-8-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-8-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-8-sean@poorly.run #v4
Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-8-sean@poorly.run #v5

Changes in v2:
-Fix mst helper function pointer reported by 0-day
Changes in v3:
-Add forward declaration for drm_atomic_state in intel_hdcp.h identified
 by 0-day
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:
-Rebased.

---
 drivers/gpu/drm/i915/display/intel_ddi.c      |  32 +-
 .../drm/i915/display/intel_display_debugfs.c  |   6 +-
 .../drm/i915/display/intel_display_types.h    |  60 +-
 drivers/gpu/drm/i915/display/intel_dp_hdcp.c  | 348 +++----
 drivers/gpu/drm/i915/display/intel_dp_mst.c   |  16 +-
 drivers/gpu/drm/i915/display/intel_hdcp.c     | 952 +++---------------
 drivers/gpu/drm/i915/display/intel_hdcp.h     |  31 +-
 drivers/gpu/drm/i915/display/intel_hdmi.c     | 270 ++---
 8 files changed, 445 insertions(+), 1270 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 69ecf2a3d6c6..a4397f066a3e 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -28,6 +28,7 @@
 #include <linux/string_helpers.h>
 
 #include <drm/display/drm_scdc_helper.h>
+#include <drm/display/drm_hdcp_helper.h>
 #include <drm/drm_privacy_screen_consumer.h>
 
 #include "i915_drv.h"
@@ -2909,6 +2910,10 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
 			     const struct intel_crtc_state *crtc_state,
 			     const struct drm_connector_state *conn_state)
 {
+	struct intel_connector *connector =
+		to_intel_connector(conn_state->connector);
+	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+
 	drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
 
 	if (!intel_crtc_is_bigjoiner_slave(crtc_state))
@@ -2925,12 +2930,10 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
 	else
 		intel_enable_ddi_dp(state, encoder, crtc_state, conn_state);
 
-	/* Enable hdcp if it's desired */
-	if (conn_state->content_protection ==
-	    DRM_MODE_CONTENT_PROTECTION_DESIRED)
-		intel_hdcp_enable(to_intel_connector(conn_state->connector),
-				  crtc_state,
-				  (u8)conn_state->hdcp_content_type);
+	if (connector->hdcp_helper_data)
+		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+					      &state->base,
+					      &dig_port->hdcp_mutex);
 }
 
 static void intel_disable_ddi_dp(struct intel_atomic_state *state,
@@ -2976,7 +2979,14 @@ static void intel_disable_ddi(struct intel_atomic_state *state,
 			      const struct intel_crtc_state *old_crtc_state,
 			      const struct drm_connector_state *old_conn_state)
 {
-	intel_hdcp_disable(to_intel_connector(old_conn_state->connector));
+	struct intel_connector *connector =
+		to_intel_connector(old_conn_state->connector);
+	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+
+	if (connector->hdcp_helper_data)
+		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+					      &state->base,
+					      &dig_port->hdcp_mutex);
 
 	if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
 		intel_disable_ddi_hdmi(state, encoder, old_crtc_state,
@@ -3004,13 +3014,19 @@ void intel_ddi_update_pipe(struct intel_atomic_state *state,
 			   const struct intel_crtc_state *crtc_state,
 			   const struct drm_connector_state *conn_state)
 {
+	struct intel_connector *connector =
+		to_intel_connector(conn_state->connector);
+	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
 
 	if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
 	    !intel_encoder_is_mst(encoder))
 		intel_ddi_update_pipe_dp(state, encoder, crtc_state,
 					 conn_state);
 
-	intel_hdcp_update_pipe(state, encoder, crtc_state, conn_state);
+	if (connector->hdcp_helper_data)
+		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+					      &state->base,
+					      &dig_port->hdcp_mutex);
 }
 
 static void
diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 13a4153bb76e..2e67cca0151c 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -7,6 +7,7 @@
 
 #include <drm/drm_debugfs.h>
 #include <drm/drm_fourcc.h>
+#include <drm/display/drm_hdcp_helper.h>
 
 #include "i915_debugfs.h"
 #include "intel_de.h"
@@ -500,10 +501,11 @@ static void intel_hdcp_info(struct seq_file *m,
 		goto out;
 	}
 
-	ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
+	ret = drm_hdcp_helper_hdcp1_capable(intel_connector->hdcp_helper_data,
+					    &hdcp_cap);
 	if (ret)
 		hdcp_cap = false;
-	ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
+	ret = intel_hdcp2_capable(&intel_connector->base, &hdcp2_cap);
 	if (ret)
 		hdcp2_cap = false;
 
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 298d00a11f47..6260a40586ae 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -416,71 +416,14 @@ enum check_link_response {
  *		The offsets of the registers are different for DP vs. HDMI
  *	- Receiver register masks/offsets
  *		For instance, the ready bit for the KSV fifo is in a different
- *		place on DP vs HDMI
- *	- Receiver register names
- *		Seriously. In the DP spec, the 16-bit register containing
- *		downstream information is called BINFO, on HDMI it's called
- *		BSTATUS. To confuse matters further, DP has a BSTATUS register
- *		with a completely different definition.
- *	- KSV FIFO
- *		On HDMI, the ksv fifo is read all at once, whereas on DP it must
- *		be read 3 keys at a time
- *	- Aksv output
- *		Since Aksv is hidden in hardware, there's different procedures
- *		to send it over DP AUX vs DDC
+ *		place on DP vs HDMI.
  */
 struct intel_hdcp_shim {
-	/* Outputs the transmitter's An and Aksv values to the receiver. */
-	int (*write_an_aksv)(struct intel_digital_port *dig_port, u8 *an);
-
-	/* Reads the receiver's key selection vector */
-	int (*read_bksv)(struct intel_digital_port *dig_port, u8 *bksv);
-
-	/*
-	 * Reads BINFO from DP receivers and BSTATUS from HDMI receivers. The
-	 * definitions are the same in the respective specs, but the names are
-	 * different. Call it BSTATUS since that's the name the HDMI spec
-	 * uses and it was there first.
-	 */
-	int (*read_bstatus)(struct intel_digital_port *dig_port,
-			    u8 *bstatus);
-
-	/* Determines whether a repeater is present downstream */
-	int (*repeater_present)(struct intel_digital_port *dig_port,
-				bool *repeater_present);
-
-	/* Reads the receiver's Ri' value */
-	int (*read_ri_prime)(struct intel_digital_port *dig_port, u8 *ri);
-
-	/* Determines if the receiver's KSV FIFO is ready for consumption */
-	int (*read_ksv_ready)(struct intel_digital_port *dig_port,
-			      bool *ksv_ready);
-
-	/* Reads the ksv fifo for num_downstream devices */
-	int (*read_ksv_fifo)(struct intel_digital_port *dig_port,
-			     int num_downstream, u8 *ksv_fifo);
-
-	/* Reads a 32-bit part of V' from the receiver */
-	int (*read_v_prime_part)(struct intel_digital_port *dig_port,
-				 int i, u32 *part);
-
 	/* Enables HDCP signalling on the port */
 	int (*toggle_signalling)(struct intel_digital_port *dig_port,
 				 enum transcoder cpu_transcoder,
 				 bool enable);
 
-	/* Enable/Disable stream encryption on DP MST Transport Link */
-	int (*stream_encryption)(struct intel_connector *connector,
-				 bool enable);
-
-	/* Ensures the link is still protected */
-	bool (*check_link)(struct intel_digital_port *dig_port,
-			   struct intel_connector *connector);
-
-	/* Detects panel's hdcp capability. This is optional for HDMI. */
-	int (*hdcp_capable)(struct intel_digital_port *dig_port,
-			    bool *hdcp_capable);
-
 	/* HDCP adaptation(DP/HDMI) required on the port */
 	enum hdcp_wired_protocol protocol;
 
@@ -610,6 +553,7 @@ struct intel_connector {
 	struct work_struct modeset_retry_work;
 
 	struct intel_hdcp hdcp;
+	struct drm_hdcp_helper_data *hdcp_helper_data;
 };
 
 struct intel_digital_connector_state {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
index 88689124c013..d61ac8d69951 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
@@ -55,17 +55,24 @@ static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
 		DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
 }
 
-static
-int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
-				u8 *an)
+static int intel_dp_hdcp1_send_an_aksv(struct drm_connector *drm_connector)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
 	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+	struct drm_hdcp_an an;
 	u8 aksv[DRM_HDCP_KSV_LEN] = {};
 	ssize_t dpcd_ret;
+	int ret;
 
 	/* Output An first, that's easy */
+	ret = intel_hdcp1_read_an(drm_connector, &an);
+	if (ret)
+		return ret;
+
 	dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux, DP_AUX_HDCP_AN,
-				     an, DRM_HDCP_AN_LEN);
+				     an.bytes, DRM_HDCP_AN_LEN);
 	if (dpcd_ret != DRM_HDCP_AN_LEN) {
 		drm_dbg_kms(&i915->drm,
 			    "Failed to write An over DP/AUX (%zd)\n",
@@ -91,158 +98,6 @@ int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
 	return 0;
 }
 
-static int intel_dp_hdcp_read_bksv(struct intel_digital_port *dig_port,
-				   u8 *bksv)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	ssize_t ret;
-
-	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
-			       DRM_HDCP_KSV_LEN);
-	if (ret != DRM_HDCP_KSV_LEN) {
-		drm_dbg_kms(&i915->drm,
-			    "Read Bksv from DP/AUX failed (%zd)\n", ret);
-		return ret >= 0 ? -EIO : ret;
-	}
-	return 0;
-}
-
-static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
-				      u8 *bstatus)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	ssize_t ret;
-
-	/*
-	 * For some reason the HDMI and DP HDCP specs call this register
-	 * definition by different names. In the HDMI spec, it's called BSTATUS,
-	 * but in DP it's called BINFO.
-	 */
-	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BINFO,
-			       bstatus, DRM_HDCP_BSTATUS_LEN);
-	if (ret != DRM_HDCP_BSTATUS_LEN) {
-		drm_dbg_kms(&i915->drm,
-			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
-		return ret >= 0 ? -EIO : ret;
-	}
-	return 0;
-}
-
-static
-int intel_dp_hdcp_read_bcaps(struct intel_digital_port *dig_port,
-			     u8 *bcaps)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	ssize_t ret;
-
-	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
-			       bcaps, 1);
-	if (ret != 1) {
-		drm_dbg_kms(&i915->drm,
-			    "Read bcaps from DP/AUX failed (%zd)\n", ret);
-		return ret >= 0 ? -EIO : ret;
-	}
-
-	return 0;
-}
-
-static
-int intel_dp_hdcp_repeater_present(struct intel_digital_port *dig_port,
-				   bool *repeater_present)
-{
-	ssize_t ret;
-	u8 bcaps;
-
-	ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
-	if (ret)
-		return ret;
-
-	*repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
-	return 0;
-}
-
-static
-int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
-				u8 *ri_prime)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	ssize_t ret;
-
-	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
-			       ri_prime, DRM_HDCP_RI_LEN);
-	if (ret != DRM_HDCP_RI_LEN) {
-		drm_dbg_kms(&i915->drm, "Read Ri' from DP/AUX failed (%zd)\n",
-			    ret);
-		return ret >= 0 ? -EIO : ret;
-	}
-	return 0;
-}
-
-static
-int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
-				 bool *ksv_ready)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	ssize_t ret;
-	u8 bstatus;
-
-	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
-			       &bstatus, 1);
-	if (ret != 1) {
-		drm_dbg_kms(&i915->drm,
-			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
-		return ret >= 0 ? -EIO : ret;
-	}
-	*ksv_ready = bstatus & DP_BSTATUS_READY;
-	return 0;
-}
-
-static
-int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
-				int num_downstream, u8 *ksv_fifo)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	ssize_t ret;
-	int i;
-
-	/* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
-	for (i = 0; i < num_downstream; i += 3) {
-		size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
-		ret = drm_dp_dpcd_read(&dig_port->dp.aux,
-				       DP_AUX_HDCP_KSV_FIFO,
-				       ksv_fifo + i * DRM_HDCP_KSV_LEN,
-				       len);
-		if (ret != len) {
-			drm_dbg_kms(&i915->drm,
-				    "Read ksv[%d] from DP/AUX failed (%zd)\n",
-				    i, ret);
-			return ret >= 0 ? -EIO : ret;
-		}
-	}
-	return 0;
-}
-
-static
-int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
-				    int i, u32 *part)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	ssize_t ret;
-
-	if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
-		return -EINVAL;
-
-	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
-			       DP_AUX_HDCP_V_PRIME(i), part,
-			       DRM_HDCP_V_PRIME_PART_LEN);
-	if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
-		drm_dbg_kms(&i915->drm,
-			    "Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
-		return ret >= 0 ? -EIO : ret;
-	}
-	return 0;
-}
-
 static
 int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
 				    enum transcoder cpu_transcoder,
@@ -252,40 +107,6 @@ int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
 	return 0;
 }
 
-static
-bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
-			      struct intel_connector *connector)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	ssize_t ret;
-	u8 bstatus;
-
-	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
-			       &bstatus, 1);
-	if (ret != 1) {
-		drm_dbg_kms(&i915->drm,
-			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
-		return false;
-	}
-
-	return !(bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ));
-}
-
-static
-int intel_dp_hdcp_capable(struct intel_digital_port *dig_port,
-			  bool *hdcp_capable)
-{
-	ssize_t ret;
-	u8 bcaps;
-
-	ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
-	if (ret)
-		return ret;
-
-	*hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
-	return 0;
-}
-
 struct hdcp2_dp_errata_stream_type {
 	u8	msg_id;
 	u8	stream_type;
@@ -628,13 +449,19 @@ int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port,
 	return ret;
 }
 
-static
-int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
-			   bool *capable)
+static int intel_dp_hdcp2_capable(struct drm_connector *drm_connector,
+				  bool *capable)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
 	u8 rx_caps[3];
 	int ret;
 
+	ret = intel_hdcp2_capable(drm_connector, capable);
+	if (ret || !capable)
+		return ret;
+
 	*capable = false;
 	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
 			       DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
@@ -650,22 +477,11 @@ int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
 }
 
 static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
-	.write_an_aksv = intel_dp_hdcp_write_an_aksv,
-	.read_bksv = intel_dp_hdcp_read_bksv,
-	.read_bstatus = intel_dp_hdcp_read_bstatus,
-	.repeater_present = intel_dp_hdcp_repeater_present,
-	.read_ri_prime = intel_dp_hdcp_read_ri_prime,
-	.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
-	.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
-	.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
 	.toggle_signalling = intel_dp_hdcp_toggle_signalling,
-	.check_link = intel_dp_hdcp_check_link,
-	.hdcp_capable = intel_dp_hdcp_capable,
 	.write_2_2_msg = intel_dp_hdcp2_write_msg,
 	.read_2_2_msg = intel_dp_hdcp2_read_msg,
 	.config_stream_type = intel_dp_hdcp2_config_stream_type,
 	.check_2_2_link = intel_dp_hdcp2_check_link,
-	.hdcp_2_2_capable = intel_dp_hdcp2_capable,
 	.protocol = HDCP_PROTOCOL_DP,
 };
 
@@ -721,6 +537,46 @@ intel_dp_mst_hdcp_stream_encryption(struct intel_connector *connector,
 	return 0;
 }
 
+static int
+intel_dp_mst_hdcp1_post_encryption(struct drm_connector *drm_connector)
+{
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	int ret;
+
+	ret = intel_hdcp1_post_encryption(drm_connector);
+	if (ret)
+		return ret;
+
+	return intel_dp_mst_hdcp_stream_encryption(connector, true);
+}
+
+static int intel_dp_mst_hdcp1_disable(struct drm_connector *drm_connector)
+{
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
+	struct drm_i915_private *i915 = to_i915(connector->base.dev);
+	int ret;
+
+	ret = intel_dp_mst_hdcp_stream_encryption(connector, true);
+	if (ret) {
+		drm_err(&i915->drm,
+			"[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
+			connector->base.name, connector->base.base.id);
+		return ret;
+	}
+
+	/*
+	 * If there are other connectors on this port using HDCP,
+	 * don't disable it until it disabled HDCP encryption for
+	 * all connectors in MST topology.
+	*/
+	if (dig_port->num_hdcp_streams > 0)
+		return 0;
+
+	return intel_hdcp1_disable(drm_connector);
+}
+
 static int
 intel_dp_mst_hdcp2_stream_encryption(struct intel_connector *connector,
 				     bool enable)
@@ -779,45 +635,85 @@ int intel_dp_mst_hdcp2_check_link(struct intel_digital_port *dig_port,
 }
 
 static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
-	.write_an_aksv = intel_dp_hdcp_write_an_aksv,
-	.read_bksv = intel_dp_hdcp_read_bksv,
-	.read_bstatus = intel_dp_hdcp_read_bstatus,
-	.repeater_present = intel_dp_hdcp_repeater_present,
-	.read_ri_prime = intel_dp_hdcp_read_ri_prime,
-	.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
-	.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
-	.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
 	.toggle_signalling = intel_dp_hdcp_toggle_signalling,
-	.stream_encryption = intel_dp_mst_hdcp_stream_encryption,
-	.check_link = intel_dp_hdcp_check_link,
-	.hdcp_capable = intel_dp_hdcp_capable,
 	.write_2_2_msg = intel_dp_hdcp2_write_msg,
 	.read_2_2_msg = intel_dp_hdcp2_read_msg,
 	.config_stream_type = intel_dp_hdcp2_config_stream_type,
 	.stream_2_2_encryption = intel_dp_mst_hdcp2_stream_encryption,
 	.check_2_2_link = intel_dp_mst_hdcp2_check_link,
-	.hdcp_2_2_capable = intel_dp_hdcp2_capable,
 	.protocol = HDCP_PROTOCOL_DP,
 };
 
+static const struct drm_hdcp_helper_funcs intel_dp_hdcp_helper_funcs = {
+	.setup = intel_hdcp_setup,
+	.load_keys = intel_hdcp_load_keys,
+	.hdcp2_capable = intel_dp_hdcp2_capable,
+	.hdcp2_enable = intel_hdcp2_enable,
+	.hdcp2_check_link = intel_hdcp2_check_link,
+	.hdcp2_disable = intel_hdcp2_disable,
+	.hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
+	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
+	.hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
+	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
+	.hdcp1_match_ri = intel_hdcp1_match_ri,
+	.hdcp1_post_encryption = intel_hdcp1_post_encryption,
+	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
+	.hdcp1_disable = intel_hdcp1_disable,
+};
+
+static const struct drm_hdcp_helper_funcs intel_dp_mst_hdcp_helper_funcs = {
+	.setup = intel_hdcp_setup,
+	.load_keys = intel_hdcp_load_keys,
+	.hdcp2_capable = intel_dp_hdcp2_capable,
+	.hdcp2_enable = intel_hdcp2_enable,
+	.hdcp2_check_link = intel_hdcp2_check_link,
+	.hdcp2_disable = intel_hdcp2_disable,
+	.hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
+	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
+	.hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
+	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
+	.hdcp1_match_ri = intel_hdcp1_match_ri,
+	.hdcp1_post_encryption = intel_dp_mst_hdcp1_post_encryption,
+	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
+	.hdcp1_disable = intel_dp_mst_hdcp1_disable,
+};
+
 int intel_dp_hdcp_init(struct intel_digital_port *dig_port,
-		       struct intel_connector *intel_connector)
+		       struct intel_connector *connector)
 {
-	struct drm_device *dev = intel_connector->base.dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	struct intel_encoder *intel_encoder = &dig_port->base;
 	enum port port = intel_encoder->port;
 	struct intel_dp *intel_dp = &dig_port->dp;
+	struct drm_hdcp_helper_data *data;
+	const struct drm_hdcp_helper_funcs *helper_funcs;
+	const struct intel_hdcp_shim *intel_shim;
+	int ret;
 
-	if (!is_hdcp_supported(dev_priv, port))
+	if (!is_hdcp_supported(dev_priv, port) || intel_dp_is_edp(intel_dp))
 		return 0;
 
-	if (intel_connector->mst_port)
-		return intel_hdcp_init(intel_connector, dig_port,
-				       &intel_dp_mst_hdcp_shim);
-	else if (!intel_dp_is_edp(intel_dp))
-		return intel_hdcp_init(intel_connector, dig_port,
-				       &intel_dp_hdcp_shim);
+	if (connector->mst_port) {
+		helper_funcs = &intel_dp_mst_hdcp_helper_funcs;
+		intel_shim = &intel_dp_mst_hdcp_shim;
+	} else {
+		helper_funcs = &intel_dp_hdcp_helper_funcs;
+		intel_shim = &intel_dp_hdcp_shim;
+	}
+
+	data = drm_hdcp_helper_initialize_dp(
+		&connector->base, &dig_port->dp.aux, helper_funcs, true);
+	if (IS_ERR(data)) {
+		drm_dbg_kms(&dev_priv->drm, "HDCP init failed, skipping.\n");
+		return PTR_ERR(data);
+	}
+
+	ret = intel_hdcp_init(connector, dig_port, intel_shim);
+	if (ret) {
+		drm_hdcp_helper_destroy(data);
+		return ret;
+	}
 
+	connector->hdcp_helper_data = data;
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 03604a37931c..ececb7aa4b90 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -27,6 +27,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/display/drm_hdcp_helper.h>
 
 #include "i915_drv.h"
 #include "intel_atomic.h"
@@ -40,7 +41,6 @@
 #include "intel_dp_hdcp.h"
 #include "intel_dp_mst.h"
 #include "intel_dpio_phy.h"
-#include "intel_hdcp.h"
 #include "intel_hotplug.h"
 #include "skl_scaler.h"
 
@@ -371,7 +371,10 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,
 	drm_dbg_kms(&i915->drm, "active links %d\n",
 		    intel_dp->active_mst_links);
 
-	intel_hdcp_disable(intel_mst->connector);
+	if (connector->hdcp_helper_data)
+		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+					      &state->base,
+					      &dig_port->hdcp_mutex);
 
 	drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state,
 			      drm_atomic_get_mst_payload_state(mst_state, connector->port));
@@ -579,11 +582,10 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
 	intel_audio_codec_enable(encoder, pipe_config, conn_state);
 
 	/* Enable hdcp if it's desired */
-	if (conn_state->content_protection ==
-	    DRM_MODE_CONTENT_PROTECTION_DESIRED)
-		intel_hdcp_enable(to_intel_connector(conn_state->connector),
-				  pipe_config,
-				  (u8)conn_state->hdcp_content_type);
+	if (connector->hdcp_helper_data)
+		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+					      &state->base,
+					      &dig_port->hdcp_mutex);
 }
 
 static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c
index 61a862ae1f28..f09afbc9567b 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
@@ -140,67 +140,10 @@ static int intel_hdcp_prepare_streams(struct intel_connector *connector)
 	return 0;
 }
 
-static
-bool intel_hdcp_is_ksv_valid(u8 *ksv)
-{
-	int i, ones = 0;
-	/* KSV has 20 1's and 20 0's */
-	for (i = 0; i < DRM_HDCP_KSV_LEN; i++)
-		ones += hweight8(ksv[i]);
-	if (ones != 20)
-		return false;
-
-	return true;
-}
-
-static
-int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port,
-			       const struct intel_hdcp_shim *shim, u8 *bksv)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	int ret, i, tries = 2;
-
-	/* HDCP spec states that we must retry the bksv if it is invalid */
-	for (i = 0; i < tries; i++) {
-		ret = shim->read_bksv(dig_port, bksv);
-		if (ret)
-			return ret;
-		if (intel_hdcp_is_ksv_valid(bksv))
-			break;
-	}
-	if (i == tries) {
-		drm_dbg_kms(&i915->drm, "Bksv is invalid\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-/* Is HDCP1.4 capable on Platform and Sink */
-int intel_hdcp_capable(struct intel_connector *connector, bool *capable)
-{
-	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
-	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
-	u8 bksv[5];
-
-	*capable = false;
-
-	if (!shim)
-		return 0;
-
-	if (shim->hdcp_capable)
-		return shim->hdcp_capable(dig_port, capable);
-
-	if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
-		*capable = true;
-
-	return 0;
-}
-
 /* Is HDCP2.2 capable on Platform and Sink */
-int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
+int intel_hdcp2_capable(struct drm_connector *drm_connector, bool *capable)
 {
-	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
+	struct intel_connector *connector = to_intel_connector(drm_connector);
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	struct intel_hdcp *hdcp = &connector->hdcp;
 
@@ -218,16 +161,26 @@ int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
 	}
 	mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
 
-	/* Sink's capability for HDCP2.2 */
-	return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
+	return 0;
 }
 
-static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv,
-			      enum transcoder cpu_transcoder, enum port port)
+int intel_hdcp1_check_link(struct drm_connector *drm_connector)
 {
-	return intel_de_read(dev_priv,
-	                     HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
-	       HDCP_STATUS_ENC;
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+	enum port port = dig_port->base.port;
+	u32 val;
+
+	val = intel_de_read(dev_priv,
+			    HDCP_STATUS(dev_priv, cpu_transcoder, port));
+
+	if (val & HDCP_STATUS_ENC)
+		return 0;
+
+	return -EINVAL;
 }
 
 static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
@@ -238,27 +191,6 @@ static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
 	       LINK_ENCRYPTION_STATUS;
 }
 
-static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *dig_port,
-				    const struct intel_hdcp_shim *shim)
-{
-	int ret, read_ret;
-	bool ksv_ready;
-
-	/* Poll for ksv list ready (spec says max time allowed is 5s) */
-	ret = __wait_for(read_ret = shim->read_ksv_ready(dig_port,
-							 &ksv_ready),
-			 read_ret || ksv_ready, 5 * 1000 * 1000, 1000,
-			 100 * 1000);
-	if (ret)
-		return ret;
-	if (read_ret)
-		return read_ret;
-	if (!ksv_ready)
-		return -ETIMEDOUT;
-
-	return 0;
-}
-
 static bool hdcp_key_loadable(struct drm_i915_private *dev_priv)
 {
 	enum i915_power_well_id id;
@@ -294,11 +226,18 @@ static void intel_hdcp_clear_keys(struct drm_i915_private *dev_priv)
 		       HDCP_KEY_LOAD_DONE | HDCP_KEY_LOAD_STATUS | HDCP_FUSE_IN_PROGRESS | HDCP_FUSE_ERROR | HDCP_FUSE_DONE);
 }
 
-static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
+int intel_hdcp_load_keys(struct drm_connector *drm_connector)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	int ret;
 	u32 val;
 
+	if (!hdcp_key_loadable(dev_priv)) {
+		drm_err(&dev_priv->drm, "HDCP key Load is not possible\n");
+		return -ENXIO;
+	}
+
 	val = intel_de_read(dev_priv, HDCP_KEY_STATUS);
 	if ((val & HDCP_KEY_LOAD_DONE) && (val & HDCP_KEY_LOAD_STATUS))
 		return 0;
@@ -308,8 +247,11 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
 	 * out of reset. So if Key is not already loaded, its an error state.
 	 */
 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
-		if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) & HDCP_KEY_LOAD_DONE))
-			return -ENXIO;
+		if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) &
+		      HDCP_KEY_LOAD_DONE)) {
+			ret = -ENXIO;
+			goto err;
+		}
 
 	/*
 	 * Initiate loading the HDCP key from fuses.
@@ -325,7 +267,7 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
 			drm_err(&dev_priv->drm,
 				"Failed to initiate HDCP key load (%d)\n",
 				ret);
-			return ret;
+			goto err;
 		}
 	} else {
 		intel_de_write(dev_priv, HDCP_KEY_CONF, HDCP_KEY_LOAD_TRIGGER);
@@ -335,15 +277,21 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
 	ret = __intel_wait_for_register(&dev_priv->uncore, HDCP_KEY_STATUS,
 					HDCP_KEY_LOAD_DONE, HDCP_KEY_LOAD_DONE,
 					10, 1, &val);
-	if (ret)
-		return ret;
-	else if (!(val & HDCP_KEY_LOAD_STATUS))
-		return -ENXIO;
+	if (ret) {
+		goto err;
+	} else if (!(val & HDCP_KEY_LOAD_STATUS)) {
+		ret = -ENXIO;
+		goto err;
+	}
 
 	/* Send Aksv over to PCH display for use in authentication */
 	intel_de_write(dev_priv, HDCP_KEY_CONF, HDCP_AKSV_SEND_TRIGGER);
 
 	return 0;
+
+err:
+	intel_hdcp_clear_keys(dev_priv);
+	return ret;
 }
 
 /* Returns updated SHA-1 index */
@@ -399,25 +347,21 @@ u32 intel_hdcp_get_repeater_ctl(struct drm_i915_private *dev_priv,
 	}
 }
 
-static
-int intel_hdcp_validate_v_prime(struct intel_connector *connector,
-				const struct intel_hdcp_shim *shim,
-				u8 *ksv_fifo, u8 num_downstream, u8 *bstatus)
+int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
+			       u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
+			       u32 *v_prime)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
 	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
 	enum port port = dig_port->base.port;
-	u32 vprime, sha_text, sha_leftovers, rep_ctl;
+	u32 sha_text, sha_leftovers, rep_ctl;
 	int ret, i, j, sha_idx;
 
 	/* Process V' values from the receiver */
-	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
-		ret = shim->read_v_prime_part(dig_port, i, &vprime);
-		if (ret)
-			return ret;
-		intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), vprime);
-	}
+	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++)
+		intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), v_prime[i]);
 
 	/*
 	 * We need to write the concatenation of all device KSVs, BINFO (DP) ||
@@ -642,131 +586,38 @@ int intel_hdcp_validate_v_prime(struct intel_connector *connector,
 	return 0;
 }
 
-/* Implements Part 2 of the HDCP authorization procedure */
-static
-int intel_hdcp_auth_downstream(struct intel_connector *connector)
+int intel_hdcp1_store_receiver_info(struct drm_connector *drm_connector,
+				    u32 *ksv, u32 status, u8 caps,
+				    bool repeater_present)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
 	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
-	u8 bstatus[2], num_downstream, *ksv_fifo;
-	int ret, i, tries = 3;
-
-	ret = intel_hdcp_poll_ksv_fifo(dig_port, shim);
-	if (ret) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "KSV list failed to become ready (%d)\n", ret);
-		return ret;
-	}
-
-	ret = shim->read_bstatus(dig_port, bstatus);
-	if (ret)
-		return ret;
-
-	if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
-	    DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
-		drm_dbg_kms(&dev_priv->drm, "Max Topology Limit Exceeded\n");
-		return -EPERM;
-	}
-
-	/*
-	 * When repeater reports 0 device count, HDCP1.4 spec allows disabling
-	 * the HDCP encryption. That implies that repeater can't have its own
-	 * display. As there is no consumption of encrypted content in the
-	 * repeater with 0 downstream devices, we are failing the
-	 * authentication.
-	 */
-	num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
-	if (num_downstream == 0) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "Repeater with zero downstream devices\n");
-		return -EINVAL;
-	}
-
-	ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream, GFP_KERNEL);
-	if (!ksv_fifo) {
-		drm_dbg_kms(&dev_priv->drm, "Out of mem: ksv_fifo\n");
-		return -ENOMEM;
-	}
-
-	ret = shim->read_ksv_fifo(dig_port, num_downstream, ksv_fifo);
-	if (ret)
-		goto err;
-
-	if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, ksv_fifo,
-					num_downstream) > 0) {
-		drm_err(&dev_priv->drm, "Revoked Ksv(s) in ksv_fifo\n");
-		ret = -EPERM;
-		goto err;
-	}
+	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+	enum port port = dig_port->base.port;
 
-	/*
-	 * When V prime mismatches, DP Spec mandates re-read of
-	 * V prime atleast twice.
-	 */
-	for (i = 0; i < tries; i++) {
-		ret = intel_hdcp_validate_v_prime(connector, shim,
-						  ksv_fifo, num_downstream,
-						  bstatus);
-		if (!ret)
-			break;
-	}
+	intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder, port),
+		       ksv[0]);
+	intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder, port),
+		       ksv[1]);
 
-	if (i == tries) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "V Prime validation failed.(%d)\n", ret);
-		goto err;
-	}
+	if (repeater_present)
+		intel_de_write(dev_priv, HDCP_REP_CTL,
+			       intel_hdcp_get_repeater_ctl(
+				       dev_priv, cpu_transcoder, port));
 
-	drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (%d downstream devices)\n",
-		    num_downstream);
-	ret = 0;
-err:
-	kfree(ksv_fifo);
-	return ret;
+	return 0;
 }
 
-/* Implements Part 1 of the HDCP authorization procedure */
-static int intel_hdcp_auth(struct intel_connector *connector)
+int intel_hdcp1_read_an(struct drm_connector *drm_connector,
+			struct drm_hdcp_an *an)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
 	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-	struct intel_hdcp *hdcp = &connector->hdcp;
-	const struct intel_hdcp_shim *shim = hdcp->shim;
 	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
 	enum port port = dig_port->base.port;
-	unsigned long r0_prime_gen_start;
-	int ret, i, tries = 2;
-	union {
-		u32 reg[2];
-		u8 shim[DRM_HDCP_AN_LEN];
-	} an;
-	union {
-		u32 reg[2];
-		u8 shim[DRM_HDCP_KSV_LEN];
-	} bksv;
-	union {
-		u32 reg;
-		u8 shim[DRM_HDCP_RI_LEN];
-	} ri;
-	bool repeater_present, hdcp_capable;
-
-	/*
-	 * Detects whether the display is HDCP capable. Although we check for
-	 * valid Bksv below, the HDCP over DP spec requires that we check
-	 * whether the display supports HDCP before we write An. For HDMI
-	 * displays, this is not necessary.
-	 */
-	if (shim->hdcp_capable) {
-		ret = shim->hdcp_capable(dig_port, &hdcp_capable);
-		if (ret)
-			return ret;
-		if (!hdcp_capable) {
-			drm_dbg_kms(&dev_priv->drm,
-				    "Panel is not HDCP capable\n");
-			return -EINVAL;
-		}
-	}
+	int i;
 
 	/* Initialize An with 2 random values and acquire it */
 	for (i = 0; i < 2; i++)
@@ -784,92 +635,81 @@ static int intel_hdcp_auth(struct intel_connector *connector)
 		return -ETIMEDOUT;
 	}
 
-	an.reg[0] = intel_de_read(dev_priv,
-				  HDCP_ANLO(dev_priv, cpu_transcoder, port));
-	an.reg[1] = intel_de_read(dev_priv,
-				  HDCP_ANHI(dev_priv, cpu_transcoder, port));
-	ret = shim->write_an_aksv(dig_port, an.shim);
-	if (ret)
-		return ret;
+	an->words[0] = intel_de_read(dev_priv,
+				     HDCP_ANLO(dev_priv, cpu_transcoder, port));
+	an->words[1] = intel_de_read(dev_priv,
+				     HDCP_ANHI(dev_priv, cpu_transcoder, port));
 
-	r0_prime_gen_start = jiffies;
-
-	memset(&bksv, 0, sizeof(bksv));
-
-	ret = intel_hdcp_read_valid_bksv(dig_port, shim, bksv.shim);
-	if (ret < 0)
-		return ret;
-
-	if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, bksv.shim, 1) > 0) {
-		drm_err(&dev_priv->drm, "BKSV is revoked\n");
-		return -EPERM;
-	}
-
-	intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder, port),
-		       bksv.reg[0]);
-	intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder, port),
-		       bksv.reg[1]);
-
-	ret = shim->repeater_present(dig_port, &repeater_present);
-	if (ret)
-		return ret;
-	if (repeater_present)
-		intel_de_write(dev_priv, HDCP_REP_CTL,
-			       intel_hdcp_get_repeater_ctl(dev_priv, cpu_transcoder, port));
+	return 0;
+}
 
-	ret = shim->toggle_signalling(dig_port, cpu_transcoder, true);
-	if (ret)
-		return ret;
+int intel_hdcp1_enable_encryption(struct drm_connector *drm_connector)
+{
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+	enum port port = dig_port->base.port;
 
 	intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port),
 		       HDCP_CONF_AUTH_AND_ENC);
 
+	return 0;
+}
+
+int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector)
+{
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+	enum port port = dig_port->base.port;
+
 	/* Wait for R0 ready */
-	if (wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
-		     (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), 1)) {
+	if (wait_for((intel_de_read(dev_priv,
+				    HDCP_STATUS(dev_priv, cpu_transcoder,
+						port))) &
+			     (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC),
+		     1)) {
 		drm_err(&dev_priv->drm, "Timed out waiting for R0 ready\n");
 		return -ETIMEDOUT;
 	}
 
-	/*
-	 * Wait for R0' to become available. The spec says 100ms from Aksv, but
-	 * some monitors can take longer than this. We'll set the timeout at
-	 * 300ms just to be sure.
-	 *
-	 * On DP, there's an R0_READY bit available but no such bit
-	 * exists on HDMI. Since the upper-bound is the same, we'll just do
-	 * the stupid thing instead of polling on one and not the other.
-	 */
-	wait_remaining_ms_from_jiffies(r0_prime_gen_start, 300);
-
-	tries = 3;
+	return 0;
+}
 
-	/*
-	 * DP HDCP Spec mandates the two more reattempt to read R0, incase
-	 * of R0 mismatch.
-	 */
-	for (i = 0; i < tries; i++) {
-		ri.reg = 0;
-		ret = shim->read_ri_prime(dig_port, ri.shim);
-		if (ret)
-			return ret;
-		intel_de_write(dev_priv,
-			       HDCP_RPRIME(dev_priv, cpu_transcoder, port),
-			       ri.reg);
+int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32 ri_prime)
+{
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+	enum port port = dig_port->base.port;
 
-		/* Wait for Ri prime match */
-		if (!wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
-			      (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1))
-			break;
-	}
+	intel_de_write(dev_priv, HDCP_RPRIME(dev_priv, cpu_transcoder, port),
+		       ri_prime);
 
-	if (i == tries) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "Timed out waiting for Ri prime match (%x)\n",
-			    intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
-					  cpu_transcoder, port)));
+	/* Wait for Ri prime match */
+	if (wait_for(intel_de_read(dev_priv,
+				   HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
+			     (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC),
+		     1))
 		return -ETIMEDOUT;
-	}
+
+	return 0;
+}
+
+int intel_hdcp1_post_encryption(struct drm_connector *drm_connector)
+{
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+	enum port port = dig_port->base.port;
 
 	/* Wait for encryption confirmation */
 	if (intel_de_wait_for_set(dev_priv,
@@ -880,56 +720,22 @@ static int intel_hdcp_auth(struct intel_connector *connector)
 		return -ETIMEDOUT;
 	}
 
-	/* DP MST Auth Part 1 Step 2.a and Step 2.b */
-	if (shim->stream_encryption) {
-		ret = shim->stream_encryption(connector, true);
-		if (ret) {
-			drm_err(&dev_priv->drm, "[%s:%d] Failed to enable HDCP 1.4 stream enc\n",
-				connector->base.name, connector->base.base.id);
-			return ret;
-		}
-		drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s stream encrypted\n",
-			    transcoder_name(hdcp->stream_transcoder));
-	}
-
-	if (repeater_present)
-		return intel_hdcp_auth_downstream(connector);
-
-	drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (no repeater present)\n");
 	return 0;
 }
 
-static int _intel_hdcp_disable(struct intel_connector *connector)
+int intel_hdcp1_disable(struct drm_connector *drm_connector)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
 	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	struct intel_hdcp *hdcp = &connector->hdcp;
 	enum port port = dig_port->base.port;
 	enum transcoder cpu_transcoder = hdcp->cpu_transcoder;
 	u32 repeater_ctl;
-	int ret;
 
 	drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being disabled...\n",
 		    connector->base.name, connector->base.base.id);
 
-	if (hdcp->shim->stream_encryption) {
-		ret = hdcp->shim->stream_encryption(connector, false);
-		if (ret) {
-			drm_err(&dev_priv->drm, "[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
-				connector->base.name, connector->base.base.id);
-			return ret;
-		}
-		drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s stream encryption disabled\n",
-			    transcoder_name(hdcp->stream_transcoder));
-		/*
-		 * If there are other connectors on this port using HDCP,
-		 * don't disable it until it disabled HDCP encryption for
-		 * all connectors in MST topology.
-		 */
-		if (dig_port->num_hdcp_streams > 0)
-			return 0;
-	}
-
 	hdcp->hdcp_encrypted = false;
 	intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port), 0);
 	if (intel_de_wait_for_clear(dev_priv,
@@ -945,190 +751,9 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
 	intel_de_write(dev_priv, HDCP_REP_CTL,
 		       intel_de_read(dev_priv, HDCP_REP_CTL) & ~repeater_ctl);
 
-	ret = hdcp->shim->toggle_signalling(dig_port, cpu_transcoder, false);
-	if (ret) {
-		drm_err(&dev_priv->drm, "Failed to disable HDCP signalling\n");
-		return ret;
-	}
-
-	drm_dbg_kms(&dev_priv->drm, "HDCP is disabled\n");
 	return 0;
 }
 
-static int _intel_hdcp_enable(struct intel_connector *connector)
-{
-	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-	struct intel_hdcp *hdcp = &connector->hdcp;
-	int i, ret, tries = 3;
-
-	drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being enabled...\n",
-		    connector->base.name, connector->base.base.id);
-
-	if (!hdcp_key_loadable(dev_priv)) {
-		drm_err(&dev_priv->drm, "HDCP key Load is not possible\n");
-		return -ENXIO;
-	}
-
-	for (i = 0; i < KEY_LOAD_TRIES; i++) {
-		ret = intel_hdcp_load_keys(dev_priv);
-		if (!ret)
-			break;
-		intel_hdcp_clear_keys(dev_priv);
-	}
-	if (ret) {
-		drm_err(&dev_priv->drm, "Could not load HDCP keys, (%d)\n",
-			ret);
-		return ret;
-	}
-
-	/* Incase of authentication failures, HDCP spec expects reauth. */
-	for (i = 0; i < tries; i++) {
-		ret = intel_hdcp_auth(connector);
-		if (!ret) {
-			hdcp->hdcp_encrypted = true;
-			return 0;
-		}
-
-		drm_dbg_kms(&dev_priv->drm, "HDCP Auth failure (%d)\n", ret);
-
-		/* Ensuring HDCP encryption and signalling are stopped. */
-		_intel_hdcp_disable(connector);
-	}
-
-	drm_dbg_kms(&dev_priv->drm,
-		    "HDCP authentication failed (%d tries/%d)\n", tries, ret);
-	return ret;
-}
-
-static struct intel_connector *intel_hdcp_to_connector(struct intel_hdcp *hdcp)
-{
-	return container_of(hdcp, struct intel_connector, hdcp);
-}
-
-static void intel_hdcp_update_value(struct intel_connector *connector,
-				    u64 value, bool update_property)
-{
-	struct drm_device *dev = connector->base.dev;
-	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
-	struct intel_hdcp *hdcp = &connector->hdcp;
-
-	drm_WARN_ON(connector->base.dev, !mutex_is_locked(&hdcp->mutex));
-
-	if (hdcp->value == value)
-		return;
-
-	drm_WARN_ON(dev, !mutex_is_locked(&dig_port->hdcp_mutex));
-
-	if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
-		if (!drm_WARN_ON(dev, dig_port->num_hdcp_streams == 0))
-			dig_port->num_hdcp_streams--;
-	} else if (value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
-		dig_port->num_hdcp_streams++;
-	}
-
-	hdcp->value = value;
-	if (update_property) {
-		drm_connector_get(&connector->base);
-		schedule_work(&hdcp->prop_work);
-	}
-}
-
-/* Implements Part 3 of the HDCP authorization procedure */
-static int intel_hdcp_check_link(struct intel_connector *connector)
-{
-	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
-	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-	struct intel_hdcp *hdcp = &connector->hdcp;
-	enum port port = dig_port->base.port;
-	enum transcoder cpu_transcoder;
-	int ret = 0;
-
-	mutex_lock(&hdcp->mutex);
-	mutex_lock(&dig_port->hdcp_mutex);
-
-	cpu_transcoder = hdcp->cpu_transcoder;
-
-	/* Check_link valid only when HDCP1.4 is enabled */
-	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED ||
-	    !hdcp->hdcp_encrypted) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (drm_WARN_ON(&dev_priv->drm,
-			!intel_hdcp_in_use(dev_priv, cpu_transcoder, port))) {
-		drm_err(&dev_priv->drm,
-			"%s:%d HDCP link stopped encryption,%x\n",
-			connector->base.name, connector->base.base.id,
-			intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)));
-		ret = -ENXIO;
-		intel_hdcp_update_value(connector,
-					DRM_MODE_CONTENT_PROTECTION_DESIRED,
-					true);
-		goto out;
-	}
-
-	if (hdcp->shim->check_link(dig_port, connector)) {
-		if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
-			intel_hdcp_update_value(connector,
-				DRM_MODE_CONTENT_PROTECTION_ENABLED, true);
-		}
-		goto out;
-	}
-
-	drm_dbg_kms(&dev_priv->drm,
-		    "[%s:%d] HDCP link failed, retrying authentication\n",
-		    connector->base.name, connector->base.base.id);
-
-	ret = _intel_hdcp_disable(connector);
-	if (ret) {
-		drm_err(&dev_priv->drm, "Failed to disable hdcp (%d)\n", ret);
-		intel_hdcp_update_value(connector,
-					DRM_MODE_CONTENT_PROTECTION_DESIRED,
-					true);
-		goto out;
-	}
-
-	ret = _intel_hdcp_enable(connector);
-	if (ret) {
-		drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n", ret);
-		intel_hdcp_update_value(connector,
-					DRM_MODE_CONTENT_PROTECTION_DESIRED,
-					true);
-		goto out;
-	}
-
-out:
-	mutex_unlock(&dig_port->hdcp_mutex);
-	mutex_unlock(&hdcp->mutex);
-	return ret;
-}
-
-static void intel_hdcp_prop_work(struct work_struct *work)
-{
-	struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp,
-					       prop_work);
-	struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
-	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-	drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, NULL);
-	mutex_lock(&hdcp->mutex);
-
-	/*
-	 * This worker is only used to flip between ENABLED/DESIRED. Either of
-	 * those to UNDESIRED is handled by core. If value == UNDESIRED,
-	 * we're running just after hdcp has been disabled, so just exit
-	 */
-	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
-		drm_hdcp_update_content_protection(&connector->base,
-						   hdcp->value);
-
-	mutex_unlock(&hdcp->mutex);
-	drm_modeset_unlock(&dev_priv->drm.mode_config.connection_mutex);
-
-	drm_connector_put(&connector->base);
-}
-
 bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port)
 {
 	return RUNTIME_INFO(dev_priv)->has_hdcp &&
@@ -1961,8 +1586,9 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
 	return ret;
 }
 
-static int _intel_hdcp2_enable(struct intel_connector *connector)
+int intel_hdcp2_enable(struct drm_connector *drm_connector)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
 	struct drm_i915_private *i915 = to_i915(connector->base.dev);
 	struct intel_hdcp *hdcp = &connector->hdcp;
 	int ret;
@@ -2024,9 +1650,15 @@ _intel_hdcp2_disable(struct intel_connector *connector, bool hdcp2_link_recovery
 	return ret;
 }
 
+int intel_hdcp2_disable(struct drm_connector *drm_connector)
+{
+	return _intel_hdcp2_disable(to_intel_connector(drm_connector), false);
+}
+
 /* Implements the Link Integrity Check for HDCP2.2 */
-static int intel_hdcp2_check_link(struct intel_connector *connector)
+int intel_hdcp2_check_link(struct drm_connector *drm_connector)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
 	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	struct intel_hdcp *hdcp = &connector->hdcp;
@@ -2034,109 +1666,39 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
 	enum transcoder cpu_transcoder;
 	int ret = 0;
 
-	mutex_lock(&hdcp->mutex);
-	mutex_lock(&dig_port->hdcp_mutex);
 	cpu_transcoder = hdcp->cpu_transcoder;
 
 	/* hdcp2_check_link is expected only when HDCP2.2 is Enabled */
-	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED ||
-	    !hdcp->hdcp2_encrypted) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (!hdcp->hdcp2_encrypted)
+		return -EINVAL;
 
 	if (drm_WARN_ON(&dev_priv->drm,
 			!intel_hdcp2_in_use(dev_priv, cpu_transcoder, port))) {
 		drm_err(&dev_priv->drm,
 			"HDCP2.2 link stopped the encryption, %x\n",
 			intel_de_read(dev_priv, HDCP2_STATUS(dev_priv, cpu_transcoder, port)));
-		ret = -ENXIO;
-		_intel_hdcp2_disable(connector, true);
-		intel_hdcp_update_value(connector,
-					DRM_MODE_CONTENT_PROTECTION_DESIRED,
-					true);
-		goto out;
+		return -ENXIO;
 	}
 
 	ret = hdcp->shim->check_2_2_link(dig_port, connector);
-	if (ret == HDCP_LINK_PROTECTED) {
-		if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
-			intel_hdcp_update_value(connector,
-					DRM_MODE_CONTENT_PROTECTION_ENABLED,
-					true);
-		}
-		goto out;
-	}
+	if (ret == HDCP_LINK_PROTECTED)
+		return 0;
 
 	if (ret == HDCP_TOPOLOGY_CHANGE) {
-		if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
-			goto out;
-
 		drm_dbg_kms(&dev_priv->drm,
 			    "HDCP2.2 Downstream topology change\n");
 		ret = hdcp2_authenticate_repeater_topology(connector);
-		if (!ret) {
-			intel_hdcp_update_value(connector,
-					DRM_MODE_CONTENT_PROTECTION_ENABLED,
-					true);
-			goto out;
-		}
-		drm_dbg_kms(&dev_priv->drm,
-			    "[%s:%d] Repeater topology auth failed.(%d)\n",
-			    connector->base.name, connector->base.base.id,
-			    ret);
-	} else {
-		drm_dbg_kms(&dev_priv->drm,
-			    "[%s:%d] HDCP2.2 link failed, retrying auth\n",
-			    connector->base.name, connector->base.base.id);
-	}
-
-	ret = _intel_hdcp2_disable(connector, true);
-	if (ret) {
-		drm_err(&dev_priv->drm,
-			"[%s:%d] Failed to disable hdcp2.2 (%d)\n",
-			connector->base.name, connector->base.base.id, ret);
-		intel_hdcp_update_value(connector,
-				DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
-		goto out;
-	}
+		if (!ret)
+			return 0;
 
-	ret = _intel_hdcp2_enable(connector);
-	if (ret) {
 		drm_dbg_kms(&dev_priv->drm,
-			    "[%s:%d] Failed to enable hdcp2.2 (%d)\n",
-			    connector->base.name, connector->base.base.id,
-			    ret);
-		intel_hdcp_update_value(connector,
-					DRM_MODE_CONTENT_PROTECTION_DESIRED,
-					true);
-		goto out;
+			    "[%s:%d] Repeater topology auth failed.(%d)\n",
+			    connector->base.name, connector->base.base.id, ret);
 	}
 
-out:
-	mutex_unlock(&dig_port->hdcp_mutex);
-	mutex_unlock(&hdcp->mutex);
 	return ret;
 }
 
-static void intel_hdcp_check_work(struct work_struct *work)
-{
-	struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
-					       struct intel_hdcp,
-					       check_work);
-	struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
-
-	if (drm_connector_is_unregistered(&connector->base))
-		return;
-
-	if (!intel_hdcp2_check_link(connector))
-		schedule_delayed_work(&hdcp->check_work,
-				      DRM_HDCP2_CHECK_PERIOD_MS);
-	else if (!intel_hdcp_check_link(connector))
-		schedule_delayed_work(&hdcp->check_work,
-				      DRM_HDCP_CHECK_PERIOD_MS);
-}
-
 static int i915_hdcp_component_bind(struct device *i915_kdev,
 				    struct device *mei_kdev, void *data)
 {
@@ -2189,22 +1751,28 @@ static enum mei_fw_tc intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
 	}
 }
 
-static int
-_intel_hdcp_setup(struct intel_connector *connector,
-		  const struct intel_crtc_state *pipe_config, u8 content_type)
+int intel_hdcp_setup(struct drm_connector *connector,
+		     struct drm_atomic_state *state)
 {
-	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
-	struct intel_hdcp *hdcp = &connector->hdcp;
+	struct drm_i915_private *dev_priv = to_i915(connector->dev);
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(intel_connector);
+	struct drm_connector_state *conn_state;
+	struct drm_crtc_state *crtc_state;
+	struct intel_crtc_state *pipe_config;
+	struct intel_hdcp *hdcp = &intel_connector->hdcp;
 	int ret = 0;
 
-	if (!connector->encoder) {
+	if (!intel_connector->encoder) {
 		drm_err(&dev_priv->drm, "[%s:%d] encoder is not initialized\n",
-			connector->base.name, connector->base.base.id);
+			connector->name, connector->base.id);
 		return -ENODEV;
 	}
 
-	hdcp->content_type = content_type;
+	conn_state = drm_atomic_get_new_connector_state(state, connector);
+	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+	pipe_config = to_intel_crtc_state(crtc_state);
 
 	if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
 		hdcp->cpu_transcoder = pipe_config->mst_master_transcoder;
@@ -2321,7 +1889,6 @@ int intel_hdcp_init(struct intel_connector *connector,
 {
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	struct intel_hdcp *hdcp = &connector->hdcp;
-	int ret;
 
 	if (!shim)
 		return -EINVAL;
@@ -2329,174 +1896,12 @@ int intel_hdcp_init(struct intel_connector *connector,
 	if (is_hdcp2_supported(dev_priv))
 		intel_hdcp2_init(connector, dig_port, shim);
 
-	ret =
-	drm_connector_attach_content_protection_property(&connector->base,
-							 hdcp->hdcp2_supported);
-	if (ret) {
-		hdcp->hdcp2_supported = false;
-		kfree(dig_port->hdcp_port_data.streams);
-		return ret;
-	}
-
 	hdcp->shim = shim;
-	mutex_init(&hdcp->mutex);
-	INIT_DELAYED_WORK(&hdcp->check_work, intel_hdcp_check_work);
-	INIT_WORK(&hdcp->prop_work, intel_hdcp_prop_work);
 	init_waitqueue_head(&hdcp->cp_irq_queue);
 
 	return 0;
 }
 
-int intel_hdcp_enable(struct intel_connector *connector,
-		      const struct intel_crtc_state *pipe_config, u8 content_type)
-{
-	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
-	struct intel_hdcp *hdcp = &connector->hdcp;
-	unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
-	bool capable;
-	int ret = -EINVAL;
-
-	if (!hdcp->shim)
-		return -ENOENT;
-
-	mutex_lock(&hdcp->mutex);
-	mutex_lock(&dig_port->hdcp_mutex);
-	drm_WARN_ON(&dev_priv->drm,
-		    hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
-
-	ret = _intel_hdcp_setup(connector, pipe_config, content_type);
-	if (ret)
-		goto out;
-
-	/*
-	 * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
-	 * is capable of HDCP2.2, it is preferred to use HDCP2.2.
-	 */
-	ret = intel_hdcp2_capable(connector, &capable);
-	if (capable) {
-		ret = _intel_hdcp2_enable(connector);
-		if (!ret) {
-			check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
-			goto out;
-		}
-	}
-
-	/*
-	 * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
-	 * be attempted.
-	 */
-	ret = intel_hdcp_capable(connector, &capable);
-	if (ret)
-		goto out;
-
-	if (capable && hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1)
-		ret = _intel_hdcp_enable(connector);
-
-out:
-	if (!ret) {
-		schedule_delayed_work(&hdcp->check_work, check_link_interval);
-		intel_hdcp_update_value(connector,
-					DRM_MODE_CONTENT_PROTECTION_ENABLED,
-					true);
-	}
-
-	mutex_unlock(&dig_port->hdcp_mutex);
-	mutex_unlock(&hdcp->mutex);
-	return ret;
-}
-
-int intel_hdcp_disable(struct intel_connector *connector)
-{
-	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
-	struct intel_hdcp *hdcp = &connector->hdcp;
-	int ret = 0;
-
-	if (!hdcp->shim)
-		return -ENOENT;
-
-	mutex_lock(&hdcp->mutex);
-	mutex_lock(&dig_port->hdcp_mutex);
-
-	if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
-		goto out;
-
-	intel_hdcp_update_value(connector,
-				DRM_MODE_CONTENT_PROTECTION_UNDESIRED, false);
-	if (hdcp->hdcp2_encrypted)
-		ret = _intel_hdcp2_disable(connector, false);
-	else if (hdcp->hdcp_encrypted)
-		ret = _intel_hdcp_disable(connector);
-
-out:
-	mutex_unlock(&dig_port->hdcp_mutex);
-	mutex_unlock(&hdcp->mutex);
-	cancel_delayed_work_sync(&hdcp->check_work);
-	return ret;
-}
-
-void intel_hdcp_update_pipe(struct intel_atomic_state *state,
-			    struct intel_encoder *encoder,
-			    const struct intel_crtc_state *crtc_state,
-			    const struct drm_connector_state *conn_state)
-{
-	struct intel_connector *connector =
-				to_intel_connector(conn_state->connector);
-	struct intel_hdcp *hdcp = &connector->hdcp;
-	bool content_protection_type_changed, desired_and_not_enabled = false;
-
-	if (!connector->hdcp.shim)
-		return;
-
-	content_protection_type_changed =
-		(conn_state->hdcp_content_type != hdcp->content_type &&
-		 conn_state->content_protection !=
-		 DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
-
-	/*
-	 * During the HDCP encryption session if Type change is requested,
-	 * disable the HDCP and reenable it with new TYPE value.
-	 */
-	if (conn_state->content_protection ==
-	    DRM_MODE_CONTENT_PROTECTION_UNDESIRED ||
-	    content_protection_type_changed)
-		intel_hdcp_disable(connector);
-
-	/*
-	 * Mark the hdcp state as DESIRED after the hdcp disable of type
-	 * change procedure.
-	 */
-	if (content_protection_type_changed) {
-		mutex_lock(&hdcp->mutex);
-		hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
-		drm_connector_get(&connector->base);
-		schedule_work(&hdcp->prop_work);
-		mutex_unlock(&hdcp->mutex);
-	}
-
-	if (conn_state->content_protection ==
-	    DRM_MODE_CONTENT_PROTECTION_DESIRED) {
-		mutex_lock(&hdcp->mutex);
-		/* Avoid enabling hdcp, if it already ENABLED */
-		desired_and_not_enabled =
-			hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED;
-		mutex_unlock(&hdcp->mutex);
-		/*
-		 * If HDCP already ENABLED and CP property is DESIRED, schedule
-		 * prop_work to update correct CP property to user space.
-		 */
-		if (!desired_and_not_enabled && !content_protection_type_changed) {
-			drm_connector_get(&connector->base);
-			schedule_work(&hdcp->prop_work);
-		}
-	}
-
-	if (desired_and_not_enabled || content_protection_type_changed)
-		intel_hdcp_enable(connector,
-				  crtc_state,
-				  (u8)conn_state->hdcp_content_type);
-}
-
 void intel_hdcp_component_fini(struct drm_i915_private *dev_priv)
 {
 	mutex_lock(&dev_priv->display.hdcp.comp_mutex);
@@ -2518,33 +1923,8 @@ void intel_hdcp_cleanup(struct intel_connector *connector)
 	if (!hdcp->shim)
 		return;
 
-	/*
-	 * If the connector is registered, it's possible userspace could kick
-	 * off another HDCP enable, which would re-spawn the workers.
-	 */
-	drm_WARN_ON(connector->base.dev,
-		connector->base.registration_state == DRM_CONNECTOR_REGISTERED);
-
-	/*
-	 * Now that the connector is not registered, check_work won't be run,
-	 * but cancel any outstanding instances of it
-	 */
-	cancel_delayed_work_sync(&hdcp->check_work);
-
-	/*
-	 * We don't cancel prop_work in the same way as check_work since it
-	 * requires connection_mutex which could be held while calling this
-	 * function. Instead, we rely on the connector references grabbed before
-	 * scheduling prop_work to ensure the connector is alive when prop_work
-	 * is run. So if we're in the destroy path (which is where this
-	 * function should be called), we're "guaranteed" that prop_work is not
-	 * active (tl;dr This Should Never Happen).
-	 */
-	drm_WARN_ON(connector->base.dev, work_pending(&hdcp->prop_work));
-
-	mutex_lock(&hdcp->mutex);
+	drm_hdcp_helper_destroy(connector->hdcp_helper_data);
 	hdcp->shim = NULL;
-	mutex_unlock(&hdcp->mutex);
 }
 
 /* Handles the CP_IRQ raised from the DP HDCP sink */
@@ -2558,5 +1938,5 @@ void intel_hdcp_handle_cp_irq(struct intel_connector *connector)
 	atomic_inc(&connector->hdcp.cp_irq_count);
 	wake_up_all(&connector->hdcp.cp_irq_queue);
 
-	schedule_delayed_work(&hdcp->check_work, 0);
+	drm_hdcp_helper_schedule_hdcp_check(connector->hdcp_helper_data);
 }
diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h b/drivers/gpu/drm/i915/display/intel_hdcp.h
index f06f6e5a2b1a..49b9d79eb30a 100644
--- a/drivers/gpu/drm/i915/display/intel_hdcp.h
+++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
@@ -10,8 +10,10 @@
 
 #define HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS	50
 
+struct drm_atomic_state;
 struct drm_connector;
 struct drm_connector_state;
+struct drm_hdcp_an;
 struct drm_i915_private;
 struct intel_atomic_state;
 struct intel_connector;
@@ -25,16 +27,29 @@ enum transcoder;
 int intel_hdcp_init(struct intel_connector *connector,
 		    struct intel_digital_port *dig_port,
 		    const struct intel_hdcp_shim *hdcp_shim);
-int intel_hdcp_enable(struct intel_connector *connector,
-		      const struct intel_crtc_state *pipe_config, u8 content_type);
-int intel_hdcp_disable(struct intel_connector *connector);
-void intel_hdcp_update_pipe(struct intel_atomic_state *state,
-			    struct intel_encoder *encoder,
-			    const struct intel_crtc_state *crtc_state,
-			    const struct drm_connector_state *conn_state);
+int intel_hdcp_setup(struct drm_connector *drm_connector,
+		     struct drm_atomic_state *state);
+int intel_hdcp_load_keys(struct drm_connector *drm_connector);
 bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
 int intel_hdcp_capable(struct intel_connector *connector, bool *capable);
-int intel_hdcp2_capable(struct intel_connector *connector, bool *capable);
+int intel_hdcp2_capable(struct drm_connector *drm_connector, bool *capable);
+int intel_hdcp2_enable(struct drm_connector *drm_connector);
+int intel_hdcp2_disable(struct drm_connector *drm_connector);
+int intel_hdcp2_check_link(struct drm_connector *drm_connector);
+int intel_hdcp1_store_receiver_info(struct drm_connector *drm_connector,
+				    u32 *ksv, u32 status, u8 caps,
+				    bool repeater_present);
+int intel_hdcp1_read_an(struct drm_connector *drm_connector,
+			struct drm_hdcp_an *an);
+int intel_hdcp1_enable_encryption(struct drm_connector *drm_connector);
+int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector);
+int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32 ri_prime);
+int intel_hdcp1_post_encryption(struct drm_connector *drm_connector);
+int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
+			       u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
+			       u32 *v_prime);
+int intel_hdcp1_check_link(struct drm_connector *drm_connector);
+int intel_hdcp1_disable(struct drm_connector *drm_connector);
 void intel_hdcp_component_init(struct drm_i915_private *dev_priv);
 void intel_hdcp_component_fini(struct drm_i915_private *dev_priv);
 void intel_hdcp_cleanup(struct intel_connector *connector);
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 7816b2a33fee..c33cfedb2e19 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -1324,17 +1324,24 @@ static int intel_hdmi_hdcp_write(struct intel_digital_port *dig_port,
 	return ret;
 }
 
-static
-int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
-				  u8 *an)
+static int intel_hdmi_hdcp1_send_an_aksv(struct drm_connector *drm_connector)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
 	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
 	struct intel_hdmi *hdmi = &dig_port->hdmi;
 	struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915,
 							      hdmi->ddc_bus);
+	struct drm_hdcp_an an;
 	int ret;
 
-	ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an,
+	/* Output An first, that's easy */
+	ret = intel_hdcp1_read_an(drm_connector, &an);
+	if (ret)
+		return ret;
+
+	ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an.bytes,
 				    DRM_HDCP_AN_LEN);
 	if (ret) {
 		drm_dbg_kms(&i915->drm, "Write An over DDC failed (%d)\n",
@@ -1350,120 +1357,6 @@ int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
 	return 0;
 }
 
-static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *dig_port,
-				     u8 *bksv)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-
-	int ret;
-	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BKSV, bksv,
-				   DRM_HDCP_KSV_LEN);
-	if (ret)
-		drm_dbg_kms(&i915->drm, "Read Bksv over DDC failed (%d)\n",
-			    ret);
-	return ret;
-}
-
-static
-int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *dig_port,
-				 u8 *bstatus)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-
-	int ret;
-	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BSTATUS,
-				   bstatus, DRM_HDCP_BSTATUS_LEN);
-	if (ret)
-		drm_dbg_kms(&i915->drm, "Read bstatus over DDC failed (%d)\n",
-			    ret);
-	return ret;
-}
-
-static
-int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *dig_port,
-				     bool *repeater_present)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	int ret;
-	u8 val;
-
-	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
-	if (ret) {
-		drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed (%d)\n",
-			    ret);
-		return ret;
-	}
-	*repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
-	return 0;
-}
-
-static
-int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
-				  u8 *ri_prime)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-
-	int ret;
-	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_RI_PRIME,
-				   ri_prime, DRM_HDCP_RI_LEN);
-	if (ret)
-		drm_dbg_kms(&i915->drm, "Read Ri' over DDC failed (%d)\n",
-			    ret);
-	return ret;
-}
-
-static
-int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
-				   bool *ksv_ready)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	int ret;
-	u8 val;
-
-	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
-	if (ret) {
-		drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed (%d)\n",
-			    ret);
-		return ret;
-	}
-	*ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
-	return 0;
-}
-
-static
-int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
-				  int num_downstream, u8 *ksv_fifo)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	int ret;
-	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_KSV_FIFO,
-				   ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN);
-	if (ret) {
-		drm_dbg_kms(&i915->drm,
-			    "Read ksv fifo over DDC failed (%d)\n", ret);
-		return ret;
-	}
-	return 0;
-}
-
-static
-int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
-				      int i, u32 *part)
-{
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	int ret;
-
-	if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
-		return -EINVAL;
-
-	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_V_PRIME(i),
-				   part, DRM_HDCP_V_PRIME_PART_LEN);
-	if (ret)
-		drm_dbg_kms(&i915->drm, "Read V'[%d] over DDC failed (%d)\n",
-			    i, ret);
-	return ret;
-}
-
 static int kbl_repositioning_enc_en_signal(struct intel_connector *connector,
 					   enum transcoder cpu_transcoder)
 {
@@ -1532,50 +1425,40 @@ int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
 	return 0;
 }
 
-static
-bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port,
-				     struct intel_connector *connector)
+static int
+intel_hdmi_hdcp1_enable_encryption(struct drm_connector *drm_connector)
 {
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	enum port port = dig_port->base.port;
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
 	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
 	int ret;
-	union {
-		u32 reg;
-		u8 shim[DRM_HDCP_RI_LEN];
-	} ri;
 
-	ret = intel_hdmi_hdcp_read_ri_prime(dig_port, ri.shim);
+	ret = intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder, true);
 	if (ret)
-		return false;
-
-	intel_de_write(i915, HDCP_RPRIME(i915, cpu_transcoder, port), ri.reg);
+		return ret;
 
-	/* Wait for Ri prime match */
-	if (wait_for((intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder, port)) &
-		      (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC)) ==
-		     (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
-		drm_dbg_kms(&i915->drm, "Ri' mismatch detected (%x)\n",
-			intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder,
-							port)));
-		return false;
-	}
-	return true;
+	return intel_hdcp1_enable_encryption(drm_connector);
 }
 
-static
-bool intel_hdmi_hdcp_check_link(struct intel_digital_port *dig_port,
-				struct intel_connector *connector)
+static int intel_hdmi_hdcp1_disable(struct drm_connector *drm_connector)
 {
-	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-	int retry;
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
+	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+	struct drm_i915_private *i915 = to_i915(connector->base.dev);
+	int ret;
 
-	for (retry = 0; retry < 3; retry++)
-		if (intel_hdmi_hdcp_check_link_once(dig_port, connector))
-			return true;
+	ret = intel_hdcp1_disable(drm_connector);
+	if (ret) {
+		drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 1.4\n",
+			connector->base.name, connector->base.base.id);
+		return ret;
+	}
 
-	drm_err(&i915->drm, "Link check failed\n");
-	return false;
+	return intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder,
+						 false);
 }
 
 struct hdcp2_hdmi_msg_timeout {
@@ -1718,9 +1601,8 @@ int intel_hdmi_hdcp2_read_msg(struct intel_digital_port *dig_port,
 	return ret;
 }
 
-static
-int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
-				struct intel_connector *connector)
+static int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
+				       struct intel_connector *connector)
 {
 	u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
 	int ret;
@@ -1741,13 +1623,19 @@ int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
 	return ret;
 }
 
-static
-int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
-			     bool *capable)
+static int intel_hdmi_hdcp2_capable(struct drm_connector *drm_connector,
+				    bool *capable)
 {
+	struct intel_connector *connector = to_intel_connector(drm_connector);
+	struct intel_digital_port *dig_port =
+		intel_attached_dig_port(connector);
 	u8 hdcp2_version;
 	int ret;
 
+	ret = intel_hdcp2_capable(drm_connector, capable);
+	if (ret || !capable)
+		return ret;
+
 	*capable = false;
 	ret = intel_hdmi_hdcp_read(dig_port, HDCP_2_2_HDMI_REG_VER_OFFSET,
 				   &hdcp2_version, sizeof(hdcp2_version));
@@ -1758,23 +1646,30 @@ int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
 }
 
 static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
-	.write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
-	.read_bksv = intel_hdmi_hdcp_read_bksv,
-	.read_bstatus = intel_hdmi_hdcp_read_bstatus,
-	.repeater_present = intel_hdmi_hdcp_repeater_present,
-	.read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
-	.read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
-	.read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
-	.read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
 	.toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
-	.check_link = intel_hdmi_hdcp_check_link,
 	.write_2_2_msg = intel_hdmi_hdcp2_write_msg,
 	.read_2_2_msg = intel_hdmi_hdcp2_read_msg,
-	.check_2_2_link	= intel_hdmi_hdcp2_check_link,
-	.hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
+	.check_2_2_link = intel_hdmi_hdcp2_check_link,
 	.protocol = HDCP_PROTOCOL_HDMI,
 };
 
+static const struct drm_hdcp_helper_funcs intel_hdmi_hdcp_helper_funcs = {
+	.setup = intel_hdcp_setup,
+	.load_keys = intel_hdcp_load_keys,
+	.hdcp2_capable = intel_hdmi_hdcp2_capable,
+	.hdcp2_enable = intel_hdcp2_enable,
+	.hdcp2_check_link = intel_hdcp2_check_link,
+	.hdcp2_disable = intel_hdcp2_disable,
+	.hdcp1_send_an_aksv = intel_hdmi_hdcp1_send_an_aksv,
+	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
+	.hdcp1_enable_encryption = intel_hdmi_hdcp1_enable_encryption,
+	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
+	.hdcp1_match_ri = intel_hdcp1_match_ri,
+	.hdcp1_post_encryption = intel_hdcp1_post_encryption,
+	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
+	.hdcp1_disable = intel_hdmi_hdcp1_disable,
+};
+
 static int intel_hdmi_source_max_tmds_clock(struct intel_encoder *encoder)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -2922,6 +2817,37 @@ void intel_infoframe_init(struct intel_digital_port *dig_port)
 	}
 }
 
+static void intel_hdmi_hdcp_init(struct intel_digital_port *dig_port,
+				 struct intel_connector *connector)
+{
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	struct intel_encoder *intel_encoder = &dig_port->base;
+	enum port port = intel_encoder->port;
+	struct drm_hdcp_helper_data *data;
+	int ret;
+
+	if (!is_hdcp_supported(dev_priv, port))
+		return;
+
+	data = drm_hdcp_helper_initialize_hdmi(
+		&connector->base, &intel_hdmi_hdcp_helper_funcs, true);
+	if (IS_ERR(data)) {
+		drm_dbg_kms(&dev_priv->drm, "HDCP init failed ret=%ld\n",
+			    PTR_ERR(data));
+		return;
+	}
+
+	ret = intel_hdcp_init(connector, dig_port, &intel_hdmi_hdcp_shim);
+	if (ret) {
+		drm_hdcp_helper_destroy(data);
+		drm_dbg_kms(&dev_priv->drm, "Intel HDCP init failed ret=%d\n",
+			    ret);
+		return;
+	}
+
+	connector->hdcp_helper_data = data;
+}
+
 void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
 			       struct intel_connector *intel_connector)
 {
@@ -2975,13 +2901,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
 	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	intel_hdmi->attached_connector = intel_connector;
 
-	if (is_hdcp_supported(dev_priv, port)) {
-		int ret = intel_hdcp_init(intel_connector, dig_port,
-					  &intel_hdmi_hdcp_shim);
-		if (ret)
-			drm_dbg_kms(&dev_priv->drm,
-				    "HDCP init failed, skipping.\n");
-	}
+	intel_hdmi_hdcp_init(dig_port, intel_connector);
 
 	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
 	 * 0xd.  Failure to do so will result in spurious interrupts being
-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v6 08/10] dt-bindings: msm/dp: Add bindings for HDCP registers
  2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
                   ` (6 preceding siblings ...)
  2023-01-18 19:30 ` [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915 Mark Yacoub
@ 2023-01-18 19:30 ` Mark Yacoub
  2023-01-19  1:16   ` Rob Herring
                     ` (2 more replies)
  2023-01-18 19:30 ` [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller Mark Yacoub
  2023-01-18 19:30 ` [PATCH v6 10/10] drm/msm: Implement HDCP 1.x using the new drm HDCP helpers Mark Yacoub
  9 siblings, 3 replies; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul, Rob Herring, Mark Yacoub

From: Sean Paul <seanpaul@chromium.org>

This patch adds the bindings for the MSM DisplayPort HDCP registers
which are required to write the HDCP key into the display controller as
well as the registers to enable HDCP authentication/key
exchange/encryption.

We'll use a new compatible string for this since the fields are optional.

Cc: Rob Herring <robh@kernel.org>
Cc: Stephen Boyd <swboyd@chromium.org>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Mark Yacoub <markyacoub@chromiu.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-13-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-13-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-13-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-13-sean@poorly.run #v4
Link: https://patchwork.freedesktop.org/patch/msgid/20211115202153.117244-1-sean@poorly.run #v4.5
Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-9-sean@poorly.run #v5

Changes in v2:
-Drop register range names (Stephen)
-Fix yaml errors (Rob)
Changes in v3:
-Add new compatible string for dp-hdcp
-Add descriptions to reg
-Add minItems/maxItems to reg
-Make reg depend on the new hdcp compatible string
Changes in v4:
-Rebase on Bjorn's multi-dp patchset
Changes in v4.5:
-Remove maxItems from reg (Rob)
-Remove leading zeros in example (Rob)
Changes in v5:
-None
Changes in v6:
-Rebased: modify minItems instead of adding it as new line.

---
 .../devicetree/bindings/display/msm/dp-controller.yaml    | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
index f2515af8256f..17d741f9af86 100644
--- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
+++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
@@ -24,13 +24,15 @@ properties:
       - qcom,sm8350-dp
 
   reg:
-    minItems: 4
+    minItems: 5
     items:
       - description: ahb register block
       - description: aux register block
       - description: link register block
       - description: p0 register block
       - description: p1 register block
+      - description: (Optional) Registers for HDCP device key injection
+      - description: (Optional) Registers for HDCP TrustZone interaction
 
   interrupts:
     maxItems: 1
@@ -154,7 +156,9 @@ examples:
               <0xae90200 0x200>,
               <0xae90400 0xc00>,
               <0xae91000 0x400>,
-              <0xae91400 0x400>;
+              <0xae91400 0x400>,
+              <0xaed1000 0x174>,
+              <0xaee1000 0x2c>;
         interrupt-parent = <&mdss>;
         interrupts = <12>;
         clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller
  2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
                   ` (7 preceding siblings ...)
  2023-01-18 19:30 ` [PATCH v6 08/10] dt-bindings: msm/dp: Add bindings for HDCP registers Mark Yacoub
@ 2023-01-18 19:30 ` Mark Yacoub
  2023-01-19  1:32   ` Abhinav Kumar
                     ` (2 more replies)
  2023-01-18 19:30 ` [PATCH v6 10/10] drm/msm: Implement HDCP 1.x using the new drm HDCP helpers Mark Yacoub
  9 siblings, 3 replies; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul

From: Sean Paul <seanpaul@chromium.org>

This patch adds the register ranges required for HDCP key injection and
HDCP TrustZone interaction as described in the dt-bindings for the
sc7180 dp controller. Now that these are supported, change the
compatible string to "dp-hdcp".

Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-15-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-14-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-14-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-14-sean@poorly.run #v4
Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-10-sean@poorly.run #v5

Changes in v3:
-Split off into a new patch containing just the dts change (Stephen)
-Add hdcp compatible string (Stephen)
Changes in v4:
-Rebase on Bjorn's multi-dp patchset
Changes in v5:
-Put the tz register offsets in trogdor dtsi (Rob C)
Changes in v6:
-Rebased: Removed modifications in sc7180.dtsi as it's already upstream

---
 arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
index 178efaaa89ec..6f6fe5cb6563 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
@@ -817,6 +817,14 @@ &mdss_dp {
 	pinctrl-names = "default";
 	pinctrl-0 = <&dp_hot_plug_det>;
 	data-lanes = <0 1>;
+
+	reg = <0 0x0ae90000 0 0x200>,
+	      <0 0x0ae90200 0 0x200>,
+	      <0 0x0ae90400 0 0xc00>,
+	      <0 0x0ae91000 0 0x400>,
+	      <0 0x0ae91400 0 0x400>,
+	      <0 0x0aed1000 0 0x175>,
+	      <0 0x0aee1000 0 0x2c>;
 };
 
 &pm6150_adc {
-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v6 10/10] drm/msm: Implement HDCP 1.x using the new drm HDCP helpers
  2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
                   ` (8 preceding siblings ...)
  2023-01-18 19:30 ` [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller Mark Yacoub
@ 2023-01-18 19:30 ` Mark Yacoub
  2023-01-19 11:35   ` Dmitry Baryshkov
  9 siblings, 1 reply; 38+ messages in thread
From: Mark Yacoub @ 2023-01-18 19:30 UTC (permalink / raw)
  To: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, markyacoub, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul

From: Sean Paul <seanpaul@chromium.org>

This patch adds HDCP 1.x support to msm DP connectors using the new HDCP
helpers.

Cc: Stephen Boyd <swboyd@chromium.org>
Cc: Abhinav Kumar <abhinavk@codeaurora.org>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-15-sean@poorly.run #v1
Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-14-sean@poorly.run #v2
Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-15-sean@poorly.run #v3
Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-15-sean@poorly.run #v4
Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-11-sean@poorly.run #v5

Changes in v2:
-Squash [1] into this patch with the following changes (Stephen)
  -Update the sc7180 dtsi file
  -Remove resource names and just use index (Stephen)
Changes in v3:
-Split out the dtsi change from v2 (Stephen)
-Fix set-but-unused warning identified by 0-day
-Fix up a couple of style nits (Stephen)
-Store HDCP key directly in dp_hdcp struct (Stephen)
-Remove wmb in HDCP key initialization, move an_seed (Stephen)
-Use FIELD_PREP for bstatus/bcaps (Stephen)
-#define read_poll_timeout values (Stephen)
-Remove unnecessary parentheses in dp_hdcp_store_ksv_fifo (Stephen)
-Add compatible string for hdcp (Stephen)
-Rename dp_hdcp_write_* functions (Abhinav)
-Add 1us delay between An reads (Abhinav)
-Delete unused dp_hdcp_read_* functions
Changes in v4:
-Rebase on Bjorn's multi-dp patchset
Changes in v5:
-Change return check of drm_hdcp_helper_initialize_dp() (Stephen)
Changes in v6:
-Change the tracking of the state from connector state to bridge as
state as drm_connector_state is no longer tracked and the functionality
has moved to msm_dp_bridge

[1] https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-14-sean@poorly.run

---
 drivers/gpu/drm/msm/Kconfig         |   1 +
 drivers/gpu/drm/msm/Makefile        |   1 +
 drivers/gpu/drm/msm/dp/dp_debug.c   |  48 ++-
 drivers/gpu/drm/msm/dp/dp_debug.h   |   6 +-
 drivers/gpu/drm/msm/dp/dp_display.c |  52 +++-
 drivers/gpu/drm/msm/dp/dp_display.h |   5 +
 drivers/gpu/drm/msm/dp/dp_drm.c     | 108 ++++++-
 drivers/gpu/drm/msm/dp/dp_drm.h     |  16 +-
 drivers/gpu/drm/msm/dp/dp_hdcp.c    | 456 ++++++++++++++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_hdcp.h    |  29 ++
 drivers/gpu/drm/msm/dp/dp_parser.c  |  20 +-
 drivers/gpu/drm/msm/dp/dp_parser.h  |   4 +
 drivers/gpu/drm/msm/dp/dp_reg.h     |  32 +-
 drivers/gpu/drm/msm/msm_atomic.c    |  15 +
 14 files changed, 772 insertions(+), 21 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.h

diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 61ca0c0757bc..9d9a66d9156c 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -15,6 +15,7 @@ config DRM_MSM
 	select REGULATOR
 	select DRM_DP_AUX_BUS
 	select DRM_DISPLAY_DP_HELPER
+	select DRM_DISPLAY_HDCP_HELPER
 	select DRM_DISPLAY_HELPER
 	select DRM_KMS_HELPER
 	select DRM_PANEL
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 7274c41228ed..a73e7b858af2 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -122,6 +122,7 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
 	dp/dp_ctrl.o \
 	dp/dp_display.o \
 	dp/dp_drm.o \
+	dp/dp_hdcp.o \
 	dp/dp_hpd.o \
 	dp/dp_link.o \
 	dp/dp_panel.o \
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index 5e35033ba3e4..e97d27edbb13 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -8,6 +8,7 @@
 #include <linux/debugfs.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_file.h>
+#include <drm/display/drm_hdcp_helper.h>
 
 #include "dp_parser.h"
 #include "dp_catalog.h"
@@ -15,6 +16,7 @@
 #include "dp_ctrl.h"
 #include "dp_debug.h"
 #include "dp_display.h"
+#include "dp_hdcp.h"
 
 #define DEBUG_NAME "msm_dp"
 
@@ -25,6 +27,7 @@ struct dp_debug_private {
 	struct dp_link *link;
 	struct dp_panel *panel;
 	struct drm_connector *connector;
+	struct dp_hdcp *hdcp;
 	struct device *dev;
 	struct drm_device *drm_dev;
 
@@ -196,6 +199,35 @@ static int dp_test_active_open(struct inode *inode,
 			inode->i_private);
 }
 
+static ssize_t dp_hdcp_key_write(struct file *file, const char __user *ubuf,
+				 size_t len, loff_t *offp)
+{
+	char *input_buffer;
+	int ret;
+	struct dp_debug_private *debug = file->private_data;
+
+	if (len != (DRM_HDCP_KSV_LEN + DP_HDCP_NUM_KEYS * DP_HDCP_KEY_LEN))
+		return -EINVAL;
+
+	if (!debug->hdcp)
+		return -ENOENT;
+
+	input_buffer = memdup_user_nul(ubuf, len);
+	if (IS_ERR(input_buffer))
+		return PTR_ERR(input_buffer);
+
+	ret = dp_hdcp_ingest_key(debug->hdcp, input_buffer, len);
+
+	kfree(input_buffer);
+	if (ret < 0) {
+		DRM_ERROR("Could not ingest HDCP key, ret=%d\n", ret);
+		return ret;
+	}
+
+	*offp += len;
+	return len;
+}
+
 static const struct file_operations test_active_fops = {
 	.owner = THIS_MODULE,
 	.open = dp_test_active_open,
@@ -205,6 +237,12 @@ static const struct file_operations test_active_fops = {
 	.write = dp_test_active_write
 };
 
+static const struct file_operations dp_hdcp_key_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.write = dp_hdcp_key_write,
+};
+
 static void dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor)
 {
 	char path[64];
@@ -229,11 +267,16 @@ static void dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor)
 	debugfs_create_file("msm_dp_test_type", 0444,
 			debug->root,
 			debug, &dp_test_type_fops);
+
+	debugfs_create_file("msm_dp_hdcp_key", 0222, minor->debugfs_root, debug,
+			    &dp_hdcp_key_fops);
 }
 
 struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
-		struct dp_usbpd *usbpd, struct dp_link *link,
-		struct drm_connector *connector, struct drm_minor *minor)
+			      struct dp_usbpd *usbpd, struct dp_link *link,
+			      struct dp_hdcp *hdcp,
+			      struct drm_connector *connector,
+			      struct drm_minor *minor)
 {
 	struct dp_debug_private *debug;
 	struct dp_debug *dp_debug;
@@ -255,6 +298,7 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 	debug->usbpd = usbpd;
 	debug->link = link;
 	debug->panel = panel;
+	debug->hdcp = hdcp;
 	debug->dev = dev;
 	debug->drm_dev = minor->dev;
 	debug->connector = connector;
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h
index 8c0d0b5178fd..55ab008876e7 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.h
+++ b/drivers/gpu/drm/msm/dp/dp_debug.h
@@ -6,6 +6,7 @@
 #ifndef _DP_DEBUG_H_
 #define _DP_DEBUG_H_
 
+#include "dp_hdcp.h"
 #include "dp_panel.h"
 #include "dp_link.h"
 
@@ -43,7 +44,7 @@ struct dp_debug {
  */
 struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 		struct dp_usbpd *usbpd, struct dp_link *link,
-		struct drm_connector *connector,
+		struct dp_hdcp *hdcp, struct drm_connector *connector,
 		struct drm_minor *minor);
 
 /**
@@ -60,7 +61,8 @@ void dp_debug_put(struct dp_debug *dp_debug);
 static inline
 struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 		struct dp_usbpd *usbpd, struct dp_link *link,
-		struct drm_connector *connector, struct drm_minor *minor)
+		struct dp_hdcp *hdcp, struct drm_connector *connector,
+		struct drm_minor *minor)
 {
 	return ERR_PTR(-EINVAL);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index a49f6dbbe888..33e82d97b714 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -27,6 +27,7 @@
 #include "dp_drm.h"
 #include "dp_audio.h"
 #include "dp_debug.h"
+#include "dp_hdcp.h"
 
 #define HPD_STRING_SIZE 30
 
@@ -97,6 +98,7 @@ struct dp_display_private {
 	struct dp_panel   *panel;
 	struct dp_ctrl    *ctrl;
 	struct dp_debug   *debug;
+	struct dp_hdcp    *hdcp;
 
 	struct dp_usbpd_cb usbpd_cb;
 	struct dp_display_mode dp_mode;
@@ -187,6 +189,20 @@ static struct dp_display_private *dev_get_dp_display_private(struct device *dev)
 	return container_of(dp, struct dp_display_private, dp_display);
 }
 
+struct dp_hdcp *dp_display_connector_to_hdcp(struct drm_connector *connector)
+{
+	struct dp_display_private *dp;
+
+	struct msm_dp *dp_display =
+		msm_bridge_from_connector(connector)->dp_display;
+	if (!dp_display)
+		return NULL;
+
+	dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+	return dp->hdcp;
+}
+
 static int dp_add_event(struct dp_display_private *dp_priv, u32 event,
 						u32 data, u32 delay)
 {
@@ -740,6 +756,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
 static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
 {
 	dp_debug_put(dp->debug);
+	dp_hdcp_put(dp->hdcp);
 	dp_audio_put(dp->audio);
 	dp_panel_put(dp->panel);
 	dp_aux_put(dp->aux);
@@ -840,8 +857,18 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
 	dp->ctrl->wide_bus_en = dp->wide_bus_en;
 	dp->catalog->wide_bus_en = dp->wide_bus_en;
 
+	dp->hdcp = dp_hdcp_get(dp->parser, dp->aux);
+	if (IS_ERR(dp->hdcp)) {
+		rc = PTR_ERR(dp->hdcp);
+		DRM_ERROR("failed to initialize hdcp, rc = %d\n", rc);
+		dp->hdcp = NULL;
+		goto error_hdcp;
+	}
+
 	return rc;
 
+error_hdcp:
+	dp_audio_put(dp->audio);
 error_ctrl:
 	dp_panel_put(dp->panel);
 error_link:
@@ -953,6 +980,16 @@ int dp_display_set_plugged_cb(struct msm_dp *dp_display,
 	return 0;
 }
 
+void dp_display_hdcp_commit(struct msm_dp *dp, struct drm_atomic_state *state)
+{
+	struct dp_display_private *dp_display;
+
+	dp_display = container_of(dp, struct dp_display_private, dp_display);
+
+	if (dp_display->hdcp)
+		dp_hdcp_commit(dp_display->hdcp, state);
+}
+
 /**
  * dp_bridge_mode_valid - callback to determine if specified mode is valid
  * @bridge: Pointer to drm bridge structure
@@ -1518,9 +1555,8 @@ void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor)
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 	dev = &dp->pdev->dev;
 
-	dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
-					dp->link, dp->dp_display.connector,
-					minor);
+	dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd, dp->link, dp->hdcp,
+				 dp->dp_display.connector, minor);
 	if (IS_ERR(dp->debug)) {
 		rc = PTR_ERR(dp->debug);
 		DRM_ERROR("failed to initialize debug, rc = %d\n", rc);
@@ -1600,6 +1636,7 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
 int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
 			struct drm_encoder *encoder)
 {
+	struct dp_display_private *dp_display_priv;
 	struct msm_drm_private *priv;
 	struct dp_display_private *dp_priv;
 	int ret;
@@ -1607,6 +1644,9 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
 	if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev))
 		return -EINVAL;
 
+	dp_display_priv =
+		container_of(dp_display, struct dp_display_private, dp_display);
+
 	priv = dev->dev_private;
 
 	if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) {
@@ -1650,6 +1690,12 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
 
 	dp_priv->panel->connector = dp_display->connector;
 
+	ret = dp_hdcp_attach(dp_display_priv->hdcp, dp_display->connector);
+	if (ret) {
+		DRM_ERROR("Failed to attach hdcp, ret=%d\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index dcedf021f7fe..5d0bb1cacced 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -30,8 +30,13 @@ struct msm_dp {
 	struct dp_audio *dp_audio;
 };
 
+struct drm_atomic_state;
+
 int dp_display_set_plugged_cb(struct msm_dp *dp_display,
 		hdmi_codec_plugged_cb fn, struct device *codec_dev);
+struct dp_hdcp *dp_display_connector_to_hdcp(struct drm_connector *connector);
+void dp_display_hdcp_commit(struct msm_dp *dp_display,
+			    struct drm_atomic_state *state);
 int dp_display_get_modes(struct msm_dp *dp_display);
 int dp_display_request_irq(struct msm_dp *dp_display);
 bool dp_display_check_video_test(struct msm_dp *dp_display);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 6db82f9b03af..6cb98d4ad2d7 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -3,15 +3,20 @@
  * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  */
 
+#include "drm/drm_connector.h"
+#include "linux/slab.h"
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_bridge_connector.h>
+#include <drm/drm_bridge_connector.h>
 #include <drm/drm_crtc.h>
+#include <drm/display/drm_hdcp_helper.h>
 
 #include "msm_drv.h"
 #include "msm_kms.h"
 #include "dp_drm.h"
+#include "dp_hdcp.h"
 
 /**
  * dp_bridge_detect - callback to determine if connector is connected
@@ -37,6 +42,7 @@ static int dp_bridge_atomic_check(struct drm_bridge *bridge,
 			    struct drm_connector_state *conn_state)
 {
 	struct msm_dp *dp;
+	struct dp_bridge_state *dp_bridge_state;
 
 	dp = to_dp_bridge(bridge)->dp_display;
 
@@ -54,8 +60,15 @@ static int dp_bridge_atomic_check(struct drm_bridge *bridge,
 	 * disabled by the hardware and thus all access to it should be forbidden.
 	 * After that this piece of code can be removed.
 	 */
-	if (bridge->ops & DRM_BRIDGE_OP_HPD)
-		return (dp->is_connected) ? 0 : -ENOTCONN;
+	if (bridge->ops & DRM_BRIDGE_OP_HPD && !dp->is_connected)
+		return -ENOTCONN;
+
+	dp_bridge_state = to_dp_bridge_state(bridge_state);
+	if (!dp_bridge_state)
+		return 0;
+
+	dp_bridge_state->hdcp_transition =
+		drm_hdcp_atomic_check(conn_state->connector, conn_state->state);
 
 	return 0;
 }
@@ -90,20 +103,93 @@ static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *
 	return rc;
 }
 
+static struct drm_bridge_state *
+dp_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge)
+{
+	struct dp_bridge_state *dp_bridge_state;
+
+	if (WARN_ON(!bridge->base.state))
+		return NULL;
+
+	dp_bridge_state = kzalloc(sizeof(*dp_bridge_state), GFP_KERNEL);
+	if (!dp_bridge_state)
+		return NULL;
+
+	dp_bridge_state->hdcp_transition = false;
+	to_dp_bridge(bridge)->state = dp_bridge_state;
+
+	__drm_atomic_helper_bridge_duplicate_state(bridge,
+						   &dp_bridge_state->base);
+	return &dp_bridge_state->base;
+}
+
 static const struct drm_bridge_funcs dp_bridge_ops = {
-	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
-	.atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
-	.atomic_reset           = drm_atomic_helper_bridge_reset,
-	.enable       = dp_bridge_enable,
-	.disable      = dp_bridge_disable,
+	.atomic_duplicate_state = dp_atomic_helper_bridge_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+	.atomic_reset = drm_atomic_helper_bridge_reset,
+	.enable = dp_bridge_enable,
+	.disable = dp_bridge_disable,
 	.post_disable = dp_bridge_post_disable,
-	.mode_set     = dp_bridge_mode_set,
-	.mode_valid   = dp_bridge_mode_valid,
-	.get_modes    = dp_bridge_get_modes,
-	.detect       = dp_bridge_detect,
+	.mode_set = dp_bridge_mode_set,
+	.mode_valid = dp_bridge_mode_valid,
+	.get_modes = dp_bridge_get_modes,
+	.detect = dp_bridge_detect,
 	.atomic_check = dp_bridge_atomic_check,
 };
 
+struct msm_dp_bridge *msm_bridge_from_connector(struct drm_connector *connector)
+{
+	struct msm_drm_private *priv = connector->dev->dev_private;
+	int i = 0;
+	if (!priv)
+		return NULL;
+
+	for (i = 0; i < priv->num_bridges; i++) {
+		struct msm_dp *dp;
+		struct drm_connector *bridge_connector;
+		struct drm_bridge *bridge = priv->bridges[i];
+		if (!bridge)
+			continue;
+
+		dp = to_dp_bridge(bridge)->dp_display;
+		if (!dp)
+			continue;
+
+		bridge_connector = dp->connector;
+		if (bridge_connector == connector)
+			return to_dp_bridge(bridge);
+	}
+
+	return NULL;
+}
+
+bool dp_drm_is_connector_msm_dp(struct drm_connector *connector)
+{
+	struct msm_dp_bridge *dp_bridge = msm_bridge_from_connector(connector);
+	if (!dp_bridge)
+		return false;
+
+	if (dp_bridge->bridge.funcs == &dp_bridge_ops)
+		return true;
+
+	return false;
+}
+
+void dp_drm_atomic_commit(struct drm_connector *connector,
+			  struct drm_connector_state *conn_state,
+			  struct drm_atomic_state *state)
+{
+	struct msm_dp_bridge *bridge = msm_bridge_from_connector(connector);
+	if (!bridge)
+		return;
+
+	if (!bridge->state || !bridge->state->hdcp_transition)
+		return;
+
+	if (bridge->dp_display)
+		dp_display_hdcp_commit(bridge->dp_display, state);
+}
+
 struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
 			struct drm_encoder *encoder)
 {
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 82035dbb0578..d97dcc0f9458 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -8,21 +8,35 @@
 
 #include <linux/types.h>
 #include <drm/drm_bridge.h>
+#include <drm/display/drm_hdcp_helper.h>
 
 #include "msm_drv.h"
 #include "dp_display.h"
 
+struct dp_bridge_state {
+	struct drm_bridge_state base;
+	bool hdcp_transition;
+};
+#define to_dp_bridge_state(x) container_of(x, struct dp_bridge_state, base)
+
 struct msm_dp_bridge {
 	struct drm_bridge bridge;
+	struct dp_bridge_state *state;
 	struct msm_dp *dp_display;
 };
-
 #define to_dp_bridge(x)     container_of((x), struct msm_dp_bridge, bridge)
 
 struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder);
 struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
 			struct drm_encoder *encoder);
 
+bool dp_drm_is_connector_msm_dp(struct drm_connector *connector);
+struct msm_dp_bridge *
+msm_bridge_from_connector(struct drm_connector *connector);
+void dp_drm_atomic_commit(struct drm_connector *connector,
+			  struct drm_connector_state *conn_state,
+			  struct drm_atomic_state *state);
+
 void dp_bridge_enable(struct drm_bridge *drm_bridge);
 void dp_bridge_disable(struct drm_bridge *drm_bridge);
 void dp_bridge_post_disable(struct drm_bridge *drm_bridge);
diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp.c b/drivers/gpu/drm/msm/dp/dp_hdcp.c
new file mode 100644
index 000000000000..4408aa5eb607
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_hdcp.c
@@ -0,0 +1,456 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2021 Google, Inc.
+ *
+ * Authors:
+ * Sean Paul <seanpaul@chromium.org>
+ */
+
+#include "dp_display.h"
+#include "dp_drm.h"
+#include "dp_hdcp.h"
+#include "dp_reg.h"
+
+#include <drm/drm_connector.h>
+#include <drm/drm_device.h>
+#include <drm/display/drm_dp_helper.h>
+#include <drm/display/drm_hdcp_helper.h>
+#include <drm/drm_print.h>
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/iopoll.h>
+#include <linux/mutex.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+
+/* Offsets based on hdcp_ksv mmio */
+#define DP_HDCP_KSV_AN_LSB 0x0
+#define DP_HDCP_KSV_AN_MSB 0x4
+#define DP_HDCP_KSV_AKSV_MSB 0x1D8
+#define DP_HDCP_KSV_AKSV_LSB 0x1DC
+
+/* Key offsets based on hdcp_key mmio */
+#define DP_HDCP_KEY_BASE 0x30
+#define DP_HDCP_KEY_MSB(x) (DP_HDCP_KEY_BASE + (x * 8))
+#define DP_HDCP_KEY_LSB(x) (DP_HDCP_KEY_MSB(x) + 4)
+#define DP_HDCP_KEY_VALID 0x170
+#define DP_HDCP_SW_KEY_VALID BIT(0)
+
+/* Timeouts */
+#define DP_KEYS_VALID_SLEEP_US (20 * 1000)
+#define DP_KEYS_VALID_TIMEOUT_US (100 * 1000)
+#define DP_AN_READY_SLEEP_US 100
+#define DP_AN_READY_TIMEOUT_US (10 * 1000)
+#define DP_R0_READY_SLEEP_US 100
+#define DP_R0_READY_TIMEOUT_US (10 * 1000)
+#define DP_RI_MATCH_SLEEP_US (20 * 1000)
+#define DP_RI_MATCH_TIMEOUT_US (100 * 1000)
+#define DP_KSV_WRITTEN_SLEEP_US 100
+#define DP_KSV_WRITTEN_TIMEOUT_US (100 * 1000)
+#define DP_SHA_COMPUTATION_SLEEP_US 100
+#define DP_SHA_COMPUTATION_TIMEOUT_US (100 * 1000)
+#define DP_AN_READ_DELAY_US 1
+
+/*
+ * dp_hdcp_key - structure which contains an HDCP key set
+ * @ksv: The key selection vector
+ * @keys: Contains 40 keys
+ */
+struct dp_hdcp_key {
+	struct drm_hdcp_ksv ksv;
+	union {
+		u32 words[2];
+		u8 bytes[DP_HDCP_KEY_LEN];
+	} keys[DP_HDCP_NUM_KEYS];
+	bool valid;
+};
+
+struct dp_hdcp {
+	struct drm_device *dev;
+	struct drm_connector *connector;
+
+	struct drm_dp_aux *aux;
+	struct dp_parser *parser;
+
+	struct drm_hdcp_helper_data *helper_data;
+
+	struct mutex key_lock;
+	struct dp_hdcp_key key;
+};
+
+static inline void dp_hdcp_write_ahb(struct dp_hdcp *hdcp, u32 offset, u32 val)
+{
+	writel(val, hdcp->parser->io.dp_controller.ahb.base + offset);
+}
+
+static inline u32 dp_hdcp_read_ahb(struct dp_hdcp *hdcp, u32 offset)
+{
+	return readl(hdcp->parser->io.dp_controller.ahb.base + offset);
+}
+
+static inline void dp_hdcp_write_aux(struct dp_hdcp *hdcp, u32 offset, u32 val)
+{
+	writel(val, hdcp->parser->io.dp_controller.aux.base + offset);
+}
+
+static inline u32 dp_hdcp_read_aux(struct dp_hdcp *hdcp, u32 offset)
+{
+	return readl(hdcp->parser->io.dp_controller.aux.base + offset);
+}
+
+static inline void dp_hdcp_write_link(struct dp_hdcp *hdcp, u32 offset, u32 val)
+{
+	writel(val, hdcp->parser->io.dp_controller.link.base + offset);
+}
+
+static inline u32 dp_hdcp_read_link(struct dp_hdcp *hdcp, u32 offset)
+{
+	return readl(hdcp->parser->io.dp_controller.link.base + offset);
+}
+
+static inline void dp_hdcp_write_key(struct dp_hdcp *hdcp, u32 offset, u32 val)
+{
+	writel(val, hdcp->parser->io.dp_controller.hdcp_key.base + offset);
+}
+
+static inline void dp_hdcp_write_tz_hlos(struct dp_hdcp *hdcp, u32 offset,
+					 u32 val)
+{
+	writel(val, hdcp->parser->io.dp_controller.hdcp_tz.base + offset);
+}
+
+int dp_hdcp_ingest_key(struct dp_hdcp *hdcp, const u8 *raw_key, int raw_len)
+{
+	unsigned int ksv_weight;
+	int i, ret = 0;
+
+	if (raw_len !=
+	    (DRM_HDCP_KSV_LEN + DP_HDCP_NUM_KEYS * DP_HDCP_KEY_LEN)) {
+		DRM_ERROR(
+			"Invalid HDCP key length expected=%d actual=%d\n",
+			(DRM_HDCP_KSV_LEN + DP_HDCP_NUM_KEYS * DP_HDCP_KEY_LEN),
+			raw_len);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hdcp->key_lock);
+
+	memcpy(hdcp->key.ksv.bytes, raw_key, DRM_HDCP_KSV_LEN);
+	ksv_weight = hweight32(hdcp->key.ksv.words[0]) +
+		     hweight32(hdcp->key.ksv.words[1]);
+	if (ksv_weight != 20) {
+		DRM_ERROR("Invalid ksv weight, expected=20 actual=%d\n",
+			  ksv_weight);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	raw_key += DRM_HDCP_KSV_LEN;
+	for (i = 0; i < DP_HDCP_NUM_KEYS; i++) {
+		memcpy(hdcp->key.keys[i].bytes, raw_key, DP_HDCP_KEY_LEN);
+		raw_key += DP_HDCP_KEY_LEN;
+	}
+
+	DRM_DEBUG_DRIVER("Successfully ingested HDCP key\n");
+	hdcp->key.valid = true;
+
+out:
+	mutex_unlock(&hdcp->key_lock);
+	return ret;
+}
+
+static bool dp_hdcp_are_keys_valid(struct drm_connector *connector)
+{
+	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
+	u32 val;
+
+	val = dp_hdcp_read_ahb(hdcp, DP_HDCP_STATUS);
+	return FIELD_GET(DP_HDCP_KEY_STATUS, val) == DP_HDCP_KEY_STATUS_VALID;
+}
+
+static int dp_hdcp_load_keys(struct drm_connector *connector)
+{
+	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
+	int i, ret = 0;
+	u64 an_seed = get_random_u64();
+
+	mutex_lock(&hdcp->key_lock);
+
+	if (!hdcp->key.valid) {
+		ret = -ENOENT;
+		goto out;
+	}
+
+	dp_hdcp_write_aux(hdcp, DP_HDCP_SW_LOWER_AKSV, hdcp->key.ksv.words[0]);
+	dp_hdcp_write_aux(hdcp, DP_HDCP_SW_UPPER_AKSV, hdcp->key.ksv.words[1]);
+
+	for (i = 0; i < DP_HDCP_NUM_KEYS; i++) {
+		dp_hdcp_write_key(hdcp, DP_HDCP_KEY_LSB(i),
+				  hdcp->key.keys[i].words[0]);
+		dp_hdcp_write_key(hdcp, DP_HDCP_KEY_MSB(i),
+				  hdcp->key.keys[i].words[1]);
+	}
+
+	dp_hdcp_write_key(hdcp, DP_HDCP_KEY_VALID, DP_HDCP_SW_KEY_VALID);
+
+	dp_hdcp_write_link(hdcp, DP_HDCP_ENTROPY_CTRL0,
+			   FIELD_GET(GENMASK(31, 0), an_seed));
+	dp_hdcp_write_link(hdcp, DP_HDCP_ENTROPY_CTRL1,
+			   FIELD_GET(GENMASK_ULL(63, 32), an_seed));
+
+out:
+	mutex_unlock(&hdcp->key_lock);
+	return ret;
+}
+
+static int dp_hdcp_hdcp2_capable(struct drm_connector *connector, bool *capable)
+{
+	*capable = false;
+	return 0;
+}
+
+static int dp_hdcp_hdcp1_read_an_aksv(struct drm_connector *connector, u32 *an,
+				      u32 *aksv)
+{
+	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
+	bool keys_valid;
+	int ret;
+	u32 val;
+
+	dp_hdcp_write_ahb(hdcp, DP_HDCP_CTRL, 1);
+
+	ret = read_poll_timeout(dp_hdcp_are_keys_valid, keys_valid, keys_valid,
+				DP_KEYS_VALID_SLEEP_US,
+				DP_KEYS_VALID_TIMEOUT_US, false, connector);
+	if (ret) {
+		drm_err(hdcp->dev, "HDCP keys invalid %d\n", ret);
+		return ret;
+	}
+
+	/* Clear AInfo */
+	dp_hdcp_write_aux(hdcp, DP_HDCP_RCVPORT_DATA4, 0);
+
+	aksv[0] = dp_hdcp_read_aux(hdcp, DP_HDCP_RCVPORT_DATA3);
+	aksv[1] = GENMASK(7, 0) & dp_hdcp_read_aux(hdcp, DP_HDCP_RCVPORT_DATA4);
+
+	ret = read_poll_timeout(dp_hdcp_read_ahb, val,
+				(val & DP_HDCP_AN_READY_MASK) ==
+					DP_HDCP_AN_READY_MASK,
+				DP_AN_READY_SLEEP_US, DP_AN_READY_TIMEOUT_US,
+				false, hdcp, DP_HDCP_STATUS);
+	if (ret) {
+		drm_err(hdcp->dev, "AN failed to become ready %x/%d\n", val,
+			ret);
+		return ret;
+	}
+
+	/*
+	 * Get An from hardware, for unknown reasons we need to read the reg
+	 * twice to get valid data.
+	 */
+	dp_hdcp_read_ahb(hdcp, DP_HDCP_RCVPORT_DATA5);
+	an[0] = dp_hdcp_read_ahb(hdcp, DP_HDCP_RCVPORT_DATA5);
+
+	udelay(DP_AN_READ_DELAY_US);
+
+	dp_hdcp_read_ahb(hdcp, DP_HDCP_RCVPORT_DATA6);
+	an[1] = dp_hdcp_read_ahb(hdcp, DP_HDCP_RCVPORT_DATA6);
+
+	return 0;
+}
+
+static int dp_hdcp_hdcp1_store_receiver_info(struct drm_connector *connector,
+					     u32 *ksv, u32 status, u8 bcaps,
+					     bool is_repeater)
+{
+	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
+	u32 val;
+
+	dp_hdcp_write_tz_hlos(hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0,
+			      ksv[0]);
+	dp_hdcp_write_tz_hlos(hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1,
+			      ksv[1]);
+
+	val = FIELD_PREP(GENMASK(23, 8), status) |
+	      FIELD_PREP(GENMASK(7, 0), bcaps);
+
+	dp_hdcp_write_tz_hlos(hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12,
+			      val);
+
+	return 0;
+}
+
+static int dp_hdcp_hdcp1_enable_encryption(struct drm_connector *connector)
+{
+	return 0;
+}
+
+static int dp_hdcp_hdcp1_wait_for_r0(struct drm_connector *connector)
+{
+	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
+	int ret;
+	u32 val;
+
+	ret = read_poll_timeout(dp_hdcp_read_ahb, val, (val & DP_HDCP_R0_READY),
+				DP_R0_READY_SLEEP_US, DP_R0_READY_TIMEOUT_US,
+				false, hdcp, DP_HDCP_STATUS);
+	if (ret) {
+		drm_err(hdcp->dev, "HDCP R0 not ready %x/%d\n", val, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dp_hdcp_hdcp1_match_ri(struct drm_connector *connector, u32 ri_prime)
+{
+	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
+	int ret;
+	u32 val;
+
+	dp_hdcp_write_ahb(hdcp, DP_HDCP_RCVPORT_DATA2_0, ri_prime);
+
+	ret = read_poll_timeout(dp_hdcp_read_ahb, val, (val & DP_HDCP_RI_MATCH),
+				DP_RI_MATCH_SLEEP_US, DP_RI_MATCH_TIMEOUT_US,
+				false, hdcp, DP_HDCP_STATUS);
+	if (ret) {
+		drm_err(hdcp->dev,
+			"Failed to match Ri and Ri` (%08x) %08x/%d\n", ri_prime,
+			val, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int dp_hdcp_hdcp1_store_ksv_fifo(struct drm_connector *connector,
+					u8 *ksv_fifo, u8 num_downstream,
+					u8 *bstatus, u32 *vprime)
+{
+	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
+	int num_bytes = num_downstream * DRM_HDCP_KSV_LEN;
+	int ret, i;
+	u32 val;
+
+	/* Reset the SHA computation block */
+	dp_hdcp_write_tz_hlos(hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL,
+			      DP_HDCP_SHA_CTRL_RESET);
+	dp_hdcp_write_tz_hlos(hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, 0);
+
+	/*
+	 * KSV info gets written a byte at a time in the same order it was
+	 * received. Every 64 bytes, we need to wait for the SHA_BLOCK_DONE
+	 * bit to be set in SHA_CTRL.
+	 */
+	for (i = 0; i < num_bytes; i++) {
+		val = FIELD_PREP(DP_HDCP_SHA_DATA_MASK, ksv_fifo[i]);
+
+		if (i == (num_bytes - 1))
+			val |= DP_HDCP_SHA_DATA_DONE;
+
+		dp_hdcp_write_tz_hlos(
+			hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA, val);
+
+		if (((i + 1) % 64) != 0)
+			continue;
+
+		ret = read_poll_timeout(dp_hdcp_read_ahb, val,
+					(val & DP_HDCP_SHA_DONE),
+					DP_KSV_WRITTEN_SLEEP_US,
+					DP_KSV_WRITTEN_TIMEOUT_US, false, hdcp,
+					DP_HDCP_SHA_STATUS);
+		if (ret) {
+			drm_err(hdcp->dev, "SHA block incomplete %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = read_poll_timeout(dp_hdcp_read_ahb, val,
+				(val & DP_HDCP_SHA_COMP_DONE),
+				DP_SHA_COMPUTATION_SLEEP_US,
+				DP_SHA_COMPUTATION_TIMEOUT_US, false, hdcp,
+				DP_HDCP_SHA_STATUS);
+	if (ret) {
+		drm_err(hdcp->dev, "SHA computation incomplete %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dp_hdcp_hdcp1_disable(struct drm_connector *connector)
+{
+	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
+	u32 val;
+
+	val = dp_hdcp_read_ahb(hdcp, REG_DP_SW_RESET);
+	dp_hdcp_write_ahb(hdcp, REG_DP_SW_RESET, val | DP_HDCP_SW_RESET);
+
+	/* Disable encryption and disable the HDCP block */
+	dp_hdcp_write_ahb(hdcp, DP_HDCP_CTRL, 0);
+
+	dp_hdcp_write_ahb(hdcp, REG_DP_SW_RESET, val);
+
+	return 0;
+}
+
+void dp_hdcp_commit(struct dp_hdcp *hdcp, struct drm_atomic_state *state)
+{
+	drm_hdcp_helper_atomic_commit(hdcp->helper_data, state, NULL);
+}
+
+static const struct drm_hdcp_helper_funcs dp_hdcp_funcs = {
+	.are_keys_valid = dp_hdcp_are_keys_valid,
+	.load_keys = dp_hdcp_load_keys,
+	.hdcp2_capable = dp_hdcp_hdcp2_capable,
+	.hdcp1_read_an_aksv = dp_hdcp_hdcp1_read_an_aksv,
+	.hdcp1_store_receiver_info = dp_hdcp_hdcp1_store_receiver_info,
+	.hdcp1_enable_encryption = dp_hdcp_hdcp1_enable_encryption,
+	.hdcp1_wait_for_r0 = dp_hdcp_hdcp1_wait_for_r0,
+	.hdcp1_match_ri = dp_hdcp_hdcp1_match_ri,
+	.hdcp1_store_ksv_fifo = dp_hdcp_hdcp1_store_ksv_fifo,
+	.hdcp1_disable = dp_hdcp_hdcp1_disable,
+};
+
+int dp_hdcp_attach(struct dp_hdcp *hdcp, struct drm_connector *connector)
+{
+	struct drm_hdcp_helper_data *helper_data;
+
+	/* HDCP is not configured for this device */
+	if (!hdcp->parser->io.dp_controller.hdcp_key.base)
+		return 0;
+
+	helper_data = drm_hdcp_helper_initialize_dp(connector, hdcp->aux,
+						    &dp_hdcp_funcs, false);
+	if (IS_ERR(helper_data))
+		return PTR_ERR(helper_data);
+
+	hdcp->dev = connector->dev;
+	hdcp->connector = connector;
+	hdcp->helper_data = helper_data;
+
+	return 0;
+}
+
+struct dp_hdcp *dp_hdcp_get(struct dp_parser *parser, struct drm_dp_aux *aux)
+{
+	struct device *dev = &parser->pdev->dev;
+	struct dp_hdcp *hdcp;
+
+	hdcp = devm_kzalloc(dev, sizeof(*hdcp), GFP_KERNEL);
+	if (!hdcp)
+		return ERR_PTR(-ENOMEM);
+
+	hdcp->parser = parser;
+	hdcp->aux = aux;
+
+	mutex_init(&hdcp->key_lock);
+
+	return hdcp;
+}
+
+void dp_hdcp_put(struct dp_hdcp *hdcp)
+{
+	if (hdcp)
+		drm_hdcp_helper_destroy(hdcp->helper_data);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp.h b/drivers/gpu/drm/msm/dp/dp_hdcp.h
new file mode 100644
index 000000000000..399b43250e55
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_hdcp.h
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2021 Google, Inc.
+ *
+ * Authors:
+ * Sean Paul <seanpaul@chromium.org>
+ */
+
+#ifndef DP_HDCP_H_
+#define DP_HDCP_H_
+
+#include <drm/display/drm_hdcp_helper.h>
+
+#define DP_HDCP_KEY_LEN 7
+#define DP_HDCP_NUM_KEYS 40
+
+struct dp_hdcp;
+struct dp_parser;
+struct drm_atomic_state;
+struct drm_dp_aux;
+
+struct dp_hdcp *dp_hdcp_get(struct dp_parser *parser, struct drm_dp_aux *aux);
+void dp_hdcp_put(struct dp_hdcp *hdcp);
+
+int dp_hdcp_attach(struct dp_hdcp *hdcp, struct drm_connector *connector);
+int dp_hdcp_ingest_key(struct dp_hdcp *hdcp, const u8 *raw_key, int raw_len);
+void dp_hdcp_commit(struct dp_hdcp *hdcp, struct drm_atomic_state *state);
+
+#endif
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index dcbe893d66d7..714b8dcbc563 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -58,7 +58,6 @@ static int dp_parser_ctrl_res(struct dp_parser *parser)
 				DRM_ERROR("legacy memory region not large enough\n");
 				return -EINVAL;
 			}
-
 			dss->ahb.len = DP_DEFAULT_AHB_SIZE;
 			dss->aux.base = dss->ahb.base + DP_DEFAULT_AUX_OFFSET;
 			dss->aux.len = DP_DEFAULT_AUX_SIZE;
@@ -66,6 +65,10 @@ static int dp_parser_ctrl_res(struct dp_parser *parser)
 			dss->link.len = DP_DEFAULT_LINK_SIZE;
 			dss->p0.base = dss->ahb.base + DP_DEFAULT_P0_OFFSET;
 			dss->p0.len = DP_DEFAULT_P0_SIZE;
+			dss->hdcp_key.base = NULL;
+			dss->hdcp_key.len = 0;
+			dss->hdcp_tz.base = NULL;
+			dss->hdcp_tz.len = 0;
 		} else {
 			DRM_ERROR("unable to remap aux region: %pe\n", dss->aux.base);
 			return PTR_ERR(dss->aux.base);
@@ -82,6 +85,21 @@ static int dp_parser_ctrl_res(struct dp_parser *parser)
 			DRM_ERROR("unable to remap p0 region: %pe\n", dss->p0.base);
 			return PTR_ERR(dss->p0.base);
 		}
+
+		dss->hdcp_key.base = dp_ioremap(pdev, 5, &dss->hdcp_key.len);
+		if (!IS_ERR(dss->hdcp_key.base)) {
+			dss->hdcp_tz.base = dp_ioremap(pdev, 6, &dss->hdcp_tz.len);
+			if (IS_ERR(dss->hdcp_tz.base)) {
+				DRM_ERROR("unable to remap hdcp_tz region: %pe\n",
+					dss->hdcp_tz.base);
+				return PTR_ERR(dss->hdcp_tz.base);
+			}
+		} else {
+			dss->hdcp_key.base = NULL;
+			dss->hdcp_key.len = 0;
+			dss->hdcp_tz.base = NULL;
+			dss->hdcp_tz.len = 0;
+		}
 	}
 
 	io->phy = devm_phy_get(&pdev->dev, "dp");
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
index d30ab773db46..b15e481d9d3b 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -34,6 +34,8 @@ struct dss_io_data {
 	struct dss_io_region aux;
 	struct dss_io_region link;
 	struct dss_io_region p0;
+	struct dss_io_region hdcp_key;
+	struct dss_io_region hdcp_tz;
 };
 
 static inline const char *dp_parser_pm_name(enum dp_pm_type module)
@@ -68,6 +70,8 @@ struct dp_display_data {
  * struct dp_ctrl_resource - controller's IO related data
  *
  * @dp_controller: Display Port controller mapped memory address
+ * @hdcp_key: mapped memory for HDCP key ingestion
+ * @hdcp_tz: mapped memory for HDCP TZ interaction
  * @phy_io: phy's mapped memory address
  */
 struct dp_io {
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index 268602803d9a..61ab70850f6b 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -6,11 +6,14 @@
 #ifndef _DP_REG_H_
 #define _DP_REG_H_
 
+#include <linux/bits.h>
+
 /* DP_TX Registers */
 #define REG_DP_HW_VERSION			(0x00000000)
 
 #define REG_DP_SW_RESET				(0x00000010)
-#define DP_SW_RESET				(0x00000001)
+#define  DP_SW_RESET				BIT(0)
+#define  DP_HDCP_SW_RESET			BIT(1)
 
 #define REG_DP_PHY_CTRL				(0x00000014)
 #define DP_PHY_CTRL_SW_RESET_PLL		(0x00000001)
@@ -283,19 +286,46 @@
 /* DP HDCP 1.3 registers */
 #define DP_HDCP_CTRL                                   (0x0A0)
 #define DP_HDCP_STATUS                                 (0x0A4)
+#define  DP_HDCP_KEY_STATUS			       GENMASK(18, 16)
+#define   DP_HDCP_KEY_STATUS_NO_KEYS		       0
+#define   DP_HDCP_KEY_STATUS_NOT_CHECKED	       1
+#define   DP_HDCP_KEY_STATUS_CHECKING		       2
+#define   DP_HDCP_KEY_STATUS_VALID		       3
+#define   DP_HDCP_KEY_STATUS_INVALID_AKSV	       4
+#define   DP_HDCP_KEY_STATUS_BAD_CHECKSUM	       5
+#define   DP_HDCP_KEY_STATUS_PROD_AKSV		       6
+#define   DP_HDCP_KEY_STATUS_RESV		       7
+#define  DP_HDCP_R0_READY			       BIT(14)
+#define  DP_HDCP_SHA_V_MATCH			       BIT(13)
+#define  DP_HDCP_RI_MATCH			       BIT(12)
+#define  DP_HDCP_AN_MSB_READY			       BIT(9)
+#define  DP_HDCP_AN_LSB_READY			       BIT(8)
+#define  DP_HDCP_AN_READY_MASK			       (DP_HDCP_AN_MSB_READY | DP_HDCP_AN_LSB_READY)
+#define  DP_HDCP_AUTH_FAIL_INFO			       GENMASK(7, 4)
+#define   DP_HDCP_AUTH_FAIL_INVALID_AKSV	       3
+#define   DP_HDCP_AUTH_FAIL_INVALID_BKSV	       4
+#define   DP_HDCP_AUTH_FAIL_RI_MISMATCH		       5
+#define  DP_HDCP_AUTH_FAIL			       BIT(2)
+#define  DP_HDCP_AUTH_SUCCESS			       BIT(0)
 #define DP_HDCP_SW_UPPER_AKSV                          (0x098)
 #define DP_HDCP_SW_LOWER_AKSV                          (0x09C)
 #define DP_HDCP_ENTROPY_CTRL0                          (0x350)
 #define DP_HDCP_ENTROPY_CTRL1                          (0x35C)
 #define DP_HDCP_SHA_STATUS                             (0x0C8)
+#define  DP_HDCP_SHA_COMP_DONE			       BIT(4)
+#define  DP_HDCP_SHA_DONE			       BIT(0)
 #define DP_HDCP_RCVPORT_DATA2_0                        (0x0B0)
 #define DP_HDCP_RCVPORT_DATA3                          (0x0A4)
 #define DP_HDCP_RCVPORT_DATA4                          (0x0A8)
 #define DP_HDCP_RCVPORT_DATA5                          (0x0C0)
 #define DP_HDCP_RCVPORT_DATA6                          (0x0C4)
+#define DP_HDCP_RCVPORT_DATA7                          (0x0C8)
 
 #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL           (0x024)
+#define  DP_HDCP_SHA_CTRL_RESET			       BIT(0)
 #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA           (0x028)
+#define  DP_HDCP_SHA_DATA_MASK			       GENMASK(23, 16)
+#define  DP_HDCP_SHA_DATA_DONE			       BIT(0)
 #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0      (0x004)
 #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1      (0x008)
 #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7      (0x00C)
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 1686fbb611fd..7447f67fba65 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -7,6 +7,7 @@
 #include <drm/drm_atomic_uapi.h>
 #include <drm/drm_vblank.h>
 
+#include "dp_drm.h"
 #include "msm_atomic_trace.h"
 #include "msm_drv.h"
 #include "msm_gem.h"
@@ -179,6 +180,18 @@ static unsigned get_crtc_mask(struct drm_atomic_state *state)
 	return mask;
 }
 
+static void msm_atomic_commit_connectors(struct drm_atomic_state *state)
+{
+	struct drm_connector_state *conn_state;
+	struct drm_connector *connector;
+	int i;
+
+	for_each_new_connector_in_state(state, connector, conn_state, i) {
+		if (dp_drm_is_connector_msm_dp(connector))
+			dp_drm_atomic_commit(connector, conn_state, state);
+	}
+}
+
 void msm_atomic_commit_tail(struct drm_atomic_state *state)
 {
 	struct drm_device *dev = state->dev;
@@ -215,6 +228,8 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state)
 	drm_atomic_helper_commit_planes(dev, state, 0);
 	drm_atomic_helper_commit_modeset_enables(dev, state);
 
+	msm_atomic_commit_connectors(state);
+
 	if (async) {
 		struct msm_pending_timer *timer =
 			&kms->pending_timers[drm_crtc_index(async_crtc)];
-- 
2.39.0.246.g2a6d74b583-goog


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 08/10] dt-bindings: msm/dp: Add bindings for HDCP registers
  2023-01-18 19:30 ` [PATCH v6 08/10] dt-bindings: msm/dp: Add bindings for HDCP registers Mark Yacoub
@ 2023-01-19  1:16   ` Rob Herring
  2023-01-19  7:48   ` Johan Hovold
  2023-01-19  8:36   ` Dmitry Baryshkov
  2 siblings, 0 replies; 38+ messages in thread
From: Rob Herring @ 2023-01-19  1:16 UTC (permalink / raw)
  To: Mark Yacoub
  Cc: javierm, devicetree, krzysztof.kozlowski+dt, quic_sbillaka,
	dianders, swboyd, quic_abhinavk, lucas.demarchi, konrad.dybcio,
	manasi.d.navare, robdclark, marex, maxime, ankit.k.nautiyal,
	arun.r.murthy, quic_khsieh, ashutosh.dixit, dri-devel, freedreno,
	tvrtko.ursulin, bhanuprakash.modem, jose.souza, rodrigo.vivi,
	linux-arm-msm, quic_jesszhan, tzimmermann, joonas.lahtinen,
	stanislav.lisovskiy, swati2.sharma, ville.syrjala, linux-kernel,
	seanpaul, sean, Mark Yacoub, bjorn.andersson, agross,
	dmitry.baryshkov, matthew.d.roper, abhinavk, intel-gfx, daniel,
	lyude, hbh25y, robh+dt, airlied, imre.deak, christophe.jaillet,
	johan+linaro, andersson, jani.nikula


On Wed, 18 Jan 2023 19:30:13 +0000, Mark Yacoub wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch adds the bindings for the MSM DisplayPort HDCP registers
> which are required to write the HDCP key into the display controller as
> well as the registers to enable HDCP authentication/key
> exchange/encryption.
> 
> We'll use a new compatible string for this since the fields are optional.
> 
> Cc: Rob Herring <robh@kernel.org>
> Cc: Stephen Boyd <swboyd@chromium.org>
> Reviewed-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromiu.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-13-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-13-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-13-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-13-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20211115202153.117244-1-sean@poorly.run #v4.5
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-9-sean@poorly.run #v5
> 
> Changes in v2:
> -Drop register range names (Stephen)
> -Fix yaml errors (Rob)
> Changes in v3:
> -Add new compatible string for dp-hdcp
> -Add descriptions to reg
> -Add minItems/maxItems to reg
> -Make reg depend on the new hdcp compatible string
> Changes in v4:
> -Rebase on Bjorn's multi-dp patchset
> Changes in v4.5:
> -Remove maxItems from reg (Rob)
> -Remove leading zeros in example (Rob)
> Changes in v5:
> -None
> Changes in v6:
> -Rebased: modify minItems instead of adding it as new line.
> 
> ---
>  .../devicetree/bindings/display/msm/dp-controller.yaml    | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/msm/dp-controller.example.dtb: displayport-controller@ae90000: reg: [[183042048, 512], [183042560, 512], [183043072, 3072], [183046144, 1024], [183047168, 1024], [183308288, 372], [183373824, 44]] is too long
	From schema: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.example.dtb: edp@aea0000: reg: [[183107584, 512], [183108096, 512], [183108608, 3072], [183111680, 1024]] is too short
	From schema: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/msm/dp-controller.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20230118193015.911074-9-markyacoub@google.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller
  2023-01-18 19:30 ` [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller Mark Yacoub
@ 2023-01-19  1:32   ` Abhinav Kumar
  2023-01-19  8:40   ` Dmitry Baryshkov
  2023-01-19 10:35   ` Krzysztof Kozlowski
  2 siblings, 0 replies; 38+ messages in thread
From: Abhinav Kumar @ 2023-01-19  1:32 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: robdclark, dmitry.baryshkov, sean, airlied, daniel, robh+dt,
	krzysztof.kozlowski+dt, agross, andersson, konrad.dybcio,
	jani.nikula, joonas.lahtinen, rodrigo.vivi, tvrtko.ursulin,
	tzimmermann, ville.syrjala, stanislav.lisovskiy, matthew.d.roper,
	imre.deak, lucas.demarchi, manasi.d.navare, swati2.sharma,
	bhanuprakash.modem, javierm, jose.souza, lyude, hbh25y,
	arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime, swboyd,
	christophe.jaillet, quic_sbillaka, johan+linaro, dianders, marex,
	quic_jesszhan, bjorn.andersson, abhinavk, seanpaul

Hi Mark

On 1/18/2023 11:30 AM, Mark Yacoub wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch adds the register ranges required for HDCP key injection and
> HDCP TrustZone interaction as described in the dt-bindings for the
> sc7180 dp controller. Now that these are supported, change the
> compatible string to "dp-hdcp".
> 
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-15-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-14-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-14-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-14-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-10-sean@poorly.run #v5
> 
> Changes in v3:
> -Split off into a new patch containing just the dts change (Stephen)
> -Add hdcp compatible string (Stephen)
> Changes in v4:
> -Rebase on Bjorn's multi-dp patchset
> Changes in v5:
> -Put the tz register offsets in trogdor dtsi (Rob C)
> Changes in v6:
> -Rebased: Removed modifications in sc7180.dtsi as it's already upstream
> 
> ---
>   arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi | 8 ++++++++
>   1 file changed, 8 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
> index 178efaaa89ec..6f6fe5cb6563 100644
> --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
> @@ -817,6 +817,14 @@ &mdss_dp {
>   	pinctrl-names = "default";
>   	pinctrl-0 = <&dp_hot_plug_det>;
>   	data-lanes = <0 1>;
> +
> +	reg = <0 0x0ae90000 0 0x200>,
> +	      <0 0x0ae90200 0 0x200>,
> +	      <0 0x0ae90400 0 0xc00>,
> +	      <0 0x0ae91000 0 0x400>,
> +	      <0 0x0ae91400 0 0x400>,
> +	      <0 0x0aed1000 0 0x175>,
> +	      <0 0x0aee1000 0 0x2c>;
>   };

Can you pls point me to which tree you rebased this on top of?

The mdss_dp node looks different here: 
https://gitlab.com/linux-kernel/linux-next/-/blob/master/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi#L815

For the TZ regs the second entry is fine but any reason for the size of 
the first register space to be 0x175 instead of 0x174?



>   
>   &pm6150_adc {

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 08/10] dt-bindings: msm/dp: Add bindings for HDCP registers
  2023-01-18 19:30 ` [PATCH v6 08/10] dt-bindings: msm/dp: Add bindings for HDCP registers Mark Yacoub
  2023-01-19  1:16   ` Rob Herring
@ 2023-01-19  7:48   ` Johan Hovold
  2023-01-19  8:36   ` Dmitry Baryshkov
  2 siblings, 0 replies; 38+ messages in thread
From: Johan Hovold @ 2023-01-19  7:48 UTC (permalink / raw)
  To: Mark Yacoub
  Cc: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx, robdclark, quic_abhinavk,
	dmitry.baryshkov, sean, airlied, daniel, robh+dt,
	krzysztof.kozlowski+dt, agross, andersson, konrad.dybcio,
	jani.nikula, joonas.lahtinen, rodrigo.vivi, tvrtko.ursulin,
	tzimmermann, ville.syrjala, stanislav.lisovskiy, matthew.d.roper,
	imre.deak, lucas.demarchi, manasi.d.navare, swati2.sharma,
	bhanuprakash.modem, javierm, jose.souza, lyude, hbh25y,
	arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime, swboyd,
	christophe.jaillet, quic_sbillaka, johan+linaro, dianders, marex,
	quic_jesszhan, bjorn.andersson, abhinavk, seanpaul, Rob Herring,
	Mark Yacoub

On Wed, Jan 18, 2023 at 07:30:13PM +0000, Mark Yacoub wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch adds the bindings for the MSM DisplayPort HDCP registers
> which are required to write the HDCP key into the display controller as
> well as the registers to enable HDCP authentication/key
> exchange/encryption.
> 
> We'll use a new compatible string for this since the fields are optional.
> 
> Cc: Rob Herring <robh@kernel.org>
> Cc: Stephen Boyd <swboyd@chromium.org>
> Reviewed-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromiu.org>

Just a drive-by comment: Your mail address is missing an 'm' here.

Perhaps check the rest of the series as well (checkpatch should catch
this).

Johan

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 08/10] dt-bindings: msm/dp: Add bindings for HDCP registers
  2023-01-18 19:30 ` [PATCH v6 08/10] dt-bindings: msm/dp: Add bindings for HDCP registers Mark Yacoub
  2023-01-19  1:16   ` Rob Herring
  2023-01-19  7:48   ` Johan Hovold
@ 2023-01-19  8:36   ` Dmitry Baryshkov
  2 siblings, 0 replies; 38+ messages in thread
From: Dmitry Baryshkov @ 2023-01-19  8:36 UTC (permalink / raw)
  To: Mark Yacoub
  Cc: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx, robdclark, quic_abhinavk, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, tzimmermann, ville.syrjala, stanislav.lisovskiy,
	matthew.d.roper, imre.deak, lucas.demarchi, manasi.d.navare,
	swati2.sharma, bhanuprakash.modem, javierm, jose.souza, lyude,
	hbh25y, arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime,
	swboyd, christophe.jaillet, quic_sbillaka, johan+linaro,
	dianders, marex, quic_jesszhan, bjorn.andersson, abhinavk,
	seanpaul, Rob Herring, Mark Yacoub

On Wed, 18 Jan 2023 at 21:30, Mark Yacoub <markyacoub@chromium.org> wrote:
>
> From: Sean Paul <seanpaul@chromium.org>
>
> This patch adds the bindings for the MSM DisplayPort HDCP registers
> which are required to write the HDCP key into the display controller as
> well as the registers to enable HDCP authentication/key
> exchange/encryption.
>
> We'll use a new compatible string for this since the fields are optional.

This doesn't correspond to patch contents.

>
> Cc: Rob Herring <robh@kernel.org>

This should be a

> Cc: Stephen Boyd <swboyd@chromium.org>
> Reviewed-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromiu.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-13-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-13-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-13-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-13-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20211115202153.117244-1-sean@poorly.run #v4.5
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-9-sean@poorly.run #v5

Please, clean this up. I suspect that the long list of previous
iterations might belong to the cover letter, but not to the series
themselves.

>
> Changes in v2:
> -Drop register range names (Stephen)
> -Fix yaml errors (Rob)
> Changes in v3:
> -Add new compatible string for dp-hdcp
> -Add descriptions to reg
> -Add minItems/maxItems to reg
> -Make reg depend on the new hdcp compatible string
> Changes in v4:
> -Rebase on Bjorn's multi-dp patchset
> Changes in v4.5:
> -Remove maxItems from reg (Rob)
> -Remove leading zeros in example (Rob)
> Changes in v5:
> -None
> Changes in v6:
> -Rebased: modify minItems instead of adding it as new line.
>
> ---
>  .../devicetree/bindings/display/msm/dp-controller.yaml    | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
> index f2515af8256f..17d741f9af86 100644
> --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
> +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml
> @@ -24,13 +24,15 @@ properties:
>        - qcom,sm8350-dp
>
>    reg:
> -    minItems: 4
> +    minItems: 5

No. eDP uses 4 register blocks.

>      items:
>        - description: ahb register block
>        - description: aux register block
>        - description: link register block
>        - description: p0 register block
>        - description: p1 register block
> +      - description: (Optional) Registers for HDCP device key injection
> +      - description: (Optional) Registers for HDCP TrustZone interaction
>
>    interrupts:
>      maxItems: 1
> @@ -154,7 +156,9 @@ examples:
>                <0xae90200 0x200>,
>                <0xae90400 0xc00>,
>                <0xae91000 0x400>,
> -              <0xae91400 0x400>;
> +              <0xae91400 0x400>,
> +              <0xaed1000 0x174>,
> +              <0xaee1000 0x2c>;
>          interrupt-parent = <&mdss>;
>          interrupts = <12>;
>          clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
> --
> 2.39.0.246.g2a6d74b583-goog
>


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller
  2023-01-18 19:30 ` [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller Mark Yacoub
  2023-01-19  1:32   ` Abhinav Kumar
@ 2023-01-19  8:40   ` Dmitry Baryshkov
  2023-01-19 10:35   ` Krzysztof Kozlowski
  2 siblings, 0 replies; 38+ messages in thread
From: Dmitry Baryshkov @ 2023-01-19  8:40 UTC (permalink / raw)
  To: Mark Yacoub
  Cc: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx, robdclark, quic_abhinavk, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, tzimmermann, ville.syrjala, stanislav.lisovskiy,
	matthew.d.roper, imre.deak, lucas.demarchi, manasi.d.navare,
	swati2.sharma, bhanuprakash.modem, javierm, jose.souza, lyude,
	hbh25y, arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime,
	swboyd, christophe.jaillet, quic_sbillaka, johan+linaro,
	dianders, marex, quic_jesszhan, bjorn.andersson, abhinavk,
	seanpaul

On Wed, 18 Jan 2023 at 21:30, Mark Yacoub <markyacoub@chromium.org> wrote:
>
> From: Sean Paul <seanpaul@chromium.org>
>
> This patch adds the register ranges required for HDCP key injection and
> HDCP TrustZone interaction as described in the dt-bindings for the
> sc7180 dp controller. Now that these are supported, change the
> compatible string to "dp-hdcp".

No change in compatibles, so patch description should be updated.

>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-15-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-14-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-14-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-14-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-10-sean@poorly.run #v5

Again, this probably belongs to a cover letter

>
> Changes in v3:
> -Split off into a new patch containing just the dts change (Stephen)
> -Add hdcp compatible string (Stephen)
> Changes in v4:
> -Rebase on Bjorn's multi-dp patchset
> Changes in v5:
> -Put the tz register offsets in trogdor dtsi (Rob C)
> Changes in v6:
> -Rebased: Removed modifications in sc7180.dtsi as it's already upstream
>
> ---
>  arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
> index 178efaaa89ec..6f6fe5cb6563 100644
> --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
> @@ -817,6 +817,14 @@ &mdss_dp {
>         pinctrl-names = "default";
>         pinctrl-0 = <&dp_hot_plug_det>;
>         data-lanes = <0 1>;
> +
> +       reg = <0 0x0ae90000 0 0x200>,
> +             <0 0x0ae90200 0 0x200>,
> +             <0 0x0ae90400 0 0xc00>,
> +             <0 0x0ae91000 0 0x400>,
> +             <0 0x0ae91400 0 0x400>,
> +             <0 0x0aed1000 0 0x175>,
> +             <0 0x0aee1000 0 0x2c>;

Is there any reason for adding these to the -trogdor instead of adding
them to the base dtsi? Does hardware differ between the sc7180.dtsi
and sc7180-trogdor.dtsi?

>  };
>
>  &pm6150_adc {
> --
> 2.39.0.246.g2a6d74b583-goog
>


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller
  2023-01-18 19:30 ` [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller Mark Yacoub
  2023-01-19  1:32   ` Abhinav Kumar
  2023-01-19  8:40   ` Dmitry Baryshkov
@ 2023-01-19 10:35   ` Krzysztof Kozlowski
  2023-01-20 15:54     ` Sean Paul
  2 siblings, 1 reply; 38+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-19 10:35 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, tzimmermann, ville.syrjala, stanislav.lisovskiy,
	matthew.d.roper, imre.deak, lucas.demarchi, manasi.d.navare,
	swati2.sharma, bhanuprakash.modem, javierm, jose.souza, lyude,
	hbh25y, arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime,
	swboyd, christophe.jaillet, quic_sbillaka, johan+linaro,
	dianders, marex, quic_jesszhan, bjorn.andersson, abhinavk,
	seanpaul

On 18/01/2023 20:30, Mark Yacoub wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch adds the register ranges required for HDCP key injection and

Do not use "This commit/patch".
https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95

This applies to all your patches. Fix it everywhere.

> HDCP TrustZone interaction as described in the dt-bindings for the
> sc7180 dp controller. Now that these are supported, change the
> compatible string to "dp-hdcp".

What does it mean? Where do you do it?

> 
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-15-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-14-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-14-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-14-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-10-sean@poorly.run #v5

Drop the links.

> 
> Changes in v3:
> -Split off into a new patch containing just the dts change (Stephen)
> -Add hdcp compatible string (Stephen)
> Changes in v4:
> -Rebase on Bjorn's multi-dp patchset
> Changes in v5:
> -Put the tz register offsets in trogdor dtsi (Rob C)
> Changes in v6:
> -Rebased: Removed modifications in sc7180.dtsi as it's already upstream
> 
> ---

Changelog after --- .

>  arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
  2023-01-18 19:30 ` [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check() Mark Yacoub
@ 2023-01-19 10:37   ` Krzysztof Kozlowski
  2023-01-20 15:32     ` Sean Paul
  2023-01-19 11:41   ` Dmitry Baryshkov
  2023-03-10  5:30   ` [Intel-gfx] " Kandpal, Suraj
  2 siblings, 1 reply; 38+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-19 10:37 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, dmitry.baryshkov, sean, airlied,
	daniel, robh+dt, krzysztof.kozlowski+dt, agross, andersson,
	konrad.dybcio, jani.nikula, joonas.lahtinen, rodrigo.vivi,
	tvrtko.ursulin, tzimmermann, ville.syrjala, stanislav.lisovskiy,
	matthew.d.roper, imre.deak, lucas.demarchi, manasi.d.navare,
	swati2.sharma, bhanuprakash.modem, javierm, jose.souza, lyude,
	hbh25y, arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime,
	swboyd, christophe.jaillet, quic_sbillaka, johan+linaro,
	dianders, marex, quic_jesszhan, bjorn.andersson, abhinavk,
	seanpaul, Jani Nikula

On 18/01/2023 20:30, Mark Yacoub wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch moves the hdcp atomic check from i915 to drm_hdcp so other
> drivers can use it. No functional changes, just cleaned up some of the
> code when moving it over.
> 
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Reviewed-by: Abhinav Kumar <abhinavk@codeaurora.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-2-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-2-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-2-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-2-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-2-sean@poorly.run #v5

It seems all your previous versions were sent not to correct people and
lists. Therefore we see it for the first time even though it is v6! It's
not the first such weird CC list in chromium, so maybe your
organisational process could be improved? Not only for you but for
colleagues as well, so you all start using get_maintainers.pl on newest
kernel (not something ancient)?

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 10/10] drm/msm: Implement HDCP 1.x using the new drm HDCP helpers
  2023-01-18 19:30 ` [PATCH v6 10/10] drm/msm: Implement HDCP 1.x using the new drm HDCP helpers Mark Yacoub
@ 2023-01-19 11:35   ` Dmitry Baryshkov
  0 siblings, 0 replies; 38+ messages in thread
From: Dmitry Baryshkov @ 2023-01-19 11:35 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, sean, airlied, daniel, robh+dt,
	krzysztof.kozlowski+dt, agross, andersson, konrad.dybcio,
	jani.nikula, joonas.lahtinen, rodrigo.vivi, tvrtko.ursulin,
	tzimmermann, ville.syrjala, stanislav.lisovskiy, matthew.d.roper,
	imre.deak, lucas.demarchi, manasi.d.navare, swati2.sharma,
	bhanuprakash.modem, javierm, jose.souza, lyude, hbh25y,
	arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime, swboyd,
	christophe.jaillet, quic_sbillaka, johan+linaro, dianders, marex,
	quic_jesszhan, bjorn.andersson, abhinavk, seanpaul

On 18/01/2023 21:30, Mark Yacoub wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch adds HDCP 1.x support to msm DP connectors using the new HDCP
> helpers.
> 
> Cc: Stephen Boyd <swboyd@chromium.org>
> Cc: Abhinav Kumar <abhinavk@codeaurora.org>
> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-15-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-14-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-15-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-15-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-11-sean@poorly.run #v5
> 
> Changes in v2:
> -Squash [1] into this patch with the following changes (Stephen)
>    -Update the sc7180 dtsi file
>    -Remove resource names and just use index (Stephen)
> Changes in v3:
> -Split out the dtsi change from v2 (Stephen)
> -Fix set-but-unused warning identified by 0-day
> -Fix up a couple of style nits (Stephen)
> -Store HDCP key directly in dp_hdcp struct (Stephen)
> -Remove wmb in HDCP key initialization, move an_seed (Stephen)
> -Use FIELD_PREP for bstatus/bcaps (Stephen)
> -#define read_poll_timeout values (Stephen)
> -Remove unnecessary parentheses in dp_hdcp_store_ksv_fifo (Stephen)
> -Add compatible string for hdcp (Stephen)
> -Rename dp_hdcp_write_* functions (Abhinav)
> -Add 1us delay between An reads (Abhinav)
> -Delete unused dp_hdcp_read_* functions
> Changes in v4:
> -Rebase on Bjorn's multi-dp patchset
> Changes in v5:
> -Change return check of drm_hdcp_helper_initialize_dp() (Stephen)
> Changes in v6:
> -Change the tracking of the state from connector state to bridge as
> state as drm_connector_state is no longer tracked and the functionality
> has moved to msm_dp_bridge
> 
> [1] https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-14-sean@poorly.run
> 
> ---
>   drivers/gpu/drm/msm/Kconfig         |   1 +
>   drivers/gpu/drm/msm/Makefile        |   1 +
>   drivers/gpu/drm/msm/dp/dp_debug.c   |  48 ++-
>   drivers/gpu/drm/msm/dp/dp_debug.h   |   6 +-
>   drivers/gpu/drm/msm/dp/dp_display.c |  52 +++-
>   drivers/gpu/drm/msm/dp/dp_display.h |   5 +
>   drivers/gpu/drm/msm/dp/dp_drm.c     | 108 ++++++-
>   drivers/gpu/drm/msm/dp/dp_drm.h     |  16 +-
>   drivers/gpu/drm/msm/dp/dp_hdcp.c    | 456 ++++++++++++++++++++++++++++
>   drivers/gpu/drm/msm/dp/dp_hdcp.h    |  29 ++
>   drivers/gpu/drm/msm/dp/dp_parser.c  |  20 +-
>   drivers/gpu/drm/msm/dp/dp_parser.h  |   4 +
>   drivers/gpu/drm/msm/dp/dp_reg.h     |  32 +-
>   drivers/gpu/drm/msm/msm_atomic.c    |  15 +
>   14 files changed, 772 insertions(+), 21 deletions(-)
>   create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.c
>   create mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp.h
> 
> diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
> index 61ca0c0757bc..9d9a66d9156c 100644
> --- a/drivers/gpu/drm/msm/Kconfig
> +++ b/drivers/gpu/drm/msm/Kconfig
> @@ -15,6 +15,7 @@ config DRM_MSM
>   	select REGULATOR
>   	select DRM_DP_AUX_BUS
>   	select DRM_DISPLAY_DP_HELPER
> +	select DRM_DISPLAY_HDCP_HELPER
>   	select DRM_DISPLAY_HELPER
>   	select DRM_KMS_HELPER
>   	select DRM_PANEL

Note to myself: split this long list of selects into a per-driver list.

> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index 7274c41228ed..a73e7b858af2 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -122,6 +122,7 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
>   	dp/dp_ctrl.o \
>   	dp/dp_display.o \
>   	dp/dp_drm.o \
> +	dp/dp_hdcp.o \
>   	dp/dp_hpd.o \
>   	dp/dp_link.o \
>   	dp/dp_panel.o \
> diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
> index 5e35033ba3e4..e97d27edbb13 100644
> --- a/drivers/gpu/drm/msm/dp/dp_debug.c
> +++ b/drivers/gpu/drm/msm/dp/dp_debug.c
> @@ -8,6 +8,7 @@
>   #include <linux/debugfs.h>
>   #include <drm/drm_connector.h>
>   #include <drm/drm_file.h>
> +#include <drm/display/drm_hdcp_helper.h>
>   
>   #include "dp_parser.h"
>   #include "dp_catalog.h"
> @@ -15,6 +16,7 @@
>   #include "dp_ctrl.h"
>   #include "dp_debug.h"
>   #include "dp_display.h"
> +#include "dp_hdcp.h"
>   
>   #define DEBUG_NAME "msm_dp"
>   
> @@ -25,6 +27,7 @@ struct dp_debug_private {
>   	struct dp_link *link;
>   	struct dp_panel *panel;
>   	struct drm_connector *connector;
> +	struct dp_hdcp *hdcp;
>   	struct device *dev;
>   	struct drm_device *drm_dev;
>   
> @@ -196,6 +199,35 @@ static int dp_test_active_open(struct inode *inode,
>   			inode->i_private);
>   }
>   
> +static ssize_t dp_hdcp_key_write(struct file *file, const char __user *ubuf,
> +				 size_t len, loff_t *offp)
> +{
> +	char *input_buffer;
> +	int ret;
> +	struct dp_debug_private *debug = file->private_data;
> +
> +	if (len != (DRM_HDCP_KSV_LEN + DP_HDCP_NUM_KEYS * DP_HDCP_KEY_LEN))
> +		return -EINVAL;
> +
> +	if (!debug->hdcp)
> +		return -ENOENT;
> +
> +	input_buffer = memdup_user_nul(ubuf, len);
> +	if (IS_ERR(input_buffer))
> +		return PTR_ERR(input_buffer);
> +
> +	ret = dp_hdcp_ingest_key(debug->hdcp, input_buffer, len);
> +
> +	kfree(input_buffer);
> +	if (ret < 0) {
> +		DRM_ERROR("Could not ingest HDCP key, ret=%d\n", ret);
> +		return ret;
> +	}
> +
> +	*offp += len;
> +	return len;
> +}
> +
>   static const struct file_operations test_active_fops = {
>   	.owner = THIS_MODULE,
>   	.open = dp_test_active_open,
> @@ -205,6 +237,12 @@ static const struct file_operations test_active_fops = {
>   	.write = dp_test_active_write
>   };
>   
> +static const struct file_operations dp_hdcp_key_fops = {
> +	.owner = THIS_MODULE,
> +	.open = simple_open,
> +	.write = dp_hdcp_key_write,
> +};
> +
>   static void dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor)
>   {
>   	char path[64];
> @@ -229,11 +267,16 @@ static void dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor)
>   	debugfs_create_file("msm_dp_test_type", 0444,
>   			debug->root,
>   			debug, &dp_test_type_fops);
> +
> +	debugfs_create_file("msm_dp_hdcp_key", 0222, minor->debugfs_root, debug,
> +			    &dp_hdcp_key_fops);

Can we have a generic hdcp_key file instead? This can be usefull to 
other DRM drivers too.

Also, which DP instance will use this key? There can be several DP 
instances being used by the same MSM DRM device.

>   }
>   
>   struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
> -		struct dp_usbpd *usbpd, struct dp_link *link,
> -		struct drm_connector *connector, struct drm_minor *minor)
> +			      struct dp_usbpd *usbpd, struct dp_link *link,
> +			      struct dp_hdcp *hdcp,
> +			      struct drm_connector *connector,
> +			      struct drm_minor *minor)

A mixture of indentation and functional changes. Please don't do this.

>   {
>   	struct dp_debug_private *debug;
>   	struct dp_debug *dp_debug;
> @@ -255,6 +298,7 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
>   	debug->usbpd = usbpd;
>   	debug->link = link;
>   	debug->panel = panel;
> +	debug->hdcp = hdcp;
>   	debug->dev = dev;
>   	debug->drm_dev = minor->dev;
>   	debug->connector = connector;
> diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h
> index 8c0d0b5178fd..55ab008876e7 100644
> --- a/drivers/gpu/drm/msm/dp/dp_debug.h
> +++ b/drivers/gpu/drm/msm/dp/dp_debug.h
> @@ -6,6 +6,7 @@
>   #ifndef _DP_DEBUG_H_
>   #define _DP_DEBUG_H_
>   
> +#include "dp_hdcp.h"
>   #include "dp_panel.h"
>   #include "dp_link.h"
>   
> @@ -43,7 +44,7 @@ struct dp_debug {
>    */
>   struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
>   		struct dp_usbpd *usbpd, struct dp_link *link,
> -		struct drm_connector *connector,
> +		struct dp_hdcp *hdcp, struct drm_connector *connector,

If it goes to a separate line, it will be better.

>   		struct drm_minor *minor);
>   
>   /**
> @@ -60,7 +61,8 @@ void dp_debug_put(struct dp_debug *dp_debug);
>   static inline
>   struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
>   		struct dp_usbpd *usbpd, struct dp_link *link,
> -		struct drm_connector *connector, struct drm_minor *minor)
> +		struct dp_hdcp *hdcp, struct drm_connector *connector,
> +		struct drm_minor *minor)
>   {
>   	return ERR_PTR(-EINVAL);
>   }
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> index a49f6dbbe888..33e82d97b714 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> @@ -27,6 +27,7 @@
>   #include "dp_drm.h"
>   #include "dp_audio.h"
>   #include "dp_debug.h"
> +#include "dp_hdcp.h"
>   
>   #define HPD_STRING_SIZE 30
>   
> @@ -97,6 +98,7 @@ struct dp_display_private {
>   	struct dp_panel   *panel;
>   	struct dp_ctrl    *ctrl;
>   	struct dp_debug   *debug;
> +	struct dp_hdcp    *hdcp;
>   
>   	struct dp_usbpd_cb usbpd_cb;
>   	struct dp_display_mode dp_mode;
> @@ -187,6 +189,20 @@ static struct dp_display_private *dev_get_dp_display_private(struct device *dev)
>   	return container_of(dp, struct dp_display_private, dp_display);
>   }
>   
> +struct dp_hdcp *dp_display_connector_to_hdcp(struct drm_connector *connector)
> +{
> +	struct dp_display_private *dp;
> +
> +	struct msm_dp *dp_display =
> +		msm_bridge_from_connector(connector)->dp_display;
> +	if (!dp_display)
> +		return NULL;
> +
> +	dp = container_of(dp_display, struct dp_display_private, dp_display);
> +
> +	return dp->hdcp;
> +}
> +
>   static int dp_add_event(struct dp_display_private *dp_priv, u32 event,
>   						u32 data, u32 delay)
>   {
> @@ -740,6 +756,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
>   static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
>   {
>   	dp_debug_put(dp->debug);
> +	dp_hdcp_put(dp->hdcp);
>   	dp_audio_put(dp->audio);
>   	dp_panel_put(dp->panel);
>   	dp_aux_put(dp->aux);
> @@ -840,8 +857,18 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
>   	dp->ctrl->wide_bus_en = dp->wide_bus_en;
>   	dp->catalog->wide_bus_en = dp->wide_bus_en;
>   
> +	dp->hdcp = dp_hdcp_get(dp->parser, dp->aux);
> +	if (IS_ERR(dp->hdcp)) {
> +		rc = PTR_ERR(dp->hdcp);
> +		DRM_ERROR("failed to initialize hdcp, rc = %d\n", rc);
> +		dp->hdcp = NULL;
> +		goto error_hdcp;
> +	}
> +
>   	return rc;
>   
> +error_hdcp:
> +	dp_audio_put(dp->audio);
>   error_ctrl:
>   	dp_panel_put(dp->panel);
>   error_link:
> @@ -953,6 +980,16 @@ int dp_display_set_plugged_cb(struct msm_dp *dp_display,
>   	return 0;
>   }
>   
> +void dp_display_hdcp_commit(struct msm_dp *dp, struct drm_atomic_state *state)
> +{
> +	struct dp_display_private *dp_display;
> +
> +	dp_display = container_of(dp, struct dp_display_private, dp_display);
> +
> +	if (dp_display->hdcp)
> +		dp_hdcp_commit(dp_display->hdcp, state);
> +}

Do you really need to pass the whole drm_atomic_state to hdcp_commit?

> +
>   /**
>    * dp_bridge_mode_valid - callback to determine if specified mode is valid
>    * @bridge: Pointer to drm bridge structure
> @@ -1518,9 +1555,8 @@ void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor)
>   	dp = container_of(dp_display, struct dp_display_private, dp_display);
>   	dev = &dp->pdev->dev;
>   
> -	dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
> -					dp->link, dp->dp_display.connector,
> -					minor);
> +	dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd, dp->link, dp->hdcp,
> +				 dp->dp_display.connector, minor);

Again, identnation squashed together with functional changes.

>   	if (IS_ERR(dp->debug)) {
>   		rc = PTR_ERR(dp->debug);
>   		DRM_ERROR("failed to initialize debug, rc = %d\n", rc);
> @@ -1600,6 +1636,7 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
>   int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
>   			struct drm_encoder *encoder)
>   {
> +	struct dp_display_private *dp_display_priv;
>   	struct msm_drm_private *priv;
>   	struct dp_display_private *dp_priv;
>   	int ret;
> @@ -1607,6 +1644,9 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
>   	if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev))
>   		return -EINVAL;
>   
> +	dp_display_priv =
> +		container_of(dp_display, struct dp_display_private, dp_display);
> +
>   	priv = dev->dev_private;
>   
>   	if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) {
> @@ -1650,6 +1690,12 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
>   
>   	dp_priv->panel->connector = dp_display->connector;
>   
> +	ret = dp_hdcp_attach(dp_display_priv->hdcp, dp_display->connector);
> +	if (ret) {
> +		DRM_ERROR("Failed to attach hdcp, ret=%d\n", ret);
> +		return ret;
> +	}
> +
>   	return 0;
>   }
>   
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
> index dcedf021f7fe..5d0bb1cacced 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.h
> +++ b/drivers/gpu/drm/msm/dp/dp_display.h
> @@ -30,8 +30,13 @@ struct msm_dp {
>   	struct dp_audio *dp_audio;
>   };
>   
> +struct drm_atomic_state;
> +
>   int dp_display_set_plugged_cb(struct msm_dp *dp_display,
>   		hdmi_codec_plugged_cb fn, struct device *codec_dev);
> +struct dp_hdcp *dp_display_connector_to_hdcp(struct drm_connector *connector);
> +void dp_display_hdcp_commit(struct msm_dp *dp_display,
> +			    struct drm_atomic_state *state);
>   int dp_display_get_modes(struct msm_dp *dp_display);
>   int dp_display_request_irq(struct msm_dp *dp_display);
>   bool dp_display_check_video_test(struct msm_dp *dp_display);
> diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
> index 6db82f9b03af..6cb98d4ad2d7 100644
> --- a/drivers/gpu/drm/msm/dp/dp_drm.c
> +++ b/drivers/gpu/drm/msm/dp/dp_drm.c
> @@ -3,15 +3,20 @@
>    * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
>    */
>   
> +#include "drm/drm_connector.h"
> +#include "linux/slab.h"

I hope somebody is kidding here.

>   #include <drm/drm_atomic_helper.h>
>   #include <drm/drm_atomic.h>
>   #include <drm/drm_bridge.h>
>   #include <drm/drm_bridge_connector.h>
> +#include <drm/drm_bridge_connector.h>

Why do you need a duplicate here?

>   #include <drm/drm_crtc.h>
> +#include <drm/display/drm_hdcp_helper.h>
>   
>   #include "msm_drv.h"
>   #include "msm_kms.h"
>   #include "dp_drm.h"
> +#include "dp_hdcp.h"
>   
>   /**
>    * dp_bridge_detect - callback to determine if connector is connected
> @@ -37,6 +42,7 @@ static int dp_bridge_atomic_check(struct drm_bridge *bridge,
>   			    struct drm_connector_state *conn_state)
>   {
>   	struct msm_dp *dp;
> +	struct dp_bridge_state *dp_bridge_state;
>   
>   	dp = to_dp_bridge(bridge)->dp_display;
>   
> @@ -54,8 +60,15 @@ static int dp_bridge_atomic_check(struct drm_bridge *bridge,
>   	 * disabled by the hardware and thus all access to it should be forbidden.
>   	 * After that this piece of code can be removed.
>   	 */
> -	if (bridge->ops & DRM_BRIDGE_OP_HPD)
> -		return (dp->is_connected) ? 0 : -ENOTCONN;
> +	if (bridge->ops & DRM_BRIDGE_OP_HPD && !dp->is_connected)
> +		return -ENOTCONN;
> +
> +	dp_bridge_state = to_dp_bridge_state(bridge_state);
> +	if (!dp_bridge_state)
> +		return 0;

to_dp_bridge_state can never return NULL if given valid bridge state.

> +
> +	dp_bridge_state->hdcp_transition =
> +		drm_hdcp_atomic_check(conn_state->connector, conn_state->state);
>   
>   	return 0;
>   }
> @@ -90,20 +103,93 @@ static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *
>   	return rc;
>   }
>   
> +static struct drm_bridge_state *
> +dp_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge)
> +{
> +	struct dp_bridge_state *dp_bridge_state;
> +
> +	if (WARN_ON(!bridge->base.state))
> +		return NULL;
> +
> +	dp_bridge_state = kzalloc(sizeof(*dp_bridge_state), GFP_KERNEL);
> +	if (!dp_bridge_state)
> +		return NULL;
> +
> +	dp_bridge_state->hdcp_transition = false;
> +	to_dp_bridge(bridge)->state = dp_bridge_state;
> +
> +	__drm_atomic_helper_bridge_duplicate_state(bridge,
> +						   &dp_bridge_state->base);
> +	return &dp_bridge_state->base;
> +}
> +
>   static const struct drm_bridge_funcs dp_bridge_ops = {
> -	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> -	.atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> -	.atomic_reset           = drm_atomic_helper_bridge_reset,
> -	.enable       = dp_bridge_enable,
> -	.disable      = dp_bridge_disable,
> +	.atomic_duplicate_state = dp_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> +	.atomic_reset = drm_atomic_helper_bridge_reset,
> +	.enable = dp_bridge_enable,
> +	.disable = dp_bridge_disable,
>   	.post_disable = dp_bridge_post_disable,
> -	.mode_set     = dp_bridge_mode_set,
> -	.mode_valid   = dp_bridge_mode_valid,
> -	.get_modes    = dp_bridge_get_modes,
> -	.detect       = dp_bridge_detect,
> +	.mode_set = dp_bridge_mode_set,
> +	.mode_valid = dp_bridge_mode_valid,
> +	.get_modes = dp_bridge_get_modes,
> +	.detect = dp_bridge_detect,

Indentation changes plus functional changes. Again.

>   	.atomic_check = dp_bridge_atomic_check,
>   };
>   
> +struct msm_dp_bridge *msm_bridge_from_connector(struct drm_connector *connector)
> +{
> +	struct msm_drm_private *priv = connector->dev->dev_private;
> +	int i = 0;
> +	if (!priv)
> +		return NULL;
> +
> +	for (i = 0; i < priv->num_bridges; i++) {
> +		struct msm_dp *dp;
> +		struct drm_connector *bridge_connector;
> +		struct drm_bridge *bridge = priv->bridges[i];

Ideally priv->bridges should go away. The only actual use case of them 
was to call drm_bridge_remove, which will go away once we switch to 
devm_drm_bridge_add().

> +		if (!bridge)
> +			continue;
> +
> +		dp = to_dp_bridge(bridge)->dp_display;
> +		if (!dp)
> +			continue;

Big fat no. The priv->bridges[i] can be e.g. HDMI bridge or DSI bridge. 
Here you are converting it to the dp_bridge without _any_ checks. This 
is a fair and straightforward way to kernel crashes. Was this patchset 
ever tested on anything other than the laptop?

> +
> +		bridge_connector = dp->connector;
> +		if (bridge_connector == connector)
> +			return to_dp_bridge(bridge);
> +	}
> +
> +	return NULL;
> +}
> +
> +bool dp_drm_is_connector_msm_dp(struct drm_connector *connector)
> +{
> +	struct msm_dp_bridge *dp_bridge = msm_bridge_from_connector(connector);
> +	if (!dp_bridge)
> +		return false;
> +
> +	if (dp_bridge->bridge.funcs == &dp_bridge_ops)
> +		return true;
> +
> +	return false;
> +}
> +
> +void dp_drm_atomic_commit(struct drm_connector *connector,
> +			  struct drm_connector_state *conn_state,
> +			  struct drm_atomic_state *state)
> +{
> +	struct msm_dp_bridge *bridge = msm_bridge_from_connector(connector);
> +	if (!bridge)
> +		return;
> +
> +	if (!bridge->state || !bridge->state->hdcp_transition)
> +		return;
> +
> +	if (bridge->dp_display)
> +		dp_display_hdcp_commit(bridge->dp_display, state);
> +}
> +
>   struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
>   			struct drm_encoder *encoder)
>   {
> diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
> index 82035dbb0578..d97dcc0f9458 100644
> --- a/drivers/gpu/drm/msm/dp/dp_drm.h
> +++ b/drivers/gpu/drm/msm/dp/dp_drm.h
> @@ -8,21 +8,35 @@
>   
>   #include <linux/types.h>
>   #include <drm/drm_bridge.h>
> +#include <drm/display/drm_hdcp_helper.h>
>   
>   #include "msm_drv.h"
>   #include "dp_display.h"
>   
> +struct dp_bridge_state {
> +	struct drm_bridge_state base;
> +	bool hdcp_transition;
> +};
> +#define to_dp_bridge_state(x) container_of(x, struct dp_bridge_state, base)
> +
>   struct msm_dp_bridge {
>   	struct drm_bridge bridge;
> +	struct dp_bridge_state *state;
>   	struct msm_dp *dp_display;
>   };
> -
>   #define to_dp_bridge(x)     container_of((x), struct msm_dp_bridge, bridge)
>   
>   struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder);
>   struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
>   			struct drm_encoder *encoder);
>   
> +bool dp_drm_is_connector_msm_dp(struct drm_connector *connector);
> +struct msm_dp_bridge *
> +msm_bridge_from_connector(struct drm_connector *connector);
> +void dp_drm_atomic_commit(struct drm_connector *connector,
> +			  struct drm_connector_state *conn_state,
> +			  struct drm_atomic_state *state);
> +
>   void dp_bridge_enable(struct drm_bridge *drm_bridge);
>   void dp_bridge_disable(struct drm_bridge *drm_bridge);
>   void dp_bridge_post_disable(struct drm_bridge *drm_bridge);
> diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp.c b/drivers/gpu/drm/msm/dp/dp_hdcp.c
> new file mode 100644
> index 000000000000..4408aa5eb607
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/dp/dp_hdcp.c
> @@ -0,0 +1,456 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright (C) 2021 Google, Inc.
> + *
> + * Authors:
> + * Sean Paul <seanpaul@chromium.org>
> + */
> +
> +#include "dp_display.h"
> +#include "dp_drm.h"
> +#include "dp_hdcp.h"
> +#include "dp_reg.h"
> +
> +#include <drm/drm_connector.h>
> +#include <drm/drm_device.h>
> +#include <drm/display/drm_dp_helper.h>
> +#include <drm/display/drm_hdcp_helper.h>
> +#include <drm/drm_print.h>
> +
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/iopoll.h>
> +#include <linux/mutex.h>
> +#include <linux/random.h>
> +#include <linux/slab.h>
> +
> +/* Offsets based on hdcp_ksv mmio */
> +#define DP_HDCP_KSV_AN_LSB 0x0
> +#define DP_HDCP_KSV_AN_MSB 0x4
> +#define DP_HDCP_KSV_AKSV_MSB 0x1D8
> +#define DP_HDCP_KSV_AKSV_LSB 0x1DC
> +
> +/* Key offsets based on hdcp_key mmio */
> +#define DP_HDCP_KEY_BASE 0x30
> +#define DP_HDCP_KEY_MSB(x) (DP_HDCP_KEY_BASE + (x * 8))
> +#define DP_HDCP_KEY_LSB(x) (DP_HDCP_KEY_MSB(x) + 4)
> +#define DP_HDCP_KEY_VALID 0x170
> +#define DP_HDCP_SW_KEY_VALID BIT(0)
> +
> +/* Timeouts */
> +#define DP_KEYS_VALID_SLEEP_US (20 * 1000)
> +#define DP_KEYS_VALID_TIMEOUT_US (100 * 1000)
> +#define DP_AN_READY_SLEEP_US 100
> +#define DP_AN_READY_TIMEOUT_US (10 * 1000)
> +#define DP_R0_READY_SLEEP_US 100
> +#define DP_R0_READY_TIMEOUT_US (10 * 1000)
> +#define DP_RI_MATCH_SLEEP_US (20 * 1000)
> +#define DP_RI_MATCH_TIMEOUT_US (100 * 1000)
> +#define DP_KSV_WRITTEN_SLEEP_US 100
> +#define DP_KSV_WRITTEN_TIMEOUT_US (100 * 1000)
> +#define DP_SHA_COMPUTATION_SLEEP_US 100
> +#define DP_SHA_COMPUTATION_TIMEOUT_US (100 * 1000)
> +#define DP_AN_READ_DELAY_US 1
> +
> +/*
> + * dp_hdcp_key - structure which contains an HDCP key set
> + * @ksv: The key selection vector
> + * @keys: Contains 40 keys
> + */
> +struct dp_hdcp_key {
> +	struct drm_hdcp_ksv ksv;
> +	union {
> +		u32 words[2];
> +		u8 bytes[DP_HDCP_KEY_LEN];
> +	} keys[DP_HDCP_NUM_KEYS];
> +	bool valid;
> +};
> +
> +struct dp_hdcp {
> +	struct drm_device *dev;
> +	struct drm_connector *connector;
> +
> +	struct drm_dp_aux *aux;
> +	struct dp_parser *parser;
> +
> +	struct drm_hdcp_helper_data *helper_data;
> +
> +	struct mutex key_lock;
> +	struct dp_hdcp_key key;
> +};
> +
> +static inline void dp_hdcp_write_ahb(struct dp_hdcp *hdcp, u32 offset, u32 val)
> +{
> +	writel(val, hdcp->parser->io.dp_controller.ahb.base + offset);
> +}
> +
> +static inline u32 dp_hdcp_read_ahb(struct dp_hdcp *hdcp, u32 offset)
> +{
> +	return readl(hdcp->parser->io.dp_controller.ahb.base + offset);
> +}
> +
> +static inline void dp_hdcp_write_aux(struct dp_hdcp *hdcp, u32 offset, u32 val)
> +{
> +	writel(val, hdcp->parser->io.dp_controller.aux.base + offset);
> +}
> +
> +static inline u32 dp_hdcp_read_aux(struct dp_hdcp *hdcp, u32 offset)
> +{
> +	return readl(hdcp->parser->io.dp_controller.aux.base + offset);
> +}
> +
> +static inline void dp_hdcp_write_link(struct dp_hdcp *hdcp, u32 offset, u32 val)
> +{
> +	writel(val, hdcp->parser->io.dp_controller.link.base + offset);
> +}
> +
> +static inline u32 dp_hdcp_read_link(struct dp_hdcp *hdcp, u32 offset)
> +{
> +	return readl(hdcp->parser->io.dp_controller.link.base + offset);
> +}
> +
> +static inline void dp_hdcp_write_key(struct dp_hdcp *hdcp, u32 offset, u32 val)
> +{
> +	writel(val, hdcp->parser->io.dp_controller.hdcp_key.base + offset);
> +}
> +
> +static inline void dp_hdcp_write_tz_hlos(struct dp_hdcp *hdcp, u32 offset,
> +					 u32 val)
> +{
> +	writel(val, hdcp->parser->io.dp_controller.hdcp_tz.base + offset);
> +}
> +
> +int dp_hdcp_ingest_key(struct dp_hdcp *hdcp, const u8 *raw_key, int raw_len)
> +{
> +	unsigned int ksv_weight;
> +	int i, ret = 0;
> +
> +	if (raw_len !=
> +	    (DRM_HDCP_KSV_LEN + DP_HDCP_NUM_KEYS * DP_HDCP_KEY_LEN)) {
> +		DRM_ERROR(
> +			"Invalid HDCP key length expected=%d actual=%d\n",
> +			(DRM_HDCP_KSV_LEN + DP_HDCP_NUM_KEYS * DP_HDCP_KEY_LEN),
> +			raw_len);
> +		return -EINVAL;
> +	}
> +
> +	mutex_lock(&hdcp->key_lock);
> +
> +	memcpy(hdcp->key.ksv.bytes, raw_key, DRM_HDCP_KSV_LEN);
> +	ksv_weight = hweight32(hdcp->key.ksv.words[0]) +
> +		     hweight32(hdcp->key.ksv.words[1]);
> +	if (ksv_weight != 20) {
> +		DRM_ERROR("Invalid ksv weight, expected=20 actual=%d\n",
> +			  ksv_weight);
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	raw_key += DRM_HDCP_KSV_LEN;
> +	for (i = 0; i < DP_HDCP_NUM_KEYS; i++) {
> +		memcpy(hdcp->key.keys[i].bytes, raw_key, DP_HDCP_KEY_LEN);
> +		raw_key += DP_HDCP_KEY_LEN;
> +	}
> +
> +	DRM_DEBUG_DRIVER("Successfully ingested HDCP key\n");
> +	hdcp->key.valid = true;
> +
> +out:
> +	mutex_unlock(&hdcp->key_lock);
> +	return ret;
> +}
> +
> +static bool dp_hdcp_are_keys_valid(struct drm_connector *connector)
> +{
> +	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
> +	u32 val;
> +
> +	val = dp_hdcp_read_ahb(hdcp, DP_HDCP_STATUS);
> +	return FIELD_GET(DP_HDCP_KEY_STATUS, val) == DP_HDCP_KEY_STATUS_VALID;
> +}
> +
> +static int dp_hdcp_load_keys(struct drm_connector *connector)
> +{
> +	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
> +	int i, ret = 0;
> +	u64 an_seed = get_random_u64();
> +
> +	mutex_lock(&hdcp->key_lock);
> +
> +	if (!hdcp->key.valid) {
> +		ret = -ENOENT;
> +		goto out;
> +	}
> +
> +	dp_hdcp_write_aux(hdcp, DP_HDCP_SW_LOWER_AKSV, hdcp->key.ksv.words[0]);
> +	dp_hdcp_write_aux(hdcp, DP_HDCP_SW_UPPER_AKSV, hdcp->key.ksv.words[1]);
> +
> +	for (i = 0; i < DP_HDCP_NUM_KEYS; i++) {
> +		dp_hdcp_write_key(hdcp, DP_HDCP_KEY_LSB(i),
> +				  hdcp->key.keys[i].words[0]);
> +		dp_hdcp_write_key(hdcp, DP_HDCP_KEY_MSB(i),
> +				  hdcp->key.keys[i].words[1]);
> +	}
> +
> +	dp_hdcp_write_key(hdcp, DP_HDCP_KEY_VALID, DP_HDCP_SW_KEY_VALID);
> +
> +	dp_hdcp_write_link(hdcp, DP_HDCP_ENTROPY_CTRL0,
> +			   FIELD_GET(GENMASK(31, 0), an_seed));
> +	dp_hdcp_write_link(hdcp, DP_HDCP_ENTROPY_CTRL1,
> +			   FIELD_GET(GENMASK_ULL(63, 32), an_seed));
> +
> +out:
> +	mutex_unlock(&hdcp->key_lock);
> +	return ret;
> +}
> +
> +static int dp_hdcp_hdcp2_capable(struct drm_connector *connector, bool *capable)
> +{
> +	*capable = false;
> +	return 0;
> +}
> +
> +static int dp_hdcp_hdcp1_read_an_aksv(struct drm_connector *connector, u32 *an,
> +				      u32 *aksv)
> +{
> +	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
> +	bool keys_valid;
> +	int ret;
> +	u32 val;
> +
> +	dp_hdcp_write_ahb(hdcp, DP_HDCP_CTRL, 1);
> +
> +	ret = read_poll_timeout(dp_hdcp_are_keys_valid, keys_valid, keys_valid,
> +				DP_KEYS_VALID_SLEEP_US,
> +				DP_KEYS_VALID_TIMEOUT_US, false, connector);
> +	if (ret) {
> +		drm_err(hdcp->dev, "HDCP keys invalid %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* Clear AInfo */
> +	dp_hdcp_write_aux(hdcp, DP_HDCP_RCVPORT_DATA4, 0);
> +
> +	aksv[0] = dp_hdcp_read_aux(hdcp, DP_HDCP_RCVPORT_DATA3);
> +	aksv[1] = GENMASK(7, 0) & dp_hdcp_read_aux(hdcp, DP_HDCP_RCVPORT_DATA4);
> +
> +	ret = read_poll_timeout(dp_hdcp_read_ahb, val,
> +				(val & DP_HDCP_AN_READY_MASK) ==
> +					DP_HDCP_AN_READY_MASK,
> +				DP_AN_READY_SLEEP_US, DP_AN_READY_TIMEOUT_US,
> +				false, hdcp, DP_HDCP_STATUS);
> +	if (ret) {
> +		drm_err(hdcp->dev, "AN failed to become ready %x/%d\n", val,
> +			ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * Get An from hardware, for unknown reasons we need to read the reg
> +	 * twice to get valid data.
> +	 */
> +	dp_hdcp_read_ahb(hdcp, DP_HDCP_RCVPORT_DATA5);
> +	an[0] = dp_hdcp_read_ahb(hdcp, DP_HDCP_RCVPORT_DATA5);
> +
> +	udelay(DP_AN_READ_DELAY_US);
> +
> +	dp_hdcp_read_ahb(hdcp, DP_HDCP_RCVPORT_DATA6);
> +	an[1] = dp_hdcp_read_ahb(hdcp, DP_HDCP_RCVPORT_DATA6);
> +
> +	return 0;
> +}
> +
> +static int dp_hdcp_hdcp1_store_receiver_info(struct drm_connector *connector,
> +					     u32 *ksv, u32 status, u8 bcaps,
> +					     bool is_repeater)
> +{
> +	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
> +	u32 val;
> +
> +	dp_hdcp_write_tz_hlos(hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0,
> +			      ksv[0]);
> +	dp_hdcp_write_tz_hlos(hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1,
> +			      ksv[1]);
> +
> +	val = FIELD_PREP(GENMASK(23, 8), status) |
> +	      FIELD_PREP(GENMASK(7, 0), bcaps);
> +
> +	dp_hdcp_write_tz_hlos(hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12,
> +			      val);
> +
> +	return 0;
> +}
> +
> +static int dp_hdcp_hdcp1_enable_encryption(struct drm_connector *connector)
> +{
> +	return 0;
> +}
> +
> +static int dp_hdcp_hdcp1_wait_for_r0(struct drm_connector *connector)
> +{
> +	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
> +	int ret;
> +	u32 val;
> +
> +	ret = read_poll_timeout(dp_hdcp_read_ahb, val, (val & DP_HDCP_R0_READY),
> +				DP_R0_READY_SLEEP_US, DP_R0_READY_TIMEOUT_US,
> +				false, hdcp, DP_HDCP_STATUS);
> +	if (ret) {
> +		drm_err(hdcp->dev, "HDCP R0 not ready %x/%d\n", val, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dp_hdcp_hdcp1_match_ri(struct drm_connector *connector, u32 ri_prime)
> +{
> +	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
> +	int ret;
> +	u32 val;
> +
> +	dp_hdcp_write_ahb(hdcp, DP_HDCP_RCVPORT_DATA2_0, ri_prime);
> +
> +	ret = read_poll_timeout(dp_hdcp_read_ahb, val, (val & DP_HDCP_RI_MATCH),
> +				DP_RI_MATCH_SLEEP_US, DP_RI_MATCH_TIMEOUT_US,
> +				false, hdcp, DP_HDCP_STATUS);
> +	if (ret) {
> +		drm_err(hdcp->dev,
> +			"Failed to match Ri and Ri` (%08x) %08x/%d\n", ri_prime,
> +			val, ret);
> +		return ret;
> +	}
> +	return 0;
> +}
> +
> +static int dp_hdcp_hdcp1_store_ksv_fifo(struct drm_connector *connector,
> +					u8 *ksv_fifo, u8 num_downstream,
> +					u8 *bstatus, u32 *vprime)
> +{
> +	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
> +	int num_bytes = num_downstream * DRM_HDCP_KSV_LEN;
> +	int ret, i;
> +	u32 val;
> +
> +	/* Reset the SHA computation block */
> +	dp_hdcp_write_tz_hlos(hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL,
> +			      DP_HDCP_SHA_CTRL_RESET);
> +	dp_hdcp_write_tz_hlos(hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, 0);
> +
> +	/*
> +	 * KSV info gets written a byte at a time in the same order it was
> +	 * received. Every 64 bytes, we need to wait for the SHA_BLOCK_DONE
> +	 * bit to be set in SHA_CTRL.
> +	 */
> +	for (i = 0; i < num_bytes; i++) {
> +		val = FIELD_PREP(DP_HDCP_SHA_DATA_MASK, ksv_fifo[i]);
> +
> +		if (i == (num_bytes - 1))
> +			val |= DP_HDCP_SHA_DATA_DONE;
> +
> +		dp_hdcp_write_tz_hlos(
> +			hdcp, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA, val);
> +
> +		if (((i + 1) % 64) != 0)
> +			continue;
> +
> +		ret = read_poll_timeout(dp_hdcp_read_ahb, val,
> +					(val & DP_HDCP_SHA_DONE),
> +					DP_KSV_WRITTEN_SLEEP_US,
> +					DP_KSV_WRITTEN_TIMEOUT_US, false, hdcp,
> +					DP_HDCP_SHA_STATUS);
> +		if (ret) {
> +			drm_err(hdcp->dev, "SHA block incomplete %d\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	ret = read_poll_timeout(dp_hdcp_read_ahb, val,
> +				(val & DP_HDCP_SHA_COMP_DONE),
> +				DP_SHA_COMPUTATION_SLEEP_US,
> +				DP_SHA_COMPUTATION_TIMEOUT_US, false, hdcp,
> +				DP_HDCP_SHA_STATUS);
> +	if (ret) {
> +		drm_err(hdcp->dev, "SHA computation incomplete %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dp_hdcp_hdcp1_disable(struct drm_connector *connector)
> +{
> +	struct dp_hdcp *hdcp = dp_display_connector_to_hdcp(connector);
> +	u32 val;
> +
> +	val = dp_hdcp_read_ahb(hdcp, REG_DP_SW_RESET);
> +	dp_hdcp_write_ahb(hdcp, REG_DP_SW_RESET, val | DP_HDCP_SW_RESET);
> +
> +	/* Disable encryption and disable the HDCP block */
> +	dp_hdcp_write_ahb(hdcp, DP_HDCP_CTRL, 0);
> +
> +	dp_hdcp_write_ahb(hdcp, REG_DP_SW_RESET, val);
> +
> +	return 0;
> +}
> +
> +void dp_hdcp_commit(struct dp_hdcp *hdcp, struct drm_atomic_state *state)
> +{
> +	drm_hdcp_helper_atomic_commit(hdcp->helper_data, state, NULL);
> +}
> +
> +static const struct drm_hdcp_helper_funcs dp_hdcp_funcs = {
> +	.are_keys_valid = dp_hdcp_are_keys_valid,
> +	.load_keys = dp_hdcp_load_keys,
> +	.hdcp2_capable = dp_hdcp_hdcp2_capable,
> +	.hdcp1_read_an_aksv = dp_hdcp_hdcp1_read_an_aksv,
> +	.hdcp1_store_receiver_info = dp_hdcp_hdcp1_store_receiver_info,
> +	.hdcp1_enable_encryption = dp_hdcp_hdcp1_enable_encryption,
> +	.hdcp1_wait_for_r0 = dp_hdcp_hdcp1_wait_for_r0,
> +	.hdcp1_match_ri = dp_hdcp_hdcp1_match_ri,
> +	.hdcp1_store_ksv_fifo = dp_hdcp_hdcp1_store_ksv_fifo,
> +	.hdcp1_disable = dp_hdcp_hdcp1_disable,
> +};
> +
> +int dp_hdcp_attach(struct dp_hdcp *hdcp, struct drm_connector *connector)
> +{
> +	struct drm_hdcp_helper_data *helper_data;
> +
> +	/* HDCP is not configured for this device */
> +	if (!hdcp->parser->io.dp_controller.hdcp_key.base)
> +		return 0;
> +
> +	helper_data = drm_hdcp_helper_initialize_dp(connector, hdcp->aux,
> +						    &dp_hdcp_funcs, false);
> +	if (IS_ERR(helper_data))
> +		return PTR_ERR(helper_data);
> +
> +	hdcp->dev = connector->dev;
> +	hdcp->connector = connector;
> +	hdcp->helper_data = helper_data;
> +
> +	return 0;
> +}
> +
> +struct dp_hdcp *dp_hdcp_get(struct dp_parser *parser, struct drm_dp_aux *aux)
> +{
> +	struct device *dev = &parser->pdev->dev;
> +	struct dp_hdcp *hdcp;
> +
> +	hdcp = devm_kzalloc(dev, sizeof(*hdcp), GFP_KERNEL);
> +	if (!hdcp)
> +		return ERR_PTR(-ENOMEM);
> +
> +	hdcp->parser = parser;
> +	hdcp->aux = aux;
> +
> +	mutex_init(&hdcp->key_lock);
> +
> +	return hdcp;
> +}
> +
> +void dp_hdcp_put(struct dp_hdcp *hdcp)
> +{
> +	if (hdcp)
> +		drm_hdcp_helper_destroy(hdcp->helper_data);
> +}
> diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp.h b/drivers/gpu/drm/msm/dp/dp_hdcp.h
> new file mode 100644
> index 000000000000..399b43250e55
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/dp/dp_hdcp.h
> @@ -0,0 +1,29 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright (C) 2021 Google, Inc.
> + *
> + * Authors:
> + * Sean Paul <seanpaul@chromium.org>
> + */
> +
> +#ifndef DP_HDCP_H_
> +#define DP_HDCP_H_
> +
> +#include <drm/display/drm_hdcp_helper.h>
> +
> +#define DP_HDCP_KEY_LEN 7
> +#define DP_HDCP_NUM_KEYS 40
> +
> +struct dp_hdcp;
> +struct dp_parser;
> +struct drm_atomic_state;
> +struct drm_dp_aux;
> +
> +struct dp_hdcp *dp_hdcp_get(struct dp_parser *parser, struct drm_dp_aux *aux);
> +void dp_hdcp_put(struct dp_hdcp *hdcp);
> +
> +int dp_hdcp_attach(struct dp_hdcp *hdcp, struct drm_connector *connector);
> +int dp_hdcp_ingest_key(struct dp_hdcp *hdcp, const u8 *raw_key, int raw_len);
> +void dp_hdcp_commit(struct dp_hdcp *hdcp, struct drm_atomic_state *state);
> +
> +#endif
> diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
> index dcbe893d66d7..714b8dcbc563 100644
> --- a/drivers/gpu/drm/msm/dp/dp_parser.c
> +++ b/drivers/gpu/drm/msm/dp/dp_parser.c
> @@ -58,7 +58,6 @@ static int dp_parser_ctrl_res(struct dp_parser *parser)
>   				DRM_ERROR("legacy memory region not large enough\n");
>   				return -EINVAL;
>   			}
> -
>   			dss->ahb.len = DP_DEFAULT_AHB_SIZE;
>   			dss->aux.base = dss->ahb.base + DP_DEFAULT_AUX_OFFSET;
>   			dss->aux.len = DP_DEFAULT_AUX_SIZE;
> @@ -66,6 +65,10 @@ static int dp_parser_ctrl_res(struct dp_parser *parser)
>   			dss->link.len = DP_DEFAULT_LINK_SIZE;
>   			dss->p0.base = dss->ahb.base + DP_DEFAULT_P0_OFFSET;
>   			dss->p0.len = DP_DEFAULT_P0_SIZE;
> +			dss->hdcp_key.base = NULL;
> +			dss->hdcp_key.len = 0;
> +			dss->hdcp_tz.base = NULL;
> +			dss->hdcp_tz.len = 0;
>   		} else {
>   			DRM_ERROR("unable to remap aux region: %pe\n", dss->aux.base);
>   			return PTR_ERR(dss->aux.base);
> @@ -82,6 +85,21 @@ static int dp_parser_ctrl_res(struct dp_parser *parser)
>   			DRM_ERROR("unable to remap p0 region: %pe\n", dss->p0.base);
>   			return PTR_ERR(dss->p0.base);
>   		}
> +
> +		dss->hdcp_key.base = dp_ioremap(pdev, 5, &dss->hdcp_key.len);
> +		if (!IS_ERR(dss->hdcp_key.base)) {
> +			dss->hdcp_tz.base = dp_ioremap(pdev, 6, &dss->hdcp_tz.len);
> +			if (IS_ERR(dss->hdcp_tz.base)) {
> +				DRM_ERROR("unable to remap hdcp_tz region: %pe\n",
> +					dss->hdcp_tz.base);
> +				return PTR_ERR(dss->hdcp_tz.base);
> +			}
> +		} else {
> +			dss->hdcp_key.base = NULL;
> +			dss->hdcp_key.len = 0;
> +			dss->hdcp_tz.base = NULL;
> +			dss->hdcp_tz.len = 0;
> +		}
>   	}
>   
>   	io->phy = devm_phy_get(&pdev->dev, "dp");
> diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
> index d30ab773db46..b15e481d9d3b 100644
> --- a/drivers/gpu/drm/msm/dp/dp_parser.h
> +++ b/drivers/gpu/drm/msm/dp/dp_parser.h
> @@ -34,6 +34,8 @@ struct dss_io_data {
>   	struct dss_io_region aux;
>   	struct dss_io_region link;
>   	struct dss_io_region p0;
> +	struct dss_io_region hdcp_key;
> +	struct dss_io_region hdcp_tz;
>   };
>   
>   static inline const char *dp_parser_pm_name(enum dp_pm_type module)
> @@ -68,6 +70,8 @@ struct dp_display_data {
>    * struct dp_ctrl_resource - controller's IO related data
>    *
>    * @dp_controller: Display Port controller mapped memory address
> + * @hdcp_key: mapped memory for HDCP key ingestion
> + * @hdcp_tz: mapped memory for HDCP TZ interaction
>    * @phy_io: phy's mapped memory address
>    */
>   struct dp_io {
> diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
> index 268602803d9a..61ab70850f6b 100644
> --- a/drivers/gpu/drm/msm/dp/dp_reg.h
> +++ b/drivers/gpu/drm/msm/dp/dp_reg.h
> @@ -6,11 +6,14 @@
>   #ifndef _DP_REG_H_
>   #define _DP_REG_H_
>   
> +#include <linux/bits.h>
> +
>   /* DP_TX Registers */
>   #define REG_DP_HW_VERSION			(0x00000000)
>   
>   #define REG_DP_SW_RESET				(0x00000010)
> -#define DP_SW_RESET				(0x00000001)
> +#define  DP_SW_RESET				BIT(0)
> +#define  DP_HDCP_SW_RESET			BIT(1)
>   
>   #define REG_DP_PHY_CTRL				(0x00000014)
>   #define DP_PHY_CTRL_SW_RESET_PLL		(0x00000001)
> @@ -283,19 +286,46 @@
>   /* DP HDCP 1.3 registers */
>   #define DP_HDCP_CTRL                                   (0x0A0)
>   #define DP_HDCP_STATUS                                 (0x0A4)
> +#define  DP_HDCP_KEY_STATUS			       GENMASK(18, 16)
> +#define   DP_HDCP_KEY_STATUS_NO_KEYS		       0
> +#define   DP_HDCP_KEY_STATUS_NOT_CHECKED	       1
> +#define   DP_HDCP_KEY_STATUS_CHECKING		       2
> +#define   DP_HDCP_KEY_STATUS_VALID		       3
> +#define   DP_HDCP_KEY_STATUS_INVALID_AKSV	       4
> +#define   DP_HDCP_KEY_STATUS_BAD_CHECKSUM	       5
> +#define   DP_HDCP_KEY_STATUS_PROD_AKSV		       6
> +#define   DP_HDCP_KEY_STATUS_RESV		       7
> +#define  DP_HDCP_R0_READY			       BIT(14)
> +#define  DP_HDCP_SHA_V_MATCH			       BIT(13)
> +#define  DP_HDCP_RI_MATCH			       BIT(12)
> +#define  DP_HDCP_AN_MSB_READY			       BIT(9)
> +#define  DP_HDCP_AN_LSB_READY			       BIT(8)
> +#define  DP_HDCP_AN_READY_MASK			       (DP_HDCP_AN_MSB_READY | DP_HDCP_AN_LSB_READY)
> +#define  DP_HDCP_AUTH_FAIL_INFO			       GENMASK(7, 4)
> +#define   DP_HDCP_AUTH_FAIL_INVALID_AKSV	       3
> +#define   DP_HDCP_AUTH_FAIL_INVALID_BKSV	       4
> +#define   DP_HDCP_AUTH_FAIL_RI_MISMATCH		       5
> +#define  DP_HDCP_AUTH_FAIL			       BIT(2)
> +#define  DP_HDCP_AUTH_SUCCESS			       BIT(0)
>   #define DP_HDCP_SW_UPPER_AKSV                          (0x098)
>   #define DP_HDCP_SW_LOWER_AKSV                          (0x09C)
>   #define DP_HDCP_ENTROPY_CTRL0                          (0x350)
>   #define DP_HDCP_ENTROPY_CTRL1                          (0x35C)
>   #define DP_HDCP_SHA_STATUS                             (0x0C8)
> +#define  DP_HDCP_SHA_COMP_DONE			       BIT(4)
> +#define  DP_HDCP_SHA_DONE			       BIT(0)
>   #define DP_HDCP_RCVPORT_DATA2_0                        (0x0B0)
>   #define DP_HDCP_RCVPORT_DATA3                          (0x0A4)
>   #define DP_HDCP_RCVPORT_DATA4                          (0x0A8)
>   #define DP_HDCP_RCVPORT_DATA5                          (0x0C0)
>   #define DP_HDCP_RCVPORT_DATA6                          (0x0C4)
> +#define DP_HDCP_RCVPORT_DATA7                          (0x0C8)
>   
>   #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL           (0x024)
> +#define  DP_HDCP_SHA_CTRL_RESET			       BIT(0)
>   #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA           (0x028)
> +#define  DP_HDCP_SHA_DATA_MASK			       GENMASK(23, 16)
> +#define  DP_HDCP_SHA_DATA_DONE			       BIT(0)
>   #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0      (0x004)
>   #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1      (0x008)
>   #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7      (0x00C)
> diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
> index 1686fbb611fd..7447f67fba65 100644
> --- a/drivers/gpu/drm/msm/msm_atomic.c
> +++ b/drivers/gpu/drm/msm/msm_atomic.c
> @@ -7,6 +7,7 @@
>   #include <drm/drm_atomic_uapi.h>
>   #include <drm/drm_vblank.h>
>   
> +#include "dp_drm.h"
>   #include "msm_atomic_trace.h"
>   #include "msm_drv.h"
>   #include "msm_gem.h"
> @@ -179,6 +180,18 @@ static unsigned get_crtc_mask(struct drm_atomic_state *state)
>   	return mask;
>   }
>   
> +static void msm_atomic_commit_connectors(struct drm_atomic_state *state)
> +{
> +	struct drm_connector_state *conn_state;
> +	struct drm_connector *connector;
> +	int i;
> +
> +	for_each_new_connector_in_state(state, connector, conn_state, i) {
> +		if (dp_drm_is_connector_msm_dp(connector))
> +			dp_drm_atomic_commit(connector, conn_state, state);
> +	}
> +}

This looks like a lame way to work around drm_bridge 
drm_bridge_connector deficiencies. Please move this to drm_bridge level 
and make it be called properly.

> +
>   void msm_atomic_commit_tail(struct drm_atomic_state *state)
>   {
>   	struct drm_device *dev = state->dev;
> @@ -215,6 +228,8 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state)
>   	drm_atomic_helper_commit_planes(dev, state, 0);
>   	drm_atomic_helper_commit_modeset_enables(dev, state);
>   
> +	msm_atomic_commit_connectors(state);
> +
>   	if (async) {
>   		struct msm_pending_timer *timer =
>   			&kms->pending_timers[drm_crtc_index(async_crtc)];

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
  2023-01-18 19:30 ` [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check() Mark Yacoub
  2023-01-19 10:37   ` Krzysztof Kozlowski
@ 2023-01-19 11:41   ` Dmitry Baryshkov
  2023-03-10  5:30   ` [Intel-gfx] " Kandpal, Suraj
  2 siblings, 0 replies; 38+ messages in thread
From: Dmitry Baryshkov @ 2023-01-19 11:41 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, sean, airlied, daniel, robh+dt,
	krzysztof.kozlowski+dt, agross, andersson, konrad.dybcio,
	jani.nikula, joonas.lahtinen, rodrigo.vivi, tvrtko.ursulin,
	tzimmermann, ville.syrjala, stanislav.lisovskiy, matthew.d.roper,
	imre.deak, lucas.demarchi, manasi.d.navare, swati2.sharma,
	bhanuprakash.modem, javierm, jose.souza, lyude, hbh25y,
	arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime, swboyd,
	christophe.jaillet, quic_sbillaka, johan+linaro, dianders, marex,
	quic_jesszhan, bjorn.andersson, abhinavk, seanpaul, Jani Nikula

On 18/01/2023 21:30, Mark Yacoub wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch moves the hdcp atomic check from i915 to drm_hdcp so other
> drivers can use it. No functional changes, just cleaned up some of the
> code when moving it over.
> 
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Reviewed-by: Abhinav Kumar <abhinavk@codeaurora.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-2-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-2-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-2-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-2-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-2-sean@poorly.run #v5
> 
> Changes in v2:
> -None
> Changes in v3:
> -None
> Changes in v4:
> -None
> Changes in v5:
> -None
> Changes in V6:
> -Rebase: move helper from drm_hdcp.c to drm_hdcp_helper.c
> 
> ---
>   drivers/gpu/drm/display/drm_hdcp_helper.c   | 69 +++++++++++++++++++++
>   drivers/gpu/drm/i915/display/intel_atomic.c |  4 +-
>   drivers/gpu/drm/i915/display/intel_hdcp.c   | 47 --------------
>   drivers/gpu/drm/i915/display/intel_hdcp.h   |  3 -
>   include/drm/display/drm_hdcp_helper.h       |  3 +
>   5 files changed, 74 insertions(+), 52 deletions(-)

With the hope that commit message is cleaned up:

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic check
  2023-01-18 19:30 ` [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic check Mark Yacoub
@ 2023-01-19 11:45   ` Dmitry Baryshkov
  2023-03-10  6:00   ` [Intel-gfx] " Kandpal, Suraj
  1 sibling, 0 replies; 38+ messages in thread
From: Dmitry Baryshkov @ 2023-01-19 11:45 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, sean, airlied, daniel, robh+dt,
	krzysztof.kozlowski+dt, agross, andersson, konrad.dybcio,
	jani.nikula, joonas.lahtinen, rodrigo.vivi, tvrtko.ursulin,
	tzimmermann, ville.syrjala, stanislav.lisovskiy, matthew.d.roper,
	imre.deak, lucas.demarchi, manasi.d.navare, swati2.sharma,
	bhanuprakash.modem, javierm, jose.souza, lyude, hbh25y,
	arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime, swboyd,
	christophe.jaillet, quic_sbillaka, johan+linaro, dianders, marex,
	quic_jesszhan, bjorn.andersson, abhinavk, seanpaul, Jani Nikula

On 18/01/2023 21:30, Mark Yacoub wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> Instead of forcing a modeset in the hdcp atomic check, simply return
> true if the content protection value is changing and let the driver
> decide whether a modeset is required or not.

I don't think this is a good idea. All foo_atomic_check functions return 
an error code (or 0 if atomic check passes). Making 
drm_hpcp_atomic_check return bool is against that custom and is a clear 
way to make one forget to notice that. Please rename function to remove 
possible confusion.

> 
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-3-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-3-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-3-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-3-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-3-sean@poorly.run #v5
> 
> Changes in v2:
> -None
> Changes in v3:
> -None
> Changes in v4:
> -None
> Changes in v5:
> -None
> Changes in V6:
> -Rebase: modifications in drm_hdcp_helper.c instead of drm_hdcp.c
> 
> ---
>   drivers/gpu/drm/display/drm_hdcp_helper.c   | 33 +++++++++++++++------
>   drivers/gpu/drm/i915/display/intel_atomic.c |  6 ++--
>   include/drm/display/drm_hdcp_helper.h       |  2 +-
>   3 files changed, 27 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_hdcp_helper.c b/drivers/gpu/drm/display/drm_hdcp_helper.c
> index 7d910523b05f..a3896b0904b5 100644
> --- a/drivers/gpu/drm/display/drm_hdcp_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdcp_helper.c
> @@ -428,11 +428,14 @@ EXPORT_SYMBOL(drm_hdcp_update_content_protection);
>    * @connector: drm_connector on which content protection state needs an update
>    *
>    * This function can be used by display drivers to perform an atomic check on the
> - * hdcp state elements. If hdcp state has changed, this function will set
> - * mode_changed on the crtc driving the connector so it can update its hardware
> - * to match the hdcp state.
> + * hdcp state elements. If hdcp state has changed in a manner which requires the
> + * driver to enable or disable content protection, this function will return
> + * true.
> + *
> + * Returns:
> + * true if the driver must enable/disable hdcp, false otherwise
>    */
> -void drm_hdcp_atomic_check(struct drm_connector *connector,
> +bool drm_hdcp_atomic_check(struct drm_connector *connector,
>   			   struct drm_atomic_state *state)
>   {
>   	struct drm_connector_state *new_conn_state, *old_conn_state;
> @@ -450,10 +453,12 @@ void drm_hdcp_atomic_check(struct drm_connector *connector,
>   		 * If the connector is being disabled with CP enabled, mark it
>   		 * desired so it's re-enabled when the connector is brought back
>   		 */
> -		if (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED)
> +		if (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
>   			new_conn_state->content_protection =
>   				DRM_MODE_CONTENT_PROTECTION_DESIRED;
> -		return;
> +			return true;
> +		}
> +		return false;
>   	}
>   
>   	new_crtc_state =
> @@ -465,9 +470,19 @@ void drm_hdcp_atomic_check(struct drm_connector *connector,
>   	*/
>   	if (drm_atomic_crtc_needs_modeset(new_crtc_state) &&
>   	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
> -	     new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED))
> +	     new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)) {
>   		new_conn_state->content_protection =
>   			DRM_MODE_CONTENT_PROTECTION_DESIRED;
> +		return true;
> +	}
> +
> +	/*
> +	 * Coming back from disable or changing CRTC with DESIRED state requires
> +	 * that the driver try CP enable.
> +	 */
> +	if (new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
> +	    new_conn_state->crtc != old_conn_state->crtc)
> +		return true;
>   
>   	/*
>   	 * Nothing to do if content type is unchanged and one of:
> @@ -482,9 +497,9 @@ void drm_hdcp_atomic_check(struct drm_connector *connector,
>   	     new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED)) {
>   		if (old_conn_state->hdcp_content_type ==
>   		    new_conn_state->hdcp_content_type)
> -			return;
> +			return false;
>   	}
>   
> -	new_crtc_state->mode_changed = true;
> +	return true;
>   }
>   EXPORT_SYMBOL(drm_hdcp_atomic_check);
> diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
> index 8a473199c4bf..a2067cbae2d5 100644
> --- a/drivers/gpu/drm/i915/display/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/display/intel_atomic.c
> @@ -123,8 +123,6 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
>   		to_intel_digital_connector_state(old_state);
>   	struct drm_crtc_state *crtc_state;
>   
> -	drm_hdcp_atomic_check(conn, state);
> -
>   	if (!new_state->crtc)
>   		return 0;
>   
> @@ -140,8 +138,8 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
>   	    new_conn_state->base.picture_aspect_ratio != old_conn_state->base.picture_aspect_ratio ||
>   	    new_conn_state->base.content_type != old_conn_state->base.content_type ||
>   	    new_conn_state->base.scaling_mode != old_conn_state->base.scaling_mode ||
> -	    new_conn_state->base.privacy_screen_sw_state != old_conn_state->base.privacy_screen_sw_state ||
> -	    !drm_connector_atomic_hdr_metadata_equal(old_state, new_state))
> +	    !drm_connector_atomic_hdr_metadata_equal(old_state, new_state) ||
> +	    drm_hdcp_atomic_check(conn, state))
>   		crtc_state->mode_changed = true;
>   
>   	return 0;
> diff --git a/include/drm/display/drm_hdcp_helper.h b/include/drm/display/drm_hdcp_helper.h
> index dd02b2e72a50..cb2cc5002f65 100644
> --- a/include/drm/display/drm_hdcp_helper.h
> +++ b/include/drm/display/drm_hdcp_helper.h
> @@ -19,7 +19,7 @@ int drm_hdcp_check_ksvs_revoked(struct drm_device *dev, u8 *ksvs, u32 ksv_count)
>   int drm_connector_attach_content_protection_property(struct drm_connector *connector,
>   						     bool hdcp_content_type);
>   void drm_hdcp_update_content_protection(struct drm_connector *connector, u64 val);
> -void drm_hdcp_atomic_check(struct drm_connector *connector,
> +bool drm_hdcp_atomic_check(struct drm_connector *connector,
>   			   struct drm_atomic_state *state);
>   
>   #endif

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 04/10] drm/hdcp: Expand HDCP helper library for enable/disable/check
  2023-01-18 19:30 ` [PATCH v6 04/10] drm/hdcp: Expand HDCP helper library for enable/disable/check Mark Yacoub
@ 2023-01-19 12:54   ` Dmitry Baryshkov
  0 siblings, 0 replies; 38+ messages in thread
From: Dmitry Baryshkov @ 2023-01-19 12:54 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: robdclark, quic_abhinavk, sean, airlied, daniel, robh+dt,
	krzysztof.kozlowski+dt, agross, andersson, konrad.dybcio,
	jani.nikula, joonas.lahtinen, rodrigo.vivi, tvrtko.ursulin,
	tzimmermann, ville.syrjala, stanislav.lisovskiy, matthew.d.roper,
	imre.deak, lucas.demarchi, manasi.d.navare, swati2.sharma,
	bhanuprakash.modem, javierm, jose.souza, lyude, hbh25y,
	arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime, swboyd,
	christophe.jaillet, quic_sbillaka, johan+linaro, dianders, marex,
	quic_jesszhan, bjorn.andersson, abhinavk, seanpaul, Jani Nikula

On 18/01/2023 21:30, Mark Yacoub wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch expands upon the HDCP helper library to manage HDCP
> enable, disable, and check.
> 
> Previous to this patch, the majority of the state management and sink
> interaction is tucked inside the Intel driver with the understanding
> that once a new platform supported HDCP we could make good decisions
> about what should be centralized. With the addition of HDCP support
> for Qualcomm, it's time to migrate the protocol-specific bits of HDCP
> authentication, key exchange, and link checks to the HDCP helper.
> 
> In terms of functionality, this migration is 1:1 with the Intel driver,
> however things are laid out a bit differently than with intel_hdcp.c,
> which is why this is a separate patch from the i915 transition to the
> helper. On i915, the shim vtable is used to account for HDMI vs. DP
> vs. DP-MST differences whereas the helper library uses a LUT to
> account for the register offsets and a remote read function to route
> the messages. On i915, storing the sink information in the source is
> done inline whereas now we use the new drm_hdcp_helper_funcs vtable
> to store and fetch information to/from source hw. Finally, instead of
> calling enable/disable directly from the driver, we'll leave that
> decision to the helper and by calling drm_hdcp_helper_atomic_commit()
> from the driver. All told, this will centralize the protocol and state
> handling in the helper, ensuring we collect all of our bugs^Wlogic
> in one place.
> 
> Cc: Abhinav Kumar <abhinavk@codeaurora.org>
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Reviewed-by: Abhinav Kumar <abhinavk@codeaurora.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-5-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-5-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-5-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-5-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-5-sean@poorly.run #v5
> 
> Changes in v2:
> -Fixed set-but-unused variable identified by 0-day
> Changes in v3:
> -Fixed uninitialized variable warning identified by 0-day
> Changes in v4:
> -None
> Changes in v5:
> -None
> Changes in v6:
> -Fixed typo in function descriptions
> -Rebased: Moved the new code between drm_hdcp.h and drm_hdcp_helper.c/h
> -Add missing headers. Reported-by: kernel test robot <lkp@intel.com>
> 
> ---
>   drivers/gpu/drm/display/drm_hdcp_helper.c | 1109 +++++++++++++++++++++
>   include/drm/display/drm_hdcp.h            |  168 +++-
>   include/drm/display/drm_hdcp_helper.h     |   30 +-
>   3 files changed, 1305 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_hdcp_helper.c b/drivers/gpu/drm/display/drm_hdcp_helper.c
> index ce92f1cac251..de8c006b9cda 100644
> --- a/drivers/gpu/drm/display/drm_hdcp_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdcp_helper.c
> @@ -6,13 +6,18 @@
>    * Ramalingam C <ramalingam.c@intel.com>
>    */
>   
> +#include <linux/delay.h>
>   #include <linux/device.h>
>   #include <linux/err.h>
>   #include <linux/gfp.h>
> +#include <linux/i2c.h>
> +#include <linux/iopoll.h>
>   #include <linux/export.h>
>   #include <linux/slab.h>
>   #include <linux/firmware.h>
> +#include <linux/workqueue.h>
>   
> +#include <drm/display/drm_dp_helper.h>
>   #include <drm/display/drm_hdcp_helper.h>
>   #include <drm/drm_sysfs.h>
>   #include <drm/drm_print.h>
> @@ -512,3 +517,1107 @@ bool drm_hdcp_atomic_check(struct drm_connector *connector,
>   	return old_hdcp != new_hdcp;
>   }
>   EXPORT_SYMBOL(drm_hdcp_atomic_check);
> +
> +struct drm_hdcp_helper_data {
> +	struct mutex mutex;
> +	struct mutex *driver_mutex;
> +
> +	struct drm_connector *connector;
> +	const struct drm_hdcp_helper_funcs *funcs;
> +
> +	u64 value;
> +	unsigned int enabled_type;
> +
> +	struct delayed_work check_work;
> +	struct work_struct prop_work;
> +
> +	struct drm_dp_aux *aux;
> +	const struct drm_hdcp_hdcp1_receiver_reg_lut *hdcp1_lut;
> +};
> +
> +struct drm_hdcp_hdcp1_receiver_reg_lut {
> +	unsigned int bksv;
> +	unsigned int ri;
> +	unsigned int aksv;
> +	unsigned int an;
> +	unsigned int ainfo;
> +	unsigned int v[5];
> +	unsigned int bcaps;
> +	unsigned int bcaps_mask_repeater_present;
> +	unsigned int bstatus;
> +};
> +
> +static const struct drm_hdcp_hdcp1_receiver_reg_lut drm_hdcp_hdcp1_ddc_lut = {
> +	.bksv = DRM_HDCP_DDC_BKSV,
> +	.ri = DRM_HDCP_DDC_RI_PRIME,
> +	.aksv = DRM_HDCP_DDC_AKSV,
> +	.an = DRM_HDCP_DDC_AN,
> +	.ainfo = DRM_HDCP_DDC_AINFO,
> +	.v = { DRM_HDCP_DDC_V_PRIME(0), DRM_HDCP_DDC_V_PRIME(1),
> +	       DRM_HDCP_DDC_V_PRIME(2), DRM_HDCP_DDC_V_PRIME(3),
> +	       DRM_HDCP_DDC_V_PRIME(4) },
> +	.bcaps = DRM_HDCP_DDC_BCAPS,
> +	.bcaps_mask_repeater_present = DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT,
> +	.bstatus = DRM_HDCP_DDC_BSTATUS,
> +};
> +
> +static const struct drm_hdcp_hdcp1_receiver_reg_lut drm_hdcp_hdcp1_dpcd_lut = {
> +	.bksv = DP_AUX_HDCP_BKSV,
> +	.ri = DP_AUX_HDCP_RI_PRIME,
> +	.aksv = DP_AUX_HDCP_AKSV,
> +	.an = DP_AUX_HDCP_AN,
> +	.ainfo = DP_AUX_HDCP_AINFO,
> +	.v = { DP_AUX_HDCP_V_PRIME(0), DP_AUX_HDCP_V_PRIME(1),
> +	       DP_AUX_HDCP_V_PRIME(2), DP_AUX_HDCP_V_PRIME(3),
> +	       DP_AUX_HDCP_V_PRIME(4) },
> +	.bcaps = DP_AUX_HDCP_BCAPS,
> +	.bcaps_mask_repeater_present = DP_BCAPS_REPEATER_PRESENT,
> +
> +	/*
> +	 * For some reason the HDMI and DP HDCP specs call this register
> +	 * definition by different names. In the HDMI spec, it's called BSTATUS,
> +	 * but in DP it's called BINFO.
> +	 */
> +	.bstatus = DP_AUX_HDCP_BINFO,
> +};
> +
> +static int drm_hdcp_remote_ddc_read(struct i2c_adapter *i2c,
> +				    unsigned int offset, u8 *value, size_t len)
> +{
> +	int ret;
> +	u8 start = offset & 0xff;
> +	struct i2c_msg msgs[] = { {
> +					  .addr = DRM_HDCP_DDC_ADDR,
> +					  .flags = 0,
> +					  .len = 1,
> +					  .buf = &start,
> +				  },
> +				  { .addr = DRM_HDCP_DDC_ADDR,
> +				    .flags = I2C_M_RD,
> +				    .len = len,
> +				    .buf = value } };

Very strange indentation, I'd say.

> +	ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs));
> +	if (ret == ARRAY_SIZE(msgs))
> +		return 0;
> +	return ret >= 0 ? -EIO : ret;
> +}
> +
> +static int drm_hdcp_remote_dpcd_read(struct drm_dp_aux *aux,
> +				     unsigned int offset, u8 *value, size_t len)
> +{
> +	ssize_t ret;
> +
> +	ret = drm_dp_dpcd_read(aux, offset, value, len);
> +	if (ret != len) {
> +		if (ret >= 0)
> +			return -EIO;
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int drm_hdcp_remote_read(struct drm_hdcp_helper_data *data,
> +				unsigned int offset, u8 *value, u8 len)
> +{
> +	if (data->aux)
> +		return drm_hdcp_remote_dpcd_read(data->aux, offset, value, len);
> +	else
> +		return drm_hdcp_remote_ddc_read(data->connector->ddc, offset,
> +						value, len);
> +}
> +
> +static int drm_hdcp_remote_ddc_write(struct i2c_adapter *i2c,
> +				     unsigned int offset, u8 *buffer,
> +				     size_t size)
> +{
> +	int ret;
> +	u8 *write_buf;
> +	struct i2c_msg msg;
> +
> +	write_buf = kzalloc(size + 1, GFP_KERNEL);
> +	if (!write_buf)
> +		return -ENOMEM;
> +
> +	write_buf[0] = offset & 0xff;
> +	memcpy(&write_buf[1], buffer, size);
> +
> +	msg.addr = DRM_HDCP_DDC_ADDR;
> +	msg.flags = 0, msg.len = size + 1, msg.buf = write_buf;
> +
> +	ret = i2c_transfer(i2c, &msg, 1);
> +	if (ret == 1)
> +		ret = 0;
> +	else if (ret >= 0)
> +		ret = -EIO;
> +
> +	kfree(write_buf);
> +	return ret;
> +}
> +
> +static int drm_hdcp_remote_dpcd_write(struct drm_dp_aux *aux,
> +				      unsigned int offset, u8 *value,
> +				      size_t len)
> +{
> +	ssize_t ret;
> +
> +	ret = drm_dp_dpcd_write(aux, offset, value, len);
> +	if (ret != len) {
> +		if (ret >= 0)
> +			return -EIO;
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int drm_hdcp_remote_write(struct drm_hdcp_helper_data *data,
> +				 unsigned int offset, u8 *value, u8 len)
> +{
> +	if (data->aux)
> +		return drm_hdcp_remote_dpcd_write(data->aux, offset, value,
> +						  len);
> +	else
> +		return drm_hdcp_remote_ddc_write(data->connector->ddc, offset,
> +						 value, len);
> +}
> +
> +static bool drm_hdcp_is_ksv_valid(struct drm_hdcp_ksv *ksv)
> +{
> +	/* Valid Ksv has 20 0's and 20 1's */
> +	return hweight32(ksv->words[0]) + hweight32(ksv->words[1]) == 20;
> +}
> +
> +static int drm_hdcp_read_valid_bksv(struct drm_hdcp_helper_data *data,
> +				    struct drm_hdcp_ksv *bksv)
> +{
> +	int ret, i, tries = 2;
> +
> +	/* HDCP spec states that we must retry the bksv if it is invalid */
> +	for (i = 0; i < tries; i++) {
> +		ret = drm_hdcp_remote_read(data, data->hdcp1_lut->bksv,
> +					   bksv->bytes, DRM_HDCP_KSV_LEN);
> +		if (ret)
> +			return ret;
> +
> +		if (drm_hdcp_is_ksv_valid(bksv))
> +			break;
> +	}
> +	if (i == tries) {
> +		drm_dbg_kms(data->connector->dev, "Bksv is invalid %*ph\n",
> +			    DRM_HDCP_KSV_LEN, bksv->bytes);
> +		return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * drm_hdcp_helper_hdcp1_capable - Checks if the sink is capable of HDCP 1.x.
> + *
> + * @data: pointer to the HDCP helper data.
> + * @capable: pointer to a bool which will contain true if the sink is capable.
> + *
> + * Returns:
> + * -errno if the transacation between source and sink fails.
> + */
> +int drm_hdcp_helper_hdcp1_capable(struct drm_hdcp_helper_data *data,
> +				  bool *capable)
> +{
> +	/*
> +	 * DisplayPort has a dedicated bit for this in DPCD whereas HDMI spec
> +	 * states that transmitters should use bksv to determine capability.
> +	 */
> +	if (data->aux) {
> +		int ret;
> +		u8 bcaps;
> +
> +		ret = drm_hdcp_remote_read(data, data->hdcp1_lut->bcaps, &bcaps,
> +					   1);
> +		*capable = !ret && (bcaps & DP_BCAPS_HDCP_CAPABLE);
> +	} else {
> +		struct drm_hdcp_ksv bksv;
> +
> +		*capable = drm_hdcp_read_valid_bksv(data, &bksv) == 0;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_hdcp_helper_hdcp1_capable);

I'd say that all previous code begs to add corresponding callbacks to 
the hdcp_helper_data and then just call them instead of manually 
multiplexing the code basing on data->aux.

> +
> +static void drm_hdcp_update_value(struct drm_hdcp_helper_data *data, u64 value,
> +				  bool update_property)
> +{
> +	WARN_ON(!mutex_is_locked(&data->mutex));
> +
> +	data->value = value;
> +	if (update_property) {
> +		drm_connector_get(data->connector);
> +		schedule_work(&data->prop_work);
> +	}
> +}
> +
> +static int
> +drm_hdcp_helper_hdcp1_ksv_fifo_ready(struct drm_hdcp_helper_data *data)
> +{
> +	int ret;
> +	u8 val, mask;
> +
> +	/* KSV FIFO ready bit is stored in different locations on DP v. HDMI */
> +	if (data->aux) {
> +		ret = drm_hdcp_remote_dpcd_read(data->aux, DP_AUX_HDCP_BSTATUS,
> +						&val, 1);
> +		mask = DP_BSTATUS_READY;
> +	} else {
> +		ret = drm_hdcp_remote_ddc_read(data->connector->ddc,
> +					       DRM_HDCP_DDC_BCAPS, &val, 1);
> +		mask = DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
> +	}
> +	if (ret)
> +		return ret;
> +	if (val & mask)
> +		return 0;
> +
> +	return -EAGAIN;
> +}

Again, this can go to hdcp-kind ops.

> +
> +static int
> +drm_hdcp_helper_hdcp1_read_ksv_fifo(struct drm_hdcp_helper_data *data, u8 *fifo,
> +				    u8 num_downstream)
> +{
> +	struct drm_device *dev = data->connector->dev;
> +	int ret, i;
> +
> +	/* Over HDMI, read the whole thing at once */
> +	if (data->connector->ddc) {

And here for some reason one choose data->connector->ddc instead of 
data->aux, so grepping for data->aux would not return this function.

> +		ret = drm_hdcp_remote_ddc_read(
> +			data->connector->ddc, DRM_HDCP_DDC_KSV_FIFO, fifo,
> +			num_downstream * DRM_HDCP_KSV_LEN);
> +		if (ret)
> +			drm_err(dev, "DDC ksv fifo read failed (%d)\n", ret);
> +		return ret;
> +	}
> +
> +	/* Over DP, read via 15 byte window (3 entries @ 5 bytes each) */
> +	for (i = 0; i < num_downstream; i += 3) {
> +		size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
> +		ret = drm_hdcp_remote_dpcd_read(data->aux, DP_AUX_HDCP_KSV_FIFO,
> +						fifo + i * DRM_HDCP_KSV_LEN,
> +						len);
> +		if (ret) {
> +			drm_err(dev, "Read ksv[%d] from DP/AUX failed (%d)\n",
> +				i, ret);
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int drm_hdcp_helper_hdcp1_read_v_prime(struct drm_hdcp_helper_data *data,
> +					      u32 *v_prime)
> +{
> +	struct drm_device *dev = data->connector->dev;
> +	int ret, i;
> +
> +	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
> +		ret = drm_hdcp_remote_read(data, data->hdcp1_lut->v[i],
> +					   (u8 *)&v_prime[i],
> +					   DRM_HDCP_V_PRIME_PART_LEN);
> +		if (ret) {
> +			drm_dbg_kms(dev, "Read v'[%d] from failed (%d)\n", i,
> +				    ret);
> +			return ret >= 0 ? -EIO : ret;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int
> +drm_hdcp_helper_hdcp1_authenticate_downstream(struct drm_hdcp_helper_data *data)
> +{
> +	struct drm_connector *connector = data->connector;
> +	struct drm_device *dev = connector->dev;
> +	u32 v_prime[DRM_HDCP_V_PRIME_NUM_PARTS];
> +	u8 bstatus[DRM_HDCP_BSTATUS_LEN];
> +	u8 num_downstream, *ksv_fifo;
> +	int ret, i, tries = 3;
> +
> +	ret = read_poll_timeout(drm_hdcp_helper_hdcp1_ksv_fifo_ready, ret, !ret,
> +				10 * 1000, 5 * 1000 * 1000, false, data);
> +	if (ret) {
> +		drm_err(dev, "Failed to poll ksv ready, %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = drm_hdcp_remote_read(data, data->hdcp1_lut->bstatus, bstatus,
> +				   DRM_HDCP_BSTATUS_LEN);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * When repeater reports 0 device count, HDCP1.4 spec allows disabling
> +	 * the HDCP encryption. That implies that repeater can't have its own
> +	 * display. As there is no consumption of encrypted content in the
> +	 * repeater with 0 downstream devices, we are failing the
> +	 * authentication.
> +	 */
> +	num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
> +	if (num_downstream == 0) {
> +		drm_err(dev, "Repeater with zero downstream devices, %*ph\n",
> +			DRM_HDCP_BSTATUS_LEN, bstatus);
> +		return -EINVAL;
> +	}
> +
> +	ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream, GFP_KERNEL);
> +	if (!ksv_fifo)
> +		return -ENOMEM;
> +
> +	ret = drm_hdcp_helper_hdcp1_read_ksv_fifo(data, ksv_fifo,
> +						  num_downstream);

I'd have moved kcalloc into read_ksv_fifo.

> +	if (ret) {
> +		drm_err(dev, "Failed to read ksv fifo, %d/%d\n", num_downstream,
> +			ret);
> +		goto out;
> +	}
> +
> +	if (drm_hdcp_check_ksvs_revoked(dev, ksv_fifo, num_downstream)) {
> +		drm_err(dev, "Revoked Ksv(s) in ksv_fifo\n");
> +		ret = -EPERM;
> +		goto out;
> +	}
> +
> +	/*
> +	 * When V prime mismatches, DP Spec mandates re-read of
> +	 * V prime at least twice.
> +	 */
> +	for (i = 0; i < tries; i++) {
> +		ret = drm_hdcp_helper_hdcp1_read_v_prime(data, v_prime);
> +		if (ret)
> +			continue;
> +
> +		ret = data->funcs->hdcp1_store_ksv_fifo(
> +			connector, ksv_fifo, num_downstream, bstatus, v_prime);
> +		if (!ret)
> +			break;
> +	}
> +	if (ret)
> +		drm_err(dev, "Could not validate KSV FIFO with V' %d\n", ret);
> +
> +out:
> +	if (!ret)
> +		drm_dbg_kms(dev, "HDCP is enabled (%d downstream devices)\n",
> +			    num_downstream);
> +
> +	kfree(ksv_fifo);
> +	return ret;
> +}
> +
> +static int drm_hdcp_helper_hdcp1_validate_ri(struct drm_hdcp_helper_data *data)
> +{
> +	union {
> +		u32 word;
> +		u8 bytes[DRM_HDCP_RI_LEN];
> +	} ri_prime = { .word = 0 };
> +	struct drm_connector *connector = data->connector;
> +	struct drm_device *dev = connector->dev;
> +	int ret;
> +
> +	ret = drm_hdcp_remote_read(data, data->hdcp1_lut->ri, ri_prime.bytes,
> +				   DRM_HDCP_RI_LEN);
> +	if (ret) {
> +		drm_err(dev, "Failed to read R0' %d\n", ret);
> +		return ret;
> +	}
> +
> +	return data->funcs->hdcp1_match_ri(connector, ri_prime.word);
> +}
> +
> +static int drm_hdcp_helper_hdcp1_authenticate(struct drm_hdcp_helper_data *data)
> +{
> +	union {
> +		u32 word;
> +		u8 bytes[DRM_HDCP_BSTATUS_LEN];
> +	} bstatus;
> +	const struct drm_hdcp_helper_funcs *funcs = data->funcs;
> +	struct drm_connector *connector = data->connector;
> +	struct drm_device *dev = connector->dev;
> +	unsigned long r0_prime_timeout, r0_prime_remaining_us = 0, tmp_jiffies;
> +	struct drm_hdcp_ksv aksv;
> +	struct drm_hdcp_ksv bksv;
> +	struct drm_hdcp_an an;
> +	bool repeater_present;
> +	int ret, i, tries = 3;
> +	u8 bcaps;
> +
> +	if (funcs->hdcp1_read_an_aksv) {
> +		ret = funcs->hdcp1_read_an_aksv(connector, an.words,
> +						aksv.words);
> +		if (ret) {
> +			drm_err(dev, "Failed to read An/Aksv values, %d\n",
> +				ret);
> +			return ret;
> +		}
> +
> +		ret = drm_hdcp_remote_write(data, data->hdcp1_lut->an, an.bytes,
> +					    DRM_HDCP_AN_LEN);
> +		if (ret) {
> +			drm_err(dev, "Failed to write An to receiver, %d\n",
> +				ret);
> +			return ret;
> +		}
> +
> +		ret = drm_hdcp_remote_write(data, data->hdcp1_lut->aksv,
> +					    aksv.bytes, DRM_HDCP_KSV_LEN);
> +		if (ret) {
> +			drm_err(dev, "Failed to write Aksv to receiver, %d\n",
> +				ret);
> +			return ret;
> +		}
> +	} else {
> +		ret = funcs->hdcp1_send_an_aksv(connector);
> +		if (ret) {
> +			drm_err(dev, "Failed to read An/Aksv values, %d\n",
> +				ret);
> +			return ret;
> +		}
> +	}
> +
> +	/*
> +	 * Timeout for R0' to become available. The spec says 100ms from Aksv,
> +	 * but some monitors can take longer than this. We'll set the timeout at
> +	 * 300ms just to be sure.
> +	 */
> +	r0_prime_timeout = jiffies + msecs_to_jiffies(300);
> +
> +	memset(&bksv, 0, sizeof(bksv));
> +
> +	ret = drm_hdcp_read_valid_bksv(data, &bksv);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (drm_hdcp_check_ksvs_revoked(dev, bksv.bytes, 1)) {
> +		drm_err(dev, "BKSV is revoked\n");
> +		return -EPERM;
> +	}
> +
> +	ret = drm_hdcp_remote_read(data, data->hdcp1_lut->bcaps, &bcaps, 1);
> +	if (ret)
> +		return ret;
> +
> +	memset(&bstatus, 0, sizeof(bstatus));
> +
> +	ret = drm_hdcp_remote_read(data, data->hdcp1_lut->bstatus,
> +				   bstatus.bytes, DRM_HDCP_BSTATUS_LEN);
> +	if (ret)
> +		return ret;
> +
> +	if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus.bytes[0]) ||
> +	    DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus.bytes[1])) {
> +		drm_err(dev, "Max Topology Limit Exceeded, bstatus=%*ph\n",
> +			DRM_HDCP_BSTATUS_LEN, bstatus.bytes);
> +		return -EPERM;
> +	}
> +
> +	repeater_present = bcaps & data->hdcp1_lut->bcaps_mask_repeater_present;
> +
> +	ret = funcs->hdcp1_store_receiver_info(
> +		connector, bksv.words, bstatus.word, bcaps, repeater_present);
> +	if (ret) {
> +		drm_err(dev, "Failed to store bksv, %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = funcs->hdcp1_enable_encryption(connector);
> +	if (ret)
> +		return ret;
> +
> +	ret = funcs->hdcp1_wait_for_r0(connector);
> +	if (ret)
> +		return ret;
> +
> +	tmp_jiffies = jiffies;
> +	if (time_before(tmp_jiffies, r0_prime_timeout))
> +		r0_prime_remaining_us =
> +			jiffies_to_usecs(r0_prime_timeout - tmp_jiffies);
> +
> +	/*
> +	 * Wait for R0' to become available.
> +	 *
> +	 * On DP, there's an R0_READY bit available but no such bit
> +	 * exists on HDMI. So poll the ready bit for DP and just wait the
> +	 * remainder of the 300 ms timeout for HDMI.
> +	 */
> +	if (data->aux) {
> +		u8 val;
> +		ret = read_poll_timeout(
> +			drm_hdcp_remote_dpcd_read, ret,
> +			!ret && (val & DP_BSTATUS_R0_PRIME_READY), 1000,
> +			r0_prime_remaining_us, false, data->aux,
> +			DP_AUX_HDCP_BSTATUS, &val, 1);
> +		if (ret) {
> +			drm_err(dev, "R0' did not become ready %d\n", ret);
> +			return ret;
> +		}
> +	} else {
> +		usleep_range(r0_prime_remaining_us,
> +			     r0_prime_remaining_us + 1000);
> +	}

Another hdcp backend function.

> +
> +	/*
> +	 * DP HDCP Spec mandates the two more reattempt to read R0, in case
> +	 * of R0 mismatch.
> +	 */
> +	for (i = 0; i < tries; i++) {
> +		ret = drm_hdcp_helper_hdcp1_validate_ri(data);
> +		if (!ret)
> +			break;
> +	}
> +	if (ret) {
> +		drm_err(dev, "Failed to match R0/R0', aborting HDCP %d\n", ret);
> +		return ret;
> +	}
> +
> +	if (repeater_present)
> +		return drm_hdcp_helper_hdcp1_authenticate_downstream(data);
> +
> +	drm_dbg_kms(dev, "HDCP is enabled (no repeater present)\n");
> +	return 0;
> +}
> +
> +static int drm_hdcp_helper_hdcp1_enable(struct drm_hdcp_helper_data *data)
> +{
> +	struct drm_connector *connector = data->connector;
> +	struct drm_device *dev = connector->dev;
> +	int i, ret, tries = 3;
> +
> +	drm_dbg_kms(dev, "[%s:%d] HDCP is being enabled...\n", connector->name,
> +		    connector->base.id);
> +
> +	/* In case of authentication failures, HDCP spec expects reauth. */
> +	for (i = 0; i < tries; i++) {
> +		ret = drm_hdcp_helper_hdcp1_authenticate(data);
> +		if (!ret)
> +			return 0;
> +
> +		drm_dbg_kms(dev, "HDCP Auth failure (%d)\n", ret);
> +
> +		/* Ensuring HDCP encryption and signalling are stopped. */
> +		data->funcs->hdcp1_disable(data->connector);
> +	}
> +
> +	drm_err(dev, "HDCP authentication failed (%d tries/%d)\n", tries, ret);
> +	return ret;
> +}
> +
> +static inline void
> +drm_hdcp_helper_driver_lock(struct drm_hdcp_helper_data *data)
> +{
> +	if (data->driver_mutex)
> +		mutex_lock(data->driver_mutex);
> +}
> +
> +static inline void
> +drm_hdcp_helper_driver_unlock(struct drm_hdcp_helper_data *data)
> +{
> +	if (data->driver_mutex)
> +		mutex_unlock(data->driver_mutex);
> +}
> +
> +static int drm_hdcp_helper_enable_hdcp(struct drm_hdcp_helper_data *data,
> +				       struct drm_atomic_state *state,
> +				       struct mutex *driver_mutex)
> +{
> +	struct drm_connector *connector = data->connector;
> +	struct drm_connector_state *conn_state;
> +	struct drm_device *dev = connector->dev;
> +	unsigned long check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
> +	bool capable;
> +	int ret = 0;
> +
> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> +
> +	mutex_lock(&data->mutex);
> +
> +	if (data->value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> +		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_ENABLED,
> +				      true);
> +		goto out_data_mutex;
> +	}
> +
> +	drm_WARN_ON(dev, data->driver_mutex != NULL);
> +	data->driver_mutex = driver_mutex;
> +
> +	drm_hdcp_helper_driver_lock(data);
> +
> +	if (data->funcs->setup) {
> +		ret = data->funcs->setup(connector, state);
> +		if (ret) {
> +			drm_err(dev, "Failed to setup HDCP %d\n", ret);
> +			goto out;
> +		}
> +	}
> +
> +	if (!data->funcs->are_keys_valid ||
> +	    !data->funcs->are_keys_valid(connector)) {
> +		if (data->funcs->load_keys) {
> +			ret = data->funcs->load_keys(connector);
> +			if (ret) {
> +				drm_err(dev, "Failed to load HDCP keys %d\n",
> +					ret);
> +				goto out;
> +			}
> +		}
> +	}
> +
> +	/*
> +	 * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
> +	 * is capable of HDCP2.2, it is preferred to use HDCP2.2.
> +	 */
> +	ret = data->funcs->hdcp2_capable(connector, &capable);
> +	if (ret) {
> +		drm_err(dev, "HDCP 2.x capability check failed %d\n", ret);
> +		goto out;
> +	}
> +	if (capable) {
> +		data->enabled_type = DRM_MODE_HDCP_CONTENT_TYPE1;
> +		ret = data->funcs->hdcp2_enable(connector);
> +		if (!ret) {
> +			check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
> +			goto out;
> +		}
> +	}
> +
> +	/*
> +	 * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
> +	 * be attempted.
> +	 */
> +	ret = drm_hdcp_helper_hdcp1_capable(data, &capable);
> +	if (ret) {
> +		drm_err(dev, "HDCP 1.x capability check failed %d\n", ret);
> +		goto out;
> +	}
> +	if (capable &&
> +	    conn_state->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) {
> +		data->enabled_type = DRM_MODE_HDCP_CONTENT_TYPE0;
> +		ret = drm_hdcp_helper_hdcp1_enable(data);
> +		if (!ret)
> +			check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
> +	}
> +
> +out:
> +	if (!ret) {
> +		schedule_delayed_work(&data->check_work, check_link_interval);
> +		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_ENABLED,
> +				      true);
> +	}
> +
> +	drm_hdcp_helper_driver_unlock(data);
> +	if (ret)
> +		data->driver_mutex = NULL;
> +
> +out_data_mutex:
> +	mutex_unlock(&data->mutex);
> +	return ret;
> +}
> +
> +static int drm_hdcp_helper_disable_hdcp(struct drm_hdcp_helper_data *data)
> +{
> +	int ret = 0;
> +
> +	mutex_lock(&data->mutex);
> +	drm_hdcp_helper_driver_lock(data);
> +
> +	if (data->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> +		goto out;
> +
> +	drm_dbg_kms(data->connector->dev, "[%s:%d] HDCP is being disabled...\n",
> +		    data->connector->name, data->connector->base.id);
> +
> +	drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_UNDESIRED,
> +			      true);
> +
> +	if (data->enabled_type == DRM_MODE_HDCP_CONTENT_TYPE1)
> +		ret = data->funcs->hdcp2_disable(data->connector);
> +	else
> +		ret = data->funcs->hdcp1_disable(data->connector);
> +
> +	drm_dbg_kms(data->connector->dev, "HDCP is disabled\n");
> +
> +out:
> +	drm_hdcp_helper_driver_unlock(data);
> +	data->driver_mutex = NULL;
> +	mutex_unlock(&data->mutex);
> +	cancel_delayed_work_sync(&data->check_work);
> +	return ret;
> +}
> +
> +/**
> + * drm_hdcp_helper_atomic_commit - Helper for drivers to call during commit to
> + * enable/disable HDCP
> + *
> + * @data: pointer to the @drm_hdcp_helper_data for the connector
> + * @state: pointer to the atomic state being committed
> + * @driver_mutex: driver-provided lock to be used while interacting with the driver
> + *
> + * This function can be used by display drivers to determine when HDCP should be
> + * enabled or disabled based on the connector state. It should be called during
> + * steady-state commits as well as connector enable/disable. The function will
> + * handle the HDCP authentication/encryption logic, calling back into the driver
> + * when source operations are necessary.
> + *
> + * @driver_mutex will be retained and used for the duration of the HDCP session
> + * since it will be needed for link checks and retries. This mutex is useful if
> + * the driver has shared resources across connectors which must be serialized.
> + * For example, driver_mutex can be used for MST connectors sharing a common
> + * encoder which should not be accessed/changed concurrently. When the
> + * connector's session is torn down, the mutex will be forgotten by the helper
> + * for this connector until the next session.
> + */
> +void drm_hdcp_helper_atomic_commit(struct drm_hdcp_helper_data *data,
> +				   struct drm_atomic_state *state,
> +				   struct mutex *driver_mutex)
> +{
> +	struct drm_connector *connector = data->connector;
> +	struct drm_connector_state *conn_state;
> +	bool type_changed;
> +
> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> +
> +	type_changed = conn_state->hdcp_content_type != data->enabled_type;
> +
> +	if (conn_state->content_protection ==
> +	    DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> +		drm_hdcp_helper_disable_hdcp(data);
> +		return;
> +	}
> +
> +	if (!conn_state->crtc) {
> +		drm_hdcp_helper_disable_hdcp(data);
> +
> +		/* Restore property to DESIRED so it's retried later */
> +		if (conn_state->content_protection ==
> +		    DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> +			mutex_lock(&data->mutex);
> +			drm_hdcp_update_value(
> +				data, DRM_MODE_CONTENT_PROTECTION_DESIRED,
> +				true);
> +			mutex_unlock(&data->mutex);
> +		}
> +		return;
> +	}
> +
> +	/* Already enabled */
> +	if (conn_state->content_protection ==
> +	    DRM_MODE_CONTENT_PROTECTION_ENABLED)
> +		return;
> +
> +	/* Disable and re-enable HDCP on content type change */
> +	if (type_changed)
> +		drm_hdcp_helper_disable_hdcp(data);
> +
> +	drm_hdcp_helper_enable_hdcp(data, state, driver_mutex);
> +}
> +EXPORT_SYMBOL(drm_hdcp_helper_atomic_commit);
> +
> +static void drm_hdcp_helper_prop_work(struct work_struct *work)
> +{
> +	struct drm_hdcp_helper_data *data =
> +		container_of(work, struct drm_hdcp_helper_data, prop_work);
> +	struct drm_connector *connector = data->connector;
> +	struct drm_device *dev = connector->dev;
> +
> +	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> +	mutex_lock(&data->mutex);
> +
> +	/*
> +	 * This worker is only used to flip between ENABLED/DESIRED. Either of
> +	 * those to UNDESIRED is handled by core. If value == UNDESIRED,
> +	 * we're running just after hdcp has been disabled, so just exit
> +	 */
> +	if (data->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> +		drm_hdcp_update_content_protection(connector, data->value);
> +
> +	mutex_unlock(&data->mutex);
> +	drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +}
> +
> +static int drm_hdcp_hdcp1_check_link(struct drm_hdcp_helper_data *data)
> +{
> +	struct drm_connector *connector = data->connector;
> +	struct drm_device *dev = connector->dev;
> +	int ret;
> +
> +	if (data->funcs->hdcp1_check_link) {
> +		ret = data->funcs->hdcp1_check_link(connector);
> +		if (ret)
> +			goto retry;
> +	}
> +
> +	/* The link is checked differently for DP and HDMI */
> +	if (data->aux) {
> +		u8 bstatus;
> +		ret = drm_hdcp_remote_dpcd_read(data->aux, DP_AUX_HDCP_BSTATUS,
> +						&bstatus, 1);
> +		if (ret) {
> +			drm_err(dev, "Failed to read dpcd bstatus, %d\n", ret);
> +			return ret;
> +		}
> +		if (bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ))
> +			ret = -EINVAL;
> +	} else {
> +		ret = drm_hdcp_helper_hdcp1_validate_ri(data);
> +		if (ret)
> +			drm_err(dev, "Ri' mismatch, check failed (%d)\n", ret);
> +	}
> +	if (!ret)
> +		return 0;
> +
> +retry:
> +	drm_err(dev, "[%s:%d] HDCP link failed, retrying authentication\n",
> +		connector->name, connector->base.id);
> +
> +	ret = data->funcs->hdcp1_disable(connector);
> +	if (ret) {
> +		drm_err(dev, "Failed to disable hdcp (%d)\n", ret);
> +		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_DESIRED,
> +				      true);
> +		return ret;
> +	}
> +
> +	ret = drm_hdcp_helper_hdcp1_enable(data);
> +	if (ret) {
> +		drm_err(dev, "Failed to enable hdcp (%d)\n", ret);
> +		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_DESIRED,
> +				      true);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int drm_hdcp_hdcp2_check_link(struct drm_hdcp_helper_data *data)
> +{
> +	struct drm_connector *connector = data->connector;
> +	struct drm_device *dev = connector->dev;
> +	int ret;
> +
> +	ret = data->funcs->hdcp2_check_link(connector);
> +	if (!ret)
> +		return 0;
> +
> +	drm_err(dev, "[%s:%d] HDCP2 link failed, retrying authentication\n",
> +		connector->name, connector->base.id);
> +
> +	ret = data->funcs->hdcp2_disable(connector);
> +	if (ret) {
> +		drm_err(dev, "Failed to disable hdcp2 (%d)\n", ret);
> +		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_DESIRED,
> +				      true);
> +		return ret;
> +	}
> +
> +	ret = data->funcs->hdcp2_enable(connector);
> +	if (ret) {
> +		drm_err(dev, "Failed to enable hdcp2 (%d)\n", ret);
> +		drm_hdcp_update_value(data, DRM_MODE_CONTENT_PROTECTION_DESIRED,
> +				      true);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void drm_hdcp_helper_check_work(struct work_struct *work)
> +{
> +	struct drm_hdcp_helper_data *data = container_of(
> +		to_delayed_work(work), struct drm_hdcp_helper_data, check_work);
> +	unsigned long check_link_interval;
> +
> +	mutex_lock(&data->mutex);
> +	if (data->value != DRM_MODE_CONTENT_PROTECTION_ENABLED)
> +		goto out_data_mutex;
> +
> +	drm_hdcp_helper_driver_lock(data);
> +
> +	if (data->enabled_type == DRM_MODE_HDCP_CONTENT_TYPE1) {
> +		if (drm_hdcp_hdcp2_check_link(data))
> +			goto out;
> +		check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
> +	} else {
> +		if (drm_hdcp_hdcp1_check_link(data))
> +			goto out;
> +		check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
> +	}
> +	schedule_delayed_work(&data->check_work, check_link_interval);
> +
> +out:
> +	drm_hdcp_helper_driver_unlock(data);
> +out_data_mutex:
> +	mutex_unlock(&data->mutex);
> +}
> +
> +/**
> + * drm_hdcp_helper_schedule_hdcp_check - Schedule a check link cycle.
> + *
> + * @data: Pointer to the HDCP helper data.
> + *
> + * This function will kick off a check link cycle on behalf of the caller. This
> + * can be used by DP short hpd interrupt handlers, where the driver must poke
> + * the helper to check the link is still valid.
> + */
> +void drm_hdcp_helper_schedule_hdcp_check(struct drm_hdcp_helper_data *data)
> +{
> +	schedule_delayed_work(&data->check_work, 0);
> +}
> +EXPORT_SYMBOL(drm_hdcp_helper_schedule_hdcp_check);
> +
> +static struct drm_hdcp_helper_data *
> +drm_hdcp_helper_initialize(struct drm_connector *connector,
> +			   const struct drm_hdcp_helper_funcs *funcs,
> +			   bool attach_content_type_property)

The argument is misnamed. The called function 
drm_connector_attach_content_protection_property() uses different name, 
better use it instead. Also why would anyone (drm/msm?) not want the 
Conent Type propery?

> +{
> +	struct drm_hdcp_helper_data *out;
> +	int ret;
> +
> +	out = kzalloc(sizeof(*out), GFP_KERNEL);
> +	if (!out)
> +		return ERR_PTR(-ENOMEM);
> +
> +	out->connector = connector;
> +	out->funcs = funcs;
> +
> +	mutex_init(&out->mutex);
> +	out->value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
> +
> +	INIT_DELAYED_WORK(&out->check_work, drm_hdcp_helper_check_work);
> +	INIT_WORK(&out->prop_work, drm_hdcp_helper_prop_work);
> +
> +	ret = drm_connector_attach_content_protection_property(
> +		connector, attach_content_type_property);
> +	if (ret) {
> +		drm_hdcp_helper_destroy(out);
> +		return ERR_PTR(ret);
> +	}
> +
> +	return out;
> +}
> +
> +/**
> + * drm_hdcp_helper_initialize_dp - Initializes the HDCP helpers for a
> + * DisplayPort connector
> + *
> + * @connector: pointer to the DisplayPort connector.
> + * @funcs: pointer to the vtable of HDCP helper funcs for this connector.
> + * @attach_content_type_property: True if the content_type property should be
> + * attached.
> + *
> + * This function initializes the HDCP helper for the given DisplayPort connector.
> + * This involves creating the Content Protection property as well as the Content
> + * Type property (if desired). Upon success, it will return a pointer to the
> + * HDCP helper data. Ownership of the underlying memory is ttransferredto the
> + * caller and should be freed using drm_hdcp_helper_destroy().
> + *
> + * Returns:
> + * Pointer to newly created HDCP helper data. PTR_ERR on failure.
> + */
> +struct drm_hdcp_helper_data *
> +drm_hdcp_helper_initialize_dp(struct drm_connector *connector,
> +			      struct drm_dp_aux *aux,
> +			      const struct drm_hdcp_helper_funcs *funcs,
> +			      bool attach_content_type_property)
> +{
> +	struct drm_hdcp_helper_data *out;
> +
> +	out = drm_hdcp_helper_initialize(connector, funcs,
> +					 attach_content_type_property);
> +	if (IS_ERR(out))
> +		return out;
> +
> +	out->aux = aux;
> +	out->hdcp1_lut = &drm_hdcp_hdcp1_dpcd_lut;
> +
> +	return out;
> +}
> +EXPORT_SYMBOL(drm_hdcp_helper_initialize_dp);
> +
> +/**
> + * drm_hdcp_helper_initialize_hdmi - Initializes the HDCP helpers for an HDMI
> + * connector
> + *
> + * @connector: pointer to the HDMI connector.
> + * @funcs: pointer to the vtable of HDCP helper funcs for this connector.
> + * @attach_content_type_property: True if the content_type property should be
> + * attached.
> + *
> + * This function initializes the HDCP helper for the given HDMI connector. This
> + * involves creating the Content Protection property as well as the Content Type
> + * property (if desired). Upon success, it will return a pointer to the HDCP
> + * helper data. Ownership of the underlying memory is transferred to the caller
> + * and should be freed using drm_hdcp_helper_destroy().
> + *
> + * Returns:
> + * Pointer to newly created HDCP helper data. PTR_ERR on failure.
> + */
> +struct drm_hdcp_helper_data *
> +drm_hdcp_helper_initialize_hdmi(struct drm_connector *connector,
> +				const struct drm_hdcp_helper_funcs *funcs,
> +				bool attach_content_type_property)
> +{
> +	struct drm_hdcp_helper_data *out;
> +
> +	out = drm_hdcp_helper_initialize(connector, funcs,
> +					 attach_content_type_property);
> +	if (IS_ERR(out))
> +		return out;
> +
> +	out->hdcp1_lut = &drm_hdcp_hdcp1_ddc_lut;
> +
> +	return out;
> +}
> +EXPORT_SYMBOL(drm_hdcp_helper_initialize_hdmi);
> +
> +/**
> + * drm_hdcp_helper_destroy - Destroys the given HDCP helper data.
> + *
> + * @data: Pointer to the HDCP helper data.
> + *
> + * This function cleans up and destroys the HDCP helper data created by
> + * drm_hdcp_helper_initialize_dp() or drm_hdcp_helper_initialize_hdmi().
> + */
> +void drm_hdcp_helper_destroy(struct drm_hdcp_helper_data *data)
> +{
> +	struct drm_connector *connector;
> +
> +	if (!data)
> +		return;
> +
> +	connector = data->connector;
> +
> +	/*
> +	 * If the connector is registered, it's possible userspace could kick
> +	 * off another HDCP enable, which would re-spawn the workers.
> +	 */
> +	drm_WARN_ON(connector->dev,
> +		    connector->registration_state == DRM_CONNECTOR_REGISTERED);
> +
> +	/*
> +	 * Now that the connector is not registered, check_work won't be run,
> +	 * but cancel any outstanding instances of it
> +	 */
> +	cancel_delayed_work_sync(&data->check_work);
> +
> +	/*
> +	 * We don't cancel prop_work in the same way as check_work since it
> +	 * requires connection_mutex which could be held while calling this
> +	 * function. Instead, we rely on the connector references grabbed before
> +	 * scheduling prop_work to ensure the connector is alive when prop_work
> +	 * is run. So if we're in the destroy path (which is where this
> +	 * function should be called), we're "guaranteed" that prop_work is not
> +	 * active (tl;dr This Should Never Happen).
> +	 */
> +	drm_WARN_ON(connector->dev, work_pending(&data->prop_work));
> +
> +	kfree(data);
> +}
> +EXPORT_SYMBOL(drm_hdcp_helper_destroy);
> diff --git a/include/drm/display/drm_hdcp.h b/include/drm/display/drm_hdcp.h
> index 96a99b1377c0..75694baf72d4 100644
> --- a/include/drm/display/drm_hdcp.h
> +++ b/include/drm/display/drm_hdcp.h
> @@ -36,6 +36,7 @@
>   #define DRM_HDCP_DDC_BKSV			0x00
>   #define DRM_HDCP_DDC_RI_PRIME			0x08
>   #define DRM_HDCP_DDC_AKSV			0x10
> +#define DRM_HDCP_DDC_AINFO			0x15
>   #define DRM_HDCP_DDC_AN				0x18
>   #define DRM_HDCP_DDC_V_PRIME(h)			(0x20 + h * 4)
>   #define DRM_HDCP_DDC_BCAPS			0x40
> @@ -123,6 +124,19 @@
>   #define HDCP_2_2_DEV_COUNT_HI(x)		((x) & BIT(0))
>   #define HDCP_2_2_DEPTH(x)			(((x) & (0x7 << 1)) >> 1)
>   
> +struct drm_hdcp_ksv {
> +	union {
> +		u32 words[2];
> +		u8 bytes[DRM_HDCP_KSV_LEN];
> +	};
> +};
> +struct drm_hdcp_an {
> +	union {
> +		u32 words[2];
> +		u8 bytes[DRM_HDCP_AN_LEN];
> +	};
> +};
> +
>   struct hdcp2_cert_rx {
>   	u8	receiver_id[HDCP_2_2_RECEIVER_ID_LEN];
>   	u8	kpub_rx[HDCP_2_2_K_PUB_RX_LEN];
> @@ -295,4 +309,156 @@ struct hdcp_srm_header {
>   #define DRM_MODE_HDCP_CONTENT_TYPE0		0
>   #define DRM_MODE_HDCP_CONTENT_TYPE1		1
>   
> -#endif
> +struct drm_connector;
> +struct drm_atomic_state;
> +
> +/**
> + * struct drm_hdcp_helper_funcs - A vtable of function hooks for the hdcp helper
> + *
> + * These hooks are used by the hdcp helper to call into the driver/connector
> + * code to read/write to hw.
> + */
> +struct drm_hdcp_helper_funcs {
> +	/**
> +	 * @setup - Performs driver-specific setup before hdcp is enabled
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*setup)(struct drm_connector *connector,
> +		     struct drm_atomic_state *state);

I think all the troubles of the drm/msm code trying to get dp_display 
from drm_connector could have been avoided if this API allowed one to 
pass private data. This is not the case for Intel, but in drm/msm case 
we have a chain of bridges, so establishing a link from connector to the 
driver's private data is not an obvious thing.

> +
> +	/**
> +	 * @are_keys_valid - Checks if the HDCP transmitter keys are valid
> +	 *
> +	 * Returns: true if the display controller has valid keys loaded
> +	 */
> +	bool (*are_keys_valid)(struct drm_connector *connector);
> +
> +	/**
> +	 * @load_keys - Instructs the driver to load its HDCP transmitter keys
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*load_keys)(struct drm_connector *connector);
> +
> +	/**
> +	 * @hdcp2_capable - Checks if both source and sink support HDCP 2.x
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp2_capable)(struct drm_connector *connector, bool *capable);
> +
> +	/**
> +	 * @hdcp2_enable - Enables HDCP 2.x on the specified connector
> +	 *
> +	 * Since we don't have multiple examples of HDCP 2.x enablement, we
> +	 * provide the bare minimum support for HDCP 2.x help. Once we have
> +	 * more examples, perhaps we can be more helpful.
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp2_enable)(struct drm_connector *connector);
> +
> +	/**
> +	 * @hdcp2_check_link - Checks the HDCP 2.x link on a specified connector
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp2_check_link)(struct drm_connector *connector);
> +
> +	/**
> +	 * @hdcp2_disable - Disables HDCP 2.x on the specified connector
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp2_disable)(struct drm_connector *connector);
> +
> +	/**
> +	 * @hdcp1_read_an_aksv - Reads transmitter's An & Aksv from hardware
> +	 *
> +	 * Use this function if hardware allows reading the transmitter's An and
> +	 * Aksv values from the kernel. If your hardware will not allow this,
> +	 * use hdcp1_send_an_aksv() and implement the transmission in the
> +	 * driver.
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp1_read_an_aksv)(struct drm_connector *connector, u32 *an,
> +				  u32 *aksv);
> +
> +	/**
> +	 * @hdcp1_send_an_aksv - Sends transmitter's An & Aksv to the receiver
> +	 *
> +	 * Only implement this on hardware where An or Aksv are not accessible
> +	 * from the kernel. If these values can be read, use
> +	 * hdcp1_read_an_aksv() instead.
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp1_send_an_aksv)(struct drm_connector *connector);
> +
> +	/**
> +	 * @hdcp1_store_receiver_info - Stores the receiver's info in the transmitter
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp1_store_receiver_info)(struct drm_connector *connector,
> +					 u32 *ksv, u32 status, u8 caps,
> +					 bool repeater_present);
> +
> +	/**
> +	 * @hdcp1_enable_encryption - Enables encryption of the outgoing signal
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp1_enable_encryption)(struct drm_connector *connector);
> +
> +	/**
> +	 * @hdcp1_wait_for_r0 - Wait for transmitter to calculate R0
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp1_wait_for_r0)(struct drm_connector *connector);
> +
> +	/**
> +	 * @hdcp1_match_ri - Matches the given Ri from the receiver with Ri in
> +	 * the transmitter
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp1_match_ri)(struct drm_connector *connector, u32 ri_prime);
> +
> +	/**
> +	 * @hdcp1_post_encryption - Allows the driver to confirm encryption and
> +	 * perform any post-processing
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp1_post_encryption)(struct drm_connector *connector);
> +
> +	/**
> +	 * @hdcp1_store_ksv_fifo - Write the receiver's KSV list to transmitter
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp1_store_ksv_fifo)(struct drm_connector *connector,
> +				    u8 *ksv_fifo, u8 num_downstream,
> +				    u8 *bstatus, u32 *vprime);
> +
> +	/**
> +	 * @hdcp1_check_link - Allows the driver to check the HDCP 1.x status
> +	 * on a specified connector
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp1_check_link)(struct drm_connector *connector);
> +
> +	/**
> +	 * @hdcp1_disable - Disables HDCP 1.x on the specified connector
> +	 *
> +	 * Returns: 0 on success, -errno on failure
> +	 */
> +	int (*hdcp1_disable)(struct drm_connector *connector);
> +};
> +
> +#endif  // INCLUDE_DRM_DISPLAY_DRM_HDCP_H_
> diff --git a/include/drm/display/drm_hdcp_helper.h b/include/drm/display/drm_hdcp_helper.h
> index cb2cc5002f65..dbbaced148f2 100644
> --- a/include/drm/display/drm_hdcp_helper.h
> +++ b/include/drm/display/drm_hdcp_helper.h
> @@ -15,11 +15,39 @@ struct drm_atomic_state;
>   struct drm_device;
>   struct drm_connector;
>   
> +struct drm_hdcp_helper_data;
> +struct drm_dp_aux;
> +struct i2c_adapter;
> +struct mutex;
> +
>   int drm_hdcp_check_ksvs_revoked(struct drm_device *dev, u8 *ksvs, u32 ksv_count);
>   int drm_connector_attach_content_protection_property(struct drm_connector *connector,
>   						     bool hdcp_content_type);
>   void drm_hdcp_update_content_protection(struct drm_connector *connector, u64 val);
>   bool drm_hdcp_atomic_check(struct drm_connector *connector,
>   			   struct drm_atomic_state *state);
> +void drm_hdcp_atomic_commit(struct drm_atomic_state *state,
> +			    struct drm_connector *connector);
> +
> +struct drm_hdcp_helper_data *
> +drm_hdcp_helper_initialize_dp(struct drm_connector *connector,
> +			      struct drm_dp_aux *aux,
> +			      const struct drm_hdcp_helper_funcs *funcs,
> +			      bool attach_content_type_property);
> +
> +struct drm_hdcp_helper_data *
> +drm_hdcp_helper_initialize_hdmi(struct drm_connector *connector,
> +				const struct drm_hdcp_helper_funcs *funcs,
> +				bool attach_content_type_property);
> +
> +void drm_hdcp_helper_destroy(struct drm_hdcp_helper_data *data);
> +
> +int drm_hdcp_helper_hdcp1_capable(struct drm_hdcp_helper_data *data,
> +				  bool *capable);
> +void drm_hdcp_helper_atomic_commit(struct drm_hdcp_helper_data *data,
> +				   struct drm_atomic_state *state,
> +				   struct mutex *driver_mutex);
> +
> +void drm_hdcp_helper_schedule_hdcp_check(struct drm_hdcp_helper_data *data);
>   
> -#endif
> +#endif  // INCLUDE_DRM_DISPLAY_DRM_HDCP_HELPER_H_"

Not related.

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
  2023-01-19 10:37   ` Krzysztof Kozlowski
@ 2023-01-20 15:32     ` Sean Paul
  2023-01-20 20:33       ` Dmitry Baryshkov
  0 siblings, 1 reply; 38+ messages in thread
From: Sean Paul @ 2023-01-20 15:32 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx, robdclark, quic_abhinavk,
	dmitry.baryshkov, sean, airlied, daniel, robh+dt,
	krzysztof.kozlowski+dt, agross, andersson, konrad.dybcio,
	jani.nikula, joonas.lahtinen, rodrigo.vivi, tvrtko.ursulin,
	tzimmermann, ville.syrjala, stanislav.lisovskiy, matthew.d.roper,
	imre.deak, lucas.demarchi, manasi.d.navare, swati2.sharma,
	bhanuprakash.modem, javierm, jose.souza, lyude, hbh25y,
	arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime, swboyd,
	christophe.jaillet, quic_sbillaka, johan+linaro, dianders, marex,
	quic_jesszhan, bjorn.andersson, abhinavk, seanpaul, Jani Nikula

On Thu, Jan 19, 2023 at 11:37:52AM +0100, Krzysztof Kozlowski wrote:
> On 18/01/2023 20:30, Mark Yacoub wrote:
> > From: Sean Paul <seanpaul@chromium.org>
> > 
> > This patch moves the hdcp atomic check from i915 to drm_hdcp so other
> > drivers can use it. No functional changes, just cleaned up some of the
> > code when moving it over.
> > 
> > Acked-by: Jani Nikula <jani.nikula@intel.com>
> > Acked-by: Jani Nikula <jani.nikula@intel.com>
> > Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > Reviewed-by: Abhinav Kumar <abhinavk@codeaurora.org>
> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> > Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-2-sean@poorly.run #v1
> > Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-2-sean@poorly.run #v2
> > Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-2-sean@poorly.run #v3
> > Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-2-sean@poorly.run #v4
> > Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-2-sean@poorly.run #v5
> 
> It seems all your previous versions were sent not to correct people and
> lists. Therefore we see it for the first time even though it is v6! 

Hi Krzysztof,
Thanks for your review comments.

Here are the addresses the last version was sent to, who is missing?

To: dri-devel@lists.freedesktop.org, 
    jani.nikula@intel.com,
    intel-gfx@lists.freedesktop.org,
    freedreno@lists.freedesktop.org,
    rodrigo.vivi@intel.com
Cc: bjorn.andersson@linaro.org, 
    swboyd@chromium.org,
    abhinavk@codeaurora.org,
    markyacoub@chromium.org,
    Sean Paul <seanpaul@chromium.org>,
    Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
    Maxime Ripard <mripard@kernel.org>,
    Thomas Zimmermann <tzimmermann@suse.de>,
    David Airlie <airlied@linux.ie>,
    Daniel Vetter <daniel@ffwll.ch>,
    Jani Nikula <jani.nikula@linux.intel.com>,
    Joonas Lahtinen <joonas.lahtinen@linux.intel.com>,
    Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>

> It's
> not the first such weird CC list in chromium, so maybe your
> organisational process could be improved? Not only for you but for
> colleagues as well, so you all start using get_maintainers.pl on newest
> kernel (not something ancient)?

I can't really speak for others, but I use MAINTAINERS from drm-tip. The 
previous patch sets were sent before 24df12013853 ("MAINTAINERS: Add 
Dmitry as MSM DRM driver co-maintainer"), which might explain why you think
there are absences?

Thanks again,

Sean

> 
> Best regards,
> Krzysztof
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller
  2023-01-19 10:35   ` Krzysztof Kozlowski
@ 2023-01-20 15:54     ` Sean Paul
  2023-01-21 10:16       ` Dmitry Baryshkov
  2023-01-21 19:06       ` Krzysztof Kozlowski
  0 siblings, 2 replies; 38+ messages in thread
From: Sean Paul @ 2023-01-20 15:54 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx, robdclark, quic_abhinavk,
	dmitry.baryshkov, sean, airlied, daniel, robh+dt,
	krzysztof.kozlowski+dt, agross, andersson, konrad.dybcio,
	jani.nikula, joonas.lahtinen, rodrigo.vivi, tvrtko.ursulin,
	tzimmermann, ville.syrjala, stanislav.lisovskiy, matthew.d.roper,
	imre.deak, lucas.demarchi, manasi.d.navare, swati2.sharma,
	bhanuprakash.modem, javierm, jose.souza, lyude, hbh25y,
	arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime, swboyd,
	christophe.jaillet, quic_sbillaka, johan+linaro, dianders, marex,
	quic_jesszhan, bjorn.andersson, abhinavk, seanpaul

On Thu, Jan 19, 2023 at 11:35:32AM +0100, Krzysztof Kozlowski wrote:
> On 18/01/2023 20:30, Mark Yacoub wrote:
> > From: Sean Paul <seanpaul@chromium.org>
> > 
> > This patch adds the register ranges required for HDCP key injection and
> 
> Do not use "This commit/patch".
> https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95
> 
> This applies to all your patches. Fix it everywhere.

My goodness, this is peak bikeshedding. Surely we have better things to do with
our time?

> 
> > HDCP TrustZone interaction as described in the dt-bindings for the
> > sc7180 dp controller. Now that these are supported, change the
> > compatible string to "dp-hdcp".
> 
> What does it mean? Where do you do it?
> 
> > 
> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> > Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-15-sean@poorly.run #v1
> > Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-14-sean@poorly.run #v2
> > Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-14-sean@poorly.run #v3
> > Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-14-sean@poorly.run #v4
> > Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-10-sean@poorly.run #v5
> 
> Drop the links.

Why? I've always done this, it seems helpful to me?

> 
> > 
> > Changes in v3:
> > -Split off into a new patch containing just the dts change (Stephen)
> > -Add hdcp compatible string (Stephen)
> > Changes in v4:
> > -Rebase on Bjorn's multi-dp patchset
> > Changes in v5:
> > -Put the tz register offsets in trogdor dtsi (Rob C)
> > Changes in v6:
> > -Rebased: Removed modifications in sc7180.dtsi as it's already upstream
> > 
> > ---
> 
> Changelog after --- .

It's common practice in drm subsystem to include this in the commit message.

Sean


> 
> >  arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi | 8 ++++++++
> >  1 file changed, 8 insertions(+)
> > 
> 
> Best regards,
> Krzysztof
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
  2023-01-20 15:32     ` Sean Paul
@ 2023-01-20 20:33       ` Dmitry Baryshkov
  0 siblings, 0 replies; 38+ messages in thread
From: Dmitry Baryshkov @ 2023-01-20 20:33 UTC (permalink / raw)
  To: Sean Paul, Krzysztof Kozlowski
  Cc: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx, robdclark, quic_abhinavk,
	sean, airlied, daniel, robh+dt, krzysztof.kozlowski+dt, agross,
	andersson, konrad.dybcio, jani.nikula, joonas.lahtinen,
	rodrigo.vivi, tvrtko.ursulin, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul, Jani Nikula



On 20 January 2023 18:32:47 GMT+03:00, Sean Paul <sean@poorly.run> wrote:
>On Thu, Jan 19, 2023 at 11:37:52AM +0100, Krzysztof Kozlowski wrote:
>> On 18/01/2023 20:30, Mark Yacoub wrote:
>> > From: Sean Paul <seanpaul@chromium.org>
>> > 
>> > This patch moves the hdcp atomic check from i915 to drm_hdcp so other
>> > drivers can use it. No functional changes, just cleaned up some of the
>> > code when moving it over.
>> > 
>> > Acked-by: Jani Nikula <jani.nikula@intel.com>
>> > Acked-by: Jani Nikula <jani.nikula@intel.com>
>> > Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
>> > Reviewed-by: Abhinav Kumar <abhinavk@codeaurora.org>
>> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
>> > Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
>> > Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-2-sean@poorly.run #v1
>> > Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-2-sean@poorly.run #v2
>> > Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-2-sean@poorly.run #v3
>> > Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-2-sean@poorly.run #v4
>> > Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-2-sean@poorly.run #v5
>> 
>> It seems all your previous versions were sent not to correct people and
>> lists. Therefore we see it for the first time even though it is v6! 
>
>Hi Krzysztof,
>Thanks for your review comments.
>
>Here are the addresses the last version was sent to, who is missing?
>
>To: dri-devel@lists.freedesktop.org, 
>    jani.nikula@intel.com,
>    intel-gfx@lists.freedesktop.org,
>    freedreno@lists.freedesktop.org,
>    rodrigo.vivi@intel.com
>Cc: bjorn.andersson@linaro.org, 
>    swboyd@chromium.org,
>    abhinavk@codeaurora.org,
>    markyacoub@chromium.org,
>    Sean Paul <seanpaul@chromium.org>,
>    Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
>    Maxime Ripard <mripard@kernel.org>,
>    Thomas Zimmermann <tzimmermann@suse.de>,
>    David Airlie <airlied@linux.ie>,
>    Daniel Vetter <daniel@ffwll.ch>,
>    Jani Nikula <jani.nikula@linux.intel.com>,
>    Joonas Lahtinen <joonas.lahtinen@linux.intel.com>,
>    Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
>
>> It's
>> not the first such weird CC list in chromium, so maybe your
>> organisational process could be improved? Not only for you but for
>> colleagues as well, so you all start using get_maintainers.pl on newest
>> kernel (not something ancient)?
>
>I can't really speak for others, but I use MAINTAINERS from drm-tip. The 
>previous patch sets were sent before 24df12013853 ("MAINTAINERS: Add 
>Dmitry as MSM DRM driver co-maintainer"), which might explain why you think
>there are absences?

Current iteration of the patchset got at least three addresses wrong. They have been changed for various reasons. Thus I also can suppose that the list is incomplete and/or incorrect.

>
>Thanks again,
>
>Sean
>
>> 
>> Best regards,
>> Krzysztof
>> 
>

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller
  2023-01-20 15:54     ` Sean Paul
@ 2023-01-21 10:16       ` Dmitry Baryshkov
  2023-01-21 19:06       ` Krzysztof Kozlowski
  1 sibling, 0 replies; 38+ messages in thread
From: Dmitry Baryshkov @ 2023-01-21 10:16 UTC (permalink / raw)
  To: Sean Paul, Krzysztof Kozlowski
  Cc: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx, robdclark, quic_abhinavk,
	airlied, daniel, robh+dt, krzysztof.kozlowski+dt, agross,
	andersson, konrad.dybcio, jani.nikula, joonas.lahtinen,
	rodrigo.vivi, tvrtko.ursulin, tzimmermann, ville.syrjala,
	stanislav.lisovskiy, matthew.d.roper, imre.deak, lucas.demarchi,
	manasi.d.navare, swati2.sharma, bhanuprakash.modem, javierm,
	jose.souza, lyude, hbh25y, arun.r.murthy, ashutosh.dixit,
	ankit.k.nautiyal, maxime, swboyd, christophe.jaillet,
	quic_sbillaka, johan+linaro, dianders, marex, quic_jesszhan,
	bjorn.andersson, abhinavk, seanpaul

On 20/01/2023 17:54, Sean Paul wrote:
> On Thu, Jan 19, 2023 at 11:35:32AM +0100, Krzysztof Kozlowski wrote:
>> On 18/01/2023 20:30, Mark Yacoub wrote:
>>> From: Sean Paul <seanpaul@chromium.org>
>>>
>>> This patch adds the register ranges required for HDCP key injection and
>>
>> Do not use "This commit/patch".
>> https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95
>>
>> This applies to all your patches. Fix it everywhere.
> 
> My goodness, this is peak bikeshedding. Surely we have better things to do with
> our time?

While I would not enforce this rule if there were no other issues with 
the commits, Mark will have to cleanup/rework commits anyway, see other 
review comments. Thus removing/slightly rephrasing a commit message 
sounds like a minor issue to me.

>>>
>>> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>>> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
>>> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-15-sean@poorly.run #v1
>>> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-14-sean@poorly.run #v2
>>> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-14-sean@poorly.run #v3
>>> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-14-sean@poorly.run #v4
>>> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-10-sean@poorly.run #v5
>>
>> Drop the links.
> 
> Why? I've always done this, it seems helpful to me?
> 

I'd say, if you wish to include them, they belong to the cover letter, 
not to the per-commit message. Once landed, they will serve no purpose.

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller
  2023-01-20 15:54     ` Sean Paul
  2023-01-21 10:16       ` Dmitry Baryshkov
@ 2023-01-21 19:06       ` Krzysztof Kozlowski
  1 sibling, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-21 19:06 UTC (permalink / raw)
  To: Sean Paul
  Cc: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx, robdclark, quic_abhinavk,
	dmitry.baryshkov, airlied, daniel, robh+dt,
	krzysztof.kozlowski+dt, agross, andersson, konrad.dybcio,
	jani.nikula, joonas.lahtinen, rodrigo.vivi, tvrtko.ursulin,
	tzimmermann, ville.syrjala, stanislav.lisovskiy, matthew.d.roper,
	imre.deak, lucas.demarchi, manasi.d.navare, swati2.sharma,
	bhanuprakash.modem, javierm, jose.souza, lyude, hbh25y,
	arun.r.murthy, ashutosh.dixit, ankit.k.nautiyal, maxime, swboyd,
	christophe.jaillet, quic_sbillaka, johan+linaro, dianders, marex,
	quic_jesszhan, bjorn.andersson, abhinavk, seanpaul

On 20/01/2023 16:54, Sean Paul wrote:
> On Thu, Jan 19, 2023 at 11:35:32AM +0100, Krzysztof Kozlowski wrote:
>> On 18/01/2023 20:30, Mark Yacoub wrote:
>>> From: Sean Paul <seanpaul@chromium.org>
>>>
>>> This patch adds the register ranges required for HDCP key injection and
>>
>> Do not use "This commit/patch".
>> https://elixir.bootlin.com/linux/v5.17.1/source/Documentation/process/submitting-patches.rst#L95
>>
>> This applies to all your patches. Fix it everywhere.
> 
> My goodness, this is peak bikeshedding. Surely we have better things to do with
> our time?

What do you mean "better things to do"? I review the patches as that's
expected from maintainer. I spend a lot of time on so indeed I could
find some other ways to use it.

I spot something which is obvious mistake, although trivial and not
important, but clicking automated answer is also trivial for me and
fast. And yes. 90% of my reviews answers are automated because people
cannot learn to test before sending, cannot learn to read Submitting
Patches and many other trivial things. Clicking this automated answer
was also trivial from my point, but entire discussion including your
disagreement about incorrect title (read Submitting Patches) instead of
just implementing it - is waste of time.

I'll then consider not wasting time on your patches.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Intel-gfx] [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915
  2023-01-18 19:30 ` [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915 Mark Yacoub
@ 2023-01-31 17:16   ` Rodrigo Vivi
  2023-01-31 17:23     ` Rodrigo Vivi
  2023-03-14  5:54   ` Kandpal, Suraj
  1 sibling, 1 reply; 38+ messages in thread
From: Rodrigo Vivi @ 2023-01-31 17:16 UTC (permalink / raw)
  To: Mark Yacoub
  Cc: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx, quic_sbillaka, konrad.dybcio,
	bjorn.andersson, krzysztof.kozlowski+dt, airlied, hbh25y, marex,
	abhinavk, javierm, agross, quic_jesszhan, daniel, Jani Nikula,
	lucas.demarchi, quic_abhinavk, swboyd, robh+dt,
	christophe.jaillet, maxime, johan+linaro, andersson, dianders,
	tzimmermann, dmitry.baryshkov, seanpaul


+Suraj who is also working on HDCP related code that even can conflict
wit this.

On Wed, Jan 18, 2023 at 07:30:12PM +0000, Mark Yacoub wrote:
> From: Sean Paul <seanpaul@chromium.org>

First of all, Sean, please accept my public apologies here. I just noticed
now that you had pinged me 9 *months* ago!
I noticed while taking a look to the history to refresh my mind around
this series.

> 
> Now that all of the HDCP 1.x logic has been migrated to the central HDCP
> helpers, use it in the i915 driver.
> 
> The majority of the driver code for HDCP 1.x will live in intel_hdcp.c,
> however there are a few helper hooks which are connector-specific and
> need to be partially or fully implemented in the intel_dp_hdcp.c or
> intel_hdmi.c.

so far so good! we need to do this soon.

> 
> We'll leave most of the HDCP 2.x code alone since we don't have another
> implementation of HDCP 2.x to use as reference for what should and
> should not live in the drm helpers. The helper will call the overly
> general enable/disable/is_capable HDCP 2.x callbacks and leave the
> interesting stuff for the driver. Once we have another HDCP 2.x
> implementation, we should do a similar migration.

I believe this part is the part that I start to get lost when
trying to review it.

Mark told me in irc that it is really hard to split this patch,
but do we really need to have the hdcp 1.x changes along with the
2.x? I start to get lost in the review when I see the changes around
the hdcp2_capable...

So, it would be really really good if we can split this patch.

> 
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>

Cc: Suraj Kandpal <suraj.kandpal@intel.com>

> Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-8-sean@poorly.run #v1
> Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-8-sean@poorly.run #v2
> Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-8-sean@poorly.run #v3
> Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-8-sean@poorly.run #v4
> Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-8-sean@poorly.run #v5
> 
> Changes in v2:
> -Fix mst helper function pointer reported by 0-day
> Changes in v3:
> -Add forward declaration for drm_atomic_state in intel_hdcp.h identified
>  by 0-day
> Changes in v4:
> -None
> Changes in v5:
> -None
> Changes in v6:
> -Rebased.
> 
> ---
>  drivers/gpu/drm/i915/display/intel_ddi.c      |  32 +-
>  .../drm/i915/display/intel_display_debugfs.c  |   6 +-
>  .../drm/i915/display/intel_display_types.h    |  60 +-
>  drivers/gpu/drm/i915/display/intel_dp_hdcp.c  | 348 +++----
>  drivers/gpu/drm/i915/display/intel_dp_mst.c   |  16 +-
>  drivers/gpu/drm/i915/display/intel_hdcp.c     | 952 +++---------------
>  drivers/gpu/drm/i915/display/intel_hdcp.h     |  31 +-
>  drivers/gpu/drm/i915/display/intel_hdmi.c     | 270 ++---
>  8 files changed, 445 insertions(+), 1270 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
> index 69ecf2a3d6c6..a4397f066a3e 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -28,6 +28,7 @@
>  #include <linux/string_helpers.h>
>  
>  #include <drm/display/drm_scdc_helper.h>
> +#include <drm/display/drm_hdcp_helper.h>
>  #include <drm/drm_privacy_screen_consumer.h>
>  
>  #include "i915_drv.h"
> @@ -2909,6 +2910,10 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
>  			     const struct intel_crtc_state *crtc_state,
>  			     const struct drm_connector_state *conn_state)
>  {
> +	struct intel_connector *connector =
> +		to_intel_connector(conn_state->connector);
> +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> +
>  	drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
>  
>  	if (!intel_crtc_is_bigjoiner_slave(crtc_state))
> @@ -2925,12 +2930,10 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
>  	else
>  		intel_enable_ddi_dp(state, encoder, crtc_state, conn_state);
>  
> -	/* Enable hdcp if it's desired */
> -	if (conn_state->content_protection ==
> -	    DRM_MODE_CONTENT_PROTECTION_DESIRED)
> -		intel_hdcp_enable(to_intel_connector(conn_state->connector),
> -				  crtc_state,
> -				  (u8)conn_state->hdcp_content_type);
> +	if (connector->hdcp_helper_data)
> +		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
> +					      &state->base,
> +					      &dig_port->hdcp_mutex);
>  }
>  
>  static void intel_disable_ddi_dp(struct intel_atomic_state *state,
> @@ -2976,7 +2979,14 @@ static void intel_disable_ddi(struct intel_atomic_state *state,
>  			      const struct intel_crtc_state *old_crtc_state,
>  			      const struct drm_connector_state *old_conn_state)
>  {
> -	intel_hdcp_disable(to_intel_connector(old_conn_state->connector));
> +	struct intel_connector *connector =
> +		to_intel_connector(old_conn_state->connector);
> +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> +
> +	if (connector->hdcp_helper_data)
> +		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
> +					      &state->base,
> +					      &dig_port->hdcp_mutex);
>  
>  	if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
>  		intel_disable_ddi_hdmi(state, encoder, old_crtc_state,
> @@ -3004,13 +3014,19 @@ void intel_ddi_update_pipe(struct intel_atomic_state *state,
>  			   const struct intel_crtc_state *crtc_state,
>  			   const struct drm_connector_state *conn_state)
>  {
> +	struct intel_connector *connector =
> +		to_intel_connector(conn_state->connector);
> +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
>  
>  	if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
>  	    !intel_encoder_is_mst(encoder))
>  		intel_ddi_update_pipe_dp(state, encoder, crtc_state,
>  					 conn_state);
>  
> -	intel_hdcp_update_pipe(state, encoder, crtc_state, conn_state);
> +	if (connector->hdcp_helper_data)
> +		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
> +					      &state->base,
> +					      &dig_port->hdcp_mutex);
>  }
>  
>  static void
> diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> index 13a4153bb76e..2e67cca0151c 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> @@ -7,6 +7,7 @@
>  
>  #include <drm/drm_debugfs.h>
>  #include <drm/drm_fourcc.h>
> +#include <drm/display/drm_hdcp_helper.h>
>  
>  #include "i915_debugfs.h"
>  #include "intel_de.h"
> @@ -500,10 +501,11 @@ static void intel_hdcp_info(struct seq_file *m,
>  		goto out;
>  	}
>  
> -	ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
> +	ret = drm_hdcp_helper_hdcp1_capable(intel_connector->hdcp_helper_data,
> +					    &hdcp_cap);
>  	if (ret)
>  		hdcp_cap = false;
> -	ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
> +	ret = intel_hdcp2_capable(&intel_connector->base, &hdcp2_cap);
>  	if (ret)
>  		hdcp2_cap = false;
>  
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 298d00a11f47..6260a40586ae 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -416,71 +416,14 @@ enum check_link_response {
>   *		The offsets of the registers are different for DP vs. HDMI
>   *	- Receiver register masks/offsets
>   *		For instance, the ready bit for the KSV fifo is in a different
> - *		place on DP vs HDMI
> - *	- Receiver register names
> - *		Seriously. In the DP spec, the 16-bit register containing
> - *		downstream information is called BINFO, on HDMI it's called
> - *		BSTATUS. To confuse matters further, DP has a BSTATUS register
> - *		with a completely different definition.
> - *	- KSV FIFO
> - *		On HDMI, the ksv fifo is read all at once, whereas on DP it must
> - *		be read 3 keys at a time
> - *	- Aksv output
> - *		Since Aksv is hidden in hardware, there's different procedures
> - *		to send it over DP AUX vs DDC

Has this information moved somewhere else? I have the feeling that this
actually deserved some documentation place.
Or we don't really need this anymore?

> + *		place on DP vs HDMI.
>   */
>  struct intel_hdcp_shim {
> -	/* Outputs the transmitter's An and Aksv values to the receiver. */
> -	int (*write_an_aksv)(struct intel_digital_port *dig_port, u8 *an);
> -
> -	/* Reads the receiver's key selection vector */
> -	int (*read_bksv)(struct intel_digital_port *dig_port, u8 *bksv);
> -
> -	/*
> -	 * Reads BINFO from DP receivers and BSTATUS from HDMI receivers. The
> -	 * definitions are the same in the respective specs, but the names are
> -	 * different. Call it BSTATUS since that's the name the HDMI spec
> -	 * uses and it was there first.
> -	 */
> -	int (*read_bstatus)(struct intel_digital_port *dig_port,
> -			    u8 *bstatus);
> -
> -	/* Determines whether a repeater is present downstream */
> -	int (*repeater_present)(struct intel_digital_port *dig_port,
> -				bool *repeater_present);
> -
> -	/* Reads the receiver's Ri' value */
> -	int (*read_ri_prime)(struct intel_digital_port *dig_port, u8 *ri);
> -
> -	/* Determines if the receiver's KSV FIFO is ready for consumption */
> -	int (*read_ksv_ready)(struct intel_digital_port *dig_port,
> -			      bool *ksv_ready);
> -
> -	/* Reads the ksv fifo for num_downstream devices */
> -	int (*read_ksv_fifo)(struct intel_digital_port *dig_port,
> -			     int num_downstream, u8 *ksv_fifo);
> -
> -	/* Reads a 32-bit part of V' from the receiver */
> -	int (*read_v_prime_part)(struct intel_digital_port *dig_port,
> -				 int i, u32 *part);
> -
>  	/* Enables HDCP signalling on the port */
>  	int (*toggle_signalling)(struct intel_digital_port *dig_port,
>  				 enum transcoder cpu_transcoder,
>  				 bool enable);
>  
> -	/* Enable/Disable stream encryption on DP MST Transport Link */
> -	int (*stream_encryption)(struct intel_connector *connector,
> -				 bool enable);
> -
> -	/* Ensures the link is still protected */
> -	bool (*check_link)(struct intel_digital_port *dig_port,
> -			   struct intel_connector *connector);
> -
> -	/* Detects panel's hdcp capability. This is optional for HDMI. */
> -	int (*hdcp_capable)(struct intel_digital_port *dig_port,
> -			    bool *hdcp_capable);
> -
>  	/* HDCP adaptation(DP/HDMI) required on the port */
>  	enum hdcp_wired_protocol protocol;
>  
> @@ -610,6 +553,7 @@ struct intel_connector {
>  	struct work_struct modeset_retry_work;
>  
>  	struct intel_hdcp hdcp;
> +	struct drm_hdcp_helper_data *hdcp_helper_data;
>  };
>  
>  struct intel_digital_connector_state {
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> index 88689124c013..d61ac8d69951 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> @@ -55,17 +55,24 @@ static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
>  		DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
>  }
>  
> -static
> -int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> -				u8 *an)
> +static int intel_dp_hdcp1_send_an_aksv(struct drm_connector *drm_connector)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
>  	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> +	struct drm_hdcp_an an;
>  	u8 aksv[DRM_HDCP_KSV_LEN] = {};
>  	ssize_t dpcd_ret;
> +	int ret;
>  
>  	/* Output An first, that's easy */
> +	ret = intel_hdcp1_read_an(drm_connector, &an);
> +	if (ret)
> +		return ret;
> +

Interesting that the comment is old, but the new code with the
old comment makes sense... I'm confused.
Why do we need this extra read now?
I believe this could be material for a separated patch for instance.

>  	dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux, DP_AUX_HDCP_AN,
> -				     an, DRM_HDCP_AN_LEN);
> +				     an.bytes, DRM_HDCP_AN_LEN);
>  	if (dpcd_ret != DRM_HDCP_AN_LEN) {
>  		drm_dbg_kms(&i915->drm,
>  			    "Failed to write An over DP/AUX (%zd)\n",
> @@ -91,158 +98,6 @@ int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
>  	return 0;
>  }
>  
> -static int intel_dp_hdcp_read_bksv(struct intel_digital_port *dig_port,
> -				   u8 *bksv)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
> -			       DRM_HDCP_KSV_LEN);
> -	if (ret != DRM_HDCP_KSV_LEN) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read Bksv from DP/AUX failed (%zd)\n", ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -	return 0;
> -}
> -
> -static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
> -				      u8 *bstatus)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -
> -	/*
> -	 * For some reason the HDMI and DP HDCP specs call this register
> -	 * definition by different names. In the HDMI spec, it's called BSTATUS,
> -	 * but in DP it's called BINFO.
> -	 */
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BINFO,
> -			       bstatus, DRM_HDCP_BSTATUS_LEN);
> -	if (ret != DRM_HDCP_BSTATUS_LEN) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_read_bcaps(struct intel_digital_port *dig_port,
> -			     u8 *bcaps)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
> -			       bcaps, 1);
> -	if (ret != 1) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read bcaps from DP/AUX failed (%zd)\n", ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_repeater_present(struct intel_digital_port *dig_port,
> -				   bool *repeater_present)
> -{
> -	ssize_t ret;
> -	u8 bcaps;
> -
> -	ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
> -	if (ret)
> -		return ret;
> -
> -	*repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
> -				u8 *ri_prime)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
> -			       ri_prime, DRM_HDCP_RI_LEN);
> -	if (ret != DRM_HDCP_RI_LEN) {
> -		drm_dbg_kms(&i915->drm, "Read Ri' from DP/AUX failed (%zd)\n",
> -			    ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
> -				 bool *ksv_ready)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -	u8 bstatus;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
> -			       &bstatus, 1);
> -	if (ret != 1) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -	*ksv_ready = bstatus & DP_BSTATUS_READY;
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
> -				int num_downstream, u8 *ksv_fifo)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -	int i;
> -
> -	/* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
> -	for (i = 0; i < num_downstream; i += 3) {
> -		size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
> -		ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> -				       DP_AUX_HDCP_KSV_FIFO,
> -				       ksv_fifo + i * DRM_HDCP_KSV_LEN,
> -				       len);
> -		if (ret != len) {
> -			drm_dbg_kms(&i915->drm,
> -				    "Read ksv[%d] from DP/AUX failed (%zd)\n",
> -				    i, ret);
> -			return ret >= 0 ? -EIO : ret;
> -		}
> -	}
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
> -				    int i, u32 *part)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -
> -	if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
> -		return -EINVAL;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> -			       DP_AUX_HDCP_V_PRIME(i), part,
> -			       DRM_HDCP_V_PRIME_PART_LEN);
> -	if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -	return 0;
> -}
> -
>  static
>  int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
>  				    enum transcoder cpu_transcoder,
> @@ -252,40 +107,6 @@ int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
>  	return 0;
>  }
>  
> -static
> -bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
> -			      struct intel_connector *connector)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -	u8 bstatus;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
> -			       &bstatus, 1);
> -	if (ret != 1) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
> -		return false;
> -	}
> -
> -	return !(bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ));
> -}
> -
> -static
> -int intel_dp_hdcp_capable(struct intel_digital_port *dig_port,
> -			  bool *hdcp_capable)
> -{
> -	ssize_t ret;
> -	u8 bcaps;
> -
> -	ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
> -	if (ret)
> -		return ret;
> -
> -	*hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
> -	return 0;
> -}
> -
>  struct hdcp2_dp_errata_stream_type {
>  	u8	msg_id;
>  	u8	stream_type;
> @@ -628,13 +449,19 @@ int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port,
>  	return ret;
>  }
>  
> -static
> -int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
> -			   bool *capable)
> +static int intel_dp_hdcp2_capable(struct drm_connector *drm_connector,
> +				  bool *capable)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
>  	u8 rx_caps[3];
>  	int ret;
>  
> +	ret = intel_hdcp2_capable(drm_connector, capable);
> +	if (ret || !capable)
> +		return ret;
> +
>  	*capable = false;
>  	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
>  			       DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
> @@ -650,22 +477,11 @@ int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
>  }
>  
>  static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
> -	.write_an_aksv = intel_dp_hdcp_write_an_aksv,
> -	.read_bksv = intel_dp_hdcp_read_bksv,

Here is the part that I get fully stuck and don't know how to proceed in the
review.
I'd like to get someone with a stronger background in HDCP here, so I hope
Suraj can help here.

When looking to the removed functions I end up in the enable and auth functions
and I see that the sequence in the new drm ones introduced in the patch 04
are totally different from the ones we had in i915. Hence I'm not comfortable
with adding a review on a flow that I'm not totally familiar with.

But let me be clear: I really don't see any blocker in this patch. Even as is.
I believe the smaller patch would help the review, but it is not mandatory.

That sad:

Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

> -	.read_bstatus = intel_dp_hdcp_read_bstatus,
> -	.repeater_present = intel_dp_hdcp_repeater_present,
> -	.read_ri_prime = intel_dp_hdcp_read_ri_prime,
> -	.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
> -	.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
> -	.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
>  	.toggle_signalling = intel_dp_hdcp_toggle_signalling,
> -	.check_link = intel_dp_hdcp_check_link,
> -	.hdcp_capable = intel_dp_hdcp_capable,
>  	.write_2_2_msg = intel_dp_hdcp2_write_msg,
>  	.read_2_2_msg = intel_dp_hdcp2_read_msg,
>  	.config_stream_type = intel_dp_hdcp2_config_stream_type,
>  	.check_2_2_link = intel_dp_hdcp2_check_link,
> -	.hdcp_2_2_capable = intel_dp_hdcp2_capable,
>  	.protocol = HDCP_PROTOCOL_DP,
>  };
>  
> @@ -721,6 +537,46 @@ intel_dp_mst_hdcp_stream_encryption(struct intel_connector *connector,
>  	return 0;
>  }
>  
> +static int
> +intel_dp_mst_hdcp1_post_encryption(struct drm_connector *drm_connector)
> +{
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	int ret;
> +
> +	ret = intel_hdcp1_post_encryption(drm_connector);
> +	if (ret)
> +		return ret;
> +
> +	return intel_dp_mst_hdcp_stream_encryption(connector, true);
> +}
> +
> +static int intel_dp_mst_hdcp1_disable(struct drm_connector *drm_connector)
> +{
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *i915 = to_i915(connector->base.dev);
> +	int ret;
> +
> +	ret = intel_dp_mst_hdcp_stream_encryption(connector, true);
> +	if (ret) {
> +		drm_err(&i915->drm,
> +			"[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
> +			connector->base.name, connector->base.base.id);
> +		return ret;
> +	}
> +
> +	/*
> +	 * If there are other connectors on this port using HDCP,
> +	 * don't disable it until it disabled HDCP encryption for
> +	 * all connectors in MST topology.
> +	*/
> +	if (dig_port->num_hdcp_streams > 0)
> +		return 0;
> +
> +	return intel_hdcp1_disable(drm_connector);
> +}
> +
>  static int
>  intel_dp_mst_hdcp2_stream_encryption(struct intel_connector *connector,
>  				     bool enable)
> @@ -779,45 +635,85 @@ int intel_dp_mst_hdcp2_check_link(struct intel_digital_port *dig_port,
>  }
>  
>  static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
> -	.write_an_aksv = intel_dp_hdcp_write_an_aksv,
> -	.read_bksv = intel_dp_hdcp_read_bksv,
> -	.read_bstatus = intel_dp_hdcp_read_bstatus,
> -	.repeater_present = intel_dp_hdcp_repeater_present,
> -	.read_ri_prime = intel_dp_hdcp_read_ri_prime,
> -	.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
> -	.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
> -	.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
>  	.toggle_signalling = intel_dp_hdcp_toggle_signalling,
> -	.stream_encryption = intel_dp_mst_hdcp_stream_encryption,
> -	.check_link = intel_dp_hdcp_check_link,
> -	.hdcp_capable = intel_dp_hdcp_capable,
>  	.write_2_2_msg = intel_dp_hdcp2_write_msg,
>  	.read_2_2_msg = intel_dp_hdcp2_read_msg,
>  	.config_stream_type = intel_dp_hdcp2_config_stream_type,
>  	.stream_2_2_encryption = intel_dp_mst_hdcp2_stream_encryption,
>  	.check_2_2_link = intel_dp_mst_hdcp2_check_link,
> -	.hdcp_2_2_capable = intel_dp_hdcp2_capable,
>  	.protocol = HDCP_PROTOCOL_DP,
>  };
>  
> +static const struct drm_hdcp_helper_funcs intel_dp_hdcp_helper_funcs = {
> +	.setup = intel_hdcp_setup,
> +	.load_keys = intel_hdcp_load_keys,
> +	.hdcp2_capable = intel_dp_hdcp2_capable,
> +	.hdcp2_enable = intel_hdcp2_enable,
> +	.hdcp2_check_link = intel_hdcp2_check_link,
> +	.hdcp2_disable = intel_hdcp2_disable,
> +	.hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
> +	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> +	.hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
> +	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> +	.hdcp1_match_ri = intel_hdcp1_match_ri,
> +	.hdcp1_post_encryption = intel_hdcp1_post_encryption,
> +	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> +	.hdcp1_disable = intel_hdcp1_disable,
> +};
> +
> +static const struct drm_hdcp_helper_funcs intel_dp_mst_hdcp_helper_funcs = {
> +	.setup = intel_hdcp_setup,
> +	.load_keys = intel_hdcp_load_keys,
> +	.hdcp2_capable = intel_dp_hdcp2_capable,
> +	.hdcp2_enable = intel_hdcp2_enable,
> +	.hdcp2_check_link = intel_hdcp2_check_link,
> +	.hdcp2_disable = intel_hdcp2_disable,
> +	.hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
> +	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> +	.hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
> +	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> +	.hdcp1_match_ri = intel_hdcp1_match_ri,
> +	.hdcp1_post_encryption = intel_dp_mst_hdcp1_post_encryption,
> +	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> +	.hdcp1_disable = intel_dp_mst_hdcp1_disable,
> +};
> +
>  int intel_dp_hdcp_init(struct intel_digital_port *dig_port,
> -		       struct intel_connector *intel_connector)
> +		       struct intel_connector *connector)
>  {
> -	struct drm_device *dev = intel_connector->base.dev;
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_encoder *intel_encoder = &dig_port->base;
>  	enum port port = intel_encoder->port;
>  	struct intel_dp *intel_dp = &dig_port->dp;
> +	struct drm_hdcp_helper_data *data;
> +	const struct drm_hdcp_helper_funcs *helper_funcs;
> +	const struct intel_hdcp_shim *intel_shim;
> +	int ret;
>  
> -	if (!is_hdcp_supported(dev_priv, port))
> +	if (!is_hdcp_supported(dev_priv, port) || intel_dp_is_edp(intel_dp))
>  		return 0;
>  
> -	if (intel_connector->mst_port)
> -		return intel_hdcp_init(intel_connector, dig_port,
> -				       &intel_dp_mst_hdcp_shim);
> -	else if (!intel_dp_is_edp(intel_dp))
> -		return intel_hdcp_init(intel_connector, dig_port,
> -				       &intel_dp_hdcp_shim);
> +	if (connector->mst_port) {
> +		helper_funcs = &intel_dp_mst_hdcp_helper_funcs;
> +		intel_shim = &intel_dp_mst_hdcp_shim;
> +	} else {
> +		helper_funcs = &intel_dp_hdcp_helper_funcs;
> +		intel_shim = &intel_dp_hdcp_shim;
> +	}
> +
> +	data = drm_hdcp_helper_initialize_dp(
> +		&connector->base, &dig_port->dp.aux, helper_funcs, true);
> +	if (IS_ERR(data)) {
> +		drm_dbg_kms(&dev_priv->drm, "HDCP init failed, skipping.\n");
> +		return PTR_ERR(data);
> +	}
> +
> +	ret = intel_hdcp_init(connector, dig_port, intel_shim);
> +	if (ret) {
> +		drm_hdcp_helper_destroy(data);
> +		return ret;
> +	}
>  
> +	connector->hdcp_helper_data = data;
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> index 03604a37931c..ececb7aa4b90 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> @@ -27,6 +27,7 @@
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_probe_helper.h>
> +#include <drm/display/drm_hdcp_helper.h>
>  
>  #include "i915_drv.h"
>  #include "intel_atomic.h"
> @@ -40,7 +41,6 @@
>  #include "intel_dp_hdcp.h"
>  #include "intel_dp_mst.h"
>  #include "intel_dpio_phy.h"
> -#include "intel_hdcp.h"
>  #include "intel_hotplug.h"
>  #include "skl_scaler.h"
>  
> @@ -371,7 +371,10 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,
>  	drm_dbg_kms(&i915->drm, "active links %d\n",
>  		    intel_dp->active_mst_links);
>  
> -	intel_hdcp_disable(intel_mst->connector);
> +	if (connector->hdcp_helper_data)
> +		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
> +					      &state->base,
> +					      &dig_port->hdcp_mutex);
>  
>  	drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state,
>  			      drm_atomic_get_mst_payload_state(mst_state, connector->port));
> @@ -579,11 +582,10 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
>  	intel_audio_codec_enable(encoder, pipe_config, conn_state);
>  
>  	/* Enable hdcp if it's desired */
> -	if (conn_state->content_protection ==
> -	    DRM_MODE_CONTENT_PROTECTION_DESIRED)
> -		intel_hdcp_enable(to_intel_connector(conn_state->connector),
> -				  pipe_config,
> -				  (u8)conn_state->hdcp_content_type);
> +	if (connector->hdcp_helper_data)
> +		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
> +					      &state->base,
> +					      &dig_port->hdcp_mutex);
>  }
>  
>  static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
> diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c
> index 61a862ae1f28..f09afbc9567b 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdcp.c
> +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
> @@ -140,67 +140,10 @@ static int intel_hdcp_prepare_streams(struct intel_connector *connector)
>  	return 0;
>  }
>  
> -static
> -bool intel_hdcp_is_ksv_valid(u8 *ksv)
> -{
> -	int i, ones = 0;
> -	/* KSV has 20 1's and 20 0's */
> -	for (i = 0; i < DRM_HDCP_KSV_LEN; i++)
> -		ones += hweight8(ksv[i]);
> -	if (ones != 20)
> -		return false;
> -
> -	return true;
> -}
> -
> -static
> -int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port,
> -			       const struct intel_hdcp_shim *shim, u8 *bksv)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int ret, i, tries = 2;
> -
> -	/* HDCP spec states that we must retry the bksv if it is invalid */
> -	for (i = 0; i < tries; i++) {
> -		ret = shim->read_bksv(dig_port, bksv);
> -		if (ret)
> -			return ret;
> -		if (intel_hdcp_is_ksv_valid(bksv))
> -			break;
> -	}
> -	if (i == tries) {
> -		drm_dbg_kms(&i915->drm, "Bksv is invalid\n");
> -		return -ENODEV;
> -	}
> -
> -	return 0;
> -}
> -
> -/* Is HDCP1.4 capable on Platform and Sink */
> -int intel_hdcp_capable(struct intel_connector *connector, bool *capable)
> -{
> -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> -	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> -	u8 bksv[5];
> -
> -	*capable = false;
> -
> -	if (!shim)
> -		return 0;
> -
> -	if (shim->hdcp_capable)
> -		return shim->hdcp_capable(dig_port, capable);
> -
> -	if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> -		*capable = true;
> -
> -	return 0;
> -}
> -
>  /* Is HDCP2.2 capable on Platform and Sink */
> -int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
> +int intel_hdcp2_capable(struct drm_connector *drm_connector, bool *capable)
>  {
> -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
>  
> @@ -218,16 +161,26 @@ int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
>  	}
>  	mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
>  
> -	/* Sink's capability for HDCP2.2 */
> -	return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
> +	return 0;
>  }
>  
> -static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv,
> -			      enum transcoder cpu_transcoder, enum port port)
> +int intel_hdcp1_check_link(struct drm_connector *drm_connector)
>  {
> -	return intel_de_read(dev_priv,
> -	                     HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> -	       HDCP_STATUS_ENC;
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
> +	u32 val;
> +
> +	val = intel_de_read(dev_priv,
> +			    HDCP_STATUS(dev_priv, cpu_transcoder, port));
> +
> +	if (val & HDCP_STATUS_ENC)
> +		return 0;
> +
> +	return -EINVAL;
>  }
>  
>  static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
> @@ -238,27 +191,6 @@ static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
>  	       LINK_ENCRYPTION_STATUS;
>  }
>  
> -static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *dig_port,
> -				    const struct intel_hdcp_shim *shim)
> -{
> -	int ret, read_ret;
> -	bool ksv_ready;
> -
> -	/* Poll for ksv list ready (spec says max time allowed is 5s) */
> -	ret = __wait_for(read_ret = shim->read_ksv_ready(dig_port,
> -							 &ksv_ready),
> -			 read_ret || ksv_ready, 5 * 1000 * 1000, 1000,
> -			 100 * 1000);
> -	if (ret)
> -		return ret;
> -	if (read_ret)
> -		return read_ret;
> -	if (!ksv_ready)
> -		return -ETIMEDOUT;
> -
> -	return 0;
> -}
> -
>  static bool hdcp_key_loadable(struct drm_i915_private *dev_priv)
>  {
>  	enum i915_power_well_id id;
> @@ -294,11 +226,18 @@ static void intel_hdcp_clear_keys(struct drm_i915_private *dev_priv)
>  		       HDCP_KEY_LOAD_DONE | HDCP_KEY_LOAD_STATUS | HDCP_FUSE_IN_PROGRESS | HDCP_FUSE_ERROR | HDCP_FUSE_DONE);
>  }
>  
> -static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
> +int intel_hdcp_load_keys(struct drm_connector *drm_connector)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	int ret;
>  	u32 val;
>  
> +	if (!hdcp_key_loadable(dev_priv)) {
> +		drm_err(&dev_priv->drm, "HDCP key Load is not possible\n");
> +		return -ENXIO;
> +	}
> +
>  	val = intel_de_read(dev_priv, HDCP_KEY_STATUS);
>  	if ((val & HDCP_KEY_LOAD_DONE) && (val & HDCP_KEY_LOAD_STATUS))
>  		return 0;
> @@ -308,8 +247,11 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
>  	 * out of reset. So if Key is not already loaded, its an error state.
>  	 */
>  	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
> -		if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) & HDCP_KEY_LOAD_DONE))
> -			return -ENXIO;
> +		if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) &
> +		      HDCP_KEY_LOAD_DONE)) {
> +			ret = -ENXIO;
> +			goto err;
> +		}
>  
>  	/*
>  	 * Initiate loading the HDCP key from fuses.
> @@ -325,7 +267,7 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
>  			drm_err(&dev_priv->drm,
>  				"Failed to initiate HDCP key load (%d)\n",
>  				ret);
> -			return ret;
> +			goto err;
>  		}
>  	} else {
>  		intel_de_write(dev_priv, HDCP_KEY_CONF, HDCP_KEY_LOAD_TRIGGER);
> @@ -335,15 +277,21 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
>  	ret = __intel_wait_for_register(&dev_priv->uncore, HDCP_KEY_STATUS,
>  					HDCP_KEY_LOAD_DONE, HDCP_KEY_LOAD_DONE,
>  					10, 1, &val);
> -	if (ret)
> -		return ret;
> -	else if (!(val & HDCP_KEY_LOAD_STATUS))
> -		return -ENXIO;
> +	if (ret) {
> +		goto err;
> +	} else if (!(val & HDCP_KEY_LOAD_STATUS)) {
> +		ret = -ENXIO;
> +		goto err;
> +	}
>  
>  	/* Send Aksv over to PCH display for use in authentication */
>  	intel_de_write(dev_priv, HDCP_KEY_CONF, HDCP_AKSV_SEND_TRIGGER);
>  
>  	return 0;
> +
> +err:
> +	intel_hdcp_clear_keys(dev_priv);
> +	return ret;
>  }
>  
>  /* Returns updated SHA-1 index */
> @@ -399,25 +347,21 @@ u32 intel_hdcp_get_repeater_ctl(struct drm_i915_private *dev_priv,
>  	}
>  }
>  
> -static
> -int intel_hdcp_validate_v_prime(struct intel_connector *connector,
> -				const struct intel_hdcp_shim *shim,
> -				u8 *ksv_fifo, u8 num_downstream, u8 *bstatus)
> +int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
> +			       u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
> +			       u32 *v_prime)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
>  	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
>  	enum port port = dig_port->base.port;
> -	u32 vprime, sha_text, sha_leftovers, rep_ctl;
> +	u32 sha_text, sha_leftovers, rep_ctl;
>  	int ret, i, j, sha_idx;
>  
>  	/* Process V' values from the receiver */
> -	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
> -		ret = shim->read_v_prime_part(dig_port, i, &vprime);
> -		if (ret)
> -			return ret;
> -		intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), vprime);
> -	}
> +	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++)
> +		intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), v_prime[i]);
>  
>  	/*
>  	 * We need to write the concatenation of all device KSVs, BINFO (DP) ||
> @@ -642,131 +586,38 @@ int intel_hdcp_validate_v_prime(struct intel_connector *connector,
>  	return 0;
>  }
>  
> -/* Implements Part 2 of the HDCP authorization procedure */
> -static
> -int intel_hdcp_auth_downstream(struct intel_connector *connector)
> +int intel_hdcp1_store_receiver_info(struct drm_connector *drm_connector,
> +				    u32 *ksv, u32 status, u8 caps,
> +				    bool repeater_present)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
>  	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> -	u8 bstatus[2], num_downstream, *ksv_fifo;
> -	int ret, i, tries = 3;
> -
> -	ret = intel_hdcp_poll_ksv_fifo(dig_port, shim);
> -	if (ret) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "KSV list failed to become ready (%d)\n", ret);
> -		return ret;
> -	}
> -
> -	ret = shim->read_bstatus(dig_port, bstatus);
> -	if (ret)
> -		return ret;
> -
> -	if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
> -	    DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
> -		drm_dbg_kms(&dev_priv->drm, "Max Topology Limit Exceeded\n");
> -		return -EPERM;
> -	}
> -
> -	/*
> -	 * When repeater reports 0 device count, HDCP1.4 spec allows disabling
> -	 * the HDCP encryption. That implies that repeater can't have its own
> -	 * display. As there is no consumption of encrypted content in the
> -	 * repeater with 0 downstream devices, we are failing the
> -	 * authentication.
> -	 */
> -	num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
> -	if (num_downstream == 0) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "Repeater with zero downstream devices\n");
> -		return -EINVAL;
> -	}
> -
> -	ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream, GFP_KERNEL);
> -	if (!ksv_fifo) {
> -		drm_dbg_kms(&dev_priv->drm, "Out of mem: ksv_fifo\n");
> -		return -ENOMEM;
> -	}
> -
> -	ret = shim->read_ksv_fifo(dig_port, num_downstream, ksv_fifo);
> -	if (ret)
> -		goto err;
> -
> -	if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, ksv_fifo,
> -					num_downstream) > 0) {
> -		drm_err(&dev_priv->drm, "Revoked Ksv(s) in ksv_fifo\n");
> -		ret = -EPERM;
> -		goto err;
> -	}
> +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
>  
> -	/*
> -	 * When V prime mismatches, DP Spec mandates re-read of
> -	 * V prime atleast twice.
> -	 */
> -	for (i = 0; i < tries; i++) {
> -		ret = intel_hdcp_validate_v_prime(connector, shim,
> -						  ksv_fifo, num_downstream,
> -						  bstatus);
> -		if (!ret)
> -			break;
> -	}
> +	intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder, port),
> +		       ksv[0]);
> +	intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder, port),
> +		       ksv[1]);
>  
> -	if (i == tries) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "V Prime validation failed.(%d)\n", ret);
> -		goto err;
> -	}
> +	if (repeater_present)
> +		intel_de_write(dev_priv, HDCP_REP_CTL,
> +			       intel_hdcp_get_repeater_ctl(
> +				       dev_priv, cpu_transcoder, port));
>  
> -	drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (%d downstream devices)\n",
> -		    num_downstream);
> -	ret = 0;
> -err:
> -	kfree(ksv_fifo);
> -	return ret;
> +	return 0;
>  }
>  
> -/* Implements Part 1 of the HDCP authorization procedure */
> -static int intel_hdcp_auth(struct intel_connector *connector)
> +int intel_hdcp1_read_an(struct drm_connector *drm_connector,
> +			struct drm_hdcp_an *an)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
>  	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	const struct intel_hdcp_shim *shim = hdcp->shim;
>  	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
>  	enum port port = dig_port->base.port;
> -	unsigned long r0_prime_gen_start;
> -	int ret, i, tries = 2;
> -	union {
> -		u32 reg[2];
> -		u8 shim[DRM_HDCP_AN_LEN];
> -	} an;
> -	union {
> -		u32 reg[2];
> -		u8 shim[DRM_HDCP_KSV_LEN];
> -	} bksv;
> -	union {
> -		u32 reg;
> -		u8 shim[DRM_HDCP_RI_LEN];
> -	} ri;
> -	bool repeater_present, hdcp_capable;
> -
> -	/*
> -	 * Detects whether the display is HDCP capable. Although we check for
> -	 * valid Bksv below, the HDCP over DP spec requires that we check
> -	 * whether the display supports HDCP before we write An. For HDMI
> -	 * displays, this is not necessary.
> -	 */
> -	if (shim->hdcp_capable) {
> -		ret = shim->hdcp_capable(dig_port, &hdcp_capable);
> -		if (ret)
> -			return ret;
> -		if (!hdcp_capable) {
> -			drm_dbg_kms(&dev_priv->drm,
> -				    "Panel is not HDCP capable\n");
> -			return -EINVAL;
> -		}
> -	}
> +	int i;
>  
>  	/* Initialize An with 2 random values and acquire it */
>  	for (i = 0; i < 2; i++)
> @@ -784,92 +635,81 @@ static int intel_hdcp_auth(struct intel_connector *connector)
>  		return -ETIMEDOUT;
>  	}
>  
> -	an.reg[0] = intel_de_read(dev_priv,
> -				  HDCP_ANLO(dev_priv, cpu_transcoder, port));
> -	an.reg[1] = intel_de_read(dev_priv,
> -				  HDCP_ANHI(dev_priv, cpu_transcoder, port));
> -	ret = shim->write_an_aksv(dig_port, an.shim);
> -	if (ret)
> -		return ret;
> +	an->words[0] = intel_de_read(dev_priv,
> +				     HDCP_ANLO(dev_priv, cpu_transcoder, port));
> +	an->words[1] = intel_de_read(dev_priv,
> +				     HDCP_ANHI(dev_priv, cpu_transcoder, port));
>  
> -	r0_prime_gen_start = jiffies;
> -
> -	memset(&bksv, 0, sizeof(bksv));
> -
> -	ret = intel_hdcp_read_valid_bksv(dig_port, shim, bksv.shim);
> -	if (ret < 0)
> -		return ret;
> -
> -	if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, bksv.shim, 1) > 0) {
> -		drm_err(&dev_priv->drm, "BKSV is revoked\n");
> -		return -EPERM;
> -	}
> -
> -	intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder, port),
> -		       bksv.reg[0]);
> -	intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder, port),
> -		       bksv.reg[1]);
> -
> -	ret = shim->repeater_present(dig_port, &repeater_present);
> -	if (ret)
> -		return ret;
> -	if (repeater_present)
> -		intel_de_write(dev_priv, HDCP_REP_CTL,
> -			       intel_hdcp_get_repeater_ctl(dev_priv, cpu_transcoder, port));
> +	return 0;
> +}
>  
> -	ret = shim->toggle_signalling(dig_port, cpu_transcoder, true);
> -	if (ret)
> -		return ret;
> +int intel_hdcp1_enable_encryption(struct drm_connector *drm_connector)
> +{
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
>  
>  	intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port),
>  		       HDCP_CONF_AUTH_AND_ENC);
>  
> +	return 0;
> +}
> +
> +int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector)
> +{
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
> +
>  	/* Wait for R0 ready */
> -	if (wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> -		     (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), 1)) {
> +	if (wait_for((intel_de_read(dev_priv,
> +				    HDCP_STATUS(dev_priv, cpu_transcoder,
> +						port))) &
> +			     (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC),
> +		     1)) {
>  		drm_err(&dev_priv->drm, "Timed out waiting for R0 ready\n");
>  		return -ETIMEDOUT;
>  	}
>  
> -	/*
> -	 * Wait for R0' to become available. The spec says 100ms from Aksv, but
> -	 * some monitors can take longer than this. We'll set the timeout at
> -	 * 300ms just to be sure.
> -	 *
> -	 * On DP, there's an R0_READY bit available but no such bit
> -	 * exists on HDMI. Since the upper-bound is the same, we'll just do
> -	 * the stupid thing instead of polling on one and not the other.
> -	 */
> -	wait_remaining_ms_from_jiffies(r0_prime_gen_start, 300);
> -
> -	tries = 3;
> +	return 0;
> +}
>  
> -	/*
> -	 * DP HDCP Spec mandates the two more reattempt to read R0, incase
> -	 * of R0 mismatch.
> -	 */
> -	for (i = 0; i < tries; i++) {
> -		ri.reg = 0;
> -		ret = shim->read_ri_prime(dig_port, ri.shim);
> -		if (ret)
> -			return ret;
> -		intel_de_write(dev_priv,
> -			       HDCP_RPRIME(dev_priv, cpu_transcoder, port),
> -			       ri.reg);
> +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32 ri_prime)
> +{
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
>  
> -		/* Wait for Ri prime match */
> -		if (!wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> -			      (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1))
> -			break;
> -	}
> +	intel_de_write(dev_priv, HDCP_RPRIME(dev_priv, cpu_transcoder, port),
> +		       ri_prime);
>  
> -	if (i == tries) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "Timed out waiting for Ri prime match (%x)\n",
> -			    intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> -					  cpu_transcoder, port)));
> +	/* Wait for Ri prime match */
> +	if (wait_for(intel_de_read(dev_priv,
> +				   HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> +			     (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC),
> +		     1))
>  		return -ETIMEDOUT;
> -	}
> +
> +	return 0;
> +}
> +
> +int intel_hdcp1_post_encryption(struct drm_connector *drm_connector)
> +{
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
>  
>  	/* Wait for encryption confirmation */
>  	if (intel_de_wait_for_set(dev_priv,
> @@ -880,56 +720,22 @@ static int intel_hdcp_auth(struct intel_connector *connector)
>  		return -ETIMEDOUT;
>  	}
>  
> -	/* DP MST Auth Part 1 Step 2.a and Step 2.b */
> -	if (shim->stream_encryption) {
> -		ret = shim->stream_encryption(connector, true);
> -		if (ret) {
> -			drm_err(&dev_priv->drm, "[%s:%d] Failed to enable HDCP 1.4 stream enc\n",
> -				connector->base.name, connector->base.base.id);
> -			return ret;
> -		}
> -		drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s stream encrypted\n",
> -			    transcoder_name(hdcp->stream_transcoder));
> -	}
> -
> -	if (repeater_present)
> -		return intel_hdcp_auth_downstream(connector);
> -
> -	drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (no repeater present)\n");
>  	return 0;
>  }
>  
> -static int _intel_hdcp_disable(struct intel_connector *connector)
> +int intel_hdcp1_disable(struct drm_connector *drm_connector)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
>  	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
>  	enum port port = dig_port->base.port;
>  	enum transcoder cpu_transcoder = hdcp->cpu_transcoder;
>  	u32 repeater_ctl;
> -	int ret;
>  
>  	drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being disabled...\n",
>  		    connector->base.name, connector->base.base.id);
>  
> -	if (hdcp->shim->stream_encryption) {
> -		ret = hdcp->shim->stream_encryption(connector, false);
> -		if (ret) {
> -			drm_err(&dev_priv->drm, "[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
> -				connector->base.name, connector->base.base.id);
> -			return ret;
> -		}
> -		drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s stream encryption disabled\n",
> -			    transcoder_name(hdcp->stream_transcoder));
> -		/*
> -		 * If there are other connectors on this port using HDCP,
> -		 * don't disable it until it disabled HDCP encryption for
> -		 * all connectors in MST topology.
> -		 */
> -		if (dig_port->num_hdcp_streams > 0)
> -			return 0;
> -	}
> -
>  	hdcp->hdcp_encrypted = false;
>  	intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port), 0);
>  	if (intel_de_wait_for_clear(dev_priv,
> @@ -945,190 +751,9 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
>  	intel_de_write(dev_priv, HDCP_REP_CTL,
>  		       intel_de_read(dev_priv, HDCP_REP_CTL) & ~repeater_ctl);
>  
> -	ret = hdcp->shim->toggle_signalling(dig_port, cpu_transcoder, false);
> -	if (ret) {
> -		drm_err(&dev_priv->drm, "Failed to disable HDCP signalling\n");
> -		return ret;
> -	}
> -
> -	drm_dbg_kms(&dev_priv->drm, "HDCP is disabled\n");
>  	return 0;
>  }
>  
> -static int _intel_hdcp_enable(struct intel_connector *connector)
> -{
> -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	int i, ret, tries = 3;
> -
> -	drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being enabled...\n",
> -		    connector->base.name, connector->base.base.id);
> -
> -	if (!hdcp_key_loadable(dev_priv)) {
> -		drm_err(&dev_priv->drm, "HDCP key Load is not possible\n");
> -		return -ENXIO;
> -	}
> -
> -	for (i = 0; i < KEY_LOAD_TRIES; i++) {
> -		ret = intel_hdcp_load_keys(dev_priv);
> -		if (!ret)
> -			break;
> -		intel_hdcp_clear_keys(dev_priv);
> -	}
> -	if (ret) {
> -		drm_err(&dev_priv->drm, "Could not load HDCP keys, (%d)\n",
> -			ret);
> -		return ret;
> -	}
> -
> -	/* Incase of authentication failures, HDCP spec expects reauth. */
> -	for (i = 0; i < tries; i++) {
> -		ret = intel_hdcp_auth(connector);
> -		if (!ret) {
> -			hdcp->hdcp_encrypted = true;
> -			return 0;
> -		}
> -
> -		drm_dbg_kms(&dev_priv->drm, "HDCP Auth failure (%d)\n", ret);
> -
> -		/* Ensuring HDCP encryption and signalling are stopped. */
> -		_intel_hdcp_disable(connector);
> -	}
> -
> -	drm_dbg_kms(&dev_priv->drm,
> -		    "HDCP authentication failed (%d tries/%d)\n", tries, ret);
> -	return ret;
> -}
> -
> -static struct intel_connector *intel_hdcp_to_connector(struct intel_hdcp *hdcp)
> -{
> -	return container_of(hdcp, struct intel_connector, hdcp);
> -}
> -
> -static void intel_hdcp_update_value(struct intel_connector *connector,
> -				    u64 value, bool update_property)
> -{
> -	struct drm_device *dev = connector->base.dev;
> -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -
> -	drm_WARN_ON(connector->base.dev, !mutex_is_locked(&hdcp->mutex));
> -
> -	if (hdcp->value == value)
> -		return;
> -
> -	drm_WARN_ON(dev, !mutex_is_locked(&dig_port->hdcp_mutex));
> -
> -	if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> -		if (!drm_WARN_ON(dev, dig_port->num_hdcp_streams == 0))
> -			dig_port->num_hdcp_streams--;
> -	} else if (value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> -		dig_port->num_hdcp_streams++;
> -	}
> -
> -	hdcp->value = value;
> -	if (update_property) {
> -		drm_connector_get(&connector->base);
> -		schedule_work(&hdcp->prop_work);
> -	}
> -}
> -
> -/* Implements Part 3 of the HDCP authorization procedure */
> -static int intel_hdcp_check_link(struct intel_connector *connector)
> -{
> -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	enum port port = dig_port->base.port;
> -	enum transcoder cpu_transcoder;
> -	int ret = 0;
> -
> -	mutex_lock(&hdcp->mutex);
> -	mutex_lock(&dig_port->hdcp_mutex);
> -
> -	cpu_transcoder = hdcp->cpu_transcoder;
> -
> -	/* Check_link valid only when HDCP1.4 is enabled */
> -	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED ||
> -	    !hdcp->hdcp_encrypted) {
> -		ret = -EINVAL;
> -		goto out;
> -	}
> -
> -	if (drm_WARN_ON(&dev_priv->drm,
> -			!intel_hdcp_in_use(dev_priv, cpu_transcoder, port))) {
> -		drm_err(&dev_priv->drm,
> -			"%s:%d HDCP link stopped encryption,%x\n",
> -			connector->base.name, connector->base.base.id,
> -			intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)));
> -		ret = -ENXIO;
> -		intel_hdcp_update_value(connector,
> -					DRM_MODE_CONTENT_PROTECTION_DESIRED,
> -					true);
> -		goto out;
> -	}
> -
> -	if (hdcp->shim->check_link(dig_port, connector)) {
> -		if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> -			intel_hdcp_update_value(connector,
> -				DRM_MODE_CONTENT_PROTECTION_ENABLED, true);
> -		}
> -		goto out;
> -	}
> -
> -	drm_dbg_kms(&dev_priv->drm,
> -		    "[%s:%d] HDCP link failed, retrying authentication\n",
> -		    connector->base.name, connector->base.base.id);
> -
> -	ret = _intel_hdcp_disable(connector);
> -	if (ret) {
> -		drm_err(&dev_priv->drm, "Failed to disable hdcp (%d)\n", ret);
> -		intel_hdcp_update_value(connector,
> -					DRM_MODE_CONTENT_PROTECTION_DESIRED,
> -					true);
> -		goto out;
> -	}
> -
> -	ret = _intel_hdcp_enable(connector);
> -	if (ret) {
> -		drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n", ret);
> -		intel_hdcp_update_value(connector,
> -					DRM_MODE_CONTENT_PROTECTION_DESIRED,
> -					true);
> -		goto out;
> -	}
> -
> -out:
> -	mutex_unlock(&dig_port->hdcp_mutex);
> -	mutex_unlock(&hdcp->mutex);
> -	return ret;
> -}
> -
> -static void intel_hdcp_prop_work(struct work_struct *work)
> -{
> -	struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp,
> -					       prop_work);
> -	struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
> -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -
> -	drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, NULL);
> -	mutex_lock(&hdcp->mutex);
> -
> -	/*
> -	 * This worker is only used to flip between ENABLED/DESIRED. Either of
> -	 * those to UNDESIRED is handled by core. If value == UNDESIRED,
> -	 * we're running just after hdcp has been disabled, so just exit
> -	 */
> -	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> -		drm_hdcp_update_content_protection(&connector->base,
> -						   hdcp->value);
> -
> -	mutex_unlock(&hdcp->mutex);
> -	drm_modeset_unlock(&dev_priv->drm.mode_config.connection_mutex);
> -
> -	drm_connector_put(&connector->base);
> -}
> -
>  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port)
>  {
>  	return RUNTIME_INFO(dev_priv)->has_hdcp &&
> @@ -1961,8 +1586,9 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
>  	return ret;
>  }
>  
> -static int _intel_hdcp2_enable(struct intel_connector *connector)
> +int intel_hdcp2_enable(struct drm_connector *drm_connector)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
>  	struct drm_i915_private *i915 = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
>  	int ret;
> @@ -2024,9 +1650,15 @@ _intel_hdcp2_disable(struct intel_connector *connector, bool hdcp2_link_recovery
>  	return ret;
>  }
>  
> +int intel_hdcp2_disable(struct drm_connector *drm_connector)
> +{
> +	return _intel_hdcp2_disable(to_intel_connector(drm_connector), false);
> +}
> +
>  /* Implements the Link Integrity Check for HDCP2.2 */
> -static int intel_hdcp2_check_link(struct intel_connector *connector)
> +int intel_hdcp2_check_link(struct drm_connector *drm_connector)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
>  	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
> @@ -2034,109 +1666,39 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
>  	enum transcoder cpu_transcoder;
>  	int ret = 0;
>  
> -	mutex_lock(&hdcp->mutex);
> -	mutex_lock(&dig_port->hdcp_mutex);
>  	cpu_transcoder = hdcp->cpu_transcoder;
>  
>  	/* hdcp2_check_link is expected only when HDCP2.2 is Enabled */
> -	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED ||
> -	    !hdcp->hdcp2_encrypted) {
> -		ret = -EINVAL;
> -		goto out;
> -	}
> +	if (!hdcp->hdcp2_encrypted)
> +		return -EINVAL;
>  
>  	if (drm_WARN_ON(&dev_priv->drm,
>  			!intel_hdcp2_in_use(dev_priv, cpu_transcoder, port))) {
>  		drm_err(&dev_priv->drm,
>  			"HDCP2.2 link stopped the encryption, %x\n",
>  			intel_de_read(dev_priv, HDCP2_STATUS(dev_priv, cpu_transcoder, port)));
> -		ret = -ENXIO;
> -		_intel_hdcp2_disable(connector, true);
> -		intel_hdcp_update_value(connector,
> -					DRM_MODE_CONTENT_PROTECTION_DESIRED,
> -					true);
> -		goto out;
> +		return -ENXIO;
>  	}
>  
>  	ret = hdcp->shim->check_2_2_link(dig_port, connector);
> -	if (ret == HDCP_LINK_PROTECTED) {
> -		if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> -			intel_hdcp_update_value(connector,
> -					DRM_MODE_CONTENT_PROTECTION_ENABLED,
> -					true);
> -		}
> -		goto out;
> -	}
> +	if (ret == HDCP_LINK_PROTECTED)
> +		return 0;
>  
>  	if (ret == HDCP_TOPOLOGY_CHANGE) {
> -		if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> -			goto out;
> -
>  		drm_dbg_kms(&dev_priv->drm,
>  			    "HDCP2.2 Downstream topology change\n");
>  		ret = hdcp2_authenticate_repeater_topology(connector);
> -		if (!ret) {
> -			intel_hdcp_update_value(connector,
> -					DRM_MODE_CONTENT_PROTECTION_ENABLED,
> -					true);
> -			goto out;
> -		}
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "[%s:%d] Repeater topology auth failed.(%d)\n",
> -			    connector->base.name, connector->base.base.id,
> -			    ret);
> -	} else {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "[%s:%d] HDCP2.2 link failed, retrying auth\n",
> -			    connector->base.name, connector->base.base.id);
> -	}
> -
> -	ret = _intel_hdcp2_disable(connector, true);
> -	if (ret) {
> -		drm_err(&dev_priv->drm,
> -			"[%s:%d] Failed to disable hdcp2.2 (%d)\n",
> -			connector->base.name, connector->base.base.id, ret);
> -		intel_hdcp_update_value(connector,
> -				DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
> -		goto out;
> -	}
> +		if (!ret)
> +			return 0;
>  
> -	ret = _intel_hdcp2_enable(connector);
> -	if (ret) {
>  		drm_dbg_kms(&dev_priv->drm,
> -			    "[%s:%d] Failed to enable hdcp2.2 (%d)\n",
> -			    connector->base.name, connector->base.base.id,
> -			    ret);
> -		intel_hdcp_update_value(connector,
> -					DRM_MODE_CONTENT_PROTECTION_DESIRED,
> -					true);
> -		goto out;
> +			    "[%s:%d] Repeater topology auth failed.(%d)\n",
> +			    connector->base.name, connector->base.base.id, ret);
>  	}
>  
> -out:
> -	mutex_unlock(&dig_port->hdcp_mutex);
> -	mutex_unlock(&hdcp->mutex);
>  	return ret;
>  }
>  
> -static void intel_hdcp_check_work(struct work_struct *work)
> -{
> -	struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
> -					       struct intel_hdcp,
> -					       check_work);
> -	struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
> -
> -	if (drm_connector_is_unregistered(&connector->base))
> -		return;
> -
> -	if (!intel_hdcp2_check_link(connector))
> -		schedule_delayed_work(&hdcp->check_work,
> -				      DRM_HDCP2_CHECK_PERIOD_MS);
> -	else if (!intel_hdcp_check_link(connector))
> -		schedule_delayed_work(&hdcp->check_work,
> -				      DRM_HDCP_CHECK_PERIOD_MS);
> -}
> -
>  static int i915_hdcp_component_bind(struct device *i915_kdev,
>  				    struct device *mei_kdev, void *data)
>  {
> @@ -2189,22 +1751,28 @@ static enum mei_fw_tc intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
>  	}
>  }
>  
> -static int
> -_intel_hdcp_setup(struct intel_connector *connector,
> -		  const struct intel_crtc_state *pipe_config, u8 content_type)
> +int intel_hdcp_setup(struct drm_connector *connector,
> +		     struct drm_atomic_state *state)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> +	struct drm_i915_private *dev_priv = to_i915(connector->dev);
> +	struct intel_connector *intel_connector = to_intel_connector(connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(intel_connector);
> +	struct drm_connector_state *conn_state;
> +	struct drm_crtc_state *crtc_state;
> +	struct intel_crtc_state *pipe_config;
> +	struct intel_hdcp *hdcp = &intel_connector->hdcp;
>  	int ret = 0;
>  
> -	if (!connector->encoder) {
> +	if (!intel_connector->encoder) {
>  		drm_err(&dev_priv->drm, "[%s:%d] encoder is not initialized\n",
> -			connector->base.name, connector->base.base.id);
> +			connector->name, connector->base.id);
>  		return -ENODEV;
>  	}
>  
> -	hdcp->content_type = content_type;
> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> +	pipe_config = to_intel_crtc_state(crtc_state);
>  
>  	if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
>  		hdcp->cpu_transcoder = pipe_config->mst_master_transcoder;
> @@ -2321,7 +1889,6 @@ int intel_hdcp_init(struct intel_connector *connector,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
> -	int ret;
>  
>  	if (!shim)
>  		return -EINVAL;
> @@ -2329,174 +1896,12 @@ int intel_hdcp_init(struct intel_connector *connector,
>  	if (is_hdcp2_supported(dev_priv))
>  		intel_hdcp2_init(connector, dig_port, shim);
>  
> -	ret =
> -	drm_connector_attach_content_protection_property(&connector->base,
> -							 hdcp->hdcp2_supported);
> -	if (ret) {
> -		hdcp->hdcp2_supported = false;
> -		kfree(dig_port->hdcp_port_data.streams);
> -		return ret;
> -	}
> -
>  	hdcp->shim = shim;
> -	mutex_init(&hdcp->mutex);
> -	INIT_DELAYED_WORK(&hdcp->check_work, intel_hdcp_check_work);
> -	INIT_WORK(&hdcp->prop_work, intel_hdcp_prop_work);
>  	init_waitqueue_head(&hdcp->cp_irq_queue);
>  
>  	return 0;
>  }
>  
> -int intel_hdcp_enable(struct intel_connector *connector,
> -		      const struct intel_crtc_state *pipe_config, u8 content_type)
> -{
> -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
> -	bool capable;
> -	int ret = -EINVAL;
> -
> -	if (!hdcp->shim)
> -		return -ENOENT;
> -
> -	mutex_lock(&hdcp->mutex);
> -	mutex_lock(&dig_port->hdcp_mutex);
> -	drm_WARN_ON(&dev_priv->drm,
> -		    hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
> -
> -	ret = _intel_hdcp_setup(connector, pipe_config, content_type);
> -	if (ret)
> -		goto out;
> -
> -	/*
> -	 * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
> -	 * is capable of HDCP2.2, it is preferred to use HDCP2.2.
> -	 */
> -	ret = intel_hdcp2_capable(connector, &capable);
> -	if (capable) {
> -		ret = _intel_hdcp2_enable(connector);
> -		if (!ret) {
> -			check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
> -			goto out;
> -		}
> -	}
> -
> -	/*
> -	 * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
> -	 * be attempted.
> -	 */
> -	ret = intel_hdcp_capable(connector, &capable);
> -	if (ret)
> -		goto out;
> -
> -	if (capable && hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1)
> -		ret = _intel_hdcp_enable(connector);
> -
> -out:
> -	if (!ret) {
> -		schedule_delayed_work(&hdcp->check_work, check_link_interval);
> -		intel_hdcp_update_value(connector,
> -					DRM_MODE_CONTENT_PROTECTION_ENABLED,
> -					true);
> -	}
> -
> -	mutex_unlock(&dig_port->hdcp_mutex);
> -	mutex_unlock(&hdcp->mutex);
> -	return ret;
> -}
> -
> -int intel_hdcp_disable(struct intel_connector *connector)
> -{
> -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	int ret = 0;
> -
> -	if (!hdcp->shim)
> -		return -ENOENT;
> -
> -	mutex_lock(&hdcp->mutex);
> -	mutex_lock(&dig_port->hdcp_mutex);
> -
> -	if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> -		goto out;
> -
> -	intel_hdcp_update_value(connector,
> -				DRM_MODE_CONTENT_PROTECTION_UNDESIRED, false);
> -	if (hdcp->hdcp2_encrypted)
> -		ret = _intel_hdcp2_disable(connector, false);
> -	else if (hdcp->hdcp_encrypted)
> -		ret = _intel_hdcp_disable(connector);
> -
> -out:
> -	mutex_unlock(&dig_port->hdcp_mutex);
> -	mutex_unlock(&hdcp->mutex);
> -	cancel_delayed_work_sync(&hdcp->check_work);
> -	return ret;
> -}
> -
> -void intel_hdcp_update_pipe(struct intel_atomic_state *state,
> -			    struct intel_encoder *encoder,
> -			    const struct intel_crtc_state *crtc_state,
> -			    const struct drm_connector_state *conn_state)
> -{
> -	struct intel_connector *connector =
> -				to_intel_connector(conn_state->connector);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	bool content_protection_type_changed, desired_and_not_enabled = false;
> -
> -	if (!connector->hdcp.shim)
> -		return;
> -
> -	content_protection_type_changed =
> -		(conn_state->hdcp_content_type != hdcp->content_type &&
> -		 conn_state->content_protection !=
> -		 DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
> -
> -	/*
> -	 * During the HDCP encryption session if Type change is requested,
> -	 * disable the HDCP and reenable it with new TYPE value.
> -	 */
> -	if (conn_state->content_protection ==
> -	    DRM_MODE_CONTENT_PROTECTION_UNDESIRED ||
> -	    content_protection_type_changed)
> -		intel_hdcp_disable(connector);
> -
> -	/*
> -	 * Mark the hdcp state as DESIRED after the hdcp disable of type
> -	 * change procedure.
> -	 */
> -	if (content_protection_type_changed) {
> -		mutex_lock(&hdcp->mutex);
> -		hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
> -		drm_connector_get(&connector->base);
> -		schedule_work(&hdcp->prop_work);
> -		mutex_unlock(&hdcp->mutex);
> -	}
> -
> -	if (conn_state->content_protection ==
> -	    DRM_MODE_CONTENT_PROTECTION_DESIRED) {
> -		mutex_lock(&hdcp->mutex);
> -		/* Avoid enabling hdcp, if it already ENABLED */
> -		desired_and_not_enabled =
> -			hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED;
> -		mutex_unlock(&hdcp->mutex);
> -		/*
> -		 * If HDCP already ENABLED and CP property is DESIRED, schedule
> -		 * prop_work to update correct CP property to user space.
> -		 */
> -		if (!desired_and_not_enabled && !content_protection_type_changed) {
> -			drm_connector_get(&connector->base);
> -			schedule_work(&hdcp->prop_work);
> -		}
> -	}
> -
> -	if (desired_and_not_enabled || content_protection_type_changed)
> -		intel_hdcp_enable(connector,
> -				  crtc_state,
> -				  (u8)conn_state->hdcp_content_type);
> -}
> -
>  void intel_hdcp_component_fini(struct drm_i915_private *dev_priv)
>  {
>  	mutex_lock(&dev_priv->display.hdcp.comp_mutex);
> @@ -2518,33 +1923,8 @@ void intel_hdcp_cleanup(struct intel_connector *connector)
>  	if (!hdcp->shim)
>  		return;
>  
> -	/*
> -	 * If the connector is registered, it's possible userspace could kick
> -	 * off another HDCP enable, which would re-spawn the workers.
> -	 */
> -	drm_WARN_ON(connector->base.dev,
> -		connector->base.registration_state == DRM_CONNECTOR_REGISTERED);
> -
> -	/*
> -	 * Now that the connector is not registered, check_work won't be run,
> -	 * but cancel any outstanding instances of it
> -	 */
> -	cancel_delayed_work_sync(&hdcp->check_work);
> -
> -	/*
> -	 * We don't cancel prop_work in the same way as check_work since it
> -	 * requires connection_mutex which could be held while calling this
> -	 * function. Instead, we rely on the connector references grabbed before
> -	 * scheduling prop_work to ensure the connector is alive when prop_work
> -	 * is run. So if we're in the destroy path (which is where this
> -	 * function should be called), we're "guaranteed" that prop_work is not
> -	 * active (tl;dr This Should Never Happen).
> -	 */
> -	drm_WARN_ON(connector->base.dev, work_pending(&hdcp->prop_work));
> -
> -	mutex_lock(&hdcp->mutex);
> +	drm_hdcp_helper_destroy(connector->hdcp_helper_data);
>  	hdcp->shim = NULL;
> -	mutex_unlock(&hdcp->mutex);
>  }
>  
>  /* Handles the CP_IRQ raised from the DP HDCP sink */
> @@ -2558,5 +1938,5 @@ void intel_hdcp_handle_cp_irq(struct intel_connector *connector)
>  	atomic_inc(&connector->hdcp.cp_irq_count);
>  	wake_up_all(&connector->hdcp.cp_irq_queue);
>  
> -	schedule_delayed_work(&hdcp->check_work, 0);
> +	drm_hdcp_helper_schedule_hdcp_check(connector->hdcp_helper_data);
>  }
> diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h b/drivers/gpu/drm/i915/display/intel_hdcp.h
> index f06f6e5a2b1a..49b9d79eb30a 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdcp.h
> +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
> @@ -10,8 +10,10 @@
>  
>  #define HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS	50
>  
> +struct drm_atomic_state;
>  struct drm_connector;
>  struct drm_connector_state;
> +struct drm_hdcp_an;
>  struct drm_i915_private;
>  struct intel_atomic_state;
>  struct intel_connector;
> @@ -25,16 +27,29 @@ enum transcoder;
>  int intel_hdcp_init(struct intel_connector *connector,
>  		    struct intel_digital_port *dig_port,
>  		    const struct intel_hdcp_shim *hdcp_shim);
> -int intel_hdcp_enable(struct intel_connector *connector,
> -		      const struct intel_crtc_state *pipe_config, u8 content_type);
> -int intel_hdcp_disable(struct intel_connector *connector);
> -void intel_hdcp_update_pipe(struct intel_atomic_state *state,
> -			    struct intel_encoder *encoder,
> -			    const struct intel_crtc_state *crtc_state,
> -			    const struct drm_connector_state *conn_state);
> +int intel_hdcp_setup(struct drm_connector *drm_connector,
> +		     struct drm_atomic_state *state);
> +int intel_hdcp_load_keys(struct drm_connector *drm_connector);
>  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
>  int intel_hdcp_capable(struct intel_connector *connector, bool *capable);
> -int intel_hdcp2_capable(struct intel_connector *connector, bool *capable);
> +int intel_hdcp2_capable(struct drm_connector *drm_connector, bool *capable);
> +int intel_hdcp2_enable(struct drm_connector *drm_connector);
> +int intel_hdcp2_disable(struct drm_connector *drm_connector);
> +int intel_hdcp2_check_link(struct drm_connector *drm_connector);
> +int intel_hdcp1_store_receiver_info(struct drm_connector *drm_connector,
> +				    u32 *ksv, u32 status, u8 caps,
> +				    bool repeater_present);
> +int intel_hdcp1_read_an(struct drm_connector *drm_connector,
> +			struct drm_hdcp_an *an);
> +int intel_hdcp1_enable_encryption(struct drm_connector *drm_connector);
> +int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector);
> +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32 ri_prime);
> +int intel_hdcp1_post_encryption(struct drm_connector *drm_connector);
> +int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
> +			       u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
> +			       u32 *v_prime);
> +int intel_hdcp1_check_link(struct drm_connector *drm_connector);
> +int intel_hdcp1_disable(struct drm_connector *drm_connector);
>  void intel_hdcp_component_init(struct drm_i915_private *dev_priv);
>  void intel_hdcp_component_fini(struct drm_i915_private *dev_priv);
>  void intel_hdcp_cleanup(struct intel_connector *connector);
> diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
> index 7816b2a33fee..c33cfedb2e19 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
> @@ -1324,17 +1324,24 @@ static int intel_hdmi_hdcp_write(struct intel_digital_port *dig_port,
>  	return ret;
>  }
>  
> -static
> -int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> -				  u8 *an)
> +static int intel_hdmi_hdcp1_send_an_aksv(struct drm_connector *drm_connector)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
>  	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
>  	struct intel_hdmi *hdmi = &dig_port->hdmi;
>  	struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915,
>  							      hdmi->ddc_bus);
> +	struct drm_hdcp_an an;
>  	int ret;
>  
> -	ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an,
> +	/* Output An first, that's easy */
> +	ret = intel_hdcp1_read_an(drm_connector, &an);
> +	if (ret)
> +		return ret;
> +
> +	ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an.bytes,
>  				    DRM_HDCP_AN_LEN);
>  	if (ret) {
>  		drm_dbg_kms(&i915->drm, "Write An over DDC failed (%d)\n",
> @@ -1350,120 +1357,6 @@ int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
>  	return 0;
>  }
>  
> -static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *dig_port,
> -				     u8 *bksv)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -
> -	int ret;
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BKSV, bksv,
> -				   DRM_HDCP_KSV_LEN);
> -	if (ret)
> -		drm_dbg_kms(&i915->drm, "Read Bksv over DDC failed (%d)\n",
> -			    ret);
> -	return ret;
> -}
> -
> -static
> -int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *dig_port,
> -				 u8 *bstatus)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -
> -	int ret;
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BSTATUS,
> -				   bstatus, DRM_HDCP_BSTATUS_LEN);
> -	if (ret)
> -		drm_dbg_kms(&i915->drm, "Read bstatus over DDC failed (%d)\n",
> -			    ret);
> -	return ret;
> -}
> -
> -static
> -int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *dig_port,
> -				     bool *repeater_present)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int ret;
> -	u8 val;
> -
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
> -	if (ret) {
> -		drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed (%d)\n",
> -			    ret);
> -		return ret;
> -	}
> -	*repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
> -	return 0;
> -}
> -
> -static
> -int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
> -				  u8 *ri_prime)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -
> -	int ret;
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_RI_PRIME,
> -				   ri_prime, DRM_HDCP_RI_LEN);
> -	if (ret)
> -		drm_dbg_kms(&i915->drm, "Read Ri' over DDC failed (%d)\n",
> -			    ret);
> -	return ret;
> -}
> -
> -static
> -int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
> -				   bool *ksv_ready)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int ret;
> -	u8 val;
> -
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
> -	if (ret) {
> -		drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed (%d)\n",
> -			    ret);
> -		return ret;
> -	}
> -	*ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
> -	return 0;
> -}
> -
> -static
> -int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
> -				  int num_downstream, u8 *ksv_fifo)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int ret;
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_KSV_FIFO,
> -				   ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN);
> -	if (ret) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read ksv fifo over DDC failed (%d)\n", ret);
> -		return ret;
> -	}
> -	return 0;
> -}
> -
> -static
> -int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
> -				      int i, u32 *part)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int ret;
> -
> -	if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
> -		return -EINVAL;
> -
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_V_PRIME(i),
> -				   part, DRM_HDCP_V_PRIME_PART_LEN);
> -	if (ret)
> -		drm_dbg_kms(&i915->drm, "Read V'[%d] over DDC failed (%d)\n",
> -			    i, ret);
> -	return ret;
> -}
> -
>  static int kbl_repositioning_enc_en_signal(struct intel_connector *connector,
>  					   enum transcoder cpu_transcoder)
>  {
> @@ -1532,50 +1425,40 @@ int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
>  	return 0;
>  }
>  
> -static
> -bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port,
> -				     struct intel_connector *connector)
> +static int
> +intel_hdmi_hdcp1_enable_encryption(struct drm_connector *drm_connector)
>  {
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	enum port port = dig_port->base.port;
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
>  	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
>  	int ret;
> -	union {
> -		u32 reg;
> -		u8 shim[DRM_HDCP_RI_LEN];
> -	} ri;
>  
> -	ret = intel_hdmi_hdcp_read_ri_prime(dig_port, ri.shim);
> +	ret = intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder, true);
>  	if (ret)
> -		return false;
> -
> -	intel_de_write(i915, HDCP_RPRIME(i915, cpu_transcoder, port), ri.reg);
> +		return ret;
>  
> -	/* Wait for Ri prime match */
> -	if (wait_for((intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder, port)) &
> -		      (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC)) ==
> -		     (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
> -		drm_dbg_kms(&i915->drm, "Ri' mismatch detected (%x)\n",
> -			intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder,
> -							port)));
> -		return false;
> -	}
> -	return true;
> +	return intel_hdcp1_enable_encryption(drm_connector);
>  }
>  
> -static
> -bool intel_hdmi_hdcp_check_link(struct intel_digital_port *dig_port,
> -				struct intel_connector *connector)
> +static int intel_hdmi_hdcp1_disable(struct drm_connector *drm_connector)
>  {
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int retry;
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> +	struct drm_i915_private *i915 = to_i915(connector->base.dev);
> +	int ret;
>  
> -	for (retry = 0; retry < 3; retry++)
> -		if (intel_hdmi_hdcp_check_link_once(dig_port, connector))
> -			return true;
> +	ret = intel_hdcp1_disable(drm_connector);
> +	if (ret) {
> +		drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 1.4\n",
> +			connector->base.name, connector->base.base.id);
> +		return ret;
> +	}
>  
> -	drm_err(&i915->drm, "Link check failed\n");
> -	return false;
> +	return intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder,
> +						 false);
>  }
>  
>  struct hdcp2_hdmi_msg_timeout {
> @@ -1718,9 +1601,8 @@ int intel_hdmi_hdcp2_read_msg(struct intel_digital_port *dig_port,
>  	return ret;
>  }
>  
> -static
> -int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
> -				struct intel_connector *connector)
> +static int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
> +				       struct intel_connector *connector)
>  {
>  	u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
>  	int ret;
> @@ -1741,13 +1623,19 @@ int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
>  	return ret;
>  }
>  
> -static
> -int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
> -			     bool *capable)
> +static int intel_hdmi_hdcp2_capable(struct drm_connector *drm_connector,
> +				    bool *capable)
>  {
> +	struct intel_connector *connector = to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
>  	u8 hdcp2_version;
>  	int ret;
>  
> +	ret = intel_hdcp2_capable(drm_connector, capable);
> +	if (ret || !capable)
> +		return ret;
> +
>  	*capable = false;
>  	ret = intel_hdmi_hdcp_read(dig_port, HDCP_2_2_HDMI_REG_VER_OFFSET,
>  				   &hdcp2_version, sizeof(hdcp2_version));
> @@ -1758,23 +1646,30 @@ int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
>  }
>  
>  static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
> -	.write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
> -	.read_bksv = intel_hdmi_hdcp_read_bksv,
> -	.read_bstatus = intel_hdmi_hdcp_read_bstatus,
> -	.repeater_present = intel_hdmi_hdcp_repeater_present,
> -	.read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
> -	.read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
> -	.read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
> -	.read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
>  	.toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
> -	.check_link = intel_hdmi_hdcp_check_link,
>  	.write_2_2_msg = intel_hdmi_hdcp2_write_msg,
>  	.read_2_2_msg = intel_hdmi_hdcp2_read_msg,
> -	.check_2_2_link	= intel_hdmi_hdcp2_check_link,
> -	.hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
> +	.check_2_2_link = intel_hdmi_hdcp2_check_link,
>  	.protocol = HDCP_PROTOCOL_HDMI,
>  };
>  
> +static const struct drm_hdcp_helper_funcs intel_hdmi_hdcp_helper_funcs = {
> +	.setup = intel_hdcp_setup,
> +	.load_keys = intel_hdcp_load_keys,
> +	.hdcp2_capable = intel_hdmi_hdcp2_capable,
> +	.hdcp2_enable = intel_hdcp2_enable,
> +	.hdcp2_check_link = intel_hdcp2_check_link,
> +	.hdcp2_disable = intel_hdcp2_disable,
> +	.hdcp1_send_an_aksv = intel_hdmi_hdcp1_send_an_aksv,
> +	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> +	.hdcp1_enable_encryption = intel_hdmi_hdcp1_enable_encryption,
> +	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> +	.hdcp1_match_ri = intel_hdcp1_match_ri,
> +	.hdcp1_post_encryption = intel_hdcp1_post_encryption,
> +	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> +	.hdcp1_disable = intel_hdmi_hdcp1_disable,
> +};
> +
>  static int intel_hdmi_source_max_tmds_clock(struct intel_encoder *encoder)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> @@ -2922,6 +2817,37 @@ void intel_infoframe_init(struct intel_digital_port *dig_port)
>  	}
>  }
>  
> +static void intel_hdmi_hdcp_init(struct intel_digital_port *dig_port,
> +				 struct intel_connector *connector)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct intel_encoder *intel_encoder = &dig_port->base;
> +	enum port port = intel_encoder->port;
> +	struct drm_hdcp_helper_data *data;
> +	int ret;
> +
> +	if (!is_hdcp_supported(dev_priv, port))
> +		return;
> +
> +	data = drm_hdcp_helper_initialize_hdmi(
> +		&connector->base, &intel_hdmi_hdcp_helper_funcs, true);
> +	if (IS_ERR(data)) {
> +		drm_dbg_kms(&dev_priv->drm, "HDCP init failed ret=%ld\n",
> +			    PTR_ERR(data));
> +		return;
> +	}
> +
> +	ret = intel_hdcp_init(connector, dig_port, &intel_hdmi_hdcp_shim);
> +	if (ret) {
> +		drm_hdcp_helper_destroy(data);
> +		drm_dbg_kms(&dev_priv->drm, "Intel HDCP init failed ret=%d\n",
> +			    ret);
> +		return;
> +	}
> +
> +	connector->hdcp_helper_data = data;
> +}
> +
>  void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
>  			       struct intel_connector *intel_connector)
>  {
> @@ -2975,13 +2901,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
>  	intel_connector_attach_encoder(intel_connector, intel_encoder);
>  	intel_hdmi->attached_connector = intel_connector;
>  
> -	if (is_hdcp_supported(dev_priv, port)) {
> -		int ret = intel_hdcp_init(intel_connector, dig_port,
> -					  &intel_hdmi_hdcp_shim);
> -		if (ret)
> -			drm_dbg_kms(&dev_priv->drm,
> -				    "HDCP init failed, skipping.\n");
> -	}
> +	intel_hdmi_hdcp_init(dig_port, intel_connector);
>  
>  	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
>  	 * 0xd.  Failure to do so will result in spurious interrupts being
> -- 
> 2.39.0.246.g2a6d74b583-goog
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Intel-gfx] [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915
  2023-01-31 17:16   ` [Intel-gfx] " Rodrigo Vivi
@ 2023-01-31 17:23     ` Rodrigo Vivi
  0 siblings, 0 replies; 38+ messages in thread
From: Rodrigo Vivi @ 2023-01-31 17:23 UTC (permalink / raw)
  To: Mark Yacoub, Suraj Kandpal
  Cc: quic_sbillaka, dianders, konrad.dybcio, dri-devel,
	bjorn.andersson, krzysztof.kozlowski+dt, airlied, hbh25y, marex,
	javierm, quic_khsieh, agross, quic_jesszhan, devicetree,
	tzimmermann, Jani Nikula, linux-arm-msm, intel-gfx,
	lucas.demarchi, quic_abhinavk, abhinavk, swboyd, robh+dt,
	christophe.jaillet, maxime, johan+linaro, andersson,
	linux-kernel, daniel, dmitry.baryshkov, seanpaul, freedreno


+Suraj

On Tue, Jan 31, 2023 at 12:16:44PM -0500, Rodrigo Vivi wrote:
> 
> +Suraj who is also working on HDCP related code that even can conflict
> wit this.
> 
> On Wed, Jan 18, 2023 at 07:30:12PM +0000, Mark Yacoub wrote:
> > From: Sean Paul <seanpaul@chromium.org>
> 
> First of all, Sean, please accept my public apologies here. I just noticed
> now that you had pinged me 9 *months* ago!
> I noticed while taking a look to the history to refresh my mind around
> this series.
> 
> > 
> > Now that all of the HDCP 1.x logic has been migrated to the central HDCP
> > helpers, use it in the i915 driver.
> > 
> > The majority of the driver code for HDCP 1.x will live in intel_hdcp.c,
> > however there are a few helper hooks which are connector-specific and
> > need to be partially or fully implemented in the intel_dp_hdcp.c or
> > intel_hdmi.c.
> 
> so far so good! we need to do this soon.
> 
> > 
> > We'll leave most of the HDCP 2.x code alone since we don't have another
> > implementation of HDCP 2.x to use as reference for what should and
> > should not live in the drm helpers. The helper will call the overly
> > general enable/disable/is_capable HDCP 2.x callbacks and leave the
> > interesting stuff for the driver. Once we have another HDCP 2.x
> > implementation, we should do a similar migration.
> 
> I believe this part is the part that I start to get lost when
> trying to review it.
> 
> Mark told me in irc that it is really hard to split this patch,
> but do we really need to have the hdcp 1.x changes along with the
> 2.x? I start to get lost in the review when I see the changes around
> the hdcp2_capable...
> 
> So, it would be really really good if we can split this patch.
> 
> > 
> > Acked-by: Jani Nikula <jani.nikula@intel.com>
> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> 
> Cc: Suraj Kandpal <suraj.kandpal@intel.com>
> 
> > Link: https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-8-sean@poorly.run #v1
> > Link: https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-8-sean@poorly.run #v2
> > Link: https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-8-sean@poorly.run #v3
> > Link: https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-8-sean@poorly.run #v4
> > Link: https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-8-sean@poorly.run #v5
> > 
> > Changes in v2:
> > -Fix mst helper function pointer reported by 0-day
> > Changes in v3:
> > -Add forward declaration for drm_atomic_state in intel_hdcp.h identified
> >  by 0-day
> > Changes in v4:
> > -None
> > Changes in v5:
> > -None
> > Changes in v6:
> > -Rebased.
> > 
> > ---
> >  drivers/gpu/drm/i915/display/intel_ddi.c      |  32 +-
> >  .../drm/i915/display/intel_display_debugfs.c  |   6 +-
> >  .../drm/i915/display/intel_display_types.h    |  60 +-
> >  drivers/gpu/drm/i915/display/intel_dp_hdcp.c  | 348 +++----
> >  drivers/gpu/drm/i915/display/intel_dp_mst.c   |  16 +-
> >  drivers/gpu/drm/i915/display/intel_hdcp.c     | 952 +++---------------
> >  drivers/gpu/drm/i915/display/intel_hdcp.h     |  31 +-
> >  drivers/gpu/drm/i915/display/intel_hdmi.c     | 270 ++---
> >  8 files changed, 445 insertions(+), 1270 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
> > index 69ecf2a3d6c6..a4397f066a3e 100644
> > --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> > @@ -28,6 +28,7 @@
> >  #include <linux/string_helpers.h>
> >  
> >  #include <drm/display/drm_scdc_helper.h>
> > +#include <drm/display/drm_hdcp_helper.h>
> >  #include <drm/drm_privacy_screen_consumer.h>
> >  
> >  #include "i915_drv.h"
> > @@ -2909,6 +2910,10 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
> >  			     const struct intel_crtc_state *crtc_state,
> >  			     const struct drm_connector_state *conn_state)
> >  {
> > +	struct intel_connector *connector =
> > +		to_intel_connector(conn_state->connector);
> > +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> > +
> >  	drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
> >  
> >  	if (!intel_crtc_is_bigjoiner_slave(crtc_state))
> > @@ -2925,12 +2930,10 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
> >  	else
> >  		intel_enable_ddi_dp(state, encoder, crtc_state, conn_state);
> >  
> > -	/* Enable hdcp if it's desired */
> > -	if (conn_state->content_protection ==
> > -	    DRM_MODE_CONTENT_PROTECTION_DESIRED)
> > -		intel_hdcp_enable(to_intel_connector(conn_state->connector),
> > -				  crtc_state,
> > -				  (u8)conn_state->hdcp_content_type);
> > +	if (connector->hdcp_helper_data)
> > +		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
> > +					      &state->base,
> > +					      &dig_port->hdcp_mutex);
> >  }
> >  
> >  static void intel_disable_ddi_dp(struct intel_atomic_state *state,
> > @@ -2976,7 +2979,14 @@ static void intel_disable_ddi(struct intel_atomic_state *state,
> >  			      const struct intel_crtc_state *old_crtc_state,
> >  			      const struct drm_connector_state *old_conn_state)
> >  {
> > -	intel_hdcp_disable(to_intel_connector(old_conn_state->connector));
> > +	struct intel_connector *connector =
> > +		to_intel_connector(old_conn_state->connector);
> > +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> > +
> > +	if (connector->hdcp_helper_data)
> > +		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
> > +					      &state->base,
> > +					      &dig_port->hdcp_mutex);
> >  
> >  	if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
> >  		intel_disable_ddi_hdmi(state, encoder, old_crtc_state,
> > @@ -3004,13 +3014,19 @@ void intel_ddi_update_pipe(struct intel_atomic_state *state,
> >  			   const struct intel_crtc_state *crtc_state,
> >  			   const struct drm_connector_state *conn_state)
> >  {
> > +	struct intel_connector *connector =
> > +		to_intel_connector(conn_state->connector);
> > +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> >  
> >  	if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
> >  	    !intel_encoder_is_mst(encoder))
> >  		intel_ddi_update_pipe_dp(state, encoder, crtc_state,
> >  					 conn_state);
> >  
> > -	intel_hdcp_update_pipe(state, encoder, crtc_state, conn_state);
> > +	if (connector->hdcp_helper_data)
> > +		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
> > +					      &state->base,
> > +					      &dig_port->hdcp_mutex);
> >  }
> >  
> >  static void
> > diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > index 13a4153bb76e..2e67cca0151c 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > @@ -7,6 +7,7 @@
> >  
> >  #include <drm/drm_debugfs.h>
> >  #include <drm/drm_fourcc.h>
> > +#include <drm/display/drm_hdcp_helper.h>
> >  
> >  #include "i915_debugfs.h"
> >  #include "intel_de.h"
> > @@ -500,10 +501,11 @@ static void intel_hdcp_info(struct seq_file *m,
> >  		goto out;
> >  	}
> >  
> > -	ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
> > +	ret = drm_hdcp_helper_hdcp1_capable(intel_connector->hdcp_helper_data,
> > +					    &hdcp_cap);
> >  	if (ret)
> >  		hdcp_cap = false;
> > -	ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
> > +	ret = intel_hdcp2_capable(&intel_connector->base, &hdcp2_cap);
> >  	if (ret)
> >  		hdcp2_cap = false;
> >  
> > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> > index 298d00a11f47..6260a40586ae 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> > @@ -416,71 +416,14 @@ enum check_link_response {
> >   *		The offsets of the registers are different for DP vs. HDMI
> >   *	- Receiver register masks/offsets
> >   *		For instance, the ready bit for the KSV fifo is in a different
> > - *		place on DP vs HDMI
> > - *	- Receiver register names
> > - *		Seriously. In the DP spec, the 16-bit register containing
> > - *		downstream information is called BINFO, on HDMI it's called
> > - *		BSTATUS. To confuse matters further, DP has a BSTATUS register
> > - *		with a completely different definition.
> > - *	- KSV FIFO
> > - *		On HDMI, the ksv fifo is read all at once, whereas on DP it must
> > - *		be read 3 keys at a time
> > - *	- Aksv output
> > - *		Since Aksv is hidden in hardware, there's different procedures
> > - *		to send it over DP AUX vs DDC
> 
> Has this information moved somewhere else? I have the feeling that this
> actually deserved some documentation place.
> Or we don't really need this anymore?
> 
> > + *		place on DP vs HDMI.
> >   */
> >  struct intel_hdcp_shim {
> > -	/* Outputs the transmitter's An and Aksv values to the receiver. */
> > -	int (*write_an_aksv)(struct intel_digital_port *dig_port, u8 *an);
> > -
> > -	/* Reads the receiver's key selection vector */
> > -	int (*read_bksv)(struct intel_digital_port *dig_port, u8 *bksv);
> > -
> > -	/*
> > -	 * Reads BINFO from DP receivers and BSTATUS from HDMI receivers. The
> > -	 * definitions are the same in the respective specs, but the names are
> > -	 * different. Call it BSTATUS since that's the name the HDMI spec
> > -	 * uses and it was there first.
> > -	 */
> > -	int (*read_bstatus)(struct intel_digital_port *dig_port,
> > -			    u8 *bstatus);
> > -
> > -	/* Determines whether a repeater is present downstream */
> > -	int (*repeater_present)(struct intel_digital_port *dig_port,
> > -				bool *repeater_present);
> > -
> > -	/* Reads the receiver's Ri' value */
> > -	int (*read_ri_prime)(struct intel_digital_port *dig_port, u8 *ri);
> > -
> > -	/* Determines if the receiver's KSV FIFO is ready for consumption */
> > -	int (*read_ksv_ready)(struct intel_digital_port *dig_port,
> > -			      bool *ksv_ready);
> > -
> > -	/* Reads the ksv fifo for num_downstream devices */
> > -	int (*read_ksv_fifo)(struct intel_digital_port *dig_port,
> > -			     int num_downstream, u8 *ksv_fifo);
> > -
> > -	/* Reads a 32-bit part of V' from the receiver */
> > -	int (*read_v_prime_part)(struct intel_digital_port *dig_port,
> > -				 int i, u32 *part);
> > -
> >  	/* Enables HDCP signalling on the port */
> >  	int (*toggle_signalling)(struct intel_digital_port *dig_port,
> >  				 enum transcoder cpu_transcoder,
> >  				 bool enable);
> >  
> > -	/* Enable/Disable stream encryption on DP MST Transport Link */
> > -	int (*stream_encryption)(struct intel_connector *connector,
> > -				 bool enable);
> > -
> > -	/* Ensures the link is still protected */
> > -	bool (*check_link)(struct intel_digital_port *dig_port,
> > -			   struct intel_connector *connector);
> > -
> > -	/* Detects panel's hdcp capability. This is optional for HDMI. */
> > -	int (*hdcp_capable)(struct intel_digital_port *dig_port,
> > -			    bool *hdcp_capable);
> > -
> >  	/* HDCP adaptation(DP/HDMI) required on the port */
> >  	enum hdcp_wired_protocol protocol;
> >  
> > @@ -610,6 +553,7 @@ struct intel_connector {
> >  	struct work_struct modeset_retry_work;
> >  
> >  	struct intel_hdcp hdcp;
> > +	struct drm_hdcp_helper_data *hdcp_helper_data;
> >  };
> >  
> >  struct intel_digital_connector_state {
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > index 88689124c013..d61ac8d69951 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > @@ -55,17 +55,24 @@ static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
> >  		DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
> >  }
> >  
> > -static
> > -int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> > -				u8 *an)
> > +static int intel_dp_hdcp1_send_an_aksv(struct drm_connector *drm_connector)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> >  	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > +	struct drm_hdcp_an an;
> >  	u8 aksv[DRM_HDCP_KSV_LEN] = {};
> >  	ssize_t dpcd_ret;
> > +	int ret;
> >  
> >  	/* Output An first, that's easy */
> > +	ret = intel_hdcp1_read_an(drm_connector, &an);
> > +	if (ret)
> > +		return ret;
> > +
> 
> Interesting that the comment is old, but the new code with the
> old comment makes sense... I'm confused.
> Why do we need this extra read now?
> I believe this could be material for a separated patch for instance.
> 
> >  	dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux, DP_AUX_HDCP_AN,
> > -				     an, DRM_HDCP_AN_LEN);
> > +				     an.bytes, DRM_HDCP_AN_LEN);
> >  	if (dpcd_ret != DRM_HDCP_AN_LEN) {
> >  		drm_dbg_kms(&i915->drm,
> >  			    "Failed to write An over DP/AUX (%zd)\n",
> > @@ -91,158 +98,6 @@ int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> >  	return 0;
> >  }
> >  
> > -static int intel_dp_hdcp_read_bksv(struct intel_digital_port *dig_port,
> > -				   u8 *bksv)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	ssize_t ret;
> > -
> > -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
> > -			       DRM_HDCP_KSV_LEN);
> > -	if (ret != DRM_HDCP_KSV_LEN) {
> > -		drm_dbg_kms(&i915->drm,
> > -			    "Read Bksv from DP/AUX failed (%zd)\n", ret);
> > -		return ret >= 0 ? -EIO : ret;
> > -	}
> > -	return 0;
> > -}
> > -
> > -static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
> > -				      u8 *bstatus)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	ssize_t ret;
> > -
> > -	/*
> > -	 * For some reason the HDMI and DP HDCP specs call this register
> > -	 * definition by different names. In the HDMI spec, it's called BSTATUS,
> > -	 * but in DP it's called BINFO.
> > -	 */
> > -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BINFO,
> > -			       bstatus, DRM_HDCP_BSTATUS_LEN);
> > -	if (ret != DRM_HDCP_BSTATUS_LEN) {
> > -		drm_dbg_kms(&i915->drm,
> > -			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
> > -		return ret >= 0 ? -EIO : ret;
> > -	}
> > -	return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_read_bcaps(struct intel_digital_port *dig_port,
> > -			     u8 *bcaps)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	ssize_t ret;
> > -
> > -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
> > -			       bcaps, 1);
> > -	if (ret != 1) {
> > -		drm_dbg_kms(&i915->drm,
> > -			    "Read bcaps from DP/AUX failed (%zd)\n", ret);
> > -		return ret >= 0 ? -EIO : ret;
> > -	}
> > -
> > -	return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_repeater_present(struct intel_digital_port *dig_port,
> > -				   bool *repeater_present)
> > -{
> > -	ssize_t ret;
> > -	u8 bcaps;
> > -
> > -	ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
> > -	if (ret)
> > -		return ret;
> > -
> > -	*repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
> > -	return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
> > -				u8 *ri_prime)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	ssize_t ret;
> > -
> > -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
> > -			       ri_prime, DRM_HDCP_RI_LEN);
> > -	if (ret != DRM_HDCP_RI_LEN) {
> > -		drm_dbg_kms(&i915->drm, "Read Ri' from DP/AUX failed (%zd)\n",
> > -			    ret);
> > -		return ret >= 0 ? -EIO : ret;
> > -	}
> > -	return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
> > -				 bool *ksv_ready)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	ssize_t ret;
> > -	u8 bstatus;
> > -
> > -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
> > -			       &bstatus, 1);
> > -	if (ret != 1) {
> > -		drm_dbg_kms(&i915->drm,
> > -			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
> > -		return ret >= 0 ? -EIO : ret;
> > -	}
> > -	*ksv_ready = bstatus & DP_BSTATUS_READY;
> > -	return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
> > -				int num_downstream, u8 *ksv_fifo)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	ssize_t ret;
> > -	int i;
> > -
> > -	/* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
> > -	for (i = 0; i < num_downstream; i += 3) {
> > -		size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
> > -		ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > -				       DP_AUX_HDCP_KSV_FIFO,
> > -				       ksv_fifo + i * DRM_HDCP_KSV_LEN,
> > -				       len);
> > -		if (ret != len) {
> > -			drm_dbg_kms(&i915->drm,
> > -				    "Read ksv[%d] from DP/AUX failed (%zd)\n",
> > -				    i, ret);
> > -			return ret >= 0 ? -EIO : ret;
> > -		}
> > -	}
> > -	return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
> > -				    int i, u32 *part)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	ssize_t ret;
> > -
> > -	if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
> > -		return -EINVAL;
> > -
> > -	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > -			       DP_AUX_HDCP_V_PRIME(i), part,
> > -			       DRM_HDCP_V_PRIME_PART_LEN);
> > -	if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
> > -		drm_dbg_kms(&i915->drm,
> > -			    "Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
> > -		return ret >= 0 ? -EIO : ret;
> > -	}
> > -	return 0;
> > -}
> > -
> >  static
> >  int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
> >  				    enum transcoder cpu_transcoder,
> > @@ -252,40 +107,6 @@ int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
> >  	return 0;
> >  }
> >  
> > -static
> > -bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
> > -			      struct intel_connector *connector)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	ssize_t ret;
> > -	u8 bstatus;
> > -
> > -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
> > -			       &bstatus, 1);
> > -	if (ret != 1) {
> > -		drm_dbg_kms(&i915->drm,
> > -			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
> > -		return false;
> > -	}
> > -
> > -	return !(bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ));
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_capable(struct intel_digital_port *dig_port,
> > -			  bool *hdcp_capable)
> > -{
> > -	ssize_t ret;
> > -	u8 bcaps;
> > -
> > -	ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
> > -	if (ret)
> > -		return ret;
> > -
> > -	*hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
> > -	return 0;
> > -}
> > -
> >  struct hdcp2_dp_errata_stream_type {
> >  	u8	msg_id;
> >  	u8	stream_type;
> > @@ -628,13 +449,19 @@ int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port,
> >  	return ret;
> >  }
> >  
> > -static
> > -int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
> > -			   bool *capable)
> > +static int intel_dp_hdcp2_capable(struct drm_connector *drm_connector,
> > +				  bool *capable)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> >  	u8 rx_caps[3];
> >  	int ret;
> >  
> > +	ret = intel_hdcp2_capable(drm_connector, capable);
> > +	if (ret || !capable)
> > +		return ret;
> > +
> >  	*capable = false;
> >  	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> >  			       DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
> > @@ -650,22 +477,11 @@ int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
> >  }
> >  
> >  static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
> > -	.write_an_aksv = intel_dp_hdcp_write_an_aksv,
> > -	.read_bksv = intel_dp_hdcp_read_bksv,
> 
> Here is the part that I get fully stuck and don't know how to proceed in the
> review.
> I'd like to get someone with a stronger background in HDCP here, so I hope
> Suraj can help here.
> 
> When looking to the removed functions I end up in the enable and auth functions
> and I see that the sequence in the new drm ones introduced in the patch 04
> are totally different from the ones we had in i915. Hence I'm not comfortable
> with adding a review on a flow that I'm not totally familiar with.
> 
> But let me be clear: I really don't see any blocker in this patch. Even as is.
> I believe the smaller patch would help the review, but it is not mandatory.
> 
> That sad:
> 
> Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> 
> > -	.read_bstatus = intel_dp_hdcp_read_bstatus,
> > -	.repeater_present = intel_dp_hdcp_repeater_present,
> > -	.read_ri_prime = intel_dp_hdcp_read_ri_prime,
> > -	.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
> > -	.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
> > -	.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
> >  	.toggle_signalling = intel_dp_hdcp_toggle_signalling,
> > -	.check_link = intel_dp_hdcp_check_link,
> > -	.hdcp_capable = intel_dp_hdcp_capable,
> >  	.write_2_2_msg = intel_dp_hdcp2_write_msg,
> >  	.read_2_2_msg = intel_dp_hdcp2_read_msg,
> >  	.config_stream_type = intel_dp_hdcp2_config_stream_type,
> >  	.check_2_2_link = intel_dp_hdcp2_check_link,
> > -	.hdcp_2_2_capable = intel_dp_hdcp2_capable,
> >  	.protocol = HDCP_PROTOCOL_DP,
> >  };
> >  
> > @@ -721,6 +537,46 @@ intel_dp_mst_hdcp_stream_encryption(struct intel_connector *connector,
> >  	return 0;
> >  }
> >  
> > +static int
> > +intel_dp_mst_hdcp1_post_encryption(struct drm_connector *drm_connector)
> > +{
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	int ret;
> > +
> > +	ret = intel_hdcp1_post_encryption(drm_connector);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return intel_dp_mst_hdcp_stream_encryption(connector, true);
> > +}
> > +
> > +static int intel_dp_mst_hdcp1_disable(struct drm_connector *drm_connector)
> > +{
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> > +	struct drm_i915_private *i915 = to_i915(connector->base.dev);
> > +	int ret;
> > +
> > +	ret = intel_dp_mst_hdcp_stream_encryption(connector, true);
> > +	if (ret) {
> > +		drm_err(&i915->drm,
> > +			"[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
> > +			connector->base.name, connector->base.base.id);
> > +		return ret;
> > +	}
> > +
> > +	/*
> > +	 * If there are other connectors on this port using HDCP,
> > +	 * don't disable it until it disabled HDCP encryption for
> > +	 * all connectors in MST topology.
> > +	*/
> > +	if (dig_port->num_hdcp_streams > 0)
> > +		return 0;
> > +
> > +	return intel_hdcp1_disable(drm_connector);
> > +}
> > +
> >  static int
> >  intel_dp_mst_hdcp2_stream_encryption(struct intel_connector *connector,
> >  				     bool enable)
> > @@ -779,45 +635,85 @@ int intel_dp_mst_hdcp2_check_link(struct intel_digital_port *dig_port,
> >  }
> >  
> >  static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
> > -	.write_an_aksv = intel_dp_hdcp_write_an_aksv,
> > -	.read_bksv = intel_dp_hdcp_read_bksv,
> > -	.read_bstatus = intel_dp_hdcp_read_bstatus,
> > -	.repeater_present = intel_dp_hdcp_repeater_present,
> > -	.read_ri_prime = intel_dp_hdcp_read_ri_prime,
> > -	.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
> > -	.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
> > -	.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
> >  	.toggle_signalling = intel_dp_hdcp_toggle_signalling,
> > -	.stream_encryption = intel_dp_mst_hdcp_stream_encryption,
> > -	.check_link = intel_dp_hdcp_check_link,
> > -	.hdcp_capable = intel_dp_hdcp_capable,
> >  	.write_2_2_msg = intel_dp_hdcp2_write_msg,
> >  	.read_2_2_msg = intel_dp_hdcp2_read_msg,
> >  	.config_stream_type = intel_dp_hdcp2_config_stream_type,
> >  	.stream_2_2_encryption = intel_dp_mst_hdcp2_stream_encryption,
> >  	.check_2_2_link = intel_dp_mst_hdcp2_check_link,
> > -	.hdcp_2_2_capable = intel_dp_hdcp2_capable,
> >  	.protocol = HDCP_PROTOCOL_DP,
> >  };
> >  
> > +static const struct drm_hdcp_helper_funcs intel_dp_hdcp_helper_funcs = {
> > +	.setup = intel_hdcp_setup,
> > +	.load_keys = intel_hdcp_load_keys,
> > +	.hdcp2_capable = intel_dp_hdcp2_capable,
> > +	.hdcp2_enable = intel_hdcp2_enable,
> > +	.hdcp2_check_link = intel_hdcp2_check_link,
> > +	.hdcp2_disable = intel_hdcp2_disable,
> > +	.hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
> > +	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> > +	.hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
> > +	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> > +	.hdcp1_match_ri = intel_hdcp1_match_ri,
> > +	.hdcp1_post_encryption = intel_hdcp1_post_encryption,
> > +	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> > +	.hdcp1_disable = intel_hdcp1_disable,
> > +};
> > +
> > +static const struct drm_hdcp_helper_funcs intel_dp_mst_hdcp_helper_funcs = {
> > +	.setup = intel_hdcp_setup,
> > +	.load_keys = intel_hdcp_load_keys,
> > +	.hdcp2_capable = intel_dp_hdcp2_capable,
> > +	.hdcp2_enable = intel_hdcp2_enable,
> > +	.hdcp2_check_link = intel_hdcp2_check_link,
> > +	.hdcp2_disable = intel_hdcp2_disable,
> > +	.hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
> > +	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> > +	.hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
> > +	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> > +	.hdcp1_match_ri = intel_hdcp1_match_ri,
> > +	.hdcp1_post_encryption = intel_dp_mst_hdcp1_post_encryption,
> > +	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> > +	.hdcp1_disable = intel_dp_mst_hdcp1_disable,
> > +};
> > +
> >  int intel_dp_hdcp_init(struct intel_digital_port *dig_port,
> > -		       struct intel_connector *intel_connector)
> > +		       struct intel_connector *connector)
> >  {
> > -	struct drm_device *dev = intel_connector->base.dev;
> > -	struct drm_i915_private *dev_priv = to_i915(dev);
> > +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >  	struct intel_encoder *intel_encoder = &dig_port->base;
> >  	enum port port = intel_encoder->port;
> >  	struct intel_dp *intel_dp = &dig_port->dp;
> > +	struct drm_hdcp_helper_data *data;
> > +	const struct drm_hdcp_helper_funcs *helper_funcs;
> > +	const struct intel_hdcp_shim *intel_shim;
> > +	int ret;
> >  
> > -	if (!is_hdcp_supported(dev_priv, port))
> > +	if (!is_hdcp_supported(dev_priv, port) || intel_dp_is_edp(intel_dp))
> >  		return 0;
> >  
> > -	if (intel_connector->mst_port)
> > -		return intel_hdcp_init(intel_connector, dig_port,
> > -				       &intel_dp_mst_hdcp_shim);
> > -	else if (!intel_dp_is_edp(intel_dp))
> > -		return intel_hdcp_init(intel_connector, dig_port,
> > -				       &intel_dp_hdcp_shim);
> > +	if (connector->mst_port) {
> > +		helper_funcs = &intel_dp_mst_hdcp_helper_funcs;
> > +		intel_shim = &intel_dp_mst_hdcp_shim;
> > +	} else {
> > +		helper_funcs = &intel_dp_hdcp_helper_funcs;
> > +		intel_shim = &intel_dp_hdcp_shim;
> > +	}
> > +
> > +	data = drm_hdcp_helper_initialize_dp(
> > +		&connector->base, &dig_port->dp.aux, helper_funcs, true);
> > +	if (IS_ERR(data)) {
> > +		drm_dbg_kms(&dev_priv->drm, "HDCP init failed, skipping.\n");
> > +		return PTR_ERR(data);
> > +	}
> > +
> > +	ret = intel_hdcp_init(connector, dig_port, intel_shim);
> > +	if (ret) {
> > +		drm_hdcp_helper_destroy(data);
> > +		return ret;
> > +	}
> >  
> > +	connector->hdcp_helper_data = data;
> >  	return 0;
> >  }
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > index 03604a37931c..ececb7aa4b90 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > @@ -27,6 +27,7 @@
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_edid.h>
> >  #include <drm/drm_probe_helper.h>
> > +#include <drm/display/drm_hdcp_helper.h>
> >  
> >  #include "i915_drv.h"
> >  #include "intel_atomic.h"
> > @@ -40,7 +41,6 @@
> >  #include "intel_dp_hdcp.h"
> >  #include "intel_dp_mst.h"
> >  #include "intel_dpio_phy.h"
> > -#include "intel_hdcp.h"
> >  #include "intel_hotplug.h"
> >  #include "skl_scaler.h"
> >  
> > @@ -371,7 +371,10 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,
> >  	drm_dbg_kms(&i915->drm, "active links %d\n",
> >  		    intel_dp->active_mst_links);
> >  
> > -	intel_hdcp_disable(intel_mst->connector);
> > +	if (connector->hdcp_helper_data)
> > +		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
> > +					      &state->base,
> > +					      &dig_port->hdcp_mutex);
> >  
> >  	drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state,
> >  			      drm_atomic_get_mst_payload_state(mst_state, connector->port));
> > @@ -579,11 +582,10 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
> >  	intel_audio_codec_enable(encoder, pipe_config, conn_state);
> >  
> >  	/* Enable hdcp if it's desired */
> > -	if (conn_state->content_protection ==
> > -	    DRM_MODE_CONTENT_PROTECTION_DESIRED)
> > -		intel_hdcp_enable(to_intel_connector(conn_state->connector),
> > -				  pipe_config,
> > -				  (u8)conn_state->hdcp_content_type);
> > +	if (connector->hdcp_helper_data)
> > +		drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
> > +					      &state->base,
> > +					      &dig_port->hdcp_mutex);
> >  }
> >  
> >  static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
> > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > index 61a862ae1f28..f09afbc9567b 100644
> > --- a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > @@ -140,67 +140,10 @@ static int intel_hdcp_prepare_streams(struct intel_connector *connector)
> >  	return 0;
> >  }
> >  
> > -static
> > -bool intel_hdcp_is_ksv_valid(u8 *ksv)
> > -{
> > -	int i, ones = 0;
> > -	/* KSV has 20 1's and 20 0's */
> > -	for (i = 0; i < DRM_HDCP_KSV_LEN; i++)
> > -		ones += hweight8(ksv[i]);
> > -	if (ones != 20)
> > -		return false;
> > -
> > -	return true;
> > -}
> > -
> > -static
> > -int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port,
> > -			       const struct intel_hdcp_shim *shim, u8 *bksv)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	int ret, i, tries = 2;
> > -
> > -	/* HDCP spec states that we must retry the bksv if it is invalid */
> > -	for (i = 0; i < tries; i++) {
> > -		ret = shim->read_bksv(dig_port, bksv);
> > -		if (ret)
> > -			return ret;
> > -		if (intel_hdcp_is_ksv_valid(bksv))
> > -			break;
> > -	}
> > -	if (i == tries) {
> > -		drm_dbg_kms(&i915->drm, "Bksv is invalid\n");
> > -		return -ENODEV;
> > -	}
> > -
> > -	return 0;
> > -}
> > -
> > -/* Is HDCP1.4 capable on Platform and Sink */
> > -int intel_hdcp_capable(struct intel_connector *connector, bool *capable)
> > -{
> > -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> > -	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> > -	u8 bksv[5];
> > -
> > -	*capable = false;
> > -
> > -	if (!shim)
> > -		return 0;
> > -
> > -	if (shim->hdcp_capable)
> > -		return shim->hdcp_capable(dig_port, capable);
> > -
> > -	if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> > -		*capable = true;
> > -
> > -	return 0;
> > -}
> > -
> >  /* Is HDCP2.2 capable on Platform and Sink */
> > -int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
> > +int intel_hdcp2_capable(struct drm_connector *drm_connector, bool *capable)
> >  {
> > -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> >  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >  	struct intel_hdcp *hdcp = &connector->hdcp;
> >  
> > @@ -218,16 +161,26 @@ int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
> >  	}
> >  	mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> >  
> > -	/* Sink's capability for HDCP2.2 */
> > -	return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
> > +	return 0;
> >  }
> >  
> > -static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv,
> > -			      enum transcoder cpu_transcoder, enum port port)
> > +int intel_hdcp1_check_link(struct drm_connector *drm_connector)
> >  {
> > -	return intel_de_read(dev_priv,
> > -	                     HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> > -	       HDCP_STATUS_ENC;
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> > +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> > +	enum port port = dig_port->base.port;
> > +	u32 val;
> > +
> > +	val = intel_de_read(dev_priv,
> > +			    HDCP_STATUS(dev_priv, cpu_transcoder, port));
> > +
> > +	if (val & HDCP_STATUS_ENC)
> > +		return 0;
> > +
> > +	return -EINVAL;
> >  }
> >  
> >  static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
> > @@ -238,27 +191,6 @@ static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
> >  	       LINK_ENCRYPTION_STATUS;
> >  }
> >  
> > -static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *dig_port,
> > -				    const struct intel_hdcp_shim *shim)
> > -{
> > -	int ret, read_ret;
> > -	bool ksv_ready;
> > -
> > -	/* Poll for ksv list ready (spec says max time allowed is 5s) */
> > -	ret = __wait_for(read_ret = shim->read_ksv_ready(dig_port,
> > -							 &ksv_ready),
> > -			 read_ret || ksv_ready, 5 * 1000 * 1000, 1000,
> > -			 100 * 1000);
> > -	if (ret)
> > -		return ret;
> > -	if (read_ret)
> > -		return read_ret;
> > -	if (!ksv_ready)
> > -		return -ETIMEDOUT;
> > -
> > -	return 0;
> > -}
> > -
> >  static bool hdcp_key_loadable(struct drm_i915_private *dev_priv)
> >  {
> >  	enum i915_power_well_id id;
> > @@ -294,11 +226,18 @@ static void intel_hdcp_clear_keys(struct drm_i915_private *dev_priv)
> >  		       HDCP_KEY_LOAD_DONE | HDCP_KEY_LOAD_STATUS | HDCP_FUSE_IN_PROGRESS | HDCP_FUSE_ERROR | HDCP_FUSE_DONE);
> >  }
> >  
> > -static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
> > +int intel_hdcp_load_keys(struct drm_connector *drm_connector)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >  	int ret;
> >  	u32 val;
> >  
> > +	if (!hdcp_key_loadable(dev_priv)) {
> > +		drm_err(&dev_priv->drm, "HDCP key Load is not possible\n");
> > +		return -ENXIO;
> > +	}
> > +
> >  	val = intel_de_read(dev_priv, HDCP_KEY_STATUS);
> >  	if ((val & HDCP_KEY_LOAD_DONE) && (val & HDCP_KEY_LOAD_STATUS))
> >  		return 0;
> > @@ -308,8 +247,11 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
> >  	 * out of reset. So if Key is not already loaded, its an error state.
> >  	 */
> >  	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
> > -		if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) & HDCP_KEY_LOAD_DONE))
> > -			return -ENXIO;
> > +		if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) &
> > +		      HDCP_KEY_LOAD_DONE)) {
> > +			ret = -ENXIO;
> > +			goto err;
> > +		}
> >  
> >  	/*
> >  	 * Initiate loading the HDCP key from fuses.
> > @@ -325,7 +267,7 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
> >  			drm_err(&dev_priv->drm,
> >  				"Failed to initiate HDCP key load (%d)\n",
> >  				ret);
> > -			return ret;
> > +			goto err;
> >  		}
> >  	} else {
> >  		intel_de_write(dev_priv, HDCP_KEY_CONF, HDCP_KEY_LOAD_TRIGGER);
> > @@ -335,15 +277,21 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
> >  	ret = __intel_wait_for_register(&dev_priv->uncore, HDCP_KEY_STATUS,
> >  					HDCP_KEY_LOAD_DONE, HDCP_KEY_LOAD_DONE,
> >  					10, 1, &val);
> > -	if (ret)
> > -		return ret;
> > -	else if (!(val & HDCP_KEY_LOAD_STATUS))
> > -		return -ENXIO;
> > +	if (ret) {
> > +		goto err;
> > +	} else if (!(val & HDCP_KEY_LOAD_STATUS)) {
> > +		ret = -ENXIO;
> > +		goto err;
> > +	}
> >  
> >  	/* Send Aksv over to PCH display for use in authentication */
> >  	intel_de_write(dev_priv, HDCP_KEY_CONF, HDCP_AKSV_SEND_TRIGGER);
> >  
> >  	return 0;
> > +
> > +err:
> > +	intel_hdcp_clear_keys(dev_priv);
> > +	return ret;
> >  }
> >  
> >  /* Returns updated SHA-1 index */
> > @@ -399,25 +347,21 @@ u32 intel_hdcp_get_repeater_ctl(struct drm_i915_private *dev_priv,
> >  	}
> >  }
> >  
> > -static
> > -int intel_hdcp_validate_v_prime(struct intel_connector *connector,
> > -				const struct intel_hdcp_shim *shim,
> > -				u8 *ksv_fifo, u8 num_downstream, u8 *bstatus)
> > +int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
> > +			       u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
> > +			       u32 *v_prime)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> >  	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> >  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >  	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> >  	enum port port = dig_port->base.port;
> > -	u32 vprime, sha_text, sha_leftovers, rep_ctl;
> > +	u32 sha_text, sha_leftovers, rep_ctl;
> >  	int ret, i, j, sha_idx;
> >  
> >  	/* Process V' values from the receiver */
> > -	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
> > -		ret = shim->read_v_prime_part(dig_port, i, &vprime);
> > -		if (ret)
> > -			return ret;
> > -		intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), vprime);
> > -	}
> > +	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++)
> > +		intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), v_prime[i]);
> >  
> >  	/*
> >  	 * We need to write the concatenation of all device KSVs, BINFO (DP) ||
> > @@ -642,131 +586,38 @@ int intel_hdcp_validate_v_prime(struct intel_connector *connector,
> >  	return 0;
> >  }
> >  
> > -/* Implements Part 2 of the HDCP authorization procedure */
> > -static
> > -int intel_hdcp_auth_downstream(struct intel_connector *connector)
> > +int intel_hdcp1_store_receiver_info(struct drm_connector *drm_connector,
> > +				    u32 *ksv, u32 status, u8 caps,
> > +				    bool repeater_present)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> >  	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> >  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> > -	u8 bstatus[2], num_downstream, *ksv_fifo;
> > -	int ret, i, tries = 3;
> > -
> > -	ret = intel_hdcp_poll_ksv_fifo(dig_port, shim);
> > -	if (ret) {
> > -		drm_dbg_kms(&dev_priv->drm,
> > -			    "KSV list failed to become ready (%d)\n", ret);
> > -		return ret;
> > -	}
> > -
> > -	ret = shim->read_bstatus(dig_port, bstatus);
> > -	if (ret)
> > -		return ret;
> > -
> > -	if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
> > -	    DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
> > -		drm_dbg_kms(&dev_priv->drm, "Max Topology Limit Exceeded\n");
> > -		return -EPERM;
> > -	}
> > -
> > -	/*
> > -	 * When repeater reports 0 device count, HDCP1.4 spec allows disabling
> > -	 * the HDCP encryption. That implies that repeater can't have its own
> > -	 * display. As there is no consumption of encrypted content in the
> > -	 * repeater with 0 downstream devices, we are failing the
> > -	 * authentication.
> > -	 */
> > -	num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
> > -	if (num_downstream == 0) {
> > -		drm_dbg_kms(&dev_priv->drm,
> > -			    "Repeater with zero downstream devices\n");
> > -		return -EINVAL;
> > -	}
> > -
> > -	ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream, GFP_KERNEL);
> > -	if (!ksv_fifo) {
> > -		drm_dbg_kms(&dev_priv->drm, "Out of mem: ksv_fifo\n");
> > -		return -ENOMEM;
> > -	}
> > -
> > -	ret = shim->read_ksv_fifo(dig_port, num_downstream, ksv_fifo);
> > -	if (ret)
> > -		goto err;
> > -
> > -	if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, ksv_fifo,
> > -					num_downstream) > 0) {
> > -		drm_err(&dev_priv->drm, "Revoked Ksv(s) in ksv_fifo\n");
> > -		ret = -EPERM;
> > -		goto err;
> > -	}
> > +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> > +	enum port port = dig_port->base.port;
> >  
> > -	/*
> > -	 * When V prime mismatches, DP Spec mandates re-read of
> > -	 * V prime atleast twice.
> > -	 */
> > -	for (i = 0; i < tries; i++) {
> > -		ret = intel_hdcp_validate_v_prime(connector, shim,
> > -						  ksv_fifo, num_downstream,
> > -						  bstatus);
> > -		if (!ret)
> > -			break;
> > -	}
> > +	intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder, port),
> > +		       ksv[0]);
> > +	intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder, port),
> > +		       ksv[1]);
> >  
> > -	if (i == tries) {
> > -		drm_dbg_kms(&dev_priv->drm,
> > -			    "V Prime validation failed.(%d)\n", ret);
> > -		goto err;
> > -	}
> > +	if (repeater_present)
> > +		intel_de_write(dev_priv, HDCP_REP_CTL,
> > +			       intel_hdcp_get_repeater_ctl(
> > +				       dev_priv, cpu_transcoder, port));
> >  
> > -	drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (%d downstream devices)\n",
> > -		    num_downstream);
> > -	ret = 0;
> > -err:
> > -	kfree(ksv_fifo);
> > -	return ret;
> > +	return 0;
> >  }
> >  
> > -/* Implements Part 1 of the HDCP authorization procedure */
> > -static int intel_hdcp_auth(struct intel_connector *connector)
> > +int intel_hdcp1_read_an(struct drm_connector *drm_connector,
> > +			struct drm_hdcp_an *an)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> >  	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> >  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -	struct intel_hdcp *hdcp = &connector->hdcp;
> > -	const struct intel_hdcp_shim *shim = hdcp->shim;
> >  	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> >  	enum port port = dig_port->base.port;
> > -	unsigned long r0_prime_gen_start;
> > -	int ret, i, tries = 2;
> > -	union {
> > -		u32 reg[2];
> > -		u8 shim[DRM_HDCP_AN_LEN];
> > -	} an;
> > -	union {
> > -		u32 reg[2];
> > -		u8 shim[DRM_HDCP_KSV_LEN];
> > -	} bksv;
> > -	union {
> > -		u32 reg;
> > -		u8 shim[DRM_HDCP_RI_LEN];
> > -	} ri;
> > -	bool repeater_present, hdcp_capable;
> > -
> > -	/*
> > -	 * Detects whether the display is HDCP capable. Although we check for
> > -	 * valid Bksv below, the HDCP over DP spec requires that we check
> > -	 * whether the display supports HDCP before we write An. For HDMI
> > -	 * displays, this is not necessary.
> > -	 */
> > -	if (shim->hdcp_capable) {
> > -		ret = shim->hdcp_capable(dig_port, &hdcp_capable);
> > -		if (ret)
> > -			return ret;
> > -		if (!hdcp_capable) {
> > -			drm_dbg_kms(&dev_priv->drm,
> > -				    "Panel is not HDCP capable\n");
> > -			return -EINVAL;
> > -		}
> > -	}
> > +	int i;
> >  
> >  	/* Initialize An with 2 random values and acquire it */
> >  	for (i = 0; i < 2; i++)
> > @@ -784,92 +635,81 @@ static int intel_hdcp_auth(struct intel_connector *connector)
> >  		return -ETIMEDOUT;
> >  	}
> >  
> > -	an.reg[0] = intel_de_read(dev_priv,
> > -				  HDCP_ANLO(dev_priv, cpu_transcoder, port));
> > -	an.reg[1] = intel_de_read(dev_priv,
> > -				  HDCP_ANHI(dev_priv, cpu_transcoder, port));
> > -	ret = shim->write_an_aksv(dig_port, an.shim);
> > -	if (ret)
> > -		return ret;
> > +	an->words[0] = intel_de_read(dev_priv,
> > +				     HDCP_ANLO(dev_priv, cpu_transcoder, port));
> > +	an->words[1] = intel_de_read(dev_priv,
> > +				     HDCP_ANHI(dev_priv, cpu_transcoder, port));
> >  
> > -	r0_prime_gen_start = jiffies;
> > -
> > -	memset(&bksv, 0, sizeof(bksv));
> > -
> > -	ret = intel_hdcp_read_valid_bksv(dig_port, shim, bksv.shim);
> > -	if (ret < 0)
> > -		return ret;
> > -
> > -	if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, bksv.shim, 1) > 0) {
> > -		drm_err(&dev_priv->drm, "BKSV is revoked\n");
> > -		return -EPERM;
> > -	}
> > -
> > -	intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder, port),
> > -		       bksv.reg[0]);
> > -	intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder, port),
> > -		       bksv.reg[1]);
> > -
> > -	ret = shim->repeater_present(dig_port, &repeater_present);
> > -	if (ret)
> > -		return ret;
> > -	if (repeater_present)
> > -		intel_de_write(dev_priv, HDCP_REP_CTL,
> > -			       intel_hdcp_get_repeater_ctl(dev_priv, cpu_transcoder, port));
> > +	return 0;
> > +}
> >  
> > -	ret = shim->toggle_signalling(dig_port, cpu_transcoder, true);
> > -	if (ret)
> > -		return ret;
> > +int intel_hdcp1_enable_encryption(struct drm_connector *drm_connector)
> > +{
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> > +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> > +	enum port port = dig_port->base.port;
> >  
> >  	intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port),
> >  		       HDCP_CONF_AUTH_AND_ENC);
> >  
> > +	return 0;
> > +}
> > +
> > +int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector)
> > +{
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> > +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> > +	enum port port = dig_port->base.port;
> > +
> >  	/* Wait for R0 ready */
> > -	if (wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> > -		     (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), 1)) {
> > +	if (wait_for((intel_de_read(dev_priv,
> > +				    HDCP_STATUS(dev_priv, cpu_transcoder,
> > +						port))) &
> > +			     (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC),
> > +		     1)) {
> >  		drm_err(&dev_priv->drm, "Timed out waiting for R0 ready\n");
> >  		return -ETIMEDOUT;
> >  	}
> >  
> > -	/*
> > -	 * Wait for R0' to become available. The spec says 100ms from Aksv, but
> > -	 * some monitors can take longer than this. We'll set the timeout at
> > -	 * 300ms just to be sure.
> > -	 *
> > -	 * On DP, there's an R0_READY bit available but no such bit
> > -	 * exists on HDMI. Since the upper-bound is the same, we'll just do
> > -	 * the stupid thing instead of polling on one and not the other.
> > -	 */
> > -	wait_remaining_ms_from_jiffies(r0_prime_gen_start, 300);
> > -
> > -	tries = 3;
> > +	return 0;
> > +}
> >  
> > -	/*
> > -	 * DP HDCP Spec mandates the two more reattempt to read R0, incase
> > -	 * of R0 mismatch.
> > -	 */
> > -	for (i = 0; i < tries; i++) {
> > -		ri.reg = 0;
> > -		ret = shim->read_ri_prime(dig_port, ri.shim);
> > -		if (ret)
> > -			return ret;
> > -		intel_de_write(dev_priv,
> > -			       HDCP_RPRIME(dev_priv, cpu_transcoder, port),
> > -			       ri.reg);
> > +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32 ri_prime)
> > +{
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> > +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> > +	enum port port = dig_port->base.port;
> >  
> > -		/* Wait for Ri prime match */
> > -		if (!wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> > -			      (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1))
> > -			break;
> > -	}
> > +	intel_de_write(dev_priv, HDCP_RPRIME(dev_priv, cpu_transcoder, port),
> > +		       ri_prime);
> >  
> > -	if (i == tries) {
> > -		drm_dbg_kms(&dev_priv->drm,
> > -			    "Timed out waiting for Ri prime match (%x)\n",
> > -			    intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> > -					  cpu_transcoder, port)));
> > +	/* Wait for Ri prime match */
> > +	if (wait_for(intel_de_read(dev_priv,
> > +				   HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> > +			     (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC),
> > +		     1))
> >  		return -ETIMEDOUT;
> > -	}
> > +
> > +	return 0;
> > +}
> > +
> > +int intel_hdcp1_post_encryption(struct drm_connector *drm_connector)
> > +{
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> > +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> > +	enum port port = dig_port->base.port;
> >  
> >  	/* Wait for encryption confirmation */
> >  	if (intel_de_wait_for_set(dev_priv,
> > @@ -880,56 +720,22 @@ static int intel_hdcp_auth(struct intel_connector *connector)
> >  		return -ETIMEDOUT;
> >  	}
> >  
> > -	/* DP MST Auth Part 1 Step 2.a and Step 2.b */
> > -	if (shim->stream_encryption) {
> > -		ret = shim->stream_encryption(connector, true);
> > -		if (ret) {
> > -			drm_err(&dev_priv->drm, "[%s:%d] Failed to enable HDCP 1.4 stream enc\n",
> > -				connector->base.name, connector->base.base.id);
> > -			return ret;
> > -		}
> > -		drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s stream encrypted\n",
> > -			    transcoder_name(hdcp->stream_transcoder));
> > -	}
> > -
> > -	if (repeater_present)
> > -		return intel_hdcp_auth_downstream(connector);
> > -
> > -	drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (no repeater present)\n");
> >  	return 0;
> >  }
> >  
> > -static int _intel_hdcp_disable(struct intel_connector *connector)
> > +int intel_hdcp1_disable(struct drm_connector *drm_connector)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> >  	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> >  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >  	struct intel_hdcp *hdcp = &connector->hdcp;
> >  	enum port port = dig_port->base.port;
> >  	enum transcoder cpu_transcoder = hdcp->cpu_transcoder;
> >  	u32 repeater_ctl;
> > -	int ret;
> >  
> >  	drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being disabled...\n",
> >  		    connector->base.name, connector->base.base.id);
> >  
> > -	if (hdcp->shim->stream_encryption) {
> > -		ret = hdcp->shim->stream_encryption(connector, false);
> > -		if (ret) {
> > -			drm_err(&dev_priv->drm, "[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
> > -				connector->base.name, connector->base.base.id);
> > -			return ret;
> > -		}
> > -		drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s stream encryption disabled\n",
> > -			    transcoder_name(hdcp->stream_transcoder));
> > -		/*
> > -		 * If there are other connectors on this port using HDCP,
> > -		 * don't disable it until it disabled HDCP encryption for
> > -		 * all connectors in MST topology.
> > -		 */
> > -		if (dig_port->num_hdcp_streams > 0)
> > -			return 0;
> > -	}
> > -
> >  	hdcp->hdcp_encrypted = false;
> >  	intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port), 0);
> >  	if (intel_de_wait_for_clear(dev_priv,
> > @@ -945,190 +751,9 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
> >  	intel_de_write(dev_priv, HDCP_REP_CTL,
> >  		       intel_de_read(dev_priv, HDCP_REP_CTL) & ~repeater_ctl);
> >  
> > -	ret = hdcp->shim->toggle_signalling(dig_port, cpu_transcoder, false);
> > -	if (ret) {
> > -		drm_err(&dev_priv->drm, "Failed to disable HDCP signalling\n");
> > -		return ret;
> > -	}
> > -
> > -	drm_dbg_kms(&dev_priv->drm, "HDCP is disabled\n");
> >  	return 0;
> >  }
> >  
> > -static int _intel_hdcp_enable(struct intel_connector *connector)
> > -{
> > -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -	struct intel_hdcp *hdcp = &connector->hdcp;
> > -	int i, ret, tries = 3;
> > -
> > -	drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being enabled...\n",
> > -		    connector->base.name, connector->base.base.id);
> > -
> > -	if (!hdcp_key_loadable(dev_priv)) {
> > -		drm_err(&dev_priv->drm, "HDCP key Load is not possible\n");
> > -		return -ENXIO;
> > -	}
> > -
> > -	for (i = 0; i < KEY_LOAD_TRIES; i++) {
> > -		ret = intel_hdcp_load_keys(dev_priv);
> > -		if (!ret)
> > -			break;
> > -		intel_hdcp_clear_keys(dev_priv);
> > -	}
> > -	if (ret) {
> > -		drm_err(&dev_priv->drm, "Could not load HDCP keys, (%d)\n",
> > -			ret);
> > -		return ret;
> > -	}
> > -
> > -	/* Incase of authentication failures, HDCP spec expects reauth. */
> > -	for (i = 0; i < tries; i++) {
> > -		ret = intel_hdcp_auth(connector);
> > -		if (!ret) {
> > -			hdcp->hdcp_encrypted = true;
> > -			return 0;
> > -		}
> > -
> > -		drm_dbg_kms(&dev_priv->drm, "HDCP Auth failure (%d)\n", ret);
> > -
> > -		/* Ensuring HDCP encryption and signalling are stopped. */
> > -		_intel_hdcp_disable(connector);
> > -	}
> > -
> > -	drm_dbg_kms(&dev_priv->drm,
> > -		    "HDCP authentication failed (%d tries/%d)\n", tries, ret);
> > -	return ret;
> > -}
> > -
> > -static struct intel_connector *intel_hdcp_to_connector(struct intel_hdcp *hdcp)
> > -{
> > -	return container_of(hdcp, struct intel_connector, hdcp);
> > -}
> > -
> > -static void intel_hdcp_update_value(struct intel_connector *connector,
> > -				    u64 value, bool update_property)
> > -{
> > -	struct drm_device *dev = connector->base.dev;
> > -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> > -	struct intel_hdcp *hdcp = &connector->hdcp;
> > -
> > -	drm_WARN_ON(connector->base.dev, !mutex_is_locked(&hdcp->mutex));
> > -
> > -	if (hdcp->value == value)
> > -		return;
> > -
> > -	drm_WARN_ON(dev, !mutex_is_locked(&dig_port->hdcp_mutex));
> > -
> > -	if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> > -		if (!drm_WARN_ON(dev, dig_port->num_hdcp_streams == 0))
> > -			dig_port->num_hdcp_streams--;
> > -	} else if (value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> > -		dig_port->num_hdcp_streams++;
> > -	}
> > -
> > -	hdcp->value = value;
> > -	if (update_property) {
> > -		drm_connector_get(&connector->base);
> > -		schedule_work(&hdcp->prop_work);
> > -	}
> > -}
> > -
> > -/* Implements Part 3 of the HDCP authorization procedure */
> > -static int intel_hdcp_check_link(struct intel_connector *connector)
> > -{
> > -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> > -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -	struct intel_hdcp *hdcp = &connector->hdcp;
> > -	enum port port = dig_port->base.port;
> > -	enum transcoder cpu_transcoder;
> > -	int ret = 0;
> > -
> > -	mutex_lock(&hdcp->mutex);
> > -	mutex_lock(&dig_port->hdcp_mutex);
> > -
> > -	cpu_transcoder = hdcp->cpu_transcoder;
> > -
> > -	/* Check_link valid only when HDCP1.4 is enabled */
> > -	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED ||
> > -	    !hdcp->hdcp_encrypted) {
> > -		ret = -EINVAL;
> > -		goto out;
> > -	}
> > -
> > -	if (drm_WARN_ON(&dev_priv->drm,
> > -			!intel_hdcp_in_use(dev_priv, cpu_transcoder, port))) {
> > -		drm_err(&dev_priv->drm,
> > -			"%s:%d HDCP link stopped encryption,%x\n",
> > -			connector->base.name, connector->base.base.id,
> > -			intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)));
> > -		ret = -ENXIO;
> > -		intel_hdcp_update_value(connector,
> > -					DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > -					true);
> > -		goto out;
> > -	}
> > -
> > -	if (hdcp->shim->check_link(dig_port, connector)) {
> > -		if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> > -			intel_hdcp_update_value(connector,
> > -				DRM_MODE_CONTENT_PROTECTION_ENABLED, true);
> > -		}
> > -		goto out;
> > -	}
> > -
> > -	drm_dbg_kms(&dev_priv->drm,
> > -		    "[%s:%d] HDCP link failed, retrying authentication\n",
> > -		    connector->base.name, connector->base.base.id);
> > -
> > -	ret = _intel_hdcp_disable(connector);
> > -	if (ret) {
> > -		drm_err(&dev_priv->drm, "Failed to disable hdcp (%d)\n", ret);
> > -		intel_hdcp_update_value(connector,
> > -					DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > -					true);
> > -		goto out;
> > -	}
> > -
> > -	ret = _intel_hdcp_enable(connector);
> > -	if (ret) {
> > -		drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n", ret);
> > -		intel_hdcp_update_value(connector,
> > -					DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > -					true);
> > -		goto out;
> > -	}
> > -
> > -out:
> > -	mutex_unlock(&dig_port->hdcp_mutex);
> > -	mutex_unlock(&hdcp->mutex);
> > -	return ret;
> > -}
> > -
> > -static void intel_hdcp_prop_work(struct work_struct *work)
> > -{
> > -	struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp,
> > -					       prop_work);
> > -	struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
> > -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -
> > -	drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, NULL);
> > -	mutex_lock(&hdcp->mutex);
> > -
> > -	/*
> > -	 * This worker is only used to flip between ENABLED/DESIRED. Either of
> > -	 * those to UNDESIRED is handled by core. If value == UNDESIRED,
> > -	 * we're running just after hdcp has been disabled, so just exit
> > -	 */
> > -	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> > -		drm_hdcp_update_content_protection(&connector->base,
> > -						   hdcp->value);
> > -
> > -	mutex_unlock(&hdcp->mutex);
> > -	drm_modeset_unlock(&dev_priv->drm.mode_config.connection_mutex);
> > -
> > -	drm_connector_put(&connector->base);
> > -}
> > -
> >  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port)
> >  {
> >  	return RUNTIME_INFO(dev_priv)->has_hdcp &&
> > @@ -1961,8 +1586,9 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
> >  	return ret;
> >  }
> >  
> > -static int _intel_hdcp2_enable(struct intel_connector *connector)
> > +int intel_hdcp2_enable(struct drm_connector *drm_connector)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> >  	struct drm_i915_private *i915 = to_i915(connector->base.dev);
> >  	struct intel_hdcp *hdcp = &connector->hdcp;
> >  	int ret;
> > @@ -2024,9 +1650,15 @@ _intel_hdcp2_disable(struct intel_connector *connector, bool hdcp2_link_recovery
> >  	return ret;
> >  }
> >  
> > +int intel_hdcp2_disable(struct drm_connector *drm_connector)
> > +{
> > +	return _intel_hdcp2_disable(to_intel_connector(drm_connector), false);
> > +}
> > +
> >  /* Implements the Link Integrity Check for HDCP2.2 */
> > -static int intel_hdcp2_check_link(struct intel_connector *connector)
> > +int intel_hdcp2_check_link(struct drm_connector *drm_connector)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> >  	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> >  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >  	struct intel_hdcp *hdcp = &connector->hdcp;
> > @@ -2034,109 +1666,39 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
> >  	enum transcoder cpu_transcoder;
> >  	int ret = 0;
> >  
> > -	mutex_lock(&hdcp->mutex);
> > -	mutex_lock(&dig_port->hdcp_mutex);
> >  	cpu_transcoder = hdcp->cpu_transcoder;
> >  
> >  	/* hdcp2_check_link is expected only when HDCP2.2 is Enabled */
> > -	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED ||
> > -	    !hdcp->hdcp2_encrypted) {
> > -		ret = -EINVAL;
> > -		goto out;
> > -	}
> > +	if (!hdcp->hdcp2_encrypted)
> > +		return -EINVAL;
> >  
> >  	if (drm_WARN_ON(&dev_priv->drm,
> >  			!intel_hdcp2_in_use(dev_priv, cpu_transcoder, port))) {
> >  		drm_err(&dev_priv->drm,
> >  			"HDCP2.2 link stopped the encryption, %x\n",
> >  			intel_de_read(dev_priv, HDCP2_STATUS(dev_priv, cpu_transcoder, port)));
> > -		ret = -ENXIO;
> > -		_intel_hdcp2_disable(connector, true);
> > -		intel_hdcp_update_value(connector,
> > -					DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > -					true);
> > -		goto out;
> > +		return -ENXIO;
> >  	}
> >  
> >  	ret = hdcp->shim->check_2_2_link(dig_port, connector);
> > -	if (ret == HDCP_LINK_PROTECTED) {
> > -		if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> > -			intel_hdcp_update_value(connector,
> > -					DRM_MODE_CONTENT_PROTECTION_ENABLED,
> > -					true);
> > -		}
> > -		goto out;
> > -	}
> > +	if (ret == HDCP_LINK_PROTECTED)
> > +		return 0;
> >  
> >  	if (ret == HDCP_TOPOLOGY_CHANGE) {
> > -		if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> > -			goto out;
> > -
> >  		drm_dbg_kms(&dev_priv->drm,
> >  			    "HDCP2.2 Downstream topology change\n");
> >  		ret = hdcp2_authenticate_repeater_topology(connector);
> > -		if (!ret) {
> > -			intel_hdcp_update_value(connector,
> > -					DRM_MODE_CONTENT_PROTECTION_ENABLED,
> > -					true);
> > -			goto out;
> > -		}
> > -		drm_dbg_kms(&dev_priv->drm,
> > -			    "[%s:%d] Repeater topology auth failed.(%d)\n",
> > -			    connector->base.name, connector->base.base.id,
> > -			    ret);
> > -	} else {
> > -		drm_dbg_kms(&dev_priv->drm,
> > -			    "[%s:%d] HDCP2.2 link failed, retrying auth\n",
> > -			    connector->base.name, connector->base.base.id);
> > -	}
> > -
> > -	ret = _intel_hdcp2_disable(connector, true);
> > -	if (ret) {
> > -		drm_err(&dev_priv->drm,
> > -			"[%s:%d] Failed to disable hdcp2.2 (%d)\n",
> > -			connector->base.name, connector->base.base.id, ret);
> > -		intel_hdcp_update_value(connector,
> > -				DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
> > -		goto out;
> > -	}
> > +		if (!ret)
> > +			return 0;
> >  
> > -	ret = _intel_hdcp2_enable(connector);
> > -	if (ret) {
> >  		drm_dbg_kms(&dev_priv->drm,
> > -			    "[%s:%d] Failed to enable hdcp2.2 (%d)\n",
> > -			    connector->base.name, connector->base.base.id,
> > -			    ret);
> > -		intel_hdcp_update_value(connector,
> > -					DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > -					true);
> > -		goto out;
> > +			    "[%s:%d] Repeater topology auth failed.(%d)\n",
> > +			    connector->base.name, connector->base.base.id, ret);
> >  	}
> >  
> > -out:
> > -	mutex_unlock(&dig_port->hdcp_mutex);
> > -	mutex_unlock(&hdcp->mutex);
> >  	return ret;
> >  }
> >  
> > -static void intel_hdcp_check_work(struct work_struct *work)
> > -{
> > -	struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
> > -					       struct intel_hdcp,
> > -					       check_work);
> > -	struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
> > -
> > -	if (drm_connector_is_unregistered(&connector->base))
> > -		return;
> > -
> > -	if (!intel_hdcp2_check_link(connector))
> > -		schedule_delayed_work(&hdcp->check_work,
> > -				      DRM_HDCP2_CHECK_PERIOD_MS);
> > -	else if (!intel_hdcp_check_link(connector))
> > -		schedule_delayed_work(&hdcp->check_work,
> > -				      DRM_HDCP_CHECK_PERIOD_MS);
> > -}
> > -
> >  static int i915_hdcp_component_bind(struct device *i915_kdev,
> >  				    struct device *mei_kdev, void *data)
> >  {
> > @@ -2189,22 +1751,28 @@ static enum mei_fw_tc intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
> >  	}
> >  }
> >  
> > -static int
> > -_intel_hdcp_setup(struct intel_connector *connector,
> > -		  const struct intel_crtc_state *pipe_config, u8 content_type)
> > +int intel_hdcp_setup(struct drm_connector *connector,
> > +		     struct drm_atomic_state *state)
> >  {
> > -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> > -	struct intel_hdcp *hdcp = &connector->hdcp;
> > +	struct drm_i915_private *dev_priv = to_i915(connector->dev);
> > +	struct intel_connector *intel_connector = to_intel_connector(connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(intel_connector);
> > +	struct drm_connector_state *conn_state;
> > +	struct drm_crtc_state *crtc_state;
> > +	struct intel_crtc_state *pipe_config;
> > +	struct intel_hdcp *hdcp = &intel_connector->hdcp;
> >  	int ret = 0;
> >  
> > -	if (!connector->encoder) {
> > +	if (!intel_connector->encoder) {
> >  		drm_err(&dev_priv->drm, "[%s:%d] encoder is not initialized\n",
> > -			connector->base.name, connector->base.base.id);
> > +			connector->name, connector->base.id);
> >  		return -ENODEV;
> >  	}
> >  
> > -	hdcp->content_type = content_type;
> > +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> > +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> > +	pipe_config = to_intel_crtc_state(crtc_state);
> >  
> >  	if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
> >  		hdcp->cpu_transcoder = pipe_config->mst_master_transcoder;
> > @@ -2321,7 +1889,6 @@ int intel_hdcp_init(struct intel_connector *connector,
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >  	struct intel_hdcp *hdcp = &connector->hdcp;
> > -	int ret;
> >  
> >  	if (!shim)
> >  		return -EINVAL;
> > @@ -2329,174 +1896,12 @@ int intel_hdcp_init(struct intel_connector *connector,
> >  	if (is_hdcp2_supported(dev_priv))
> >  		intel_hdcp2_init(connector, dig_port, shim);
> >  
> > -	ret =
> > -	drm_connector_attach_content_protection_property(&connector->base,
> > -							 hdcp->hdcp2_supported);
> > -	if (ret) {
> > -		hdcp->hdcp2_supported = false;
> > -		kfree(dig_port->hdcp_port_data.streams);
> > -		return ret;
> > -	}
> > -
> >  	hdcp->shim = shim;
> > -	mutex_init(&hdcp->mutex);
> > -	INIT_DELAYED_WORK(&hdcp->check_work, intel_hdcp_check_work);
> > -	INIT_WORK(&hdcp->prop_work, intel_hdcp_prop_work);
> >  	init_waitqueue_head(&hdcp->cp_irq_queue);
> >  
> >  	return 0;
> >  }
> >  
> > -int intel_hdcp_enable(struct intel_connector *connector,
> > -		      const struct intel_crtc_state *pipe_config, u8 content_type)
> > -{
> > -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> > -	struct intel_hdcp *hdcp = &connector->hdcp;
> > -	unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
> > -	bool capable;
> > -	int ret = -EINVAL;
> > -
> > -	if (!hdcp->shim)
> > -		return -ENOENT;
> > -
> > -	mutex_lock(&hdcp->mutex);
> > -	mutex_lock(&dig_port->hdcp_mutex);
> > -	drm_WARN_ON(&dev_priv->drm,
> > -		    hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
> > -
> > -	ret = _intel_hdcp_setup(connector, pipe_config, content_type);
> > -	if (ret)
> > -		goto out;
> > -
> > -	/*
> > -	 * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
> > -	 * is capable of HDCP2.2, it is preferred to use HDCP2.2.
> > -	 */
> > -	ret = intel_hdcp2_capable(connector, &capable);
> > -	if (capable) {
> > -		ret = _intel_hdcp2_enable(connector);
> > -		if (!ret) {
> > -			check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
> > -			goto out;
> > -		}
> > -	}
> > -
> > -	/*
> > -	 * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
> > -	 * be attempted.
> > -	 */
> > -	ret = intel_hdcp_capable(connector, &capable);
> > -	if (ret)
> > -		goto out;
> > -
> > -	if (capable && hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1)
> > -		ret = _intel_hdcp_enable(connector);
> > -
> > -out:
> > -	if (!ret) {
> > -		schedule_delayed_work(&hdcp->check_work, check_link_interval);
> > -		intel_hdcp_update_value(connector,
> > -					DRM_MODE_CONTENT_PROTECTION_ENABLED,
> > -					true);
> > -	}
> > -
> > -	mutex_unlock(&dig_port->hdcp_mutex);
> > -	mutex_unlock(&hdcp->mutex);
> > -	return ret;
> > -}
> > -
> > -int intel_hdcp_disable(struct intel_connector *connector)
> > -{
> > -	struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
> > -	struct intel_hdcp *hdcp = &connector->hdcp;
> > -	int ret = 0;
> > -
> > -	if (!hdcp->shim)
> > -		return -ENOENT;
> > -
> > -	mutex_lock(&hdcp->mutex);
> > -	mutex_lock(&dig_port->hdcp_mutex);
> > -
> > -	if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> > -		goto out;
> > -
> > -	intel_hdcp_update_value(connector,
> > -				DRM_MODE_CONTENT_PROTECTION_UNDESIRED, false);
> > -	if (hdcp->hdcp2_encrypted)
> > -		ret = _intel_hdcp2_disable(connector, false);
> > -	else if (hdcp->hdcp_encrypted)
> > -		ret = _intel_hdcp_disable(connector);
> > -
> > -out:
> > -	mutex_unlock(&dig_port->hdcp_mutex);
> > -	mutex_unlock(&hdcp->mutex);
> > -	cancel_delayed_work_sync(&hdcp->check_work);
> > -	return ret;
> > -}
> > -
> > -void intel_hdcp_update_pipe(struct intel_atomic_state *state,
> > -			    struct intel_encoder *encoder,
> > -			    const struct intel_crtc_state *crtc_state,
> > -			    const struct drm_connector_state *conn_state)
> > -{
> > -	struct intel_connector *connector =
> > -				to_intel_connector(conn_state->connector);
> > -	struct intel_hdcp *hdcp = &connector->hdcp;
> > -	bool content_protection_type_changed, desired_and_not_enabled = false;
> > -
> > -	if (!connector->hdcp.shim)
> > -		return;
> > -
> > -	content_protection_type_changed =
> > -		(conn_state->hdcp_content_type != hdcp->content_type &&
> > -		 conn_state->content_protection !=
> > -		 DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
> > -
> > -	/*
> > -	 * During the HDCP encryption session if Type change is requested,
> > -	 * disable the HDCP and reenable it with new TYPE value.
> > -	 */
> > -	if (conn_state->content_protection ==
> > -	    DRM_MODE_CONTENT_PROTECTION_UNDESIRED ||
> > -	    content_protection_type_changed)
> > -		intel_hdcp_disable(connector);
> > -
> > -	/*
> > -	 * Mark the hdcp state as DESIRED after the hdcp disable of type
> > -	 * change procedure.
> > -	 */
> > -	if (content_protection_type_changed) {
> > -		mutex_lock(&hdcp->mutex);
> > -		hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
> > -		drm_connector_get(&connector->base);
> > -		schedule_work(&hdcp->prop_work);
> > -		mutex_unlock(&hdcp->mutex);
> > -	}
> > -
> > -	if (conn_state->content_protection ==
> > -	    DRM_MODE_CONTENT_PROTECTION_DESIRED) {
> > -		mutex_lock(&hdcp->mutex);
> > -		/* Avoid enabling hdcp, if it already ENABLED */
> > -		desired_and_not_enabled =
> > -			hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED;
> > -		mutex_unlock(&hdcp->mutex);
> > -		/*
> > -		 * If HDCP already ENABLED and CP property is DESIRED, schedule
> > -		 * prop_work to update correct CP property to user space.
> > -		 */
> > -		if (!desired_and_not_enabled && !content_protection_type_changed) {
> > -			drm_connector_get(&connector->base);
> > -			schedule_work(&hdcp->prop_work);
> > -		}
> > -	}
> > -
> > -	if (desired_and_not_enabled || content_protection_type_changed)
> > -		intel_hdcp_enable(connector,
> > -				  crtc_state,
> > -				  (u8)conn_state->hdcp_content_type);
> > -}
> > -
> >  void intel_hdcp_component_fini(struct drm_i915_private *dev_priv)
> >  {
> >  	mutex_lock(&dev_priv->display.hdcp.comp_mutex);
> > @@ -2518,33 +1923,8 @@ void intel_hdcp_cleanup(struct intel_connector *connector)
> >  	if (!hdcp->shim)
> >  		return;
> >  
> > -	/*
> > -	 * If the connector is registered, it's possible userspace could kick
> > -	 * off another HDCP enable, which would re-spawn the workers.
> > -	 */
> > -	drm_WARN_ON(connector->base.dev,
> > -		connector->base.registration_state == DRM_CONNECTOR_REGISTERED);
> > -
> > -	/*
> > -	 * Now that the connector is not registered, check_work won't be run,
> > -	 * but cancel any outstanding instances of it
> > -	 */
> > -	cancel_delayed_work_sync(&hdcp->check_work);
> > -
> > -	/*
> > -	 * We don't cancel prop_work in the same way as check_work since it
> > -	 * requires connection_mutex which could be held while calling this
> > -	 * function. Instead, we rely on the connector references grabbed before
> > -	 * scheduling prop_work to ensure the connector is alive when prop_work
> > -	 * is run. So if we're in the destroy path (which is where this
> > -	 * function should be called), we're "guaranteed" that prop_work is not
> > -	 * active (tl;dr This Should Never Happen).
> > -	 */
> > -	drm_WARN_ON(connector->base.dev, work_pending(&hdcp->prop_work));
> > -
> > -	mutex_lock(&hdcp->mutex);
> > +	drm_hdcp_helper_destroy(connector->hdcp_helper_data);
> >  	hdcp->shim = NULL;
> > -	mutex_unlock(&hdcp->mutex);
> >  }
> >  
> >  /* Handles the CP_IRQ raised from the DP HDCP sink */
> > @@ -2558,5 +1938,5 @@ void intel_hdcp_handle_cp_irq(struct intel_connector *connector)
> >  	atomic_inc(&connector->hdcp.cp_irq_count);
> >  	wake_up_all(&connector->hdcp.cp_irq_queue);
> >  
> > -	schedule_delayed_work(&hdcp->check_work, 0);
> > +	drm_hdcp_helper_schedule_hdcp_check(connector->hdcp_helper_data);
> >  }
> > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > index f06f6e5a2b1a..49b9d79eb30a 100644
> > --- a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > @@ -10,8 +10,10 @@
> >  
> >  #define HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS	50
> >  
> > +struct drm_atomic_state;
> >  struct drm_connector;
> >  struct drm_connector_state;
> > +struct drm_hdcp_an;
> >  struct drm_i915_private;
> >  struct intel_atomic_state;
> >  struct intel_connector;
> > @@ -25,16 +27,29 @@ enum transcoder;
> >  int intel_hdcp_init(struct intel_connector *connector,
> >  		    struct intel_digital_port *dig_port,
> >  		    const struct intel_hdcp_shim *hdcp_shim);
> > -int intel_hdcp_enable(struct intel_connector *connector,
> > -		      const struct intel_crtc_state *pipe_config, u8 content_type);
> > -int intel_hdcp_disable(struct intel_connector *connector);
> > -void intel_hdcp_update_pipe(struct intel_atomic_state *state,
> > -			    struct intel_encoder *encoder,
> > -			    const struct intel_crtc_state *crtc_state,
> > -			    const struct drm_connector_state *conn_state);
> > +int intel_hdcp_setup(struct drm_connector *drm_connector,
> > +		     struct drm_atomic_state *state);
> > +int intel_hdcp_load_keys(struct drm_connector *drm_connector);
> >  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
> >  int intel_hdcp_capable(struct intel_connector *connector, bool *capable);
> > -int intel_hdcp2_capable(struct intel_connector *connector, bool *capable);
> > +int intel_hdcp2_capable(struct drm_connector *drm_connector, bool *capable);
> > +int intel_hdcp2_enable(struct drm_connector *drm_connector);
> > +int intel_hdcp2_disable(struct drm_connector *drm_connector);
> > +int intel_hdcp2_check_link(struct drm_connector *drm_connector);
> > +int intel_hdcp1_store_receiver_info(struct drm_connector *drm_connector,
> > +				    u32 *ksv, u32 status, u8 caps,
> > +				    bool repeater_present);
> > +int intel_hdcp1_read_an(struct drm_connector *drm_connector,
> > +			struct drm_hdcp_an *an);
> > +int intel_hdcp1_enable_encryption(struct drm_connector *drm_connector);
> > +int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector);
> > +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32 ri_prime);
> > +int intel_hdcp1_post_encryption(struct drm_connector *drm_connector);
> > +int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
> > +			       u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
> > +			       u32 *v_prime);
> > +int intel_hdcp1_check_link(struct drm_connector *drm_connector);
> > +int intel_hdcp1_disable(struct drm_connector *drm_connector);
> >  void intel_hdcp_component_init(struct drm_i915_private *dev_priv);
> >  void intel_hdcp_component_fini(struct drm_i915_private *dev_priv);
> >  void intel_hdcp_cleanup(struct intel_connector *connector);
> > diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
> > index 7816b2a33fee..c33cfedb2e19 100644
> > --- a/drivers/gpu/drm/i915/display/intel_hdmi.c
> > +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
> > @@ -1324,17 +1324,24 @@ static int intel_hdmi_hdcp_write(struct intel_digital_port *dig_port,
> >  	return ret;
> >  }
> >  
> > -static
> > -int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> > -				  u8 *an)
> > +static int intel_hdmi_hdcp1_send_an_aksv(struct drm_connector *drm_connector)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> >  	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> >  	struct intel_hdmi *hdmi = &dig_port->hdmi;
> >  	struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915,
> >  							      hdmi->ddc_bus);
> > +	struct drm_hdcp_an an;
> >  	int ret;
> >  
> > -	ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an,
> > +	/* Output An first, that's easy */
> > +	ret = intel_hdcp1_read_an(drm_connector, &an);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an.bytes,
> >  				    DRM_HDCP_AN_LEN);
> >  	if (ret) {
> >  		drm_dbg_kms(&i915->drm, "Write An over DDC failed (%d)\n",
> > @@ -1350,120 +1357,6 @@ int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> >  	return 0;
> >  }
> >  
> > -static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *dig_port,
> > -				     u8 *bksv)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -
> > -	int ret;
> > -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BKSV, bksv,
> > -				   DRM_HDCP_KSV_LEN);
> > -	if (ret)
> > -		drm_dbg_kms(&i915->drm, "Read Bksv over DDC failed (%d)\n",
> > -			    ret);
> > -	return ret;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *dig_port,
> > -				 u8 *bstatus)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -
> > -	int ret;
> > -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BSTATUS,
> > -				   bstatus, DRM_HDCP_BSTATUS_LEN);
> > -	if (ret)
> > -		drm_dbg_kms(&i915->drm, "Read bstatus over DDC failed (%d)\n",
> > -			    ret);
> > -	return ret;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *dig_port,
> > -				     bool *repeater_present)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	int ret;
> > -	u8 val;
> > -
> > -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
> > -	if (ret) {
> > -		drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed (%d)\n",
> > -			    ret);
> > -		return ret;
> > -	}
> > -	*repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
> > -	return 0;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
> > -				  u8 *ri_prime)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -
> > -	int ret;
> > -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_RI_PRIME,
> > -				   ri_prime, DRM_HDCP_RI_LEN);
> > -	if (ret)
> > -		drm_dbg_kms(&i915->drm, "Read Ri' over DDC failed (%d)\n",
> > -			    ret);
> > -	return ret;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
> > -				   bool *ksv_ready)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	int ret;
> > -	u8 val;
> > -
> > -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
> > -	if (ret) {
> > -		drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed (%d)\n",
> > -			    ret);
> > -		return ret;
> > -	}
> > -	*ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
> > -	return 0;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
> > -				  int num_downstream, u8 *ksv_fifo)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	int ret;
> > -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_KSV_FIFO,
> > -				   ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN);
> > -	if (ret) {
> > -		drm_dbg_kms(&i915->drm,
> > -			    "Read ksv fifo over DDC failed (%d)\n", ret);
> > -		return ret;
> > -	}
> > -	return 0;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
> > -				      int i, u32 *part)
> > -{
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	int ret;
> > -
> > -	if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
> > -		return -EINVAL;
> > -
> > -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_V_PRIME(i),
> > -				   part, DRM_HDCP_V_PRIME_PART_LEN);
> > -	if (ret)
> > -		drm_dbg_kms(&i915->drm, "Read V'[%d] over DDC failed (%d)\n",
> > -			    i, ret);
> > -	return ret;
> > -}
> > -
> >  static int kbl_repositioning_enc_en_signal(struct intel_connector *connector,
> >  					   enum transcoder cpu_transcoder)
> >  {
> > @@ -1532,50 +1425,40 @@ int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
> >  	return 0;
> >  }
> >  
> > -static
> > -bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port,
> > -				     struct intel_connector *connector)
> > +static int
> > +intel_hdmi_hdcp1_enable_encryption(struct drm_connector *drm_connector)
> >  {
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	enum port port = dig_port->base.port;
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> >  	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> >  	int ret;
> > -	union {
> > -		u32 reg;
> > -		u8 shim[DRM_HDCP_RI_LEN];
> > -	} ri;
> >  
> > -	ret = intel_hdmi_hdcp_read_ri_prime(dig_port, ri.shim);
> > +	ret = intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder, true);
> >  	if (ret)
> > -		return false;
> > -
> > -	intel_de_write(i915, HDCP_RPRIME(i915, cpu_transcoder, port), ri.reg);
> > +		return ret;
> >  
> > -	/* Wait for Ri prime match */
> > -	if (wait_for((intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder, port)) &
> > -		      (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC)) ==
> > -		     (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
> > -		drm_dbg_kms(&i915->drm, "Ri' mismatch detected (%x)\n",
> > -			intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder,
> > -							port)));
> > -		return false;
> > -	}
> > -	return true;
> > +	return intel_hdcp1_enable_encryption(drm_connector);
> >  }
> >  
> > -static
> > -bool intel_hdmi_hdcp_check_link(struct intel_digital_port *dig_port,
> > -				struct intel_connector *connector)
> > +static int intel_hdmi_hdcp1_disable(struct drm_connector *drm_connector)
> >  {
> > -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -	int retry;
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> > +	enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
> > +	struct drm_i915_private *i915 = to_i915(connector->base.dev);
> > +	int ret;
> >  
> > -	for (retry = 0; retry < 3; retry++)
> > -		if (intel_hdmi_hdcp_check_link_once(dig_port, connector))
> > -			return true;
> > +	ret = intel_hdcp1_disable(drm_connector);
> > +	if (ret) {
> > +		drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 1.4\n",
> > +			connector->base.name, connector->base.base.id);
> > +		return ret;
> > +	}
> >  
> > -	drm_err(&i915->drm, "Link check failed\n");
> > -	return false;
> > +	return intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder,
> > +						 false);
> >  }
> >  
> >  struct hdcp2_hdmi_msg_timeout {
> > @@ -1718,9 +1601,8 @@ int intel_hdmi_hdcp2_read_msg(struct intel_digital_port *dig_port,
> >  	return ret;
> >  }
> >  
> > -static
> > -int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
> > -				struct intel_connector *connector)
> > +static int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
> > +				       struct intel_connector *connector)
> >  {
> >  	u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
> >  	int ret;
> > @@ -1741,13 +1623,19 @@ int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
> >  	return ret;
> >  }
> >  
> > -static
> > -int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
> > -			     bool *capable)
> > +static int intel_hdmi_hdcp2_capable(struct drm_connector *drm_connector,
> > +				    bool *capable)
> >  {
> > +	struct intel_connector *connector = to_intel_connector(drm_connector);
> > +	struct intel_digital_port *dig_port =
> > +		intel_attached_dig_port(connector);
> >  	u8 hdcp2_version;
> >  	int ret;
> >  
> > +	ret = intel_hdcp2_capable(drm_connector, capable);
> > +	if (ret || !capable)
> > +		return ret;
> > +
> >  	*capable = false;
> >  	ret = intel_hdmi_hdcp_read(dig_port, HDCP_2_2_HDMI_REG_VER_OFFSET,
> >  				   &hdcp2_version, sizeof(hdcp2_version));
> > @@ -1758,23 +1646,30 @@ int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
> >  }
> >  
> >  static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
> > -	.write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
> > -	.read_bksv = intel_hdmi_hdcp_read_bksv,
> > -	.read_bstatus = intel_hdmi_hdcp_read_bstatus,
> > -	.repeater_present = intel_hdmi_hdcp_repeater_present,
> > -	.read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
> > -	.read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
> > -	.read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
> > -	.read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
> >  	.toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
> > -	.check_link = intel_hdmi_hdcp_check_link,
> >  	.write_2_2_msg = intel_hdmi_hdcp2_write_msg,
> >  	.read_2_2_msg = intel_hdmi_hdcp2_read_msg,
> > -	.check_2_2_link	= intel_hdmi_hdcp2_check_link,
> > -	.hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
> > +	.check_2_2_link = intel_hdmi_hdcp2_check_link,
> >  	.protocol = HDCP_PROTOCOL_HDMI,
> >  };
> >  
> > +static const struct drm_hdcp_helper_funcs intel_hdmi_hdcp_helper_funcs = {
> > +	.setup = intel_hdcp_setup,
> > +	.load_keys = intel_hdcp_load_keys,
> > +	.hdcp2_capable = intel_hdmi_hdcp2_capable,
> > +	.hdcp2_enable = intel_hdcp2_enable,
> > +	.hdcp2_check_link = intel_hdcp2_check_link,
> > +	.hdcp2_disable = intel_hdcp2_disable,
> > +	.hdcp1_send_an_aksv = intel_hdmi_hdcp1_send_an_aksv,
> > +	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> > +	.hdcp1_enable_encryption = intel_hdmi_hdcp1_enable_encryption,
> > +	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> > +	.hdcp1_match_ri = intel_hdcp1_match_ri,
> > +	.hdcp1_post_encryption = intel_hdcp1_post_encryption,
> > +	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> > +	.hdcp1_disable = intel_hdmi_hdcp1_disable,
> > +};
> > +
> >  static int intel_hdmi_source_max_tmds_clock(struct intel_encoder *encoder)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > @@ -2922,6 +2817,37 @@ void intel_infoframe_init(struct intel_digital_port *dig_port)
> >  	}
> >  }
> >  
> > +static void intel_hdmi_hdcp_init(struct intel_digital_port *dig_port,
> > +				 struct intel_connector *connector)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +	struct intel_encoder *intel_encoder = &dig_port->base;
> > +	enum port port = intel_encoder->port;
> > +	struct drm_hdcp_helper_data *data;
> > +	int ret;
> > +
> > +	if (!is_hdcp_supported(dev_priv, port))
> > +		return;
> > +
> > +	data = drm_hdcp_helper_initialize_hdmi(
> > +		&connector->base, &intel_hdmi_hdcp_helper_funcs, true);
> > +	if (IS_ERR(data)) {
> > +		drm_dbg_kms(&dev_priv->drm, "HDCP init failed ret=%ld\n",
> > +			    PTR_ERR(data));
> > +		return;
> > +	}
> > +
> > +	ret = intel_hdcp_init(connector, dig_port, &intel_hdmi_hdcp_shim);
> > +	if (ret) {
> > +		drm_hdcp_helper_destroy(data);
> > +		drm_dbg_kms(&dev_priv->drm, "Intel HDCP init failed ret=%d\n",
> > +			    ret);
> > +		return;
> > +	}
> > +
> > +	connector->hdcp_helper_data = data;
> > +}
> > +
> >  void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
> >  			       struct intel_connector *intel_connector)
> >  {
> > @@ -2975,13 +2901,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
> >  	intel_connector_attach_encoder(intel_connector, intel_encoder);
> >  	intel_hdmi->attached_connector = intel_connector;
> >  
> > -	if (is_hdcp_supported(dev_priv, port)) {
> > -		int ret = intel_hdcp_init(intel_connector, dig_port,
> > -					  &intel_hdmi_hdcp_shim);
> > -		if (ret)
> > -			drm_dbg_kms(&dev_priv->drm,
> > -				    "HDCP init failed, skipping.\n");
> > -	}
> > +	intel_hdmi_hdcp_init(dig_port, intel_connector);
> >  
> >  	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
> >  	 * 0xd.  Failure to do so will result in spurious interrupts being
> > -- 
> > 2.39.0.246.g2a6d74b583-goog
> > 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [Intel-gfx] [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
  2023-01-18 19:30 ` [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check() Mark Yacoub
  2023-01-19 10:37   ` Krzysztof Kozlowski
  2023-01-19 11:41   ` Dmitry Baryshkov
@ 2023-03-10  5:30   ` Kandpal, Suraj
  2 siblings, 0 replies; 38+ messages in thread
From: Kandpal, Suraj @ 2023-03-10  5:30 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: quic_sbillaka, konrad.dybcio, bjorn.andersson,
	krzysztof.kozlowski+dt, airlied, hbh25y, Vasut, Marek, abhinavk,
	javierm, agross, quic_jesszhan, daniel, Nikula, Jani, De Marchi,
	Lucas, quic_abhinavk, swboyd, robh+dt, christophe.jaillet,
	maxime, Vivi, Rodrigo, johan+linaro, andersson, dianders,
	tzimmermann, dmitry.baryshkov, seanpaul

> 
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch moves the hdcp atomic check from i915 to drm_hdcp so other
> drivers can use it. No functional changes, just cleaned up some of the code
> when moving it over.
> 
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Reviewed-by: Abhinav Kumar <abhinavk@codeaurora.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-2-
> sean@poorly.run #v1
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-2-
> sean@poorly.run #v2
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-2-
> sean@poorly.run #v3
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
> 2-sean@poorly.run #v4
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
> 2-sean@poorly.run #v5
> 
> Changes in v2:
> -None
> Changes in v3:
> -None
> Changes in v4:
> -None
> Changes in v5:
> -None
> Changes in V6:
> -Rebase: move helper from drm_hdcp.c to drm_hdcp_helper.c
> 
> ---
>  drivers/gpu/drm/display/drm_hdcp_helper.c   | 69
> +++++++++++++++++++++
>  drivers/gpu/drm/i915/display/intel_atomic.c |  4 +-
>  drivers/gpu/drm/i915/display/intel_hdcp.c   | 47 --------------
>  drivers/gpu/drm/i915/display/intel_hdcp.h   |  3 -
>  include/drm/display/drm_hdcp_helper.h       |  3 +
>  5 files changed, 74 insertions(+), 52 deletions(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_hdcp_helper.c
> b/drivers/gpu/drm/display/drm_hdcp_helper.c
> index e78999c72bd7..7d910523b05f 100644
> --- a/drivers/gpu/drm/display/drm_hdcp_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdcp_helper.c
> @@ -20,6 +20,7 @@
>  #include <drm/drm_property.h>
>  #include <drm/drm_mode_object.h>
>  #include <drm/drm_connector.h>
> +#include <drm/drm_atomic.h>
> 
>  static inline void drm_hdcp_print_ksv(const u8 *ksv)  { @@ -419,3 +420,71
> @@ void drm_hdcp_update_content_protection(struct drm_connector
> *connector,
>  				 dev-
> >mode_config.content_protection_property);
>  }
>  EXPORT_SYMBOL(drm_hdcp_update_content_protection);
> +
> +/**
> + * drm_hdcp_atomic_check - Helper for drivers to call during
> +connector->atomic_check
> + *
> + * @state: pointer to the atomic state being checked
> + * @connector: drm_connector on which content protection state needs an
> +update
> + *
> + * This function can be used by display drivers to perform an atomic
> +check on the
> + * hdcp state elements. If hdcp state has changed, this function will
> +set
> + * mode_changed on the crtc driving the connector so it can update its
> +hardware
> + * to match the hdcp state.
> + */
> +void drm_hdcp_atomic_check(struct drm_connector *connector,
> +			   struct drm_atomic_state *state)
> +{
> +	struct drm_connector_state *new_conn_state, *old_conn_state;
> +	struct drm_crtc_state *new_crtc_state;
> +	u64 old_hdcp, new_hdcp;
> +
> +	old_conn_state = drm_atomic_get_old_connector_state(state,
> connector);
> +	old_hdcp = old_conn_state->content_protection;
> +
> +	new_conn_state = drm_atomic_get_new_connector_state(state,
> connector);
> +	new_hdcp = new_conn_state->content_protection;
> +
> +	if (!new_conn_state->crtc) {
> +		/*
> +		 * If the connector is being disabled with CP enabled, mark it
> +		 * desired so it's re-enabled when the connector is brought
> back
> +		 */
> +		if (old_hdcp ==
> DRM_MODE_CONTENT_PROTECTION_ENABLED)
> +			new_conn_state->content_protection =
> +
> 	DRM_MODE_CONTENT_PROTECTION_DESIRED;
> +		return;
> +	}
> +
> +	new_crtc_state =
> +		drm_atomic_get_new_crtc_state(state, new_conn_state-
> >crtc);
> +	/*
> +	* Fix the HDCP uapi content protection state in case of modeset.
> +	* FIXME: As per HDCP content protection property uapi doc, an
> uevent()
> +	* need to be sent if there is transition from ENABLED->DESIRED.
> +	*/

Hi Mark,
Is the above comment needed here as drm_hdcp_update_content_protection is
used to change property which sends a uevent making the above comment misleading

Regards,
Suraj Kandpal
> +	if (drm_atomic_crtc_needs_modeset(new_crtc_state) &&
> +	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
> +	     new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED))
> +		new_conn_state->content_protection =
> +			DRM_MODE_CONTENT_PROTECTION_DESIRED;
> +
> +	/*
> +	 * Nothing to do if content type is unchanged and one of:
> +	 *  - state didn't change
> +	 *  - HDCP was activated since the last commit
> +	 *  - attempting to set to desired while already enabled
> +	 */
> +	if (old_hdcp == new_hdcp ||
> +	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
> +	     new_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED) ||
> +	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
> +	     new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED)) {
> +		if (old_conn_state->hdcp_content_type ==
> +		    new_conn_state->hdcp_content_type)
> +			return;
> +	}
> +
> +	new_crtc_state->mode_changed = true;
> +}
> +EXPORT_SYMBOL(drm_hdcp_atomic_check);
> diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c
> b/drivers/gpu/drm/i915/display/intel_atomic.c
> index 18f0a5ae3bac..8a473199c4bf 100644
> --- a/drivers/gpu/drm/i915/display/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/display/intel_atomic.c
> @@ -32,6 +32,7 @@
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_fourcc.h>
> +#include <drm/display/drm_hdcp_helper.h>
> 
>  #include "i915_drv.h"
>  #include "i915_reg.h"
> @@ -39,7 +40,6 @@
>  #include "intel_cdclk.h"
>  #include "intel_display_types.h"
>  #include "intel_global_state.h"
> -#include "intel_hdcp.h"
>  #include "intel_psr.h"
>  #include "skl_universal_plane.h"
> 
> @@ -123,7 +123,7 @@ int intel_digital_connector_atomic_check(struct
> drm_connector *conn,
>  		to_intel_digital_connector_state(old_state);
>  	struct drm_crtc_state *crtc_state;
> 
> -	intel_hdcp_atomic_check(conn, old_state, new_state);
> +	drm_hdcp_atomic_check(conn, state);
> 
>  	if (!new_state->crtc)
>  		return 0;
> diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c
> b/drivers/gpu/drm/i915/display/intel_hdcp.c
> index 6406fd487ee5..396d2cef000a 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdcp.c
> +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
> @@ -2524,53 +2524,6 @@ void intel_hdcp_cleanup(struct intel_connector
> *connector)
>  	mutex_unlock(&hdcp->mutex);
>  }
> 
> -void intel_hdcp_atomic_check(struct drm_connector *connector,
> -			     struct drm_connector_state *old_state,
> -			     struct drm_connector_state *new_state)
> -{
> -	u64 old_cp = old_state->content_protection;
> -	u64 new_cp = new_state->content_protection;
> -	struct drm_crtc_state *crtc_state;
> -
> -	if (!new_state->crtc) {
> -		/*
> -		 * If the connector is being disabled with CP enabled, mark it
> -		 * desired so it's re-enabled when the connector is brought
> back
> -		 */
> -		if (old_cp ==
> DRM_MODE_CONTENT_PROTECTION_ENABLED)
> -			new_state->content_protection =
> -
> 	DRM_MODE_CONTENT_PROTECTION_DESIRED;
> -		return;
> -	}
> -
> -	crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
> -						   new_state->crtc);
> -	/*
> -	 * Fix the HDCP uapi content protection state in case of modeset.
> -	 * FIXME: As per HDCP content protection property uapi doc, an
> uevent()
> -	 * need to be sent if there is transition from ENABLED->DESIRED.
> -	 */
> -	if (drm_atomic_crtc_needs_modeset(crtc_state) &&
> -	    (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
> -	    new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED))
> -		new_state->content_protection =
> -			DRM_MODE_CONTENT_PROTECTION_DESIRED;
> -
> -	/*
> -	 * Nothing to do if the state didn't change, or HDCP was activated
> since
> -	 * the last commit. And also no change in hdcp content type.
> -	 */
> -	if (old_cp == new_cp ||
> -	    (old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
> -	     new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)) {
> -		if (old_state->hdcp_content_type ==
> -				new_state->hdcp_content_type)
> -			return;
> -	}
> -
> -	crtc_state->mode_changed = true;
> -}
> -
>  /* Handles the CP_IRQ raised from the DP HDCP sink */  void
> intel_hdcp_handle_cp_irq(struct intel_connector *connector)  { diff --git
> a/drivers/gpu/drm/i915/display/intel_hdcp.h
> b/drivers/gpu/drm/i915/display/intel_hdcp.h
> index 8f53b0c7fe5c..7c5fd84a7b65 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdcp.h
> +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
> @@ -22,9 +22,6 @@ struct intel_digital_port;  enum port;  enum transcoder;
> 
> -void intel_hdcp_atomic_check(struct drm_connector *connector,
> -			     struct drm_connector_state *old_state,
> -			     struct drm_connector_state *new_state);
>  int intel_hdcp_init(struct intel_connector *connector,
>  		    struct intel_digital_port *dig_port,
>  		    const struct intel_hdcp_shim *hdcp_shim); diff --git
> a/include/drm/display/drm_hdcp_helper.h
> b/include/drm/display/drm_hdcp_helper.h
> index 8aaf87bf2735..dd02b2e72a50 100644
> --- a/include/drm/display/drm_hdcp_helper.h
> +++ b/include/drm/display/drm_hdcp_helper.h
> @@ -11,6 +11,7 @@
> 
>  #include <drm/display/drm_hdcp.h>
> 
> +struct drm_atomic_state;
>  struct drm_device;
>  struct drm_connector;
> 
> @@ -18,5 +19,7 @@ int drm_hdcp_check_ksvs_revoked(struct drm_device
> *dev, u8 *ksvs, u32 ksv_count)  int
> drm_connector_attach_content_protection_property(struct drm_connector
> *connector,
>  						     bool hdcp_content_type);
>  void drm_hdcp_update_content_protection(struct drm_connector
> *connector, u64 val);
> +void drm_hdcp_atomic_check(struct drm_connector *connector,
> +			   struct drm_atomic_state *state);
> 
>  #endif
> --
> 2.39.0.246.g2a6d74b583-goog


^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [Intel-gfx] [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic check
  2023-01-18 19:30 ` [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic check Mark Yacoub
  2023-01-19 11:45   ` Dmitry Baryshkov
@ 2023-03-10  6:00   ` Kandpal, Suraj
  1 sibling, 0 replies; 38+ messages in thread
From: Kandpal, Suraj @ 2023-03-10  6:00 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: quic_sbillaka, konrad.dybcio, bjorn.andersson,
	krzysztof.kozlowski+dt, airlied, hbh25y, Vasut, Marek, abhinavk,
	javierm, agross, quic_jesszhan, daniel, Nikula, Jani, De Marchi,
	Lucas, quic_abhinavk, swboyd, robh+dt, christophe.jaillet,
	maxime, Vivi, Rodrigo, johan+linaro, andersson, dianders,
	tzimmermann, dmitry.baryshkov, seanpaul



> -----Original Message-----
> From: Intel-gfx <intel-gfx-bounces@lists.freedesktop.org> On Behalf Of Mark
> Yacoub
> Sent: Thursday, January 19, 2023 1:00 AM
> To: quic_khsieh@quicinc.com; linux-arm-msm@vger.kernel.org; dri-
> devel@lists.freedesktop.org; freedreno@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; intel-
> gfx@lists.freedesktop.org
> Cc: quic_sbillaka@quicinc.com; konrad.dybcio@somainline.org;
> bjorn.andersson@linaro.org; krzysztof.kozlowski+dt@linaro.org;
> airlied@gmail.com; hbh25y@gmail.com; Vasut, Marek <marex@denx.de>;
> abhinavk@codeaurora.org; javierm@redhat.com; agross@kernel.org;
> quic_jesszhan@quicinc.com; daniel@ffwll.ch; Nikula, Jani
> <jani.nikula@intel.com>; De Marchi, Lucas <lucas.demarchi@intel.com>;
> quic_abhinavk@quicinc.com; swboyd@chromium.org; robh+dt@kernel.org;
> christophe.jaillet@wanadoo.fr; maxime@cerno.tech; Vivi, Rodrigo
> <rodrigo.vivi@intel.com>; johan+linaro@kernel.org;
> markyacoub@chromium.org; andersson@kernel.org;
> dianders@chromium.org; tzimmermann@suse.de;
> dmitry.baryshkov@linaro.org; seanpaul@chromium.org
> Subject: [Intel-gfx] [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in
> hdcp atomic check
> 
> From: Sean Paul <seanpaul@chromium.org>
> 
> Instead of forcing a modeset in the hdcp atomic check, simply return true if
> the content protection value is changing and let the driver decide whether a
> modeset is required or not.
> 
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-3-
> sean@poorly.run #v1
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-3-
> sean@poorly.run #v2
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-3-
> sean@poorly.run #v3
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
> 3-sean@poorly.run #v4
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
> 3-sean@poorly.run #v5
> 
> Changes in v2:
> -None
> Changes in v3:
> -None
> Changes in v4:
> -None
> Changes in v5:
> -None
> Changes in V6:
> -Rebase: modifications in drm_hdcp_helper.c instead of drm_hdcp.c
> 
> ---
>  drivers/gpu/drm/display/drm_hdcp_helper.c   | 33 +++++++++++++++------
>  drivers/gpu/drm/i915/display/intel_atomic.c |  6 ++--
>  include/drm/display/drm_hdcp_helper.h       |  2 +-
>  3 files changed, 27 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_hdcp_helper.c
> b/drivers/gpu/drm/display/drm_hdcp_helper.c
> index 7d910523b05f..a3896b0904b5 100644
> --- a/drivers/gpu/drm/display/drm_hdcp_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdcp_helper.c
> @@ -428,11 +428,14 @@
> EXPORT_SYMBOL(drm_hdcp_update_content_protection);
>   * @connector: drm_connector on which content protection state needs an
> update
>   *
>   * This function can be used by display drivers to perform an atomic check
> on the
> - * hdcp state elements. If hdcp state has changed, this function will set
> - * mode_changed on the crtc driving the connector so it can update its
> hardware
> - * to match the hdcp state.
> + * hdcp state elements. If hdcp state has changed in a manner which
> + requires the
> + * driver to enable or disable content protection, this function will
> + return
> + * true.
> + *
> + * Returns:
> + * true if the driver must enable/disable hdcp, false otherwise
>   */
> -void drm_hdcp_atomic_check(struct drm_connector *connector,
> +bool drm_hdcp_atomic_check(struct drm_connector *connector,
>  			   struct drm_atomic_state *state)
>  {
>  	struct drm_connector_state *new_conn_state, *old_conn_state;
> @@ -450,10 +453,12 @@ void drm_hdcp_atomic_check(struct
> drm_connector *connector,
>  		 * If the connector is being disabled with CP enabled, mark it
>  		 * desired so it's re-enabled when the connector is brought
> back
>  		 */
> -		if (old_hdcp ==
> DRM_MODE_CONTENT_PROTECTION_ENABLED)
> +		if (old_hdcp ==
> DRM_MODE_CONTENT_PROTECTION_ENABLED) {
>  			new_conn_state->content_protection =
> 
> 	DRM_MODE_CONTENT_PROTECTION_DESIRED;
> -		return;
> +			return true;
> +		}
> +		return false;
>  	}
> 
>  	new_crtc_state =
> @@ -465,9 +470,19 @@ void drm_hdcp_atomic_check(struct
> drm_connector *connector,
>  	*/
>  	if (drm_atomic_crtc_needs_modeset(new_crtc_state) &&
>  	    (old_hdcp == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
> -	     new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED))
> +	     new_hdcp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED))
> {
>  		new_conn_state->content_protection =
>  			DRM_MODE_CONTENT_PROTECTION_DESIRED;
> +		return true;
> +	}
> +
> +	/*
> +	 * Coming back from disable or changing CRTC with DESIRED state
> requires
> +	 * that the driver try CP enable.
> +	 */

Hi ,
We can have a clearer comment which says something like "Coming back from
UNDESIRED state, CRTC change or re-enablement requires the driver to try CP enable"

Regards,
Suraj Kandpal
> +	if (new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
> +	    new_conn_state->crtc != old_conn_state->crtc)
> +		return true;
> 
>  	/*
>  	 * Nothing to do if content type is unchanged and one of:
> @@ -482,9 +497,9 @@ void drm_hdcp_atomic_check(struct drm_connector
> *connector,
>  	     new_hdcp == DRM_MODE_CONTENT_PROTECTION_DESIRED)) {
>  		if (old_conn_state->hdcp_content_type ==
>  		    new_conn_state->hdcp_content_type)
> -			return;
> +			return false;
>  	}
> 
> -	new_crtc_state->mode_changed = true;
> +	return true;
>  }
>  EXPORT_SYMBOL(drm_hdcp_atomic_check);
> diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c
> b/drivers/gpu/drm/i915/display/intel_atomic.c
> index 8a473199c4bf..a2067cbae2d5 100644
> --- a/drivers/gpu/drm/i915/display/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/display/intel_atomic.c
> @@ -123,8 +123,6 @@ int intel_digital_connector_atomic_check(struct
> drm_connector *conn,
>  		to_intel_digital_connector_state(old_state);
>  	struct drm_crtc_state *crtc_state;
> 
> -	drm_hdcp_atomic_check(conn, state);
> -
>  	if (!new_state->crtc)
>  		return 0;
> 
> @@ -140,8 +138,8 @@ int intel_digital_connector_atomic_check(struct
> drm_connector *conn,
>  	    new_conn_state->base.picture_aspect_ratio != old_conn_state-
> >base.picture_aspect_ratio ||
>  	    new_conn_state->base.content_type != old_conn_state-
> >base.content_type ||
>  	    new_conn_state->base.scaling_mode != old_conn_state-
> >base.scaling_mode ||
> -	    new_conn_state->base.privacy_screen_sw_state !=
> old_conn_state->base.privacy_screen_sw_state ||
> -	    !drm_connector_atomic_hdr_metadata_equal(old_state,
> new_state))
> +	    !drm_connector_atomic_hdr_metadata_equal(old_state,
> new_state) ||
> +	    drm_hdcp_atomic_check(conn, state))
>  		crtc_state->mode_changed = true;
> 
>  	return 0;
> diff --git a/include/drm/display/drm_hdcp_helper.h
> b/include/drm/display/drm_hdcp_helper.h
> index dd02b2e72a50..cb2cc5002f65 100644
> --- a/include/drm/display/drm_hdcp_helper.h
> +++ b/include/drm/display/drm_hdcp_helper.h
> @@ -19,7 +19,7 @@ int drm_hdcp_check_ksvs_revoked(struct drm_device
> *dev, u8 *ksvs, u32 ksv_count)  int
> drm_connector_attach_content_protection_property(struct drm_connector
> *connector,
>  						     bool hdcp_content_type);
>  void drm_hdcp_update_content_protection(struct drm_connector
> *connector, u64 val); -void drm_hdcp_atomic_check(struct drm_connector
> *connector,
> +bool drm_hdcp_atomic_check(struct drm_connector *connector,
>  			   struct drm_atomic_state *state);
> 
>  #endif
> --
> 2.39.0.246.g2a6d74b583-goog


^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes
  2023-01-18 19:30 ` [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes Mark Yacoub
@ 2023-03-10  8:25   ` Kandpal, Suraj
  2023-03-23  7:17     ` Kandpal, Suraj
  0 siblings, 1 reply; 38+ messages in thread
From: Kandpal, Suraj @ 2023-03-10  8:25 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: quic_sbillaka, konrad.dybcio, Souza, Jose, bjorn.andersson,
	krzysztof.kozlowski+dt, hbh25y, Vasut, Marek, Dixit, Ashutosh,
	sean, abhinavk, javierm, Murthy, Arun R, Lisovskiy, Stanislav,
	agross, quic_jesszhan, Nautiyal, Ankit K, Nikula, Jani,
	De Marchi, Lucas, quic_abhinavk, swboyd, robh+dt,
	christophe.jaillet, maxime, Vivi, Rodrigo, johan+linaro,
	tvrtko.ursulin, andersson, dianders, Sharma, Swati2, Navare,
	Manasi D, tzimmermann, Modem, Bhanuprakash, dmitry.baryshkov,
	seanpaul

> Subject: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes
> 
> From: Sean Paul <seanpaul@chromium.org>
> 
> The shim functions return error codes, but they are discarded in
> intel_hdcp.c. This patch plumbs the return codes through so they are
> properly handled.
> 
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-7-
> sean@poorly.run #v1
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-7-
> sean@poorly.run #v2
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-7-
> sean@poorly.run #v3
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
> 7-sean@poorly.run #v4
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
> 7-sean@poorly.run #v5
> 
> Changes in v2:
> -None
> Changes in v3:
> -None
> Changes in v4:
> -None
> Changes in v5:
> -None
> Changes in v6:
> -Rebased
> 
> ---
>  .../drm/i915/display/intel_display_debugfs.c  |  9 +++-
>  drivers/gpu/drm/i915/display/intel_hdcp.c     | 51 ++++++++++---------
>  drivers/gpu/drm/i915/display/intel_hdcp.h     |  4 +-
>  3 files changed, 37 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> index 7c7253a2541c..13a4153bb76e 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> @@ -492,6 +492,7 @@ static void intel_panel_info(struct seq_file *m,  static
> void intel_hdcp_info(struct seq_file *m,
>  			    struct intel_connector *intel_connector)  {
> +	int ret;
>  	bool hdcp_cap, hdcp2_cap;
> 
>  	if (!intel_connector->hdcp.shim) {
> @@ -499,8 +500,12 @@ static void intel_hdcp_info(struct seq_file *m,
>  		goto out;
>  	}
> 
> -	hdcp_cap = intel_hdcp_capable(intel_connector);
> -	hdcp2_cap = intel_hdcp2_capable(intel_connector);
> +	ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
> +	if (ret)
> +		hdcp_cap = false;
> +	ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
> +	if (ret)
> +		hdcp2_cap = false;
> 

This does not seem to be adding value here as this error which you referred to as being ignored
is used both in case of hdmi and dp is being to determine if hdcp_cap or hdcp2 cap is true or false
which you basically reiterate here too
check the intel_dp_hdcp2_capable and intel_hdmi_hdcp2_capable .
this change in itself can be removed.

Regards,
Suraj Kandpal

>  	if (hdcp_cap)
>  		seq_puts(m, "HDCP1.4 ");
> diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c
> b/drivers/gpu/drm/i915/display/intel_hdcp.c
> index 0a20bc41be55..61a862ae1f28 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdcp.c
> +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
> @@ -177,50 +177,49 @@ int intel_hdcp_read_valid_bksv(struct
> intel_digital_port *dig_port,  }
> 
>  /* Is HDCP1.4 capable on Platform and Sink */ -bool
> intel_hdcp_capable(struct intel_connector *connector)
> +int intel_hdcp_capable(struct intel_connector *connector, bool
> +*capable)
>  {
>  	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
>  	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> -	bool capable = false;
>  	u8 bksv[5];
> 
> +	*capable = false;
> +
>  	if (!shim)
> -		return capable;
> +		return 0;
> 
> -	if (shim->hdcp_capable) {
> -		shim->hdcp_capable(dig_port, &capable);
> -	} else {
> -		if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> -			capable = true;
> -	}
> +	if (shim->hdcp_capable)
> +		return shim->hdcp_capable(dig_port, capable);
> +
> +	if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> +		*capable = true;
> 
> -	return capable;
> +	return 0;
>  }
> 
>  /* Is HDCP2.2 capable on Platform and Sink */ -bool
> intel_hdcp2_capable(struct intel_connector *connector)
> +int intel_hdcp2_capable(struct intel_connector *connector, bool
> +*capable)
>  {
>  	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
> -	bool capable = false;
> +
> +	*capable = false;
> 
>  	/* I915 support for HDCP2.2 */
>  	if (!hdcp->hdcp2_supported)
> -		return false;
> +		return 0;
> 
>  	/* MEI interface is solid */
>  	mutex_lock(&dev_priv->display.hdcp.comp_mutex);
>  	if (!dev_priv->display.hdcp.comp_added ||  !dev_priv-
> >display.hdcp.master) {
>  		mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> -		return false;
> +		return 0;
>  	}
>  	mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> 
>  	/* Sink's capability for HDCP2.2 */
> -	hdcp->shim->hdcp_2_2_capable(dig_port, &capable);
> -
> -	return capable;
> +	return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
>  }
> 
>  static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv, @@ -
> 2355,6 +2354,7 @@ int intel_hdcp_enable(struct intel_connector
> *connector,
>  	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
>  	unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
> +	bool capable;
>  	int ret = -EINVAL;
> 
>  	if (!hdcp->shim)
> @@ -2373,21 +2373,27 @@ int intel_hdcp_enable(struct intel_connector
> *connector,
>  	 * Considering that HDCP2.2 is more secure than HDCP1.4, If the
> setup
>  	 * is capable of HDCP2.2, it is preferred to use HDCP2.2.
>  	 */
> -	if (intel_hdcp2_capable(connector)) {
> +	ret = intel_hdcp2_capable(connector, &capable);
> +	if (capable) {
>  		ret = _intel_hdcp2_enable(connector);
> -		if (!ret)
> +		if (!ret) {
>  			check_link_interval =
> DRM_HDCP2_CHECK_PERIOD_MS;
> +			goto out;
> +		}
>  	}
> 
>  	/*
>  	 * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
>  	 * be attempted.
>  	 */
> -	if (ret && intel_hdcp_capable(connector) &&
> -	    hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) {
> +	ret = intel_hdcp_capable(connector, &capable);
> +	if (ret)
> +		goto out;
> +
> +	if (capable && hdcp->content_type !=
> DRM_MODE_HDCP_CONTENT_TYPE1)
>  		ret = _intel_hdcp_enable(connector);
> -	}
> 
> +out:
>  	if (!ret) {
>  		schedule_delayed_work(&hdcp->check_work,
> check_link_interval);
>  		intel_hdcp_update_value(connector,
> @@ -2395,7 +2401,6 @@ int intel_hdcp_enable(struct intel_connector
> *connector,
>  					true);
>  	}
> 
> -out:
>  	mutex_unlock(&dig_port->hdcp_mutex);
>  	mutex_unlock(&hdcp->mutex);
>  	return ret;
> diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h
> b/drivers/gpu/drm/i915/display/intel_hdcp.h
> index 7c5fd84a7b65..f06f6e5a2b1a 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdcp.h
> +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
> @@ -33,8 +33,8 @@ void intel_hdcp_update_pipe(struct intel_atomic_state
> *state,
>  			    const struct intel_crtc_state *crtc_state,
>  			    const struct drm_connector_state *conn_state);
> bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port
> port); -bool intel_hdcp_capable(struct intel_connector *connector); -bool
> intel_hdcp2_capable(struct intel_connector *connector);
> +int intel_hdcp_capable(struct intel_connector *connector, bool
> +*capable); int intel_hdcp2_capable(struct intel_connector *connector,
> +bool *capable);
>  void intel_hdcp_component_init(struct drm_i915_private *dev_priv);  void
> intel_hdcp_component_fini(struct drm_i915_private *dev_priv);  void
> intel_hdcp_cleanup(struct intel_connector *connector);
> --
> 2.39.0.246.g2a6d74b583-goog


^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [Intel-gfx] [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915
  2023-01-18 19:30 ` [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915 Mark Yacoub
  2023-01-31 17:16   ` [Intel-gfx] " Rodrigo Vivi
@ 2023-03-14  5:54   ` Kandpal, Suraj
  2023-03-24 19:34     ` Mark Yacoub
  1 sibling, 1 reply; 38+ messages in thread
From: Kandpal, Suraj @ 2023-03-14  5:54 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: quic_sbillaka, konrad.dybcio, bjorn.andersson,
	krzysztof.kozlowski+dt, airlied, hbh25y, Vasut, Marek, abhinavk,
	javierm, agross, quic_jesszhan, daniel, Nikula, Jani, De Marchi,
	Lucas, quic_abhinavk, swboyd, robh+dt, christophe.jaillet,
	maxime, Vivi, Rodrigo, johan+linaro, andersson, dianders,
	tzimmermann, dmitry.baryshkov, seanpaul

> 
> From: Sean Paul <seanpaul@chromium.org>
> 
> Now that all of the HDCP 1.x logic has been migrated to the central HDCP
> helpers, use it in the i915 driver.
> 
> The majority of the driver code for HDCP 1.x will live in intel_hdcp.c,
> however there are a few helper hooks which are connector-specific and
> need to be partially or fully implemented in the intel_dp_hdcp.c or
> intel_hdmi.c.
> 
> We'll leave most of the HDCP 2.x code alone since we don't have another
> implementation of HDCP 2.x to use as reference for what should and
> should not live in the drm helpers. The helper will call the overly
> general enable/disable/is_capable HDCP 2.x callbacks and leave the
> interesting stuff for the driver. Once we have another HDCP 2.x
> implementation, we should do a similar migration.
> 
> Acked-by: Jani Nikula <jani.nikula@intel.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-8-
> sean@poorly.run #v1
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-8-
> sean@poorly.run #v2
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-8-
> sean@poorly.run #v3
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
> 8-sean@poorly.run #v4
> Link:
> https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
> 8-sean@poorly.run #v5
> 
> Changes in v2:
> -Fix mst helper function pointer reported by 0-day
> Changes in v3:
> -Add forward declaration for drm_atomic_state in intel_hdcp.h identified
>  by 0-day
> Changes in v4:
> -None
> Changes in v5:
> -None
> Changes in v6:
> -Rebased.
> 
> ---
>  drivers/gpu/drm/i915/display/intel_ddi.c      |  32 +-
>  .../drm/i915/display/intel_display_debugfs.c  |   6 +-
>  .../drm/i915/display/intel_display_types.h    |  60 +-
>  drivers/gpu/drm/i915/display/intel_dp_hdcp.c  | 348 +++----
>  drivers/gpu/drm/i915/display/intel_dp_mst.c   |  16 +-
>  drivers/gpu/drm/i915/display/intel_hdcp.c     | 952 +++---------------
>  drivers/gpu/drm/i915/display/intel_hdcp.h     |  31 +-
>  drivers/gpu/drm/i915/display/intel_hdmi.c     | 270 ++---
>  8 files changed, 445 insertions(+), 1270 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c
> b/drivers/gpu/drm/i915/display/intel_ddi.c
> index 69ecf2a3d6c6..a4397f066a3e 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -28,6 +28,7 @@
>  #include <linux/string_helpers.h>
> 
>  #include <drm/display/drm_scdc_helper.h>
> +#include <drm/display/drm_hdcp_helper.h>
>  #include <drm/drm_privacy_screen_consumer.h>
> 
>  #include "i915_drv.h"
> @@ -2909,6 +2910,10 @@ static void intel_enable_ddi(struct
> intel_atomic_state *state,
>  			     const struct intel_crtc_state *crtc_state,
>  			     const struct drm_connector_state *conn_state)
>  {
> +	struct intel_connector *connector =
> +		to_intel_connector(conn_state->connector);
> +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> +
>  	drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
> 
>  	if (!intel_crtc_is_bigjoiner_slave(crtc_state))
> @@ -2925,12 +2930,10 @@ static void intel_enable_ddi(struct
> intel_atomic_state *state,
>  	else
>  		intel_enable_ddi_dp(state, encoder, crtc_state,
> conn_state);
> 
> -	/* Enable hdcp if it's desired */
> -	if (conn_state->content_protection ==
> -	    DRM_MODE_CONTENT_PROTECTION_DESIRED)
> -		intel_hdcp_enable(to_intel_connector(conn_state-
> >connector),
> -				  crtc_state,
> -				  (u8)conn_state->hdcp_content_type);
> +	if (connector->hdcp_helper_data)
> +		drm_hdcp_helper_atomic_commit(connector-
> >hdcp_helper_data,
> +					      &state->base,
> +					      &dig_port->hdcp_mutex);
>  }
> 
>  static void intel_disable_ddi_dp(struct intel_atomic_state *state,
> @@ -2976,7 +2979,14 @@ static void intel_disable_ddi(struct
> intel_atomic_state *state,
>  			      const struct intel_crtc_state *old_crtc_state,
>  			      const struct drm_connector_state
> *old_conn_state)
>  {
> -	intel_hdcp_disable(to_intel_connector(old_conn_state-
> >connector));
> +	struct intel_connector *connector =
> +		to_intel_connector(old_conn_state->connector);
> +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> +
> +	if (connector->hdcp_helper_data)
> +		drm_hdcp_helper_atomic_commit(connector-
> >hdcp_helper_data,
> +					      &state->base,
> +					      &dig_port->hdcp_mutex);
> 
>  	if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
>  		intel_disable_ddi_hdmi(state, encoder, old_crtc_state,
> @@ -3004,13 +3014,19 @@ void intel_ddi_update_pipe(struct
> intel_atomic_state *state,
>  			   const struct intel_crtc_state *crtc_state,
>  			   const struct drm_connector_state *conn_state)
>  {
> +	struct intel_connector *connector =
> +		to_intel_connector(conn_state->connector);
> +	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> 
>  	if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
>  	    !intel_encoder_is_mst(encoder))
>  		intel_ddi_update_pipe_dp(state, encoder, crtc_state,
>  					 conn_state);
> 
> -	intel_hdcp_update_pipe(state, encoder, crtc_state, conn_state);
> +	if (connector->hdcp_helper_data)
> +		drm_hdcp_helper_atomic_commit(connector-
> >hdcp_helper_data,
> +					      &state->base,
> +					      &dig_port->hdcp_mutex);
>  }
> 
>  static void
> diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> index 13a4153bb76e..2e67cca0151c 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> @@ -7,6 +7,7 @@
> 
>  #include <drm/drm_debugfs.h>
>  #include <drm/drm_fourcc.h>
> +#include <drm/display/drm_hdcp_helper.h>
> 
>  #include "i915_debugfs.h"
>  #include "intel_de.h"
> @@ -500,10 +501,11 @@ static void intel_hdcp_info(struct seq_file *m,
>  		goto out;
>  	}
> 
> -	ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
> +	ret = drm_hdcp_helper_hdcp1_capable(intel_connector-
> >hdcp_helper_data,
> +					    &hdcp_cap);
>  	if (ret)
>  		hdcp_cap = false;
> -	ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
> +	ret = intel_hdcp2_capable(&intel_connector->base, &hdcp2_cap);
>  	if (ret)
>  		hdcp2_cap = false;
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h
> b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 298d00a11f47..6260a40586ae 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -416,71 +416,14 @@ enum check_link_response {
>   *		The offsets of the registers are different for DP vs. HDMI
>   *	- Receiver register masks/offsets
>   *		For instance, the ready bit for the KSV fifo is in a different
> - *		place on DP vs HDMI
> - *	- Receiver register names
> - *		Seriously. In the DP spec, the 16-bit register containing
> - *		downstream information is called BINFO, on HDMI it's called
> - *		BSTATUS. To confuse matters further, DP has a BSTATUS
> register
> - *		with a completely different definition.
> - *	- KSV FIFO
> - *		On HDMI, the ksv fifo is read all at once, whereas on DP it
> must
> - *		be read 3 keys at a time
> - *	- Aksv output
> - *		Since Aksv is hidden in hardware, there's different
> procedures
> - *		to send it over DP AUX vs DDC

I really think we can keep the comment as its mentioning the ways that the two busses differ

> + *		place on DP vs HDMI.
>   */
>  struct intel_hdcp_shim {
> -	/* Outputs the transmitter's An and Aksv values to the receiver. */
> -	int (*write_an_aksv)(struct intel_digital_port *dig_port, u8 *an);
> -
> -	/* Reads the receiver's key selection vector */
> -	int (*read_bksv)(struct intel_digital_port *dig_port, u8 *bksv);
> -
> -	/*
> -	 * Reads BINFO from DP receivers and BSTATUS from HDMI
> receivers. The
> -	 * definitions are the same in the respective specs, but the names
> are
> -	 * different. Call it BSTATUS since that's the name the HDMI spec
> -	 * uses and it was there first.
> -	 */
> -	int (*read_bstatus)(struct intel_digital_port *dig_port,
> -			    u8 *bstatus);
> -
> -	/* Determines whether a repeater is present downstream */
> -	int (*repeater_present)(struct intel_digital_port *dig_port,
> -				bool *repeater_present);
> -
> -	/* Reads the receiver's Ri' value */
> -	int (*read_ri_prime)(struct intel_digital_port *dig_port, u8 *ri);
> -
> -	/* Determines if the receiver's KSV FIFO is ready for consumption */
> -	int (*read_ksv_ready)(struct intel_digital_port *dig_port,
> -			      bool *ksv_ready);
> -
> -	/* Reads the ksv fifo for num_downstream devices */
> -	int (*read_ksv_fifo)(struct intel_digital_port *dig_port,
> -			     int num_downstream, u8 *ksv_fifo);
> -
> -	/* Reads a 32-bit part of V' from the receiver */
> -	int (*read_v_prime_part)(struct intel_digital_port *dig_port,
> -				 int i, u32 *part);
> -
>  	/* Enables HDCP signalling on the port */
>  	int (*toggle_signalling)(struct intel_digital_port *dig_port,
>  				 enum transcoder cpu_transcoder,
>  				 bool enable);
> 
> -	/* Enable/Disable stream encryption on DP MST Transport Link */
> -	int (*stream_encryption)(struct intel_connector *connector,
> -				 bool enable);
> -
> -	/* Ensures the link is still protected */
> -	bool (*check_link)(struct intel_digital_port *dig_port,
> -			   struct intel_connector *connector);
> -
> -	/* Detects panel's hdcp capability. This is optional for HDMI. */
> -	int (*hdcp_capable)(struct intel_digital_port *dig_port,
> -			    bool *hdcp_capable);
> -
>  	/* HDCP adaptation(DP/HDMI) required on the port */
>  	enum hdcp_wired_protocol protocol;
> 
> @@ -610,6 +553,7 @@ struct intel_connector {
>  	struct work_struct modeset_retry_work;
> 
>  	struct intel_hdcp hdcp;
> +	struct drm_hdcp_helper_data *hdcp_helper_data;
>  };
> 
>  struct intel_digital_connector_state {
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> index 88689124c013..d61ac8d69951 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> @@ -55,17 +55,24 @@ static void intel_dp_hdcp_wait_for_cp_irq(struct
> intel_hdcp *hdcp, int timeout)
>  		DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
>  }
> 
> -static
> -int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> -				u8 *an)
> +static int intel_dp_hdcp1_send_an_aksv(struct drm_connector
> *drm_connector)
>  {

I think the name intel_dp_hdcp_send_an_aksv should be enough as this step
is done only for hdcp 1.x and not hdcp 2.x.

> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
>  	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> +	struct drm_hdcp_an an;
>  	u8 aksv[DRM_HDCP_KSV_LEN] = {};
>  	ssize_t dpcd_ret;
> +	int ret;
> 
>  	/* Output An first, that's easy */
> +	ret = intel_hdcp1_read_an(drm_connector, &an);
> +	if (ret)
> +		return ret;
> +
>  	dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux,
> DP_AUX_HDCP_AN,
> -				     an, DRM_HDCP_AN_LEN);
> +				     an.bytes, DRM_HDCP_AN_LEN);
>  	if (dpcd_ret != DRM_HDCP_AN_LEN) {
>  		drm_dbg_kms(&i915->drm,
>  			    "Failed to write An over DP/AUX (%zd)\n",
> @@ -91,158 +98,6 @@ int intel_dp_hdcp_write_an_aksv(struct
> intel_digital_port *dig_port,
>  	return 0;
>  }
> 
> -static int intel_dp_hdcp_read_bksv(struct intel_digital_port *dig_port,
> -				   u8 *bksv)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BKSV,
> bksv,
> -			       DRM_HDCP_KSV_LEN);
> -	if (ret != DRM_HDCP_KSV_LEN) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read Bksv from DP/AUX failed (%zd)\n", ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -	return 0;
> -}
> -
> -static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
> -				      u8 *bstatus)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -
> -	/*
> -	 * For some reason the HDMI and DP HDCP specs call this register
> -	 * definition by different names. In the HDMI spec, it's called
> BSTATUS,
> -	 * but in DP it's called BINFO.
> -	 */
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> DP_AUX_HDCP_BINFO,
> -			       bstatus, DRM_HDCP_BSTATUS_LEN);
> -	if (ret != DRM_HDCP_BSTATUS_LEN) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_read_bcaps(struct intel_digital_port *dig_port,
> -			     u8 *bcaps)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> DP_AUX_HDCP_BCAPS,
> -			       bcaps, 1);
> -	if (ret != 1) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read bcaps from DP/AUX failed (%zd)\n", ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_repeater_present(struct intel_digital_port *dig_port,
> -				   bool *repeater_present)
> -{
> -	ssize_t ret;
> -	u8 bcaps;
> -
> -	ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
> -	if (ret)
> -		return ret;
> -
> -	*repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
> -				u8 *ri_prime)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> DP_AUX_HDCP_RI_PRIME,
> -			       ri_prime, DRM_HDCP_RI_LEN);
> -	if (ret != DRM_HDCP_RI_LEN) {
> -		drm_dbg_kms(&i915->drm, "Read Ri' from DP/AUX failed
> (%zd)\n",
> -			    ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
> -				 bool *ksv_ready)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -	u8 bstatus;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> DP_AUX_HDCP_BSTATUS,
> -			       &bstatus, 1);
> -	if (ret != 1) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -	*ksv_ready = bstatus & DP_BSTATUS_READY;
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
> -				int num_downstream, u8 *ksv_fifo)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -	int i;
> -
> -	/* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
> -	for (i = 0; i < num_downstream; i += 3) {
> -		size_t len = min(num_downstream - i, 3) *
> DRM_HDCP_KSV_LEN;
> -		ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> -				       DP_AUX_HDCP_KSV_FIFO,
> -				       ksv_fifo + i * DRM_HDCP_KSV_LEN,
> -				       len);
> -		if (ret != len) {
> -			drm_dbg_kms(&i915->drm,
> -				    "Read ksv[%d] from DP/AUX failed
> (%zd)\n",
> -				    i, ret);
> -			return ret >= 0 ? -EIO : ret;
> -		}
> -	}
> -	return 0;
> -}
> -
> -static
> -int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
> -				    int i, u32 *part)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -
> -	if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
> -		return -EINVAL;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> -			       DP_AUX_HDCP_V_PRIME(i), part,
> -			       DRM_HDCP_V_PRIME_PART_LEN);
> -	if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
> -		return ret >= 0 ? -EIO : ret;
> -	}
> -	return 0;
> -}
> -
>  static
>  int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
>  				    enum transcoder cpu_transcoder,
> @@ -252,40 +107,6 @@ int intel_dp_hdcp_toggle_signalling(struct
> intel_digital_port *dig_port,
>  	return 0;
>  }
> 
> -static
> -bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
> -			      struct intel_connector *connector)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	ssize_t ret;
> -	u8 bstatus;
> -
> -	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> DP_AUX_HDCP_BSTATUS,
> -			       &bstatus, 1);
> -	if (ret != 1) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read bstatus from DP/AUX failed (%zd)\n", ret);
> -		return false;
> -	}
> -
> -	return !(bstatus & (DP_BSTATUS_LINK_FAILURE |
> DP_BSTATUS_REAUTH_REQ));
> -}
> -
> -static
> -int intel_dp_hdcp_capable(struct intel_digital_port *dig_port,
> -			  bool *hdcp_capable)
> -{
> -	ssize_t ret;
> -	u8 bcaps;
> -
> -	ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
> -	if (ret)
> -		return ret;
> -
> -	*hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
> -	return 0;
> -}
> -
>  struct hdcp2_dp_errata_stream_type {
>  	u8	msg_id;
>  	u8	stream_type;
> @@ -628,13 +449,19 @@ int intel_dp_hdcp2_check_link(struct
> intel_digital_port *dig_port,
>  	return ret;
>  }
> 
> -static
> -int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
> -			   bool *capable)
> +static int intel_dp_hdcp2_capable(struct drm_connector *drm_connector,
> +				  bool *capable)
>  {
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
>  	u8 rx_caps[3];
>  	int ret;
> 
> +	ret = intel_hdcp2_capable(drm_connector, capable);
> +	if (ret || !capable)
> +		return ret;
> +
>  	*capable = false;
>  	ret = drm_dp_dpcd_read(&dig_port->dp.aux,
>  			       DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
> @@ -650,22 +477,11 @@ int intel_dp_hdcp2_capable(struct
> intel_digital_port *dig_port,
>  }
> 
>  static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
> -	.write_an_aksv = intel_dp_hdcp_write_an_aksv,
> -	.read_bksv = intel_dp_hdcp_read_bksv,
> -	.read_bstatus = intel_dp_hdcp_read_bstatus,
> -	.repeater_present = intel_dp_hdcp_repeater_present,
> -	.read_ri_prime = intel_dp_hdcp_read_ri_prime,
> -	.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
> -	.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
> -	.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
>  	.toggle_signalling = intel_dp_hdcp_toggle_signalling,
> -	.check_link = intel_dp_hdcp_check_link,
> -	.hdcp_capable = intel_dp_hdcp_capable,
>  	.write_2_2_msg = intel_dp_hdcp2_write_msg,
>  	.read_2_2_msg = intel_dp_hdcp2_read_msg,
>  	.config_stream_type = intel_dp_hdcp2_config_stream_type,
>  	.check_2_2_link = intel_dp_hdcp2_check_link,
> -	.hdcp_2_2_capable = intel_dp_hdcp2_capable,
>  	.protocol = HDCP_PROTOCOL_DP,
>  };
> 
> @@ -721,6 +537,46 @@ intel_dp_mst_hdcp_stream_encryption(struct
> intel_connector *connector,
>  	return 0;
>  }
> 
> +static int
> +intel_dp_mst_hdcp1_post_encryption(struct drm_connector
> *drm_connector)
> +{
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	int ret;
> +
> +	ret = intel_hdcp1_post_encryption(drm_connector);
> +	if (ret)
> +		return ret;
> +
> +	return intel_dp_mst_hdcp_stream_encryption(connector, true);
> +}
> +
> +static int intel_dp_mst_hdcp1_disable(struct drm_connector
> *drm_connector)
> +{
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *i915 = to_i915(connector->base.dev);
> +	int ret;
> +
> +	ret = intel_dp_mst_hdcp_stream_encryption(connector, true);
> +	if (ret) {
> +		drm_err(&i915->drm,
> +			"[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
> +			connector->base.name, connector->base.base.id);
> +		return ret;
> +	}
> +
> +	/*
> +	 * If there are other connectors on this port using HDCP,
> +	 * don't disable it until it disabled HDCP encryption for
> +	 * all connectors in MST topology.
> +	*/
> +	if (dig_port->num_hdcp_streams > 0)
> +		return 0;
> +
> +	return intel_hdcp1_disable(drm_connector);
> +}
> +
>  static int
>  intel_dp_mst_hdcp2_stream_encryption(struct intel_connector
> *connector,
>  				     bool enable)
> @@ -779,45 +635,85 @@ int intel_dp_mst_hdcp2_check_link(struct
> intel_digital_port *dig_port,
>  }
> 
>  static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
> -	.write_an_aksv = intel_dp_hdcp_write_an_aksv,
> -	.read_bksv = intel_dp_hdcp_read_bksv,
> -	.read_bstatus = intel_dp_hdcp_read_bstatus,
> -	.repeater_present = intel_dp_hdcp_repeater_present,
> -	.read_ri_prime = intel_dp_hdcp_read_ri_prime,
> -	.read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
> -	.read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
> -	.read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
>  	.toggle_signalling = intel_dp_hdcp_toggle_signalling,
> -	.stream_encryption = intel_dp_mst_hdcp_stream_encryption,
> -	.check_link = intel_dp_hdcp_check_link,
> -	.hdcp_capable = intel_dp_hdcp_capable,
>  	.write_2_2_msg = intel_dp_hdcp2_write_msg,
>  	.read_2_2_msg = intel_dp_hdcp2_read_msg,
>  	.config_stream_type = intel_dp_hdcp2_config_stream_type,
>  	.stream_2_2_encryption = intel_dp_mst_hdcp2_stream_encryption,
>  	.check_2_2_link = intel_dp_mst_hdcp2_check_link,
> -	.hdcp_2_2_capable = intel_dp_hdcp2_capable,
>  	.protocol = HDCP_PROTOCOL_DP,
>  };
> 
> +static const struct drm_hdcp_helper_funcs intel_dp_hdcp_helper_funcs = {
> +	.setup = intel_hdcp_setup,
> +	.load_keys = intel_hdcp_load_keys,
> +	.hdcp2_capable = intel_dp_hdcp2_capable,
> +	.hdcp2_enable = intel_hdcp2_enable,
> +	.hdcp2_check_link = intel_hdcp2_check_link,
> +	.hdcp2_disable = intel_hdcp2_disable,
> +	.hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
> +	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> +	.hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
> +	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> +	.hdcp1_match_ri = intel_hdcp1_match_ri,
> +	.hdcp1_post_encryption = intel_hdcp1_post_encryption,
> +	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> +	.hdcp1_disable = intel_hdcp1_disable,
> +};
> +
> +static const struct drm_hdcp_helper_funcs
> intel_dp_mst_hdcp_helper_funcs = {
> +	.setup = intel_hdcp_setup,
> +	.load_keys = intel_hdcp_load_keys,
> +	.hdcp2_capable = intel_dp_hdcp2_capable,
> +	.hdcp2_enable = intel_hdcp2_enable,
> +	.hdcp2_check_link = intel_hdcp2_check_link,
> +	.hdcp2_disable = intel_hdcp2_disable,
> +	.hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
> +	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> +	.hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
> +	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> +	.hdcp1_match_ri = intel_hdcp1_match_ri,
> +	.hdcp1_post_encryption = intel_dp_mst_hdcp1_post_encryption,
> +	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> +	.hdcp1_disable = intel_dp_mst_hdcp1_disable,
> +};
> +
>  int intel_dp_hdcp_init(struct intel_digital_port *dig_port,
> -		       struct intel_connector *intel_connector)
> +		       struct intel_connector *connector)
>  {
> -	struct drm_device *dev = intel_connector->base.dev;
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_encoder *intel_encoder = &dig_port->base;
>  	enum port port = intel_encoder->port;
>  	struct intel_dp *intel_dp = &dig_port->dp;
> +	struct drm_hdcp_helper_data *data;
> +	const struct drm_hdcp_helper_funcs *helper_funcs;
> +	const struct intel_hdcp_shim *intel_shim;
> +	int ret;
> 
> -	if (!is_hdcp_supported(dev_priv, port))
> +	if (!is_hdcp_supported(dev_priv, port) ||
> intel_dp_is_edp(intel_dp))
>  		return 0;
> 
> -	if (intel_connector->mst_port)
> -		return intel_hdcp_init(intel_connector, dig_port,
> -				       &intel_dp_mst_hdcp_shim);
> -	else if (!intel_dp_is_edp(intel_dp))
> -		return intel_hdcp_init(intel_connector, dig_port,
> -				       &intel_dp_hdcp_shim);
> +	if (connector->mst_port) {
> +		helper_funcs = &intel_dp_mst_hdcp_helper_funcs;
> +		intel_shim = &intel_dp_mst_hdcp_shim;
> +	} else {
> +		helper_funcs = &intel_dp_hdcp_helper_funcs;
> +		intel_shim = &intel_dp_hdcp_shim;
> +	}
> +
> +	data = drm_hdcp_helper_initialize_dp(
> +		&connector->base, &dig_port->dp.aux, helper_funcs, true);

The alignment here needs fixing

> +	if (IS_ERR(data)) {
> +		drm_dbg_kms(&dev_priv->drm, "HDCP init failed,
> skipping.\n");
> +		return PTR_ERR(data);
> +	}
> +
> +	ret = intel_hdcp_init(connector, dig_port, intel_shim);
> +	if (ret) {
> +		drm_hdcp_helper_destroy(data);
> +		return ret;
> +	}
> 
> +	connector->hdcp_helper_data = data;
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> index 03604a37931c..ececb7aa4b90 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> @@ -27,6 +27,7 @@
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_edid.h>
>  #include <drm/drm_probe_helper.h>
> +#include <drm/display/drm_hdcp_helper.h>
> 
>  #include "i915_drv.h"
>  #include "intel_atomic.h"
> @@ -40,7 +41,6 @@
>  #include "intel_dp_hdcp.h"
>  #include "intel_dp_mst.h"
>  #include "intel_dpio_phy.h"
> -#include "intel_hdcp.h"
>  #include "intel_hotplug.h"
>  #include "skl_scaler.h"
> 
> @@ -371,7 +371,10 @@ static void intel_mst_disable_dp(struct
> intel_atomic_state *state,
>  	drm_dbg_kms(&i915->drm, "active links %d\n",
>  		    intel_dp->active_mst_links);
> 
> -	intel_hdcp_disable(intel_mst->connector);
> +	if (connector->hdcp_helper_data)
> +		drm_hdcp_helper_atomic_commit(connector-
> >hdcp_helper_data,
> +					      &state->base,
> +					      &dig_port->hdcp_mutex);
> 
>  	drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state,
>  			      drm_atomic_get_mst_payload_state(mst_state,
> connector->port));
> @@ -579,11 +582,10 @@ static void intel_mst_enable_dp(struct
> intel_atomic_state *state,
>  	intel_audio_codec_enable(encoder, pipe_config, conn_state);
> 
>  	/* Enable hdcp if it's desired */
> -	if (conn_state->content_protection ==
> -	    DRM_MODE_CONTENT_PROTECTION_DESIRED)
> -		intel_hdcp_enable(to_intel_connector(conn_state-
> >connector),
> -				  pipe_config,
> -				  (u8)conn_state->hdcp_content_type);
> +	if (connector->hdcp_helper_data)
> +		drm_hdcp_helper_atomic_commit(connector-
> >hdcp_helper_data,
> +					      &state->base,
> +					      &dig_port->hdcp_mutex);
>  }
> 
>  static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
> diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c
> b/drivers/gpu/drm/i915/display/intel_hdcp.c
> index 61a862ae1f28..f09afbc9567b 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdcp.c
> +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
> @@ -140,67 +140,10 @@ static int intel_hdcp_prepare_streams(struct
> intel_connector *connector)
>  	return 0;
>  }
> 
> -static
> -bool intel_hdcp_is_ksv_valid(u8 *ksv)
> -{
> -	int i, ones = 0;
> -	/* KSV has 20 1's and 20 0's */
> -	for (i = 0; i < DRM_HDCP_KSV_LEN; i++)
> -		ones += hweight8(ksv[i]);
> -	if (ones != 20)
> -		return false;
> -
> -	return true;
> -}
> -
> -static
> -int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port,
> -			       const struct intel_hdcp_shim *shim, u8 *bksv)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int ret, i, tries = 2;
> -
> -	/* HDCP spec states that we must retry the bksv if it is invalid */
> -	for (i = 0; i < tries; i++) {
> -		ret = shim->read_bksv(dig_port, bksv);
> -		if (ret)
> -			return ret;
> -		if (intel_hdcp_is_ksv_valid(bksv))
> -			break;
> -	}
> -	if (i == tries) {
> -		drm_dbg_kms(&i915->drm, "Bksv is invalid\n");
> -		return -ENODEV;
> -	}
> -
> -	return 0;
> -}
> -
> -/* Is HDCP1.4 capable on Platform and Sink */
> -int intel_hdcp_capable(struct intel_connector *connector, bool *capable)
> -{
> -	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
> -	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> -	u8 bksv[5];
> -
> -	*capable = false;
> -
> -	if (!shim)
> -		return 0;
> -
> -	if (shim->hdcp_capable)
> -		return shim->hdcp_capable(dig_port, capable);
> -
> -	if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> -		*capable = true;
> -
> -	return 0;
> -}
> -
>  /* Is HDCP2.2 capable on Platform and Sink */
> -int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
> +int intel_hdcp2_capable(struct drm_connector *drm_connector, bool
> *capable)
>  {
> -	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
> 
> @@ -218,16 +161,26 @@ int intel_hdcp2_capable(struct intel_connector
> *connector, bool *capable)
>  	}
>  	mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> 
> -	/* Sink's capability for HDCP2.2 */
> -	return hdcp->shim->hdcp_2_2_capable(dig_port, capable);

Did you miss adding the drm hdcp helper  here to check sink capability

> +	return 0;
>  }
> 
> -static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv,
> -			      enum transcoder cpu_transcoder, enum port
> port)
> +int intel_hdcp1_check_link(struct drm_connector *drm_connector)
>  {
> -	return intel_de_read(dev_priv,
> -	                     HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> -	       HDCP_STATUS_ENC;
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	enum transcoder cpu_transcoder = connector-
> >hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
> +	u32 val;
> +
> +	val = intel_de_read(dev_priv,
> +			    HDCP_STATUS(dev_priv, cpu_transcoder, port));
> +
> +	if (val & HDCP_STATUS_ENC)
> +		return 0;
> +
> +	return -EINVAL;
>  }
> 
>  static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
> @@ -238,27 +191,6 @@ static bool intel_hdcp2_in_use(struct
> drm_i915_private *dev_priv,
>  	       LINK_ENCRYPTION_STATUS;
>  }
> 
> -static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *dig_port,
> -				    const struct intel_hdcp_shim *shim)
> -{
> -	int ret, read_ret;
> -	bool ksv_ready;
> -
> -	/* Poll for ksv list ready (spec says max time allowed is 5s) */
> -	ret = __wait_for(read_ret = shim->read_ksv_ready(dig_port,
> -							 &ksv_ready),
> -			 read_ret || ksv_ready, 5 * 1000 * 1000, 1000,
> -			 100 * 1000);
> -	if (ret)
> -		return ret;
> -	if (read_ret)
> -		return read_ret;
> -	if (!ksv_ready)
> -		return -ETIMEDOUT;
> -
> -	return 0;
> -}
> -
>  static bool hdcp_key_loadable(struct drm_i915_private *dev_priv)
>  {
>  	enum i915_power_well_id id;
> @@ -294,11 +226,18 @@ static void intel_hdcp_clear_keys(struct
> drm_i915_private *dev_priv)
>  		       HDCP_KEY_LOAD_DONE | HDCP_KEY_LOAD_STATUS |
> HDCP_FUSE_IN_PROGRESS | HDCP_FUSE_ERROR | HDCP_FUSE_DONE);
>  }
> 
> -static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
> +int intel_hdcp_load_keys(struct drm_connector *drm_connector)
>  {
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	int ret;
>  	u32 val;
> 
> +	if (!hdcp_key_loadable(dev_priv)) {
> +		drm_err(&dev_priv->drm, "HDCP key Load is not
> possible\n");
> +		return -ENXIO;
> +	}
> +
>  	val = intel_de_read(dev_priv, HDCP_KEY_STATUS);
>  	if ((val & HDCP_KEY_LOAD_DONE) && (val &
> HDCP_KEY_LOAD_STATUS))
>  		return 0;
> @@ -308,8 +247,11 @@ static int intel_hdcp_load_keys(struct
> drm_i915_private *dev_priv)
>  	 * out of reset. So if Key is not already loaded, its an error state.
>  	 */
>  	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
> -		if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) &
> HDCP_KEY_LOAD_DONE))
> -			return -ENXIO;
> +		if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) &
> +		      HDCP_KEY_LOAD_DONE)) {
> +			ret = -ENXIO;
> +			goto err;
> +		}
> 
>  	/*
>  	 * Initiate loading the HDCP key from fuses.
> @@ -325,7 +267,7 @@ static int intel_hdcp_load_keys(struct
> drm_i915_private *dev_priv)
>  			drm_err(&dev_priv->drm,
>  				"Failed to initiate HDCP key load (%d)\n",
>  				ret);
> -			return ret;
> +			goto err;
>  		}
>  	} else {
>  		intel_de_write(dev_priv, HDCP_KEY_CONF,
> HDCP_KEY_LOAD_TRIGGER);
> @@ -335,15 +277,21 @@ static int intel_hdcp_load_keys(struct
> drm_i915_private *dev_priv)
>  	ret = __intel_wait_for_register(&dev_priv->uncore,
> HDCP_KEY_STATUS,
>  					HDCP_KEY_LOAD_DONE,
> HDCP_KEY_LOAD_DONE,
>  					10, 1, &val);
> -	if (ret)
> -		return ret;
> -	else if (!(val & HDCP_KEY_LOAD_STATUS))
> -		return -ENXIO;
> +	if (ret) {
> +		goto err;
> +	} else if (!(val & HDCP_KEY_LOAD_STATUS)) {
> +		ret = -ENXIO;
> +		goto err;
> +	}
> 
>  	/* Send Aksv over to PCH display for use in authentication */
>  	intel_de_write(dev_priv, HDCP_KEY_CONF,
> HDCP_AKSV_SEND_TRIGGER);
> 
>  	return 0;
> +
> +err:
> +	intel_hdcp_clear_keys(dev_priv);
> +	return ret;
>  }
> 
>  /* Returns updated SHA-1 index */
> @@ -399,25 +347,21 @@ u32 intel_hdcp_get_repeater_ctl(struct
> drm_i915_private *dev_priv,
>  	}
>  }
> 
> -static
> -int intel_hdcp_validate_v_prime(struct intel_connector *connector,
> -				const struct intel_hdcp_shim *shim,
> -				u8 *ksv_fifo, u8 num_downstream, u8
> *bstatus)
> +int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
> +			       u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
> +			       u32 *v_prime)
>  {
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
>  	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	enum transcoder cpu_transcoder = connector-
> >hdcp.cpu_transcoder;
>  	enum port port = dig_port->base.port;
> -	u32 vprime, sha_text, sha_leftovers, rep_ctl;
> +	u32 sha_text, sha_leftovers, rep_ctl;
>  	int ret, i, j, sha_idx;
> 
>  	/* Process V' values from the receiver */
> -	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
> -		ret = shim->read_v_prime_part(dig_port, i, &vprime);
> -		if (ret)
> -			return ret;
> -		intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), vprime);
> -	}
> +	for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++)
> +		intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i),
> v_prime[i]);
> 
>  	/*
>  	 * We need to write the concatenation of all device KSVs, BINFO (DP)
> ||
> @@ -642,131 +586,38 @@ int intel_hdcp_validate_v_prime(struct
> intel_connector *connector,
>  	return 0;
>  }
> 
> -/* Implements Part 2 of the HDCP authorization procedure */
> -static
> -int intel_hdcp_auth_downstream(struct intel_connector *connector)
> +int intel_hdcp1_store_receiver_info(struct drm_connector
> *drm_connector,
> +				    u32 *ksv, u32 status, u8 caps,
> +				    bool repeater_present)
>  {
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
>  	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> -	u8 bstatus[2], num_downstream, *ksv_fifo;
> -	int ret, i, tries = 3;
> -
> -	ret = intel_hdcp_poll_ksv_fifo(dig_port, shim);
> -	if (ret) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "KSV list failed to become ready (%d)\n", ret);
> -		return ret;
> -	}
> -
> -	ret = shim->read_bstatus(dig_port, bstatus);
> -	if (ret)
> -		return ret;
> -
> -	if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
> -	    DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
> -		drm_dbg_kms(&dev_priv->drm, "Max Topology Limit
> Exceeded\n");
> -		return -EPERM;
> -	}
> -
> -	/*
> -	 * When repeater reports 0 device count, HDCP1.4 spec allows
> disabling
> -	 * the HDCP encryption. That implies that repeater can't have its own
> -	 * display. As there is no consumption of encrypted content in the
> -	 * repeater with 0 downstream devices, we are failing the
> -	 * authentication.
> -	 */
> -	num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
> -	if (num_downstream == 0) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "Repeater with zero downstream devices\n");
> -		return -EINVAL;
> -	}
> -
> -	ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream,
> GFP_KERNEL);
> -	if (!ksv_fifo) {
> -		drm_dbg_kms(&dev_priv->drm, "Out of mem: ksv_fifo\n");
> -		return -ENOMEM;
> -	}
> -
> -	ret = shim->read_ksv_fifo(dig_port, num_downstream, ksv_fifo);
> -	if (ret)
> -		goto err;
> -
> -	if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, ksv_fifo,
> -					num_downstream) > 0) {
> -		drm_err(&dev_priv->drm, "Revoked Ksv(s) in ksv_fifo\n");
> -		ret = -EPERM;
> -		goto err;
> -	}
> +	enum transcoder cpu_transcoder = connector-
> >hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
> 
> -	/*
> -	 * When V prime mismatches, DP Spec mandates re-read of
> -	 * V prime atleast twice.
> -	 */
> -	for (i = 0; i < tries; i++) {
> -		ret = intel_hdcp_validate_v_prime(connector, shim,
> -						  ksv_fifo, num_downstream,
> -						  bstatus);
> -		if (!ret)
> -			break;
> -	}
> +	intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder,
> port),
> +		       ksv[0]);
> +	intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder,
> port),
> +		       ksv[1]);
> 
> -	if (i == tries) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "V Prime validation failed.(%d)\n", ret);
> -		goto err;
> -	}
> +	if (repeater_present)
> +		intel_de_write(dev_priv, HDCP_REP_CTL,
> +			       intel_hdcp_get_repeater_ctl(
> +				       dev_priv, cpu_transcoder, port));
> 
> -	drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (%d downstream
> devices)\n",
> -		    num_downstream);
> -	ret = 0;
> -err:
> -	kfree(ksv_fifo);
> -	return ret;
> +	return 0;
>  }
> 
> -/* Implements Part 1 of the HDCP authorization procedure */
> -static int intel_hdcp_auth(struct intel_connector *connector)
> +int intel_hdcp1_read_an(struct drm_connector *drm_connector,
> +			struct drm_hdcp_an *an)
>  {
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
>  	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	const struct intel_hdcp_shim *shim = hdcp->shim;
>  	enum transcoder cpu_transcoder = connector-
> >hdcp.cpu_transcoder;
>  	enum port port = dig_port->base.port;
> -	unsigned long r0_prime_gen_start;
> -	int ret, i, tries = 2;
> -	union {
> -		u32 reg[2];
> -		u8 shim[DRM_HDCP_AN_LEN];
> -	} an;
> -	union {
> -		u32 reg[2];
> -		u8 shim[DRM_HDCP_KSV_LEN];
> -	} bksv;
> -	union {
> -		u32 reg;
> -		u8 shim[DRM_HDCP_RI_LEN];
> -	} ri;
> -	bool repeater_present, hdcp_capable;
> -
> -	/*
> -	 * Detects whether the display is HDCP capable. Although we check
> for
> -	 * valid Bksv below, the HDCP over DP spec requires that we check
> -	 * whether the display supports HDCP before we write An. For HDMI
> -	 * displays, this is not necessary.
> -	 */
> -	if (shim->hdcp_capable) {
> -		ret = shim->hdcp_capable(dig_port, &hdcp_capable);
> -		if (ret)
> -			return ret;
> -		if (!hdcp_capable) {
> -			drm_dbg_kms(&dev_priv->drm,
> -				    "Panel is not HDCP capable\n");
> -			return -EINVAL;
> -		}
> -	}
> +	int i;
> 
>  	/* Initialize An with 2 random values and acquire it */
>  	for (i = 0; i < 2; i++)
> @@ -784,92 +635,81 @@ static int intel_hdcp_auth(struct intel_connector
> *connector)
>  		return -ETIMEDOUT;
>  	}
> 
> -	an.reg[0] = intel_de_read(dev_priv,
> -				  HDCP_ANLO(dev_priv, cpu_transcoder,
> port));
> -	an.reg[1] = intel_de_read(dev_priv,
> -				  HDCP_ANHI(dev_priv, cpu_transcoder,
> port));
> -	ret = shim->write_an_aksv(dig_port, an.shim);
> -	if (ret)
> -		return ret;
> +	an->words[0] = intel_de_read(dev_priv,
> +				     HDCP_ANLO(dev_priv, cpu_transcoder,
> port));
> +	an->words[1] = intel_de_read(dev_priv,
> +				     HDCP_ANHI(dev_priv, cpu_transcoder,
> port));
> 
> -	r0_prime_gen_start = jiffies;
> -
> -	memset(&bksv, 0, sizeof(bksv));
> -
> -	ret = intel_hdcp_read_valid_bksv(dig_port, shim, bksv.shim);
> -	if (ret < 0)
> -		return ret;
> -
> -	if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, bksv.shim, 1) >
> 0) {
> -		drm_err(&dev_priv->drm, "BKSV is revoked\n");
> -		return -EPERM;
> -	}
> -
> -	intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder,
> port),
> -		       bksv.reg[0]);
> -	intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder,
> port),
> -		       bksv.reg[1]);
> -
> -	ret = shim->repeater_present(dig_port, &repeater_present);
> -	if (ret)
> -		return ret;
> -	if (repeater_present)
> -		intel_de_write(dev_priv, HDCP_REP_CTL,
> -			       intel_hdcp_get_repeater_ctl(dev_priv,
> cpu_transcoder, port));
> +	return 0;
> +}
> 
> -	ret = shim->toggle_signalling(dig_port, cpu_transcoder, true);
> -	if (ret)
> -		return ret;
> +int intel_hdcp1_enable_encryption(struct drm_connector
> *drm_connector)
> +{
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	enum transcoder cpu_transcoder = connector-
> >hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
> 
>  	intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder,
> port),
>  		       HDCP_CONF_AUTH_AND_ENC);
> 
> +	return 0;
> +}
> +
> +int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector)
> +{
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	enum transcoder cpu_transcoder = connector-
> >hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
> +
>  	/* Wait for R0 ready */
> -	if (wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> cpu_transcoder, port)) &
> -		     (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), 1)) {
> +	if (wait_for((intel_de_read(dev_priv,
> +				    HDCP_STATUS(dev_priv, cpu_transcoder,
> +						port))) &
> +			     (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC),
> +		     1)) {

Alignment here seem wrong

>  		drm_err(&dev_priv->drm, "Timed out waiting for R0
> ready\n");
>  		return -ETIMEDOUT;
>  	}
> 
> -	/*
> -	 * Wait for R0' to become available. The spec says 100ms from Aksv,
> but
> -	 * some monitors can take longer than this. We'll set the timeout at
> -	 * 300ms just to be sure.
> -	 *
> -	 * On DP, there's an R0_READY bit available but no such bit
> -	 * exists on HDMI. Since the upper-bound is the same, we'll just do
> -	 * the stupid thing instead of polling on one and not the other.
> -	 */
> -	wait_remaining_ms_from_jiffies(r0_prime_gen_start, 300);
> -
> -	tries = 3;
> +	return 0;
> +}
> 
> -	/*
> -	 * DP HDCP Spec mandates the two more reattempt to read R0,
> incase
> -	 * of R0 mismatch.
> -	 */
> -	for (i = 0; i < tries; i++) {
> -		ri.reg = 0;
> -		ret = shim->read_ri_prime(dig_port, ri.shim);
> -		if (ret)
> -			return ret;
> -		intel_de_write(dev_priv,
> -			       HDCP_RPRIME(dev_priv, cpu_transcoder, port),
> -			       ri.reg);
> +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32
> ri_prime)
> +{
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	enum transcoder cpu_transcoder = connector-
> >hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
> 
> -		/* Wait for Ri prime match */
> -		if (!wait_for(intel_de_read(dev_priv,
> HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> -			      (HDCP_STATUS_RI_MATCH |
> HDCP_STATUS_ENC), 1))
> -			break;
> -	}
> +	intel_de_write(dev_priv, HDCP_RPRIME(dev_priv, cpu_transcoder,
> port),
> +		       ri_prime);
> 
> -	if (i == tries) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "Timed out waiting for Ri prime match (%x)\n",
> -			    intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> -					  cpu_transcoder, port)));
> +	/* Wait for Ri prime match */
> +	if (wait_for(intel_de_read(dev_priv,
> +				   HDCP_STATUS(dev_priv, cpu_transcoder,
> port)) &
> +			     (HDCP_STATUS_RI_MATCH |
> HDCP_STATUS_ENC),
> +		     1))
>  		return -ETIMEDOUT;
> -	}
> +
> +	return 0;
> +}
> +
> +int intel_hdcp1_post_encryption(struct drm_connector *drm_connector)
> +{
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	enum transcoder cpu_transcoder = connector-
> >hdcp.cpu_transcoder;
> +	enum port port = dig_port->base.port;
> 
>  	/* Wait for encryption confirmation */
>  	if (intel_de_wait_for_set(dev_priv,
> @@ -880,56 +720,22 @@ static int intel_hdcp_auth(struct intel_connector
> *connector)
>  		return -ETIMEDOUT;
>  	}
> 
> -	/* DP MST Auth Part 1 Step 2.a and Step 2.b */
> -	if (shim->stream_encryption) {
> -		ret = shim->stream_encryption(connector, true);
> -		if (ret) {
> -			drm_err(&dev_priv->drm, "[%s:%d] Failed to enable
> HDCP 1.4 stream enc\n",
> -				connector->base.name, connector-
> >base.base.id);
> -			return ret;
> -		}
> -		drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s
> stream encrypted\n",
> -			    transcoder_name(hdcp->stream_transcoder));
> -	}
> -
> -	if (repeater_present)
> -		return intel_hdcp_auth_downstream(connector);
> -
> -	drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (no repeater
> present)\n");
>  	return 0;
>  }
> 
> -static int _intel_hdcp_disable(struct intel_connector *connector)
> +int intel_hdcp1_disable(struct drm_connector *drm_connector)
>  {
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
>  	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
>  	enum port port = dig_port->base.port;
>  	enum transcoder cpu_transcoder = hdcp->cpu_transcoder;
>  	u32 repeater_ctl;
> -	int ret;
> 
>  	drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being
> disabled...\n",
>  		    connector->base.name, connector->base.base.id);
> 
> -	if (hdcp->shim->stream_encryption) {
> -		ret = hdcp->shim->stream_encryption(connector, false);
> -		if (ret) {
> -			drm_err(&dev_priv->drm, "[%s:%d] Failed to disable
> HDCP 1.4 stream enc\n",
> -				connector->base.name, connector-
> >base.base.id);
> -			return ret;
> -		}
> -		drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s
> stream encryption disabled\n",
> -			    transcoder_name(hdcp->stream_transcoder));
> -		/*
> -		 * If there are other connectors on this port using HDCP,
> -		 * don't disable it until it disabled HDCP encryption for
> -		 * all connectors in MST topology.
> -		 */
> -		if (dig_port->num_hdcp_streams > 0)
> -			return 0;
> -	}
> -
>  	hdcp->hdcp_encrypted = false;
>  	intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder,
> port), 0);
>  	if (intel_de_wait_for_clear(dev_priv,
> @@ -945,190 +751,9 @@ static int _intel_hdcp_disable(struct
> intel_connector *connector)
>  	intel_de_write(dev_priv, HDCP_REP_CTL,
>  		       intel_de_read(dev_priv, HDCP_REP_CTL) &
> ~repeater_ctl);
> 
> -	ret = hdcp->shim->toggle_signalling(dig_port, cpu_transcoder,
> false);
> -	if (ret) {
> -		drm_err(&dev_priv->drm, "Failed to disable HDCP
> signalling\n");
> -		return ret;
> -	}
> -
> -	drm_dbg_kms(&dev_priv->drm, "HDCP is disabled\n");
>  	return 0;
>  }
> 
> -static int _intel_hdcp_enable(struct intel_connector *connector)
> -{
> -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	int i, ret, tries = 3;
> -
> -	drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being
> enabled...\n",
> -		    connector->base.name, connector->base.base.id);
> -
> -	if (!hdcp_key_loadable(dev_priv)) {
> -		drm_err(&dev_priv->drm, "HDCP key Load is not
> possible\n");
> -		return -ENXIO;
> -	}
> -
> -	for (i = 0; i < KEY_LOAD_TRIES; i++) {
> -		ret = intel_hdcp_load_keys(dev_priv);
> -		if (!ret)
> -			break;
> -		intel_hdcp_clear_keys(dev_priv);
> -	}
> -	if (ret) {
> -		drm_err(&dev_priv->drm, "Could not load HDCP keys,
> (%d)\n",
> -			ret);
> -		return ret;
> -	}
> -
> -	/* Incase of authentication failures, HDCP spec expects reauth. */
> -	for (i = 0; i < tries; i++) {
> -		ret = intel_hdcp_auth(connector);
> -		if (!ret) {
> -			hdcp->hdcp_encrypted = true;
> -			return 0;
> -		}
> -
> -		drm_dbg_kms(&dev_priv->drm, "HDCP Auth failure (%d)\n",
> ret);
> -
> -		/* Ensuring HDCP encryption and signalling are stopped. */
> -		_intel_hdcp_disable(connector);
> -	}
> -
> -	drm_dbg_kms(&dev_priv->drm,
> -		    "HDCP authentication failed (%d tries/%d)\n", tries, ret);
> -	return ret;
> -}
> -
> -static struct intel_connector *intel_hdcp_to_connector(struct intel_hdcp
> *hdcp)
> -{
> -	return container_of(hdcp, struct intel_connector, hdcp);
> -}
> -
> -static void intel_hdcp_update_value(struct intel_connector *connector,
> -				    u64 value, bool update_property)
> -{
> -	struct drm_device *dev = connector->base.dev;
> -	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -
> -	drm_WARN_ON(connector->base.dev, !mutex_is_locked(&hdcp-
> >mutex));
> -
> -	if (hdcp->value == value)
> -		return;
> -
> -	drm_WARN_ON(dev, !mutex_is_locked(&dig_port->hdcp_mutex));
> -
> -	if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> -		if (!drm_WARN_ON(dev, dig_port->num_hdcp_streams ==
> 0))
> -			dig_port->num_hdcp_streams--;
> -	} else if (value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> -		dig_port->num_hdcp_streams++;
> -	}
> -
> -	hdcp->value = value;
> -	if (update_property) {
> -		drm_connector_get(&connector->base);
> -		schedule_work(&hdcp->prop_work);
> -	}
> -}
> -
> -/* Implements Part 3 of the HDCP authorization procedure */
> -static int intel_hdcp_check_link(struct intel_connector *connector)
> -{
> -	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
> -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	enum port port = dig_port->base.port;
> -	enum transcoder cpu_transcoder;
> -	int ret = 0;
> -
> -	mutex_lock(&hdcp->mutex);
> -	mutex_lock(&dig_port->hdcp_mutex);
> -
> -	cpu_transcoder = hdcp->cpu_transcoder;
> -
> -	/* Check_link valid only when HDCP1.4 is enabled */
> -	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED
> ||
> -	    !hdcp->hdcp_encrypted) {
> -		ret = -EINVAL;
> -		goto out;
> -	}
> -
> -	if (drm_WARN_ON(&dev_priv->drm,
> -			!intel_hdcp_in_use(dev_priv, cpu_transcoder,
> port))) {
> -		drm_err(&dev_priv->drm,
> -			"%s:%d HDCP link stopped encryption,%x\n",
> -			connector->base.name, connector->base.base.id,
> -			intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> cpu_transcoder, port)));
> -		ret = -ENXIO;
> -		intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_DESIRED,
> -					true);
> -		goto out;
> -	}
> -
> -	if (hdcp->shim->check_link(dig_port, connector)) {
> -		if (hdcp->value !=
> DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> -			intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_ENABLED, true);
> -		}
> -		goto out;
> -	}
> -
> -	drm_dbg_kms(&dev_priv->drm,
> -		    "[%s:%d] HDCP link failed, retrying authentication\n",
> -		    connector->base.name, connector->base.base.id);
> -
> -	ret = _intel_hdcp_disable(connector);
> -	if (ret) {
> -		drm_err(&dev_priv->drm, "Failed to disable hdcp (%d)\n",
> ret);
> -		intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_DESIRED,
> -					true);
> -		goto out;
> -	}
> -
> -	ret = _intel_hdcp_enable(connector);
> -	if (ret) {
> -		drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n",
> ret);
> -		intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_DESIRED,
> -					true);
> -		goto out;
> -	}
> -
> -out:
> -	mutex_unlock(&dig_port->hdcp_mutex);
> -	mutex_unlock(&hdcp->mutex);
> -	return ret;
> -}
> -
> -static void intel_hdcp_prop_work(struct work_struct *work)
> -{
> -	struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp,
> -					       prop_work);
> -	struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
> -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -
> -	drm_modeset_lock(&dev_priv-
> >drm.mode_config.connection_mutex, NULL);
> -	mutex_lock(&hdcp->mutex);
> -
> -	/*
> -	 * This worker is only used to flip between ENABLED/DESIRED. Either
> of
> -	 * those to UNDESIRED is handled by core. If value == UNDESIRED,
> -	 * we're running just after hdcp has been disabled, so just exit
> -	 */
> -	if (hdcp->value !=
> DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> -		drm_hdcp_update_content_protection(&connector->base,
> -						   hdcp->value);
> -
> -	mutex_unlock(&hdcp->mutex);
> -	drm_modeset_unlock(&dev_priv-
> >drm.mode_config.connection_mutex);
> -
> -	drm_connector_put(&connector->base);
> -}
> -
>  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port
> port)
>  {
>  	return RUNTIME_INFO(dev_priv)->has_hdcp &&
> @@ -1961,8 +1586,9 @@ static int hdcp2_authenticate_and_encrypt(struct
> intel_connector *connector)
>  	return ret;
>  }
> 
> -static int _intel_hdcp2_enable(struct intel_connector *connector)
> +int intel_hdcp2_enable(struct drm_connector *drm_connector)
>  {
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
>  	struct drm_i915_private *i915 = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
>  	int ret;
> @@ -2024,9 +1650,15 @@ _intel_hdcp2_disable(struct intel_connector
> *connector, bool hdcp2_link_recovery
>  	return ret;
>  }
> 
> +int intel_hdcp2_disable(struct drm_connector *drm_connector)
> +{
> +	return _intel_hdcp2_disable(to_intel_connector(drm_connector),
> false);
> +}
> +
>  /* Implements the Link Integrity Check for HDCP2.2 */
> -static int intel_hdcp2_check_link(struct intel_connector *connector)
> +int intel_hdcp2_check_link(struct drm_connector *drm_connector)
>  {
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
>  	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
> @@ -2034,109 +1666,39 @@ static int intel_hdcp2_check_link(struct
> intel_connector *connector)
>  	enum transcoder cpu_transcoder;
>  	int ret = 0;
> 
> -	mutex_lock(&hdcp->mutex);
> -	mutex_lock(&dig_port->hdcp_mutex);
>  	cpu_transcoder = hdcp->cpu_transcoder;
> 
>  	/* hdcp2_check_link is expected only when HDCP2.2 is Enabled */
> -	if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED
> ||
> -	    !hdcp->hdcp2_encrypted) {
> -		ret = -EINVAL;
> -		goto out;
> -	}
> +	if (!hdcp->hdcp2_encrypted)
> +		return -EINVAL;
> 
>  	if (drm_WARN_ON(&dev_priv->drm,
>  			!intel_hdcp2_in_use(dev_priv, cpu_transcoder,
> port))) {
>  		drm_err(&dev_priv->drm,
>  			"HDCP2.2 link stopped the encryption, %x\n",
>  			intel_de_read(dev_priv, HDCP2_STATUS(dev_priv,
> cpu_transcoder, port)));
> -		ret = -ENXIO;
> -		_intel_hdcp2_disable(connector, true);
> -		intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_DESIRED,
> -					true);
> -		goto out;
> +		return -ENXIO;
>  	}
> 
>  	ret = hdcp->shim->check_2_2_link(dig_port, connector);
> -	if (ret == HDCP_LINK_PROTECTED) {
> -		if (hdcp->value !=
> DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> -			intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_ENABLED,
> -					true);
> -		}
> -		goto out;
> -	}
> +	if (ret == HDCP_LINK_PROTECTED)
> +		return 0;
> 
>  	if (ret == HDCP_TOPOLOGY_CHANGE) {
> -		if (hdcp->value ==
> DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> -			goto out;
> -
>  		drm_dbg_kms(&dev_priv->drm,
>  			    "HDCP2.2 Downstream topology change\n");
>  		ret = hdcp2_authenticate_repeater_topology(connector);
> -		if (!ret) {
> -			intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_ENABLED,
> -					true);
> -			goto out;
> -		}
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "[%s:%d] Repeater topology auth failed.(%d)\n",
> -			    connector->base.name, connector->base.base.id,
> -			    ret);
> -	} else {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "[%s:%d] HDCP2.2 link failed, retrying auth\n",
> -			    connector->base.name, connector->base.base.id);
> -	}
> -
> -	ret = _intel_hdcp2_disable(connector, true);
> -	if (ret) {
> -		drm_err(&dev_priv->drm,
> -			"[%s:%d] Failed to disable hdcp2.2 (%d)\n",
> -			connector->base.name, connector->base.base.id,
> ret);
> -		intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
> -		goto out;
> -	}
> +		if (!ret)
> +			return 0;
> 
> -	ret = _intel_hdcp2_enable(connector);
> -	if (ret) {
>  		drm_dbg_kms(&dev_priv->drm,
> -			    "[%s:%d] Failed to enable hdcp2.2 (%d)\n",
> -			    connector->base.name, connector->base.base.id,
> -			    ret);
> -		intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_DESIRED,
> -					true);
> -		goto out;
> +			    "[%s:%d] Repeater topology auth failed.(%d)\n",
> +			    connector->base.name, connector->base.base.id,
> ret);
>  	}
> 
> -out:
> -	mutex_unlock(&dig_port->hdcp_mutex);
> -	mutex_unlock(&hdcp->mutex);
>  	return ret;
>  }

Wouldn't it be better if we used that value in drm_hdcp_helper_data rather than getting rid of all these checks
As they are needed same thing for other places where the checks are removed because value isn't present in 
Intel_hdcp structure

> 
> -static void intel_hdcp_check_work(struct work_struct *work)
> -{
> -	struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
> -					       struct intel_hdcp,
> -					       check_work);
> -	struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
> -
> -	if (drm_connector_is_unregistered(&connector->base))
> -		return;
> -
> -	if (!intel_hdcp2_check_link(connector))
> -		schedule_delayed_work(&hdcp->check_work,
> -				      DRM_HDCP2_CHECK_PERIOD_MS);
> -	else if (!intel_hdcp_check_link(connector))
> -		schedule_delayed_work(&hdcp->check_work,
> -				      DRM_HDCP_CHECK_PERIOD_MS);
> -}
> -
>  static int i915_hdcp_component_bind(struct device *i915_kdev,
>  				    struct device *mei_kdev, void *data)
>  {
> @@ -2189,22 +1751,28 @@ static enum mei_fw_tc
> intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
>  	}
>  }
> 
> -static int
> -_intel_hdcp_setup(struct intel_connector *connector,
> -		  const struct intel_crtc_state *pipe_config, u8 content_type)
> +int intel_hdcp_setup(struct drm_connector *connector,
> +		     struct drm_atomic_state *state)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> +	struct drm_i915_private *dev_priv = to_i915(connector->dev);
> +	struct intel_connector *intel_connector =
> to_intel_connector(connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(intel_connector);
> +	struct drm_connector_state *conn_state;
> +	struct drm_crtc_state *crtc_state;
> +	struct intel_crtc_state *pipe_config;
> +	struct intel_hdcp *hdcp = &intel_connector->hdcp;
>  	int ret = 0;
> 
> -	if (!connector->encoder) {
> +	if (!intel_connector->encoder) {
>  		drm_err(&dev_priv->drm, "[%s:%d] encoder is not
> initialized\n",
> -			connector->base.name, connector->base.base.id);
> +			connector->name, connector->base.id);
>  		return -ENODEV;
>  	}
> 
> -	hdcp->content_type = content_type;
> +	conn_state = drm_atomic_get_new_connector_state(state,
> connector);
> +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state-
> >crtc);
> +	pipe_config = to_intel_crtc_state(crtc_state);
> 
>  	if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
>  		hdcp->cpu_transcoder = pipe_config-
> >mst_master_transcoder;
> @@ -2321,7 +1889,6 @@ int intel_hdcp_init(struct intel_connector
> *connector,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_hdcp *hdcp = &connector->hdcp;
> -	int ret;
> 
>  	if (!shim)
>  		return -EINVAL;
> @@ -2329,174 +1896,12 @@ int intel_hdcp_init(struct intel_connector
> *connector,
>  	if (is_hdcp2_supported(dev_priv))
>  		intel_hdcp2_init(connector, dig_port, shim);
> 
> -	ret =
> -	drm_connector_attach_content_protection_property(&connector-
> >base,
> -							 hdcp-
> >hdcp2_supported);
> -	if (ret) {
> -		hdcp->hdcp2_supported = false;
> -		kfree(dig_port->hdcp_port_data.streams);
> -		return ret;
> -	}
> -
>  	hdcp->shim = shim;
> -	mutex_init(&hdcp->mutex);

I don't think removing mutex is a good idea

Regards,
Suraj Kandpal
> -	INIT_DELAYED_WORK(&hdcp->check_work,
> intel_hdcp_check_work);
> -	INIT_WORK(&hdcp->prop_work, intel_hdcp_prop_work);
>  	init_waitqueue_head(&hdcp->cp_irq_queue);
> 
>  	return 0;
>  }
> 
> -int intel_hdcp_enable(struct intel_connector *connector,
> -		      const struct intel_crtc_state *pipe_config, u8
> content_type)
> -{
> -	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> -	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	unsigned long check_link_interval =
> DRM_HDCP_CHECK_PERIOD_MS;
> -	bool capable;
> -	int ret = -EINVAL;
> -
> -	if (!hdcp->shim)
> -		return -ENOENT;
> -
> -	mutex_lock(&hdcp->mutex);
> -	mutex_lock(&dig_port->hdcp_mutex);
> -	drm_WARN_ON(&dev_priv->drm,
> -		    hdcp->value ==
> DRM_MODE_CONTENT_PROTECTION_ENABLED);
> -
> -	ret = _intel_hdcp_setup(connector, pipe_config, content_type);
> -	if (ret)
> -		goto out;
> -
> -	/*
> -	 * Considering that HDCP2.2 is more secure than HDCP1.4, If the
> setup
> -	 * is capable of HDCP2.2, it is preferred to use HDCP2.2.
> -	 */
> -	ret = intel_hdcp2_capable(connector, &capable);
> -	if (capable) {
> -		ret = _intel_hdcp2_enable(connector);
> -		if (!ret) {
> -			check_link_interval =
> DRM_HDCP2_CHECK_PERIOD_MS;
> -			goto out;
> -		}
> -	}
> -
> -	/*
> -	 * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
> -	 * be attempted.
> -	 */
> -	ret = intel_hdcp_capable(connector, &capable);
> -	if (ret)
> -		goto out;
> -
> -	if (capable && hdcp->content_type !=
> DRM_MODE_HDCP_CONTENT_TYPE1)
> -		ret = _intel_hdcp_enable(connector);
> -
> -out:
> -	if (!ret) {
> -		schedule_delayed_work(&hdcp->check_work,
> check_link_interval);
> -		intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_ENABLED,
> -					true);
> -	}
> -
> -	mutex_unlock(&dig_port->hdcp_mutex);
> -	mutex_unlock(&hdcp->mutex);
> -	return ret;
> -}
> -
> -int intel_hdcp_disable(struct intel_connector *connector)
> -{
> -	struct intel_digital_port *dig_port =
> intel_attached_dig_port(connector);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	int ret = 0;
> -
> -	if (!hdcp->shim)
> -		return -ENOENT;
> -
> -	mutex_lock(&hdcp->mutex);
> -	mutex_lock(&dig_port->hdcp_mutex);
> -
> -	if (hdcp->value ==
> DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> -		goto out;
> -
> -	intel_hdcp_update_value(connector,
> -
> 	DRM_MODE_CONTENT_PROTECTION_UNDESIRED, false);
> -	if (hdcp->hdcp2_encrypted)
> -		ret = _intel_hdcp2_disable(connector, false);
> -	else if (hdcp->hdcp_encrypted)
> -		ret = _intel_hdcp_disable(connector);
> -
> -out:
> -	mutex_unlock(&dig_port->hdcp_mutex);
> -	mutex_unlock(&hdcp->mutex);
> -	cancel_delayed_work_sync(&hdcp->check_work);
> -	return ret;
> -}
> -
> -void intel_hdcp_update_pipe(struct intel_atomic_state *state,
> -			    struct intel_encoder *encoder,
> -			    const struct intel_crtc_state *crtc_state,
> -			    const struct drm_connector_state *conn_state)
> -{
> -	struct intel_connector *connector =
> -				to_intel_connector(conn_state->connector);
> -	struct intel_hdcp *hdcp = &connector->hdcp;
> -	bool content_protection_type_changed, desired_and_not_enabled
> = false;
> -
> -	if (!connector->hdcp.shim)
> -		return;
> -
> -	content_protection_type_changed =
> -		(conn_state->hdcp_content_type != hdcp->content_type
> &&
> -		 conn_state->content_protection !=
> -		 DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
> -
> -	/*
> -	 * During the HDCP encryption session if Type change is requested,
> -	 * disable the HDCP and reenable it with new TYPE value.
> -	 */
> -	if (conn_state->content_protection ==
> -	    DRM_MODE_CONTENT_PROTECTION_UNDESIRED ||
> -	    content_protection_type_changed)
> -		intel_hdcp_disable(connector);
> -
> -	/*
> -	 * Mark the hdcp state as DESIRED after the hdcp disable of type
> -	 * change procedure.
> -	 */
> -	if (content_protection_type_changed) {
> -		mutex_lock(&hdcp->mutex);
> -		hdcp->value =
> DRM_MODE_CONTENT_PROTECTION_DESIRED;
> -		drm_connector_get(&connector->base);
> -		schedule_work(&hdcp->prop_work);
> -		mutex_unlock(&hdcp->mutex);
> -	}
> -
> -	if (conn_state->content_protection ==
> -	    DRM_MODE_CONTENT_PROTECTION_DESIRED) {
> -		mutex_lock(&hdcp->mutex);
> -		/* Avoid enabling hdcp, if it already ENABLED */
> -		desired_and_not_enabled =
> -			hdcp->value !=
> DRM_MODE_CONTENT_PROTECTION_ENABLED;
> -		mutex_unlock(&hdcp->mutex);
> -		/*
> -		 * If HDCP already ENABLED and CP property is DESIRED,
> schedule
> -		 * prop_work to update correct CP property to user space.
> -		 */
> -		if (!desired_and_not_enabled &&
> !content_protection_type_changed) {
> -			drm_connector_get(&connector->base);
> -			schedule_work(&hdcp->prop_work);
> -		}
> -	}
> -
> -	if (desired_and_not_enabled || content_protection_type_changed)
> -		intel_hdcp_enable(connector,
> -				  crtc_state,
> -				  (u8)conn_state->hdcp_content_type);
> -}
> -
>  void intel_hdcp_component_fini(struct drm_i915_private *dev_priv)
>  {
>  	mutex_lock(&dev_priv->display.hdcp.comp_mutex);
> @@ -2518,33 +1923,8 @@ void intel_hdcp_cleanup(struct intel_connector
> *connector)
>  	if (!hdcp->shim)
>  		return;
> 
> -	/*
> -	 * If the connector is registered, it's possible userspace could kick
> -	 * off another HDCP enable, which would re-spawn the workers.
> -	 */
> -	drm_WARN_ON(connector->base.dev,
> -		connector->base.registration_state ==
> DRM_CONNECTOR_REGISTERED);
> -
> -	/*
> -	 * Now that the connector is not registered, check_work won't be
> run,
> -	 * but cancel any outstanding instances of it
> -	 */
> -	cancel_delayed_work_sync(&hdcp->check_work);
> -
> -	/*
> -	 * We don't cancel prop_work in the same way as check_work since it
> -	 * requires connection_mutex which could be held while calling this
> -	 * function. Instead, we rely on the connector references grabbed
> before
> -	 * scheduling prop_work to ensure the connector is alive when
> prop_work
> -	 * is run. So if we're in the destroy path (which is where this
> -	 * function should be called), we're "guaranteed" that prop_work is
> not
> -	 * active (tl;dr This Should Never Happen).
> -	 */
> -	drm_WARN_ON(connector->base.dev, work_pending(&hdcp-
> >prop_work));
> -
> -	mutex_lock(&hdcp->mutex);
> +	drm_hdcp_helper_destroy(connector->hdcp_helper_data);
>  	hdcp->shim = NULL;
> -	mutex_unlock(&hdcp->mutex);
>  }
> 
>  /* Handles the CP_IRQ raised from the DP HDCP sink */
> @@ -2558,5 +1938,5 @@ void intel_hdcp_handle_cp_irq(struct
> intel_connector *connector)
>  	atomic_inc(&connector->hdcp.cp_irq_count);
>  	wake_up_all(&connector->hdcp.cp_irq_queue);
> 
> -	schedule_delayed_work(&hdcp->check_work, 0);
> +	drm_hdcp_helper_schedule_hdcp_check(connector-
> >hdcp_helper_data);
>  }
> diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h
> b/drivers/gpu/drm/i915/display/intel_hdcp.h
> index f06f6e5a2b1a..49b9d79eb30a 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdcp.h
> +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
> @@ -10,8 +10,10 @@
> 
>  #define HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS	50
> 
> +struct drm_atomic_state;
>  struct drm_connector;
>  struct drm_connector_state;
> +struct drm_hdcp_an;
>  struct drm_i915_private;
>  struct intel_atomic_state;
>  struct intel_connector;
> @@ -25,16 +27,29 @@ enum transcoder;
>  int intel_hdcp_init(struct intel_connector *connector,
>  		    struct intel_digital_port *dig_port,
>  		    const struct intel_hdcp_shim *hdcp_shim);
> -int intel_hdcp_enable(struct intel_connector *connector,
> -		      const struct intel_crtc_state *pipe_config, u8
> content_type);
> -int intel_hdcp_disable(struct intel_connector *connector);
> -void intel_hdcp_update_pipe(struct intel_atomic_state *state,
> -			    struct intel_encoder *encoder,
> -			    const struct intel_crtc_state *crtc_state,
> -			    const struct drm_connector_state *conn_state);
> +int intel_hdcp_setup(struct drm_connector *drm_connector,
> +		     struct drm_atomic_state *state);
> +int intel_hdcp_load_keys(struct drm_connector *drm_connector);
>  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port
> port);
>  int intel_hdcp_capable(struct intel_connector *connector, bool *capable);
> -int intel_hdcp2_capable(struct intel_connector *connector, bool *capable);
> +int intel_hdcp2_capable(struct drm_connector *drm_connector, bool
> *capable);
> +int intel_hdcp2_enable(struct drm_connector *drm_connector);
> +int intel_hdcp2_disable(struct drm_connector *drm_connector);
> +int intel_hdcp2_check_link(struct drm_connector *drm_connector);
> +int intel_hdcp1_store_receiver_info(struct drm_connector
> *drm_connector,
> +				    u32 *ksv, u32 status, u8 caps,
> +				    bool repeater_present);
> +int intel_hdcp1_read_an(struct drm_connector *drm_connector,
> +			struct drm_hdcp_an *an);
> +int intel_hdcp1_enable_encryption(struct drm_connector
> *drm_connector);
> +int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector);
> +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32
> ri_prime);
> +int intel_hdcp1_post_encryption(struct drm_connector *drm_connector);
> +int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
> +			       u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
> +			       u32 *v_prime);
> +int intel_hdcp1_check_link(struct drm_connector *drm_connector);
> +int intel_hdcp1_disable(struct drm_connector *drm_connector);
>  void intel_hdcp_component_init(struct drm_i915_private *dev_priv);
>  void intel_hdcp_component_fini(struct drm_i915_private *dev_priv);
>  void intel_hdcp_cleanup(struct intel_connector *connector);
> diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c
> b/drivers/gpu/drm/i915/display/intel_hdmi.c
> index 7816b2a33fee..c33cfedb2e19 100644
> --- a/drivers/gpu/drm/i915/display/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
> @@ -1324,17 +1324,24 @@ static int intel_hdmi_hdcp_write(struct
> intel_digital_port *dig_port,
>  	return ret;
>  }
> 
> -static
> -int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> -				  u8 *an)
> +static int intel_hdmi_hdcp1_send_an_aksv(struct drm_connector
> *drm_connector)
>  {
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
>  	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
>  	struct intel_hdmi *hdmi = &dig_port->hdmi;
>  	struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915,
>  							      hdmi->ddc_bus);
> +	struct drm_hdcp_an an;
>  	int ret;
> 
> -	ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an,
> +	/* Output An first, that's easy */
> +	ret = intel_hdcp1_read_an(drm_connector, &an);
> +	if (ret)
> +		return ret;
> +
> +	ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN,
> an.bytes,
>  				    DRM_HDCP_AN_LEN);
>  	if (ret) {
>  		drm_dbg_kms(&i915->drm, "Write An over DDC failed
> (%d)\n",
> @@ -1350,120 +1357,6 @@ int intel_hdmi_hdcp_write_an_aksv(struct
> intel_digital_port *dig_port,
>  	return 0;
>  }
> 
> -static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *dig_port,
> -				     u8 *bksv)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -
> -	int ret;
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BKSV, bksv,
> -				   DRM_HDCP_KSV_LEN);
> -	if (ret)
> -		drm_dbg_kms(&i915->drm, "Read Bksv over DDC failed
> (%d)\n",
> -			    ret);
> -	return ret;
> -}
> -
> -static
> -int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *dig_port,
> -				 u8 *bstatus)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -
> -	int ret;
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BSTATUS,
> -				   bstatus, DRM_HDCP_BSTATUS_LEN);
> -	if (ret)
> -		drm_dbg_kms(&i915->drm, "Read bstatus over DDC failed
> (%d)\n",
> -			    ret);
> -	return ret;
> -}
> -
> -static
> -int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *dig_port,
> -				     bool *repeater_present)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int ret;
> -	u8 val;
> -
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS,
> &val, 1);
> -	if (ret) {
> -		drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed
> (%d)\n",
> -			    ret);
> -		return ret;
> -	}
> -	*repeater_present = val &
> DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
> -	return 0;
> -}
> -
> -static
> -int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
> -				  u8 *ri_prime)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -
> -	int ret;
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_RI_PRIME,
> -				   ri_prime, DRM_HDCP_RI_LEN);
> -	if (ret)
> -		drm_dbg_kms(&i915->drm, "Read Ri' over DDC failed
> (%d)\n",
> -			    ret);
> -	return ret;
> -}
> -
> -static
> -int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
> -				   bool *ksv_ready)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int ret;
> -	u8 val;
> -
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS,
> &val, 1);
> -	if (ret) {
> -		drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed
> (%d)\n",
> -			    ret);
> -		return ret;
> -	}
> -	*ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
> -	return 0;
> -}
> -
> -static
> -int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
> -				  int num_downstream, u8 *ksv_fifo)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int ret;
> -	ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_KSV_FIFO,
> -				   ksv_fifo, num_downstream *
> DRM_HDCP_KSV_LEN);
> -	if (ret) {
> -		drm_dbg_kms(&i915->drm,
> -			    "Read ksv fifo over DDC failed (%d)\n", ret);
> -		return ret;
> -	}
> -	return 0;
> -}
> -
> -static
> -int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port
> *dig_port,
> -				      int i, u32 *part)
> -{
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int ret;
> -
> -	if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
> -		return -EINVAL;
> -
> -	ret = intel_hdmi_hdcp_read(dig_port,
> DRM_HDCP_DDC_V_PRIME(i),
> -				   part, DRM_HDCP_V_PRIME_PART_LEN);
> -	if (ret)
> -		drm_dbg_kms(&i915->drm, "Read V'[%d] over DDC failed
> (%d)\n",
> -			    i, ret);
> -	return ret;
> -}
> -
>  static int kbl_repositioning_enc_en_signal(struct intel_connector
> *connector,
>  					   enum transcoder cpu_transcoder)
>  {
> @@ -1532,50 +1425,40 @@ int intel_hdmi_hdcp_toggle_signalling(struct
> intel_digital_port *dig_port,
>  	return 0;
>  }
> 
> -static
> -bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port,
> -				     struct intel_connector *connector)
> +static int
> +intel_hdmi_hdcp1_enable_encryption(struct drm_connector
> *drm_connector)
>  {
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	enum port port = dig_port->base.port;
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
>  	enum transcoder cpu_transcoder = connector-
> >hdcp.cpu_transcoder;
>  	int ret;
> -	union {
> -		u32 reg;
> -		u8 shim[DRM_HDCP_RI_LEN];
> -	} ri;
> 
> -	ret = intel_hdmi_hdcp_read_ri_prime(dig_port, ri.shim);
> +	ret = intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder,
> true);
>  	if (ret)
> -		return false;
> -
> -	intel_de_write(i915, HDCP_RPRIME(i915, cpu_transcoder, port),
> ri.reg);
> +		return ret;
> 
> -	/* Wait for Ri prime match */
> -	if (wait_for((intel_de_read(i915, HDCP_STATUS(i915,
> cpu_transcoder, port)) &
> -		      (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC)) ==
> -		     (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
> -		drm_dbg_kms(&i915->drm, "Ri' mismatch detected (%x)\n",
> -			intel_de_read(i915, HDCP_STATUS(i915,
> cpu_transcoder,
> -							port)));
> -		return false;
> -	}
> -	return true;
> +	return intel_hdcp1_enable_encryption(drm_connector);
>  }
> 
> -static
> -bool intel_hdmi_hdcp_check_link(struct intel_digital_port *dig_port,
> -				struct intel_connector *connector)
> +static int intel_hdmi_hdcp1_disable(struct drm_connector
> *drm_connector)
>  {
> -	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> -	int retry;
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
> +	enum transcoder cpu_transcoder = connector-
> >hdcp.cpu_transcoder;
> +	struct drm_i915_private *i915 = to_i915(connector->base.dev);
> +	int ret;
> 
> -	for (retry = 0; retry < 3; retry++)
> -		if (intel_hdmi_hdcp_check_link_once(dig_port, connector))
> -			return true;
> +	ret = intel_hdcp1_disable(drm_connector);
> +	if (ret) {
> +		drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 1.4\n",
> +			connector->base.name, connector->base.base.id);
> +		return ret;
> +	}
> 
> -	drm_err(&i915->drm, "Link check failed\n");
> -	return false;
> +	return intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder,
> +						 false);
>  }
> 
>  struct hdcp2_hdmi_msg_timeout {
> @@ -1718,9 +1601,8 @@ int intel_hdmi_hdcp2_read_msg(struct
> intel_digital_port *dig_port,
>  	return ret;
>  }
> 
> -static
> -int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
> -				struct intel_connector *connector)
> +static int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
> +				       struct intel_connector *connector)
>  {
>  	u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
>  	int ret;
> @@ -1741,13 +1623,19 @@ int intel_hdmi_hdcp2_check_link(struct
> intel_digital_port *dig_port,
>  	return ret;
>  }
> 
> -static
> -int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
> -			     bool *capable)
> +static int intel_hdmi_hdcp2_capable(struct drm_connector
> *drm_connector,
> +				    bool *capable)
>  {
> +	struct intel_connector *connector =
> to_intel_connector(drm_connector);
> +	struct intel_digital_port *dig_port =
> +		intel_attached_dig_port(connector);
>  	u8 hdcp2_version;
>  	int ret;
> 
> +	ret = intel_hdcp2_capable(drm_connector, capable);
> +	if (ret || !capable)
> +		return ret;
> +
>  	*capable = false;
>  	ret = intel_hdmi_hdcp_read(dig_port,
> HDCP_2_2_HDMI_REG_VER_OFFSET,
>  				   &hdcp2_version, sizeof(hdcp2_version));
> @@ -1758,23 +1646,30 @@ int intel_hdmi_hdcp2_capable(struct
> intel_digital_port *dig_port,
>  }
> 
>  static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
> -	.write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
> -	.read_bksv = intel_hdmi_hdcp_read_bksv,
> -	.read_bstatus = intel_hdmi_hdcp_read_bstatus,
> -	.repeater_present = intel_hdmi_hdcp_repeater_present,
> -	.read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
> -	.read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
> -	.read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
> -	.read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
>  	.toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
> -	.check_link = intel_hdmi_hdcp_check_link,
>  	.write_2_2_msg = intel_hdmi_hdcp2_write_msg,
>  	.read_2_2_msg = intel_hdmi_hdcp2_read_msg,
> -	.check_2_2_link	= intel_hdmi_hdcp2_check_link,
> -	.hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
> +	.check_2_2_link = intel_hdmi_hdcp2_check_link,
>  	.protocol = HDCP_PROTOCOL_HDMI,
>  };
> 
> +static const struct drm_hdcp_helper_funcs intel_hdmi_hdcp_helper_funcs
> = {
> +	.setup = intel_hdcp_setup,
> +	.load_keys = intel_hdcp_load_keys,
> +	.hdcp2_capable = intel_hdmi_hdcp2_capable,
> +	.hdcp2_enable = intel_hdcp2_enable,
> +	.hdcp2_check_link = intel_hdcp2_check_link,
> +	.hdcp2_disable = intel_hdcp2_disable,
> +	.hdcp1_send_an_aksv = intel_hdmi_hdcp1_send_an_aksv,
> +	.hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> +	.hdcp1_enable_encryption = intel_hdmi_hdcp1_enable_encryption,
> +	.hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> +	.hdcp1_match_ri = intel_hdcp1_match_ri,
> +	.hdcp1_post_encryption = intel_hdcp1_post_encryption,
> +	.hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> +	.hdcp1_disable = intel_hdmi_hdcp1_disable,
> +};
> +
>  static int intel_hdmi_source_max_tmds_clock(struct intel_encoder
> *encoder)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> @@ -2922,6 +2817,37 @@ void intel_infoframe_init(struct intel_digital_port
> *dig_port)
>  	}
>  }
> 
> +static void intel_hdmi_hdcp_init(struct intel_digital_port *dig_port,
> +				 struct intel_connector *connector)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct intel_encoder *intel_encoder = &dig_port->base;
> +	enum port port = intel_encoder->port;
> +	struct drm_hdcp_helper_data *data;
> +	int ret;
> +
> +	if (!is_hdcp_supported(dev_priv, port))
> +		return;
> +
> +	data = drm_hdcp_helper_initialize_hdmi(
> +		&connector->base, &intel_hdmi_hdcp_helper_funcs, true);
> +	if (IS_ERR(data)) {
> +		drm_dbg_kms(&dev_priv->drm, "HDCP init failed
> ret=%ld\n",
> +			    PTR_ERR(data));
> +		return;
> +	}
> +
> +	ret = intel_hdcp_init(connector, dig_port, &intel_hdmi_hdcp_shim);
> +	if (ret) {
> +		drm_hdcp_helper_destroy(data);
> +		drm_dbg_kms(&dev_priv->drm, "Intel HDCP init failed
> ret=%d\n",
> +			    ret);
> +		return;
> +	}
> +
> +	connector->hdcp_helper_data = data;
> +}
> +
>  void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
>  			       struct intel_connector *intel_connector)
>  {
> @@ -2975,13 +2901,7 @@ void intel_hdmi_init_connector(struct
> intel_digital_port *dig_port,
>  	intel_connector_attach_encoder(intel_connector, intel_encoder);
>  	intel_hdmi->attached_connector = intel_connector;
> 
> -	if (is_hdcp_supported(dev_priv, port)) {
> -		int ret = intel_hdcp_init(intel_connector, dig_port,
> -					  &intel_hdmi_hdcp_shim);
> -		if (ret)
> -			drm_dbg_kms(&dev_priv->drm,
> -				    "HDCP init failed, skipping.\n");
> -	}
> +	intel_hdmi_hdcp_init(dig_port, intel_connector);
> 
>  	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be
> written
>  	 * 0xd.  Failure to do so will result in spurious interrupts being
> --
> 2.39.0.246.g2a6d74b583-goog


^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes
  2023-03-10  8:25   ` Kandpal, Suraj
@ 2023-03-23  7:17     ` Kandpal, Suraj
  2023-03-24 19:27       ` Mark Yacoub
  0 siblings, 1 reply; 38+ messages in thread
From: Kandpal, Suraj @ 2023-03-23  7:17 UTC (permalink / raw)
  To: Mark Yacoub, quic_khsieh, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, intel-gfx
  Cc: quic_sbillaka, konrad.dybcio, Souza, Jose, bjorn.andersson,
	krzysztof.kozlowski+dt, hbh25y, Vasut, Marek, Dixit, Ashutosh,
	sean, abhinavk, javierm, Murthy, Arun R, Lisovskiy, Stanislav,
	agross, quic_jesszhan, Nautiyal, Ankit K, Nikula, Jani,
	De Marchi, Lucas, quic_abhinavk, swboyd, robh+dt,
	christophe.jaillet, maxime, Vivi, Rodrigo, johan+linaro,
	tvrtko.ursulin, andersson, dianders, Sharma, Swati2, 'Navare,
	Manasi D',
	tzimmermann, Modem, Bhanuprakash, dmitry.baryshkov, seanpaul



> -----Original Message-----
> From: Kandpal, Suraj
> Sent: Friday, March 10, 2023 1:55 PM
> To: Mark Yacoub <markyacoub@chromium.org>; quic_khsieh@quicinc.com;
> linux-arm-msm@vger.kernel.org; dri-devel@lists.freedesktop.org;
> freedreno@lists.freedesktop.org; devicetree@vger.kernel.org; linux-
> kernel@vger.kernel.org; intel-gfx@lists.freedesktop.org
> Cc: quic_sbillaka@quicinc.com; konrad.dybcio@somainline.org; Souza, Jose
> <jose.souza@intel.com>; bjorn.andersson@linaro.org;
> krzysztof.kozlowski+dt@linaro.org; hbh25y@gmail.com; Vasut, Marek
> <marex@denx.de>; Dixit, Ashutosh <ashutosh.dixit@intel.com>;
> sean@poorly.run; abhinavk@codeaurora.org; javierm@redhat.com; Murthy,
> Arun R <arun.r.murthy@intel.com>; Lisovskiy, Stanislav
> <Stanislav.Lisovskiy@intel.com>; agross@kernel.org;
> quic_jesszhan@quicinc.com; Nautiyal, Ankit K <ankit.k.nautiyal@intel.com>;
> Nikula, Jani <jani.nikula@intel.com>; De Marchi, Lucas
> <lucas.demarchi@intel.com>; quic_abhinavk@quicinc.com;
> swboyd@chromium.org; robh+dt@kernel.org;
> christophe.jaillet@wanadoo.fr; maxime@cerno.tech; Vivi, Rodrigo
> <rodrigo.vivi@intel.com>; johan+linaro@kernel.org;
> tvrtko.ursulin@linux.intel.com; andersson@kernel.org;
> dianders@chromium.org; Sharma, Swati2 <swati2.sharma@intel.com>;
> Navare, Manasi D <manasi.d.navare@intel.com>; tzimmermann@suse.de;
> Modem, Bhanuprakash <Bhanuprakash.Modem@intel.com>;
> dmitry.baryshkov@linaro.org; seanpaul@chromium.org
> Subject: RE: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return
> codes
> 
> > Subject: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return
> > codes
> >
> > From: Sean Paul <seanpaul@chromium.org>
> >
> > The shim functions return error codes, but they are discarded in
> > intel_hdcp.c. This patch plumbs the return codes through so they are
> > properly handled.
> >
> > Acked-by: Jani Nikula <jani.nikula@intel.com>
> > Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> > Link:
> > https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-7-
> > sean@poorly.run #v1
> > Link:
> > https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-7-
> > sean@poorly.run #v2
> > Link:
> > https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-7-
> > sean@poorly.run #v3
> > Link:
> >
> https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
> > 7-sean@poorly.run #v4
> > Link:
> >
> https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
> > 7-sean@poorly.run #v5
> >
> > Changes in v2:
> > -None
> > Changes in v3:
> > -None
> > Changes in v4:
> > -None
> > Changes in v5:
> > -None
> > Changes in v6:
> > -Rebased
> >
> > ---
> >  .../drm/i915/display/intel_display_debugfs.c  |  9 +++-
> >  drivers/gpu/drm/i915/display/intel_hdcp.c     | 51 ++++++++++---------
> >  drivers/gpu/drm/i915/display/intel_hdcp.h     |  4 +-
> >  3 files changed, 37 insertions(+), 27 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > index 7c7253a2541c..13a4153bb76e 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > @@ -492,6 +492,7 @@ static void intel_panel_info(struct seq_file *m,
> > static void intel_hdcp_info(struct seq_file *m,
> >  			    struct intel_connector *intel_connector)  {
> > +	int ret;
> >  	bool hdcp_cap, hdcp2_cap;
> >
> >  	if (!intel_connector->hdcp.shim) {
> > @@ -499,8 +500,12 @@ static void intel_hdcp_info(struct seq_file *m,
> >  		goto out;
> >  	}
> >
> > -	hdcp_cap = intel_hdcp_capable(intel_connector);
> > -	hdcp2_cap = intel_hdcp2_capable(intel_connector);
> > +	ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
> > +	if (ret)
> > +		hdcp_cap = false;
> > +	ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
> > +	if (ret)
> > +		hdcp2_cap = false;
> >
> 
> This does not seem to be adding value here as this error which you referred
> to as being ignored is used both in case of hdmi and dp is being to determine
> if hdcp_cap or hdcp2 cap is true or false which you basically reiterate here too
> check the intel_dp_hdcp2_capable and intel_hdmi_hdcp2_capable .
> this change in itself can be removed.
> 
> Regards,
> Suraj Kandpal
> 
> >  	if (hdcp_cap)
> >  		seq_puts(m, "HDCP1.4 ");
> > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > index 0a20bc41be55..61a862ae1f28 100644
> > --- a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > @@ -177,50 +177,49 @@ int intel_hdcp_read_valid_bksv(struct
> > intel_digital_port *dig_port,  }
> >
> >  /* Is HDCP1.4 capable on Platform and Sink */ -bool
> > intel_hdcp_capable(struct intel_connector *connector)
> > +int intel_hdcp_capable(struct intel_connector *connector, bool
> > +*capable)
> >  {
> >  	struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> >  	const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> > -	bool capable = false;
> >  	u8 bksv[5];
> >
> > +	*capable = false;
> > +
> >  	if (!shim)
> > -		return capable;
> > +		return 0;
> >
> > -	if (shim->hdcp_capable) {
> > -		shim->hdcp_capable(dig_port, &capable);
> > -	} else {
> > -		if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> > -			capable = true;
> > -	}
> > +	if (shim->hdcp_capable)
> > +		return shim->hdcp_capable(dig_port, capable);
> > +
> > +	if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> > +		*capable = true;
> >
> > -	return capable;
> > +	return 0;
> >  }
> >
> >  /* Is HDCP2.2 capable on Platform and Sink */ -bool
> > intel_hdcp2_capable(struct intel_connector *connector)
> > +int intel_hdcp2_capable(struct intel_connector *connector, bool
> > +*capable)
> >  {
> >  	struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> >  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >  	struct intel_hdcp *hdcp = &connector->hdcp;
> > -	bool capable = false;
> > +
> > +	*capable = false;
> >
> >  	/* I915 support for HDCP2.2 */
> >  	if (!hdcp->hdcp2_supported)
> > -		return false;
> > +		return 0;
> >
> >  	/* MEI interface is solid */
> >  	mutex_lock(&dev_priv->display.hdcp.comp_mutex);
> >  	if (!dev_priv->display.hdcp.comp_added ||  !dev_priv-
> > >display.hdcp.master) {
> >  		mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> > -		return false;
> > +		return 0;
> >  	}
> >  	mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> >
> >  	/* Sink's capability for HDCP2.2 */
> > -	hdcp->shim->hdcp_2_2_capable(dig_port, &capable);
> > -
> > -	return capable;
> > +	return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
> >  }
> >
> >  static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv, @@ -
> > 2355,6 +2354,7 @@ int intel_hdcp_enable(struct intel_connector
> > *connector,
> >  	struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> >  	struct intel_hdcp *hdcp = &connector->hdcp;
> >  	unsigned long check_link_interval =
> DRM_HDCP_CHECK_PERIOD_MS;
> > +	bool capable;
> >  	int ret = -EINVAL;
> >
> >  	if (!hdcp->shim)
> > @@ -2373,21 +2373,27 @@ int intel_hdcp_enable(struct intel_connector
> > *connector,
> >  	 * Considering that HDCP2.2 is more secure than HDCP1.4, If the
> > setup
> >  	 * is capable of HDCP2.2, it is preferred to use HDCP2.2.
> >  	 */
> > -	if (intel_hdcp2_capable(connector)) {
> > +	ret = intel_hdcp2_capable(connector, &capable);
> > +	if (capable) {
> >  		ret = _intel_hdcp2_enable(connector);
> > -		if (!ret)
> > +		if (!ret) {
> >  			check_link_interval =
> > DRM_HDCP2_CHECK_PERIOD_MS;
> > +			goto out;
> > +		}

HI,
Just noticed another changed here if any error is returned with intel_hdc2_capable
You directly jump to out which will stop us from enabling hdcp 1.4 we should check
for hdcp 1.4 capability even if hdcp 2.2 capability is returned with an error one other
reason I don't think the handling of error codes are adding value here.

Regards,
Suraj Kandpal
> >  	}
> >
> >  	/*
> >  	 * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
> >  	 * be attempted.
> >  	 */
> > -	if (ret && intel_hdcp_capable(connector) &&
> > -	    hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) {
> > +	ret = intel_hdcp_capable(connector, &capable);
> > +	if (ret)
> > +		goto out;
> > +
> > +	if (capable && hdcp->content_type !=
> > DRM_MODE_HDCP_CONTENT_TYPE1)
> >  		ret = _intel_hdcp_enable(connector);
> > -	}
> >
> > +out:
> >  	if (!ret) {
> >  		schedule_delayed_work(&hdcp->check_work,
> > check_link_interval);
> >  		intel_hdcp_update_value(connector,
> > @@ -2395,7 +2401,6 @@ int intel_hdcp_enable(struct intel_connector
> > *connector,
> >  					true);
> >  	}
> >
> > -out:
> >  	mutex_unlock(&dig_port->hdcp_mutex);
> >  	mutex_unlock(&hdcp->mutex);
> >  	return ret;
> > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > index 7c5fd84a7b65..f06f6e5a2b1a 100644
> > --- a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > @@ -33,8 +33,8 @@ void intel_hdcp_update_pipe(struct
> > intel_atomic_state *state,
> >  			    const struct intel_crtc_state *crtc_state,
> >  			    const struct drm_connector_state *conn_state);
> bool
> > is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
> > -bool intel_hdcp_capable(struct intel_connector *connector); -bool
> > intel_hdcp2_capable(struct intel_connector *connector);
> > +int intel_hdcp_capable(struct intel_connector *connector, bool
> > +*capable); int intel_hdcp2_capable(struct intel_connector *connector,
> > +bool *capable);
> >  void intel_hdcp_component_init(struct drm_i915_private *dev_priv);
> > void intel_hdcp_component_fini(struct drm_i915_private *dev_priv);
> > void intel_hdcp_cleanup(struct intel_connector *connector);
> > --
> > 2.39.0.246.g2a6d74b583-goog


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes
  2023-03-23  7:17     ` Kandpal, Suraj
@ 2023-03-24 19:27       ` Mark Yacoub
  2023-03-28  5:52         ` Kandpal, Suraj
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Yacoub @ 2023-03-24 19:27 UTC (permalink / raw)
  To: Kandpal, Suraj
  Cc: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx, quic_sbillaka, konrad.dybcio, Souza,
	Jose, bjorn.andersson, krzysztof.kozlowski+dt, hbh25y, Vasut,
	Marek, Dixit, Ashutosh, sean, abhinavk, javierm, Murthy, Arun R,
	Lisovskiy, Stanislav, agross, quic_jesszhan, Nautiyal, Ankit K,
	Nikula, Jani, De Marchi, Lucas, quic_abhinavk, swboyd, robh+dt,
	christophe.jaillet, maxime, Vivi, Rodrigo, johan+linaro,
	tvrtko.ursulin, andersson, dianders, Sharma, Swati2, Navare,
	Manasi D, tzimmermann, Modem, Bhanuprakash, dmitry.baryshkov,
	seanpaul

On Thu, Mar 23, 2023 at 3:18 AM Kandpal, Suraj <suraj.kandpal@intel.com> wrote:
>
>
>
> > -----Original Message-----
> > From: Kandpal, Suraj
> > Sent: Friday, March 10, 2023 1:55 PM
> > To: Mark Yacoub <markyacoub@chromium.org>; quic_khsieh@quicinc.com;
> > linux-arm-msm@vger.kernel.org; dri-devel@lists.freedesktop.org;
> > freedreno@lists.freedesktop.org; devicetree@vger.kernel.org; linux-
> > kernel@vger.kernel.org; intel-gfx@lists.freedesktop.org
> > Cc: quic_sbillaka@quicinc.com; konrad.dybcio@somainline.org; Souza, Jose
> > <jose.souza@intel.com>; bjorn.andersson@linaro.org;
> > krzysztof.kozlowski+dt@linaro.org; hbh25y@gmail.com; Vasut, Marek
> > <marex@denx.de>; Dixit, Ashutosh <ashutosh.dixit@intel.com>;
> > sean@poorly.run; abhinavk@codeaurora.org; javierm@redhat.com; Murthy,
> > Arun R <arun.r.murthy@intel.com>; Lisovskiy, Stanislav
> > <Stanislav.Lisovskiy@intel.com>; agross@kernel.org;
> > quic_jesszhan@quicinc.com; Nautiyal, Ankit K <ankit.k.nautiyal@intel.com>;
> > Nikula, Jani <jani.nikula@intel.com>; De Marchi, Lucas
> > <lucas.demarchi@intel.com>; quic_abhinavk@quicinc.com;
> > swboyd@chromium.org; robh+dt@kernel.org;
> > christophe.jaillet@wanadoo.fr; maxime@cerno.tech; Vivi, Rodrigo
> > <rodrigo.vivi@intel.com>; johan+linaro@kernel.org;
> > tvrtko.ursulin@linux.intel.com; andersson@kernel.org;
> > dianders@chromium.org; Sharma, Swati2 <swati2.sharma@intel.com>;
> > Navare, Manasi D <manasi.d.navare@intel.com>; tzimmermann@suse.de;
> > Modem, Bhanuprakash <Bhanuprakash.Modem@intel.com>;
> > dmitry.baryshkov@linaro.org; seanpaul@chromium.org
> > Subject: RE: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return
> > codes
> >
> > > Subject: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return
> > > codes
> > >
> > > From: Sean Paul <seanpaul@chromium.org>
> > >
> > > The shim functions return error codes, but they are discarded in
> > > intel_hdcp.c. This patch plumbs the return codes through so they are
> > > properly handled.
> > >
> > > Acked-by: Jani Nikula <jani.nikula@intel.com>
> > > Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > > Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> > > Link:
> > > https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-7-
> > > sean@poorly.run #v1
> > > Link:
> > > https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-7-
> > > sean@poorly.run #v2
> > > Link:
> > > https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-7-
> > > sean@poorly.run #v3
> > > Link:
> > >
> > https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
> > > 7-sean@poorly.run #v4
> > > Link:
> > >
> > https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
> > > 7-sean@poorly.run #v5
> > >
> > > Changes in v2:
> > > -None
> > > Changes in v3:
> > > -None
> > > Changes in v4:
> > > -None
> > > Changes in v5:
> > > -None
> > > Changes in v6:
> > > -Rebased
> > >
> > > ---
> > >  .../drm/i915/display/intel_display_debugfs.c  |  9 +++-
> > >  drivers/gpu/drm/i915/display/intel_hdcp.c     | 51 ++++++++++---------
> > >  drivers/gpu/drm/i915/display/intel_hdcp.h     |  4 +-
> > >  3 files changed, 37 insertions(+), 27 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > index 7c7253a2541c..13a4153bb76e 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > @@ -492,6 +492,7 @@ static void intel_panel_info(struct seq_file *m,
> > > static void intel_hdcp_info(struct seq_file *m,
> > >                         struct intel_connector *intel_connector)  {
> > > +   int ret;
> > >     bool hdcp_cap, hdcp2_cap;
> > >
> > >     if (!intel_connector->hdcp.shim) {
> > > @@ -499,8 +500,12 @@ static void intel_hdcp_info(struct seq_file *m,
> > >             goto out;
> > >     }
> > >
> > > -   hdcp_cap = intel_hdcp_capable(intel_connector);
> > > -   hdcp2_cap = intel_hdcp2_capable(intel_connector);
> > > +   ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
> > > +   if (ret)
> > > +           hdcp_cap = false;
> > > +   ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
> > > +   if (ret)
> > > +           hdcp2_cap = false;
> > >
> >
> > This does not seem to be adding value here as this error which you referred
> > to as being ignored is used both in case of hdmi and dp is being to determine
> > if hdcp_cap or hdcp2 cap is true or false which you basically reiterate here too
> > check the intel_dp_hdcp2_capable and intel_hdmi_hdcp2_capable .
> > this change in itself can be removed.
> >
> > Regards,
> > Suraj Kandpal
> >
Hey Suraj, what we're trying to do here is to have a distinction
between 2 things:
1. were we able to check of the capability or not. like did the
connection work well
2. if the check went well, what capability were were able to read
We may or may not need both info. But since we moved to common DRM, it
might be best keep the distinction and each driver can handle it as it
sees fit.
> > >     if (hdcp_cap)
> > >             seq_puts(m, "HDCP1.4 ");
> > > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > index 0a20bc41be55..61a862ae1f28 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > @@ -177,50 +177,49 @@ int intel_hdcp_read_valid_bksv(struct
> > > intel_digital_port *dig_port,  }
> > >
> > >  /* Is HDCP1.4 capable on Platform and Sink */ -bool
> > > intel_hdcp_capable(struct intel_connector *connector)
> > > +int intel_hdcp_capable(struct intel_connector *connector, bool
> > > +*capable)
> > >  {
> > >     struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > >     const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> > > -   bool capable = false;
> > >     u8 bksv[5];
> > >
> > > +   *capable = false;
> > > +
> > >     if (!shim)
> > > -           return capable;
> > > +           return 0;
> > >
> > > -   if (shim->hdcp_capable) {
> > > -           shim->hdcp_capable(dig_port, &capable);
> > > -   } else {
> > > -           if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> > > -                   capable = true;
> > > -   }
> > > +   if (shim->hdcp_capable)
> > > +           return shim->hdcp_capable(dig_port, capable);
> > > +
> > > +   if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> > > +           *capable = true;
> > >
> > > -   return capable;
> > > +   return 0;
> > >  }
> > >
> > >  /* Is HDCP2.2 capable on Platform and Sink */ -bool
> > > intel_hdcp2_capable(struct intel_connector *connector)
> > > +int intel_hdcp2_capable(struct intel_connector *connector, bool
> > > +*capable)
> > >  {
> > >     struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > >     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > >     struct intel_hdcp *hdcp = &connector->hdcp;
> > > -   bool capable = false;
> > > +
> > > +   *capable = false;
> > >
> > >     /* I915 support for HDCP2.2 */
> > >     if (!hdcp->hdcp2_supported)
> > > -           return false;
> > > +           return 0;
> > >
> > >     /* MEI interface is solid */
> > >     mutex_lock(&dev_priv->display.hdcp.comp_mutex);
> > >     if (!dev_priv->display.hdcp.comp_added ||  !dev_priv-
> > > >display.hdcp.master) {
> > >             mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> > > -           return false;
> > > +           return 0;
> > >     }
> > >     mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> > >
> > >     /* Sink's capability for HDCP2.2 */
> > > -   hdcp->shim->hdcp_2_2_capable(dig_port, &capable);
> > > -
> > > -   return capable;
> > > +   return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
> > >  }
> > >
> > >  static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv, @@ -
> > > 2355,6 +2354,7 @@ int intel_hdcp_enable(struct intel_connector
> > > *connector,
> > >     struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > >     struct intel_hdcp *hdcp = &connector->hdcp;
> > >     unsigned long check_link_interval =
> > DRM_HDCP_CHECK_PERIOD_MS;
> > > +   bool capable;
> > >     int ret = -EINVAL;
> > >
> > >     if (!hdcp->shim)
> > > @@ -2373,21 +2373,27 @@ int intel_hdcp_enable(struct intel_connector
> > > *connector,
> > >      * Considering that HDCP2.2 is more secure than HDCP1.4, If the
> > > setup
> > >      * is capable of HDCP2.2, it is preferred to use HDCP2.2.
> > >      */
> > > -   if (intel_hdcp2_capable(connector)) {
> > > +   ret = intel_hdcp2_capable(connector, &capable);
> > > +   if (capable) {
> > >             ret = _intel_hdcp2_enable(connector);
> > > -           if (!ret)
> > > +           if (!ret) {
> > >                     check_link_interval =
> > > DRM_HDCP2_CHECK_PERIOD_MS;
> > > +                   goto out;
> > > +           }
>
> HI,
> Just noticed another changed here if any error is returned with intel_hdc2_capable
> You directly jump to out which will stop us from enabling hdcp 1.4 we should check
> for hdcp 1.4 capability even if hdcp 2.2 capability is returned with an error one other
> reason I don't think the handling of error codes are adding value here.
>
> Regards,
> Suraj Kandpal
Hey Suraj - the goto happens if we know that the device is hdcp2
capable. If it's capable, we do enable it. If we have no error
returned, that's when we skip hdcp1.4
otherwise, if it's not capable, or the enable returned with an error
code, we don't goto out but move on to try on hdcp 1.4
Thanks!
> > >     }
> > >
> > >     /*
> > >      * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
> > >      * be attempted.
> > >      */
> > > -   if (ret && intel_hdcp_capable(connector) &&
> > > -       hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) {
> > > +   ret = intel_hdcp_capable(connector, &capable);
> > > +   if (ret)
> > > +           goto out;
> > > +
> > > +   if (capable && hdcp->content_type !=
> > > DRM_MODE_HDCP_CONTENT_TYPE1)
> > >             ret = _intel_hdcp_enable(connector);
> > > -   }
> > >
> > > +out:
> > >     if (!ret) {
> > >             schedule_delayed_work(&hdcp->check_work,
> > > check_link_interval);
> > >             intel_hdcp_update_value(connector,
> > > @@ -2395,7 +2401,6 @@ int intel_hdcp_enable(struct intel_connector
> > > *connector,
> > >                                     true);
> > >     }
> > >
> > > -out:
> > >     mutex_unlock(&dig_port->hdcp_mutex);
> > >     mutex_unlock(&hdcp->mutex);
> > >     return ret;
> > > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > index 7c5fd84a7b65..f06f6e5a2b1a 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > @@ -33,8 +33,8 @@ void intel_hdcp_update_pipe(struct
> > > intel_atomic_state *state,
> > >                         const struct intel_crtc_state *crtc_state,
> > >                         const struct drm_connector_state *conn_state);
> > bool
> > > is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
> > > -bool intel_hdcp_capable(struct intel_connector *connector); -bool
> > > intel_hdcp2_capable(struct intel_connector *connector);
> > > +int intel_hdcp_capable(struct intel_connector *connector, bool
> > > +*capable); int intel_hdcp2_capable(struct intel_connector *connector,
> > > +bool *capable);
> > >  void intel_hdcp_component_init(struct drm_i915_private *dev_priv);
> > > void intel_hdcp_component_fini(struct drm_i915_private *dev_priv);
> > > void intel_hdcp_cleanup(struct intel_connector *connector);
> > > --
> > > 2.39.0.246.g2a6d74b583-goog
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Intel-gfx] [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915
  2023-03-14  5:54   ` Kandpal, Suraj
@ 2023-03-24 19:34     ` Mark Yacoub
  2023-03-28  6:12       ` Kandpal, Suraj
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Yacoub @ 2023-03-24 19:34 UTC (permalink / raw)
  To: Kandpal, Suraj
  Cc: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx, quic_sbillaka, konrad.dybcio,
	bjorn.andersson, krzysztof.kozlowski+dt, airlied, hbh25y, Vasut,
	Marek, abhinavk, javierm, agross, quic_jesszhan, daniel, Nikula,
	Jani, De Marchi, Lucas, quic_abhinavk, swboyd, robh+dt,
	christophe.jaillet, maxime, Vivi, Rodrigo, johan+linaro,
	andersson, dianders, tzimmermann, dmitry.baryshkov, seanpaul

On Tue, Mar 14, 2023 at 1:54 AM Kandpal, Suraj <suraj.kandpal@intel.com> wrote:
>
> >
> > From: Sean Paul <seanpaul@chromium.org>
> >
> > Now that all of the HDCP 1.x logic has been migrated to the central HDCP
> > helpers, use it in the i915 driver.
> >
> > The majority of the driver code for HDCP 1.x will live in intel_hdcp.c,
> > however there are a few helper hooks which are connector-specific and
> > need to be partially or fully implemented in the intel_dp_hdcp.c or
> > intel_hdmi.c.
> >
> > We'll leave most of the HDCP 2.x code alone since we don't have another
> > implementation of HDCP 2.x to use as reference for what should and
> > should not live in the drm helpers. The helper will call the overly
> > general enable/disable/is_capable HDCP 2.x callbacks and leave the
> > interesting stuff for the driver. Once we have another HDCP 2.x
> > implementation, we should do a similar migration.
> >
> > Acked-by: Jani Nikula <jani.nikula@intel.com>
> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> > Link:
> > https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-8-
> > sean@poorly.run #v1
> > Link:
> > https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-8-
> > sean@poorly.run #v2
> > Link:
> > https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-8-
> > sean@poorly.run #v3
> > Link:
> > https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
> > 8-sean@poorly.run #v4
> > Link:
> > https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
> > 8-sean@poorly.run #v5
> >
> > Changes in v2:
> > -Fix mst helper function pointer reported by 0-day
> > Changes in v3:
> > -Add forward declaration for drm_atomic_state in intel_hdcp.h identified
> >  by 0-day
> > Changes in v4:
> > -None
> > Changes in v5:
> > -None
> > Changes in v6:
> > -Rebased.
> >
> > ---
> >  drivers/gpu/drm/i915/display/intel_ddi.c      |  32 +-
> >  .../drm/i915/display/intel_display_debugfs.c  |   6 +-
> >  .../drm/i915/display/intel_display_types.h    |  60 +-
> >  drivers/gpu/drm/i915/display/intel_dp_hdcp.c  | 348 +++----
> >  drivers/gpu/drm/i915/display/intel_dp_mst.c   |  16 +-
> >  drivers/gpu/drm/i915/display/intel_hdcp.c     | 952 +++---------------
> >  drivers/gpu/drm/i915/display/intel_hdcp.h     |  31 +-
> >  drivers/gpu/drm/i915/display/intel_hdmi.c     | 270 ++---
> >  8 files changed, 445 insertions(+), 1270 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c
> > b/drivers/gpu/drm/i915/display/intel_ddi.c
> > index 69ecf2a3d6c6..a4397f066a3e 100644
> > --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> > @@ -28,6 +28,7 @@
> >  #include <linux/string_helpers.h>
> >
> >  #include <drm/display/drm_scdc_helper.h>
> > +#include <drm/display/drm_hdcp_helper.h>
> >  #include <drm/drm_privacy_screen_consumer.h>
> >
> >  #include "i915_drv.h"
> > @@ -2909,6 +2910,10 @@ static void intel_enable_ddi(struct
> > intel_atomic_state *state,
> >                            const struct intel_crtc_state *crtc_state,
> >                            const struct drm_connector_state *conn_state)
> >  {
> > +     struct intel_connector *connector =
> > +             to_intel_connector(conn_state->connector);
> > +     struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> > +
> >       drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
> >
> >       if (!intel_crtc_is_bigjoiner_slave(crtc_state))
> > @@ -2925,12 +2930,10 @@ static void intel_enable_ddi(struct
> > intel_atomic_state *state,
> >       else
> >               intel_enable_ddi_dp(state, encoder, crtc_state,
> > conn_state);
> >
> > -     /* Enable hdcp if it's desired */
> > -     if (conn_state->content_protection ==
> > -         DRM_MODE_CONTENT_PROTECTION_DESIRED)
> > -             intel_hdcp_enable(to_intel_connector(conn_state-
> > >connector),
> > -                               crtc_state,
> > -                               (u8)conn_state->hdcp_content_type);
> > +     if (connector->hdcp_helper_data)
> > +             drm_hdcp_helper_atomic_commit(connector-
> > >hdcp_helper_data,
> > +                                           &state->base,
> > +                                           &dig_port->hdcp_mutex);
> >  }
> >
> >  static void intel_disable_ddi_dp(struct intel_atomic_state *state,
> > @@ -2976,7 +2979,14 @@ static void intel_disable_ddi(struct
> > intel_atomic_state *state,
> >                             const struct intel_crtc_state *old_crtc_state,
> >                             const struct drm_connector_state
> > *old_conn_state)
> >  {
> > -     intel_hdcp_disable(to_intel_connector(old_conn_state-
> > >connector));
> > +     struct intel_connector *connector =
> > +             to_intel_connector(old_conn_state->connector);
> > +     struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> > +
> > +     if (connector->hdcp_helper_data)
> > +             drm_hdcp_helper_atomic_commit(connector-
> > >hdcp_helper_data,
> > +                                           &state->base,
> > +                                           &dig_port->hdcp_mutex);
> >
> >       if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
> >               intel_disable_ddi_hdmi(state, encoder, old_crtc_state,
> > @@ -3004,13 +3014,19 @@ void intel_ddi_update_pipe(struct
> > intel_atomic_state *state,
> >                          const struct intel_crtc_state *crtc_state,
> >                          const struct drm_connector_state *conn_state)
> >  {
> > +     struct intel_connector *connector =
> > +             to_intel_connector(conn_state->connector);
> > +     struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> >
> >       if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
> >           !intel_encoder_is_mst(encoder))
> >               intel_ddi_update_pipe_dp(state, encoder, crtc_state,
> >                                        conn_state);
> >
> > -     intel_hdcp_update_pipe(state, encoder, crtc_state, conn_state);
> > +     if (connector->hdcp_helper_data)
> > +             drm_hdcp_helper_atomic_commit(connector-
> > >hdcp_helper_data,
> > +                                           &state->base,
> > +                                           &dig_port->hdcp_mutex);
> >  }
> >
> >  static void
> > diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > index 13a4153bb76e..2e67cca0151c 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > @@ -7,6 +7,7 @@
> >
> >  #include <drm/drm_debugfs.h>
> >  #include <drm/drm_fourcc.h>
> > +#include <drm/display/drm_hdcp_helper.h>
> >
> >  #include "i915_debugfs.h"
> >  #include "intel_de.h"
> > @@ -500,10 +501,11 @@ static void intel_hdcp_info(struct seq_file *m,
> >               goto out;
> >       }
> >
> > -     ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
> > +     ret = drm_hdcp_helper_hdcp1_capable(intel_connector-
> > >hdcp_helper_data,
> > +                                         &hdcp_cap);
> >       if (ret)
> >               hdcp_cap = false;
> > -     ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
> > +     ret = intel_hdcp2_capable(&intel_connector->base, &hdcp2_cap);
> >       if (ret)
> >               hdcp2_cap = false;
> >
> > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h
> > b/drivers/gpu/drm/i915/display/intel_display_types.h
> > index 298d00a11f47..6260a40586ae 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> > @@ -416,71 +416,14 @@ enum check_link_response {
> >   *           The offsets of the registers are different for DP vs. HDMI
> >   *   - Receiver register masks/offsets
> >   *           For instance, the ready bit for the KSV fifo is in a different
> > - *           place on DP vs HDMI
> > - *   - Receiver register names
> > - *           Seriously. In the DP spec, the 16-bit register containing
> > - *           downstream information is called BINFO, on HDMI it's called
> > - *           BSTATUS. To confuse matters further, DP has a BSTATUS
> > register
> > - *           with a completely different definition.
> > - *   - KSV FIFO
> > - *           On HDMI, the ksv fifo is read all at once, whereas on DP it
> > must
> > - *           be read 3 keys at a time
> > - *   - Aksv output
> > - *           Since Aksv is hidden in hardware, there's different
> > procedures
> > - *           to send it over DP AUX vs DDC
>
> I really think we can keep the comment as its mentioning the ways that the two busses differ
>
Reverted the change.
> > + *           place on DP vs HDMI.
> >   */
> >  struct intel_hdcp_shim {
> > -     /* Outputs the transmitter's An and Aksv values to the receiver. */
> > -     int (*write_an_aksv)(struct intel_digital_port *dig_port, u8 *an);
> > -
> > -     /* Reads the receiver's key selection vector */
> > -     int (*read_bksv)(struct intel_digital_port *dig_port, u8 *bksv);
> > -
> > -     /*
> > -      * Reads BINFO from DP receivers and BSTATUS from HDMI
> > receivers. The
> > -      * definitions are the same in the respective specs, but the names
> > are
> > -      * different. Call it BSTATUS since that's the name the HDMI spec
> > -      * uses and it was there first.
> > -      */
> > -     int (*read_bstatus)(struct intel_digital_port *dig_port,
> > -                         u8 *bstatus);
> > -
> > -     /* Determines whether a repeater is present downstream */
> > -     int (*repeater_present)(struct intel_digital_port *dig_port,
> > -                             bool *repeater_present);
> > -
> > -     /* Reads the receiver's Ri' value */
> > -     int (*read_ri_prime)(struct intel_digital_port *dig_port, u8 *ri);
> > -
> > -     /* Determines if the receiver's KSV FIFO is ready for consumption */
> > -     int (*read_ksv_ready)(struct intel_digital_port *dig_port,
> > -                           bool *ksv_ready);
> > -
> > -     /* Reads the ksv fifo for num_downstream devices */
> > -     int (*read_ksv_fifo)(struct intel_digital_port *dig_port,
> > -                          int num_downstream, u8 *ksv_fifo);
> > -
> > -     /* Reads a 32-bit part of V' from the receiver */
> > -     int (*read_v_prime_part)(struct intel_digital_port *dig_port,
> > -                              int i, u32 *part);
> > -
> >       /* Enables HDCP signalling on the port */
> >       int (*toggle_signalling)(struct intel_digital_port *dig_port,
> >                                enum transcoder cpu_transcoder,
> >                                bool enable);
> >
> > -     /* Enable/Disable stream encryption on DP MST Transport Link */
> > -     int (*stream_encryption)(struct intel_connector *connector,
> > -                              bool enable);
> > -
> > -     /* Ensures the link is still protected */
> > -     bool (*check_link)(struct intel_digital_port *dig_port,
> > -                        struct intel_connector *connector);
> > -
> > -     /* Detects panel's hdcp capability. This is optional for HDMI. */
> > -     int (*hdcp_capable)(struct intel_digital_port *dig_port,
> > -                         bool *hdcp_capable);
> > -
> >       /* HDCP adaptation(DP/HDMI) required on the port */
> >       enum hdcp_wired_protocol protocol;
> >
> > @@ -610,6 +553,7 @@ struct intel_connector {
> >       struct work_struct modeset_retry_work;
> >
> >       struct intel_hdcp hdcp;
> > +     struct drm_hdcp_helper_data *hdcp_helper_data;
> >  };
> >
> >  struct intel_digital_connector_state {
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > index 88689124c013..d61ac8d69951 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > @@ -55,17 +55,24 @@ static void intel_dp_hdcp_wait_for_cp_irq(struct
> > intel_hdcp *hdcp, int timeout)
> >               DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
> >  }
> >
> > -static
> > -int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> > -                             u8 *an)
> > +static int intel_dp_hdcp1_send_an_aksv(struct drm_connector
> > *drm_connector)
> >  {
>
> I think the name intel_dp_hdcp_send_an_aksv should be enough as this step
> is done only for hdcp 1.x and not hdcp 2.x.
>
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> >       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > +     struct drm_hdcp_an an;
> >       u8 aksv[DRM_HDCP_KSV_LEN] = {};
> >       ssize_t dpcd_ret;
> > +     int ret;
> >
> >       /* Output An first, that's easy */
> > +     ret = intel_hdcp1_read_an(drm_connector, &an);
> > +     if (ret)
> > +             return ret;
> > +
> >       dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux,
> > DP_AUX_HDCP_AN,
> > -                                  an, DRM_HDCP_AN_LEN);
> > +                                  an.bytes, DRM_HDCP_AN_LEN);
> >       if (dpcd_ret != DRM_HDCP_AN_LEN) {
> >               drm_dbg_kms(&i915->drm,
> >                           "Failed to write An over DP/AUX (%zd)\n",
> > @@ -91,158 +98,6 @@ int intel_dp_hdcp_write_an_aksv(struct
> > intel_digital_port *dig_port,
> >       return 0;
> >  }
> >
> > -static int intel_dp_hdcp_read_bksv(struct intel_digital_port *dig_port,
> > -                                u8 *bksv)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     ssize_t ret;
> > -
> > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BKSV,
> > bksv,
> > -                            DRM_HDCP_KSV_LEN);
> > -     if (ret != DRM_HDCP_KSV_LEN) {
> > -             drm_dbg_kms(&i915->drm,
> > -                         "Read Bksv from DP/AUX failed (%zd)\n", ret);
> > -             return ret >= 0 ? -EIO : ret;
> > -     }
> > -     return 0;
> > -}
> > -
> > -static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
> > -                                   u8 *bstatus)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     ssize_t ret;
> > -
> > -     /*
> > -      * For some reason the HDMI and DP HDCP specs call this register
> > -      * definition by different names. In the HDMI spec, it's called
> > BSTATUS,
> > -      * but in DP it's called BINFO.
> > -      */
> > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > DP_AUX_HDCP_BINFO,
> > -                            bstatus, DRM_HDCP_BSTATUS_LEN);
> > -     if (ret != DRM_HDCP_BSTATUS_LEN) {
> > -             drm_dbg_kms(&i915->drm,
> > -                         "Read bstatus from DP/AUX failed (%zd)\n", ret);
> > -             return ret >= 0 ? -EIO : ret;
> > -     }
> > -     return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_read_bcaps(struct intel_digital_port *dig_port,
> > -                          u8 *bcaps)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     ssize_t ret;
> > -
> > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > DP_AUX_HDCP_BCAPS,
> > -                            bcaps, 1);
> > -     if (ret != 1) {
> > -             drm_dbg_kms(&i915->drm,
> > -                         "Read bcaps from DP/AUX failed (%zd)\n", ret);
> > -             return ret >= 0 ? -EIO : ret;
> > -     }
> > -
> > -     return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_repeater_present(struct intel_digital_port *dig_port,
> > -                                bool *repeater_present)
> > -{
> > -     ssize_t ret;
> > -     u8 bcaps;
> > -
> > -     ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
> > -     if (ret)
> > -             return ret;
> > -
> > -     *repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
> > -     return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
> > -                             u8 *ri_prime)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     ssize_t ret;
> > -
> > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > DP_AUX_HDCP_RI_PRIME,
> > -                            ri_prime, DRM_HDCP_RI_LEN);
> > -     if (ret != DRM_HDCP_RI_LEN) {
> > -             drm_dbg_kms(&i915->drm, "Read Ri' from DP/AUX failed
> > (%zd)\n",
> > -                         ret);
> > -             return ret >= 0 ? -EIO : ret;
> > -     }
> > -     return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
> > -                              bool *ksv_ready)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     ssize_t ret;
> > -     u8 bstatus;
> > -
> > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > DP_AUX_HDCP_BSTATUS,
> > -                            &bstatus, 1);
> > -     if (ret != 1) {
> > -             drm_dbg_kms(&i915->drm,
> > -                         "Read bstatus from DP/AUX failed (%zd)\n", ret);
> > -             return ret >= 0 ? -EIO : ret;
> > -     }
> > -     *ksv_ready = bstatus & DP_BSTATUS_READY;
> > -     return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
> > -                             int num_downstream, u8 *ksv_fifo)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     ssize_t ret;
> > -     int i;
> > -
> > -     /* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
> > -     for (i = 0; i < num_downstream; i += 3) {
> > -             size_t len = min(num_downstream - i, 3) *
> > DRM_HDCP_KSV_LEN;
> > -             ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > -                                    DP_AUX_HDCP_KSV_FIFO,
> > -                                    ksv_fifo + i * DRM_HDCP_KSV_LEN,
> > -                                    len);
> > -             if (ret != len) {
> > -                     drm_dbg_kms(&i915->drm,
> > -                                 "Read ksv[%d] from DP/AUX failed
> > (%zd)\n",
> > -                                 i, ret);
> > -                     return ret >= 0 ? -EIO : ret;
> > -             }
> > -     }
> > -     return 0;
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
> > -                                 int i, u32 *part)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     ssize_t ret;
> > -
> > -     if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
> > -             return -EINVAL;
> > -
> > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > -                            DP_AUX_HDCP_V_PRIME(i), part,
> > -                            DRM_HDCP_V_PRIME_PART_LEN);
> > -     if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
> > -             drm_dbg_kms(&i915->drm,
> > -                         "Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
> > -             return ret >= 0 ? -EIO : ret;
> > -     }
> > -     return 0;
> > -}
> > -
> >  static
> >  int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
> >                                   enum transcoder cpu_transcoder,
> > @@ -252,40 +107,6 @@ int intel_dp_hdcp_toggle_signalling(struct
> > intel_digital_port *dig_port,
> >       return 0;
> >  }
> >
> > -static
> > -bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
> > -                           struct intel_connector *connector)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     ssize_t ret;
> > -     u8 bstatus;
> > -
> > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > DP_AUX_HDCP_BSTATUS,
> > -                            &bstatus, 1);
> > -     if (ret != 1) {
> > -             drm_dbg_kms(&i915->drm,
> > -                         "Read bstatus from DP/AUX failed (%zd)\n", ret);
> > -             return false;
> > -     }
> > -
> > -     return !(bstatus & (DP_BSTATUS_LINK_FAILURE |
> > DP_BSTATUS_REAUTH_REQ));
> > -}
> > -
> > -static
> > -int intel_dp_hdcp_capable(struct intel_digital_port *dig_port,
> > -                       bool *hdcp_capable)
> > -{
> > -     ssize_t ret;
> > -     u8 bcaps;
> > -
> > -     ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
> > -     if (ret)
> > -             return ret;
> > -
> > -     *hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
> > -     return 0;
> > -}
> > -
> >  struct hdcp2_dp_errata_stream_type {
> >       u8      msg_id;
> >       u8      stream_type;
> > @@ -628,13 +449,19 @@ int intel_dp_hdcp2_check_link(struct
> > intel_digital_port *dig_port,
> >       return ret;
> >  }
> >
> > -static
> > -int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
> > -                        bool *capable)
> > +static int intel_dp_hdcp2_capable(struct drm_connector *drm_connector,
> > +                               bool *capable)
> >  {
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> >       u8 rx_caps[3];
> >       int ret;
> >
> > +     ret = intel_hdcp2_capable(drm_connector, capable);
> > +     if (ret || !capable)
> > +             return ret;
> > +
> >       *capable = false;
> >       ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> >                              DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
> > @@ -650,22 +477,11 @@ int intel_dp_hdcp2_capable(struct
> > intel_digital_port *dig_port,
> >  }
> >
> >  static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
> > -     .write_an_aksv = intel_dp_hdcp_write_an_aksv,
> > -     .read_bksv = intel_dp_hdcp_read_bksv,
> > -     .read_bstatus = intel_dp_hdcp_read_bstatus,
> > -     .repeater_present = intel_dp_hdcp_repeater_present,
> > -     .read_ri_prime = intel_dp_hdcp_read_ri_prime,
> > -     .read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
> > -     .read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
> > -     .read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
> >       .toggle_signalling = intel_dp_hdcp_toggle_signalling,
> > -     .check_link = intel_dp_hdcp_check_link,
> > -     .hdcp_capable = intel_dp_hdcp_capable,
> >       .write_2_2_msg = intel_dp_hdcp2_write_msg,
> >       .read_2_2_msg = intel_dp_hdcp2_read_msg,
> >       .config_stream_type = intel_dp_hdcp2_config_stream_type,
> >       .check_2_2_link = intel_dp_hdcp2_check_link,
> > -     .hdcp_2_2_capable = intel_dp_hdcp2_capable,
> >       .protocol = HDCP_PROTOCOL_DP,
> >  };
> >
> > @@ -721,6 +537,46 @@ intel_dp_mst_hdcp_stream_encryption(struct
> > intel_connector *connector,
> >       return 0;
> >  }
> >
> > +static int
> > +intel_dp_mst_hdcp1_post_encryption(struct drm_connector
> > *drm_connector)
> > +{
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     int ret;
> > +
> > +     ret = intel_hdcp1_post_encryption(drm_connector);
> > +     if (ret)
> > +             return ret;
> > +
> > +     return intel_dp_mst_hdcp_stream_encryption(connector, true);
> > +}
> > +
> > +static int intel_dp_mst_hdcp1_disable(struct drm_connector
> > *drm_connector)
> > +{
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> > +     struct drm_i915_private *i915 = to_i915(connector->base.dev);
> > +     int ret;
> > +
> > +     ret = intel_dp_mst_hdcp_stream_encryption(connector, true);
> > +     if (ret) {
> > +             drm_err(&i915->drm,
> > +                     "[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
> > +                     connector->base.name, connector->base.base.id);
> > +             return ret;
> > +     }
> > +
> > +     /*
> > +      * If there are other connectors on this port using HDCP,
> > +      * don't disable it until it disabled HDCP encryption for
> > +      * all connectors in MST topology.
> > +     */
> > +     if (dig_port->num_hdcp_streams > 0)
> > +             return 0;
> > +
> > +     return intel_hdcp1_disable(drm_connector);
> > +}
> > +
> >  static int
> >  intel_dp_mst_hdcp2_stream_encryption(struct intel_connector
> > *connector,
> >                                    bool enable)
> > @@ -779,45 +635,85 @@ int intel_dp_mst_hdcp2_check_link(struct
> > intel_digital_port *dig_port,
> >  }
> >
> >  static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
> > -     .write_an_aksv = intel_dp_hdcp_write_an_aksv,
> > -     .read_bksv = intel_dp_hdcp_read_bksv,
> > -     .read_bstatus = intel_dp_hdcp_read_bstatus,
> > -     .repeater_present = intel_dp_hdcp_repeater_present,
> > -     .read_ri_prime = intel_dp_hdcp_read_ri_prime,
> > -     .read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
> > -     .read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
> > -     .read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
> >       .toggle_signalling = intel_dp_hdcp_toggle_signalling,
> > -     .stream_encryption = intel_dp_mst_hdcp_stream_encryption,
> > -     .check_link = intel_dp_hdcp_check_link,
> > -     .hdcp_capable = intel_dp_hdcp_capable,
> >       .write_2_2_msg = intel_dp_hdcp2_write_msg,
> >       .read_2_2_msg = intel_dp_hdcp2_read_msg,
> >       .config_stream_type = intel_dp_hdcp2_config_stream_type,
> >       .stream_2_2_encryption = intel_dp_mst_hdcp2_stream_encryption,
> >       .check_2_2_link = intel_dp_mst_hdcp2_check_link,
> > -     .hdcp_2_2_capable = intel_dp_hdcp2_capable,
> >       .protocol = HDCP_PROTOCOL_DP,
> >  };
> >
> > +static const struct drm_hdcp_helper_funcs intel_dp_hdcp_helper_funcs = {
> > +     .setup = intel_hdcp_setup,
> > +     .load_keys = intel_hdcp_load_keys,
> > +     .hdcp2_capable = intel_dp_hdcp2_capable,
> > +     .hdcp2_enable = intel_hdcp2_enable,
> > +     .hdcp2_check_link = intel_hdcp2_check_link,
> > +     .hdcp2_disable = intel_hdcp2_disable,
> > +     .hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
> > +     .hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> > +     .hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
> > +     .hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> > +     .hdcp1_match_ri = intel_hdcp1_match_ri,
> > +     .hdcp1_post_encryption = intel_hdcp1_post_encryption,
> > +     .hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> > +     .hdcp1_disable = intel_hdcp1_disable,
> > +};
> > +
> > +static const struct drm_hdcp_helper_funcs
> > intel_dp_mst_hdcp_helper_funcs = {
> > +     .setup = intel_hdcp_setup,
> > +     .load_keys = intel_hdcp_load_keys,
> > +     .hdcp2_capable = intel_dp_hdcp2_capable,
> > +     .hdcp2_enable = intel_hdcp2_enable,
> > +     .hdcp2_check_link = intel_hdcp2_check_link,
> > +     .hdcp2_disable = intel_hdcp2_disable,
> > +     .hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
> > +     .hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> > +     .hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
> > +     .hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> > +     .hdcp1_match_ri = intel_hdcp1_match_ri,
> > +     .hdcp1_post_encryption = intel_dp_mst_hdcp1_post_encryption,
> > +     .hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> > +     .hdcp1_disable = intel_dp_mst_hdcp1_disable,
> > +};
> > +
> >  int intel_dp_hdcp_init(struct intel_digital_port *dig_port,
> > -                    struct intel_connector *intel_connector)
> > +                    struct intel_connector *connector)
> >  {
> > -     struct drm_device *dev = intel_connector->base.dev;
> > -     struct drm_i915_private *dev_priv = to_i915(dev);
> > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >       struct intel_encoder *intel_encoder = &dig_port->base;
> >       enum port port = intel_encoder->port;
> >       struct intel_dp *intel_dp = &dig_port->dp;
> > +     struct drm_hdcp_helper_data *data;
> > +     const struct drm_hdcp_helper_funcs *helper_funcs;
> > +     const struct intel_hdcp_shim *intel_shim;
> > +     int ret;
> >
> > -     if (!is_hdcp_supported(dev_priv, port))
> > +     if (!is_hdcp_supported(dev_priv, port) ||
> > intel_dp_is_edp(intel_dp))
> >               return 0;
> >
> > -     if (intel_connector->mst_port)
> > -             return intel_hdcp_init(intel_connector, dig_port,
> > -                                    &intel_dp_mst_hdcp_shim);
> > -     else if (!intel_dp_is_edp(intel_dp))
> > -             return intel_hdcp_init(intel_connector, dig_port,
> > -                                    &intel_dp_hdcp_shim);
> > +     if (connector->mst_port) {
> > +             helper_funcs = &intel_dp_mst_hdcp_helper_funcs;
> > +             intel_shim = &intel_dp_mst_hdcp_shim;
> > +     } else {
> > +             helper_funcs = &intel_dp_hdcp_helper_funcs;
> > +             intel_shim = &intel_dp_hdcp_shim;
> > +     }
> > +
> > +     data = drm_hdcp_helper_initialize_dp(
> > +             &connector->base, &dig_port->dp.aux, helper_funcs, true);
>
> The alignment here needs fixing
>
> > +     if (IS_ERR(data)) {
> > +             drm_dbg_kms(&dev_priv->drm, "HDCP init failed,
> > skipping.\n");
> > +             return PTR_ERR(data);
> > +     }
> > +
> > +     ret = intel_hdcp_init(connector, dig_port, intel_shim);
> > +     if (ret) {
> > +             drm_hdcp_helper_destroy(data);
> > +             return ret;
> > +     }
> >
> > +     connector->hdcp_helper_data = data;
> >       return 0;
> >  }
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > index 03604a37931c..ececb7aa4b90 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > @@ -27,6 +27,7 @@
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_edid.h>
> >  #include <drm/drm_probe_helper.h>
> > +#include <drm/display/drm_hdcp_helper.h>
> >
> >  #include "i915_drv.h"
> >  #include "intel_atomic.h"
> > @@ -40,7 +41,6 @@
> >  #include "intel_dp_hdcp.h"
> >  #include "intel_dp_mst.h"
> >  #include "intel_dpio_phy.h"
> > -#include "intel_hdcp.h"
> >  #include "intel_hotplug.h"
> >  #include "skl_scaler.h"
> >
> > @@ -371,7 +371,10 @@ static void intel_mst_disable_dp(struct
> > intel_atomic_state *state,
> >       drm_dbg_kms(&i915->drm, "active links %d\n",
> >                   intel_dp->active_mst_links);
> >
> > -     intel_hdcp_disable(intel_mst->connector);
> > +     if (connector->hdcp_helper_data)
> > +             drm_hdcp_helper_atomic_commit(connector-
> > >hdcp_helper_data,
> > +                                           &state->base,
> > +                                           &dig_port->hdcp_mutex);
> >
> >       drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state,
> >                             drm_atomic_get_mst_payload_state(mst_state,
> > connector->port));
> > @@ -579,11 +582,10 @@ static void intel_mst_enable_dp(struct
> > intel_atomic_state *state,
> >       intel_audio_codec_enable(encoder, pipe_config, conn_state);
> >
> >       /* Enable hdcp if it's desired */
> > -     if (conn_state->content_protection ==
> > -         DRM_MODE_CONTENT_PROTECTION_DESIRED)
> > -             intel_hdcp_enable(to_intel_connector(conn_state-
> > >connector),
> > -                               pipe_config,
> > -                               (u8)conn_state->hdcp_content_type);
> > +     if (connector->hdcp_helper_data)
> > +             drm_hdcp_helper_atomic_commit(connector-
> > >hdcp_helper_data,
> > +                                           &state->base,
> > +                                           &dig_port->hdcp_mutex);
> >  }
> >
> >  static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
> > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > index 61a862ae1f28..f09afbc9567b 100644
> > --- a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > @@ -140,67 +140,10 @@ static int intel_hdcp_prepare_streams(struct
> > intel_connector *connector)
> >       return 0;
> >  }
> >
> > -static
> > -bool intel_hdcp_is_ksv_valid(u8 *ksv)
> > -{
> > -     int i, ones = 0;
> > -     /* KSV has 20 1's and 20 0's */
> > -     for (i = 0; i < DRM_HDCP_KSV_LEN; i++)
> > -             ones += hweight8(ksv[i]);
> > -     if (ones != 20)
> > -             return false;
> > -
> > -     return true;
> > -}
> > -
> > -static
> > -int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port,
> > -                            const struct intel_hdcp_shim *shim, u8 *bksv)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     int ret, i, tries = 2;
> > -
> > -     /* HDCP spec states that we must retry the bksv if it is invalid */
> > -     for (i = 0; i < tries; i++) {
> > -             ret = shim->read_bksv(dig_port, bksv);
> > -             if (ret)
> > -                     return ret;
> > -             if (intel_hdcp_is_ksv_valid(bksv))
> > -                     break;
> > -     }
> > -     if (i == tries) {
> > -             drm_dbg_kms(&i915->drm, "Bksv is invalid\n");
> > -             return -ENODEV;
> > -     }
> > -
> > -     return 0;
> > -}
> > -
> > -/* Is HDCP1.4 capable on Platform and Sink */
> > -int intel_hdcp_capable(struct intel_connector *connector, bool *capable)
> > -{
> > -     struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> > -     const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> > -     u8 bksv[5];
> > -
> > -     *capable = false;
> > -
> > -     if (!shim)
> > -             return 0;
> > -
> > -     if (shim->hdcp_capable)
> > -             return shim->hdcp_capable(dig_port, capable);
> > -
> > -     if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> > -             *capable = true;
> > -
> > -     return 0;
> > -}
> > -
> >  /* Is HDCP2.2 capable on Platform and Sink */
> > -int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
> > +int intel_hdcp2_capable(struct drm_connector *drm_connector, bool
> > *capable)
> >  {
> > -     struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >       struct intel_hdcp *hdcp = &connector->hdcp;
> >
> > @@ -218,16 +161,26 @@ int intel_hdcp2_capable(struct intel_connector
> > *connector, bool *capable)
> >       }
> >       mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> >
> > -     /* Sink's capability for HDCP2.2 */
> > -     return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
>
> Did you miss adding the drm hdcp helper  here to check sink capability
>
Hey,
As the flow change and the protocol was split away from the full
implementation, the function here only checks if the driver supports
it. the call to sync happens in the helper.
> > +     return 0;
> >  }
> >
> > -static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv,
> > -                           enum transcoder cpu_transcoder, enum port
> > port)
> > +int intel_hdcp1_check_link(struct drm_connector *drm_connector)
> >  {
> > -     return intel_de_read(dev_priv,
> > -                          HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> > -            HDCP_STATUS_ENC;
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +     enum transcoder cpu_transcoder = connector-
> > >hdcp.cpu_transcoder;
> > +     enum port port = dig_port->base.port;
> > +     u32 val;
> > +
> > +     val = intel_de_read(dev_priv,
> > +                         HDCP_STATUS(dev_priv, cpu_transcoder, port));
> > +
> > +     if (val & HDCP_STATUS_ENC)
> > +             return 0;
> > +
> > +     return -EINVAL;
> >  }
> >
> >  static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
> > @@ -238,27 +191,6 @@ static bool intel_hdcp2_in_use(struct
> > drm_i915_private *dev_priv,
> >              LINK_ENCRYPTION_STATUS;
> >  }
> >
> > -static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *dig_port,
> > -                                 const struct intel_hdcp_shim *shim)
> > -{
> > -     int ret, read_ret;
> > -     bool ksv_ready;
> > -
> > -     /* Poll for ksv list ready (spec says max time allowed is 5s) */
> > -     ret = __wait_for(read_ret = shim->read_ksv_ready(dig_port,
> > -                                                      &ksv_ready),
> > -                      read_ret || ksv_ready, 5 * 1000 * 1000, 1000,
> > -                      100 * 1000);
> > -     if (ret)
> > -             return ret;
> > -     if (read_ret)
> > -             return read_ret;
> > -     if (!ksv_ready)
> > -             return -ETIMEDOUT;
> > -
> > -     return 0;
> > -}
> > -
> >  static bool hdcp_key_loadable(struct drm_i915_private *dev_priv)
> >  {
> >       enum i915_power_well_id id;
> > @@ -294,11 +226,18 @@ static void intel_hdcp_clear_keys(struct
> > drm_i915_private *dev_priv)
> >                      HDCP_KEY_LOAD_DONE | HDCP_KEY_LOAD_STATUS |
> > HDCP_FUSE_IN_PROGRESS | HDCP_FUSE_ERROR | HDCP_FUSE_DONE);
> >  }
> >
> > -static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
> > +int intel_hdcp_load_keys(struct drm_connector *drm_connector)
> >  {
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >       int ret;
> >       u32 val;
> >
> > +     if (!hdcp_key_loadable(dev_priv)) {
> > +             drm_err(&dev_priv->drm, "HDCP key Load is not
> > possible\n");
> > +             return -ENXIO;
> > +     }
> > +
> >       val = intel_de_read(dev_priv, HDCP_KEY_STATUS);
> >       if ((val & HDCP_KEY_LOAD_DONE) && (val &
> > HDCP_KEY_LOAD_STATUS))
> >               return 0;
> > @@ -308,8 +247,11 @@ static int intel_hdcp_load_keys(struct
> > drm_i915_private *dev_priv)
> >        * out of reset. So if Key is not already loaded, its an error state.
> >        */
> >       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
> > -             if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) &
> > HDCP_KEY_LOAD_DONE))
> > -                     return -ENXIO;
> > +             if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) &
> > +                   HDCP_KEY_LOAD_DONE)) {
> > +                     ret = -ENXIO;
> > +                     goto err;
> > +             }
> >
> >       /*
> >        * Initiate loading the HDCP key from fuses.
> > @@ -325,7 +267,7 @@ static int intel_hdcp_load_keys(struct
> > drm_i915_private *dev_priv)
> >                       drm_err(&dev_priv->drm,
> >                               "Failed to initiate HDCP key load (%d)\n",
> >                               ret);
> > -                     return ret;
> > +                     goto err;
> >               }
> >       } else {
> >               intel_de_write(dev_priv, HDCP_KEY_CONF,
> > HDCP_KEY_LOAD_TRIGGER);
> > @@ -335,15 +277,21 @@ static int intel_hdcp_load_keys(struct
> > drm_i915_private *dev_priv)
> >       ret = __intel_wait_for_register(&dev_priv->uncore,
> > HDCP_KEY_STATUS,
> >                                       HDCP_KEY_LOAD_DONE,
> > HDCP_KEY_LOAD_DONE,
> >                                       10, 1, &val);
> > -     if (ret)
> > -             return ret;
> > -     else if (!(val & HDCP_KEY_LOAD_STATUS))
> > -             return -ENXIO;
> > +     if (ret) {
> > +             goto err;
> > +     } else if (!(val & HDCP_KEY_LOAD_STATUS)) {
> > +             ret = -ENXIO;
> > +             goto err;
> > +     }
> >
> >       /* Send Aksv over to PCH display for use in authentication */
> >       intel_de_write(dev_priv, HDCP_KEY_CONF,
> > HDCP_AKSV_SEND_TRIGGER);
> >
> >       return 0;
> > +
> > +err:
> > +     intel_hdcp_clear_keys(dev_priv);
> > +     return ret;
> >  }
> >
> >  /* Returns updated SHA-1 index */
> > @@ -399,25 +347,21 @@ u32 intel_hdcp_get_repeater_ctl(struct
> > drm_i915_private *dev_priv,
> >       }
> >  }
> >
> > -static
> > -int intel_hdcp_validate_v_prime(struct intel_connector *connector,
> > -                             const struct intel_hdcp_shim *shim,
> > -                             u8 *ksv_fifo, u8 num_downstream, u8
> > *bstatus)
> > +int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
> > +                            u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
> > +                            u32 *v_prime)
> >  {
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> >       struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >       enum transcoder cpu_transcoder = connector-
> > >hdcp.cpu_transcoder;
> >       enum port port = dig_port->base.port;
> > -     u32 vprime, sha_text, sha_leftovers, rep_ctl;
> > +     u32 sha_text, sha_leftovers, rep_ctl;
> >       int ret, i, j, sha_idx;
> >
> >       /* Process V' values from the receiver */
> > -     for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
> > -             ret = shim->read_v_prime_part(dig_port, i, &vprime);
> > -             if (ret)
> > -                     return ret;
> > -             intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), vprime);
> > -     }
> > +     for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++)
> > +             intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i),
> > v_prime[i]);
> >
> >       /*
> >        * We need to write the concatenation of all device KSVs, BINFO (DP)
> > ||
> > @@ -642,131 +586,38 @@ int intel_hdcp_validate_v_prime(struct
> > intel_connector *connector,
> >       return 0;
> >  }
> >
> > -/* Implements Part 2 of the HDCP authorization procedure */
> > -static
> > -int intel_hdcp_auth_downstream(struct intel_connector *connector)
> > +int intel_hdcp1_store_receiver_info(struct drm_connector
> > *drm_connector,
> > +                                 u32 *ksv, u32 status, u8 caps,
> > +                                 bool repeater_present)
> >  {
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> >       struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -     const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> > -     u8 bstatus[2], num_downstream, *ksv_fifo;
> > -     int ret, i, tries = 3;
> > -
> > -     ret = intel_hdcp_poll_ksv_fifo(dig_port, shim);
> > -     if (ret) {
> > -             drm_dbg_kms(&dev_priv->drm,
> > -                         "KSV list failed to become ready (%d)\n", ret);
> > -             return ret;
> > -     }
> > -
> > -     ret = shim->read_bstatus(dig_port, bstatus);
> > -     if (ret)
> > -             return ret;
> > -
> > -     if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
> > -         DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
> > -             drm_dbg_kms(&dev_priv->drm, "Max Topology Limit
> > Exceeded\n");
> > -             return -EPERM;
> > -     }
> > -
> > -     /*
> > -      * When repeater reports 0 device count, HDCP1.4 spec allows
> > disabling
> > -      * the HDCP encryption. That implies that repeater can't have its own
> > -      * display. As there is no consumption of encrypted content in the
> > -      * repeater with 0 downstream devices, we are failing the
> > -      * authentication.
> > -      */
> > -     num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
> > -     if (num_downstream == 0) {
> > -             drm_dbg_kms(&dev_priv->drm,
> > -                         "Repeater with zero downstream devices\n");
> > -             return -EINVAL;
> > -     }
> > -
> > -     ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream,
> > GFP_KERNEL);
> > -     if (!ksv_fifo) {
> > -             drm_dbg_kms(&dev_priv->drm, "Out of mem: ksv_fifo\n");
> > -             return -ENOMEM;
> > -     }
> > -
> > -     ret = shim->read_ksv_fifo(dig_port, num_downstream, ksv_fifo);
> > -     if (ret)
> > -             goto err;
> > -
> > -     if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, ksv_fifo,
> > -                                     num_downstream) > 0) {
> > -             drm_err(&dev_priv->drm, "Revoked Ksv(s) in ksv_fifo\n");
> > -             ret = -EPERM;
> > -             goto err;
> > -     }
> > +     enum transcoder cpu_transcoder = connector-
> > >hdcp.cpu_transcoder;
> > +     enum port port = dig_port->base.port;
> >
> > -     /*
> > -      * When V prime mismatches, DP Spec mandates re-read of
> > -      * V prime atleast twice.
> > -      */
> > -     for (i = 0; i < tries; i++) {
> > -             ret = intel_hdcp_validate_v_prime(connector, shim,
> > -                                               ksv_fifo, num_downstream,
> > -                                               bstatus);
> > -             if (!ret)
> > -                     break;
> > -     }
> > +     intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder,
> > port),
> > +                    ksv[0]);
> > +     intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder,
> > port),
> > +                    ksv[1]);
> >
> > -     if (i == tries) {
> > -             drm_dbg_kms(&dev_priv->drm,
> > -                         "V Prime validation failed.(%d)\n", ret);
> > -             goto err;
> > -     }
> > +     if (repeater_present)
> > +             intel_de_write(dev_priv, HDCP_REP_CTL,
> > +                            intel_hdcp_get_repeater_ctl(
> > +                                    dev_priv, cpu_transcoder, port));
> >
> > -     drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (%d downstream
> > devices)\n",
> > -                 num_downstream);
> > -     ret = 0;
> > -err:
> > -     kfree(ksv_fifo);
> > -     return ret;
> > +     return 0;
> >  }
> >
> > -/* Implements Part 1 of the HDCP authorization procedure */
> > -static int intel_hdcp_auth(struct intel_connector *connector)
> > +int intel_hdcp1_read_an(struct drm_connector *drm_connector,
> > +                     struct drm_hdcp_an *an)
> >  {
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> >       struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > -     const struct intel_hdcp_shim *shim = hdcp->shim;
> >       enum transcoder cpu_transcoder = connector-
> > >hdcp.cpu_transcoder;
> >       enum port port = dig_port->base.port;
> > -     unsigned long r0_prime_gen_start;
> > -     int ret, i, tries = 2;
> > -     union {
> > -             u32 reg[2];
> > -             u8 shim[DRM_HDCP_AN_LEN];
> > -     } an;
> > -     union {
> > -             u32 reg[2];
> > -             u8 shim[DRM_HDCP_KSV_LEN];
> > -     } bksv;
> > -     union {
> > -             u32 reg;
> > -             u8 shim[DRM_HDCP_RI_LEN];
> > -     } ri;
> > -     bool repeater_present, hdcp_capable;
> > -
> > -     /*
> > -      * Detects whether the display is HDCP capable. Although we check
> > for
> > -      * valid Bksv below, the HDCP over DP spec requires that we check
> > -      * whether the display supports HDCP before we write An. For HDMI
> > -      * displays, this is not necessary.
> > -      */
> > -     if (shim->hdcp_capable) {
> > -             ret = shim->hdcp_capable(dig_port, &hdcp_capable);
> > -             if (ret)
> > -                     return ret;
> > -             if (!hdcp_capable) {
> > -                     drm_dbg_kms(&dev_priv->drm,
> > -                                 "Panel is not HDCP capable\n");
> > -                     return -EINVAL;
> > -             }
> > -     }
> > +     int i;
> >
> >       /* Initialize An with 2 random values and acquire it */
> >       for (i = 0; i < 2; i++)
> > @@ -784,92 +635,81 @@ static int intel_hdcp_auth(struct intel_connector
> > *connector)
> >               return -ETIMEDOUT;
> >       }
> >
> > -     an.reg[0] = intel_de_read(dev_priv,
> > -                               HDCP_ANLO(dev_priv, cpu_transcoder,
> > port));
> > -     an.reg[1] = intel_de_read(dev_priv,
> > -                               HDCP_ANHI(dev_priv, cpu_transcoder,
> > port));
> > -     ret = shim->write_an_aksv(dig_port, an.shim);
> > -     if (ret)
> > -             return ret;
> > +     an->words[0] = intel_de_read(dev_priv,
> > +                                  HDCP_ANLO(dev_priv, cpu_transcoder,
> > port));
> > +     an->words[1] = intel_de_read(dev_priv,
> > +                                  HDCP_ANHI(dev_priv, cpu_transcoder,
> > port));
> >
> > -     r0_prime_gen_start = jiffies;
> > -
> > -     memset(&bksv, 0, sizeof(bksv));
> > -
> > -     ret = intel_hdcp_read_valid_bksv(dig_port, shim, bksv.shim);
> > -     if (ret < 0)
> > -             return ret;
> > -
> > -     if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, bksv.shim, 1) >
> > 0) {
> > -             drm_err(&dev_priv->drm, "BKSV is revoked\n");
> > -             return -EPERM;
> > -     }
> > -
> > -     intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder,
> > port),
> > -                    bksv.reg[0]);
> > -     intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder,
> > port),
> > -                    bksv.reg[1]);
> > -
> > -     ret = shim->repeater_present(dig_port, &repeater_present);
> > -     if (ret)
> > -             return ret;
> > -     if (repeater_present)
> > -             intel_de_write(dev_priv, HDCP_REP_CTL,
> > -                            intel_hdcp_get_repeater_ctl(dev_priv,
> > cpu_transcoder, port));
> > +     return 0;
> > +}
> >
> > -     ret = shim->toggle_signalling(dig_port, cpu_transcoder, true);
> > -     if (ret)
> > -             return ret;
> > +int intel_hdcp1_enable_encryption(struct drm_connector
> > *drm_connector)
> > +{
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +     enum transcoder cpu_transcoder = connector-
> > >hdcp.cpu_transcoder;
> > +     enum port port = dig_port->base.port;
> >
> >       intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder,
> > port),
> >                      HDCP_CONF_AUTH_AND_ENC);
> >
> > +     return 0;
> > +}
> > +
> > +int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector)
> > +{
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +     enum transcoder cpu_transcoder = connector-
> > >hdcp.cpu_transcoder;
> > +     enum port port = dig_port->base.port;
> > +
> >       /* Wait for R0 ready */
> > -     if (wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> > cpu_transcoder, port)) &
> > -                  (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), 1)) {
> > +     if (wait_for((intel_de_read(dev_priv,
> > +                                 HDCP_STATUS(dev_priv, cpu_transcoder,
> > +                                             port))) &
> > +                          (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC),
> > +                  1)) {
>
> Alignment here seem wrong
>
> >               drm_err(&dev_priv->drm, "Timed out waiting for R0
> > ready\n");
> >               return -ETIMEDOUT;
> >       }
> >
> > -     /*
> > -      * Wait for R0' to become available. The spec says 100ms from Aksv,
> > but
> > -      * some monitors can take longer than this. We'll set the timeout at
> > -      * 300ms just to be sure.
> > -      *
> > -      * On DP, there's an R0_READY bit available but no such bit
> > -      * exists on HDMI. Since the upper-bound is the same, we'll just do
> > -      * the stupid thing instead of polling on one and not the other.
> > -      */
> > -     wait_remaining_ms_from_jiffies(r0_prime_gen_start, 300);
> > -
> > -     tries = 3;
> > +     return 0;
> > +}
> >
> > -     /*
> > -      * DP HDCP Spec mandates the two more reattempt to read R0,
> > incase
> > -      * of R0 mismatch.
> > -      */
> > -     for (i = 0; i < tries; i++) {
> > -             ri.reg = 0;
> > -             ret = shim->read_ri_prime(dig_port, ri.shim);
> > -             if (ret)
> > -                     return ret;
> > -             intel_de_write(dev_priv,
> > -                            HDCP_RPRIME(dev_priv, cpu_transcoder, port),
> > -                            ri.reg);
> > +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32
> > ri_prime)
> > +{
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +     enum transcoder cpu_transcoder = connector-
> > >hdcp.cpu_transcoder;
> > +     enum port port = dig_port->base.port;
> >
> > -             /* Wait for Ri prime match */
> > -             if (!wait_for(intel_de_read(dev_priv,
> > HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> > -                           (HDCP_STATUS_RI_MATCH |
> > HDCP_STATUS_ENC), 1))
> > -                     break;
> > -     }
> > +     intel_de_write(dev_priv, HDCP_RPRIME(dev_priv, cpu_transcoder,
> > port),
> > +                    ri_prime);
> >
> > -     if (i == tries) {
> > -             drm_dbg_kms(&dev_priv->drm,
> > -                         "Timed out waiting for Ri prime match (%x)\n",
> > -                         intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> > -                                       cpu_transcoder, port)));
> > +     /* Wait for Ri prime match */
> > +     if (wait_for(intel_de_read(dev_priv,
> > +                                HDCP_STATUS(dev_priv, cpu_transcoder,
> > port)) &
> > +                          (HDCP_STATUS_RI_MATCH |
> > HDCP_STATUS_ENC),
> > +                  1))
> >               return -ETIMEDOUT;
> > -     }
> > +
> > +     return 0;
> > +}
> > +
> > +int intel_hdcp1_post_encryption(struct drm_connector *drm_connector)
> > +{
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +     enum transcoder cpu_transcoder = connector-
> > >hdcp.cpu_transcoder;
> > +     enum port port = dig_port->base.port;
> >
> >       /* Wait for encryption confirmation */
> >       if (intel_de_wait_for_set(dev_priv,
> > @@ -880,56 +720,22 @@ static int intel_hdcp_auth(struct intel_connector
> > *connector)
> >               return -ETIMEDOUT;
> >       }
> >
> > -     /* DP MST Auth Part 1 Step 2.a and Step 2.b */
> > -     if (shim->stream_encryption) {
> > -             ret = shim->stream_encryption(connector, true);
> > -             if (ret) {
> > -                     drm_err(&dev_priv->drm, "[%s:%d] Failed to enable
> > HDCP 1.4 stream enc\n",
> > -                             connector->base.name, connector-
> > >base.base.id);
> > -                     return ret;
> > -             }
> > -             drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s
> > stream encrypted\n",
> > -                         transcoder_name(hdcp->stream_transcoder));
> > -     }
> > -
> > -     if (repeater_present)
> > -             return intel_hdcp_auth_downstream(connector);
> > -
> > -     drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (no repeater
> > present)\n");
> >       return 0;
> >  }
> >
> > -static int _intel_hdcp_disable(struct intel_connector *connector)
> > +int intel_hdcp1_disable(struct drm_connector *drm_connector)
> >  {
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> >       struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >       struct intel_hdcp *hdcp = &connector->hdcp;
> >       enum port port = dig_port->base.port;
> >       enum transcoder cpu_transcoder = hdcp->cpu_transcoder;
> >       u32 repeater_ctl;
> > -     int ret;
> >
> >       drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being
> > disabled...\n",
> >                   connector->base.name, connector->base.base.id);
> >
> > -     if (hdcp->shim->stream_encryption) {
> > -             ret = hdcp->shim->stream_encryption(connector, false);
> > -             if (ret) {
> > -                     drm_err(&dev_priv->drm, "[%s:%d] Failed to disable
> > HDCP 1.4 stream enc\n",
> > -                             connector->base.name, connector-
> > >base.base.id);
> > -                     return ret;
> > -             }
> > -             drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s
> > stream encryption disabled\n",
> > -                         transcoder_name(hdcp->stream_transcoder));
> > -             /*
> > -              * If there are other connectors on this port using HDCP,
> > -              * don't disable it until it disabled HDCP encryption for
> > -              * all connectors in MST topology.
> > -              */
> > -             if (dig_port->num_hdcp_streams > 0)
> > -                     return 0;
> > -     }
> > -
> >       hdcp->hdcp_encrypted = false;
> >       intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder,
> > port), 0);
> >       if (intel_de_wait_for_clear(dev_priv,
> > @@ -945,190 +751,9 @@ static int _intel_hdcp_disable(struct
> > intel_connector *connector)
> >       intel_de_write(dev_priv, HDCP_REP_CTL,
> >                      intel_de_read(dev_priv, HDCP_REP_CTL) &
> > ~repeater_ctl);
> >
> > -     ret = hdcp->shim->toggle_signalling(dig_port, cpu_transcoder,
> > false);
> > -     if (ret) {
> > -             drm_err(&dev_priv->drm, "Failed to disable HDCP
> > signalling\n");
> > -             return ret;
> > -     }
> > -
> > -     drm_dbg_kms(&dev_priv->drm, "HDCP is disabled\n");
> >       return 0;
> >  }
> >
> > -static int _intel_hdcp_enable(struct intel_connector *connector)
> > -{
> > -     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > -     int i, ret, tries = 3;
> > -
> > -     drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being
> > enabled...\n",
> > -                 connector->base.name, connector->base.base.id);
> > -
> > -     if (!hdcp_key_loadable(dev_priv)) {
> > -             drm_err(&dev_priv->drm, "HDCP key Load is not
> > possible\n");
> > -             return -ENXIO;
> > -     }
> > -
> > -     for (i = 0; i < KEY_LOAD_TRIES; i++) {
> > -             ret = intel_hdcp_load_keys(dev_priv);
> > -             if (!ret)
> > -                     break;
> > -             intel_hdcp_clear_keys(dev_priv);
> > -     }
> > -     if (ret) {
> > -             drm_err(&dev_priv->drm, "Could not load HDCP keys,
> > (%d)\n",
> > -                     ret);
> > -             return ret;
> > -     }
> > -
> > -     /* Incase of authentication failures, HDCP spec expects reauth. */
> > -     for (i = 0; i < tries; i++) {
> > -             ret = intel_hdcp_auth(connector);
> > -             if (!ret) {
> > -                     hdcp->hdcp_encrypted = true;
> > -                     return 0;
> > -             }
> > -
> > -             drm_dbg_kms(&dev_priv->drm, "HDCP Auth failure (%d)\n",
> > ret);
> > -
> > -             /* Ensuring HDCP encryption and signalling are stopped. */
> > -             _intel_hdcp_disable(connector);
> > -     }
> > -
> > -     drm_dbg_kms(&dev_priv->drm,
> > -                 "HDCP authentication failed (%d tries/%d)\n", tries, ret);
> > -     return ret;
> > -}
> > -
> > -static struct intel_connector *intel_hdcp_to_connector(struct intel_hdcp
> > *hdcp)
> > -{
> > -     return container_of(hdcp, struct intel_connector, hdcp);
> > -}
> > -
> > -static void intel_hdcp_update_value(struct intel_connector *connector,
> > -                                 u64 value, bool update_property)
> > -{
> > -     struct drm_device *dev = connector->base.dev;
> > -     struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > -
> > -     drm_WARN_ON(connector->base.dev, !mutex_is_locked(&hdcp-
> > >mutex));
> > -
> > -     if (hdcp->value == value)
> > -             return;
> > -
> > -     drm_WARN_ON(dev, !mutex_is_locked(&dig_port->hdcp_mutex));
> > -
> > -     if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> > -             if (!drm_WARN_ON(dev, dig_port->num_hdcp_streams ==
> > 0))
> > -                     dig_port->num_hdcp_streams--;
> > -     } else if (value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> > -             dig_port->num_hdcp_streams++;
> > -     }
> > -
> > -     hdcp->value = value;
> > -     if (update_property) {
> > -             drm_connector_get(&connector->base);
> > -             schedule_work(&hdcp->prop_work);
> > -     }
> > -}
> > -
> > -/* Implements Part 3 of the HDCP authorization procedure */
> > -static int intel_hdcp_check_link(struct intel_connector *connector)
> > -{
> > -     struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> > -     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > -     enum port port = dig_port->base.port;
> > -     enum transcoder cpu_transcoder;
> > -     int ret = 0;
> > -
> > -     mutex_lock(&hdcp->mutex);
> > -     mutex_lock(&dig_port->hdcp_mutex);
> > -
> > -     cpu_transcoder = hdcp->cpu_transcoder;
> > -
> > -     /* Check_link valid only when HDCP1.4 is enabled */
> > -     if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED
> > ||
> > -         !hdcp->hdcp_encrypted) {
> > -             ret = -EINVAL;
> > -             goto out;
> > -     }
> > -
> > -     if (drm_WARN_ON(&dev_priv->drm,
> > -                     !intel_hdcp_in_use(dev_priv, cpu_transcoder,
> > port))) {
> > -             drm_err(&dev_priv->drm,
> > -                     "%s:%d HDCP link stopped encryption,%x\n",
> > -                     connector->base.name, connector->base.base.id,
> > -                     intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> > cpu_transcoder, port)));
> > -             ret = -ENXIO;
> > -             intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > -                                     true);
> > -             goto out;
> > -     }
> > -
> > -     if (hdcp->shim->check_link(dig_port, connector)) {
> > -             if (hdcp->value !=
> > DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> > -                     intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_ENABLED, true);
> > -             }
> > -             goto out;
> > -     }
> > -
> > -     drm_dbg_kms(&dev_priv->drm,
> > -                 "[%s:%d] HDCP link failed, retrying authentication\n",
> > -                 connector->base.name, connector->base.base.id);
> > -
> > -     ret = _intel_hdcp_disable(connector);
> > -     if (ret) {
> > -             drm_err(&dev_priv->drm, "Failed to disable hdcp (%d)\n",
> > ret);
> > -             intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > -                                     true);
> > -             goto out;
> > -     }
> > -
> > -     ret = _intel_hdcp_enable(connector);
> > -     if (ret) {
> > -             drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n",
> > ret);
> > -             intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > -                                     true);
> > -             goto out;
> > -     }
> > -
> > -out:
> > -     mutex_unlock(&dig_port->hdcp_mutex);
> > -     mutex_unlock(&hdcp->mutex);
> > -     return ret;
> > -}
> > -
> > -static void intel_hdcp_prop_work(struct work_struct *work)
> > -{
> > -     struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp,
> > -                                            prop_work);
> > -     struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
> > -     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -
> > -     drm_modeset_lock(&dev_priv-
> > >drm.mode_config.connection_mutex, NULL);
> > -     mutex_lock(&hdcp->mutex);
> > -
> > -     /*
> > -      * This worker is only used to flip between ENABLED/DESIRED. Either
> > of
> > -      * those to UNDESIRED is handled by core. If value == UNDESIRED,
> > -      * we're running just after hdcp has been disabled, so just exit
> > -      */
> > -     if (hdcp->value !=
> > DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> > -             drm_hdcp_update_content_protection(&connector->base,
> > -                                                hdcp->value);
> > -
> > -     mutex_unlock(&hdcp->mutex);
> > -     drm_modeset_unlock(&dev_priv-
> > >drm.mode_config.connection_mutex);
> > -
> > -     drm_connector_put(&connector->base);
> > -}
> > -
> >  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port
> > port)
> >  {
> >       return RUNTIME_INFO(dev_priv)->has_hdcp &&
> > @@ -1961,8 +1586,9 @@ static int hdcp2_authenticate_and_encrypt(struct
> > intel_connector *connector)
> >       return ret;
> >  }
> >
> > -static int _intel_hdcp2_enable(struct intel_connector *connector)
> > +int intel_hdcp2_enable(struct drm_connector *drm_connector)
> >  {
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> >       struct drm_i915_private *i915 = to_i915(connector->base.dev);
> >       struct intel_hdcp *hdcp = &connector->hdcp;
> >       int ret;
> > @@ -2024,9 +1650,15 @@ _intel_hdcp2_disable(struct intel_connector
> > *connector, bool hdcp2_link_recovery
> >       return ret;
> >  }
> >
> > +int intel_hdcp2_disable(struct drm_connector *drm_connector)
> > +{
> > +     return _intel_hdcp2_disable(to_intel_connector(drm_connector),
> > false);
> > +}
> > +
> >  /* Implements the Link Integrity Check for HDCP2.2 */
> > -static int intel_hdcp2_check_link(struct intel_connector *connector)
> > +int intel_hdcp2_check_link(struct drm_connector *drm_connector)
> >  {
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> >       struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >       struct intel_hdcp *hdcp = &connector->hdcp;
> > @@ -2034,109 +1666,39 @@ static int intel_hdcp2_check_link(struct
> > intel_connector *connector)
> >       enum transcoder cpu_transcoder;
> >       int ret = 0;
> >
> > -     mutex_lock(&hdcp->mutex);
> > -     mutex_lock(&dig_port->hdcp_mutex);
> >       cpu_transcoder = hdcp->cpu_transcoder;
> >
> >       /* hdcp2_check_link is expected only when HDCP2.2 is Enabled */
> > -     if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED
> > ||
> > -         !hdcp->hdcp2_encrypted) {
> > -             ret = -EINVAL;
> > -             goto out;
> > -     }
> > +     if (!hdcp->hdcp2_encrypted)
> > +             return -EINVAL;
> >
> >       if (drm_WARN_ON(&dev_priv->drm,
> >                       !intel_hdcp2_in_use(dev_priv, cpu_transcoder,
> > port))) {
> >               drm_err(&dev_priv->drm,
> >                       "HDCP2.2 link stopped the encryption, %x\n",
> >                       intel_de_read(dev_priv, HDCP2_STATUS(dev_priv,
> > cpu_transcoder, port)));
> > -             ret = -ENXIO;
> > -             _intel_hdcp2_disable(connector, true);
> > -             intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > -                                     true);
> > -             goto out;
> > +             return -ENXIO;
> >       }
> >
> >       ret = hdcp->shim->check_2_2_link(dig_port, connector);
> > -     if (ret == HDCP_LINK_PROTECTED) {
> > -             if (hdcp->value !=
> > DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> > -                     intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_ENABLED,
> > -                                     true);
> > -             }
> > -             goto out;
> > -     }
> > +     if (ret == HDCP_LINK_PROTECTED)
> > +             return 0;
> >
> >       if (ret == HDCP_TOPOLOGY_CHANGE) {
> > -             if (hdcp->value ==
> > DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> > -                     goto out;
> > -
> >               drm_dbg_kms(&dev_priv->drm,
> >                           "HDCP2.2 Downstream topology change\n");
> >               ret = hdcp2_authenticate_repeater_topology(connector);
> > -             if (!ret) {
> > -                     intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_ENABLED,
> > -                                     true);
> > -                     goto out;
> > -             }
> > -             drm_dbg_kms(&dev_priv->drm,
> > -                         "[%s:%d] Repeater topology auth failed.(%d)\n",
> > -                         connector->base.name, connector->base.base.id,
> > -                         ret);
> > -     } else {
> > -             drm_dbg_kms(&dev_priv->drm,
> > -                         "[%s:%d] HDCP2.2 link failed, retrying auth\n",
> > -                         connector->base.name, connector->base.base.id);
> > -     }
> > -
> > -     ret = _intel_hdcp2_disable(connector, true);
> > -     if (ret) {
> > -             drm_err(&dev_priv->drm,
> > -                     "[%s:%d] Failed to disable hdcp2.2 (%d)\n",
> > -                     connector->base.name, connector->base.base.id,
> > ret);
> > -             intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
> > -             goto out;
> > -     }
> > +             if (!ret)
> > +                     return 0;
> >
> > -     ret = _intel_hdcp2_enable(connector);
> > -     if (ret) {
> >               drm_dbg_kms(&dev_priv->drm,
> > -                         "[%s:%d] Failed to enable hdcp2.2 (%d)\n",
> > -                         connector->base.name, connector->base.base.id,
> > -                         ret);
> > -             intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > -                                     true);
> > -             goto out;
> > +                         "[%s:%d] Repeater topology auth failed.(%d)\n",
> > +                         connector->base.name, connector->base.base.id,
> > ret);
> >       }
> >
> > -out:
> > -     mutex_unlock(&dig_port->hdcp_mutex);
> > -     mutex_unlock(&hdcp->mutex);
> >       return ret;
> >  }
>
> Wouldn't it be better if we used that value in drm_hdcp_helper_data rather than getting rid of all these checks
> As they are needed same thing for other places where the checks are removed because value isn't present in
> Intel_hdcp structure
>
I'm not 100% sure I get what you're referring to, but basically the
work has been split between the helper and the driver. the intel
specific protocol is what remains in the driver. Everything else is
handled in the helper.
> >
> > -static void intel_hdcp_check_work(struct work_struct *work)
> > -{
> > -     struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
> > -                                            struct intel_hdcp,
> > -                                            check_work);
> > -     struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
> > -
> > -     if (drm_connector_is_unregistered(&connector->base))
> > -             return;
> > -
> > -     if (!intel_hdcp2_check_link(connector))
> > -             schedule_delayed_work(&hdcp->check_work,
> > -                                   DRM_HDCP2_CHECK_PERIOD_MS);
> > -     else if (!intel_hdcp_check_link(connector))
> > -             schedule_delayed_work(&hdcp->check_work,
> > -                                   DRM_HDCP_CHECK_PERIOD_MS);
> > -}
> > -
> >  static int i915_hdcp_component_bind(struct device *i915_kdev,
> >                                   struct device *mei_kdev, void *data)
> >  {
> > @@ -2189,22 +1751,28 @@ static enum mei_fw_tc
> > intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
> >       }
> >  }
> >
> > -static int
> > -_intel_hdcp_setup(struct intel_connector *connector,
> > -               const struct intel_crtc_state *pipe_config, u8 content_type)
> > +int intel_hdcp_setup(struct drm_connector *connector,
> > +                  struct drm_atomic_state *state)
> >  {
> > -     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -     struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > +     struct drm_i915_private *dev_priv = to_i915(connector->dev);
> > +     struct intel_connector *intel_connector =
> > to_intel_connector(connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(intel_connector);
> > +     struct drm_connector_state *conn_state;
> > +     struct drm_crtc_state *crtc_state;
> > +     struct intel_crtc_state *pipe_config;
> > +     struct intel_hdcp *hdcp = &intel_connector->hdcp;
> >       int ret = 0;
> >
> > -     if (!connector->encoder) {
> > +     if (!intel_connector->encoder) {
> >               drm_err(&dev_priv->drm, "[%s:%d] encoder is not
> > initialized\n",
> > -                     connector->base.name, connector->base.base.id);
> > +                     connector->name, connector->base.id);
> >               return -ENODEV;
> >       }
> >
> > -     hdcp->content_type = content_type;
> > +     conn_state = drm_atomic_get_new_connector_state(state,
> > connector);
> > +     crtc_state = drm_atomic_get_new_crtc_state(state, conn_state-
> > >crtc);
> > +     pipe_config = to_intel_crtc_state(crtc_state);
> >
> >       if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
> >               hdcp->cpu_transcoder = pipe_config-
> > >mst_master_transcoder;
> > @@ -2321,7 +1889,6 @@ int intel_hdcp_init(struct intel_connector
> > *connector,
> >  {
> >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> >       struct intel_hdcp *hdcp = &connector->hdcp;
> > -     int ret;
> >
> >       if (!shim)
> >               return -EINVAL;
> > @@ -2329,174 +1896,12 @@ int intel_hdcp_init(struct intel_connector
> > *connector,
> >       if (is_hdcp2_supported(dev_priv))
> >               intel_hdcp2_init(connector, dig_port, shim);
> >
> > -     ret =
> > -     drm_connector_attach_content_protection_property(&connector-
> > >base,
> > -                                                      hdcp-
> > >hdcp2_supported);
> > -     if (ret) {
> > -             hdcp->hdcp2_supported = false;
> > -             kfree(dig_port->hdcp_port_data.streams);
> > -             return ret;
> > -     }
> > -
> >       hdcp->shim = shim;
> > -     mutex_init(&hdcp->mutex);
>
> I don't think removing mutex is a good idea
>
The mutex is just moved to the drm hdpc helper. Is there any race
condition that you might be missing?
> Regards,
> Suraj Kandpal
> > -     INIT_DELAYED_WORK(&hdcp->check_work,
> > intel_hdcp_check_work);
> > -     INIT_WORK(&hdcp->prop_work, intel_hdcp_prop_work);
> >       init_waitqueue_head(&hdcp->cp_irq_queue);
> >
> >       return 0;
> >  }
> >
> > -int intel_hdcp_enable(struct intel_connector *connector,
> > -                   const struct intel_crtc_state *pipe_config, u8
> > content_type)
> > -{
> > -     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > -     struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > -     unsigned long check_link_interval =
> > DRM_HDCP_CHECK_PERIOD_MS;
> > -     bool capable;
> > -     int ret = -EINVAL;
> > -
> > -     if (!hdcp->shim)
> > -             return -ENOENT;
> > -
> > -     mutex_lock(&hdcp->mutex);
> > -     mutex_lock(&dig_port->hdcp_mutex);
> > -     drm_WARN_ON(&dev_priv->drm,
> > -                 hdcp->value ==
> > DRM_MODE_CONTENT_PROTECTION_ENABLED);
> > -
> > -     ret = _intel_hdcp_setup(connector, pipe_config, content_type);
> > -     if (ret)
> > -             goto out;
> > -
> > -     /*
> > -      * Considering that HDCP2.2 is more secure than HDCP1.4, If the
> > setup
> > -      * is capable of HDCP2.2, it is preferred to use HDCP2.2.
> > -      */
> > -     ret = intel_hdcp2_capable(connector, &capable);
> > -     if (capable) {
> > -             ret = _intel_hdcp2_enable(connector);
> > -             if (!ret) {
> > -                     check_link_interval =
> > DRM_HDCP2_CHECK_PERIOD_MS;
> > -                     goto out;
> > -             }
> > -     }
> > -
> > -     /*
> > -      * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
> > -      * be attempted.
> > -      */
> > -     ret = intel_hdcp_capable(connector, &capable);
> > -     if (ret)
> > -             goto out;
> > -
> > -     if (capable && hdcp->content_type !=
> > DRM_MODE_HDCP_CONTENT_TYPE1)
> > -             ret = _intel_hdcp_enable(connector);
> > -
> > -out:
> > -     if (!ret) {
> > -             schedule_delayed_work(&hdcp->check_work,
> > check_link_interval);
> > -             intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_ENABLED,
> > -                                     true);
> > -     }
> > -
> > -     mutex_unlock(&dig_port->hdcp_mutex);
> > -     mutex_unlock(&hdcp->mutex);
> > -     return ret;
> > -}
> > -
> > -int intel_hdcp_disable(struct intel_connector *connector)
> > -{
> > -     struct intel_digital_port *dig_port =
> > intel_attached_dig_port(connector);
> > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > -     int ret = 0;
> > -
> > -     if (!hdcp->shim)
> > -             return -ENOENT;
> > -
> > -     mutex_lock(&hdcp->mutex);
> > -     mutex_lock(&dig_port->hdcp_mutex);
> > -
> > -     if (hdcp->value ==
> > DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> > -             goto out;
> > -
> > -     intel_hdcp_update_value(connector,
> > -
> >       DRM_MODE_CONTENT_PROTECTION_UNDESIRED, false);
> > -     if (hdcp->hdcp2_encrypted)
> > -             ret = _intel_hdcp2_disable(connector, false);
> > -     else if (hdcp->hdcp_encrypted)
> > -             ret = _intel_hdcp_disable(connector);
> > -
> > -out:
> > -     mutex_unlock(&dig_port->hdcp_mutex);
> > -     mutex_unlock(&hdcp->mutex);
> > -     cancel_delayed_work_sync(&hdcp->check_work);
> > -     return ret;
> > -}
> > -
> > -void intel_hdcp_update_pipe(struct intel_atomic_state *state,
> > -                         struct intel_encoder *encoder,
> > -                         const struct intel_crtc_state *crtc_state,
> > -                         const struct drm_connector_state *conn_state)
> > -{
> > -     struct intel_connector *connector =
> > -                             to_intel_connector(conn_state->connector);
> > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > -     bool content_protection_type_changed, desired_and_not_enabled
> > = false;
> > -
> > -     if (!connector->hdcp.shim)
> > -             return;
> > -
> > -     content_protection_type_changed =
> > -             (conn_state->hdcp_content_type != hdcp->content_type
> > &&
> > -              conn_state->content_protection !=
> > -              DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
> > -
> > -     /*
> > -      * During the HDCP encryption session if Type change is requested,
> > -      * disable the HDCP and reenable it with new TYPE value.
> > -      */
> > -     if (conn_state->content_protection ==
> > -         DRM_MODE_CONTENT_PROTECTION_UNDESIRED ||
> > -         content_protection_type_changed)
> > -             intel_hdcp_disable(connector);
> > -
> > -     /*
> > -      * Mark the hdcp state as DESIRED after the hdcp disable of type
> > -      * change procedure.
> > -      */
> > -     if (content_protection_type_changed) {
> > -             mutex_lock(&hdcp->mutex);
> > -             hdcp->value =
> > DRM_MODE_CONTENT_PROTECTION_DESIRED;
> > -             drm_connector_get(&connector->base);
> > -             schedule_work(&hdcp->prop_work);
> > -             mutex_unlock(&hdcp->mutex);
> > -     }
> > -
> > -     if (conn_state->content_protection ==
> > -         DRM_MODE_CONTENT_PROTECTION_DESIRED) {
> > -             mutex_lock(&hdcp->mutex);
> > -             /* Avoid enabling hdcp, if it already ENABLED */
> > -             desired_and_not_enabled =
> > -                     hdcp->value !=
> > DRM_MODE_CONTENT_PROTECTION_ENABLED;
> > -             mutex_unlock(&hdcp->mutex);
> > -             /*
> > -              * If HDCP already ENABLED and CP property is DESIRED,
> > schedule
> > -              * prop_work to update correct CP property to user space.
> > -              */
> > -             if (!desired_and_not_enabled &&
> > !content_protection_type_changed) {
> > -                     drm_connector_get(&connector->base);
> > -                     schedule_work(&hdcp->prop_work);
> > -             }
> > -     }
> > -
> > -     if (desired_and_not_enabled || content_protection_type_changed)
> > -             intel_hdcp_enable(connector,
> > -                               crtc_state,
> > -                               (u8)conn_state->hdcp_content_type);
> > -}
> > -
> >  void intel_hdcp_component_fini(struct drm_i915_private *dev_priv)
> >  {
> >       mutex_lock(&dev_priv->display.hdcp.comp_mutex);
> > @@ -2518,33 +1923,8 @@ void intel_hdcp_cleanup(struct intel_connector
> > *connector)
> >       if (!hdcp->shim)
> >               return;
> >
> > -     /*
> > -      * If the connector is registered, it's possible userspace could kick
> > -      * off another HDCP enable, which would re-spawn the workers.
> > -      */
> > -     drm_WARN_ON(connector->base.dev,
> > -             connector->base.registration_state ==
> > DRM_CONNECTOR_REGISTERED);
> > -
> > -     /*
> > -      * Now that the connector is not registered, check_work won't be
> > run,
> > -      * but cancel any outstanding instances of it
> > -      */
> > -     cancel_delayed_work_sync(&hdcp->check_work);
> > -
> > -     /*
> > -      * We don't cancel prop_work in the same way as check_work since it
> > -      * requires connection_mutex which could be held while calling this
> > -      * function. Instead, we rely on the connector references grabbed
> > before
> > -      * scheduling prop_work to ensure the connector is alive when
> > prop_work
> > -      * is run. So if we're in the destroy path (which is where this
> > -      * function should be called), we're "guaranteed" that prop_work is
> > not
> > -      * active (tl;dr This Should Never Happen).
> > -      */
> > -     drm_WARN_ON(connector->base.dev, work_pending(&hdcp-
> > >prop_work));
> > -
> > -     mutex_lock(&hdcp->mutex);
> > +     drm_hdcp_helper_destroy(connector->hdcp_helper_data);
> >       hdcp->shim = NULL;
> > -     mutex_unlock(&hdcp->mutex);
> >  }
> >
> >  /* Handles the CP_IRQ raised from the DP HDCP sink */
> > @@ -2558,5 +1938,5 @@ void intel_hdcp_handle_cp_irq(struct
> > intel_connector *connector)
> >       atomic_inc(&connector->hdcp.cp_irq_count);
> >       wake_up_all(&connector->hdcp.cp_irq_queue);
> >
> > -     schedule_delayed_work(&hdcp->check_work, 0);
> > +     drm_hdcp_helper_schedule_hdcp_check(connector-
> > >hdcp_helper_data);
> >  }
> > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > index f06f6e5a2b1a..49b9d79eb30a 100644
> > --- a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > @@ -10,8 +10,10 @@
> >
> >  #define HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS        50
> >
> > +struct drm_atomic_state;
> >  struct drm_connector;
> >  struct drm_connector_state;
> > +struct drm_hdcp_an;
> >  struct drm_i915_private;
> >  struct intel_atomic_state;
> >  struct intel_connector;
> > @@ -25,16 +27,29 @@ enum transcoder;
> >  int intel_hdcp_init(struct intel_connector *connector,
> >                   struct intel_digital_port *dig_port,
> >                   const struct intel_hdcp_shim *hdcp_shim);
> > -int intel_hdcp_enable(struct intel_connector *connector,
> > -                   const struct intel_crtc_state *pipe_config, u8
> > content_type);
> > -int intel_hdcp_disable(struct intel_connector *connector);
> > -void intel_hdcp_update_pipe(struct intel_atomic_state *state,
> > -                         struct intel_encoder *encoder,
> > -                         const struct intel_crtc_state *crtc_state,
> > -                         const struct drm_connector_state *conn_state);
> > +int intel_hdcp_setup(struct drm_connector *drm_connector,
> > +                  struct drm_atomic_state *state);
> > +int intel_hdcp_load_keys(struct drm_connector *drm_connector);
> >  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port
> > port);
> >  int intel_hdcp_capable(struct intel_connector *connector, bool *capable);
> > -int intel_hdcp2_capable(struct intel_connector *connector, bool *capable);
> > +int intel_hdcp2_capable(struct drm_connector *drm_connector, bool
> > *capable);
> > +int intel_hdcp2_enable(struct drm_connector *drm_connector);
> > +int intel_hdcp2_disable(struct drm_connector *drm_connector);
> > +int intel_hdcp2_check_link(struct drm_connector *drm_connector);
> > +int intel_hdcp1_store_receiver_info(struct drm_connector
> > *drm_connector,
> > +                                 u32 *ksv, u32 status, u8 caps,
> > +                                 bool repeater_present);
> > +int intel_hdcp1_read_an(struct drm_connector *drm_connector,
> > +                     struct drm_hdcp_an *an);
> > +int intel_hdcp1_enable_encryption(struct drm_connector
> > *drm_connector);
> > +int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector);
> > +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32
> > ri_prime);
> > +int intel_hdcp1_post_encryption(struct drm_connector *drm_connector);
> > +int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
> > +                            u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
> > +                            u32 *v_prime);
> > +int intel_hdcp1_check_link(struct drm_connector *drm_connector);
> > +int intel_hdcp1_disable(struct drm_connector *drm_connector);
> >  void intel_hdcp_component_init(struct drm_i915_private *dev_priv);
> >  void intel_hdcp_component_fini(struct drm_i915_private *dev_priv);
> >  void intel_hdcp_cleanup(struct intel_connector *connector);
> > diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c
> > b/drivers/gpu/drm/i915/display/intel_hdmi.c
> > index 7816b2a33fee..c33cfedb2e19 100644
> > --- a/drivers/gpu/drm/i915/display/intel_hdmi.c
> > +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
> > @@ -1324,17 +1324,24 @@ static int intel_hdmi_hdcp_write(struct
> > intel_digital_port *dig_port,
> >       return ret;
> >  }
> >
> > -static
> > -int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> > -                               u8 *an)
> > +static int intel_hdmi_hdcp1_send_an_aksv(struct drm_connector
> > *drm_connector)
> >  {
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> >       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> >       struct intel_hdmi *hdmi = &dig_port->hdmi;
> >       struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915,
> >                                                             hdmi->ddc_bus);
> > +     struct drm_hdcp_an an;
> >       int ret;
> >
> > -     ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an,
> > +     /* Output An first, that's easy */
> > +     ret = intel_hdcp1_read_an(drm_connector, &an);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN,
> > an.bytes,
> >                                   DRM_HDCP_AN_LEN);
> >       if (ret) {
> >               drm_dbg_kms(&i915->drm, "Write An over DDC failed
> > (%d)\n",
> > @@ -1350,120 +1357,6 @@ int intel_hdmi_hdcp_write_an_aksv(struct
> > intel_digital_port *dig_port,
> >       return 0;
> >  }
> >
> > -static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *dig_port,
> > -                                  u8 *bksv)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -
> > -     int ret;
> > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BKSV, bksv,
> > -                                DRM_HDCP_KSV_LEN);
> > -     if (ret)
> > -             drm_dbg_kms(&i915->drm, "Read Bksv over DDC failed
> > (%d)\n",
> > -                         ret);
> > -     return ret;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *dig_port,
> > -                              u8 *bstatus)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -
> > -     int ret;
> > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BSTATUS,
> > -                                bstatus, DRM_HDCP_BSTATUS_LEN);
> > -     if (ret)
> > -             drm_dbg_kms(&i915->drm, "Read bstatus over DDC failed
> > (%d)\n",
> > -                         ret);
> > -     return ret;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *dig_port,
> > -                                  bool *repeater_present)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     int ret;
> > -     u8 val;
> > -
> > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS,
> > &val, 1);
> > -     if (ret) {
> > -             drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed
> > (%d)\n",
> > -                         ret);
> > -             return ret;
> > -     }
> > -     *repeater_present = val &
> > DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
> > -     return 0;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
> > -                               u8 *ri_prime)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -
> > -     int ret;
> > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_RI_PRIME,
> > -                                ri_prime, DRM_HDCP_RI_LEN);
> > -     if (ret)
> > -             drm_dbg_kms(&i915->drm, "Read Ri' over DDC failed
> > (%d)\n",
> > -                         ret);
> > -     return ret;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
> > -                                bool *ksv_ready)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     int ret;
> > -     u8 val;
> > -
> > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS,
> > &val, 1);
> > -     if (ret) {
> > -             drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed
> > (%d)\n",
> > -                         ret);
> > -             return ret;
> > -     }
> > -     *ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
> > -     return 0;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
> > -                               int num_downstream, u8 *ksv_fifo)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     int ret;
> > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_KSV_FIFO,
> > -                                ksv_fifo, num_downstream *
> > DRM_HDCP_KSV_LEN);
> > -     if (ret) {
> > -             drm_dbg_kms(&i915->drm,
> > -                         "Read ksv fifo over DDC failed (%d)\n", ret);
> > -             return ret;
> > -     }
> > -     return 0;
> > -}
> > -
> > -static
> > -int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port
> > *dig_port,
> > -                                   int i, u32 *part)
> > -{
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     int ret;
> > -
> > -     if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
> > -             return -EINVAL;
> > -
> > -     ret = intel_hdmi_hdcp_read(dig_port,
> > DRM_HDCP_DDC_V_PRIME(i),
> > -                                part, DRM_HDCP_V_PRIME_PART_LEN);
> > -     if (ret)
> > -             drm_dbg_kms(&i915->drm, "Read V'[%d] over DDC failed
> > (%d)\n",
> > -                         i, ret);
> > -     return ret;
> > -}
> > -
> >  static int kbl_repositioning_enc_en_signal(struct intel_connector
> > *connector,
> >                                          enum transcoder cpu_transcoder)
> >  {
> > @@ -1532,50 +1425,40 @@ int intel_hdmi_hdcp_toggle_signalling(struct
> > intel_digital_port *dig_port,
> >       return 0;
> >  }
> >
> > -static
> > -bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port,
> > -                                  struct intel_connector *connector)
> > +static int
> > +intel_hdmi_hdcp1_enable_encryption(struct drm_connector
> > *drm_connector)
> >  {
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     enum port port = dig_port->base.port;
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> >       enum transcoder cpu_transcoder = connector-
> > >hdcp.cpu_transcoder;
> >       int ret;
> > -     union {
> > -             u32 reg;
> > -             u8 shim[DRM_HDCP_RI_LEN];
> > -     } ri;
> >
> > -     ret = intel_hdmi_hdcp_read_ri_prime(dig_port, ri.shim);
> > +     ret = intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder,
> > true);
> >       if (ret)
> > -             return false;
> > -
> > -     intel_de_write(i915, HDCP_RPRIME(i915, cpu_transcoder, port),
> > ri.reg);
> > +             return ret;
> >
> > -     /* Wait for Ri prime match */
> > -     if (wait_for((intel_de_read(i915, HDCP_STATUS(i915,
> > cpu_transcoder, port)) &
> > -                   (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC)) ==
> > -                  (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
> > -             drm_dbg_kms(&i915->drm, "Ri' mismatch detected (%x)\n",
> > -                     intel_de_read(i915, HDCP_STATUS(i915,
> > cpu_transcoder,
> > -                                                     port)));
> > -             return false;
> > -     }
> > -     return true;
> > +     return intel_hdcp1_enable_encryption(drm_connector);
> >  }
> >
> > -static
> > -bool intel_hdmi_hdcp_check_link(struct intel_digital_port *dig_port,
> > -                             struct intel_connector *connector)
> > +static int intel_hdmi_hdcp1_disable(struct drm_connector
> > *drm_connector)
> >  {
> > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > -     int retry;
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> > +     enum transcoder cpu_transcoder = connector-
> > >hdcp.cpu_transcoder;
> > +     struct drm_i915_private *i915 = to_i915(connector->base.dev);
> > +     int ret;
> >
> > -     for (retry = 0; retry < 3; retry++)
> > -             if (intel_hdmi_hdcp_check_link_once(dig_port, connector))
> > -                     return true;
> > +     ret = intel_hdcp1_disable(drm_connector);
> > +     if (ret) {
> > +             drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 1.4\n",
> > +                     connector->base.name, connector->base.base.id);
> > +             return ret;
> > +     }
> >
> > -     drm_err(&i915->drm, "Link check failed\n");
> > -     return false;
> > +     return intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder,
> > +                                              false);
> >  }
> >
> >  struct hdcp2_hdmi_msg_timeout {
> > @@ -1718,9 +1601,8 @@ int intel_hdmi_hdcp2_read_msg(struct
> > intel_digital_port *dig_port,
> >       return ret;
> >  }
> >
> > -static
> > -int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
> > -                             struct intel_connector *connector)
> > +static int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
> > +                                    struct intel_connector *connector)
> >  {
> >       u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
> >       int ret;
> > @@ -1741,13 +1623,19 @@ int intel_hdmi_hdcp2_check_link(struct
> > intel_digital_port *dig_port,
> >       return ret;
> >  }
> >
> > -static
> > -int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
> > -                          bool *capable)
> > +static int intel_hdmi_hdcp2_capable(struct drm_connector
> > *drm_connector,
> > +                                 bool *capable)
> >  {
> > +     struct intel_connector *connector =
> > to_intel_connector(drm_connector);
> > +     struct intel_digital_port *dig_port =
> > +             intel_attached_dig_port(connector);
> >       u8 hdcp2_version;
> >       int ret;
> >
> > +     ret = intel_hdcp2_capable(drm_connector, capable);
> > +     if (ret || !capable)
> > +             return ret;
> > +
> >       *capable = false;
> >       ret = intel_hdmi_hdcp_read(dig_port,
> > HDCP_2_2_HDMI_REG_VER_OFFSET,
> >                                  &hdcp2_version, sizeof(hdcp2_version));
> > @@ -1758,23 +1646,30 @@ int intel_hdmi_hdcp2_capable(struct
> > intel_digital_port *dig_port,
> >  }
> >
> >  static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
> > -     .write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
> > -     .read_bksv = intel_hdmi_hdcp_read_bksv,
> > -     .read_bstatus = intel_hdmi_hdcp_read_bstatus,
> > -     .repeater_present = intel_hdmi_hdcp_repeater_present,
> > -     .read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
> > -     .read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
> > -     .read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
> > -     .read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
> >       .toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
> > -     .check_link = intel_hdmi_hdcp_check_link,
> >       .write_2_2_msg = intel_hdmi_hdcp2_write_msg,
> >       .read_2_2_msg = intel_hdmi_hdcp2_read_msg,
> > -     .check_2_2_link = intel_hdmi_hdcp2_check_link,
> > -     .hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
> > +     .check_2_2_link = intel_hdmi_hdcp2_check_link,
> >       .protocol = HDCP_PROTOCOL_HDMI,
> >  };
> >
> > +static const struct drm_hdcp_helper_funcs intel_hdmi_hdcp_helper_funcs
> > = {
> > +     .setup = intel_hdcp_setup,
> > +     .load_keys = intel_hdcp_load_keys,
> > +     .hdcp2_capable = intel_hdmi_hdcp2_capable,
> > +     .hdcp2_enable = intel_hdcp2_enable,
> > +     .hdcp2_check_link = intel_hdcp2_check_link,
> > +     .hdcp2_disable = intel_hdcp2_disable,
> > +     .hdcp1_send_an_aksv = intel_hdmi_hdcp1_send_an_aksv,
> > +     .hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> > +     .hdcp1_enable_encryption = intel_hdmi_hdcp1_enable_encryption,
> > +     .hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> > +     .hdcp1_match_ri = intel_hdcp1_match_ri,
> > +     .hdcp1_post_encryption = intel_hdcp1_post_encryption,
> > +     .hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> > +     .hdcp1_disable = intel_hdmi_hdcp1_disable,
> > +};
> > +
> >  static int intel_hdmi_source_max_tmds_clock(struct intel_encoder
> > *encoder)
> >  {
> >       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > @@ -2922,6 +2817,37 @@ void intel_infoframe_init(struct intel_digital_port
> > *dig_port)
> >       }
> >  }
> >
> > +static void intel_hdmi_hdcp_init(struct intel_digital_port *dig_port,
> > +                              struct intel_connector *connector)
> > +{
> > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > +     struct intel_encoder *intel_encoder = &dig_port->base;
> > +     enum port port = intel_encoder->port;
> > +     struct drm_hdcp_helper_data *data;
> > +     int ret;
> > +
> > +     if (!is_hdcp_supported(dev_priv, port))
> > +             return;
> > +
> > +     data = drm_hdcp_helper_initialize_hdmi(
> > +             &connector->base, &intel_hdmi_hdcp_helper_funcs, true);
> > +     if (IS_ERR(data)) {
> > +             drm_dbg_kms(&dev_priv->drm, "HDCP init failed
> > ret=%ld\n",
> > +                         PTR_ERR(data));
> > +             return;
> > +     }
> > +
> > +     ret = intel_hdcp_init(connector, dig_port, &intel_hdmi_hdcp_shim);
> > +     if (ret) {
> > +             drm_hdcp_helper_destroy(data);
> > +             drm_dbg_kms(&dev_priv->drm, "Intel HDCP init failed
> > ret=%d\n",
> > +                         ret);
> > +             return;
> > +     }
> > +
> > +     connector->hdcp_helper_data = data;
> > +}
> > +
> >  void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
> >                              struct intel_connector *intel_connector)
> >  {
> > @@ -2975,13 +2901,7 @@ void intel_hdmi_init_connector(struct
> > intel_digital_port *dig_port,
> >       intel_connector_attach_encoder(intel_connector, intel_encoder);
> >       intel_hdmi->attached_connector = intel_connector;
> >
> > -     if (is_hdcp_supported(dev_priv, port)) {
> > -             int ret = intel_hdcp_init(intel_connector, dig_port,
> > -                                       &intel_hdmi_hdcp_shim);
> > -             if (ret)
> > -                     drm_dbg_kms(&dev_priv->drm,
> > -                                 "HDCP init failed, skipping.\n");
> > -     }
> > +     intel_hdmi_hdcp_init(dig_port, intel_connector);
> >
> >       /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be
> > written
> >        * 0xd.  Failure to do so will result in spurious interrupts being
> > --
> > 2.39.0.246.g2a6d74b583-goog
>
I send v7 which should have the comments addressed. Thanks a lot!

^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes
  2023-03-24 19:27       ` Mark Yacoub
@ 2023-03-28  5:52         ` Kandpal, Suraj
  0 siblings, 0 replies; 38+ messages in thread
From: Kandpal, Suraj @ 2023-03-28  5:52 UTC (permalink / raw)
  To: Mark Yacoub
  Cc: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx, quic_sbillaka, konrad.dybcio, Souza,
	Jose, bjorn.andersson, krzysztof.kozlowski+dt, hbh25y, Vasut,
	Marek, Dixit, Ashutosh, sean, abhinavk, javierm, Murthy, Arun R,
	Lisovskiy, Stanislav, agross, quic_jesszhan, Nautiyal, Ankit K,
	Nikula, Jani, De Marchi, Lucas, quic_abhinavk, swboyd, robh+dt,
	christophe.jaillet, maxime, Vivi, Rodrigo, johan+linaro,
	tvrtko.ursulin, andersson, dianders, Sharma, Swati2, Navare,
	Manasi D, tzimmermann, Modem, Bhanuprakash, dmitry.baryshkov,
	seanpaul



> -----Original Message-----
> From: Mark Yacoub <markyacoub@chromium.org>
> Sent: Saturday, March 25, 2023 12:57 AM
> To: Kandpal, Suraj <suraj.kandpal@intel.com>
> Cc: quic_khsieh@quicinc.com; linux-arm-msm@vger.kernel.org; dri-
> devel@lists.freedesktop.org; freedreno@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; intel-
> gfx@lists.freedesktop.org; quic_sbillaka@quicinc.com;
> konrad.dybcio@somainline.org; Souza, Jose <jose.souza@intel.com>;
> bjorn.andersson@linaro.org; krzysztof.kozlowski+dt@linaro.org;
> hbh25y@gmail.com; Vasut, Marek <marex@denx.de>; Dixit, Ashutosh
> <ashutosh.dixit@intel.com>; sean@poorly.run; abhinavk@codeaurora.org;
> javierm@redhat.com; Murthy, Arun R <arun.r.murthy@intel.com>; Lisovskiy,
> Stanislav <stanislav.lisovskiy@intel.com>; agross@kernel.org;
> quic_jesszhan@quicinc.com; Nautiyal, Ankit K <ankit.k.nautiyal@intel.com>;
> Nikula, Jani <jani.nikula@intel.com>; De Marchi, Lucas
> <lucas.demarchi@intel.com>; quic_abhinavk@quicinc.com;
> swboyd@chromium.org; robh+dt@kernel.org;
> christophe.jaillet@wanadoo.fr; maxime@cerno.tech; Vivi, Rodrigo
> <rodrigo.vivi@intel.com>; johan+linaro@kernel.org;
> tvrtko.ursulin@linux.intel.com; andersson@kernel.org;
> dianders@chromium.org; Sharma, Swati2 <swati2.sharma@intel.com>;
> Navare, Manasi D <manasi.d.navare@intel.com>; tzimmermann@suse.de;
> Modem, Bhanuprakash <bhanuprakash.modem@intel.com>;
> dmitry.baryshkov@linaro.org; seanpaul@chromium.org
> Subject: Re: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return
> codes
> 
> On Thu, Mar 23, 2023 at 3:18 AM Kandpal, Suraj <suraj.kandpal@intel.com>
> wrote:
> >
> >
> >
> > > -----Original Message-----
> > > From: Kandpal, Suraj
> > > Sent: Friday, March 10, 2023 1:55 PM
> > > To: Mark Yacoub <markyacoub@chromium.org>;
> quic_khsieh@quicinc.com;
> > > linux-arm-msm@vger.kernel.org; dri-devel@lists.freedesktop.org;
> > > freedreno@lists.freedesktop.org; devicetree@vger.kernel.org; linux-
> > > kernel@vger.kernel.org; intel-gfx@lists.freedesktop.org
> > > Cc: quic_sbillaka@quicinc.com; konrad.dybcio@somainline.org; Souza,
> > > Jose <jose.souza@intel.com>; bjorn.andersson@linaro.org;
> > > krzysztof.kozlowski+dt@linaro.org; hbh25y@gmail.com; Vasut, Marek
> > > <marex@denx.de>; Dixit, Ashutosh <ashutosh.dixit@intel.com>;
> > > sean@poorly.run; abhinavk@codeaurora.org; javierm@redhat.com;
> > > Murthy, Arun R <arun.r.murthy@intel.com>; Lisovskiy, Stanislav
> > > <Stanislav.Lisovskiy@intel.com>; agross@kernel.org;
> > > quic_jesszhan@quicinc.com; Nautiyal, Ankit K
> > > <ankit.k.nautiyal@intel.com>; Nikula, Jani <jani.nikula@intel.com>;
> > > De Marchi, Lucas <lucas.demarchi@intel.com>;
> > > quic_abhinavk@quicinc.com; swboyd@chromium.org;
> robh+dt@kernel.org;
> > > christophe.jaillet@wanadoo.fr; maxime@cerno.tech; Vivi, Rodrigo
> > > <rodrigo.vivi@intel.com>; johan+linaro@kernel.org;
> > > tvrtko.ursulin@linux.intel.com; andersson@kernel.org;
> > > dianders@chromium.org; Sharma, Swati2 <swati2.sharma@intel.com>;
> > > Navare, Manasi D <manasi.d.navare@intel.com>;
> tzimmermann@suse.de;
> > > Modem, Bhanuprakash <Bhanuprakash.Modem@intel.com>;
> > > dmitry.baryshkov@linaro.org; seanpaul@chromium.org
> > > Subject: RE: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable
> > > return codes
> > >
> > > > Subject: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable
> > > > return codes
> > > >
> > > > From: Sean Paul <seanpaul@chromium.org>
> > > >
> > > > The shim functions return error codes, but they are discarded in
> > > > intel_hdcp.c. This patch plumbs the return codes through so they
> > > > are properly handled.
> > > >
> > > > Acked-by: Jani Nikula <jani.nikula@intel.com>
> > > > Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > > > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > > > Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> > > > Link:
> > > >
> https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456
> > > > -7-
> > > > sean@poorly.run #v1
> > > > Link:
> > > >
> https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-
> > > > 7-
> > > > sean@poorly.run #v2
> > > > Link:
> > > >
> https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916
> > > > -7-
> > > > sean@poorly.run #v3
> > > > Link:
> > > >
> > >
> https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845
> > > -
> > > > 7-sean@poorly.run #v4
> > > > Link:
> > > >
> > >
> https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308
> > > -
> > > > 7-sean@poorly.run #v5
> > > >
> > > > Changes in v2:
> > > > -None
> > > > Changes in v3:
> > > > -None
> > > > Changes in v4:
> > > > -None
> > > > Changes in v5:
> > > > -None
> > > > Changes in v6:
> > > > -Rebased
> > > >
> > > > ---
> > > >  .../drm/i915/display/intel_display_debugfs.c  |  9 +++-
> > > >  drivers/gpu/drm/i915/display/intel_hdcp.c     | 51 ++++++++++---------
> > > >  drivers/gpu/drm/i915/display/intel_hdcp.h     |  4 +-
> > > >  3 files changed, 37 insertions(+), 27 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > > b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > > index 7c7253a2541c..13a4153bb76e 100644
> > > > --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > > +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > > @@ -492,6 +492,7 @@ static void intel_panel_info(struct seq_file
> > > > *m, static void intel_hdcp_info(struct seq_file *m,
> > > >                         struct intel_connector *intel_connector)
> > > > {
> > > > +   int ret;
> > > >     bool hdcp_cap, hdcp2_cap;
> > > >
> > > >     if (!intel_connector->hdcp.shim) { @@ -499,8 +500,12 @@ static
> > > > void intel_hdcp_info(struct seq_file *m,
> > > >             goto out;
> > > >     }
> > > >
> > > > -   hdcp_cap = intel_hdcp_capable(intel_connector);
> > > > -   hdcp2_cap = intel_hdcp2_capable(intel_connector);
> > > > +   ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
> > > > +   if (ret)
> > > > +           hdcp_cap = false;
> > > > +   ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
> > > > +   if (ret)
> > > > +           hdcp2_cap = false;
> > > >
> > >
> > > This does not seem to be adding value here as this error which you
> > > referred to as being ignored is used both in case of hdmi and dp is
> > > being to determine if hdcp_cap or hdcp2 cap is true or false which
> > > you basically reiterate here too check the intel_dp_hdcp2_capable and
> intel_hdmi_hdcp2_capable .
> > > this change in itself can be removed.
> > >
> > > Regards,
> > > Suraj Kandpal
> > >
> Hey Suraj, what we're trying to do here is to have a distinction between 2
> things:
> 1. were we able to check of the capability or not. like did the connection work
> well 2. if the check went well, what capability were were able to read We
> may or may not need both info. But since we moved to common DRM, it
> might be best keep the distinction and each driver can handle it as it sees fit.

Hi Mark,
Hmm I think it make sense to allow each driver to decide how to handle it then.

> > > >     if (hdcp_cap)
> > > >             seq_puts(m, "HDCP1.4 "); diff --git
> > > > a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > > b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > > index 0a20bc41be55..61a862ae1f28 100644
> > > > --- a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > > @@ -177,50 +177,49 @@ int intel_hdcp_read_valid_bksv(struct
> > > > intel_digital_port *dig_port,  }
> > > >
> > > >  /* Is HDCP1.4 capable on Platform and Sink */ -bool
> > > > intel_hdcp_capable(struct intel_connector *connector)
> > > > +int intel_hdcp_capable(struct intel_connector *connector, bool
> > > > +*capable)
> > > >  {
> > > >     struct intel_digital_port *dig_port =
> > > > intel_attached_dig_port(connector);
> > > >     const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> > > > -   bool capable = false;
> > > >     u8 bksv[5];
> > > >
> > > > +   *capable = false;
> > > > +
> > > >     if (!shim)
> > > > -           return capable;
> > > > +           return 0;
> > > >
> > > > -   if (shim->hdcp_capable) {
> > > > -           shim->hdcp_capable(dig_port, &capable);
> > > > -   } else {
> > > > -           if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> > > > -                   capable = true;
> > > > -   }
> > > > +   if (shim->hdcp_capable)
> > > > +           return shim->hdcp_capable(dig_port, capable);
> > > > +
> > > > +   if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> > > > +           *capable = true;
> > > >
> > > > -   return capable;
> > > > +   return 0;
> > > >  }
> > > >
> > > >  /* Is HDCP2.2 capable on Platform and Sink */ -bool
> > > > intel_hdcp2_capable(struct intel_connector *connector)
> > > > +int intel_hdcp2_capable(struct intel_connector *connector, bool
> > > > +*capable)
> > > >  {
> > > >     struct intel_digital_port *dig_port =
> > > > intel_attached_dig_port(connector);
> > > >     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > >     struct intel_hdcp *hdcp = &connector->hdcp;
> > > > -   bool capable = false;
> > > > +
> > > > +   *capable = false;
> > > >
> > > >     /* I915 support for HDCP2.2 */
> > > >     if (!hdcp->hdcp2_supported)
> > > > -           return false;
> > > > +           return 0;
> > > >
> > > >     /* MEI interface is solid */
> > > >     mutex_lock(&dev_priv->display.hdcp.comp_mutex);
> > > >     if (!dev_priv->display.hdcp.comp_added ||  !dev_priv-
> > > > >display.hdcp.master) {
> > > >             mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> > > > -           return false;
> > > > +           return 0;
> > > >     }
> > > >     mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> > > >
> > > >     /* Sink's capability for HDCP2.2 */
> > > > -   hdcp->shim->hdcp_2_2_capable(dig_port, &capable);
> > > > -
> > > > -   return capable;
> > > > +   return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
> > > >  }
> > > >
> > > >  static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv,
> > > > @@ -
> > > > 2355,6 +2354,7 @@ int intel_hdcp_enable(struct intel_connector
> > > > *connector,
> > > >     struct intel_digital_port *dig_port =
> > > > intel_attached_dig_port(connector);
> > > >     struct intel_hdcp *hdcp = &connector->hdcp;
> > > >     unsigned long check_link_interval =
> > > DRM_HDCP_CHECK_PERIOD_MS;
> > > > +   bool capable;
> > > >     int ret = -EINVAL;
> > > >
> > > >     if (!hdcp->shim)
> > > > @@ -2373,21 +2373,27 @@ int intel_hdcp_enable(struct
> > > > intel_connector *connector,
> > > >      * Considering that HDCP2.2 is more secure than HDCP1.4, If
> > > > the setup
> > > >      * is capable of HDCP2.2, it is preferred to use HDCP2.2.
> > > >      */
> > > > -   if (intel_hdcp2_capable(connector)) {
> > > > +   ret = intel_hdcp2_capable(connector, &capable);
> > > > +   if (capable) {
> > > >             ret = _intel_hdcp2_enable(connector);
> > > > -           if (!ret)
> > > > +           if (!ret) {
> > > >                     check_link_interval =
> > > > DRM_HDCP2_CHECK_PERIOD_MS;
> > > > +                   goto out;
> > > > +           }
> >
> > HI,
> > Just noticed another changed here if any error is returned with
> > intel_hdc2_capable You directly jump to out which will stop us from
> > enabling hdcp 1.4 we should check for hdcp 1.4 capability even if hdcp
> > 2.2 capability is returned with an error one other reason I don't think the
> handling of error codes are adding value here.
> >
> > Regards,
> > Suraj Kandpal
> Hey Suraj - the goto happens if we know that the device is hdcp2 capable. If
> it's capable, we do enable it. If we have no error returned, that's when we
> skip hdcp1.4 otherwise, if it's not capable, or the enable returned with an
> error code, we don't goto out but move on to try on hdcp 1.4 Thanks!

This logic will not work as hdcp2 capability is determined by reading RxCaps register
and hdcp1.x capability is determined by looking at the devices bksv which means
there is a possibility hdcp2 may throw an error reading the rxcaps register but not issue an
error while reading the bksv and since hdcp2 devices also supports hdcp 1.x in this case we
should try enable hdcp1.4 if error is issued in at the time of hdcp2 but this code makes that
impossible.

Regards,
Suraj Kandpal

> > > >     }
> > > >
> > > >     /*
> > > >      * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
> > > >      * be attempted.
> > > >      */
> > > > -   if (ret && intel_hdcp_capable(connector) &&
> > > > -       hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) {
> > > > +   ret = intel_hdcp_capable(connector, &capable);
> > > > +   if (ret)
> > > > +           goto out;
> > > > +
> > > > +   if (capable && hdcp->content_type !=
> > > > DRM_MODE_HDCP_CONTENT_TYPE1)
> > > >             ret = _intel_hdcp_enable(connector);
> > > > -   }
> > > >
> > > > +out:
> > > >     if (!ret) {
> > > >             schedule_delayed_work(&hdcp->check_work,
> > > > check_link_interval);
> > > >             intel_hdcp_update_value(connector,
> > > > @@ -2395,7 +2401,6 @@ int intel_hdcp_enable(struct intel_connector
> > > > *connector,
> > > >                                     true);
> > > >     }
> > > >
> > > > -out:
> > > >     mutex_unlock(&dig_port->hdcp_mutex);
> > > >     mutex_unlock(&hdcp->mutex);
> > > >     return ret;
> > > > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > > b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > > index 7c5fd84a7b65..f06f6e5a2b1a 100644
> > > > --- a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > > @@ -33,8 +33,8 @@ void intel_hdcp_update_pipe(struct
> > > > intel_atomic_state *state,
> > > >                         const struct intel_crtc_state *crtc_state,
> > > >                         const struct drm_connector_state
> > > > *conn_state);
> > > bool
> > > > is_hdcp_supported(struct drm_i915_private *dev_priv, enum port
> > > > port); -bool intel_hdcp_capable(struct intel_connector
> > > > *connector); -bool intel_hdcp2_capable(struct intel_connector
> > > > *connector);
> > > > +int intel_hdcp_capable(struct intel_connector *connector, bool
> > > > +*capable); int intel_hdcp2_capable(struct intel_connector
> > > > +*connector, bool *capable);
> > > >  void intel_hdcp_component_init(struct drm_i915_private
> > > > *dev_priv); void intel_hdcp_component_fini(struct drm_i915_private
> > > > *dev_priv); void intel_hdcp_cleanup(struct intel_connector
> > > > *connector);
> > > > --
> > > > 2.39.0.246.g2a6d74b583-goog
> >

^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [Intel-gfx] [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915
  2023-03-24 19:34     ` Mark Yacoub
@ 2023-03-28  6:12       ` Kandpal, Suraj
  0 siblings, 0 replies; 38+ messages in thread
From: Kandpal, Suraj @ 2023-03-28  6:12 UTC (permalink / raw)
  To: Mark Yacoub
  Cc: quic_khsieh, linux-arm-msm, dri-devel, freedreno, devicetree,
	linux-kernel, intel-gfx, quic_sbillaka, konrad.dybcio,
	bjorn.andersson, krzysztof.kozlowski+dt, airlied, hbh25y, Vasut,
	Marek, abhinavk, javierm, agross, quic_jesszhan, daniel, Nikula,
	Jani, De Marchi, Lucas, quic_abhinavk, swboyd, robh+dt,
	christophe.jaillet, maxime, Vivi, Rodrigo, johan+linaro,
	andersson, dianders, tzimmermann, dmitry.baryshkov, seanpaul



> -----Original Message-----
> From: Mark Yacoub <markyacoub@chromium.org>
> Sent: Saturday, March 25, 2023 1:04 AM
> To: Kandpal, Suraj <suraj.kandpal@intel.com>
> Cc: quic_khsieh@quicinc.com; linux-arm-msm@vger.kernel.org; dri-
> devel@lists.freedesktop.org; freedreno@lists.freedesktop.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; intel-
> gfx@lists.freedesktop.org; quic_sbillaka@quicinc.com;
> konrad.dybcio@somainline.org; bjorn.andersson@linaro.org;
> krzysztof.kozlowski+dt@linaro.org; airlied@gmail.com; hbh25y@gmail.com;
> Vasut, Marek <marex@denx.de>; abhinavk@codeaurora.org;
> javierm@redhat.com; agross@kernel.org; quic_jesszhan@quicinc.com;
> daniel@ffwll.ch; Nikula, Jani <jani.nikula@intel.com>; De Marchi, Lucas
> <lucas.demarchi@intel.com>; quic_abhinavk@quicinc.com;
> swboyd@chromium.org; robh+dt@kernel.org;
> christophe.jaillet@wanadoo.fr; maxime@cerno.tech; Vivi, Rodrigo
> <rodrigo.vivi@intel.com>; johan+linaro@kernel.org; andersson@kernel.org;
> dianders@chromium.org; tzimmermann@suse.de;
> dmitry.baryshkov@linaro.org; seanpaul@chromium.org
> Subject: Re: [Intel-gfx] [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers
> for i915
> 
> On Tue, Mar 14, 2023 at 1:54 AM Kandpal, Suraj <suraj.kandpal@intel.com>
> wrote:
> >
> > >
> > > From: Sean Paul <seanpaul@chromium.org>
> > >
> > > Now that all of the HDCP 1.x logic has been migrated to the central HDCP
> > > helpers, use it in the i915 driver.
> > >
> > > The majority of the driver code for HDCP 1.x will live in intel_hdcp.c,
> > > however there are a few helper hooks which are connector-specific and
> > > need to be partially or fully implemented in the intel_dp_hdcp.c or
> > > intel_hdmi.c.
> > >
> > > We'll leave most of the HDCP 2.x code alone since we don't have another
> > > implementation of HDCP 2.x to use as reference for what should and
> > > should not live in the drm helpers. The helper will call the overly
> > > general enable/disable/is_capable HDCP 2.x callbacks and leave the
> > > interesting stuff for the driver. Once we have another HDCP 2.x
> > > implementation, we should do a similar migration.
> > >
> > > Acked-by: Jani Nikula <jani.nikula@intel.com>
> > > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > > Signed-off-by: Mark Yacoub <markyacoub@chromium.org>
> > > Link:
> > >
> https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-8-
> > > sean@poorly.run #v1
> > > Link:
> > > https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-
> 8-
> > > sean@poorly.run #v2
> > > Link:
> > >
> https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-8-
> > > sean@poorly.run #v3
> > > Link:
> > >
> https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
> > > 8-sean@poorly.run #v4
> > > Link:
> > >
> https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
> > > 8-sean@poorly.run #v5
> > >
> > > Changes in v2:
> > > -Fix mst helper function pointer reported by 0-day
> > > Changes in v3:
> > > -Add forward declaration for drm_atomic_state in intel_hdcp.h identified
> > >  by 0-day
> > > Changes in v4:
> > > -None
> > > Changes in v5:
> > > -None
> > > Changes in v6:
> > > -Rebased.
> > >
> > > ---
> > >  drivers/gpu/drm/i915/display/intel_ddi.c      |  32 +-
> > >  .../drm/i915/display/intel_display_debugfs.c  |   6 +-
> > >  .../drm/i915/display/intel_display_types.h    |  60 +-
> > >  drivers/gpu/drm/i915/display/intel_dp_hdcp.c  | 348 +++----
> > >  drivers/gpu/drm/i915/display/intel_dp_mst.c   |  16 +-
> > >  drivers/gpu/drm/i915/display/intel_hdcp.c     | 952 +++---------------
> > >  drivers/gpu/drm/i915/display/intel_hdcp.h     |  31 +-
> > >  drivers/gpu/drm/i915/display/intel_hdmi.c     | 270 ++---
> > >  8 files changed, 445 insertions(+), 1270 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c
> > > b/drivers/gpu/drm/i915/display/intel_ddi.c
> > > index 69ecf2a3d6c6..a4397f066a3e 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> > > @@ -28,6 +28,7 @@
> > >  #include <linux/string_helpers.h>
> > >
> > >  #include <drm/display/drm_scdc_helper.h>
> > > +#include <drm/display/drm_hdcp_helper.h>
> > >  #include <drm/drm_privacy_screen_consumer.h>
> > >
> > >  #include "i915_drv.h"
> > > @@ -2909,6 +2910,10 @@ static void intel_enable_ddi(struct
> > > intel_atomic_state *state,
> > >                            const struct intel_crtc_state *crtc_state,
> > >                            const struct drm_connector_state *conn_state)
> > >  {
> > > +     struct intel_connector *connector =
> > > +             to_intel_connector(conn_state->connector);
> > > +     struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> > > +
> > >       drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
> > >
> > >       if (!intel_crtc_is_bigjoiner_slave(crtc_state))
> > > @@ -2925,12 +2930,10 @@ static void intel_enable_ddi(struct
> > > intel_atomic_state *state,
> > >       else
> > >               intel_enable_ddi_dp(state, encoder, crtc_state,
> > > conn_state);
> > >
> > > -     /* Enable hdcp if it's desired */
> > > -     if (conn_state->content_protection ==
> > > -         DRM_MODE_CONTENT_PROTECTION_DESIRED)
> > > -             intel_hdcp_enable(to_intel_connector(conn_state-
> > > >connector),
> > > -                               crtc_state,
> > > -                               (u8)conn_state->hdcp_content_type);
> > > +     if (connector->hdcp_helper_data)
> > > +             drm_hdcp_helper_atomic_commit(connector-
> > > >hdcp_helper_data,
> > > +                                           &state->base,
> > > +                                           &dig_port->hdcp_mutex);
> > >  }
> > >
> > >  static void intel_disable_ddi_dp(struct intel_atomic_state *state,
> > > @@ -2976,7 +2979,14 @@ static void intel_disable_ddi(struct
> > > intel_atomic_state *state,
> > >                             const struct intel_crtc_state *old_crtc_state,
> > >                             const struct drm_connector_state
> > > *old_conn_state)
> > >  {
> > > -     intel_hdcp_disable(to_intel_connector(old_conn_state-
> > > >connector));
> > > +     struct intel_connector *connector =
> > > +             to_intel_connector(old_conn_state->connector);
> > > +     struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> > > +
> > > +     if (connector->hdcp_helper_data)
> > > +             drm_hdcp_helper_atomic_commit(connector-
> > > >hdcp_helper_data,
> > > +                                           &state->base,
> > > +                                           &dig_port->hdcp_mutex);
> > >
> > >       if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
> > >               intel_disable_ddi_hdmi(state, encoder, old_crtc_state,
> > > @@ -3004,13 +3014,19 @@ void intel_ddi_update_pipe(struct
> > > intel_atomic_state *state,
> > >                          const struct intel_crtc_state *crtc_state,
> > >                          const struct drm_connector_state *conn_state)
> > >  {
> > > +     struct intel_connector *connector =
> > > +             to_intel_connector(conn_state->connector);
> > > +     struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
> > >
> > >       if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
> > >           !intel_encoder_is_mst(encoder))
> > >               intel_ddi_update_pipe_dp(state, encoder, crtc_state,
> > >                                        conn_state);
> > >
> > > -     intel_hdcp_update_pipe(state, encoder, crtc_state, conn_state);
> > > +     if (connector->hdcp_helper_data)
> > > +             drm_hdcp_helper_atomic_commit(connector-
> > > >hdcp_helper_data,
> > > +                                           &state->base,
> > > +                                           &dig_port->hdcp_mutex);
> > >  }
> > >
> > >  static void
> > > diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > index 13a4153bb76e..2e67cca0151c 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> > > @@ -7,6 +7,7 @@
> > >
> > >  #include <drm/drm_debugfs.h>
> > >  #include <drm/drm_fourcc.h>
> > > +#include <drm/display/drm_hdcp_helper.h>
> > >
> > >  #include "i915_debugfs.h"
> > >  #include "intel_de.h"
> > > @@ -500,10 +501,11 @@ static void intel_hdcp_info(struct seq_file *m,
> > >               goto out;
> > >       }
> > >
> > > -     ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
> > > +     ret = drm_hdcp_helper_hdcp1_capable(intel_connector-
> > > >hdcp_helper_data,
> > > +                                         &hdcp_cap);
> > >       if (ret)
> > >               hdcp_cap = false;
> > > -     ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
> > > +     ret = intel_hdcp2_capable(&intel_connector->base, &hdcp2_cap);
> > >       if (ret)
> > >               hdcp2_cap = false;
> > >
> > > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h
> > > b/drivers/gpu/drm/i915/display/intel_display_types.h
> > > index 298d00a11f47..6260a40586ae 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> > > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> > > @@ -416,71 +416,14 @@ enum check_link_response {
> > >   *           The offsets of the registers are different for DP vs. HDMI
> > >   *   - Receiver register masks/offsets
> > >   *           For instance, the ready bit for the KSV fifo is in a different
> > > - *           place on DP vs HDMI
> > > - *   - Receiver register names
> > > - *           Seriously. In the DP spec, the 16-bit register containing
> > > - *           downstream information is called BINFO, on HDMI it's called
> > > - *           BSTATUS. To confuse matters further, DP has a BSTATUS
> > > register
> > > - *           with a completely different definition.
> > > - *   - KSV FIFO
> > > - *           On HDMI, the ksv fifo is read all at once, whereas on DP it
> > > must
> > > - *           be read 3 keys at a time
> > > - *   - Aksv output
> > > - *           Since Aksv is hidden in hardware, there's different
> > > procedures
> > > - *           to send it over DP AUX vs DDC
> >
> > I really think we can keep the comment as its mentioning the ways that the
> two busses differ
> >
> Reverted the change.
> > > + *           place on DP vs HDMI.
> > >   */
> > >  struct intel_hdcp_shim {
> > > -     /* Outputs the transmitter's An and Aksv values to the receiver. */
> > > -     int (*write_an_aksv)(struct intel_digital_port *dig_port, u8 *an);
> > > -
> > > -     /* Reads the receiver's key selection vector */
> > > -     int (*read_bksv)(struct intel_digital_port *dig_port, u8 *bksv);
> > > -
> > > -     /*
> > > -      * Reads BINFO from DP receivers and BSTATUS from HDMI
> > > receivers. The
> > > -      * definitions are the same in the respective specs, but the names
> > > are
> > > -      * different. Call it BSTATUS since that's the name the HDMI spec
> > > -      * uses and it was there first.
> > > -      */
> > > -     int (*read_bstatus)(struct intel_digital_port *dig_port,
> > > -                         u8 *bstatus);
> > > -
> > > -     /* Determines whether a repeater is present downstream */
> > > -     int (*repeater_present)(struct intel_digital_port *dig_port,
> > > -                             bool *repeater_present);
> > > -
> > > -     /* Reads the receiver's Ri' value */
> > > -     int (*read_ri_prime)(struct intel_digital_port *dig_port, u8 *ri);
> > > -
> > > -     /* Determines if the receiver's KSV FIFO is ready for consumption */
> > > -     int (*read_ksv_ready)(struct intel_digital_port *dig_port,
> > > -                           bool *ksv_ready);
> > > -
> > > -     /* Reads the ksv fifo for num_downstream devices */
> > > -     int (*read_ksv_fifo)(struct intel_digital_port *dig_port,
> > > -                          int num_downstream, u8 *ksv_fifo);
> > > -
> > > -     /* Reads a 32-bit part of V' from the receiver */
> > > -     int (*read_v_prime_part)(struct intel_digital_port *dig_port,
> > > -                              int i, u32 *part);
> > > -
> > >       /* Enables HDCP signalling on the port */
> > >       int (*toggle_signalling)(struct intel_digital_port *dig_port,
> > >                                enum transcoder cpu_transcoder,
> > >                                bool enable);
> > >
> > > -     /* Enable/Disable stream encryption on DP MST Transport Link */
> > > -     int (*stream_encryption)(struct intel_connector *connector,
> > > -                              bool enable);
> > > -
> > > -     /* Ensures the link is still protected */
> > > -     bool (*check_link)(struct intel_digital_port *dig_port,
> > > -                        struct intel_connector *connector);
> > > -
> > > -     /* Detects panel's hdcp capability. This is optional for HDMI. */
> > > -     int (*hdcp_capable)(struct intel_digital_port *dig_port,
> > > -                         bool *hdcp_capable);
> > > -
> > >       /* HDCP adaptation(DP/HDMI) required on the port */
> > >       enum hdcp_wired_protocol protocol;
> > >
> > > @@ -610,6 +553,7 @@ struct intel_connector {
> > >       struct work_struct modeset_retry_work;
> > >
> > >       struct intel_hdcp hdcp;
> > > +     struct drm_hdcp_helper_data *hdcp_helper_data;
> > >  };
> > >
> > >  struct intel_digital_connector_state {
> > > diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > > b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > > index 88689124c013..d61ac8d69951 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c
> > > @@ -55,17 +55,24 @@ static void intel_dp_hdcp_wait_for_cp_irq(struct
> > > intel_hdcp *hdcp, int timeout)
> > >               DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
> > >  }
> > >
> > > -static
> > > -int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> > > -                             u8 *an)
> > > +static int intel_dp_hdcp1_send_an_aksv(struct drm_connector
> > > *drm_connector)
> > >  {
> >
> > I think the name intel_dp_hdcp_send_an_aksv should be enough as this
> step
> > is done only for hdcp 1.x and not hdcp 2.x.
> >
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > >       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > +     struct drm_hdcp_an an;
> > >       u8 aksv[DRM_HDCP_KSV_LEN] = {};
> > >       ssize_t dpcd_ret;
> > > +     int ret;
> > >
> > >       /* Output An first, that's easy */
> > > +     ret = intel_hdcp1_read_an(drm_connector, &an);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > >       dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux,
> > > DP_AUX_HDCP_AN,
> > > -                                  an, DRM_HDCP_AN_LEN);
> > > +                                  an.bytes, DRM_HDCP_AN_LEN);
> > >       if (dpcd_ret != DRM_HDCP_AN_LEN) {
> > >               drm_dbg_kms(&i915->drm,
> > >                           "Failed to write An over DP/AUX (%zd)\n",
> > > @@ -91,158 +98,6 @@ int intel_dp_hdcp_write_an_aksv(struct
> > > intel_digital_port *dig_port,
> > >       return 0;
> > >  }
> > >
> > > -static int intel_dp_hdcp_read_bksv(struct intel_digital_port *dig_port,
> > > -                                u8 *bksv)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     ssize_t ret;
> > > -
> > > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BKSV,
> > > bksv,
> > > -                            DRM_HDCP_KSV_LEN);
> > > -     if (ret != DRM_HDCP_KSV_LEN) {
> > > -             drm_dbg_kms(&i915->drm,
> > > -                         "Read Bksv from DP/AUX failed (%zd)\n", ret);
> > > -             return ret >= 0 ? -EIO : ret;
> > > -     }
> > > -     return 0;
> > > -}
> > > -
> > > -static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
> > > -                                   u8 *bstatus)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     ssize_t ret;
> > > -
> > > -     /*
> > > -      * For some reason the HDMI and DP HDCP specs call this register
> > > -      * definition by different names. In the HDMI spec, it's called
> > > BSTATUS,
> > > -      * but in DP it's called BINFO.
> > > -      */
> > > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > > DP_AUX_HDCP_BINFO,
> > > -                            bstatus, DRM_HDCP_BSTATUS_LEN);
> > > -     if (ret != DRM_HDCP_BSTATUS_LEN) {
> > > -             drm_dbg_kms(&i915->drm,
> > > -                         "Read bstatus from DP/AUX failed (%zd)\n", ret);
> > > -             return ret >= 0 ? -EIO : ret;
> > > -     }
> > > -     return 0;
> > > -}
> > > -
> > > -static
> > > -int intel_dp_hdcp_read_bcaps(struct intel_digital_port *dig_port,
> > > -                          u8 *bcaps)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     ssize_t ret;
> > > -
> > > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > > DP_AUX_HDCP_BCAPS,
> > > -                            bcaps, 1);
> > > -     if (ret != 1) {
> > > -             drm_dbg_kms(&i915->drm,
> > > -                         "Read bcaps from DP/AUX failed (%zd)\n", ret);
> > > -             return ret >= 0 ? -EIO : ret;
> > > -     }
> > > -
> > > -     return 0;
> > > -}
> > > -
> > > -static
> > > -int intel_dp_hdcp_repeater_present(struct intel_digital_port *dig_port,
> > > -                                bool *repeater_present)
> > > -{
> > > -     ssize_t ret;
> > > -     u8 bcaps;
> > > -
> > > -     ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
> > > -     if (ret)
> > > -             return ret;
> > > -
> > > -     *repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
> > > -     return 0;
> > > -}
> > > -
> > > -static
> > > -int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
> > > -                             u8 *ri_prime)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     ssize_t ret;
> > > -
> > > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > > DP_AUX_HDCP_RI_PRIME,
> > > -                            ri_prime, DRM_HDCP_RI_LEN);
> > > -     if (ret != DRM_HDCP_RI_LEN) {
> > > -             drm_dbg_kms(&i915->drm, "Read Ri' from DP/AUX failed
> > > (%zd)\n",
> > > -                         ret);
> > > -             return ret >= 0 ? -EIO : ret;
> > > -     }
> > > -     return 0;
> > > -}
> > > -
> > > -static
> > > -int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
> > > -                              bool *ksv_ready)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     ssize_t ret;
> > > -     u8 bstatus;
> > > -
> > > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > > DP_AUX_HDCP_BSTATUS,
> > > -                            &bstatus, 1);
> > > -     if (ret != 1) {
> > > -             drm_dbg_kms(&i915->drm,
> > > -                         "Read bstatus from DP/AUX failed (%zd)\n", ret);
> > > -             return ret >= 0 ? -EIO : ret;
> > > -     }
> > > -     *ksv_ready = bstatus & DP_BSTATUS_READY;
> > > -     return 0;
> > > -}
> > > -
> > > -static
> > > -int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
> > > -                             int num_downstream, u8 *ksv_fifo)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     ssize_t ret;
> > > -     int i;
> > > -
> > > -     /* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
> > > -     for (i = 0; i < num_downstream; i += 3) {
> > > -             size_t len = min(num_downstream - i, 3) *
> > > DRM_HDCP_KSV_LEN;
> > > -             ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > > -                                    DP_AUX_HDCP_KSV_FIFO,
> > > -                                    ksv_fifo + i * DRM_HDCP_KSV_LEN,
> > > -                                    len);
> > > -             if (ret != len) {
> > > -                     drm_dbg_kms(&i915->drm,
> > > -                                 "Read ksv[%d] from DP/AUX failed
> > > (%zd)\n",
> > > -                                 i, ret);
> > > -                     return ret >= 0 ? -EIO : ret;
> > > -             }
> > > -     }
> > > -     return 0;
> > > -}
> > > -
> > > -static
> > > -int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port
> *dig_port,
> > > -                                 int i, u32 *part)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     ssize_t ret;
> > > -
> > > -     if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
> > > -             return -EINVAL;
> > > -
> > > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > > -                            DP_AUX_HDCP_V_PRIME(i), part,
> > > -                            DRM_HDCP_V_PRIME_PART_LEN);
> > > -     if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
> > > -             drm_dbg_kms(&i915->drm,
> > > -                         "Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
> > > -             return ret >= 0 ? -EIO : ret;
> > > -     }
> > > -     return 0;
> > > -}
> > > -
> > >  static
> > >  int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
> > >                                   enum transcoder cpu_transcoder,
> > > @@ -252,40 +107,6 @@ int intel_dp_hdcp_toggle_signalling(struct
> > > intel_digital_port *dig_port,
> > >       return 0;
> > >  }
> > >
> > > -static
> > > -bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
> > > -                           struct intel_connector *connector)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     ssize_t ret;
> > > -     u8 bstatus;
> > > -
> > > -     ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > > DP_AUX_HDCP_BSTATUS,
> > > -                            &bstatus, 1);
> > > -     if (ret != 1) {
> > > -             drm_dbg_kms(&i915->drm,
> > > -                         "Read bstatus from DP/AUX failed (%zd)\n", ret);
> > > -             return false;
> > > -     }
> > > -
> > > -     return !(bstatus & (DP_BSTATUS_LINK_FAILURE |
> > > DP_BSTATUS_REAUTH_REQ));
> > > -}
> > > -
> > > -static
> > > -int intel_dp_hdcp_capable(struct intel_digital_port *dig_port,
> > > -                       bool *hdcp_capable)
> > > -{
> > > -     ssize_t ret;
> > > -     u8 bcaps;
> > > -
> > > -     ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
> > > -     if (ret)
> > > -             return ret;
> > > -
> > > -     *hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
> > > -     return 0;
> > > -}
> > > -
> > >  struct hdcp2_dp_errata_stream_type {
> > >       u8      msg_id;
> > >       u8      stream_type;
> > > @@ -628,13 +449,19 @@ int intel_dp_hdcp2_check_link(struct
> > > intel_digital_port *dig_port,
> > >       return ret;
> > >  }
> > >
> > > -static
> > > -int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
> > > -                        bool *capable)
> > > +static int intel_dp_hdcp2_capable(struct drm_connector
> *drm_connector,
> > > +                               bool *capable)
> > >  {
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > >       u8 rx_caps[3];
> > >       int ret;
> > >
> > > +     ret = intel_hdcp2_capable(drm_connector, capable);
> > > +     if (ret || !capable)
> > > +             return ret;
> > > +
> > >       *capable = false;
> > >       ret = drm_dp_dpcd_read(&dig_port->dp.aux,
> > >                              DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
> > > @@ -650,22 +477,11 @@ int intel_dp_hdcp2_capable(struct
> > > intel_digital_port *dig_port,
> > >  }
> > >
> > >  static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
> > > -     .write_an_aksv = intel_dp_hdcp_write_an_aksv,
> > > -     .read_bksv = intel_dp_hdcp_read_bksv,
> > > -     .read_bstatus = intel_dp_hdcp_read_bstatus,
> > > -     .repeater_present = intel_dp_hdcp_repeater_present,
> > > -     .read_ri_prime = intel_dp_hdcp_read_ri_prime,
> > > -     .read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
> > > -     .read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
> > > -     .read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
> > >       .toggle_signalling = intel_dp_hdcp_toggle_signalling,
> > > -     .check_link = intel_dp_hdcp_check_link,
> > > -     .hdcp_capable = intel_dp_hdcp_capable,
> > >       .write_2_2_msg = intel_dp_hdcp2_write_msg,
> > >       .read_2_2_msg = intel_dp_hdcp2_read_msg,
> > >       .config_stream_type = intel_dp_hdcp2_config_stream_type,
> > >       .check_2_2_link = intel_dp_hdcp2_check_link,
> > > -     .hdcp_2_2_capable = intel_dp_hdcp2_capable,
> > >       .protocol = HDCP_PROTOCOL_DP,
> > >  };
> > >
> > > @@ -721,6 +537,46 @@ intel_dp_mst_hdcp_stream_encryption(struct
> > > intel_connector *connector,
> > >       return 0;
> > >  }
> > >
> > > +static int
> > > +intel_dp_mst_hdcp1_post_encryption(struct drm_connector
> > > *drm_connector)
> > > +{
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     int ret;
> > > +
> > > +     ret = intel_hdcp1_post_encryption(drm_connector);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     return intel_dp_mst_hdcp_stream_encryption(connector, true);
> > > +}
> > > +
> > > +static int intel_dp_mst_hdcp1_disable(struct drm_connector
> > > *drm_connector)
> > > +{
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > > +     struct drm_i915_private *i915 = to_i915(connector->base.dev);
> > > +     int ret;
> > > +
> > > +     ret = intel_dp_mst_hdcp_stream_encryption(connector, true);
> > > +     if (ret) {
> > > +             drm_err(&i915->drm,
> > > +                     "[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
> > > +                     connector->base.name, connector->base.base.id);
> > > +             return ret;
> > > +     }
> > > +
> > > +     /*
> > > +      * If there are other connectors on this port using HDCP,
> > > +      * don't disable it until it disabled HDCP encryption for
> > > +      * all connectors in MST topology.
> > > +     */
> > > +     if (dig_port->num_hdcp_streams > 0)
> > > +             return 0;
> > > +
> > > +     return intel_hdcp1_disable(drm_connector);
> > > +}
> > > +
> > >  static int
> > >  intel_dp_mst_hdcp2_stream_encryption(struct intel_connector
> > > *connector,
> > >                                    bool enable)
> > > @@ -779,45 +635,85 @@ int intel_dp_mst_hdcp2_check_link(struct
> > > intel_digital_port *dig_port,
> > >  }
> > >
> > >  static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
> > > -     .write_an_aksv = intel_dp_hdcp_write_an_aksv,
> > > -     .read_bksv = intel_dp_hdcp_read_bksv,
> > > -     .read_bstatus = intel_dp_hdcp_read_bstatus,
> > > -     .repeater_present = intel_dp_hdcp_repeater_present,
> > > -     .read_ri_prime = intel_dp_hdcp_read_ri_prime,
> > > -     .read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
> > > -     .read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
> > > -     .read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
> > >       .toggle_signalling = intel_dp_hdcp_toggle_signalling,
> > > -     .stream_encryption = intel_dp_mst_hdcp_stream_encryption,
> > > -     .check_link = intel_dp_hdcp_check_link,
> > > -     .hdcp_capable = intel_dp_hdcp_capable,
> > >       .write_2_2_msg = intel_dp_hdcp2_write_msg,
> > >       .read_2_2_msg = intel_dp_hdcp2_read_msg,
> > >       .config_stream_type = intel_dp_hdcp2_config_stream_type,
> > >       .stream_2_2_encryption = intel_dp_mst_hdcp2_stream_encryption,
> > >       .check_2_2_link = intel_dp_mst_hdcp2_check_link,
> > > -     .hdcp_2_2_capable = intel_dp_hdcp2_capable,
> > >       .protocol = HDCP_PROTOCOL_DP,
> > >  };
> > >
> > > +static const struct drm_hdcp_helper_funcs intel_dp_hdcp_helper_funcs
> = {
> > > +     .setup = intel_hdcp_setup,
> > > +     .load_keys = intel_hdcp_load_keys,
> > > +     .hdcp2_capable = intel_dp_hdcp2_capable,
> > > +     .hdcp2_enable = intel_hdcp2_enable,
> > > +     .hdcp2_check_link = intel_hdcp2_check_link,
> > > +     .hdcp2_disable = intel_hdcp2_disable,
> > > +     .hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
> > > +     .hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> > > +     .hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
> > > +     .hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> > > +     .hdcp1_match_ri = intel_hdcp1_match_ri,
> > > +     .hdcp1_post_encryption = intel_hdcp1_post_encryption,
> > > +     .hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> > > +     .hdcp1_disable = intel_hdcp1_disable,
> > > +};
> > > +
> > > +static const struct drm_hdcp_helper_funcs
> > > intel_dp_mst_hdcp_helper_funcs = {
> > > +     .setup = intel_hdcp_setup,
> > > +     .load_keys = intel_hdcp_load_keys,
> > > +     .hdcp2_capable = intel_dp_hdcp2_capable,
> > > +     .hdcp2_enable = intel_hdcp2_enable,
> > > +     .hdcp2_check_link = intel_hdcp2_check_link,
> > > +     .hdcp2_disable = intel_hdcp2_disable,
> > > +     .hdcp1_send_an_aksv = intel_dp_hdcp1_send_an_aksv,
> > > +     .hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> > > +     .hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
> > > +     .hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> > > +     .hdcp1_match_ri = intel_hdcp1_match_ri,
> > > +     .hdcp1_post_encryption = intel_dp_mst_hdcp1_post_encryption,
> > > +     .hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> > > +     .hdcp1_disable = intel_dp_mst_hdcp1_disable,
> > > +};
> > > +
> > >  int intel_dp_hdcp_init(struct intel_digital_port *dig_port,
> > > -                    struct intel_connector *intel_connector)
> > > +                    struct intel_connector *connector)
> > >  {
> > > -     struct drm_device *dev = intel_connector->base.dev;
> > > -     struct drm_i915_private *dev_priv = to_i915(dev);
> > > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > >       struct intel_encoder *intel_encoder = &dig_port->base;
> > >       enum port port = intel_encoder->port;
> > >       struct intel_dp *intel_dp = &dig_port->dp;
> > > +     struct drm_hdcp_helper_data *data;
> > > +     const struct drm_hdcp_helper_funcs *helper_funcs;
> > > +     const struct intel_hdcp_shim *intel_shim;
> > > +     int ret;
> > >
> > > -     if (!is_hdcp_supported(dev_priv, port))
> > > +     if (!is_hdcp_supported(dev_priv, port) ||
> > > intel_dp_is_edp(intel_dp))
> > >               return 0;
> > >
> > > -     if (intel_connector->mst_port)
> > > -             return intel_hdcp_init(intel_connector, dig_port,
> > > -                                    &intel_dp_mst_hdcp_shim);
> > > -     else if (!intel_dp_is_edp(intel_dp))
> > > -             return intel_hdcp_init(intel_connector, dig_port,
> > > -                                    &intel_dp_hdcp_shim);
> > > +     if (connector->mst_port) {
> > > +             helper_funcs = &intel_dp_mst_hdcp_helper_funcs;
> > > +             intel_shim = &intel_dp_mst_hdcp_shim;
> > > +     } else {
> > > +             helper_funcs = &intel_dp_hdcp_helper_funcs;
> > > +             intel_shim = &intel_dp_hdcp_shim;
> > > +     }
> > > +
> > > +     data = drm_hdcp_helper_initialize_dp(
> > > +             &connector->base, &dig_port->dp.aux, helper_funcs, true);
> >
> > The alignment here needs fixing
> >
> > > +     if (IS_ERR(data)) {
> > > +             drm_dbg_kms(&dev_priv->drm, "HDCP init failed,
> > > skipping.\n");
> > > +             return PTR_ERR(data);
> > > +     }
> > > +
> > > +     ret = intel_hdcp_init(connector, dig_port, intel_shim);
> > > +     if (ret) {
> > > +             drm_hdcp_helper_destroy(data);
> > > +             return ret;
> > > +     }
> > >
> > > +     connector->hdcp_helper_data = data;
> > >       return 0;
> > >  }
> > > diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > > b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > > index 03604a37931c..ececb7aa4b90 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > > @@ -27,6 +27,7 @@
> > >  #include <drm/drm_atomic_helper.h>
> > >  #include <drm/drm_edid.h>
> > >  #include <drm/drm_probe_helper.h>
> > > +#include <drm/display/drm_hdcp_helper.h>
> > >
> > >  #include "i915_drv.h"
> > >  #include "intel_atomic.h"
> > > @@ -40,7 +41,6 @@
> > >  #include "intel_dp_hdcp.h"
> > >  #include "intel_dp_mst.h"
> > >  #include "intel_dpio_phy.h"
> > > -#include "intel_hdcp.h"
> > >  #include "intel_hotplug.h"
> > >  #include "skl_scaler.h"
> > >
> > > @@ -371,7 +371,10 @@ static void intel_mst_disable_dp(struct
> > > intel_atomic_state *state,
> > >       drm_dbg_kms(&i915->drm, "active links %d\n",
> > >                   intel_dp->active_mst_links);
> > >
> > > -     intel_hdcp_disable(intel_mst->connector);
> > > +     if (connector->hdcp_helper_data)
> > > +             drm_hdcp_helper_atomic_commit(connector-
> > > >hdcp_helper_data,
> > > +                                           &state->base,
> > > +                                           &dig_port->hdcp_mutex);
> > >
> > >       drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state,
> > >                             drm_atomic_get_mst_payload_state(mst_state,
> > > connector->port));
> > > @@ -579,11 +582,10 @@ static void intel_mst_enable_dp(struct
> > > intel_atomic_state *state,
> > >       intel_audio_codec_enable(encoder, pipe_config, conn_state);
> > >
> > >       /* Enable hdcp if it's desired */
> > > -     if (conn_state->content_protection ==
> > > -         DRM_MODE_CONTENT_PROTECTION_DESIRED)
> > > -             intel_hdcp_enable(to_intel_connector(conn_state-
> > > >connector),
> > > -                               pipe_config,
> > > -                               (u8)conn_state->hdcp_content_type);
> > > +     if (connector->hdcp_helper_data)
> > > +             drm_hdcp_helper_atomic_commit(connector-
> > > >hdcp_helper_data,
> > > +                                           &state->base,
> > > +                                           &dig_port->hdcp_mutex);
> > >  }
> > >
> > >  static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder
> *encoder,
> > > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > index 61a862ae1f28..f09afbc9567b 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c
> > > @@ -140,67 +140,10 @@ static int intel_hdcp_prepare_streams(struct
> > > intel_connector *connector)
> > >       return 0;
> > >  }
> > >
> > > -static
> > > -bool intel_hdcp_is_ksv_valid(u8 *ksv)
> > > -{
> > > -     int i, ones = 0;
> > > -     /* KSV has 20 1's and 20 0's */
> > > -     for (i = 0; i < DRM_HDCP_KSV_LEN; i++)
> > > -             ones += hweight8(ksv[i]);
> > > -     if (ones != 20)
> > > -             return false;
> > > -
> > > -     return true;
> > > -}
> > > -
> > > -static
> > > -int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port,
> > > -                            const struct intel_hdcp_shim *shim, u8 *bksv)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     int ret, i, tries = 2;
> > > -
> > > -     /* HDCP spec states that we must retry the bksv if it is invalid */
> > > -     for (i = 0; i < tries; i++) {
> > > -             ret = shim->read_bksv(dig_port, bksv);
> > > -             if (ret)
> > > -                     return ret;
> > > -             if (intel_hdcp_is_ksv_valid(bksv))
> > > -                     break;
> > > -     }
> > > -     if (i == tries) {
> > > -             drm_dbg_kms(&i915->drm, "Bksv is invalid\n");
> > > -             return -ENODEV;
> > > -     }
> > > -
> > > -     return 0;
> > > -}
> > > -
> > > -/* Is HDCP1.4 capable on Platform and Sink */
> > > -int intel_hdcp_capable(struct intel_connector *connector, bool
> *capable)
> > > -{
> > > -     struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > > -     const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> > > -     u8 bksv[5];
> > > -
> > > -     *capable = false;
> > > -
> > > -     if (!shim)
> > > -             return 0;
> > > -
> > > -     if (shim->hdcp_capable)
> > > -             return shim->hdcp_capable(dig_port, capable);
> > > -
> > > -     if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
> > > -             *capable = true;
> > > -
> > > -     return 0;
> > > -}
> > > -
> > >  /* Is HDCP2.2 capable on Platform and Sink */
> > > -int intel_hdcp2_capable(struct intel_connector *connector, bool
> *capable)
> > > +int intel_hdcp2_capable(struct drm_connector *drm_connector, bool
> > > *capable)
> > >  {
> > > -     struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > >       struct intel_hdcp *hdcp = &connector->hdcp;
> > >
> > > @@ -218,16 +161,26 @@ int intel_hdcp2_capable(struct intel_connector
> > > *connector, bool *capable)
> > >       }
> > >       mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
> > >
> > > -     /* Sink's capability for HDCP2.2 */
> > > -     return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
> >
> > Did you miss adding the drm hdcp helper  here to check sink capability
> >
> Hey,
> As the flow change and the protocol was split away from the full
> implementation, the function here only checks if the driver supports
> it. the call to sync happens in the helper.

Okay got it,

> > > +     return 0;
> > >  }
> > >
> > > -static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv,
> > > -                           enum transcoder cpu_transcoder, enum port
> > > port)
> > > +int intel_hdcp1_check_link(struct drm_connector *drm_connector)
> > >  {
> > > -     return intel_de_read(dev_priv,
> > > -                          HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> > > -            HDCP_STATUS_ENC;
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > +     enum transcoder cpu_transcoder = connector-
> > > >hdcp.cpu_transcoder;
> > > +     enum port port = dig_port->base.port;
> > > +     u32 val;
> > > +
> > > +     val = intel_de_read(dev_priv,
> > > +                         HDCP_STATUS(dev_priv, cpu_transcoder, port));
> > > +
> > > +     if (val & HDCP_STATUS_ENC)
> > > +             return 0;
> > > +
> > > +     return -EINVAL;
> > >  }
> > >
> > >  static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
> > > @@ -238,27 +191,6 @@ static bool intel_hdcp2_in_use(struct
> > > drm_i915_private *dev_priv,
> > >              LINK_ENCRYPTION_STATUS;
> > >  }
> > >
> > > -static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *dig_port,
> > > -                                 const struct intel_hdcp_shim *shim)
> > > -{
> > > -     int ret, read_ret;
> > > -     bool ksv_ready;
> > > -
> > > -     /* Poll for ksv list ready (spec says max time allowed is 5s) */
> > > -     ret = __wait_for(read_ret = shim->read_ksv_ready(dig_port,
> > > -                                                      &ksv_ready),
> > > -                      read_ret || ksv_ready, 5 * 1000 * 1000, 1000,
> > > -                      100 * 1000);
> > > -     if (ret)
> > > -             return ret;
> > > -     if (read_ret)
> > > -             return read_ret;
> > > -     if (!ksv_ready)
> > > -             return -ETIMEDOUT;
> > > -
> > > -     return 0;
> > > -}
> > > -
> > >  static bool hdcp_key_loadable(struct drm_i915_private *dev_priv)
> > >  {
> > >       enum i915_power_well_id id;
> > > @@ -294,11 +226,18 @@ static void intel_hdcp_clear_keys(struct
> > > drm_i915_private *dev_priv)
> > >                      HDCP_KEY_LOAD_DONE | HDCP_KEY_LOAD_STATUS |
> > > HDCP_FUSE_IN_PROGRESS | HDCP_FUSE_ERROR | HDCP_FUSE_DONE);
> > >  }
> > >
> > > -static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
> > > +int intel_hdcp_load_keys(struct drm_connector *drm_connector)
> > >  {
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > >       int ret;
> > >       u32 val;
> > >
> > > +     if (!hdcp_key_loadable(dev_priv)) {
> > > +             drm_err(&dev_priv->drm, "HDCP key Load is not
> > > possible\n");
> > > +             return -ENXIO;
> > > +     }
> > > +
> > >       val = intel_de_read(dev_priv, HDCP_KEY_STATUS);
> > >       if ((val & HDCP_KEY_LOAD_DONE) && (val &
> > > HDCP_KEY_LOAD_STATUS))
> > >               return 0;
> > > @@ -308,8 +247,11 @@ static int intel_hdcp_load_keys(struct
> > > drm_i915_private *dev_priv)
> > >        * out of reset. So if Key is not already loaded, its an error state.
> > >        */
> > >       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
> > > -             if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) &
> > > HDCP_KEY_LOAD_DONE))
> > > -                     return -ENXIO;
> > > +             if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) &
> > > +                   HDCP_KEY_LOAD_DONE)) {
> > > +                     ret = -ENXIO;
> > > +                     goto err;
> > > +             }
> > >
> > >       /*
> > >        * Initiate loading the HDCP key from fuses.
> > > @@ -325,7 +267,7 @@ static int intel_hdcp_load_keys(struct
> > > drm_i915_private *dev_priv)
> > >                       drm_err(&dev_priv->drm,
> > >                               "Failed to initiate HDCP key load (%d)\n",
> > >                               ret);
> > > -                     return ret;
> > > +                     goto err;
> > >               }
> > >       } else {
> > >               intel_de_write(dev_priv, HDCP_KEY_CONF,
> > > HDCP_KEY_LOAD_TRIGGER);
> > > @@ -335,15 +277,21 @@ static int intel_hdcp_load_keys(struct
> > > drm_i915_private *dev_priv)
> > >       ret = __intel_wait_for_register(&dev_priv->uncore,
> > > HDCP_KEY_STATUS,
> > >                                       HDCP_KEY_LOAD_DONE,
> > > HDCP_KEY_LOAD_DONE,
> > >                                       10, 1, &val);
> > > -     if (ret)
> > > -             return ret;
> > > -     else if (!(val & HDCP_KEY_LOAD_STATUS))
> > > -             return -ENXIO;
> > > +     if (ret) {
> > > +             goto err;
> > > +     } else if (!(val & HDCP_KEY_LOAD_STATUS)) {
> > > +             ret = -ENXIO;
> > > +             goto err;
> > > +     }
> > >
> > >       /* Send Aksv over to PCH display for use in authentication */
> > >       intel_de_write(dev_priv, HDCP_KEY_CONF,
> > > HDCP_AKSV_SEND_TRIGGER);
> > >
> > >       return 0;
> > > +
> > > +err:
> > > +     intel_hdcp_clear_keys(dev_priv);
> > > +     return ret;
> > >  }
> > >
> > >  /* Returns updated SHA-1 index */
> > > @@ -399,25 +347,21 @@ u32 intel_hdcp_get_repeater_ctl(struct
> > > drm_i915_private *dev_priv,
> > >       }
> > >  }
> > >
> > > -static
> > > -int intel_hdcp_validate_v_prime(struct intel_connector *connector,
> > > -                             const struct intel_hdcp_shim *shim,
> > > -                             u8 *ksv_fifo, u8 num_downstream, u8
> > > *bstatus)
> > > +int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
> > > +                            u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
> > > +                            u32 *v_prime)
> > >  {
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > >       struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > >       enum transcoder cpu_transcoder = connector-
> > > >hdcp.cpu_transcoder;
> > >       enum port port = dig_port->base.port;
> > > -     u32 vprime, sha_text, sha_leftovers, rep_ctl;
> > > +     u32 sha_text, sha_leftovers, rep_ctl;
> > >       int ret, i, j, sha_idx;
> > >
> > >       /* Process V' values from the receiver */
> > > -     for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
> > > -             ret = shim->read_v_prime_part(dig_port, i, &vprime);
> > > -             if (ret)
> > > -                     return ret;
> > > -             intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), vprime);
> > > -     }
> > > +     for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++)
> > > +             intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i),
> > > v_prime[i]);
> > >
> > >       /*
> > >        * We need to write the concatenation of all device KSVs, BINFO (DP)
> > > ||
> > > @@ -642,131 +586,38 @@ int intel_hdcp_validate_v_prime(struct
> > > intel_connector *connector,
> > >       return 0;
> > >  }
> > >
> > > -/* Implements Part 2 of the HDCP authorization procedure */
> > > -static
> > > -int intel_hdcp_auth_downstream(struct intel_connector *connector)
> > > +int intel_hdcp1_store_receiver_info(struct drm_connector
> > > *drm_connector,
> > > +                                 u32 *ksv, u32 status, u8 caps,
> > > +                                 bool repeater_present)
> > >  {
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > >       struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > -     const struct intel_hdcp_shim *shim = connector->hdcp.shim;
> > > -     u8 bstatus[2], num_downstream, *ksv_fifo;
> > > -     int ret, i, tries = 3;
> > > -
> > > -     ret = intel_hdcp_poll_ksv_fifo(dig_port, shim);
> > > -     if (ret) {
> > > -             drm_dbg_kms(&dev_priv->drm,
> > > -                         "KSV list failed to become ready (%d)\n", ret);
> > > -             return ret;
> > > -     }
> > > -
> > > -     ret = shim->read_bstatus(dig_port, bstatus);
> > > -     if (ret)
> > > -             return ret;
> > > -
> > > -     if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
> > > -         DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
> > > -             drm_dbg_kms(&dev_priv->drm, "Max Topology Limit
> > > Exceeded\n");
> > > -             return -EPERM;
> > > -     }
> > > -
> > > -     /*
> > > -      * When repeater reports 0 device count, HDCP1.4 spec allows
> > > disabling
> > > -      * the HDCP encryption. That implies that repeater can't have its own
> > > -      * display. As there is no consumption of encrypted content in the
> > > -      * repeater with 0 downstream devices, we are failing the
> > > -      * authentication.
> > > -      */
> > > -     num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
> > > -     if (num_downstream == 0) {
> > > -             drm_dbg_kms(&dev_priv->drm,
> > > -                         "Repeater with zero downstream devices\n");
> > > -             return -EINVAL;
> > > -     }
> > > -
> > > -     ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream,
> > > GFP_KERNEL);
> > > -     if (!ksv_fifo) {
> > > -             drm_dbg_kms(&dev_priv->drm, "Out of mem: ksv_fifo\n");
> > > -             return -ENOMEM;
> > > -     }
> > > -
> > > -     ret = shim->read_ksv_fifo(dig_port, num_downstream, ksv_fifo);
> > > -     if (ret)
> > > -             goto err;
> > > -
> > > -     if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, ksv_fifo,
> > > -                                     num_downstream) > 0) {
> > > -             drm_err(&dev_priv->drm, "Revoked Ksv(s) in ksv_fifo\n");
> > > -             ret = -EPERM;
> > > -             goto err;
> > > -     }
> > > +     enum transcoder cpu_transcoder = connector-
> > > >hdcp.cpu_transcoder;
> > > +     enum port port = dig_port->base.port;
> > >
> > > -     /*
> > > -      * When V prime mismatches, DP Spec mandates re-read of
> > > -      * V prime atleast twice.
> > > -      */
> > > -     for (i = 0; i < tries; i++) {
> > > -             ret = intel_hdcp_validate_v_prime(connector, shim,
> > > -                                               ksv_fifo, num_downstream,
> > > -                                               bstatus);
> > > -             if (!ret)
> > > -                     break;
> > > -     }
> > > +     intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder,
> > > port),
> > > +                    ksv[0]);
> > > +     intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder,
> > > port),
> > > +                    ksv[1]);
> > >
> > > -     if (i == tries) {
> > > -             drm_dbg_kms(&dev_priv->drm,
> > > -                         "V Prime validation failed.(%d)\n", ret);
> > > -             goto err;
> > > -     }
> > > +     if (repeater_present)
> > > +             intel_de_write(dev_priv, HDCP_REP_CTL,
> > > +                            intel_hdcp_get_repeater_ctl(
> > > +                                    dev_priv, cpu_transcoder, port));
> > >
> > > -     drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (%d downstream
> > > devices)\n",
> > > -                 num_downstream);
> > > -     ret = 0;
> > > -err:
> > > -     kfree(ksv_fifo);
> > > -     return ret;
> > > +     return 0;
> > >  }
> > >
> > > -/* Implements Part 1 of the HDCP authorization procedure */
> > > -static int intel_hdcp_auth(struct intel_connector *connector)
> > > +int intel_hdcp1_read_an(struct drm_connector *drm_connector,
> > > +                     struct drm_hdcp_an *an)
> > >  {
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > >       struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > > -     const struct intel_hdcp_shim *shim = hdcp->shim;
> > >       enum transcoder cpu_transcoder = connector-
> > > >hdcp.cpu_transcoder;
> > >       enum port port = dig_port->base.port;
> > > -     unsigned long r0_prime_gen_start;
> > > -     int ret, i, tries = 2;
> > > -     union {
> > > -             u32 reg[2];
> > > -             u8 shim[DRM_HDCP_AN_LEN];
> > > -     } an;
> > > -     union {
> > > -             u32 reg[2];
> > > -             u8 shim[DRM_HDCP_KSV_LEN];
> > > -     } bksv;
> > > -     union {
> > > -             u32 reg;
> > > -             u8 shim[DRM_HDCP_RI_LEN];
> > > -     } ri;
> > > -     bool repeater_present, hdcp_capable;
> > > -
> > > -     /*
> > > -      * Detects whether the display is HDCP capable. Although we check
> > > for
> > > -      * valid Bksv below, the HDCP over DP spec requires that we check
> > > -      * whether the display supports HDCP before we write An. For HDMI
> > > -      * displays, this is not necessary.
> > > -      */
> > > -     if (shim->hdcp_capable) {
> > > -             ret = shim->hdcp_capable(dig_port, &hdcp_capable);
> > > -             if (ret)
> > > -                     return ret;
> > > -             if (!hdcp_capable) {
> > > -                     drm_dbg_kms(&dev_priv->drm,
> > > -                                 "Panel is not HDCP capable\n");
> > > -                     return -EINVAL;
> > > -             }
> > > -     }
> > > +     int i;
> > >
> > >       /* Initialize An with 2 random values and acquire it */
> > >       for (i = 0; i < 2; i++)
> > > @@ -784,92 +635,81 @@ static int intel_hdcp_auth(struct
> intel_connector
> > > *connector)
> > >               return -ETIMEDOUT;
> > >       }
> > >
> > > -     an.reg[0] = intel_de_read(dev_priv,
> > > -                               HDCP_ANLO(dev_priv, cpu_transcoder,
> > > port));
> > > -     an.reg[1] = intel_de_read(dev_priv,
> > > -                               HDCP_ANHI(dev_priv, cpu_transcoder,
> > > port));
> > > -     ret = shim->write_an_aksv(dig_port, an.shim);
> > > -     if (ret)
> > > -             return ret;
> > > +     an->words[0] = intel_de_read(dev_priv,
> > > +                                  HDCP_ANLO(dev_priv, cpu_transcoder,
> > > port));
> > > +     an->words[1] = intel_de_read(dev_priv,
> > > +                                  HDCP_ANHI(dev_priv, cpu_transcoder,
> > > port));
> > >
> > > -     r0_prime_gen_start = jiffies;
> > > -
> > > -     memset(&bksv, 0, sizeof(bksv));
> > > -
> > > -     ret = intel_hdcp_read_valid_bksv(dig_port, shim, bksv.shim);
> > > -     if (ret < 0)
> > > -             return ret;
> > > -
> > > -     if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, bksv.shim, 1) >
> > > 0) {
> > > -             drm_err(&dev_priv->drm, "BKSV is revoked\n");
> > > -             return -EPERM;
> > > -     }
> > > -
> > > -     intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder,
> > > port),
> > > -                    bksv.reg[0]);
> > > -     intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder,
> > > port),
> > > -                    bksv.reg[1]);
> > > -
> > > -     ret = shim->repeater_present(dig_port, &repeater_present);
> > > -     if (ret)
> > > -             return ret;
> > > -     if (repeater_present)
> > > -             intel_de_write(dev_priv, HDCP_REP_CTL,
> > > -                            intel_hdcp_get_repeater_ctl(dev_priv,
> > > cpu_transcoder, port));
> > > +     return 0;
> > > +}
> > >
> > > -     ret = shim->toggle_signalling(dig_port, cpu_transcoder, true);
> > > -     if (ret)
> > > -             return ret;
> > > +int intel_hdcp1_enable_encryption(struct drm_connector
> > > *drm_connector)
> > > +{
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > +     enum transcoder cpu_transcoder = connector-
> > > >hdcp.cpu_transcoder;
> > > +     enum port port = dig_port->base.port;
> > >
> > >       intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder,
> > > port),
> > >                      HDCP_CONF_AUTH_AND_ENC);
> > >
> > > +     return 0;
> > > +}
> > > +
> > > +int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector)
> > > +{
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > +     enum transcoder cpu_transcoder = connector-
> > > >hdcp.cpu_transcoder;
> > > +     enum port port = dig_port->base.port;
> > > +
> > >       /* Wait for R0 ready */
> > > -     if (wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> > > cpu_transcoder, port)) &
> > > -                  (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), 1)) {
> > > +     if (wait_for((intel_de_read(dev_priv,
> > > +                                 HDCP_STATUS(dev_priv, cpu_transcoder,
> > > +                                             port))) &
> > > +                          (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC),
> > > +                  1)) {
> >
> > Alignment here seem wrong
> >
> > >               drm_err(&dev_priv->drm, "Timed out waiting for R0
> > > ready\n");
> > >               return -ETIMEDOUT;
> > >       }
> > >
> > > -     /*
> > > -      * Wait for R0' to become available. The spec says 100ms from Aksv,
> > > but
> > > -      * some monitors can take longer than this. We'll set the timeout at
> > > -      * 300ms just to be sure.
> > > -      *
> > > -      * On DP, there's an R0_READY bit available but no such bit
> > > -      * exists on HDMI. Since the upper-bound is the same, we'll just do
> > > -      * the stupid thing instead of polling on one and not the other.
> > > -      */
> > > -     wait_remaining_ms_from_jiffies(r0_prime_gen_start, 300);
> > > -
> > > -     tries = 3;
> > > +     return 0;
> > > +}
> > >
> > > -     /*
> > > -      * DP HDCP Spec mandates the two more reattempt to read R0,
> > > incase
> > > -      * of R0 mismatch.
> > > -      */
> > > -     for (i = 0; i < tries; i++) {
> > > -             ri.reg = 0;
> > > -             ret = shim->read_ri_prime(dig_port, ri.shim);
> > > -             if (ret)
> > > -                     return ret;
> > > -             intel_de_write(dev_priv,
> > > -                            HDCP_RPRIME(dev_priv, cpu_transcoder, port),
> > > -                            ri.reg);
> > > +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32
> > > ri_prime)
> > > +{
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > +     enum transcoder cpu_transcoder = connector-
> > > >hdcp.cpu_transcoder;
> > > +     enum port port = dig_port->base.port;
> > >
> > > -             /* Wait for Ri prime match */
> > > -             if (!wait_for(intel_de_read(dev_priv,
> > > HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
> > > -                           (HDCP_STATUS_RI_MATCH |
> > > HDCP_STATUS_ENC), 1))
> > > -                     break;
> > > -     }
> > > +     intel_de_write(dev_priv, HDCP_RPRIME(dev_priv, cpu_transcoder,
> > > port),
> > > +                    ri_prime);
> > >
> > > -     if (i == tries) {
> > > -             drm_dbg_kms(&dev_priv->drm,
> > > -                         "Timed out waiting for Ri prime match (%x)\n",
> > > -                         intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> > > -                                       cpu_transcoder, port)));
> > > +     /* Wait for Ri prime match */
> > > +     if (wait_for(intel_de_read(dev_priv,
> > > +                                HDCP_STATUS(dev_priv, cpu_transcoder,
> > > port)) &
> > > +                          (HDCP_STATUS_RI_MATCH |
> > > HDCP_STATUS_ENC),
> > > +                  1))
> > >               return -ETIMEDOUT;
> > > -     }
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +int intel_hdcp1_post_encryption(struct drm_connector
> *drm_connector)
> > > +{
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > +     enum transcoder cpu_transcoder = connector-
> > > >hdcp.cpu_transcoder;
> > > +     enum port port = dig_port->base.port;
> > >
> > >       /* Wait for encryption confirmation */
> > >       if (intel_de_wait_for_set(dev_priv,
> > > @@ -880,56 +720,22 @@ static int intel_hdcp_auth(struct
> intel_connector
> > > *connector)
> > >               return -ETIMEDOUT;
> > >       }
> > >
> > > -     /* DP MST Auth Part 1 Step 2.a and Step 2.b */
> > > -     if (shim->stream_encryption) {
> > > -             ret = shim->stream_encryption(connector, true);
> > > -             if (ret) {
> > > -                     drm_err(&dev_priv->drm, "[%s:%d] Failed to enable
> > > HDCP 1.4 stream enc\n",
> > > -                             connector->base.name, connector-
> > > >base.base.id);
> > > -                     return ret;
> > > -             }
> > > -             drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s
> > > stream encrypted\n",
> > > -                         transcoder_name(hdcp->stream_transcoder));
> > > -     }
> > > -
> > > -     if (repeater_present)
> > > -             return intel_hdcp_auth_downstream(connector);
> > > -
> > > -     drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (no repeater
> > > present)\n");
> > >       return 0;
> > >  }
> > >
> > > -static int _intel_hdcp_disable(struct intel_connector *connector)
> > > +int intel_hdcp1_disable(struct drm_connector *drm_connector)
> > >  {
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > >       struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > >       struct intel_hdcp *hdcp = &connector->hdcp;
> > >       enum port port = dig_port->base.port;
> > >       enum transcoder cpu_transcoder = hdcp->cpu_transcoder;
> > >       u32 repeater_ctl;
> > > -     int ret;
> > >
> > >       drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being
> > > disabled...\n",
> > >                   connector->base.name, connector->base.base.id);
> > >
> > > -     if (hdcp->shim->stream_encryption) {
> > > -             ret = hdcp->shim->stream_encryption(connector, false);
> > > -             if (ret) {
> > > -                     drm_err(&dev_priv->drm, "[%s:%d] Failed to disable
> > > HDCP 1.4 stream enc\n",
> > > -                             connector->base.name, connector-
> > > >base.base.id);
> > > -                     return ret;
> > > -             }
> > > -             drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s
> > > stream encryption disabled\n",
> > > -                         transcoder_name(hdcp->stream_transcoder));
> > > -             /*
> > > -              * If there are other connectors on this port using HDCP,
> > > -              * don't disable it until it disabled HDCP encryption for
> > > -              * all connectors in MST topology.
> > > -              */
> > > -             if (dig_port->num_hdcp_streams > 0)
> > > -                     return 0;
> > > -     }
> > > -
> > >       hdcp->hdcp_encrypted = false;
> > >       intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder,
> > > port), 0);
> > >       if (intel_de_wait_for_clear(dev_priv,
> > > @@ -945,190 +751,9 @@ static int _intel_hdcp_disable(struct
> > > intel_connector *connector)
> > >       intel_de_write(dev_priv, HDCP_REP_CTL,
> > >                      intel_de_read(dev_priv, HDCP_REP_CTL) &
> > > ~repeater_ctl);
> > >
> > > -     ret = hdcp->shim->toggle_signalling(dig_port, cpu_transcoder,
> > > false);
> > > -     if (ret) {
> > > -             drm_err(&dev_priv->drm, "Failed to disable HDCP
> > > signalling\n");
> > > -             return ret;
> > > -     }
> > > -
> > > -     drm_dbg_kms(&dev_priv->drm, "HDCP is disabled\n");
> > >       return 0;
> > >  }
> > >
> > > -static int _intel_hdcp_enable(struct intel_connector *connector)
> > > -{
> > > -     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > > -     int i, ret, tries = 3;
> > > -
> > > -     drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being
> > > enabled...\n",
> > > -                 connector->base.name, connector->base.base.id);
> > > -
> > > -     if (!hdcp_key_loadable(dev_priv)) {
> > > -             drm_err(&dev_priv->drm, "HDCP key Load is not
> > > possible\n");
> > > -             return -ENXIO;
> > > -     }
> > > -
> > > -     for (i = 0; i < KEY_LOAD_TRIES; i++) {
> > > -             ret = intel_hdcp_load_keys(dev_priv);
> > > -             if (!ret)
> > > -                     break;
> > > -             intel_hdcp_clear_keys(dev_priv);
> > > -     }
> > > -     if (ret) {
> > > -             drm_err(&dev_priv->drm, "Could not load HDCP keys,
> > > (%d)\n",
> > > -                     ret);
> > > -             return ret;
> > > -     }
> > > -
> > > -     /* Incase of authentication failures, HDCP spec expects reauth. */
> > > -     for (i = 0; i < tries; i++) {
> > > -             ret = intel_hdcp_auth(connector);
> > > -             if (!ret) {
> > > -                     hdcp->hdcp_encrypted = true;
> > > -                     return 0;
> > > -             }
> > > -
> > > -             drm_dbg_kms(&dev_priv->drm, "HDCP Auth failure (%d)\n",
> > > ret);
> > > -
> > > -             /* Ensuring HDCP encryption and signalling are stopped. */
> > > -             _intel_hdcp_disable(connector);
> > > -     }
> > > -
> > > -     drm_dbg_kms(&dev_priv->drm,
> > > -                 "HDCP authentication failed (%d tries/%d)\n", tries, ret);
> > > -     return ret;
> > > -}
> > > -
> > > -static struct intel_connector *intel_hdcp_to_connector(struct intel_hdcp
> > > *hdcp)
> > > -{
> > > -     return container_of(hdcp, struct intel_connector, hdcp);
> > > -}
> > > -
> > > -static void intel_hdcp_update_value(struct intel_connector *connector,
> > > -                                 u64 value, bool update_property)
> > > -{
> > > -     struct drm_device *dev = connector->base.dev;
> > > -     struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > > -
> > > -     drm_WARN_ON(connector->base.dev, !mutex_is_locked(&hdcp-
> > > >mutex));
> > > -
> > > -     if (hdcp->value == value)
> > > -             return;
> > > -
> > > -     drm_WARN_ON(dev, !mutex_is_locked(&dig_port->hdcp_mutex));
> > > -
> > > -     if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> > > -             if (!drm_WARN_ON(dev, dig_port->num_hdcp_streams ==
> > > 0))
> > > -                     dig_port->num_hdcp_streams--;
> > > -     } else if (value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
> > > -             dig_port->num_hdcp_streams++;
> > > -     }
> > > -
> > > -     hdcp->value = value;
> > > -     if (update_property) {
> > > -             drm_connector_get(&connector->base);
> > > -             schedule_work(&hdcp->prop_work);
> > > -     }
> > > -}
> > > -
> > > -/* Implements Part 3 of the HDCP authorization procedure */
> > > -static int intel_hdcp_check_link(struct intel_connector *connector)
> > > -{
> > > -     struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > > -     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > > -     enum port port = dig_port->base.port;
> > > -     enum transcoder cpu_transcoder;
> > > -     int ret = 0;
> > > -
> > > -     mutex_lock(&hdcp->mutex);
> > > -     mutex_lock(&dig_port->hdcp_mutex);
> > > -
> > > -     cpu_transcoder = hdcp->cpu_transcoder;
> > > -
> > > -     /* Check_link valid only when HDCP1.4 is enabled */
> > > -     if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED
> > > ||
> > > -         !hdcp->hdcp_encrypted) {
> > > -             ret = -EINVAL;
> > > -             goto out;
> > > -     }
> > > -
> > > -     if (drm_WARN_ON(&dev_priv->drm,
> > > -                     !intel_hdcp_in_use(dev_priv, cpu_transcoder,
> > > port))) {
> > > -             drm_err(&dev_priv->drm,
> > > -                     "%s:%d HDCP link stopped encryption,%x\n",
> > > -                     connector->base.name, connector->base.base.id,
> > > -                     intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
> > > cpu_transcoder, port)));
> > > -             ret = -ENXIO;
> > > -             intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > > -                                     true);
> > > -             goto out;
> > > -     }
> > > -
> > > -     if (hdcp->shim->check_link(dig_port, connector)) {
> > > -             if (hdcp->value !=
> > > DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> > > -                     intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_ENABLED, true);
> > > -             }
> > > -             goto out;
> > > -     }
> > > -
> > > -     drm_dbg_kms(&dev_priv->drm,
> > > -                 "[%s:%d] HDCP link failed, retrying authentication\n",
> > > -                 connector->base.name, connector->base.base.id);
> > > -
> > > -     ret = _intel_hdcp_disable(connector);
> > > -     if (ret) {
> > > -             drm_err(&dev_priv->drm, "Failed to disable hdcp (%d)\n",
> > > ret);
> > > -             intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > > -                                     true);
> > > -             goto out;
> > > -     }
> > > -
> > > -     ret = _intel_hdcp_enable(connector);
> > > -     if (ret) {
> > > -             drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n",
> > > ret);
> > > -             intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > > -                                     true);
> > > -             goto out;
> > > -     }
> > > -
> > > -out:
> > > -     mutex_unlock(&dig_port->hdcp_mutex);
> > > -     mutex_unlock(&hdcp->mutex);
> > > -     return ret;
> > > -}
> > > -
> > > -static void intel_hdcp_prop_work(struct work_struct *work)
> > > -{
> > > -     struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp,
> > > -                                            prop_work);
> > > -     struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
> > > -     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > -
> > > -     drm_modeset_lock(&dev_priv-
> > > >drm.mode_config.connection_mutex, NULL);
> > > -     mutex_lock(&hdcp->mutex);
> > > -
> > > -     /*
> > > -      * This worker is only used to flip between ENABLED/DESIRED. Either
> > > of
> > > -      * those to UNDESIRED is handled by core. If value == UNDESIRED,
> > > -      * we're running just after hdcp has been disabled, so just exit
> > > -      */
> > > -     if (hdcp->value !=
> > > DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> > > -             drm_hdcp_update_content_protection(&connector->base,
> > > -                                                hdcp->value);
> > > -
> > > -     mutex_unlock(&hdcp->mutex);
> > > -     drm_modeset_unlock(&dev_priv-
> > > >drm.mode_config.connection_mutex);
> > > -
> > > -     drm_connector_put(&connector->base);
> > > -}
> > > -
> > >  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port
> > > port)
> > >  {
> > >       return RUNTIME_INFO(dev_priv)->has_hdcp &&
> > > @@ -1961,8 +1586,9 @@ static int
> hdcp2_authenticate_and_encrypt(struct
> > > intel_connector *connector)
> > >       return ret;
> > >  }
> > >
> > > -static int _intel_hdcp2_enable(struct intel_connector *connector)
> > > +int intel_hdcp2_enable(struct drm_connector *drm_connector)
> > >  {
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > >       struct drm_i915_private *i915 = to_i915(connector->base.dev);
> > >       struct intel_hdcp *hdcp = &connector->hdcp;
> > >       int ret;
> > > @@ -2024,9 +1650,15 @@ _intel_hdcp2_disable(struct intel_connector
> > > *connector, bool hdcp2_link_recovery
> > >       return ret;
> > >  }
> > >
> > > +int intel_hdcp2_disable(struct drm_connector *drm_connector)
> > > +{
> > > +     return _intel_hdcp2_disable(to_intel_connector(drm_connector),
> > > false);
> > > +}
> > > +
> > >  /* Implements the Link Integrity Check for HDCP2.2 */
> > > -static int intel_hdcp2_check_link(struct intel_connector *connector)
> > > +int intel_hdcp2_check_link(struct drm_connector *drm_connector)
> > >  {
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > >       struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > >       struct intel_hdcp *hdcp = &connector->hdcp;
> > > @@ -2034,109 +1666,39 @@ static int intel_hdcp2_check_link(struct
> > > intel_connector *connector)
> > >       enum transcoder cpu_transcoder;
> > >       int ret = 0;
> > >
> > > -     mutex_lock(&hdcp->mutex);
> > > -     mutex_lock(&dig_port->hdcp_mutex);
> > >       cpu_transcoder = hdcp->cpu_transcoder;
> > >
> > >       /* hdcp2_check_link is expected only when HDCP2.2 is Enabled */
> > > -     if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED
> > > ||
> > > -         !hdcp->hdcp2_encrypted) {
> > > -             ret = -EINVAL;
> > > -             goto out;
> > > -     }
> > > +     if (!hdcp->hdcp2_encrypted)
> > > +             return -EINVAL;
> > >
> > >       if (drm_WARN_ON(&dev_priv->drm,
> > >                       !intel_hdcp2_in_use(dev_priv, cpu_transcoder,
> > > port))) {
> > >               drm_err(&dev_priv->drm,
> > >                       "HDCP2.2 link stopped the encryption, %x\n",
> > >                       intel_de_read(dev_priv, HDCP2_STATUS(dev_priv,
> > > cpu_transcoder, port)));
> > > -             ret = -ENXIO;
> > > -             _intel_hdcp2_disable(connector, true);
> > > -             intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > > -                                     true);
> > > -             goto out;
> > > +             return -ENXIO;
> > >       }
> > >
> > >       ret = hdcp->shim->check_2_2_link(dig_port, connector);
> > > -     if (ret == HDCP_LINK_PROTECTED) {
> > > -             if (hdcp->value !=
> > > DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
> > > -                     intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_ENABLED,
> > > -                                     true);
> > > -             }
> > > -             goto out;
> > > -     }
> > > +     if (ret == HDCP_LINK_PROTECTED)
> > > +             return 0;
> > >
> > >       if (ret == HDCP_TOPOLOGY_CHANGE) {
> > > -             if (hdcp->value ==
> > > DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> > > -                     goto out;
> > > -
> > >               drm_dbg_kms(&dev_priv->drm,
> > >                           "HDCP2.2 Downstream topology change\n");
> > >               ret = hdcp2_authenticate_repeater_topology(connector);
> > > -             if (!ret) {
> > > -                     intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_ENABLED,
> > > -                                     true);
> > > -                     goto out;
> > > -             }
> > > -             drm_dbg_kms(&dev_priv->drm,
> > > -                         "[%s:%d] Repeater topology auth failed.(%d)\n",
> > > -                         connector->base.name, connector->base.base.id,
> > > -                         ret);
> > > -     } else {
> > > -             drm_dbg_kms(&dev_priv->drm,
> > > -                         "[%s:%d] HDCP2.2 link failed, retrying auth\n",
> > > -                         connector->base.name, connector->base.base.id);
> > > -     }
> > > -
> > > -     ret = _intel_hdcp2_disable(connector, true);
> > > -     if (ret) {
> > > -             drm_err(&dev_priv->drm,
> > > -                     "[%s:%d] Failed to disable hdcp2.2 (%d)\n",
> > > -                     connector->base.name, connector->base.base.id,
> > > ret);
> > > -             intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
> > > -             goto out;
> > > -     }
> > > +             if (!ret)
> > > +                     return 0;
> > >
> > > -     ret = _intel_hdcp2_enable(connector);
> > > -     if (ret) {
> > >               drm_dbg_kms(&dev_priv->drm,
> > > -                         "[%s:%d] Failed to enable hdcp2.2 (%d)\n",
> > > -                         connector->base.name, connector->base.base.id,
> > > -                         ret);
> > > -             intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_DESIRED,
> > > -                                     true);
> > > -             goto out;
> > > +                         "[%s:%d] Repeater topology auth failed.(%d)\n",
> > > +                         connector->base.name, connector->base.base.id,
> > > ret);
> > >       }
> > >
> > > -out:
> > > -     mutex_unlock(&dig_port->hdcp_mutex);
> > > -     mutex_unlock(&hdcp->mutex);
> > >       return ret;
> > >  }
> >
> > Wouldn't it be better if we used that value in drm_hdcp_helper_data
> rather than getting rid of all these checks
> > As they are needed same thing for other places where the checks are
> removed because value isn't present in
> > Intel_hdcp structure
> >
> I'm not 100% sure I get what you're referring to, but basically the
> work has been split between the helper and the driver. the intel
> specific protocol is what remains in the driver. Everything else is
> handled in the helper

From what I can see all the checks concerning hdcp->value have been removed and not been
Taken care In any of the drm_hdcp_helper function for hdcp2_check_link we can use
The value field here which is store in drm_hdcp_helper_data

> > >
> > > -static void intel_hdcp_check_work(struct work_struct *work)
> > > -{
> > > -     struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
> > > -                                            struct intel_hdcp,
> > > -                                            check_work);
> > > -     struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
> > > -
> > > -     if (drm_connector_is_unregistered(&connector->base))
> > > -             return;
> > > -
> > > -     if (!intel_hdcp2_check_link(connector))
> > > -             schedule_delayed_work(&hdcp->check_work,
> > > -                                   DRM_HDCP2_CHECK_PERIOD_MS);
> > > -     else if (!intel_hdcp_check_link(connector))
> > > -             schedule_delayed_work(&hdcp->check_work,
> > > -                                   DRM_HDCP_CHECK_PERIOD_MS);
> > > -}
> > > -
> > >  static int i915_hdcp_component_bind(struct device *i915_kdev,
> > >                                   struct device *mei_kdev, void *data)
> > >  {
> > > @@ -2189,22 +1751,28 @@ static enum mei_fw_tc
> > > intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
> > >       }
> > >  }
> > >
> > > -static int
> > > -_intel_hdcp_setup(struct intel_connector *connector,
> > > -               const struct intel_crtc_state *pipe_config, u8 content_type)
> > > +int intel_hdcp_setup(struct drm_connector *connector,
> > > +                  struct drm_atomic_state *state)
> > >  {
> > > -     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > -     struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > > +     struct drm_i915_private *dev_priv = to_i915(connector->dev);
> > > +     struct intel_connector *intel_connector =
> > > to_intel_connector(connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(intel_connector);
> > > +     struct drm_connector_state *conn_state;
> > > +     struct drm_crtc_state *crtc_state;
> > > +     struct intel_crtc_state *pipe_config;
> > > +     struct intel_hdcp *hdcp = &intel_connector->hdcp;
> > >       int ret = 0;
> > >
> > > -     if (!connector->encoder) {
> > > +     if (!intel_connector->encoder) {
> > >               drm_err(&dev_priv->drm, "[%s:%d] encoder is not
> > > initialized\n",
> > > -                     connector->base.name, connector->base.base.id);
> > > +                     connector->name, connector->base.id);
> > >               return -ENODEV;
> > >       }
> > >
> > > -     hdcp->content_type = content_type;
> > > +     conn_state = drm_atomic_get_new_connector_state(state,
> > > connector);
> > > +     crtc_state = drm_atomic_get_new_crtc_state(state, conn_state-
> > > >crtc);
> > > +     pipe_config = to_intel_crtc_state(crtc_state);
> > >
> > >       if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
> > >               hdcp->cpu_transcoder = pipe_config-
> > > >mst_master_transcoder;
> > > @@ -2321,7 +1889,6 @@ int intel_hdcp_init(struct intel_connector
> > > *connector,
> > >  {
> > >       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > >       struct intel_hdcp *hdcp = &connector->hdcp;
> > > -     int ret;
> > >
> > >       if (!shim)
> > >               return -EINVAL;
> > > @@ -2329,174 +1896,12 @@ int intel_hdcp_init(struct intel_connector
> > > *connector,
> > >       if (is_hdcp2_supported(dev_priv))
> > >               intel_hdcp2_init(connector, dig_port, shim);
> > >
> > > -     ret =
> > > -     drm_connector_attach_content_protection_property(&connector-
> > > >base,
> > > -                                                      hdcp-
> > > >hdcp2_supported);
> > > -     if (ret) {
> > > -             hdcp->hdcp2_supported = false;
> > > -             kfree(dig_port->hdcp_port_data.streams);
> > > -             return ret;
> > > -     }
> > > -
> > >       hdcp->shim = shim;
> > > -     mutex_init(&hdcp->mutex);
> >
> > I don't think removing mutex is a good idea
> >
> The mutex is just moved to the drm hdpc helper. Is there any race
> condition that you might be missing?
> > Regards,
> > Suraj Kandpal
> > > -     INIT_DELAYED_WORK(&hdcp->check_work,
> > > intel_hdcp_check_work);
> > > -     INIT_WORK(&hdcp->prop_work, intel_hdcp_prop_work);
> > >       init_waitqueue_head(&hdcp->cp_irq_queue);
> > >
> > >       return 0;
> > >  }
> > >
> > > -int intel_hdcp_enable(struct intel_connector *connector,
> > > -                   const struct intel_crtc_state *pipe_config, u8
> > > content_type)
> > > -{
> > > -     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > -     struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > > -     unsigned long check_link_interval =
> > > DRM_HDCP_CHECK_PERIOD_MS;
> > > -     bool capable;
> > > -     int ret = -EINVAL;
> > > -
> > > -     if (!hdcp->shim)
> > > -             return -ENOENT;
> > > -
> > > -     mutex_lock(&hdcp->mutex);
> > > -     mutex_lock(&dig_port->hdcp_mutex);
> > > -     drm_WARN_ON(&dev_priv->drm,
> > > -                 hdcp->value ==
> > > DRM_MODE_CONTENT_PROTECTION_ENABLED);
> > > -
> > > -     ret = _intel_hdcp_setup(connector, pipe_config, content_type);
> > > -     if (ret)
> > > -             goto out;
> > > -
> > > -     /*
> > > -      * Considering that HDCP2.2 is more secure than HDCP1.4, If the
> > > setup
> > > -      * is capable of HDCP2.2, it is preferred to use HDCP2.2.
> > > -      */
> > > -     ret = intel_hdcp2_capable(connector, &capable);
> > > -     if (capable) {
> > > -             ret = _intel_hdcp2_enable(connector);
> > > -             if (!ret) {
> > > -                     check_link_interval =
> > > DRM_HDCP2_CHECK_PERIOD_MS;
> > > -                     goto out;
> > > -             }
> > > -     }
> > > -
> > > -     /*
> > > -      * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
> > > -      * be attempted.
> > > -      */
> > > -     ret = intel_hdcp_capable(connector, &capable);
> > > -     if (ret)
> > > -             goto out;
> > > -
> > > -     if (capable && hdcp->content_type !=
> > > DRM_MODE_HDCP_CONTENT_TYPE1)
> > > -             ret = _intel_hdcp_enable(connector);
> > > -
> > > -out:
> > > -     if (!ret) {
> > > -             schedule_delayed_work(&hdcp->check_work,
> > > check_link_interval);
> > > -             intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_ENABLED,
> > > -                                     true);
> > > -     }
> > > -
> > > -     mutex_unlock(&dig_port->hdcp_mutex);
> > > -     mutex_unlock(&hdcp->mutex);
> > > -     return ret;
> > > -}
> > > -
> > > -int intel_hdcp_disable(struct intel_connector *connector)
> > > -{
> > > -     struct intel_digital_port *dig_port =
> > > intel_attached_dig_port(connector);
> > > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > > -     int ret = 0;
> > > -
> > > -     if (!hdcp->shim)
> > > -             return -ENOENT;
> > > -
> > > -     mutex_lock(&hdcp->mutex);
> > > -     mutex_lock(&dig_port->hdcp_mutex);
> > > -
> > > -     if (hdcp->value ==
> > > DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
> > > -             goto out;
> > > -
> > > -     intel_hdcp_update_value(connector,
> > > -
> > >       DRM_MODE_CONTENT_PROTECTION_UNDESIRED, false);
> > > -     if (hdcp->hdcp2_encrypted)
> > > -             ret = _intel_hdcp2_disable(connector, false);
> > > -     else if (hdcp->hdcp_encrypted)
> > > -             ret = _intel_hdcp_disable(connector);
> > > -
> > > -out:
> > > -     mutex_unlock(&dig_port->hdcp_mutex);
> > > -     mutex_unlock(&hdcp->mutex);
> > > -     cancel_delayed_work_sync(&hdcp->check_work);
> > > -     return ret;
> > > -}
> > > -
> > > -void intel_hdcp_update_pipe(struct intel_atomic_state *state,
> > > -                         struct intel_encoder *encoder,
> > > -                         const struct intel_crtc_state *crtc_state,
> > > -                         const struct drm_connector_state *conn_state)
> > > -{
> > > -     struct intel_connector *connector =
> > > -                             to_intel_connector(conn_state->connector);
> > > -     struct intel_hdcp *hdcp = &connector->hdcp;
> > > -     bool content_protection_type_changed, desired_and_not_enabled
> > > = false;
> > > -
> > > -     if (!connector->hdcp.shim)
> > > -             return;
> > > -
> > > -     content_protection_type_changed =
> > > -             (conn_state->hdcp_content_type != hdcp->content_type
> > > &&
> > > -              conn_state->content_protection !=
> > > -              DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
> > > -
> > > -     /*
> > > -      * During the HDCP encryption session if Type change is requested,
> > > -      * disable the HDCP and reenable it with new TYPE value.
> > > -      */
> > > -     if (conn_state->content_protection ==
> > > -         DRM_MODE_CONTENT_PROTECTION_UNDESIRED ||
> > > -         content_protection_type_changed)
> > > -             intel_hdcp_disable(connector);
> > > -
> > > -     /*
> > > -      * Mark the hdcp state as DESIRED after the hdcp disable of type
> > > -      * change procedure.
> > > -      */
> > > -     if (content_protection_type_changed) {
> > > -             mutex_lock(&hdcp->mutex);
> > > -             hdcp->value =
> > > DRM_MODE_CONTENT_PROTECTION_DESIRED;
> > > -             drm_connector_get(&connector->base);
> > > -             schedule_work(&hdcp->prop_work);
> > > -             mutex_unlock(&hdcp->mutex);
> > > -     }
> > > -
> > > -     if (conn_state->content_protection ==
> > > -         DRM_MODE_CONTENT_PROTECTION_DESIRED) {
> > > -             mutex_lock(&hdcp->mutex);
> > > -             /* Avoid enabling hdcp, if it already ENABLED */
> > > -             desired_and_not_enabled =
> > > -                     hdcp->value !=
> > > DRM_MODE_CONTENT_PROTECTION_ENABLED;
> > > -             mutex_unlock(&hdcp->mutex);
> > > -             /*
> > > -              * If HDCP already ENABLED and CP property is DESIRED,
> > > schedule
> > > -              * prop_work to update correct CP property to user space.
> > > -              */
> > > -             if (!desired_and_not_enabled &&
> > > !content_protection_type_changed) {
> > > -                     drm_connector_get(&connector->base);
> > > -                     schedule_work(&hdcp->prop_work);
> > > -             }
> > > -     }
> > > -
> > > -     if (desired_and_not_enabled || content_protection_type_changed)
> > > -             intel_hdcp_enable(connector,
> > > -                               crtc_state,
> > > -                               (u8)conn_state->hdcp_content_type);
> > > -}
> > > -
> > >  void intel_hdcp_component_fini(struct drm_i915_private *dev_priv)
> > >  {
> > >       mutex_lock(&dev_priv->display.hdcp.comp_mutex);
> > > @@ -2518,33 +1923,8 @@ void intel_hdcp_cleanup(struct
> intel_connector
> > > *connector)
> > >       if (!hdcp->shim)
> > >               return;
> > >
> > > -     /*
> > > -      * If the connector is registered, it's possible userspace could kick
> > > -      * off another HDCP enable, which would re-spawn the workers.
> > > -      */
> > > -     drm_WARN_ON(connector->base.dev,
> > > -             connector->base.registration_state ==
> > > DRM_CONNECTOR_REGISTERED);
> > > -
> > > -     /*
> > > -      * Now that the connector is not registered, check_work won't be
> > > run,
> > > -      * but cancel any outstanding instances of it
> > > -      */
> > > -     cancel_delayed_work_sync(&hdcp->check_work);
> > > -
> > > -     /*
> > > -      * We don't cancel prop_work in the same way as check_work since it
> > > -      * requires connection_mutex which could be held while calling this
> > > -      * function. Instead, we rely on the connector references grabbed
> > > before
> > > -      * scheduling prop_work to ensure the connector is alive when
> > > prop_work
> > > -      * is run. So if we're in the destroy path (which is where this
> > > -      * function should be called), we're "guaranteed" that prop_work is
> > > not
> > > -      * active (tl;dr This Should Never Happen).
> > > -      */
> > > -     drm_WARN_ON(connector->base.dev, work_pending(&hdcp-
> > > >prop_work));
> > > -
> > > -     mutex_lock(&hdcp->mutex);
> > > +     drm_hdcp_helper_destroy(connector->hdcp_helper_data);
> > >       hdcp->shim = NULL;
> > > -     mutex_unlock(&hdcp->mutex);
> > >  }
> > >
> > >  /* Handles the CP_IRQ raised from the DP HDCP sink */
> > > @@ -2558,5 +1938,5 @@ void intel_hdcp_handle_cp_irq(struct
> > > intel_connector *connector)
> > >       atomic_inc(&connector->hdcp.cp_irq_count);
> > >       wake_up_all(&connector->hdcp.cp_irq_queue);
> > >
> > > -     schedule_delayed_work(&hdcp->check_work, 0);
> > > +     drm_hdcp_helper_schedule_hdcp_check(connector-
> > > >hdcp_helper_data);
> > >  }
> > > diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > index f06f6e5a2b1a..49b9d79eb30a 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h
> > > @@ -10,8 +10,10 @@
> > >
> > >  #define HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS        50
> > >
> > > +struct drm_atomic_state;
> > >  struct drm_connector;
> > >  struct drm_connector_state;
> > > +struct drm_hdcp_an;
> > >  struct drm_i915_private;
> > >  struct intel_atomic_state;
> > >  struct intel_connector;
> > > @@ -25,16 +27,29 @@ enum transcoder;
> > >  int intel_hdcp_init(struct intel_connector *connector,
> > >                   struct intel_digital_port *dig_port,
> > >                   const struct intel_hdcp_shim *hdcp_shim);
> > > -int intel_hdcp_enable(struct intel_connector *connector,
> > > -                   const struct intel_crtc_state *pipe_config, u8
> > > content_type);
> > > -int intel_hdcp_disable(struct intel_connector *connector);
> > > -void intel_hdcp_update_pipe(struct intel_atomic_state *state,
> > > -                         struct intel_encoder *encoder,
> > > -                         const struct intel_crtc_state *crtc_state,
> > > -                         const struct drm_connector_state *conn_state);
> > > +int intel_hdcp_setup(struct drm_connector *drm_connector,
> > > +                  struct drm_atomic_state *state);
> > > +int intel_hdcp_load_keys(struct drm_connector *drm_connector);
> > >  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port
> > > port);
> > >  int intel_hdcp_capable(struct intel_connector *connector, bool
> *capable);
> > > -int intel_hdcp2_capable(struct intel_connector *connector, bool
> *capable);
> > > +int intel_hdcp2_capable(struct drm_connector *drm_connector, bool
> > > *capable);
> > > +int intel_hdcp2_enable(struct drm_connector *drm_connector);
> > > +int intel_hdcp2_disable(struct drm_connector *drm_connector);
> > > +int intel_hdcp2_check_link(struct drm_connector *drm_connector);
> > > +int intel_hdcp1_store_receiver_info(struct drm_connector
> > > *drm_connector,
> > > +                                 u32 *ksv, u32 status, u8 caps,
> > > +                                 bool repeater_present);
> > > +int intel_hdcp1_read_an(struct drm_connector *drm_connector,
> > > +                     struct drm_hdcp_an *an);
> > > +int intel_hdcp1_enable_encryption(struct drm_connector
> > > *drm_connector);
> > > +int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector);
> > > +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32
> > > ri_prime);
> > > +int intel_hdcp1_post_encryption(struct drm_connector
> *drm_connector);
> > > +int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
> > > +                            u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
> > > +                            u32 *v_prime);
> > > +int intel_hdcp1_check_link(struct drm_connector *drm_connector);
> > > +int intel_hdcp1_disable(struct drm_connector *drm_connector);
> > >  void intel_hdcp_component_init(struct drm_i915_private *dev_priv);
> > >  void intel_hdcp_component_fini(struct drm_i915_private *dev_priv);
> > >  void intel_hdcp_cleanup(struct intel_connector *connector);
> > > diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c
> > > b/drivers/gpu/drm/i915/display/intel_hdmi.c
> > > index 7816b2a33fee..c33cfedb2e19 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_hdmi.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
> > > @@ -1324,17 +1324,24 @@ static int intel_hdmi_hdcp_write(struct
> > > intel_digital_port *dig_port,
> > >       return ret;
> > >  }
> > >
> > > -static
> > > -int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
> > > -                               u8 *an)
> > > +static int intel_hdmi_hdcp1_send_an_aksv(struct drm_connector
> > > *drm_connector)
> > >  {
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > >       struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > >       struct intel_hdmi *hdmi = &dig_port->hdmi;
> > >       struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915,
> > >                                                             hdmi->ddc_bus);
> > > +     struct drm_hdcp_an an;
> > >       int ret;
> > >
> > > -     ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an,
> > > +     /* Output An first, that's easy */
> > > +     ret = intel_hdcp1_read_an(drm_connector, &an);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN,
> > > an.bytes,
> > >                                   DRM_HDCP_AN_LEN);
> > >       if (ret) {
> > >               drm_dbg_kms(&i915->drm, "Write An over DDC failed
> > > (%d)\n",
> > > @@ -1350,120 +1357,6 @@ int intel_hdmi_hdcp_write_an_aksv(struct
> > > intel_digital_port *dig_port,
> > >       return 0;
> > >  }
> > >
> > > -static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *dig_port,
> > > -                                  u8 *bksv)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -
> > > -     int ret;
> > > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BKSV, bksv,
> > > -                                DRM_HDCP_KSV_LEN);
> > > -     if (ret)
> > > -             drm_dbg_kms(&i915->drm, "Read Bksv over DDC failed
> > > (%d)\n",
> > > -                         ret);
> > > -     return ret;
> > > -}
> > > -
> > > -static
> > > -int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *dig_port,
> > > -                              u8 *bstatus)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -
> > > -     int ret;
> > > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BSTATUS,
> > > -                                bstatus, DRM_HDCP_BSTATUS_LEN);
> > > -     if (ret)
> > > -             drm_dbg_kms(&i915->drm, "Read bstatus over DDC failed
> > > (%d)\n",
> > > -                         ret);
> > > -     return ret;
> > > -}
> > > -
> > > -static
> > > -int intel_hdmi_hdcp_repeater_present(struct intel_digital_port
> *dig_port,
> > > -                                  bool *repeater_present)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     int ret;
> > > -     u8 val;
> > > -
> > > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS,
> > > &val, 1);
> > > -     if (ret) {
> > > -             drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed
> > > (%d)\n",
> > > -                         ret);
> > > -             return ret;
> > > -     }
> > > -     *repeater_present = val &
> > > DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
> > > -     return 0;
> > > -}
> > > -
> > > -static
> > > -int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
> > > -                               u8 *ri_prime)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -
> > > -     int ret;
> > > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_RI_PRIME,
> > > -                                ri_prime, DRM_HDCP_RI_LEN);
> > > -     if (ret)
> > > -             drm_dbg_kms(&i915->drm, "Read Ri' over DDC failed
> > > (%d)\n",
> > > -                         ret);
> > > -     return ret;
> > > -}
> > > -
> > > -static
> > > -int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
> > > -                                bool *ksv_ready)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     int ret;
> > > -     u8 val;
> > > -
> > > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS,
> > > &val, 1);
> > > -     if (ret) {
> > > -             drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed
> > > (%d)\n",
> > > -                         ret);
> > > -             return ret;
> > > -     }
> > > -     *ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
> > > -     return 0;
> > > -}
> > > -
> > > -static
> > > -int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
> > > -                               int num_downstream, u8 *ksv_fifo)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     int ret;
> > > -     ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_KSV_FIFO,
> > > -                                ksv_fifo, num_downstream *
> > > DRM_HDCP_KSV_LEN);
> > > -     if (ret) {
> > > -             drm_dbg_kms(&i915->drm,
> > > -                         "Read ksv fifo over DDC failed (%d)\n", ret);
> > > -             return ret;
> > > -     }
> > > -     return 0;
> > > -}
> > > -
> > > -static
> > > -int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port
> > > *dig_port,
> > > -                                   int i, u32 *part)
> > > -{
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     int ret;
> > > -
> > > -     if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
> > > -             return -EINVAL;
> > > -
> > > -     ret = intel_hdmi_hdcp_read(dig_port,
> > > DRM_HDCP_DDC_V_PRIME(i),
> > > -                                part, DRM_HDCP_V_PRIME_PART_LEN);
> > > -     if (ret)
> > > -             drm_dbg_kms(&i915->drm, "Read V'[%d] over DDC failed
> > > (%d)\n",
> > > -                         i, ret);
> > > -     return ret;
> > > -}
> > > -
> > >  static int kbl_repositioning_enc_en_signal(struct intel_connector
> > > *connector,
> > >                                          enum transcoder cpu_transcoder)
> > >  {
> > > @@ -1532,50 +1425,40 @@ int intel_hdmi_hdcp_toggle_signalling(struct
> > > intel_digital_port *dig_port,
> > >       return 0;
> > >  }
> > >
> > > -static
> > > -bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port
> *dig_port,
> > > -                                  struct intel_connector *connector)
> > > +static int
> > > +intel_hdmi_hdcp1_enable_encryption(struct drm_connector
> > > *drm_connector)
> > >  {
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     enum port port = dig_port->base.port;
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > >       enum transcoder cpu_transcoder = connector-
> > > >hdcp.cpu_transcoder;
> > >       int ret;
> > > -     union {
> > > -             u32 reg;
> > > -             u8 shim[DRM_HDCP_RI_LEN];
> > > -     } ri;
> > >
> > > -     ret = intel_hdmi_hdcp_read_ri_prime(dig_port, ri.shim);
> > > +     ret = intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder,
> > > true);
> > >       if (ret)
> > > -             return false;
> > > -
> > > -     intel_de_write(i915, HDCP_RPRIME(i915, cpu_transcoder, port),
> > > ri.reg);
> > > +             return ret;
> > >
> > > -     /* Wait for Ri prime match */
> > > -     if (wait_for((intel_de_read(i915, HDCP_STATUS(i915,
> > > cpu_transcoder, port)) &
> > > -                   (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC)) ==
> > > -                  (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
> > > -             drm_dbg_kms(&i915->drm, "Ri' mismatch detected (%x)\n",
> > > -                     intel_de_read(i915, HDCP_STATUS(i915,
> > > cpu_transcoder,
> > > -                                                     port)));
> > > -             return false;
> > > -     }
> > > -     return true;
> > > +     return intel_hdcp1_enable_encryption(drm_connector);
> > >  }
> > >
> > > -static
> > > -bool intel_hdmi_hdcp_check_link(struct intel_digital_port *dig_port,
> > > -                             struct intel_connector *connector)
> > > +static int intel_hdmi_hdcp1_disable(struct drm_connector
> > > *drm_connector)
> > >  {
> > > -     struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
> > > -     int retry;
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > > +     enum transcoder cpu_transcoder = connector-
> > > >hdcp.cpu_transcoder;
> > > +     struct drm_i915_private *i915 = to_i915(connector->base.dev);
> > > +     int ret;
> > >
> > > -     for (retry = 0; retry < 3; retry++)
> > > -             if (intel_hdmi_hdcp_check_link_once(dig_port, connector))
> > > -                     return true;
> > > +     ret = intel_hdcp1_disable(drm_connector);
> > > +     if (ret) {
> > > +             drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 1.4\n",
> > > +                     connector->base.name, connector->base.base.id);
> > > +             return ret;
> > > +     }
> > >
> > > -     drm_err(&i915->drm, "Link check failed\n");
> > > -     return false;
> > > +     return intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder,
> > > +                                              false);
> > >  }
> > >
> > >  struct hdcp2_hdmi_msg_timeout {
> > > @@ -1718,9 +1601,8 @@ int intel_hdmi_hdcp2_read_msg(struct
> > > intel_digital_port *dig_port,
> > >       return ret;
> > >  }
> > >
> > > -static
> > > -int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
> > > -                             struct intel_connector *connector)
> > > +static int intel_hdmi_hdcp2_check_link(struct intel_digital_port
> *dig_port,
> > > +                                    struct intel_connector *connector)
> > >  {
> > >       u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN];
> > >       int ret;
> > > @@ -1741,13 +1623,19 @@ int intel_hdmi_hdcp2_check_link(struct
> > > intel_digital_port *dig_port,
> > >       return ret;
> > >  }
> > >
> > > -static
> > > -int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
> > > -                          bool *capable)
> > > +static int intel_hdmi_hdcp2_capable(struct drm_connector
> > > *drm_connector,
> > > +                                 bool *capable)
> > >  {
> > > +     struct intel_connector *connector =
> > > to_intel_connector(drm_connector);
> > > +     struct intel_digital_port *dig_port =
> > > +             intel_attached_dig_port(connector);
> > >       u8 hdcp2_version;
> > >       int ret;
> > >
> > > +     ret = intel_hdcp2_capable(drm_connector, capable);
> > > +     if (ret || !capable)
> > > +             return ret;
> > > +
> > >       *capable = false;
> > >       ret = intel_hdmi_hdcp_read(dig_port,
> > > HDCP_2_2_HDMI_REG_VER_OFFSET,
> > >                                  &hdcp2_version, sizeof(hdcp2_version));
> > > @@ -1758,23 +1646,30 @@ int intel_hdmi_hdcp2_capable(struct
> > > intel_digital_port *dig_port,
> > >  }
> > >
> > >  static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
> > > -     .write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
> > > -     .read_bksv = intel_hdmi_hdcp_read_bksv,
> > > -     .read_bstatus = intel_hdmi_hdcp_read_bstatus,
> > > -     .repeater_present = intel_hdmi_hdcp_repeater_present,
> > > -     .read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
> > > -     .read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
> > > -     .read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
> > > -     .read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
> > >       .toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
> > > -     .check_link = intel_hdmi_hdcp_check_link,
> > >       .write_2_2_msg = intel_hdmi_hdcp2_write_msg,
> > >       .read_2_2_msg = intel_hdmi_hdcp2_read_msg,
> > > -     .check_2_2_link = intel_hdmi_hdcp2_check_link,
> > > -     .hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
> > > +     .check_2_2_link = intel_hdmi_hdcp2_check_link,
> > >       .protocol = HDCP_PROTOCOL_HDMI,
> > >  };
> > >
> > > +static const struct drm_hdcp_helper_funcs
> intel_hdmi_hdcp_helper_funcs
> > > = {
> > > +     .setup = intel_hdcp_setup,
> > > +     .load_keys = intel_hdcp_load_keys,
> > > +     .hdcp2_capable = intel_hdmi_hdcp2_capable,
> > > +     .hdcp2_enable = intel_hdcp2_enable,
> > > +     .hdcp2_check_link = intel_hdcp2_check_link,
> > > +     .hdcp2_disable = intel_hdcp2_disable,
> > > +     .hdcp1_send_an_aksv = intel_hdmi_hdcp1_send_an_aksv,
> > > +     .hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
> > > +     .hdcp1_enable_encryption = intel_hdmi_hdcp1_enable_encryption,
> > > +     .hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
> > > +     .hdcp1_match_ri = intel_hdcp1_match_ri,
> > > +     .hdcp1_post_encryption = intel_hdcp1_post_encryption,
> > > +     .hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
> > > +     .hdcp1_disable = intel_hdmi_hdcp1_disable,
> > > +};
> > > +
> > >  static int intel_hdmi_source_max_tmds_clock(struct intel_encoder
> > > *encoder)
> > >  {
> > >       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > @@ -2922,6 +2817,37 @@ void intel_infoframe_init(struct
> intel_digital_port
> > > *dig_port)
> > >       }
> > >  }
> > >
> > > +static void intel_hdmi_hdcp_init(struct intel_digital_port *dig_port,
> > > +                              struct intel_connector *connector)
> > > +{
> > > +     struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> > > +     struct intel_encoder *intel_encoder = &dig_port->base;
> > > +     enum port port = intel_encoder->port;
> > > +     struct drm_hdcp_helper_data *data;
> > > +     int ret;
> > > +
> > > +     if (!is_hdcp_supported(dev_priv, port))
> > > +             return;
> > > +
> > > +     data = drm_hdcp_helper_initialize_hdmi(
> > > +             &connector->base, &intel_hdmi_hdcp_helper_funcs, true);
> > > +     if (IS_ERR(data)) {
> > > +             drm_dbg_kms(&dev_priv->drm, "HDCP init failed
> > > ret=%ld\n",
> > > +                         PTR_ERR(data));
> > > +             return;
> > > +     }
> > > +
> > > +     ret = intel_hdcp_init(connector, dig_port, &intel_hdmi_hdcp_shim);
> > > +     if (ret) {
> > > +             drm_hdcp_helper_destroy(data);
> > > +             drm_dbg_kms(&dev_priv->drm, "Intel HDCP init failed
> > > ret=%d\n",
> > > +                         ret);
> > > +             return;
> > > +     }
> > > +
> > > +     connector->hdcp_helper_data = data;
> > > +}
> > > +
> > >  void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
> > >                              struct intel_connector *intel_connector)
> > >  {
> > > @@ -2975,13 +2901,7 @@ void intel_hdmi_init_connector(struct
> > > intel_digital_port *dig_port,
> > >       intel_connector_attach_encoder(intel_connector, intel_encoder);
> > >       intel_hdmi->attached_connector = intel_connector;
> > >
> > > -     if (is_hdcp_supported(dev_priv, port)) {
> > > -             int ret = intel_hdcp_init(intel_connector, dig_port,
> > > -                                       &intel_hdmi_hdcp_shim);
> > > -             if (ret)
> > > -                     drm_dbg_kms(&dev_priv->drm,
> > > -                                 "HDCP init failed, skipping.\n");
> > > -     }
> > > +     intel_hdmi_hdcp_init(dig_port, intel_connector);
> > >
> > >       /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be
> > > written
> > >        * 0xd.  Failure to do so will result in spurious interrupts being
> > > --
> > > 2.39.0.246.g2a6d74b583-goog
> >
> I send v7 which should have the comments addressed. Thanks a lot!

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2023-03-28  6:12 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-18 19:30 [PATCH v6 00/10] drm/hdcp: Pull HDCP auth/exchange/check into helpers Mark Yacoub
2023-01-18 19:30 ` [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check() Mark Yacoub
2023-01-19 10:37   ` Krzysztof Kozlowski
2023-01-20 15:32     ` Sean Paul
2023-01-20 20:33       ` Dmitry Baryshkov
2023-01-19 11:41   ` Dmitry Baryshkov
2023-03-10  5:30   ` [Intel-gfx] " Kandpal, Suraj
2023-01-18 19:30 ` [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic check Mark Yacoub
2023-01-19 11:45   ` Dmitry Baryshkov
2023-03-10  6:00   ` [Intel-gfx] " Kandpal, Suraj
2023-01-18 19:30 ` [PATCH v6 03/10] drm/hdcp: Update property value on content type and user changes Mark Yacoub
2023-01-18 19:30 ` [PATCH v6 04/10] drm/hdcp: Expand HDCP helper library for enable/disable/check Mark Yacoub
2023-01-19 12:54   ` Dmitry Baryshkov
2023-01-18 19:30 ` [PATCH v6 05/10] drm/i915/hdcp: Consolidate HDCP setup/state cache Mark Yacoub
2023-01-18 19:30 ` [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes Mark Yacoub
2023-03-10  8:25   ` Kandpal, Suraj
2023-03-23  7:17     ` Kandpal, Suraj
2023-03-24 19:27       ` Mark Yacoub
2023-03-28  5:52         ` Kandpal, Suraj
2023-01-18 19:30 ` [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915 Mark Yacoub
2023-01-31 17:16   ` [Intel-gfx] " Rodrigo Vivi
2023-01-31 17:23     ` Rodrigo Vivi
2023-03-14  5:54   ` Kandpal, Suraj
2023-03-24 19:34     ` Mark Yacoub
2023-03-28  6:12       ` Kandpal, Suraj
2023-01-18 19:30 ` [PATCH v6 08/10] dt-bindings: msm/dp: Add bindings for HDCP registers Mark Yacoub
2023-01-19  1:16   ` Rob Herring
2023-01-19  7:48   ` Johan Hovold
2023-01-19  8:36   ` Dmitry Baryshkov
2023-01-18 19:30 ` [PATCH v6 09/10] arm64: dts: qcom: sc7180: Add support for HDCP in dp-controller Mark Yacoub
2023-01-19  1:32   ` Abhinav Kumar
2023-01-19  8:40   ` Dmitry Baryshkov
2023-01-19 10:35   ` Krzysztof Kozlowski
2023-01-20 15:54     ` Sean Paul
2023-01-21 10:16       ` Dmitry Baryshkov
2023-01-21 19:06       ` Krzysztof Kozlowski
2023-01-18 19:30 ` [PATCH v6 10/10] drm/msm: Implement HDCP 1.x using the new drm HDCP helpers Mark Yacoub
2023-01-19 11:35   ` Dmitry Baryshkov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).