Adopt the DRM core DisplayPort helpers by setting DRM_BRIDGE_OP_DP and
populating the bridge dp_link_caps at probe time. Report the sink
capabilities on hotplug, reset them on disconnect, and report the link
parameters once link training succeeds.

Signed-off-by: Kory Maincent <[email protected]>
---
Change in v3:
- New patch
---
 drivers/gpu/drm/bridge/analogix/anx7625.c | 68 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/bridge/analogix/anx7625.h |  1 +
 2 files changed, 69 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index c3af88e14f8b2..2b1235efc9fa4 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -2558,6 +2558,31 @@ static int anx7625_bridge_atomic_check(struct drm_bridge 
*bridge,
        return 0;
 }
 
+static void anx7625_report_link_train(struct anx7625_data *ctx,
+                                     struct drm_connector *connector)
+{
+       int bw_code, rate, nlanes;
+
+       /*
+        * The DP link training is handled by the internal OCM firmware, read
+        * back the negotiated link rate and lane count.
+        */
+       bw_code = anx7625_reg_read(ctx, ctx->i2c.tx_p0_client,
+                                  SP_TX_LINK_BW_SET_REG);
+       if (bw_code < 0)
+               return;
+
+       rate = drm_dp_bw_code_to_link_rate(bw_code & SP_TX_LINK_BW_SET_MASK);
+
+       nlanes = anx7625_reg_read(ctx, ctx->i2c.tx_p0_client,
+                                 SP_TX_LANE_COUNT_SET_REG);
+       if (nlanes < 0)
+               return;
+       nlanes &= DP_MAX_LANE_COUNT_MASK;
+
+       drm_dp_set_cur_link_params(connector, rate, nlanes, false);
+}
+
 static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge,
                                         struct drm_atomic_commit *state)
 {
@@ -2565,6 +2590,7 @@ static void anx7625_bridge_atomic_enable(struct 
drm_bridge *bridge,
        struct device *dev = ctx->dev;
        struct drm_connector *connector;
        struct drm_connector_state *conn_state;
+       int ret;
 
        dev_dbg(dev, "drm atomic enable\n");
 
@@ -2580,6 +2606,17 @@ static void anx7625_bridge_atomic_enable(struct 
drm_bridge *bridge,
 
        anx7625_dp_start(ctx);
 
+       /* On DisplayPort case, the caps are set in the detect callback. */
+       if (bridge->type == DRM_MODE_CONNECTOR_eDP) {
+               ret = drm_dp_sink_sync_caps(connector, &ctx->aux, NULL);
+               if (ret)
+                       DRM_DEV_DEBUG_DRIVER(dev,
+                                            "error sink caps synchronisation 
(%d)\n",
+                                            ret);
+       }
+
+       anx7625_report_link_train(ctx, connector);
+
        conn_state = drm_atomic_get_new_connector_state(state, connector);
 
        if (WARN_ON(!conn_state))
@@ -2616,6 +2653,12 @@ static void anx7625_bridge_atomic_disable(struct 
drm_bridge *bridge,
                dev_dbg(dev, "update CP to DESIRE\n");
        }
 
+       /* On DisplayPort unplug, the caps are already reset in the detect
+        * callback.
+        */
+       if (bridge->type == DRM_MODE_CONNECTOR_eDP)
+               drm_dp_sink_reset_caps(ctx->connector);
+
        ctx->connector = NULL;
        anx7625_dp_stop(ctx);
 
@@ -2634,11 +2677,25 @@ anx7625_bridge_detect(struct drm_bridge *bridge, struct 
drm_connector *connector
        struct anx7625_data *ctx = bridge_to_anx7625(bridge);
        struct device *dev = ctx->dev;
        enum drm_connector_status status;
+       int ret;
 
        DRM_DEV_DEBUG_DRIVER(dev, "drm bridge detect\n");
 
        status = anx7625_sink_detect(ctx);
        anx7625_audio_update_connector_status(ctx, status);
+
+       if (status == connector_status_connected) {
+               ret = drm_dp_sink_sync_caps(connector, &ctx->aux, NULL);
+               if (ret)
+                       DRM_DEV_DEBUG_DRIVER(dev,
+                                            "error sink caps synchronisation 
(%d)\n",
+                                            ret);
+
+               anx7625_report_link_train(ctx, connector);
+       } else {
+               drm_dp_sink_reset_caps(connector);
+       }
+
        return status;
 }
 
@@ -2765,6 +2822,14 @@ static const struct dev_pm_ops anx7625_pm_ops = {
                           anx7625_runtime_pm_resume, NULL)
 };
 
+static int anx7625_dp_rates[] = {162000, 270000, 540000, 675000};
+
+static struct drm_connector_dp_link_caps anx7625_dp_link_caps = {
+       .nlanes = 2,
+       .nlink_rates = ARRAY_SIZE(anx7625_dp_rates),
+       .link_rates = anx7625_dp_rates,
+};
+
 static int anx7625_link_bridge(struct drm_dp_aux *aux)
 {
        struct anx7625_data *platform = container_of(aux, struct anx7625_data, 
aux);
@@ -2787,6 +2852,9 @@ static int anx7625_link_bridge(struct drm_dp_aux *aux)
                                    DRM_MODE_CONNECTOR_DisplayPort;
        platform->bridge.support_hdcp = true;
 
+       platform->bridge.dp_link_caps = &anx7625_dp_link_caps;
+       platform->bridge.ops |= DRM_BRIDGE_OP_DP;
+
        drm_bridge_add(&platform->bridge);
 
        if (!platform->pdata.is_dpi) {
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h 
b/drivers/gpu/drm/bridge/analogix/anx7625.h
index 957d234ec07c8..b9a0f62f6398c 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.h
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.h
@@ -90,6 +90,7 @@
 #define HDCP2TX_FW_EN                  BIT(4)
 
 #define SP_TX_LINK_BW_SET_REG          0xA0
+#define SP_TX_LINK_BW_SET_MASK         0x1F
 #define SP_TX_LANE_COUNT_SET_REG       0xA1
 
 #define M_VID_0 0xC0

-- 
2.43.0

Reply via email to