]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/hisilicon/hibmc: Add dp serdes cfg in dp process
authorBaihan Li <libaihan@huawei.com>
Mon, 31 Mar 2025 07:42:06 +0000 (15:42 +0800)
committerDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Fri, 11 Apr 2025 11:40:00 +0000 (14:40 +0300)
Add dp serdes cfg in link training process, and related adapting
and modificating. Change some init values about training, because we want
completely to negotiation process, so we start with the maximum rate and
the electrical characteristic level is 0. Because serdes default cfgs is
changed and used in hibmc_kms_init(), we changed the if-statement to check
whether the value is 0.

Signed-off-by: Baihan Li <libaihan@huawei.com>
Signed-off-by: Yongbang Shi <shiyongbang@huawei.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20250331074212.3370287-4-shiyongbang@huawei.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h
drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c
drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c
drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c

index 74dd9956144e4e352d13879b0060333f0c6c5fae..c5feef8dc27d1883efd24c064c143dc446dd1da1 100644 (file)
@@ -15,5 +15,6 @@
 #define HIBMC_DP_CLK_EN                        0x7
 #define HIBMC_DP_SYNC_EN_MASK          0x3
 #define HIBMC_DP_LINK_RATE_CAL         27
+#define HIBMC_DP_SYNC_DELAY(lanes)     ((lanes) == 0x2 ? 86 : 46)
 
 #endif
index 3612f3c5ab231d4ada62fa2035a875885abdb2e0..dcb2ab5ea6bb80265b076e3a3bf28d7f68770c96 100644 (file)
@@ -72,6 +72,9 @@ static void hibmc_dp_set_sst(struct hibmc_dp_dev *dp, struct drm_display_mode *m
                                 HIBMC_DP_CFG_STREAM_HTOTAL_SIZE, htotal_size);
        hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_HORIZONTAL_SIZE,
                                 HIBMC_DP_CFG_STREAM_HBLANK_SIZE, hblank_size);
+       hibmc_dp_reg_write_field(dp, HIBMC_DP_VIDEO_PACKET,
+                                HIBMC_DP_CFG_STREAM_SYNC_CALIBRATION,
+                                HIBMC_DP_SYNC_DELAY(dp->link.cap.lanes));
 }
 
 static void hibmc_dp_link_cfg(struct hibmc_dp_dev *dp, struct drm_display_mode *mode)
@@ -171,7 +174,7 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp)
                return ret;
 
        dp_dev->link.cap.lanes = 0x2;
-       dp_dev->link.cap.link_rate = DP_LINK_BW_2_7;
+       dp_dev->link.cap.link_rate = DP_LINK_BW_8_1;
 
        /* hdcp data */
        writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG);
index a3b78b0fd53ef854a54edf40fb333766da88f1c6..61397852957156d15ab49d4192f07c530532b900 100644 (file)
@@ -9,6 +9,22 @@
 
 #define HIBMC_EQ_MAX_RETRY 5
 
+static inline int hibmc_dp_get_serdes_rate_cfg(struct hibmc_dp_dev *dp)
+{
+       switch (dp->link.cap.link_rate) {
+       case DP_LINK_BW_1_62:
+               return DP_SERDES_BW_1_62;
+       case DP_LINK_BW_2_7:
+               return DP_SERDES_BW_2_7;
+       case DP_LINK_BW_5_4:
+               return DP_SERDES_BW_5_4;
+       case DP_LINK_BW_8_1:
+               return DP_SERDES_BW_8_1;
+       default:
+               return -EINVAL;
+       }
+}
+
 static int hibmc_dp_link_training_configure(struct hibmc_dp_dev *dp)
 {
        u8 buf[2];
@@ -41,11 +57,7 @@ static int hibmc_dp_link_training_configure(struct hibmc_dp_dev *dp)
                return ret >= 0 ? -EIO : ret;
        }
 
-       ret = drm_dp_read_dpcd_caps(&dp->aux, dp->dpcd);
-       if (ret)
-               drm_err(dp->dev, "dp aux read dpcd failed, ret: %d\n", ret);
-
-       return ret;
+       return 0;
 }
 
 static int hibmc_dp_link_set_pattern(struct hibmc_dp_dev *dp, int pattern)
@@ -108,7 +120,11 @@ static int hibmc_dp_link_training_cr_pre(struct hibmc_dp_dev *dp)
                return ret;
 
        for (i = 0; i < dp->link.cap.lanes; i++)
-               train_set[i] = DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
+               train_set[i] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
+
+       ret = hibmc_dp_serdes_set_tx_cfg(dp, dp->link.train_set);
+       if (ret)
+               return ret;
 
        ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, train_set, dp->link.cap.lanes);
        if (ret != dp->link.cap.lanes) {
@@ -137,21 +153,29 @@ static bool hibmc_dp_link_get_adjust_train(struct hibmc_dp_dev *dp,
        return false;
 }
 
-static inline int hibmc_dp_link_reduce_rate(struct hibmc_dp_dev *dp)
+static int hibmc_dp_link_reduce_rate(struct hibmc_dp_dev *dp)
 {
+       int ret;
+
        switch (dp->link.cap.link_rate) {
        case DP_LINK_BW_2_7:
                dp->link.cap.link_rate = DP_LINK_BW_1_62;
-               return 0;
+               break;
        case DP_LINK_BW_5_4:
                dp->link.cap.link_rate = DP_LINK_BW_2_7;
-               return 0;
+               break;
        case DP_LINK_BW_8_1:
                dp->link.cap.link_rate = DP_LINK_BW_5_4;
-               return 0;
+               break;
        default:
                return -EINVAL;
        }
+
+       ret = hibmc_dp_get_serdes_rate_cfg(dp);
+       if (ret < 0)
+               return ret;
+
+       return hibmc_dp_serdes_rate_switch(ret, dp);
 }
 
 static inline int hibmc_dp_link_reduce_lane(struct hibmc_dp_dev *dp)
@@ -159,6 +183,7 @@ static inline int hibmc_dp_link_reduce_lane(struct hibmc_dp_dev *dp)
        switch (dp->link.cap.lanes) {
        case 0x2:
                dp->link.cap.lanes--;
+               drm_dbg_dp(dp->dev, "dp link training reduce to 1 lane\n");
                break;
        case 0x1:
                drm_err(dp->dev, "dp link training reduce lane failed, already reach minimum\n");
@@ -206,6 +231,11 @@ static int hibmc_dp_link_training_cr(struct hibmc_dp_dev *dp)
                }
 
                level_changed = hibmc_dp_link_get_adjust_train(dp, lane_status);
+
+               ret = hibmc_dp_serdes_set_tx_cfg(dp, dp->link.train_set);
+               if (ret)
+                       return ret;
+
                ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->link.train_set,
                                        dp->link.cap.lanes);
                if (ret != dp->link.cap.lanes) {
@@ -255,6 +285,11 @@ static int hibmc_dp_link_training_channel_eq(struct hibmc_dp_dev *dp)
                }
 
                hibmc_dp_link_get_adjust_train(dp, lane_status);
+
+               ret = hibmc_dp_serdes_set_tx_cfg(dp, dp->link.train_set);
+               if (ret)
+                       return ret;
+
                ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET,
                                        dp->link.train_set, dp->link.cap.lanes);
                if (ret != dp->link.cap.lanes) {
@@ -295,6 +330,21 @@ int hibmc_dp_link_training(struct hibmc_dp_dev *dp)
        struct hibmc_dp_link *link = &dp->link;
        int ret;
 
+       ret = drm_dp_read_dpcd_caps(&dp->aux, dp->dpcd);
+       if (ret)
+               drm_err(dp->dev, "dp aux read dpcd failed, ret: %d\n", ret);
+
+       dp->link.cap.link_rate = dp->dpcd[DP_MAX_LINK_RATE];
+       dp->link.cap.lanes = 0x2;
+
+       ret = hibmc_dp_get_serdes_rate_cfg(dp);
+       if (ret < 0)
+               return ret;
+
+       ret = hibmc_dp_serdes_rate_switch(ret, dp);
+       if (ret)
+               return ret;
+
        while (true) {
                ret = hibmc_dp_link_training_cr_pre(dp);
                if (ret)
index 16ea589035980fa590e8e1fb1f2e48358b507c55..6eb76decc636e3d0d53d0ffc5dafd9538ae569a9 100644 (file)
@@ -54,6 +54,7 @@
 #define HIBMC_DP_VIDEO_PACKET                  0x114
 #define HIBMC_DP_CFG_STREAM_TU_SYMBOL_SIZE     GENMASK(5, 0)
 #define HIBMC_DP_CFG_STREAM_TU_SYMBOL_FRAC_SIZE        GENMASK(9, 6)
+#define HIBMC_DP_CFG_STREAM_SYNC_CALIBRATION   GENMASK(31, 20)
 
 #define HIBMC_DP_VIDEO_MSA0                    0x118
 #define HIBMC_DP_CFG_STREAM_VSTART             GENMASK(31, 16)
 #define HIBMC_DP_LANE_STATUS_OFFSET    0x10
 #define HIBMC_DP_PMA_LANE0_OFFSET      0x18
 #define HIBMC_DP_PMA_LANE1_OFFSET      0x1c
+#define HIBMC_DP_HOST_SERDES_CTRL      0x1f001c
 #define HIBMC_DP_PMA_TXDEEMPH          GENMASK(18, 1)
 #define DP_SERDES_DONE                 0x3
 
 #define DP_SERDES_VOL2_PRE1            0x4500
 #define DP_SERDES_VOL3_PRE0            0x600
 #define DP_SERDES_BW_8_1               0x3
+#define DP_SERDES_BW_5_4               0x2
+#define DP_SERDES_BW_2_7               0x1
+#define DP_SERDES_BW_1_62              0x0
 
 #endif
index e6de6d5edf6b0503141946119f6218e69639828d..98b01c8aee8eb561c868b492478556b040289080 100644 (file)
@@ -28,9 +28,7 @@
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_regs.h"
 
-#define HIBMC_DP_HOST_SERDES_CTRL              0x1f001c
-#define HIBMC_DP_HOST_SERDES_CTRL_VAL          0x8a00
-#define HIBMC_DP_HOST_SERDES_CTRL_MASK         0x7ffff
+#include "dp/dp_reg.h"
 
 DEFINE_DRM_GEM_FOPS(hibmc_fops);
 
@@ -121,9 +119,12 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
                return ret;
        }
 
-       /* if DP existed, init DP */
-       if ((readl(priv->mmio + HIBMC_DP_HOST_SERDES_CTRL) &
-            HIBMC_DP_HOST_SERDES_CTRL_MASK) == HIBMC_DP_HOST_SERDES_CTRL_VAL) {
+       /*
+        * If the serdes reg is readable and is not equal to 0,
+        * DP block exists and initializes it.
+        */
+       ret = readl(priv->mmio + HIBMC_DP_HOST_SERDES_CTRL);
+       if (ret) {
                ret = hibmc_dp_init(priv);
                if (ret)
                        drm_err(dev, "failed to init dp: %d\n", ret);