On 2025-08-07 15:12, Harry Wentland wrote:
> On 2025-07-23 11:58, Timur Kristóf wrote:
>> Analog displays typically have a DDC connection which can be
>> used by the GPU to read EDID. This commit adds the capability
>> to probe analog displays using DDC, reading the EDID header and
>> deciding whether the analog link is connected based on the data
>> that was read.
>>
>> As a reference, I used the following functions:
>> amdgpu_connector_vga_detect
>> amdgpu_display_ddc_probe
>>
>> DAC load detection will be implemented in a separate commit.
> 
> Another regression in our internal testing with this patch, unfortunately
> only on not-yet released HW.
> 

While this shows on unreleased HW I wouldn't be surprised if it
repros on other (recent-ish) APUs (integrated GPUs). It's just
that this week's test was on currently unreleased HW.

Harry

> I wonder if pipe-ctx->stream could be NULL in some cases.
> 
> Harry
> 
>>
>> Signed-off-by: Timur Kristóf <[email protected]>
>> ---
>>  .../amd/display/dc/link/hwss/link_hwss_dio.c  | 16 ++--
>>  .../drm/amd/display/dc/link/link_detection.c  | 80 ++++++++++++++++++-
>>  .../gpu/drm/amd/display/dc/link/link_dpms.c   |  3 +
>>  .../drm/amd/display/dc/link/link_factory.c    |  3 +
>>  4 files changed, 95 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c 
>> b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c
>> index f3470716734d..b9ebb992dc98 100644
>> --- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c
>> +++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c
>> @@ -58,8 +58,9 @@ void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
>>              return;
>>      }
>>  
>> -    link_enc->funcs->connect_dig_be_to_fe(link_enc,
>> -                    pipe_ctx->stream_res.stream_enc->id, true);
>> +    if (!dc_is_rgb_signal(pipe_ctx->stream->signal))
>> +            link_enc->funcs->connect_dig_be_to_fe(link_enc,
>> +                            pipe_ctx->stream_res.stream_enc->id, true);
>>      if (dc_is_dp_signal(pipe_ctx->stream->signal))
>>              
>> pipe_ctx->stream->ctx->dc->link_srv->dp_trace_source_sequence(pipe_ctx->stream->link,
>>                              DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
>> @@ -98,10 +99,13 @@ void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
>>      if (stream_enc->funcs->enable_stream)
>>              stream_enc->funcs->enable_stream(stream_enc,
>>                              pipe_ctx->stream->signal, false);
>> -    link_enc->funcs->connect_dig_be_to_fe(
>> -                    link_enc,
>> -                    pipe_ctx->stream_res.stream_enc->id,
>> -                    false);
>> +
>> +    if (!dc_is_rgb_signal(pipe_ctx->stream->signal))
>> +            link_enc->funcs->connect_dig_be_to_fe(
>> +                            link_enc,
>> +                            pipe_ctx->stream_res.stream_enc->id,
>> +                            false);
>> +
>>      if (dc_is_dp_signal(pipe_ctx->stream->signal))
>>              pipe_ctx->stream->ctx->dc->link_srv->dp_trace_source_sequence(
>>                              pipe_ctx->stream->link,
>> diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c 
>> b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
>> index 827b630daf49..fcabc83464af 100644
>> --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c
>> +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
>> @@ -942,6 +942,12 @@ static bool detect_link_and_local_sink(struct dc_link 
>> *link,
>>                      break;
>>              }
>>  
>> +            case SIGNAL_TYPE_RGB: {
>> +                    sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
>> +                    sink_caps.signal = SIGNAL_TYPE_RGB;
>> +                    break;
>> +            }
>> +
>>              case SIGNAL_TYPE_LVDS: {
>>                      sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
>>                      sink_caps.signal = SIGNAL_TYPE_LVDS;
>> @@ -1133,9 +1139,17 @@ static bool detect_link_and_local_sink(struct dc_link 
>> *link,
>>                              sink = prev_sink;
>>                              prev_sink = NULL;
>>                      }
>> -                    query_hdcp_capability(sink->sink_signal, link);
>> +
>> +                    if (!sink->edid_caps.analog)
>> +                            query_hdcp_capability(sink->sink_signal, link);
>>              }
>>  
>> +            /* DVI-I connector connected to analog display. */
>> +            if ((link->link_enc->connector.id == 
>> CONNECTOR_ID_DUAL_LINK_DVII ||
>> +                 link->link_enc->connector.id == 
>> CONNECTOR_ID_SINGLE_LINK_DVII) &&
>> +                    sink->edid_caps.analog)
>> +                    sink->sink_signal = SIGNAL_TYPE_RGB;
>> +
>>              /* HDMI-DVI Dongle */
>>              if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A &&
>>                  !sink->edid_caps.edid_hdmi)
>> @@ -1228,6 +1242,64 @@ static bool detect_link_and_local_sink(struct dc_link 
>> *link,
>>      return true;
>>  }
>>  
>> +/**
>> + * Evaluates whether an EDID header is acceptable,
>> + * for the purpose of determining a connection with a display.
>> + */
>> +static bool link_detect_evaluate_edid_header(uint8_t edid_header[8])
>> +{
>> +    int edid_header_score = 0;
>> +    int i;
>> +
>> +    for (i = 0; i < 8; ++i)
>> +            edid_header_score += edid_header[i] == ((i == 0 || i == 7) ? 
>> 0x00 : 0xff);
>> +
>> +    return edid_header_score >= 6;
>> +}
>> +
>> +/**
>> + * Tries to detect a connected display by probing the DDC
>> + * and reading the EDID header.
>> + * The probing is considered successful if we receive a
>> + * reply from the DDC over I2C and the EDID header matches.
>> + */
>> +static bool link_detect_ddc_probe(struct dc_link *link)
>> +{
>> +    if (!link->ddc)
>> +            return false;
>> +
>> +    uint8_t edid_header[8] = {0};
>> +    bool ddc_probed = i2c_read(link->ddc, 0x50, edid_header, 
>> sizeof(edid_header));
>> +
>> +    if (!ddc_probed)
>> +            return false;
>> +
>> +    if (!link_detect_evaluate_edid_header(edid_header))
>> +            return false;
>> +
>> +    return true;
>> +}
>> +
>> +/**
>> + * Determines if there is an analog sink connected.
>> + */
>> +static bool link_detect_analog(struct dc_link *link, enum 
>> dc_connection_type *type)
>> +{
>> +    /* Don't care about connectors that don't support an analog signal. */
>> +    if (link->link_enc->connector.id != CONNECTOR_ID_VGA &&
>> +            link->link_enc->connector.id != CONNECTOR_ID_SINGLE_LINK_DVII &&
>> +            link->link_enc->connector.id != CONNECTOR_ID_DUAL_LINK_DVII)
>> +            return false;
>> +
>> +    if (link_detect_ddc_probe(link)) {
>> +            *type = dc_connection_single;
>> +            return true;
>> +    }
>> +
>> +    *type = dc_connection_none;
>> +    return true;
>> +}
>> +
>>  /*
>>   * link_detect_connection_type() - Determine if there is a sink connected
>>   *
>> @@ -1238,6 +1310,7 @@ static bool detect_link_and_local_sink(struct dc_link 
>> *link,
>>  bool link_detect_connection_type(struct dc_link *link, enum 
>> dc_connection_type *type)
>>  {
>>      uint32_t is_hpd_high = 0;
>> +    bool supports_hpd = link->irq_source_hpd != DC_IRQ_SOURCE_INVALID;
>>  
>>      if (link->connector_signal == SIGNAL_TYPE_LVDS) {
>>              *type = dc_connection_single;
>> @@ -1261,6 +1334,8 @@ bool link_detect_connection_type(struct dc_link *link, 
>> enum dc_connection_type *
>>              return true;
>>      }
>>  
>> +    if (!supports_hpd)
>> +            return link_detect_analog(link, type);
>>  
>>      if (!query_hpd_status(link, &is_hpd_high))
>>              goto hpd_gpio_failure;
>> @@ -1269,6 +1344,9 @@ bool link_detect_connection_type(struct dc_link *link, 
>> enum dc_connection_type *
>>              *type = dc_connection_single;
>>              /* TODO: need to do the actual detection */
>>      } else {
>> +            if (link_detect_analog(link, type))
>> +                    return true;
>> +
>>              *type = dc_connection_none;
>>              if (link->connector_signal == SIGNAL_TYPE_EDP) {
>>                      /* eDP is not connected, power down it */
>> diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c 
>> b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
>> index d6b7347c6c11..ac25d89a4148 100644
>> --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
>> +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
>> @@ -2256,6 +2256,9 @@ static enum dc_status enable_link(
>>              enable_link_lvds(pipe_ctx);
>>              status = DC_OK;
>>              break;
>> +    case SIGNAL_TYPE_RGB:
>> +            status = DC_OK;
>> +            break;
>>      case SIGNAL_TYPE_VIRTUAL:
>>              status = enable_link_virtual(pipe_ctx);
>>              break;
>> diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c 
>> b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
>> index 71c10a1261b9..c9725fd316f6 100644
>> --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c
>> +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
>> @@ -555,6 +555,9 @@ static bool construct_phy(struct dc_link *link,
>>      case CONNECTOR_ID_DUAL_LINK_DVII:
>>              link->connector_signal = SIGNAL_TYPE_DVI_DUAL_LINK;
>>              break;
>> +    case CONNECTOR_ID_VGA:
>> +            link->connector_signal = SIGNAL_TYPE_RGB;
>> +            break;
>>      case CONNECTOR_ID_DISPLAY_PORT:
>>      case CONNECTOR_ID_MXM:
>>      case CONNECTOR_ID_USBC:
> 

Reply via email to