drm/hdcp: Pull HDCP auth/exchange/check into helpers
Subsystems (9)
v6 cover drm/hdcp: Pull HDCP auth/exchange/check into helpers
From: Mark Yacoub <[email protected]>
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
Signature · 1 line
2.39.0.246.g2a6d74b583-goog
PATCH v6 1/10 drm/hdcp: Add drm_hdcp_atomic_check()
From: Sean Paul <[email protected]>
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.
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(-)
drivers/gpu/drm/display/drm_hdcp_helper.c +69 -0
@@ -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);
drivers/gpu/drm/i915/display/intel_atomic.c +2 -2
@@ -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 ;
drivers/gpu/drm/i915/display/intel_hdcp.c +0 -47
53 lines not on this page · raw message
drivers/gpu/drm/i915/display/intel_hdcp.h +0 -3
@@ -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);
include/drm/display/drm_hdcp_helper.h +3 -0
@@ -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
Signature · 1 line
2.39.0.246.g2a6d74b583-goog
Re: [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
Quoted 6 lines · Mark Yacoub
From: Sean Paul <[email protected]>
This patch moves the hdcp atomic check from i915 to
drm_hdcpso other drivers can use it. No functional changes, just cleaned up some of the code when moving it over.
Quoted 11 lines
Acked-by Jani Nikula <[email protected]>Acked-by Jani Nikula <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Reviewed-by Abhinav Kumar <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>
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
Sean Paul
reviewerRe: [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
Quoted 19 lines · Krzysztof Kozlowski
Quoted 6 lines · Mark Yacoub
From: Sean Paul <[email protected]>
This patch moves the hdcp atomic check from i915 to
drm_hdcpso other drivers can use it. No functional changes, just cleaned up some of the code when moving it over.Quoted 11 lines
Acked-by Jani Nikula <[email protected]>Acked-by Jani Nikula <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Reviewed-by Abhinav Kumar <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>
Quoted 2 lines
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: [email protected],
[email protected], [email protected], [email protected], [email protected]
Cc: [email protected],
[email protected],
[email protected], [email protected],
Sean Paul <[email protected]>,
Maarten Lankhorst <[email protected]>, Maxime Ripard <[email protected]>,
Thomas Zimmermann <[email protected]>, David Airlie <[email protected]>,
Daniel Vetter <[email protected]>,
Jani Nikula <[email protected]>, Joonas Lahtinen <[email protected]>, Tvrtko Ursulin <[email protected]>
Quoted 5 lines
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
Quoted 4 lines
Best regards,
Krzysztof
Signature · 1 line
Sean Paul, Software Engineer, Google / Chromium OS
Re: [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
Quoted 53 lines · Sean Paul
Quoted 19 lines · Krzysztof Kozlowski
Quoted 6 lines · Mark Yacoub
From: Sean Paul <[email protected]>
This patch moves the hdcp atomic check from i915 to
drm_hdcpso other drivers can use it. No functional changes, just cleaned up some of the code when moving it over.Quoted 11 lines
Acked-by Jani Nikula <[email protected]>Acked-by Jani Nikula <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Reviewed-by Abhinav Kumar <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Quoted 2 lines
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: [email protected],
[email protected], [email protected], [email protected], [email protected]
Cc: [email protected],
[email protected],
[email protected], [email protected],
Sean Paul <[email protected]>,
Maarten Lankhorst <[email protected]>, Maxime Ripard <[email protected]>,
Thomas Zimmermann <[email protected]>, David Airlie <[email protected]>,
Daniel Vetter <[email protected]>,
Jani Nikula <[email protected]>, Joonas Lahtinen <[email protected]>, Tvrtko Ursulin <[email protected]>Quoted 5 lines
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)?
Quoted 4 lines
I can't really speak for others, but I use
MAINTAINERSfrom drm-tip. The previous patch sets were sent before24df12013853("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.
Quoted 10 lines
Thanks again,
Sean
Quoted 4 lines
Best regards,
Krzysztof
Signature · 2 lines
With best wishes Dmitry
Re: [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
In reply to Mark YacoubQuoted 29 lines · Mark Yacoub
From: Sean Paul <[email protected]>
This patch moves the hdcp atomic check from i915 to
drm_hdcpso other drivers can use it. No functional changes, just cleaned up some of the code when moving it over.Acked-by Jani Nikula <[email protected]>Acked-by Jani Nikula <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Reviewed-by Abhinav Kumar <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in V6:
-Rebase: move helper fromdrm_hdcp.ctodrm_hdcp_helper.c
Quoted 7 lines
--- 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:
Signature · 2 lines
With best wishes Dmitry
RE: [Intel-gfx] [PATCH v6 01/10] drm/hdcp: Add drm_hdcp_atomic_check()
In reply to Mark YacoubQuoted 120 lines
From: Sean Paul <[email protected]>
This patch moves the hdcp atomic check from i915 to
drm_hdcpso other drivers can use it. No functional changes, just cleaned up some of the code when moving it over.Acked-by Jani Nikula <[email protected]>Acked-by Jani Nikula <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Reviewed-by Abhinav Kumar <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Link:
https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-2-
[email protected] #v1
Link:
https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-2-
[email protected] #v2
Link:
https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-2-
[email protected] #v3
Link:
https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
[email protected] #v4
Link:
https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
[email protected] #v5Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in V6:(quoted diff) +1
-2-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(-)drivers/gpu/drm/display/drm_hdcp_helper.c +1
-0@@ -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-Quoted 1 line
mode_config.content_protection_property);
}
EXPORT_SYMBOL(drm_hdcp_update_content_protection);drivers/gpu/drm/display/drm_hdcp_helper.c +25
-0+ +/** +* 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);
drivers/gpu/drm/display/drm_hdcp_helper.c +3
-0+ old_hdcp = old_conn_state->content_protection; + + new_conn_state = drm_atomic_get_new_connector_state(state,connector);
drivers/gpu/drm/display/drm_hdcp_helper.c +6
-0+ 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
drivers/gpu/drm/display/drm_hdcp_helper.c +2
-0+*/ + if (old_hdcp ==
DRM_MODE_CONTENT_PROTECTION_ENABLED)drivers/gpu/drm/display/drm_hdcp_helper.c +2
-0+ new_conn_state->content_protection = +DRM_MODE_CONTENT_PROTECTION_DESIRED;drivers/gpu/drm/display/drm_hdcp_helper.c +5
-0+return ; + } + + new_crtc_state = + drm_atomic_get_new_crtc_state(state, new_conn_state-Quoted 1 line
crtc);
drivers/gpu/drm/display/drm_hdcp_helper.c +3
-0+/* +* Fix the HDCP uapi content protection state in case of modeset. +* FIXME: As per HDCP content protection property uapi doc, an
uevent()
drivers/gpu/drm/display/drm_hdcp_helper.c
Quoted 2 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +2
-0+* 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
Quoted 159 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +25
-0+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);drivers/gpu/drm/i915/display/intel_atomic.c +2
-2@@ -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(structdrm_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)drivers/gpu/drm/i915/display/intel_atomic.c +0
-0return 0 ;drivers/gpu/drm/i915/display/intel_hdcp.c +0
-12@@ -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
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2-*/ - if (old_cp ==
DRM_MODE_CONTENT_PROTECTION_ENABLED)drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2- new_state->content_protection = -DRM_MODE_CONTENT_PROTECTION_DESIRED;drivers/gpu/drm/i915/display/intel_hdcp.c +0
-8-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()drivers/gpu/drm/i915/display/intel_hdcp.c +0
-10-* 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
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-13-* 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 --gita/drivers/gpu/drm/i915/display/intel_hdcp.hb/drivers/gpu/drm/i915/display/intel_hdcp.h
index8f53b0c7fe5c..7c5fd84a7b65100644drivers/gpu/drm/i915/display/intel_hdcp.h +0
-3@@ -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.hb/include/drm/display/drm_hdcp_helper.h
index8aaf87bf2735..dd02b2e72a50100644include/drm/display/drm_hdcp_helper.h +1
-0@@ -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) intdrm_connector_attach_content_protection_property(struct
drm_connector*connector,
boolhdcp_content_type);
void drm_hdcp_update_content_protection(structdrm_connector
*connector, u64 val);include/drm/display/drm_hdcp_helper.h +2
-1+void drm_hdcp_atomic_check (struct drm_connector *connector, +struct drm_atomic_state *state);#endif --2.39.0.246.g2a6d74b583-goog
PATCH v6 2/10 drm/hdcp: Avoid changing crtc state in hdcp atomic check
In reply to Mark YacoubFrom: Sean Paul <[email protected]>
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.
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(-)
drivers/gpu/drm/display/drm_hdcp_helper.c +24 -9
@@ -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);
drivers/gpu/drm/i915/display/intel_atomic.c +2 -4
@@ -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 ;
include/drm/display/drm_hdcp_helper.h +1 -1
@@ -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
Signature · 1 line
2.39.0.246.g2a6d74b583-goog
Re: [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic check
Quoted 5 lines · Mark Yacoub
From: Sean Paul <[email protected]>
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.
Quoted 136 lines
Acked-by Jani Nikula <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in V6:(quoted diff) +0
-2-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(-)drivers/gpu/drm/display/drm_hdcp_helper.c +24
-9@@ -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);drivers/gpu/drm/i915/display/intel_atomic.c +2
-4@@ -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 ;include/drm/display/drm_hdcp_helper.h +1
-1@@ -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
Signature · 2 lines
With best wishes Dmitry
RE: [Intel-gfx] [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic check
In reply to Mark YacoubQuoted 134 lines
-----Original Message-----
From: Intel-gfx <[email protected]> On Behalf Of Mark Yacoub
Sent: Thursday, January 19, 2023 1:00 AM
To: [email protected]; [email protected]; dri- [email protected]; [email protected]; [email protected]; [email protected]; intel- [email protected]
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Vasut, Marek <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Nikula, Jani <[email protected]>; De Marchi, Lucas <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Vivi, Rodrigo <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: [Intel-gfx] [PATCH v6 02/10] drm/hdcp: Avoid changing crtc state in hdcp atomic checkFrom: Sean Paul <[email protected]>
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 <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Link:
https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-3-
[email protected] #v1
Link:
https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-3-
[email protected] #v2
Link:
https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-3-
[email protected] #v3
Link:
https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
[email protected] #v4
Link:
https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
[email protected] #v5Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in V6:(quoted diff) +0
-2-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(-)drivers/gpu/drm/display/drm_hdcp_helper.c +0
-0@@ -428,11 +428,14 @@EXPORT_SYMBOL (drm_hdcp_update_content_protection); * @connector: drm_connector on which content protection state needs anupdate
*
* 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_changedon 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 */drivers/gpu/drm/display/drm_hdcp_helper.c +1
-1-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(structdrm_connector *connector, * If the connector is being disabled with CP enabled, mark it * desired so it's re-enabled when the connector is broughtback
drivers/gpu/drm/display/drm_hdcp_helper.c +0
-1*/ - if (old_hdcp ==
DRM_MODE_CONTENT_PROTECTION_ENABLED)drivers/gpu/drm/display/drm_hdcp_helper.c +1
-0+ if (old_hdcp ==
DRM_MODE_CONTENT_PROTECTION_ENABLED) {
new_conn_state->content_protection=DRM_MODE_CONTENT_PROTECTION_DESIRED;drivers/gpu/drm/display/drm_hdcp_helper.c +9
-2-return ; +return true; + } +return false; } new_crtc_state =@@ -465,9 +470,19 @@ void drm_hdcp_atomic_check(structdrm_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
drivers/gpu/drm/display/drm_hdcp_helper.c void drm_hdcp_atomic_check(struct drm_connector *connector, · line 482
Quoted 2 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +2
-0+* 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
Quoted 71 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +5
-2+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);drivers/gpu/drm/i915/display/intel_atomic.c +0
-2@@ -123,8 +123,6 @@ int intel_digital_connector_atomic_check(structdrm_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-Quoted 1 line
base.picture_aspect_ratio ||
new_conn_state->base.content_type!= old_conn_state-Quoted 1 line
base.content_type ||
new_conn_state->base.scaling_mode!= old_conn_state-Quoted 1 line
base.scaling_mode ||
drivers/gpu/drm/i915/display/intel_atomic.c +0
-1- new_conn_state->base.privacy_screen_sw_state !=
old_conn_state->base.privacy_screen_sw_state||drivers/gpu/drm/i915/display/intel_atomic.c +0
-1- !drm_connector_atomic_hdr_metadata_equal(old_state,
new_state))drivers/gpu/drm/i915/display/intel_atomic.c +1
-0+ !drm_connector_atomic_hdr_metadata_equal(old_state,
new_state) ||drivers/gpu/drm/i915/display/intel_atomic.c +1
-0+ drm_hdcp_atomic_check(conn, state)) crtc_state->mode_changed = true;return 0 ;include/drm/display/drm_hdcp_helper.h +0
-0@@ -19,7 +19,7 @@ int drm_hdcp_check_ksvs_revoked(struct drm_device *dev, u8 *ksvs, u32 ksv_count) intdrm_connector_attach_content_protection_property(struct
drm_connector*connector,
boolhdcp_content_type);
void drm_hdcp_update_content_protection(structdrm_connector
*connector, u64 val); -void drm_hdcp_atomic_check(structdrm_connector*connector,include/drm/display/drm_hdcp_helper.h +1
-1+bool drm_hdcp_atomic_check (struct drm_connector *connector,struct drm_atomic_state *state);#endif --2.39.0.246.g2a6d74b583-goog
PATCH v6 3/10 drm/hdcp: Update property value on content type and user changes
In reply to Mark YacoubFrom: Sean Paul <[email protected]>
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).
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(-)
drivers/gpu/drm/display/drm_hdcp_helper.c +19 -10
@@ -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);
Signature · 1 line
2.39.0.246.g2a6d74b583-goog
PATCH v6 4/10 drm/hdcp: Expand HDCP helper library for enable/disable/check
In reply to Mark YacoubFrom: Sean Paul <[email protected]>
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.
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 <[email protected]>
--- 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(-)
drivers/gpu/drm/display/drm_hdcp_helper.c +1109 -0
@@ -6,13 +6,18 @@* Ramalingam C <[email protected]> */ +#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);
include/drm/display/drm_hdcp.h +167 -1
183 lines not on this page · raw message
include/drm/display/drm_hdcp_helper.h +29 -1
@@ -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_"
Signature · 1 line
2.39.0.246.g2a6d74b583-goog
Re: [PATCH v6 04/10] drm/hdcp: Expand HDCP helper library for enable/disable/check
Quoted 153 lines · Mark Yacoub
From: Sean Paul <[email protected]>
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 newdrm_hdcp_helper_funcsvtable 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 callingdrm_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 <[email protected]>Acked-by Jani Nikula <[email protected]>Reviewed-by Abhinav Kumar <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>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:(quoted diff) +0
-4-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 <[email protected]> --- 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(-)drivers/gpu/drm/display/drm_hdcp_helper.c +74
-0@@ -6,13 +6,18 @@* Ramalingam C <[email protected]> */ +#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 ;
drivers/gpu/drm/display/drm_hdcp_helper.c bool drm_hdcp_atomic_check(struct drm_connector *connector, · line 598
Quoted 10 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +10
-0+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.
Quoted 138 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +138
-0+ 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 );
drivers/gpu/drm/display/drm_hdcp_helper.c bool drm_hdcp_atomic_check(struct drm_connector *connector, · line 746
Quoted 10 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +10
-0+ *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.
Quoted 26 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +26
-0+ +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,
drivers/gpu/drm/display/drm_hdcp_helper.c bool drm_hdcp_atomic_check(struct drm_connector *connector, · line 782
Quoted 10 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +10
-0+ 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.
drivers/gpu/drm/display/drm_hdcp_helper.c bool drm_hdcp_atomic_check(struct drm_connector *connector, · line 792
Quoted 10 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +10
-0+ +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.
Quoted 75 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +75
-0+ 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",
drivers/gpu/drm/display/drm_hdcp_helper.c bool drm_hdcp_atomic_check(struct drm_connector *connector, · line 877
Quoted 10 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +10
-0+ 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.
Quoted 178 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +178
-0+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,
drivers/gpu/drm/display/drm_hdcp_helper.c bool drm_hdcp_atomic_check(struct drm_connector *connector, · line 1065
Quoted 10 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +10
-0+ 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.
Quoted 403 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +403
-0+ +/* +* 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. +*/
drivers/gpu/drm/display/drm_hdcp_helper.c bool drm_hdcp_atomic_check(struct drm_connector *connector, · line 1478
Quoted 10 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +10
-0+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?
Quoted 189 lines
drivers/gpu/drm/display/drm_hdcp_helper.c +145
-0+{ +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);include/drm/display/drm_hdcp.h +21
-1@@ -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
include/drm/display/drm_hdcp.h struct hdcp_srm_header { · line 328
Quoted 10 lines
include/drm/display/drm_hdcp.h +10
-0+* 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.
Quoted 171 lines
include/drm/display/drm_hdcp.h +136
-0+ +/** +* @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_ include/drm/display/drm_hdcp_helper.h +21
-0@@ -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); +
include/drm/display/drm_hdcp_helper.h struct drm_atomic_state; · line 53
Quoted 10 lines
include/drm/display/drm_hdcp_helper.h +8
-1+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.
Signature · 2 lines
With best wishes Dmitry
PATCH v6 5/10 drm/i915/hdcp: Consolidate HDCP setup/state cache
In reply to Mark YacoubFrom: Sean Paul <[email protected]>
Stick all of the setup for HDCP into a dedicated function. No functional change, but this will facilitate moving HDCP logic into helpers.
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(-)
drivers/gpu/drm/i915/display/intel_hdcp.c +35 -17
@@ -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;
Signature · 1 line
2.39.0.246.g2a6d74b583-goog
PATCH v6 6/10 drm/i915/hdcp: Retain hdcp_capable return codes
In reply to Mark YacoubFrom: Sean Paul <[email protected]>
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.
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(-)
drivers/gpu/drm/i915/display/intel_display_debugfs.c +7 -2
@@ -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 " );
drivers/gpu/drm/i915/display/intel_hdcp.c +28 -23
112 lines not on this page · raw message
drivers/gpu/drm/i915/display/intel_hdcp.h +2 -2
@@ -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);
Signature · 1 line
2.39.0.246.g2a6d74b583-goog
RE: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes
Quoted 60 lines
Subject: [PATCH v6 06/10] drm/i915/hdcp: Retain
hdcp_capablereturn codesFrom: Sean Paul <[email protected]>
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 <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Link:
https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-7-
[email protected] #v1
Link:
https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-7-
[email protected] #v2
Link:
https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-7-
[email protected] #v3
Link:
https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
[email protected] #v4
Link:
https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
[email protected] #v5Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:(quoted diff) +0
-2-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(-)drivers/gpu/drm/i915/display/intel_display_debugfs.c +1
-0@@ -492,6 +492,7 @@ static void intel_panel_info(struct seq_file *m, staticvoid 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; }
drivers/gpu/drm/i915/display/intel_display_debugfs.c static void intel_hdcp_info(struct seq_file *m, · line 509
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_display_debugfs.c +6
-2- 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
Quoted 156 lines
drivers/gpu/drm/i915/display/intel_display_debugfs.c +0
-0if (hdcp_cap)seq_puts (m,"HDCP1.4 " );drivers/gpu/drm/i915/display/intel_hdcp.c +18
-15@@ -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,
structintel_digital_port*dig_port=intel_attached_dig_port(connector);drivers/gpu/drm/i915/display/intel_hdcp.c +1
-0struct 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 thesetup
drivers/gpu/drm/i915/display/intel_hdcp.c +3
-2* 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;drivers/gpu/drm/i915/display/intel_hdcp.c +7
-2+ 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)drivers/gpu/drm/i915/display/intel_hdcp.c +1
-1ret =_intel_hdcp_enable (connector); - } +out:if (!ret) { schedule_delayed_work(&hdcp->check_work,
check_link_interval);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-1intel_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);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-0return ret;drivers/gpu/drm/i915/display/intel_hdcp.h +0
-0@@ -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); -boolintel_hdcp_capable(struct intel_connector *connector); -boolintel_hdcp2_capable(struct intel_connector *connector);drivers/gpu/drm/i915/display/intel_hdcp.h +3
-0+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); voidintel_hdcp_cleanup(struct intel_connector *connector); --
2.39.0.246.g2a6d74b583-goog
RE: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes
Quoted 211 lines
-----Original Message-----
From: Kandpal, Suraj
Sent: Friday, March 10, 2023 1:55 PM
To: Mark Yacoub <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; [email protected]
Cc: [email protected]; [email protected]; Souza, Jose <[email protected]>; [email protected]; [email protected]; [email protected]; Vasut, Marek <[email protected]>; Dixit, Ashutosh <[email protected]>; [email protected]; [email protected]; [email protected]; Murthy, Arun R <[email protected]>; Lisovskiy, Stanislav <[email protected]>; [email protected]; [email protected]; Nautiyal, Ankit K <[email protected]>; Nikula, Jani <[email protected]>; De Marchi, Lucas <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Vivi, Rodrigo <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; Sharma, Swati2 <[email protected]>; Navare, Manasi D <[email protected]>; [email protected]; Modem, Bhanuprakash <[email protected]>; [email protected]; [email protected]
Subject: RE: [PATCH v6 06/10] drm/i915/hdcp: Retainhdcp_capablereturn codesQuoted 13 lines
Subject: [PATCH v6 06/10] drm/i915/hdcp: Retain
hdcp_capablereturn codesFrom: Sean Paul <[email protected]>
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 <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Quoted 11 lines
Link:
https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-7-
[email protected] #v1
Link:
https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-7-
[email protected] #v2
Link:
https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-7-
[email protected] #v3
Link:https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
Quoted 3 lines
[email protected] #v4
Link:https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
Quoted 34 lines
Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:(quoted diff) +0
-2-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(-)drivers/gpu/drm/i915/display/intel_display_debugfs.c +1
-0@@ -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; }drivers/gpu/drm/i915/display/intel_display_debugfs.c static void intel_hdcp_info(struct seq_file *m, · line 509
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_display_debugfs.c +6
-2- 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_capor hdcp2 cap is true or false which you basically reiterate here too check theintel_dp_hdcp2_capableandintel_hdmi_hdcp2_capable. this change in itself can be removed.Regards,
Suraj KandpalQuoted 83 lines
drivers/gpu/drm/i915/display/intel_display_debugfs.c +0
-0if (hdcp_cap)seq_puts (m,"HDCP1.4 " );drivers/gpu/drm/i915/display/intel_hdcp.c +18
-15@@ -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,
structintel_digital_port*dig_port=intel_attached_dig_port(connector);drivers/gpu/drm/i915/display/intel_hdcp.c
Quoted 2 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-0struct intel_hdcp *hdcp = &connector->hdcp; unsigned long check_link_interval =
DRM_HDCP_CHECK_PERIOD_MS;Quoted 12 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +1
-0+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 thesetup
drivers/gpu/drm/i915/display/intel_hdcp.c +1
-1* is capable of HDCP2.2, it is preferred to use HDCP2.2. */ -if (intel_hdcp2_capable (connector)) { + ret =intel_hdcp2_capable (connector, &capable);
Quoted 8 lines
drivers/gpu/drm/i915/display/intel_hdcp.c int intel_hdcp_enable(struct intel_connector *connector, · line 2382
Quoted 8 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +2
-1+if (capable) { ret =_intel_hdcp2_enable (connector); -if (!ret) +if (!ret) { check_link_interval =
DRM_HDCP2_CHECK_PERIOD_MS;drivers/gpu/drm/i915/display/intel_hdcp.c +2
-0+ 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
Quoted 52 lines
Quoted 37 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +5
-2}/* * 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)drivers/gpu/drm/i915/display/intel_hdcp.c +1
-1ret =_intel_hdcp_enable (connector); - } +out:if (!ret) { schedule_delayed_work(&hdcp->check_work,
check_link_interval);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-1intel_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);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-0return ret;drivers/gpu/drm/i915/display/intel_hdcp.h +0
-0drivers/gpu/drm/i915/display/intel_hdcp.h void intel_hdcp_update_pipe(struct · line 35
Quoted 3 lines
drivers/gpu/drm/i915/display/intel_hdcp.h +0
-0@@ -33,8 +33,8 @@ void intel_hdcp_update_pipe(structintel_atomic_state *state, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state);bool
Quoted 11 lines
drivers/gpu/drm/i915/display/intel_hdcp.h +3
-1is_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); voidintel_hdcp_cleanup(struct intel_connector *connector); --
2.39.0.246.g2a6d74b583-goog
Re: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes
Quoted 111 lines · Suraj
Quoted 111 lines
-----Original Message-----
From: Kandpal, Suraj
Sent: Friday, March 10, 2023 1:55 PM
To: Mark Yacoub <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; [email protected]
Cc: [email protected]; [email protected]; Souza, Jose <[email protected]>; [email protected]; [email protected]; [email protected]; Vasut, Marek <[email protected]>; Dixit, Ashutosh <[email protected]>; [email protected]; [email protected]; [email protected]; Murthy, Arun R <[email protected]>; Lisovskiy, Stanislav <[email protected]>; [email protected]; [email protected]; Nautiyal, Ankit K <[email protected]>; Nikula, Jani <[email protected]>; De Marchi, Lucas <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Vivi, Rodrigo <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; Sharma, Swati2 <[email protected]>; Navare, Manasi D <[email protected]>; [email protected]; Modem, Bhanuprakash <[email protected]>; [email protected]; [email protected]
Subject: RE: [PATCH v6 06/10] drm/i915/hdcp: Retainhdcp_capablereturn codesQuoted 13 lines
Subject: [PATCH v6 06/10] drm/i915/hdcp: Retain
hdcp_capablereturn codesFrom: Sean Paul <[email protected]>
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 <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Quoted 11 lines
Link:
https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-7-
[email protected] #v1
Link:
https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-7-
[email protected] #v2
Link:
https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-7-
[email protected] #v3
Link:https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
Quoted 3 lines
[email protected] #v4
Link:https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
Quoted 34 lines
Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:(quoted diff) +0
-2-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(-)drivers/gpu/drm/i915/display/intel_display_debugfs.c +1
-0@@ -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; }drivers/gpu/drm/i915/display/intel_display_debugfs.c static void intel_hdcp_info(struct seq_file *m, · line 509
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_display_debugfs.c +6
-2- 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_capor hdcp2 cap is true or false which you basically reiterate here too check theintel_dp_hdcp2_capableandintel_hdmi_hdcp2_capable. this change in itself can be removed.
Quoted 3 lines
Quoted 3 lines
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.
Quoted 113 lines
Quoted 98 lines
Quoted 79 lines
drivers/gpu/drm/i915/display/intel_display_debugfs.c +0
-0if (hdcp_cap)seq_puts (m,"HDCP1.4 " );drivers/gpu/drm/i915/display/intel_hdcp.c +18
-15@@ -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, @@ -Quoted 6 lines
2355,6 +2354,7 @@ int intel_hdcp_enable(struct
intel_connector*connector,
structintel_digital_port*dig_port=intel_attached_dig_port(connector);
structintel_hdcp*hdcp =&connector->hdcp; unsigned longcheck_link_interval=
DRM_HDCP_CHECK_PERIOD_MS;Quoted 12 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +1
-0+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 thesetup
* is capable of HDCP2.2, it is preferred to use HDCP2.2. */drivers/gpu/drm/i915/display/intel_hdcp.c +1
-1-if (intel_hdcp2_capable (connector)) { + ret =intel_hdcp2_capable (connector, &capable);Quoted 8 lines
drivers/gpu/drm/i915/display/intel_hdcp.c int intel_hdcp_enable(struct intel_connector *connector, · line 2382
Quoted 8 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +2
-1+if (capable) { ret =_intel_hdcp2_enable (connector); -if (!ret) +if (!ret) { check_link_interval =
DRM_HDCP2_CHECK_PERIOD_MS;drivers/gpu/drm/i915/display/intel_hdcp.c +2
-0+ goto out; + }HI,
Just noticed another changed here if any error is returned withintel_hdc2_capableYou 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.
Quoted 2 lines
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!
Quoted 53 lines
Quoted 52 lines
Quoted 37 lines
} /* * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will * be attempted. */drivers/gpu/drm/i915/display/intel_hdcp.c +5
-2-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);drivers/gpu/drm/i915/display/intel_hdcp.c +1
-1- } +out:if (!ret) { schedule_delayed_work(&hdcp->check_work,
check_link_interval);
intel_hdcp_update_value(connector,drivers/gpu/drm/i915/display/intel_hdcp.c +0
-1@@ -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;drivers/gpu/drm/i915/display/intel_hdcp.h +0
-0drivers/gpu/drm/i915/display/intel_hdcp.h void intel_hdcp_update_pipe(struct · line 35
Quoted 3 lines
drivers/gpu/drm/i915/display/intel_hdcp.h +0
-0@@ -33,8 +33,8 @@ void intel_hdcp_update_pipe(structintel_atomic_state *state, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state);bool
Quoted 11 lines
drivers/gpu/drm/i915/display/intel_hdcp.h +3
-1is_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); voidintel_hdcp_cleanup(struct intel_connector *connector); --
2.39.0.246.g2a6d74b583-goog
RE: [PATCH v6 06/10] drm/i915/hdcp: Retain hdcp_capable return codes
Quoted 161 lines
-----Original Message-----
From: Mark Yacoub <[email protected]>
Sent: Saturday, March 25, 2023 12:57 AM
To: Kandpal, Suraj <[email protected]>
Cc: [email protected]; [email protected]; dri- [email protected]; [email protected]; [email protected]; [email protected]; intel- [email protected]; [email protected]; [email protected]; Souza, Jose <[email protected]>; [email protected]; [email protected]; [email protected]; Vasut, Marek <[email protected]>; Dixit, Ashutosh <[email protected]>; [email protected]; [email protected]; [email protected]; Murthy, Arun R <[email protected]>; Lisovskiy, Stanislav <[email protected]>; [email protected]; [email protected]; Nautiyal, Ankit K <[email protected]>; Nikula, Jani <[email protected]>; De Marchi, Lucas <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Vivi, Rodrigo <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; Sharma, Swati2 <[email protected]>; Navare, Manasi D <[email protected]>; [email protected]; Modem, Bhanuprakash <[email protected]>; [email protected]; [email protected]
Subject: Re: [PATCH v6 06/10] drm/i915/hdcp: Retainhdcp_capablereturn codesQuoted 7 lines · Suraj
Quoted 7 lines
-----Original Message-----
From: Kandpal, Suraj
Sent: Friday, March 10, 2023 1:55 PM
To: Mark Yacoub <[email protected]>;Quoted 6 lines
Quoted 6 lines
[email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; [email protected]
Cc: [email protected]; [email protected]; Souza, Jose <[email protected]>; [email protected]; [email protected]; [email protected]; Vasut, MarekQuoted 8 lines
Quoted 8 lines
<[email protected]>; Dixit, Ashutosh <[email protected]>; [email protected]; [email protected]; [email protected]; Murthy, Arun R <[email protected]>; Lisovskiy, Stanislav <[email protected]>; [email protected]; [email protected]; Nautiyal, Ankit K <[email protected]>; Nikula, Jani <[email protected]>; De Marchi, Lucas <[email protected]>; [email protected]; [email protected];
Quoted 5 lines
Quoted 5 lines
[email protected]; [email protected]; Vivi, Rodrigo <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; Sharma, Swati2 <[email protected]>; Navare, Manasi D <[email protected]>;
Quoted 14 lines
Quoted 14 lines
Modem, Bhanuprakash <[email protected]>; [email protected]; [email protected]
Subject: RE: [PATCH v6 06/10] drm/i915/hdcp: Retainhdcp_capablereturn codesQuoted 9 lines
Subject: [PATCH v6 06/10] drm/i915/hdcp: Retain
hdcp_capablereturn codesFrom: Sean Paul <[email protected]>
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.Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Acked-by Jani Nikula <[email protected]>Reviewed-by Rodrigo Vivi <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Link:
https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
-7-
[email protected] #v1
Link:https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
7-
[email protected] #v2
Link:https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
-7-
[email protected] #v3
Link:https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845
Quoted 5 lines
Quoted 5 lines
-
Quoted 3 lines
[email protected] #v4
Link:https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308
Quoted 37 lines
Quoted 37 lines
-
Quoted 36 lines
Changes in v2:
-None
Changes in v3:
-None
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:(quoted diff) +0
-2-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(-)drivers/gpu/drm/i915/display/intel_display_debugfs.c +1
-0@@ -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 @@ staticvoid intel_hdcp_info(struct
seq_file*m,goto out; }Quoted 14 lines
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_display_debugfs.c static void intel_hdcp_info(struct seq_file *m, · line 508
Quoted 9 lines
drivers/gpu/drm/i915/display/intel_display_debugfs.c +6
-2- 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;Quoted 4 lines
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_capor hdcp2 cap is true or false which you basically reiterate here too check theintel_dp_hdcp2_capableand
intel_hdmi_hdcp2_capable.Quoted 5 lines
Quoted 5 lines
this change in itself can be removed.
Regards,
Suraj Kandpal
Quoted 6 lines
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.
Quoted 113 lines
Quoted 105 lines
Quoted 105 lines
Quoted 79 lines
if (hdcp_cap) seq_puts(m, "HDCP1.4 "); diff --git
a/drivers/gpu/drm/i915/display/intel_hdcp.cb/drivers/gpu/drm/i915/display/intel_hdcp.c
index0a20bc41be55..61a862ae1f28100644drivers/gpu/drm/i915/display/intel_hdcp.c +18
-15@@ -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,Quoted 7 lines
@@ -
2355,6 +2354,7 @@ int intel_hdcp_enable(structintel_connector*connector,
structintel_digital_port*dig_port=intel_attached_dig_port(connector);
structintel_hdcp*hdcp =&connector->hdcp; unsigned longcheck_link_interval=
DRM_HDCP_CHECK_PERIOD_MS;Quoted 18 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +1
-0+bool capable;int ret = -EINVAL ;if (!hdcp->shim)@@ -2373,21 +2373,27 @@ int intel_hdcp_enable(structintel_connector *connector, * Considering that HDCP2.2 is more secure than HDCP1.4, Ifthe setup
* is capable of HDCP2.2, it is preferred to use HDCP2.2. */drivers/gpu/drm/i915/display/intel_hdcp.c +3
-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;Quoted 8 lines
Quoted 2 lines
drivers/gpu/drm/i915/display/intel_hdcp.c int intel_hdcp_enable(struct intel_connector *connector, · line 2382
Quoted 2 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +2
-0+ goto out; + }HI,
Just noticed another changed here if any error is returned withintel_hdc2_capableYou 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
Quoted 8 lines
handling of error codes are adding value here.
Quoted 3 lines
Regards,
Suraj KandpalHey 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
Quoted 56 lines
Quoted 56 lines
Quoted 55 lines
Quoted 37 lines
} /* * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will * be attempted. */drivers/gpu/drm/i915/display/intel_hdcp.c +5
-2-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);drivers/gpu/drm/i915/display/intel_hdcp.c +1
-1- } +out:if (!ret) { schedule_delayed_work(&hdcp->check_work,
check_link_interval);
intel_hdcp_update_value(connector,drivers/gpu/drm/i915/display/intel_hdcp.c +0
-1@@ -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;drivers/gpu/drm/i915/display/intel_hdcp.h +0
-0drivers/gpu/drm/i915/display/intel_hdcp.h void intel_hdcp_update_pipe(struct · line 36
Quoted 4 lines
drivers/gpu/drm/i915/display/intel_hdcp.h +0
-0@@ -33,8 +33,8 @@ void intel_hdcp_update_pipe(structintel_atomic_state *state, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state);bool
Quoted 13 lines
is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port); -boolintel_hdcp_capable(struct intel_connector *connector); -boolintel_hdcp2_capable(struct intel_connector *connector);drivers/gpu/drm/i915/display/intel_hdcp.h +3
-0+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); voidintel_hdcp_component_fini(struct drm_i915_private *dev_priv); voidintel_hdcp_cleanup(struct intel_connector *connector);
--
2.39.0.246.g2a6d74b583-goog
PATCH v6 7/10 drm/i915/hdcp: Use HDCP helpers for i915
In reply to Mark YacoubFrom: Sean Paul <[email protected]>
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.
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(-)
drivers/gpu/drm/i915/display/intel_ddi.c +24 -8
@@ -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
drivers/gpu/drm/i915/display/intel_display_debugfs.c +4 -2
@@ -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;
drivers/gpu/drm/i915/display/intel_display_types.h +2 -58
79 lines not on this page · raw message
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +122 -226
423 lines not on this page · raw message
drivers/gpu/drm/i915/display/intel_dp_mst.c +9 -7
@@ -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,
drivers/gpu/drm/i915/display/intel_hdcp.c +166 -786
1,178 lines not on this page · raw message
drivers/gpu/drm/i915/display/intel_hdcp.h +23 -8
@@ -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);
drivers/gpu/drm/i915/display/intel_hdmi.c +95 -175
346 lines not on this page · raw message
Signature · 1 line
2.39.0.246.g2a6d74b583-goog
Re: [Intel-gfx] [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915
+Suraj who is also working on HDCP related code that even can conflict wit this.
Quoted 1 line · Mark Yacoub
From: Sean Paul <[email protected]>
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.
Quoted 8 lines
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 theintel_dp_hdcp.corintel_hdmi.c.
so far so good! we need to do this soon.
Quoted 7 lines
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.
Quoted 4 lines
Acked-by Jani Nikula <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>
Quoted 142 lines
Changes in v2:
-Fix mst helper function pointer reported by 0-day
Changes in v3:
-Add forward declaration fordrm_atomic_stateinintel_hdcp.hidentified
by 0-day
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:(quoted diff) +0
-2-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(-)drivers/gpu/drm/i915/display/intel_ddi.c +24
-8@@ -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 voiddrivers/gpu/drm/i915/display/intel_display_debugfs.c +4
-2@@ -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;drivers/gpu/drm/i915/display/intel_display_types.h +0
-2@@ -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
drivers/gpu/drm/i915/display/intel_display_types.h enum check_link_response { · line 430
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_display_types.h +0
-10-* 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?
Quoted 82 lines
drivers/gpu/drm/i915/display/intel_display_types.h +2
-46+* 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 {drivers/gpu/drm/i915/display/intel_dp_hdcp.c +4
-3@@ -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);
drivers/gpu/drm/i915/display/intel_dp_hdcp.c static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout) · line 73
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +6
-0+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.
Quoted 230 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +10
-190dpcd_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,
drivers/gpu/drm/i915/display/intel_dp_hdcp.c int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port, · line 654
Quoted 5 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +0
-2@@ -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:
Quoted 1,836 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +102
-31- .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 ; }drivers/gpu/drm/i915/display/intel_dp_mst.c +9
-7@@ -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,drivers/gpu/drm/i915/display/intel_hdcp.c +166
-786@@ -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_recoveryreturn 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); }drivers/gpu/drm/i915/display/intel_hdcp.h +23
-8@@ -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);drivers/gpu/drm/i915/display/intel_hdmi.c +95
-175@@ -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 Signature · 1 line
2.39.0.246.g2a6d74b583-goog
Rodrigo Vivi
maintainerRe: [Intel-gfx] [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915
+Suraj
Quoted 2,392 lines · Rodrigo Vivi
+Suraj who is also working on HDCP related code that even can conflict wit this.
Quoted 1 line · Mark Yacoub
From: Sean Paul <[email protected]>
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.Quoted 8 lines
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 theintel_dp_hdcp.corintel_hdmi.c.so far so good! we need to do this soon.
Quoted 7 lines
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.
Quoted 4 lines
Acked-by Jani Nikula <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Cc Suraj Kandpal <[email protected]>Quoted 142 lines
Changes in v2:
-Fix mst helper function pointer reported by 0-day
Changes in v3:
-Add forward declaration fordrm_atomic_stateinintel_hdcp.hidentified
by 0-day
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:(quoted diff) +0
-2-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(-)drivers/gpu/drm/i915/display/intel_ddi.c +24
-8@@ -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 voiddrivers/gpu/drm/i915/display/intel_display_debugfs.c +4
-2@@ -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;drivers/gpu/drm/i915/display/intel_display_types.h +0
-2@@ -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 drivers/gpu/drm/i915/display/intel_display_types.h enum check_link_response { · line 430
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_display_types.h +0
-10-* 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?Quoted 82 lines
drivers/gpu/drm/i915/display/intel_display_types.h +2
-46+* 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 {drivers/gpu/drm/i915/display/intel_dp_hdcp.c +4
-3@@ -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);drivers/gpu/drm/i915/display/intel_dp_hdcp.c static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout) · line 73
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +6
-0+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.Quoted 230 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +10
-190dpcd_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,drivers/gpu/drm/i915/display/intel_dp_hdcp.c int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port, · line 654
Quoted 5 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +0
-2@@ -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 <[email protected]>Quoted 1,836 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +102
-31- .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 ; }drivers/gpu/drm/i915/display/intel_dp_mst.c +9
-7@@ -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,drivers/gpu/drm/i915/display/intel_hdcp.c +166
-786@@ -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_recoveryreturn 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); }drivers/gpu/drm/i915/display/intel_hdcp.h +23
-8@@ -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);drivers/gpu/drm/i915/display/intel_hdmi.c +95
-175@@ -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 Signature · 1 line
2.39.0.246.g2a6d74b583-goog
RE: [Intel-gfx] [PATCH v6 07/10] drm/i915/hdcp: Use HDCP helpers for i915
In reply to Mark YacoubQuoted 193 lines
From: Sean Paul <[email protected]>
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 theintel_dp_hdcp.corintel_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 <[email protected]>Signed-off-by Sean Paul <[email protected]>Signed-off-by Mark Yacoub <[email protected]>Link:
https://patchwork.freedesktop.org/patch/msgid/20210913175747.47456-8-
[email protected] #v1
Link:
https://patchwork.freedesktop.org/patch/msgid/20210915203834.1439-8-
[email protected] #v2
Link:
https://patchwork.freedesktop.org/patch/msgid/20211001151145.55916-8-
[email protected] #v3
Link:
https://patchwork.freedesktop.org/patch/msgid/20211105030434.2828845-
[email protected] #v4
Link:
https://patchwork.freedesktop.org/patch/msgid/20220411204741.1074308-
[email protected] #v5Changes in v2:
-Fix mst helper function pointer reported by 0-day
Changes in v3:
-Add forward declaration fordrm_atomic_stateinintel_hdcp.hidentified
by 0-day
Changes in v4:
-None
Changes in v5:
-None
Changes in v6:(quoted diff) +0
-2-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(-)drivers/gpu/drm/i915/display/intel_ddi.c +5
-0@@ -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(structintel_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);drivers/gpu/drm/i915/display/intel_ddi.c +2
-6if (!intel_crtc_is_bigjoiner_slave (crtc_state))@@ -2925,12 +2930,10 @@ static void intel_enable_ddi(structintel_atomic_state *state, elseintel_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-Quoted 1 line
hdcp_helper_data,drivers/gpu/drm/i915/display/intel_ddi.c +8
-1+ &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(structintel_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-Quoted 1 line
hdcp_helper_data,drivers/gpu/drm/i915/display/intel_ddi.c +9
-1+ &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(structintel_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
drivers/gpu/drm/i915/display/intel_display_debugfs.c +4
-2@@ -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;drivers/gpu/drm/i915/display/intel_display_types.h +0
-5@@ -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.
Quoted 8 lines
- * - 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
Quoted 73 lines
+ * place on DP vs HDMI.
*/
structintel_hdcp_shim{drivers/gpu/drm/i915/display/intel_display_types.h +0
-8-/* 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
drivers/gpu/drm/i915/display/intel_display_types.h +0
-1-* definitions are the same in the respective specs, but the names are
drivers/gpu/drm/i915/display/intel_display_types.h +1
-37-* 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 {drivers/gpu/drm/i915/display/intel_dp_hdcp.c +0
-0
drivers/gpu/drm/i915/display/intel_dp_hdcp.c static void intel_dp_hdcp_wait_for_cp_irq(struct · line 61
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +1
-3@@ -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.
Quoted 424 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +10
-29+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(structintel_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,drivers/gpu/drm/i915/display/intel_dp_hdcp.c +0
-17- 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,drivers/gpu/drm/i915/display/intel_dp_hdcp.c +0
-33- 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,drivers/gpu/drm/i915/display/intel_dp_hdcp.c +0
-3- 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",
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +0
-15- 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,drivers/gpu/drm/i915/display/intel_dp_hdcp.c +0
-21- &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;drivers/gpu/drm/i915/display/intel_dp_hdcp.c +0
-7- 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",
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +0
-62- 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(structintel_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{drivers/gpu/drm/i915/display/intel_dp_hdcp.c +9
-3u8 msg_id;u8 stream_type;@@ -628,13 +449,19 @@ int intel_dp_hdcp2_check_link(structintel_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;drivers/gpu/drm/i915/display/intel_dp_hdcp.c +14
-11ret = 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(structintel_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)drivers/gpu/drm/i915/display/intel_dp_hdcp.c +2
-0+{ + struct intel_connector *connector =
to_intel_connector(drm_connector);drivers/gpu/drm/i915/display/intel_dp_hdcp.c +24
-0+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,
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +41
-22bool 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);
drivers/gpu/drm/i915/display/intel_dp_hdcp.c int intel_dp_mst_hdcp2_check_link(struct · line 708
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +10
-0+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
Quoted 151 lines
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +2
-0+if (IS_ERR (data)) { + drm_dbg_kms(&dev_priv->drm, "HDCP init failed,skipping.\n");
drivers/gpu/drm/i915/display/intel_dp_hdcp.c +9
-0+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 ; }drivers/gpu/drm/i915/display/intel_dp_mst.c +5
-2@@ -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);drivers/gpu/drm/i915/display/intel_dp_mst.c +0
-0drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state, drm_atomic_get_mst_payload_state(mst_state,
connector->port));drivers/gpu/drm/i915/display/intel_dp_mst.c +4
-5@@ -579,11 +582,10 @@ static void intel_mst_enable_dp(structintel_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,drivers/gpu/drm/i915/display/intel_hdcp.c +1
-59@@ -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);drivers/gpu/drm/i915/display/intel_hdcp.c +1
-0+ struct intel_connector *connector =
to_intel_connector(drm_connector);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-0struct drm_i915_private *dev_priv =to_i915 (connector->base.dev);struct intel_hdcp *hdcp = &connector->hdcp;
drivers/gpu/drm/i915/display/intel_hdcp.c int intel_hdcp2_capable(struct intel_connector · line 223
Quoted 6 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2@@ -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
Quoted 436 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +7
-5+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-Quoted 1 line
hdcp.cpu_transcoder;
drivers/gpu/drm/i915/display/intel_hdcp.c +10
-21+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(structdrm_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) {drivers/gpu/drm/i915/display/intel_hdcp.c +5
-1enum 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 notpossible\n");
drivers/gpu/drm/i915/display/intel_hdcp.c +3
-0+return -ENXIO ; + } + val =intel_de_read (dev_priv,HDCP_KEY_STATUS ); if ((val & HDCP_KEY_LOAD_DONE) && (val &
HDCP_KEY_LOAD_STATUS))drivers/gpu/drm/i915/display/intel_hdcp.c +5
-2return 0 ;@@ -308,8 +247,11 @@ static int intel_hdcp_load_keys(structdrm_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; + }drivers/gpu/drm/i915/display/intel_hdcp.c +1
-1/* * 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);drivers/gpu/drm/i915/display/intel_hdcp.c +17
-15@@ -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(structdrm_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]);
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-0/* * We need to write the concatenation of all device KSVs, BINFO (DP) ||
drivers/gpu/drm/i915/display/intel_hdcp.c +4
-26@@ -642,131 +586,38 @@ int intel_hdcp_validate_v_prime(structintel_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
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-13-* 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);drivers/gpu/drm/i915/display/intel_hdcp.c +1
-15-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-Quoted 1 line
hdcp.cpu_transcoder;
drivers/gpu/drm/i915/display/intel_hdcp.c +2
-11+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),
drivers/gpu/drm/i915/display/intel_hdcp.c +2
-0+ ksv[0]); + intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder,port),
drivers/gpu/drm/i915/display/intel_hdcp.c +5
-6+ 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 downstreamdevices)\n",
drivers/gpu/drm/i915/display/intel_hdcp.c +4
-7- 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);
structintel_digital_port*dig_port=intel_attached_dig_port(connector);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2struct 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-Quoted 1 line
hdcp.cpu_transcoder;
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-18enum 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
drivers/gpu/drm/i915/display/intel_hdcp.c +27
-49-* 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)) &
drivers/gpu/drm/i915/display/intel_hdcp.c static int intel_hdcp_auth(struct intel_connector *connector) · line 675
Quoted 6 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +5
-1- (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
Quoted 515 lines
drm_err(&dev_priv->drm, "Timed out waiting for R0
ready\n");drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2return -ETIMEDOUT ; } -/* -* Wait for R0' to become available. The spec says 100ms from Aksv, but
drivers/gpu/drm/i915/display/intel_hdcp.c +2
-12-* 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
drivers/gpu/drm/i915/display/intel_hdcp.c +1
-10-* 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)drivers/gpu/drm/i915/display/intel_hdcp.c +2
-0+{ + struct intel_connector *connector =
to_intel_connector(drm_connector);drivers/gpu/drm/i915/display/intel_hdcp.c +4
-0+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-Quoted 1 line
hdcp.cpu_transcoder;
drivers/gpu/drm/i915/display/intel_hdcp.c +1
-2+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)) &drivers/gpu/drm/i915/display/intel_hdcp.c +0
-1- (HDCP_STATUS_RI_MATCH |
HDCP_STATUS_ENC), 1))drivers/gpu/drm/i915/display/intel_hdcp.c +1
-2-break ; - } + intel_de_write(dev_priv, HDCP_RPRIME(dev_priv, cpu_transcoder,port),
drivers/gpu/drm/i915/display/intel_hdcp.c +4
-5+ 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)) &
drivers/gpu/drm/i915/display/intel_hdcp.c +1
-0+ (HDCP_STATUS_RI_MATCH |
HDCP_STATUS_ENC),drivers/gpu/drm/i915/display/intel_hdcp.c +8
-1+ 1))return -ETIMEDOUT ; - } + +return 0 ; +} + +int intel_hdcp1_post_encryption (struct drm_connector *drm_connector) +{ + struct intel_connector *connector =
to_intel_connector(drm_connector);drivers/gpu/drm/i915/display/intel_hdcp.c +4
-0+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-Quoted 1 line
hdcp.cpu_transcoder;
drivers/gpu/drm/i915/display/intel_hdcp.c +3
-18+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 beingdisabled...\n",
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-4connector->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 disableHDCP 1.4 stream enc\n",
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-1- connector->base.name, connector-Quoted 1 line
base.base.id);
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-3-return ret; - } - drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %sstream encryption disabled\n",
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-10- 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);
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-14if (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 beingenabled...\n",
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-4- connector->base.name, connector->base.base.id); - -if (!hdcp_key_loadable (dev_priv)) { - drm_err(&dev_priv->drm, "HDCP key Load is notpossible\n");
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-11-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",
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-13- 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);
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-11- -/* 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)
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-9-{ - 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);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-3-struct intel_hdcp *hdcp = &connector->hdcp; - - drm_WARN_ON(connector->base.dev, !mutex_is_locked(&hdcp-Quoted 1 line
mutex));
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-8- -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))
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-16- 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);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-13-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||
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-7- !hdcp->hdcp_encrypted) { - ret = -EINVAL ; - goto out; - } - - if (drm_WARN_ON(&dev_priv->drm, - !intel_hdcp_in_use(dev_priv, cpu_transcoder,port))) {
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-4- 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)));drivers/gpu/drm/i915/display/intel_hdcp.c +0
-3- ret = -ENXIO ; - intel_hdcp_update_value(connector, -
DRM_MODE_CONTENT_PROTECTION_DESIRED,drivers/gpu/drm/i915/display/intel_hdcp.c +0
-6- true); - goto out; - } - -if (hdcp->shim->check_link (dig_port, connector)) { - if (hdcp->value !=
DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2- intel_hdcp_update_value(connector, -DRM_MODE_CONTENT_PROTECTION_ENABLED, true);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-11- } - 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);
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2- intel_hdcp_update_value(connector, -
DRM_MODE_CONTENT_PROTECTION_DESIRED,drivers/gpu/drm/i915/display/intel_hdcp.c +0
-7- true); - goto out; - } - - ret =_intel_hdcp_enable (connector); -if (ret) { - drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n",ret);
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2- intel_hdcp_update_value(connector, -
DRM_MODE_CONTENT_PROTECTION_DESIRED,drivers/gpu/drm/i915/display/intel_hdcp.c +0
-18- 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-Quoted 1 line
drm.mode_config.connection_mutex, NULL);
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-4-mutex_lock (&hdcp->mutex); - -/* -* This worker is only used to flip between ENABLED/DESIRED. Either of
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-4-* 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)drivers/gpu/drm/i915/display/intel_hdcp.c +0
-5-drm_hdcp_update_content_protection (&connector->base, - hdcp->value); - -mutex_unlock (&hdcp->mutex); - drm_modeset_unlock(&dev_priv-Quoted 1 line
drm.mode_config.connection_mutex);
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-4- -drm_connector_put (&connector->base); -} - bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum portport)
{drivers/gpu/drm/i915/display/intel_hdcp.c +2
-1return 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);drivers/gpu/drm/i915/display/intel_hdcp.c +7
-1struct intel_hdcp *hdcp = &connector->hdcp;int ret;@@ -2024,9 +1650,15 @@ _intel_hdcp2_disable(struct intel_connector *connector, bool hdcp2_link_recoveryreturn 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);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-3struct 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||
drivers/gpu/drm/i915/display/intel_hdcp.c +2
-4- !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))) {
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-0drm_err(&dev_priv->drm, "HDCP2.2 link stopped the encryption, %x\n", intel_de_read(dev_priv, HDCP2_STATUS(dev_priv,
cpu_transcoder, port)));drivers/gpu/drm/i915/display/intel_hdcp.c +0
-4- ret = -ENXIO ; -_intel_hdcp2_disable (connector, true); - intel_hdcp_update_value(connector, -
DRM_MODE_CONTENT_PROTECTION_DESIRED,drivers/gpu/drm/i915/display/intel_hdcp.c +1
-4- 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) {drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2- intel_hdcp_update_value(connector, -
DRM_MODE_CONTENT_PROTECTION_ENABLED,drivers/gpu/drm/i915/display/intel_hdcp.c +2
-5- true); - } - goto out; - } +if (ret ==HDCP_LINK_PROTECTED ) +return 0 ;if (ret ==HDCP_TOPOLOGY_CHANGE ) { - if (hdcp->value ==
DRM_MODE_CONTENT_PROTECTION_UNDESIRED)drivers/gpu/drm/i915/display/intel_hdcp.c +0
-5- 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,drivers/gpu/drm/i915/display/intel_hdcp.c +0
-18- 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);
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2- intel_hdcp_update_value(connector, -DRM_MODE_CONTENT_PROTECTION_DESIRED, true);drivers/gpu/drm/i915/display/intel_hdcp.c +2
-9- 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,drivers/gpu/drm/i915/display/intel_hdcp.c +2
-2- true); - goto out; +"[%s:%d] Repeater topology auth failed.(%d)\n" , + connector->base.name, connector->base.base.id,ret);
drivers/gpu/drm/i915/display/intel_hdcp.c static int intel_hdcp2_check_link(struct intel_connector *connector) · line 1700
Quoted 7 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-3} -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
Quoted 84 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +13
-27-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);
drivers/gpu/drm/i915/display/intel_hdcp.c +1
-0+ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state-Quoted 1 line
crtc);
drivers/gpu/drm/i915/display/intel_hdcp.c +1
-0+ pipe_config =to_intel_crtc_state (crtc_state);if (intel_crtc_has_type (pipe_config,INTEL_OUTPUT_DP_MST )) { hdcp->cpu_transcoder = pipe_config-Quoted 1 line
mst_master_transcoder;drivers/gpu/drm/i915/display/intel_hdcp.c +0
-1@@ -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)drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2return -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,
drivers/gpu/drm/i915/display/intel_hdcp.c int intel_hdcp_init(struct intel_connector · line 2345
Quoted 10 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-8- 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
Quoted 694 lines
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-4-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)drivers/gpu/drm/i915/display/intel_hdcp.c +0
-3-{ -struct drm_i915_private *dev_priv =to_i915 (connector->base.dev); - struct intel_digital_port *dig_port =
intel_attached_dig_port(connector);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2-struct intel_hdcp *hdcp = &connector->hdcp; - unsigned long check_link_interval =
DRM_HDCP_CHECK_PERIOD_MS;drivers/gpu/drm/i915/display/intel_hdcp.c +0
-10-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);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-7- - 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
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-7-* 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;drivers/gpu/drm/i915/display/intel_hdcp.c +0
-13- 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)drivers/gpu/drm/i915/display/intel_hdcp.c +0
-5- ret =_intel_hdcp_enable (connector); - -out: -if (!ret) { - schedule_delayed_work(&hdcp->check_work,
check_link_interval);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-2- intel_hdcp_update_value(connector, -
DRM_MODE_CONTENT_PROTECTION_ENABLED,drivers/gpu/drm/i915/display/intel_hdcp.c +0
-11- 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);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-10-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)drivers/gpu/drm/i915/display/intel_hdcp.c +0
-4- goto out; - - intel_hdcp_update_value(connector, -DRM_MODE_CONTENT_PROTECTION_UNDESIRED, false);drivers/gpu/drm/i915/display/intel_hdcp.c +0
-21-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;
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-6- -if (!connector->hdcp.shim) -return ; - - content_protection_type_changed = - (conn_state->hdcp_content_type != hdcp->content_type&&
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-19- 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;drivers/gpu/drm/i915/display/intel_hdcp.c +0
-11-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;drivers/gpu/drm/i915/display/intel_hdcp.c +0
-3-mutex_unlock (&hdcp->mutex); -/* -* If HDCP already ENABLED and CP property is DESIRED, schedule
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-3-* prop_work to update correct CP property to user space. -*/ - if (!desired_and_not_enabled &&!content_protection_type_changed) {
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-28-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
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-1-* scheduling prop_work to ensure the connector is alive when
prop_workdrivers/gpu/drm/i915/display/intel_hdcp.c +0
-2-* 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
drivers/gpu/drm/i915/display/intel_hdcp.c +0
-3-* active (tl;dr This Should Never Happen). -*/ - drm_WARN_ON(connector->base.dev, work_pending(&hdcp-Quoted 1 line
prop_work));drivers/gpu/drm/i915/display/intel_hdcp.c +2
-4- -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-Quoted 1 line
hdcp_helper_data);}
drivers/gpu/drm/i915/display/intel_hdcp.h +10
-8@@ -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,drivers/gpu/drm/i915/display/intel_hdcp.h +5
-0+ 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);drivers/gpu/drm/i915/display/intel_hdcp.h +2
-0+int intel_hdcp1_wait_for_r0 (struct drm_connector *drm_connector); +int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32
ri_prime);drivers/gpu/drm/i915/display/intel_hdcp.h +6
-0+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);drivers/gpu/drm/i915/display/intel_hdmi.c +11
-4@@ -1324,17 +1324,24 @@ static int intel_hdmi_hdcp_write(structintel_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,
drivers/gpu/drm/i915/display/intel_hdmi.c +0
-0DRM_HDCP_AN_LEN);if (ret) { drm_dbg_kms(&i915->drm, "Write An over DDC failed(%d)\n",
drivers/gpu/drm/i915/display/intel_hdmi.c +0
-38@@ -1350,120 +1357,6 @@ int intel_hdmi_hdcp_write_an_aksv(structintel_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);
drivers/gpu/drm/i915/display/intel_hdmi.c +0
-2-if (ret) { - drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed(%d)\n",
drivers/gpu/drm/i915/display/intel_hdmi.c +0
-4- ret); -return ret; - } - *repeater_present = val &
DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;drivers/gpu/drm/i915/display/intel_hdmi.c +0
-14-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",
drivers/gpu/drm/i915/display/intel_hdmi.c +0
-13- 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);
drivers/gpu/drm/i915/display/intel_hdmi.c +0
-2-if (ret) { - drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed(%d)\n",
drivers/gpu/drm/i915/display/intel_hdmi.c +0
-15- 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);drivers/gpu/drm/i915/display/intel_hdmi.c +0
-10-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,drivers/gpu/drm/i915/display/intel_hdmi.c +0
-9- 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),drivers/gpu/drm/i915/display/intel_hdmi.c +0
-3- part, DRM_HDCP_V_PRIME_PART_LEN); -if (ret) - drm_dbg_kms(&i915->drm, "Read V'[%d] over DDC failed(%d)\n",
drivers/gpu/drm/i915/display/intel_hdmi.c +0
-4- i, ret); -return ret; -} - static int kbl_repositioning_enc_en_signal(struct intel_connector*connector,
drivers/gpu/drm/i915/display/intel_hdmi.c +7
-15enum transcoder cpu_transcoder) {@@ -1532,50 +1425,40 @@ int intel_hdmi_hdcp_toggle_signalling(structintel_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)) &drivers/gpu/drm/i915/display/intel_hdmi.c +0
-4- (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,drivers/gpu/drm/i915/display/intel_hdmi.c +2
-7- 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)
{drivers/gpu/drm/i915/display/intel_hdmi.c +1
-2-struct drm_i915_private *i915 =to_i915 (dig_port->base.base.dev); -int retry; + struct intel_connector *connector =
to_intel_connector(drm_connector);drivers/gpu/drm/i915/display/intel_hdmi.c +3
-0+struct intel_digital_port *dig_port = +intel_attached_dig_port (connector); + enum transcoder cpu_transcoder = connector-Quoted 1 line
hdcp.cpu_transcoder;
drivers/gpu/drm/i915/display/intel_hdmi.c +12
-8+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(structintel_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 ];drivers/gpu/drm/i915/display/intel_hdmi.c +9
-3int ret;@@ -1741,13 +1623,19 @@ int intel_hdmi_hdcp2_check_link(structintel_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; +drivers/gpu/drm/i915/display/intel_hdmi.c +0
-0*capable = false; ret = intel_hdmi_hdcp_read(dig_port,
HDCP_2_2_HDMI_REG_VER_OFFSET,drivers/gpu/drm/i915/display/intel_hdmi.c +18
-11&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)
{drivers/gpu/drm/i915/display/intel_hdmi.c +31
-0struct 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,drivers/gpu/drm/i915/display/intel_hdmi.c +1
-7struct intel_connector *intel_connector) {@@ -2975,13 +2901,7 @@ void intel_hdmi_init_connector(structintel_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