From: Przemyslaw Gaj <p...@cadence.com>

This patch enables FEC (Forward Error Correction) on Cadence DisplayPort
controller if it's supported by the Sink.

This patch is an addition to patch with mhdp8546 driver @
patchwork.kernel.org/cover/10632065/

Signed-off-by: Przemyslaw Gaj <p...@cadence.com>
Signed-off-by: Damian Kos <d...@cadence.com>
---
 drivers/gpu/drm/bridge/cdns-mhdp.c    | 138 ++++++++++++++++++++++++++
 drivers/gpu/drm/bridge/cdns-mhdp.h    |   4 +-
 include/drm/bridge/cdns-mhdp-common.h |   2 +
 3 files changed, 143 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/cdns-mhdp.c 
b/drivers/gpu/drm/bridge/cdns-mhdp.c
index caaf3c17d74f..3bfe1eda1468 100644
--- a/drivers/gpu/drm/bridge/cdns-mhdp.c
+++ b/drivers/gpu/drm/bridge/cdns-mhdp.c
@@ -392,6 +392,127 @@ static void mhdp_adjust_requested_eq(struct 
cdns_mhdp_device *mhdp,
        }
 }
 
+static int cdns_mhdp_wait_for_fec(struct cdns_mhdp_device *mhdp,
+                                 bool expected_status)
+{
+       u32 fec_status;
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       cdns_mhdp_reg_read(mhdp, CDNS_DP_FEC_STATUS, &fec_status);
+       while (((fec_status & CDNS_DP_FEC_BUSY) != expected_status) &&
+                time_before(jiffies, timeout)) {
+               cdns_mhdp_reg_read(mhdp, CDNS_DP_FEC_STATUS, &fec_status);
+               cpu_relax();
+       }
+
+       if (time_after_eq(jiffies, timeout)) {
+               DRM_DEV_ERROR(mhdp->dev, "Timeout while waiting for FEC\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int cdns_mhdp_fec_sink_support(struct cdns_mhdp_device *mhdp)
+{
+       int ret;
+       u16 dpcd_buffer;
+
+       ret = drm_dp_dpcd_read(&mhdp->aux, DP_FEC_CAPABILITY, &dpcd_buffer, 1);
+       if (ret)
+               return ret;
+
+       if (!(dpcd_buffer & DP_FEC_CAPABLE)) {
+               ret = -ENOTSUPP;
+               DRM_DEV_ERROR(mhdp->dev, "sink does not support FEC: %d\n",
+                             ret);
+               goto err;
+       }
+
+       ret = 0;
+
+err:
+       return ret;
+}
+
+static int cdns_mhdp_fec_sink_set_ready(struct cdns_mhdp_device *mhdp,
+                                       bool enable)
+{
+       int ret;
+       u16 dpcd_buffer;
+
+       ret = drm_dp_dpcd_read(&mhdp->aux, DP_FEC_CONFIGURATION,
+                              &dpcd_buffer, 1);
+       if (ret)
+               goto err;
+
+       if (enable)
+               dpcd_buffer |= DP_FEC_READY;
+       else
+               dpcd_buffer &= ~DP_FEC_READY;
+
+       ret = drm_dp_dpcd_write(&mhdp->aux, DP_FEC_CONFIGURATION,
+                               &dpcd_buffer, 1);
+       if (ret)
+               return 0;
+
+err:
+       DRM_DEV_ERROR(mhdp->dev, "cannot set sink FEC ready: %d\n", ret);
+       return -EIO;
+}
+
+static int cdns_mhdp_fec_set_ready(struct cdns_mhdp_device *mhdp, bool enable)
+{
+       int ret;
+
+       ret = cdns_mhdp_fec_sink_support(mhdp);
+       if (ret)
+               goto err;
+
+       ret = cdns_mhdp_fec_sink_set_ready(mhdp, enable);
+       if (ret)
+               goto err;
+
+       ret = cdns_mhdp_reg_write_bit(mhdp, CDNS_DP_FEC_CTRL, 1, 1, enable);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       return ret;
+}
+
+static int cdns_mhdp_fec_enable(struct cdns_mhdp_device *mhdp, bool enable)
+{
+       int ret;
+       u32 resp;
+       unsigned int dp_framer_global_config;
+
+       if (mhdp->fec_enabled == enable) {
+               ret = -EEXIST;
+               goto err;
+       }
+
+       ret = cdns_mhdp_reg_read(mhdp, DP_FRAMER_GLOBAL_CONFIG, &resp);
+       if (ret)
+               goto err;
+
+       dp_framer_global_config = be32_to_cpu(resp);
+       pr_err("0x%.8x\n", dp_framer_global_config);
+       if (!(dp_framer_global_config & CDNS_DP_NO_VIDEO_MODE)) {
+               ret = -EIO;
+               goto err;
+       }
+
+       ret = cdns_mhdp_reg_write_bit(mhdp, CDNS_DP_FEC_CTRL, 0, 1, enable);
+
+       return cdns_mhdp_wait_for_fec(mhdp, enable);
+err:
+       DRM_DEV_ERROR(mhdp->dev, "set fec enable failed: %d\n", ret);
+       return ret;
+}
+
+
 static bool mhdp_link_training_channel_eq(struct cdns_mhdp_device *mhdp,
                                          u8 eq_tps,
                                          unsigned int training_interval)
@@ -769,6 +890,13 @@ static int cdns_mhdp_link_up(struct cdns_mhdp_device *mhdp)
        amp[1] = DP_SET_ANSI_8B10B;
        drm_dp_dpcd_write(&mhdp->aux, DP_DOWNSPREAD_CTRL, amp, 2);
 
+       if (cdns_mhdp_fec_set_ready(mhdp, true)) {
+               mhdp->fec_enabled = false;
+               dev_info(mhdp->dev, "Cannot set FEC ready.\n");
+       } else {
+               mhdp->fec_enabled = true;
+       }
+
        if (mhdp->host.fast_link & mhdp->sink.fast_link) {
                /* FIXME: implement fastlink */
                dev_dbg(mhdp->dev, "fastlink\n");
@@ -807,6 +935,14 @@ static int cdns_mhdp_sst_enable(struct drm_bridge *bridge)
        pxlfmt = cdns_mhdp_get_pxlfmt(disp_info->color_formats);
        bpp = cdns_mhdp_get_bpp(disp_info->bpc, pxlfmt);
 
+       if (mhdp->fec_enabled && cdns_mhdp_fec_enable(mhdp, true)) {
+               mhdp->fec_enabled = false;
+               dev_info(mhdp->dev, "Cannot enable FEC.\n");
+       } else {
+               mhdp->fec_enabled = true;
+       }
+
+
        /* find optimal tu_size */
        required_bandwidth = pxlclock * bpp / 8;
        available_bandwidth = mhdp->link.num_lanes * rate;
@@ -814,6 +950,8 @@ static int cdns_mhdp_sst_enable(struct drm_bridge *bridge)
                tu_size += 2;
 
                vs_f = tu_size * required_bandwidth / available_bandwidth;
+               if (mhdp->fec_enabled)
+                       vs_f = (vs_f * 1024) / 1000; // 102.4 percent
                vs = vs_f / 1000;
                vs_f = vs_f % 1000;
                /*
diff --git a/drivers/gpu/drm/bridge/cdns-mhdp.h 
b/drivers/gpu/drm/bridge/cdns-mhdp.h
index abc1fa3f51a6..ba233adf9fe7 100644
--- a/drivers/gpu/drm/bridge/cdns-mhdp.h
+++ b/drivers/gpu/drm/bridge/cdns-mhdp.h
@@ -179,7 +179,9 @@
 #define CDNS_DP_LANE_EN                                (CDNS_DPTX_GLOBAL + 
0x00)
 #define CDNS_DP_LANE_EN_LANES(x)               GENMASK(x - 1, 0)
 #define CDNS_DP_ENHNCD                         (CDNS_DPTX_GLOBAL + 0x04)
-
+#define CDNS_DP_FEC_CTRL                       (CDNS_DPTX_GLOBAL + 0x10)
+#define CDNS_DP_FEC_STATUS                     (CDNS_DPTX_GLOBAL + 0x14)
+#define CDNS_DP_FEC_BUSY                       BIT(0)
 
 #define to_mhdp_connector(x) container_of(x, struct cdns_mhdp_connector, base)
 #define to_mhdp_bridge(x) container_of(x, struct cdns_mhdp_bridge, base)
diff --git a/include/drm/bridge/cdns-mhdp-common.h 
b/include/drm/bridge/cdns-mhdp-common.h
index 1e8a44138ce2..52feeca3a914 100644
--- a/include/drm/bridge/cdns-mhdp-common.h
+++ b/include/drm/bridge/cdns-mhdp-common.h
@@ -566,6 +566,8 @@ struct cdns_mhdp_device {
        bool can_mst;
        bool link_up;
        bool plugged;
+
+       bool fec_enabled;
 };
 
 void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to