drm/amd/display: Handle Content protection property changes
[Why] We need to manage the content protection property changes for different usecase, once cp is DESIRED we need to maintain the ENABLED/DESIRED status for different cases. [How] 1. Attach the content_protection property 2. HDCP enable (UNDESIRED -> DESIRED) call into the module with the correct parameters to start hdcp. Set cp to ENABLED 3. HDCP disable (ENABLED -> UNDESIRED) Call the module to disable hdcp. 3. Handle Special cases (Hotplug, S3, headless S3, DPMS) If already ENABLED: set to DESIRED on unplug/suspend/dpms, and disable hdcp Then on plugin/resume/dpms: enable HDCP Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
52704fcaf7
commit
0c8620d63d
@ -70,6 +70,7 @@
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/drm_audio_component.h>
|
||||
#include <drm/drm_hdcp.h>
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
|
||||
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
|
||||
@ -1475,6 +1476,11 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
|
||||
dc_sink_release(aconnector->dc_sink);
|
||||
aconnector->dc_sink = NULL;
|
||||
aconnector->edid = NULL;
|
||||
#ifdef CONFIG_DRM_AMD_DC_HDCP
|
||||
/* Set CP to DESIRED if it was ENABLED, so we can re-enable it again on hotplug */
|
||||
if (connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
|
||||
connector->state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
|
||||
#endif
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
@ -1489,6 +1495,9 @@ static void handle_hpd_irq(void *param)
|
||||
struct drm_connector *connector = &aconnector->base;
|
||||
struct drm_device *dev = connector->dev;
|
||||
enum dc_connection_type new_connection_type = dc_connection_none;
|
||||
#ifdef CONFIG_DRM_AMD_DC_HDCP
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In case of failure or MST no need to update connector status or notify the OS
|
||||
@ -1496,6 +1505,9 @@ static void handle_hpd_irq(void *param)
|
||||
*/
|
||||
mutex_lock(&aconnector->hpd_lock);
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_DC_HDCP
|
||||
hdcp_reset_display(adev->dm.hdcp_workqueue, aconnector->dc_link->link_index);
|
||||
#endif
|
||||
if (aconnector->fake_enable)
|
||||
aconnector->fake_enable = false;
|
||||
|
||||
@ -5124,6 +5136,9 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
|
||||
|
||||
drm_connector_attach_vrr_capable_property(
|
||||
&aconnector->base);
|
||||
#ifdef CONFIG_DRM_AMD_DC_HDCP
|
||||
drm_connector_attach_content_protection_property(&aconnector->base, false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -5366,6 +5381,63 @@ is_scaling_state_different(const struct dm_connector_state *dm_state,
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_DC_HDCP
|
||||
static bool is_content_protection_different(struct drm_connector_state *state,
|
||||
const struct drm_connector_state *old_state,
|
||||
const struct drm_connector *connector, struct hdcp_workqueue *hdcp_w)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
||||
/* CP is being re enabled, ignore this */
|
||||
if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
|
||||
state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
|
||||
state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* S3 resume case, since old state will always be 0 (UNDESIRED) and the restored state will be ENABLED */
|
||||
if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED &&
|
||||
state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
|
||||
state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
|
||||
|
||||
/* Check if something is connected/enabled, otherwise we start hdcp but nothing is connected/enabled
|
||||
* hot-plug, headless s3, dpms
|
||||
*/
|
||||
if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED && connector->dpms == DRM_MODE_DPMS_ON &&
|
||||
aconnector->dc_sink != NULL)
|
||||
return true;
|
||||
|
||||
if (old_state->content_protection == state->content_protection)
|
||||
return false;
|
||||
|
||||
if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void update_content_protection(struct drm_connector_state *state, const struct drm_connector *connector,
|
||||
struct hdcp_workqueue *hdcp_w)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
||||
if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
|
||||
hdcp_add_display(hdcp_w, aconnector->dc_link->link_index);
|
||||
|
||||
/*
|
||||
* TODO: ENABLED should be verified using psp, it is planned later.
|
||||
* Just set this to ENABLED for now
|
||||
*/
|
||||
state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
|
||||
hdcp_remove_display(hdcp_w, aconnector->dc_link->link_index, aconnector->base.index);
|
||||
|
||||
}
|
||||
#endif
|
||||
static void remove_stream(struct amdgpu_device *adev,
|
||||
struct amdgpu_crtc *acrtc,
|
||||
struct dc_stream_state *stream)
|
||||
@ -6290,6 +6362,30 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
acrtc->otg_inst = status->primary_otg_inst;
|
||||
}
|
||||
}
|
||||
#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);
|
||||
|
||||
new_crtc_state = NULL;
|
||||
|
||||
if (acrtc)
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
|
||||
|
||||
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
|
||||
|
||||
if (dm_new_crtc_state && dm_new_crtc_state->stream == NULL &&
|
||||
connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
|
||||
hdcp_reset_display(adev->dm.hdcp_workqueue, aconnector->dc_link->link_index);
|
||||
new_con_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_content_protection_different(new_con_state, old_con_state, connector, adev->dm.hdcp_workqueue))
|
||||
update_content_protection(new_con_state, connector, adev->dm.hdcp_workqueue);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Handle connector state changes */
|
||||
for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
|
||||
|
Loading…
Reference in New Issue
Block a user