mirror of
https://github.com/torvalds/linux.git
synced 2026-04-26 18:42:25 -04:00
drm/amd/display: add CEC notifier to amdgpu driver
This patch adds the cec_notifier feature to amdgpu driver. The changes will allow amdgpu driver code to notify EDID and HPD changes to an eventual CEC adapter. Signed-off-by: Kun Liu <Kun.Liu2@amd.com> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
@@ -97,6 +97,7 @@
|
||||
#include <drm/drm_audio_component.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
|
||||
#include <media/cec-notifier.h>
|
||||
#include <acpi/video.h>
|
||||
|
||||
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
|
||||
@@ -2751,6 +2752,48 @@ out_fail:
|
||||
mutex_unlock(&mgr->lock);
|
||||
}
|
||||
|
||||
void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector)
|
||||
{
|
||||
struct cec_notifier *n = aconnector->notifier;
|
||||
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
cec_notifier_phys_addr_invalidate(n);
|
||||
}
|
||||
|
||||
void hdmi_cec_set_edid(struct amdgpu_dm_connector *aconnector)
|
||||
{
|
||||
struct drm_connector *connector = &aconnector->base;
|
||||
struct cec_notifier *n = aconnector->notifier;
|
||||
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
cec_notifier_set_phys_addr(n,
|
||||
connector->display_info.source_physical_address);
|
||||
}
|
||||
|
||||
static void s3_handle_hdmi_cec(struct drm_device *ddev, bool suspend)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
|
||||
drm_connector_list_iter_begin(ddev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
continue;
|
||||
|
||||
aconnector = to_amdgpu_dm_connector(connector);
|
||||
if (suspend)
|
||||
hdmi_cec_unset_edid(aconnector);
|
||||
else
|
||||
hdmi_cec_set_edid(aconnector);
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
}
|
||||
|
||||
static void s3_handle_mst(struct drm_device *dev, bool suspend)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
@@ -3022,6 +3065,8 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
|
||||
if (IS_ERR(adev->dm.cached_state))
|
||||
return PTR_ERR(adev->dm.cached_state);
|
||||
|
||||
s3_handle_hdmi_cec(adev_to_drm(adev), true);
|
||||
|
||||
s3_handle_mst(adev_to_drm(adev), true);
|
||||
|
||||
amdgpu_dm_irq_suspend(adev);
|
||||
@@ -3294,6 +3339,8 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
|
||||
*/
|
||||
amdgpu_dm_irq_resume_early(adev);
|
||||
|
||||
s3_handle_hdmi_cec(ddev, false);
|
||||
|
||||
/* On resume we need to rewrite the MSTM control bits to enable MST*/
|
||||
s3_handle_mst(ddev, false);
|
||||
|
||||
@@ -3603,6 +3650,7 @@ void amdgpu_dm_update_connector_after_detect(
|
||||
dc_sink_retain(aconnector->dc_sink);
|
||||
if (sink->dc_edid.length == 0) {
|
||||
aconnector->drm_edid = NULL;
|
||||
hdmi_cec_unset_edid(aconnector);
|
||||
if (aconnector->dc_link->aux_mode) {
|
||||
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
|
||||
}
|
||||
@@ -3612,6 +3660,7 @@ void amdgpu_dm_update_connector_after_detect(
|
||||
aconnector->drm_edid = drm_edid_alloc(edid, sink->dc_edid.length);
|
||||
drm_edid_connector_update(connector, aconnector->drm_edid);
|
||||
|
||||
hdmi_cec_set_edid(aconnector);
|
||||
if (aconnector->dc_link->aux_mode)
|
||||
drm_dp_cec_attach(&aconnector->dm_dp_aux.aux,
|
||||
connector->display_info.source_physical_address);
|
||||
@@ -3628,6 +3677,7 @@ void amdgpu_dm_update_connector_after_detect(
|
||||
amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid);
|
||||
update_connector_ext_caps(aconnector);
|
||||
} else {
|
||||
hdmi_cec_unset_edid(aconnector);
|
||||
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
|
||||
amdgpu_dm_update_freesync_caps(connector, NULL);
|
||||
aconnector->num_modes = 0;
|
||||
@@ -7044,6 +7094,7 @@ static void amdgpu_dm_connector_unregister(struct drm_connector *connector)
|
||||
if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector))
|
||||
sysfs_remove_group(&connector->kdev->kobj, &amdgpu_group);
|
||||
|
||||
cec_notifier_conn_unregister(amdgpu_dm_connector->notifier);
|
||||
drm_dp_aux_unregister(&amdgpu_dm_connector->dm_dp_aux.aux);
|
||||
}
|
||||
|
||||
@@ -8280,6 +8331,27 @@ create_i2c(struct ddc_service *ddc_service,
|
||||
return i2c;
|
||||
}
|
||||
|
||||
int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector)
|
||||
{
|
||||
struct cec_connector_info conn_info;
|
||||
struct drm_device *ddev = aconnector->base.dev;
|
||||
struct device *hdmi_dev = ddev->dev;
|
||||
|
||||
if (amdgpu_dc_debug_mask & DC_DISABLE_HDMI_CEC) {
|
||||
drm_info(ddev, "HDMI-CEC feature masked\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cec_fill_conn_info_from_drm(&conn_info, &aconnector->base);
|
||||
aconnector->notifier =
|
||||
cec_notifier_conn_register(hdmi_dev, NULL, &conn_info);
|
||||
if (!aconnector->notifier) {
|
||||
drm_err(ddev, "Failed to create cec notifier\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: this function assumes that dc_link_detect() was called for the
|
||||
@@ -8343,6 +8415,10 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
|
||||
drm_connector_attach_encoder(
|
||||
&aconnector->base, &aencoder->base);
|
||||
|
||||
if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
|
||||
connector_type == DRM_MODE_CONNECTOR_HDMIB)
|
||||
amdgpu_dm_initialize_hdmi_connector(aconnector);
|
||||
|
||||
if (connector_type == DRM_MODE_CONNECTOR_DisplayPort
|
||||
|| connector_type == DRM_MODE_CONNECTOR_eDP)
|
||||
amdgpu_dm_initialize_dp_connector(dm, aconnector, link->link_index);
|
||||
|
||||
Reference in New Issue
Block a user