Skip to content

Commit fbbdadf

Browse files
Bhawanpreet Lakhaalexdeucher
authored andcommitted
drm/amd/display: Fix Edid emulation for linux
[Why] EDID emulation didn't work properly for linux, as we stop programming if nothing is connected physically. [How] We get a flag from DRM when we want to do edid emulation. We check if this flag is true and nothing is connected physically, if so we only program the front end using VIRTUAL_SIGNAL. Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1 parent 599760d commit fbbdadf

File tree

3 files changed

+137
-7
lines changed

3 files changed

+137
-7
lines changed

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

Lines changed: 134 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,87 @@ amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
641641
return NULL;
642642
}
643643

644+
static void emulated_link_detect(struct dc_link *link)
645+
{
646+
struct dc_sink_init_data sink_init_data = { 0 };
647+
struct display_sink_capability sink_caps = { 0 };
648+
enum dc_edid_status edid_status;
649+
struct dc_context *dc_ctx = link->ctx;
650+
struct dc_sink *sink = NULL;
651+
struct dc_sink *prev_sink = NULL;
652+
653+
link->type = dc_connection_none;
654+
prev_sink = link->local_sink;
655+
656+
if (prev_sink != NULL)
657+
dc_sink_retain(prev_sink);
658+
659+
switch (link->connector_signal) {
660+
case SIGNAL_TYPE_HDMI_TYPE_A: {
661+
sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
662+
sink_caps.signal = SIGNAL_TYPE_HDMI_TYPE_A;
663+
break;
664+
}
665+
666+
case SIGNAL_TYPE_DVI_SINGLE_LINK: {
667+
sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
668+
sink_caps.signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
669+
break;
670+
}
671+
672+
case SIGNAL_TYPE_DVI_DUAL_LINK: {
673+
sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
674+
sink_caps.signal = SIGNAL_TYPE_DVI_DUAL_LINK;
675+
break;
676+
}
677+
678+
case SIGNAL_TYPE_LVDS: {
679+
sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
680+
sink_caps.signal = SIGNAL_TYPE_LVDS;
681+
break;
682+
}
683+
684+
case SIGNAL_TYPE_EDP: {
685+
sink_caps.transaction_type =
686+
DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
687+
sink_caps.signal = SIGNAL_TYPE_EDP;
688+
break;
689+
}
690+
691+
case SIGNAL_TYPE_DISPLAY_PORT: {
692+
sink_caps.transaction_type =
693+
DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
694+
sink_caps.signal = SIGNAL_TYPE_VIRTUAL;
695+
break;
696+
}
697+
698+
default:
699+
DC_ERROR("Invalid connector type! signal:%d\n",
700+
link->connector_signal);
701+
return;
702+
}
703+
704+
sink_init_data.link = link;
705+
sink_init_data.sink_signal = sink_caps.signal;
706+
707+
sink = dc_sink_create(&sink_init_data);
708+
if (!sink) {
709+
DC_ERROR("Failed to create sink!\n");
710+
return;
711+
}
712+
713+
link->local_sink = sink;
714+
715+
edid_status = dm_helpers_read_local_edid(
716+
link->ctx,
717+
link,
718+
sink);
719+
720+
if (edid_status != EDID_OK)
721+
DC_ERROR("Failed to read EDID");
722+
723+
}
724+
644725
static int dm_resume(void *handle)
645726
{
646727
struct amdgpu_device *adev = handle;
@@ -654,6 +735,7 @@ static int dm_resume(void *handle)
654735
struct drm_plane *plane;
655736
struct drm_plane_state *new_plane_state;
656737
struct dm_plane_state *dm_new_plane_state;
738+
enum dc_connection_type new_connection_type = dc_connection_none;
657739
int ret;
658740
int i;
659741

@@ -684,7 +766,13 @@ static int dm_resume(void *handle)
684766
continue;
685767

686768
mutex_lock(&aconnector->hpd_lock);
687-
dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
769+
if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
770+
DRM_ERROR("KMS: Failed to detect connector\n");
771+
772+
if (aconnector->base.force && new_connection_type == dc_connection_none)
773+
emulated_link_detect(aconnector->dc_link);
774+
else
775+
dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
688776

689777
if (aconnector->fake_enable && aconnector->dc_link->local_sink)
690778
aconnector->fake_enable = false;
@@ -922,6 +1010,7 @@ static void handle_hpd_irq(void *param)
9221010
struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param;
9231011
struct drm_connector *connector = &aconnector->base;
9241012
struct drm_device *dev = connector->dev;
1013+
enum dc_connection_type new_connection_type = dc_connection_none;
9251014

9261015
/* In case of failure or MST no need to update connector status or notify the OS
9271016
* since (for MST case) MST does this in it's own context.
@@ -931,7 +1020,21 @@ static void handle_hpd_irq(void *param)
9311020
if (aconnector->fake_enable)
9321021
aconnector->fake_enable = false;
9331022

934-
if (dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD)) {
1023+
if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
1024+
DRM_ERROR("KMS: Failed to detect connector\n");
1025+
1026+
if (aconnector->base.force && new_connection_type == dc_connection_none) {
1027+
emulated_link_detect(aconnector->dc_link);
1028+
1029+
1030+
drm_modeset_lock_all(dev);
1031+
dm_restore_drm_connector_state(dev, connector);
1032+
drm_modeset_unlock_all(dev);
1033+
1034+
if (aconnector->base.force == DRM_FORCE_UNSPECIFIED)
1035+
drm_kms_helper_hotplug_event(dev);
1036+
1037+
} else if (dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD)) {
9351038
amdgpu_dm_update_connector_after_detect(aconnector);
9361039

9371040

@@ -1031,6 +1134,7 @@ static void handle_hpd_rx_irq(void *param)
10311134
struct drm_device *dev = connector->dev;
10321135
struct dc_link *dc_link = aconnector->dc_link;
10331136
bool is_mst_root_connector = aconnector->mst_mgr.mst_state;
1137+
enum dc_connection_type new_connection_type = dc_connection_none;
10341138

10351139
/* TODO:Temporary add mutex to protect hpd interrupt not have a gpio
10361140
* conflict, after implement i2c helper, this mutex should be
@@ -1042,7 +1146,24 @@ static void handle_hpd_rx_irq(void *param)
10421146
if (dc_link_handle_hpd_rx_irq(dc_link, NULL, NULL) &&
10431147
!is_mst_root_connector) {
10441148
/* Downstream Port status changed. */
1045-
if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) {
1149+
if (!dc_link_detect_sink(dc_link, &new_connection_type))
1150+
DRM_ERROR("KMS: Failed to detect connector\n");
1151+
1152+
if (aconnector->base.force && new_connection_type == dc_connection_none) {
1153+
emulated_link_detect(dc_link);
1154+
1155+
if (aconnector->fake_enable)
1156+
aconnector->fake_enable = false;
1157+
1158+
amdgpu_dm_update_connector_after_detect(aconnector);
1159+
1160+
1161+
drm_modeset_lock_all(dev);
1162+
dm_restore_drm_connector_state(dev, connector);
1163+
drm_modeset_unlock_all(dev);
1164+
1165+
drm_kms_helper_hotplug_event(dev);
1166+
} else if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) {
10461167

10471168
if (aconnector->fake_enable)
10481169
aconnector->fake_enable = false;
@@ -1433,6 +1554,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
14331554
struct amdgpu_mode_info *mode_info = &adev->mode_info;
14341555
uint32_t link_cnt;
14351556
int32_t total_overlay_planes, total_primary_planes;
1557+
enum dc_connection_type new_connection_type = dc_connection_none;
14361558

14371559
link_cnt = dm->dc->caps.max_links;
14381560
if (amdgpu_dm_mode_config_init(dm->adev)) {
@@ -1499,7 +1621,14 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
14991621

15001622
link = dc_get_link_at_index(dm->dc, i);
15011623

1502-
if (dc_link_detect(link, DETECT_REASON_BOOT)) {
1624+
if (!dc_link_detect_sink(link, &new_connection_type))
1625+
DRM_ERROR("KMS: Failed to detect connector\n");
1626+
1627+
if (aconnector->base.force && new_connection_type == dc_connection_none) {
1628+
emulated_link_detect(link);
1629+
amdgpu_dm_update_connector_after_detect(aconnector);
1630+
1631+
} else if (dc_link_detect(link, DETECT_REASON_BOOT)) {
15031632
amdgpu_dm_update_connector_after_detect(aconnector);
15041633
register_backlight_device(dm, link);
15051634
}
@@ -2494,7 +2623,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
24942623
if (dm_state && dm_state->freesync_capable)
24952624
stream->ignore_msa_timing_param = true;
24962625
finish:
2497-
if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL)
2626+
if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL && aconnector->base.force != DRM_FORCE_ON)
24982627
dc_sink_release(sink);
24992628

25002629
return stream;

drivers/gpu/drm/amd/display/dc/core/dc_link.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ static bool program_hpd_filter(
195195
return result;
196196
}
197197

198-
static bool detect_sink(struct dc_link *link, enum dc_connection_type *type)
198+
bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type)
199199
{
200200
uint32_t is_hpd_high = 0;
201201
struct gpio *hpd_pin;
@@ -604,7 +604,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
604604
if (link->connector_signal == SIGNAL_TYPE_VIRTUAL)
605605
return false;
606606

607-
if (false == detect_sink(link, &new_connection_type)) {
607+
if (false == dc_link_detect_sink(link, &new_connection_type)) {
608608
BREAK_TO_DEBUGGER();
609609
return false;
610610
}

drivers/gpu/drm/amd/display/dc/dc_link.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ void dc_link_enable_hpd_filter(struct dc_link *link, bool enable);
215215

216216
bool dc_link_is_dp_sink_present(struct dc_link *link);
217217

218+
bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type);
218219
/*
219220
* DPCD access interfaces
220221
*/

0 commit comments

Comments
 (0)