From: Wayne Lin <[email protected]>

If sink like HDMI indicates supporting freesync via MCCS,
explicitly to send vcp set command on sink to enable freesync.

Reviewed-by: Harry Wentland <[email protected]>
Signed-off-by: Wayne Lin <[email protected]>
Signed-off-by: Roman Li <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  2 +
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 74 +++++++++++++++++++
 drivers/gpu/drm/amd/display/dc/dm_helpers.h   |  5 ++
 3 files changed, 81 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index ceef9b6e1599..07612463455a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -13379,6 +13379,8 @@ void amdgpu_dm_update_freesync_caps(struct 
drm_connector *connector,
                (!sink->edid_caps.freesync_vcp_code ||
                (sink->edid_caps.freesync_vcp_code && 
!sink->mccs_caps.freesync_supported)))
                freesync_capable = false;
+       if (sink->mccs_caps.freesync_supported && freesync_capable)
+               dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, 
amdgpu_dm_connector->dc_link, sink);
 
 update:
        if (dm_con_state)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 0146e894a15a..c53230cdfdc5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -1606,3 +1606,77 @@ void dm_helpers_read_mccs_caps(struct dc_context *ctx, 
struct dc_link *link,
        }
 }
 
+static int mccs_operation_vcp_set(unsigned int vcp_code, struct dc_link *link, 
uint16_t value)
+{
+       const unsigned char retry_interval_ms = 40;
+       unsigned char retry = 5;
+       struct amdgpu_dm_connector *aconnector = link->priv;
+       struct i2c_adapter *ddc;
+       struct i2c_msg msg = {0};
+       int ret = 0;
+       int idx;
+
+       unsigned char wr_data[MCCS_OP_BUFF_SIZE_WR_VCP_SET] = {
+               MCCS_SRC_ADDR,                          /* Byte0 - Src Addr */
+               MCCS_LENGTH_OFFSET + 4,         /* Byte1 - Length */
+               MCCS_OP_CODE_VCP_SET,           /* Byte2 - MCCS Command */
+               (unsigned char)vcp_code,        /* Byte3 - VCP Code */
+               (unsigned char)(value >> 8),    /* Byte4 - Value High Byte */
+               (unsigned char)(value & 0xFF),  /* Byte5 - Value Low Byte */
+               MCCS_DEST_ADDR << 1             /* Byte6 - CheckSum */
+       };
+
+       /* calculate checksum */
+       for (idx = 0; idx < (MCCS_OP_BUFF_SIZE_WR_VCP_SET - 1); idx++)
+               wr_data[MCCS_OP_BUFF_SIZE_WR_VCP_SET - 1] ^= wr_data[idx];
+
+       if (link->aux_mode)
+               ddc = &aconnector->dm_dp_aux.aux.ddc;
+       else
+               ddc = &aconnector->i2c->base;
+
+       do {
+               msg.addr = MCCS_DEST_ADDR;
+               msg.flags = 0;
+               msg.len = MCCS_OP_BUFF_SIZE_WR_VCP_SET;
+               msg.buf = wr_data;
+
+               ret = i2c_transfer(ddc, &msg, 1);
+               if (ret == 1)
+                       break;
+
+               retry--;
+               msleep(retry_interval_ms);
+       } while (retry);
+
+       if (!retry)
+               return -EIO;
+
+       return 0;
+}
+
+void dm_helpers_mccs_vcp_set(struct dc_context *ctx, struct dc_link *link,
+               struct dc_sink *sink)
+{
+       struct drm_device *dev;
+       const uint16_t enable = 0x0101;
+
+       if (!ctx)
+               return;
+       dev = adev_to_drm(ctx->driver_context);
+
+       if (!link || !sink) {
+               drm_dbg_driver(dev, "%s: link or sink is NULL", __func__);
+               return;
+       }
+
+       if (!sink->mccs_caps.freesync_supported) {
+               drm_dbg_driver(dev, "%s: MCCS freesync not supported on this 
sink", __func__);
+               return;
+       }
+
+       if (mccs_operation_vcp_set(sink->edid_caps.freesync_vcp_code, link, 
enable))
+               drm_dbg_driver(dev, "%s: Failed to set VCP code %d", __func__,
+                               sink->edid_caps.freesync_vcp_code);
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h 
b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index 3aa2b11f559b..107aec6a1265 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -186,6 +186,11 @@ void dm_helpers_read_mccs_caps(
                struct dc_link *link,
                struct dc_sink *sink);
 
+void dm_helpers_mccs_vcp_set(
+               struct dc_context *ctx,
+               struct dc_link *link,
+               struct dc_sink *sink);
+
 bool dm_helpers_dp_handle_test_pattern_request(
                struct dc_context *ctx,
                const struct dc_link *link,
-- 
2.34.1

Reply via email to