Commit e8fd3eeb authored by hersen wu's avatar hersen wu Committed by Alex Deucher

drm/amd/display: phase3 mst hdcp for multiple displays

[Why]
multiple display hdcp are enabled within event_property_validate,
event_property_update by looping all displays on mst hub. when
one of display on mst hub in unplugged or disabled, hdcp are
disabled for all displays on mst hub within hdcp_reset_display
by looping all displays of mst link. for displays still active,
their encryption status are off. kernel driver will not run hdcp
authentication again. therefore, hdcp are not enabled automatically.

[How]
within is_content_protection_different, check drm_crtc_state changes
of all displays on mst hub, if need, triger hdcp_update_display to
re-run hdcp authentication.
Acked-by: default avatarAurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: default avatarhersen wu <hersenxs.wu@amd.com>
Reviewed-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 0b04ea39
...@@ -7374,27 +7374,55 @@ is_scaling_state_different(const struct dm_connector_state *dm_state, ...@@ -7374,27 +7374,55 @@ is_scaling_state_different(const struct dm_connector_state *dm_state,
} }
#ifdef CONFIG_DRM_AMD_DC_HDCP #ifdef CONFIG_DRM_AMD_DC_HDCP
static bool is_content_protection_different(struct drm_connector_state *state, static bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
const struct drm_connector_state *old_state, struct drm_crtc_state *old_crtc_state,
const struct drm_connector *connector, struct hdcp_workqueue *hdcp_w) struct drm_connector_state *new_conn_state,
struct drm_connector_state *old_conn_state,
const struct drm_connector *connector,
struct hdcp_workqueue *hdcp_w)
{ {
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state); struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state);
/* Handle: Type0/1 change */ pr_debug("[HDCP_DM] connector->index: %x connect_status: %x dpms: %x\n",
if (old_state->hdcp_content_type != state->hdcp_content_type && connector->index, connector->status, connector->dpms);
state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { pr_debug("[HDCP_DM] state protection old: %x new: %x\n",
state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; old_conn_state->content_protection, new_conn_state->content_protection);
if (old_crtc_state)
pr_debug("[HDCP_DM] old crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n",
old_crtc_state->enable,
old_crtc_state->active,
old_crtc_state->mode_changed,
old_crtc_state->active_changed,
old_crtc_state->connectors_changed);
if (new_crtc_state)
pr_debug("[HDCP_DM] NEW crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n",
new_crtc_state->enable,
new_crtc_state->active,
new_crtc_state->mode_changed,
new_crtc_state->active_changed,
new_crtc_state->connectors_changed);
/* hdcp content type change */
if (old_conn_state->hdcp_content_type != new_conn_state->hdcp_content_type &&
new_conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
pr_debug("[HDCP_DM] Type0/1 change %s :true\n", __func__);
return true; return true;
} }
/* CP is being re enabled, ignore this /* CP is being re enabled, ignore this */
* if (old_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
* Handles: ENABLED -> DESIRED new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
*/ if (new_crtc_state && new_crtc_state->mode_changed) {
if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED && new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) { pr_debug("[HDCP_DM] ENABLED->DESIRED & mode_changed %s :true\n", __func__);
state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED; return true;
};
new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
pr_debug("[HDCP_DM] ENABLED -> DESIRED %s :false\n", __func__);
return false; return false;
} }
...@@ -7402,9 +7430,9 @@ static bool is_content_protection_different(struct drm_connector_state *state, ...@@ -7402,9 +7430,9 @@ static bool is_content_protection_different(struct drm_connector_state *state,
* *
* Handles: UNDESIRED -> ENABLED * Handles: UNDESIRED -> ENABLED
*/ */
if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED && if (old_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED &&
state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
/* Stream removed and re-enabled /* Stream removed and re-enabled
* *
...@@ -7414,10 +7442,12 @@ static bool is_content_protection_different(struct drm_connector_state *state, ...@@ -7414,10 +7442,12 @@ static bool is_content_protection_different(struct drm_connector_state *state,
* *
* Handles: DESIRED -> DESIRED (Special case) * Handles: DESIRED -> DESIRED (Special case)
*/ */
if (!(old_state->crtc && old_state->crtc->enabled) && if (!(old_conn_state->crtc && old_conn_state->crtc->enabled) &&
state->crtc && state->crtc->enabled && new_conn_state->crtc && new_conn_state->crtc->enabled &&
connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) { connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
dm_con_state->update_hdcp = false; dm_con_state->update_hdcp = false;
pr_debug("[HDCP_DM] DESIRED->DESIRED (Stream removed and re-enabled) %s :true\n",
__func__);
return true; return true;
} }
...@@ -7429,35 +7459,42 @@ static bool is_content_protection_different(struct drm_connector_state *state, ...@@ -7429,35 +7459,42 @@ static bool is_content_protection_different(struct drm_connector_state *state,
* *
* Handles: DESIRED -> DESIRED (Special case) * Handles: DESIRED -> DESIRED (Special case)
*/ */
if (dm_con_state->update_hdcp && state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED && if (dm_con_state->update_hdcp &&
new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
connector->dpms == DRM_MODE_DPMS_ON && aconnector->dc_sink != NULL) { connector->dpms == DRM_MODE_DPMS_ON && aconnector->dc_sink != NULL) {
dm_con_state->update_hdcp = false; dm_con_state->update_hdcp = false;
pr_debug("[HDCP_DM] DESIRED->DESIRED (Hot-plug, headless s3, dpms) %s :true\n",
__func__);
return true; return true;
} }
/* if (old_conn_state->content_protection == new_conn_state->content_protection) {
* Handles: UNDESIRED -> UNDESIRED if (new_conn_state->content_protection >= DRM_MODE_CONTENT_PROTECTION_DESIRED) {
* DESIRED -> DESIRED if (new_crtc_state && new_crtc_state->mode_changed) {
* ENABLED -> ENABLED pr_debug("[HDCP_DM] DESIRED->DESIRED or ENABLE->ENABLE mode_change %s :true\n",
*/ __func__);
if (old_state->content_protection == state->content_protection) return true;
};
pr_debug("[HDCP_DM] DESIRED->DESIRED & ENABLE->ENABLE %s :false\n",
__func__);
return false; return false;
};
/* pr_debug("[HDCP_DM] UNDESIRED->UNDESIRED %s :false\n", __func__);
* Handles: UNDESIRED -> DESIRED return false;
* DESIRED -> UNDESIRED }
* ENABLED -> UNDESIRED
*/ if (new_conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_ENABLED) {
if (state->content_protection != DRM_MODE_CONTENT_PROTECTION_ENABLED) pr_debug("[HDCP_DM] UNDESIRED->DESIRED or DESIRED->UNDESIRED or ENABLED->UNDESIRED %s :true\n",
__func__);
return true; return true;
}
/* pr_debug("[HDCP_DM] DESIRED->ENABLED %s :false\n", __func__);
* Handles: DESIRED -> ENABLED
*/
return false; return false;
} }
#endif #endif
static void remove_stream(struct amdgpu_device *adev, static void remove_stream(struct amdgpu_device *adev,
struct amdgpu_crtc *acrtc, struct amdgpu_crtc *acrtc,
struct dc_stream_state *stream) struct dc_stream_state *stream)
...@@ -8292,15 +8329,66 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -8292,15 +8329,66 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
} }
} }
#ifdef CONFIG_DRM_AMD_DC_HDCP #ifdef CONFIG_DRM_AMD_DC_HDCP
for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
pr_debug("[HDCP_DM] -------------- i : %x ----------\n", i);
if (!connector)
continue;
pr_debug("[HDCP_DM] connector->index: %x connect_status: %x dpms: %x\n",
connector->index, connector->status, connector->dpms);
pr_debug("[HDCP_DM] state protection old: %x new: %x\n",
old_con_state->content_protection, new_con_state->content_protection);
if (aconnector->dc_sink) {
if (aconnector->dc_sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
aconnector->dc_sink->sink_signal != SIGNAL_TYPE_NONE) {
pr_debug("[HDCP_DM] pipe_ctx dispname=%s\n",
aconnector->dc_sink->edid_caps.display_name);
}
}
new_crtc_state = NULL;
old_crtc_state = NULL;
if (acrtc) {
new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base);
}
if (old_crtc_state)
pr_debug("old crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n",
old_crtc_state->enable,
old_crtc_state->active,
old_crtc_state->mode_changed,
old_crtc_state->active_changed,
old_crtc_state->connectors_changed);
if (new_crtc_state)
pr_debug("NEW crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n",
new_crtc_state->enable,
new_crtc_state->active,
new_crtc_state->mode_changed,
new_crtc_state->active_changed,
new_crtc_state->connectors_changed);
}
for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state); struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
new_crtc_state = NULL; new_crtc_state = NULL;
old_crtc_state = NULL;
if (acrtc) if (acrtc) {
new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base); new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base);
}
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
...@@ -8312,7 +8400,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -8312,7 +8400,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
continue; continue;
} }
if (is_content_protection_different(new_con_state, old_con_state, connector, adev->dm.hdcp_workqueue)) { if (is_content_protection_different(new_crtc_state, old_crtc_state, new_con_state,
old_con_state, connector, adev->dm.hdcp_workqueue)) {
/* when display is unplugged from mst hub, connctor will /* when display is unplugged from mst hub, connctor will
* be destroyed within dm_dp_mst_connector_destroy. connector * be destroyed within dm_dp_mst_connector_destroy. connector
* hdcp perperties, like type, undesired, desired, enabled, * hdcp perperties, like type, undesired, desired, enabled,
...@@ -8322,6 +8411,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -8322,6 +8411,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
* will be retrieved from hdcp_work within dm_dp_mst_get_modes * will be retrieved from hdcp_work within dm_dp_mst_get_modes
*/ */
bool enable_encryption = false;
if (new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED)
enable_encryption = true;
if (aconnector->dc_link && aconnector->dc_sink && if (aconnector->dc_link && aconnector->dc_sink &&
aconnector->dc_link->type == dc_connection_mst_branch) { aconnector->dc_link->type == dc_connection_mst_branch) {
struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue; struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue;
...@@ -8334,10 +8428,15 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -8334,10 +8428,15 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
new_con_state->content_protection; new_con_state->content_protection;
} }
if (new_crtc_state && new_crtc_state->mode_changed &&
new_con_state->content_protection >= DRM_MODE_CONTENT_PROTECTION_DESIRED)
enable_encryption = true;
DRM_INFO("[HDCP_DM] hdcp_update_display enable_encryption = %x\n", enable_encryption);
hdcp_update_display( hdcp_update_display(
adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector, adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector,
new_con_state->hdcp_content_type, new_con_state->hdcp_content_type, enable_encryption);
new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED);
} }
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment