]> Git Repo - linux.git/commitdiff
Merge tag 'topic/drm-dp-training-delay-helpers-2021-10-19' of git://anongit.freedeskt...
authorJani Nikula <[email protected]>
Tue, 19 Oct 2021 15:15:27 +0000 (18:15 +0300)
committerJani Nikula <[email protected]>
Tue, 19 Oct 2021 15:32:23 +0000 (18:32 +0300)
Core Changes:
- drm dp helpers for figuring out link training delays

Merge to drm-intel-next as well after c93ce6a6dfbd ("Merge tag
'topic/drm-dp-training-delay-helpers-2021-10-19' of
git://anongit.freedesktop.org/drm/drm-intel into drm-misc-next").

Signed-off-by: Jani Nikula <[email protected]>
From: Jani Nikula <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1  2 
drivers/gpu/drm/drm_dp_helper.c
include/drm/drm_dp_helper.h

index 4d0d1e8e51fa77e530821ec7a90114093a9b4e7c,3b46eb31c74bbab9715543380bd127fe6c67896c..ada0a1ff262d749db5e30a6fe1116dba8e135474
@@@ -130,20 -130,6 +130,20 @@@ u8 drm_dp_get_adjust_request_pre_emphas
  }
  EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
  
 +/* DP 2.0 128b/132b */
 +u8 drm_dp_get_adjust_tx_ffe_preset(const u8 link_status[DP_LINK_STATUS_SIZE],
 +                                 int lane)
 +{
 +      int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
 +      int s = ((lane & 1) ?
 +               DP_ADJUST_TX_FFE_PRESET_LANE1_SHIFT :
 +               DP_ADJUST_TX_FFE_PRESET_LANE0_SHIFT);
 +      u8 l = dp_link_status(link_status, i);
 +
 +      return (l >> s) & 0xf;
 +}
 +EXPORT_SYMBOL(drm_dp_get_adjust_tx_ffe_preset);
 +
  u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE],
                                         unsigned int lane)
  {
  }
  EXPORT_SYMBOL(drm_dp_get_adjust_request_post_cursor);
  
- void drm_dp_link_train_clock_recovery_delay(const struct drm_dp_aux *aux,
-                                           const u8 dpcd[DP_RECEIVER_CAP_SIZE])
+ static int __8b10b_clock_recovery_delay_us(const struct drm_dp_aux *aux, u8 rd_interval)
  {
-       unsigned long rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
-                                        DP_TRAINING_AUX_RD_MASK;
        if (rd_interval > 4)
-               drm_dbg_kms(aux->drm_dev, "%s: AUX interval %lu, out of range (max 4)\n",
+               drm_dbg_kms(aux->drm_dev, "%s: invalid AUX interval 0x%02x (max 4)\n",
                            aux->name, rd_interval);
  
-       if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
-               rd_interval = 100;
-       else
-               rd_interval *= 4 * USEC_PER_MSEC;
+       if (rd_interval == 0)
+               return 100;
  
-       usleep_range(rd_interval, rd_interval * 2);
+       return rd_interval * 4 * USEC_PER_MSEC;
  }
- EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
  
- static void __drm_dp_link_train_channel_eq_delay(const struct drm_dp_aux *aux,
-                                                unsigned long rd_interval)
+ static int __8b10b_channel_eq_delay_us(const struct drm_dp_aux *aux, u8 rd_interval)
  {
        if (rd_interval > 4)
-               drm_dbg_kms(aux->drm_dev, "%s: AUX interval %lu, out of range (max 4)\n",
+               drm_dbg_kms(aux->drm_dev, "%s: invalid AUX interval 0x%02x (max 4)\n",
                            aux->name, rd_interval);
  
        if (rd_interval == 0)
-               rd_interval = 400;
+               return 400;
+       return rd_interval * 4 * USEC_PER_MSEC;
+ }
+ static int __128b132b_channel_eq_delay_us(const struct drm_dp_aux *aux, u8 rd_interval)
+ {
+       switch (rd_interval) {
+       default:
+               drm_dbg_kms(aux->drm_dev, "%s: invalid AUX interval 0x%02x\n",
+                           aux->name, rd_interval);
+               fallthrough;
+       case DP_128B132B_TRAINING_AUX_RD_INTERVAL_400_US:
+               return 400;
+       case DP_128B132B_TRAINING_AUX_RD_INTERVAL_4_MS:
+               return 4000;
+       case DP_128B132B_TRAINING_AUX_RD_INTERVAL_8_MS:
+               return 8000;
+       case DP_128B132B_TRAINING_AUX_RD_INTERVAL_12_MS:
+               return 12000;
+       case DP_128B132B_TRAINING_AUX_RD_INTERVAL_16_MS:
+               return 16000;
+       case DP_128B132B_TRAINING_AUX_RD_INTERVAL_32_MS:
+               return 32000;
+       case DP_128B132B_TRAINING_AUX_RD_INTERVAL_64_MS:
+               return 64000;
+       }
+ }
+ /*
+  * The link training delays are different for:
+  *
+  *  - Clock recovery vs. channel equalization
+  *  - DPRX vs. LTTPR
+  *  - 128b/132b vs. 8b/10b
+  *  - DPCD rev 1.3 vs. later
+  *
+  * Get the correct delay in us, reading DPCD if necessary.
+  */
+ static int __read_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                       enum drm_dp_phy dp_phy, bool uhbr, bool cr)
+ {
+       int (*parse)(const struct drm_dp_aux *aux, u8 rd_interval);
+       unsigned int offset;
+       u8 rd_interval, mask;
+       if (dp_phy == DP_PHY_DPRX) {
+               if (uhbr) {
+                       if (cr)
+                               return 100;
+                       offset = DP_128B132B_TRAINING_AUX_RD_INTERVAL;
+                       mask = DP_128B132B_TRAINING_AUX_RD_INTERVAL_MASK;
+                       parse = __128b132b_channel_eq_delay_us;
+               } else {
+                       if (cr && dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
+                               return 100;
+                       offset = DP_TRAINING_AUX_RD_INTERVAL;
+                       mask = DP_TRAINING_AUX_RD_MASK;
+                       if (cr)
+                               parse = __8b10b_clock_recovery_delay_us;
+                       else
+                               parse = __8b10b_channel_eq_delay_us;
+               }
+       } else {
+               if (uhbr) {
+                       offset = DP_128B132B_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy);
+                       mask = DP_128B132B_TRAINING_AUX_RD_INTERVAL_MASK;
+                       parse = __128b132b_channel_eq_delay_us;
+               } else {
+                       if (cr)
+                               return 100;
+                       offset = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy);
+                       mask = DP_TRAINING_AUX_RD_MASK;
+                       parse = __8b10b_channel_eq_delay_us;
+               }
+       }
+       if (offset < DP_RECEIVER_CAP_SIZE) {
+               rd_interval = dpcd[offset];
+       } else {
+               if (drm_dp_dpcd_readb(aux, offset, &rd_interval) != 1) {
+                       drm_dbg_kms(aux->drm_dev, "%s: failed rd interval read\n",
+                                   aux->name);
+                       /* arbitrary default delay */
+                       return 400;
+               }
+       }
+       return parse(aux, rd_interval & mask);
+ }
+ int drm_dp_read_clock_recovery_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                                    enum drm_dp_phy dp_phy, bool uhbr)
+ {
+       return __read_delay(aux, dpcd, dp_phy, uhbr, true);
+ }
+ EXPORT_SYMBOL(drm_dp_read_clock_recovery_delay);
+ int drm_dp_read_channel_eq_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                                enum drm_dp_phy dp_phy, bool uhbr)
+ {
+       return __read_delay(aux, dpcd, dp_phy, uhbr, false);
+ }
+ EXPORT_SYMBOL(drm_dp_read_channel_eq_delay);
+ void drm_dp_link_train_clock_recovery_delay(const struct drm_dp_aux *aux,
+                                           const u8 dpcd[DP_RECEIVER_CAP_SIZE])
+ {
+       u8 rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
+               DP_TRAINING_AUX_RD_MASK;
+       int delay_us;
+       if (dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
+               delay_us = 100;
        else
-               rd_interval *= 4 * USEC_PER_MSEC;
+               delay_us = __8b10b_clock_recovery_delay_us(aux, rd_interval);
+       usleep_range(delay_us, delay_us * 2);
+ }
+ EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
+ static void __drm_dp_link_train_channel_eq_delay(const struct drm_dp_aux *aux,
+                                                u8 rd_interval)
+ {
+       int delay_us = __8b10b_channel_eq_delay_us(aux, rd_interval);
  
-       usleep_range(rd_interval, rd_interval * 2);
+       usleep_range(delay_us, delay_us * 2);
  }
  
  void drm_dp_link_train_channel_eq_delay(const struct drm_dp_aux *aux,
@@@ -221,33 -324,15 +338,33 @@@ EXPORT_SYMBOL(drm_dp_lttpr_link_train_c
  
  u8 drm_dp_link_rate_to_bw_code(int link_rate)
  {
 -      /* Spec says link_bw = link_rate / 0.27Gbps */
 -      return link_rate / 27000;
 +      switch (link_rate) {
 +      case 1000000:
 +              return DP_LINK_BW_10;
 +      case 1350000:
 +              return DP_LINK_BW_13_5;
 +      case 2000000:
 +              return DP_LINK_BW_20;
 +      default:
 +              /* Spec says link_bw = link_rate / 0.27Gbps */
 +              return link_rate / 27000;
 +      }
  }
  EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code);
  
  int drm_dp_bw_code_to_link_rate(u8 link_bw)
  {
 -      /* Spec says link_rate = link_bw * 0.27Gbps */
 -      return link_bw * 27000;
 +      switch (link_bw) {
 +      case DP_LINK_BW_10:
 +              return 1000000;
 +      case DP_LINK_BW_13_5:
 +              return 1350000;
 +      case DP_LINK_BW_20:
 +              return 2000000;
 +      default:
 +              /* Spec says link_rate = link_bw * 0.27Gbps */
 +              return link_bw * 27000;
 +      }
  }
  EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate);
  
@@@ -622,7 -707,7 +739,7 @@@ static u8 drm_dp_downstream_port_count(
  static int drm_dp_read_extended_dpcd_caps(struct drm_dp_aux *aux,
                                          u8 dpcd[DP_RECEIVER_CAP_SIZE])
  {
 -      u8 dpcd_ext[6];
 +      u8 dpcd_ext[DP_RECEIVER_CAP_SIZE];
        int ret;
  
        /*
index b52df4db3e8fe2b737bb9ae3145f1e6944da5a5b,b653c5da7065100317f33f4819086b5e7522ace9..afdf7f4183f9a0dadfd22adeafb70bf2fbe27822
@@@ -1114,8 -1114,15 +1114,15 @@@ struct drm_panel
  # define DP_UHBR20                             (1 << 1)
  # define DP_UHBR13_5                           (1 << 2)
  
- #define DP_128B132B_TRAINING_AUX_RD_INTERVAL   0x2216 /* 2.0 */
- # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_MASK 0x7f
+ #define DP_128B132B_TRAINING_AUX_RD_INTERVAL                    0x2216 /* 2.0 */
+ # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_MASK              0x7f
+ # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_400_US            0x00
+ # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_4_MS              0x01
+ # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_8_MS              0x02
+ # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_12_MS             0x03
+ # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_16_MS             0x04
+ # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_32_MS             0x05
+ # define DP_128B132B_TRAINING_AUX_RD_INTERVAL_64_MS             0x06
  
  #define DP_TEST_264BIT_CUSTOM_PATTERN_7_0             0x2230
  #define DP_TEST_264BIT_CUSTOM_PATTERN_263_256 0x2250
  #define DP_MAX_LANE_COUNT_PHY_REPEATER                            0xf0004 /* 1.4a */
  #define DP_Repeater_FEC_CAPABILITY                        0xf0004 /* 1.4 */
  #define DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT             0xf0005 /* 1.4a */
 +#define DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER          0xf0006 /* 2.0 */
 +# define DP_PHY_REPEATER_128B132B_SUPPORTED               (1 << 0)
 +/* See DP_128B132B_SUPPORTED_LINK_RATES for values */
 +#define DP_PHY_REPEATER_128B132B_RATES                            0xf0007 /* 2.0 */
  
  enum drm_dp_phy {
        DP_PHY_DPRX,
  # define DP_VOLTAGE_SWING_LEVEL_3_SUPPORTED               BIT(0)
  # define DP_PRE_EMPHASIS_LEVEL_3_SUPPORTED                BIT(1)
  
+ #define DP_128B132B_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1  0xf0022 /* 2.0 */
+ #define DP_128B132B_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy)     \
+       DP_LTTPR_REG(dp_phy, DP_128B132B_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1)
+ /* see DP_128B132B_TRAINING_AUX_RD_INTERVAL for values */
  #define DP_LANE0_1_STATUS_PHY_REPEATER1                           0xf0030 /* 1.3 */
  #define DP_LANE0_1_STATUS_PHY_REPEATER(dp_phy) \
        DP_LTTPR_REG(dp_phy, DP_LANE0_1_STATUS_PHY_REPEATER1)
@@@ -1514,8 -1522,6 +1526,8 @@@ u8 drm_dp_get_adjust_request_voltage(co
                                     int lane);
  u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE],
                                          int lane);
 +u8 drm_dp_get_adjust_tx_ffe_preset(const u8 link_status[DP_LINK_STATUS_SIZE],
 +                                 int lane);
  u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE],
                                         unsigned int lane);
  
  #define DP_LTTPR_COMMON_CAP_SIZE      8
  #define DP_LTTPR_PHY_CAP_SIZE         3
  
+ int drm_dp_read_clock_recovery_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                                    enum drm_dp_phy dp_phy, bool uhbr);
+ int drm_dp_read_channel_eq_delay(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
+                                enum drm_dp_phy dp_phy, bool uhbr);
  void drm_dp_link_train_clock_recovery_delay(const struct drm_dp_aux *aux,
                                            const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
  void drm_dp_lttpr_link_train_clock_recovery_delay(void);
This page took 0.069613 seconds and 4 git commands to generate.