diff options
-rw-r--r-- | drivers/gpu/drm/drm_dp_helper.c | 83 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 45 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp_mst.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_lspcon.c | 2 | ||||
-rw-r--r-- | include/drm/drm_dp_helper.h | 51 |
8 files changed, 166 insertions, 58 deletions
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 3e5f52110ea1..213fb837e1c4 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c | |||
@@ -1208,3 +1208,86 @@ int drm_dp_stop_crc(struct drm_dp_aux *aux) | |||
1208 | return 0; | 1208 | return 0; |
1209 | } | 1209 | } |
1210 | EXPORT_SYMBOL(drm_dp_stop_crc); | 1210 | EXPORT_SYMBOL(drm_dp_stop_crc); |
1211 | |||
1212 | struct dpcd_quirk { | ||
1213 | u8 oui[3]; | ||
1214 | bool is_branch; | ||
1215 | u32 quirks; | ||
1216 | }; | ||
1217 | |||
1218 | #define OUI(first, second, third) { (first), (second), (third) } | ||
1219 | |||
1220 | static const struct dpcd_quirk dpcd_quirk_list[] = { | ||
1221 | /* Analogix 7737 needs reduced M and N at HBR2 link rates */ | ||
1222 | { OUI(0x00, 0x22, 0xb9), true, BIT(DP_DPCD_QUIRK_LIMITED_M_N) }, | ||
1223 | }; | ||
1224 | |||
1225 | #undef OUI | ||
1226 | |||
1227 | /* | ||
1228 | * Get a bit mask of DPCD quirks for the sink/branch device identified by | ||
1229 | * ident. The quirk data is shared but it's up to the drivers to act on the | ||
1230 | * data. | ||
1231 | * | ||
1232 | * For now, only the OUI (first three bytes) is used, but this may be extended | ||
1233 | * to device identification string and hardware/firmware revisions later. | ||
1234 | */ | ||
1235 | static u32 | ||
1236 | drm_dp_get_quirks(const struct drm_dp_dpcd_ident *ident, bool is_branch) | ||
1237 | { | ||
1238 | const struct dpcd_quirk *quirk; | ||
1239 | u32 quirks = 0; | ||
1240 | int i; | ||
1241 | |||
1242 | for (i = 0; i < ARRAY_SIZE(dpcd_quirk_list); i++) { | ||
1243 | quirk = &dpcd_quirk_list[i]; | ||
1244 | |||
1245 | if (quirk->is_branch != is_branch) | ||
1246 | continue; | ||
1247 | |||
1248 | if (memcmp(quirk->oui, ident->oui, sizeof(ident->oui)) != 0) | ||
1249 | continue; | ||
1250 | |||
1251 | quirks |= quirk->quirks; | ||
1252 | } | ||
1253 | |||
1254 | return quirks; | ||
1255 | } | ||
1256 | |||
1257 | /** | ||
1258 | * drm_dp_read_desc - read sink/branch descriptor from DPCD | ||
1259 | * @aux: DisplayPort AUX channel | ||
1260 | * @desc: Device decriptor to fill from DPCD | ||
1261 | * @is_branch: true for branch devices, false for sink devices | ||
1262 | * | ||
1263 | * Read DPCD 0x400 (sink) or 0x500 (branch) into @desc. Also debug log the | ||
1264 | * identification. | ||
1265 | * | ||
1266 | * Returns 0 on success or a negative error code on failure. | ||
1267 | */ | ||
1268 | int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, | ||
1269 | bool is_branch) | ||
1270 | { | ||
1271 | struct drm_dp_dpcd_ident *ident = &desc->ident; | ||
1272 | unsigned int offset = is_branch ? DP_BRANCH_OUI : DP_SINK_OUI; | ||
1273 | int ret, dev_id_len; | ||
1274 | |||
1275 | ret = drm_dp_dpcd_read(aux, offset, ident, sizeof(*ident)); | ||
1276 | if (ret < 0) | ||
1277 | return ret; | ||
1278 | |||
1279 | desc->quirks = drm_dp_get_quirks(ident, is_branch); | ||
1280 | |||
1281 | dev_id_len = strnlen(ident->device_id, sizeof(ident->device_id)); | ||
1282 | |||
1283 | DRM_DEBUG_KMS("DP %s: OUI %*phD dev-ID %*pE HW-rev %d.%d SW-rev %d.%d quirks 0x%04x\n", | ||
1284 | is_branch ? "branch" : "sink", | ||
1285 | (int)sizeof(ident->oui), ident->oui, | ||
1286 | dev_id_len, ident->device_id, | ||
1287 | ident->hw_rev >> 4, ident->hw_rev & 0xf, | ||
1288 | ident->sw_major_rev, ident->sw_minor_rev, | ||
1289 | desc->quirks); | ||
1290 | |||
1291 | return 0; | ||
1292 | } | ||
1293 | EXPORT_SYMBOL(drm_dp_read_desc); | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c9b0949f6c1a..963f6d4481f7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -562,7 +562,8 @@ struct intel_link_m_n { | |||
562 | 562 | ||
563 | void intel_link_compute_m_n(int bpp, int nlanes, | 563 | void intel_link_compute_m_n(int bpp, int nlanes, |
564 | int pixel_clock, int link_clock, | 564 | int pixel_clock, int link_clock, |
565 | struct intel_link_m_n *m_n); | 565 | struct intel_link_m_n *m_n, |
566 | bool reduce_m_n); | ||
566 | 567 | ||
567 | /* Interface history: | 568 | /* Interface history: |
568 | * | 569 | * |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3617927af269..3cabe52a4e3b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -6101,7 +6101,7 @@ retry: | |||
6101 | pipe_config->fdi_lanes = lane; | 6101 | pipe_config->fdi_lanes = lane; |
6102 | 6102 | ||
6103 | intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock, | 6103 | intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock, |
6104 | link_bw, &pipe_config->fdi_m_n); | 6104 | link_bw, &pipe_config->fdi_m_n, false); |
6105 | 6105 | ||
6106 | ret = ironlake_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config); | 6106 | ret = ironlake_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config); |
6107 | if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) { | 6107 | if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) { |
@@ -6277,7 +6277,8 @@ intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) | |||
6277 | } | 6277 | } |
6278 | 6278 | ||
6279 | static void compute_m_n(unsigned int m, unsigned int n, | 6279 | static void compute_m_n(unsigned int m, unsigned int n, |
6280 | uint32_t *ret_m, uint32_t *ret_n) | 6280 | uint32_t *ret_m, uint32_t *ret_n, |
6281 | bool reduce_m_n) | ||
6281 | { | 6282 | { |
6282 | /* | 6283 | /* |
6283 | * Reduce M/N as much as possible without loss in precision. Several DP | 6284 | * Reduce M/N as much as possible without loss in precision. Several DP |
@@ -6285,9 +6286,11 @@ static void compute_m_n(unsigned int m, unsigned int n, | |||
6285 | * values. The passed in values are more likely to have the least | 6286 | * values. The passed in values are more likely to have the least |
6286 | * significant bits zero than M after rounding below, so do this first. | 6287 | * significant bits zero than M after rounding below, so do this first. |
6287 | */ | 6288 | */ |
6288 | while ((m & 1) == 0 && (n & 1) == 0) { | 6289 | if (reduce_m_n) { |
6289 | m >>= 1; | 6290 | while ((m & 1) == 0 && (n & 1) == 0) { |
6290 | n >>= 1; | 6291 | m >>= 1; |
6292 | n >>= 1; | ||
6293 | } | ||
6291 | } | 6294 | } |
6292 | 6295 | ||
6293 | *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX); | 6296 | *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX); |
@@ -6298,16 +6301,19 @@ static void compute_m_n(unsigned int m, unsigned int n, | |||
6298 | void | 6301 | void |
6299 | intel_link_compute_m_n(int bits_per_pixel, int nlanes, | 6302 | intel_link_compute_m_n(int bits_per_pixel, int nlanes, |
6300 | int pixel_clock, int link_clock, | 6303 | int pixel_clock, int link_clock, |
6301 | struct intel_link_m_n *m_n) | 6304 | struct intel_link_m_n *m_n, |
6305 | bool reduce_m_n) | ||
6302 | { | 6306 | { |
6303 | m_n->tu = 64; | 6307 | m_n->tu = 64; |
6304 | 6308 | ||
6305 | compute_m_n(bits_per_pixel * pixel_clock, | 6309 | compute_m_n(bits_per_pixel * pixel_clock, |
6306 | link_clock * nlanes * 8, | 6310 | link_clock * nlanes * 8, |
6307 | &m_n->gmch_m, &m_n->gmch_n); | 6311 | &m_n->gmch_m, &m_n->gmch_n, |
6312 | reduce_m_n); | ||
6308 | 6313 | ||
6309 | compute_m_n(pixel_clock, link_clock, | 6314 | compute_m_n(pixel_clock, link_clock, |
6310 | &m_n->link_m, &m_n->link_n); | 6315 | &m_n->link_m, &m_n->link_n, |
6316 | reduce_m_n); | ||
6311 | } | 6317 | } |
6312 | 6318 | ||
6313 | static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) | 6319 | static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) |
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ee77b519835c..fc691b8b317c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -1507,37 +1507,6 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp) | |||
1507 | DRM_DEBUG_KMS("common rates: %s\n", str); | 1507 | DRM_DEBUG_KMS("common rates: %s\n", str); |
1508 | } | 1508 | } |
1509 | 1509 | ||
1510 | bool | ||
1511 | __intel_dp_read_desc(struct intel_dp *intel_dp, struct intel_dp_desc *desc) | ||
1512 | { | ||
1513 | u32 base = drm_dp_is_branch(intel_dp->dpcd) ? DP_BRANCH_OUI : | ||
1514 | DP_SINK_OUI; | ||
1515 | |||
1516 | return drm_dp_dpcd_read(&intel_dp->aux, base, desc, sizeof(*desc)) == | ||
1517 | sizeof(*desc); | ||
1518 | } | ||
1519 | |||
1520 | bool intel_dp_read_desc(struct intel_dp *intel_dp) | ||
1521 | { | ||
1522 | struct intel_dp_desc *desc = &intel_dp->desc; | ||
1523 | bool oui_sup = intel_dp->dpcd[DP_DOWN_STREAM_PORT_COUNT] & | ||
1524 | DP_OUI_SUPPORT; | ||
1525 | int dev_id_len; | ||
1526 | |||
1527 | if (!__intel_dp_read_desc(intel_dp, desc)) | ||
1528 | return false; | ||
1529 | |||
1530 | dev_id_len = strnlen(desc->device_id, sizeof(desc->device_id)); | ||
1531 | DRM_DEBUG_KMS("DP %s: OUI %*phD%s dev-ID %*pE HW-rev %d.%d SW-rev %d.%d\n", | ||
1532 | drm_dp_is_branch(intel_dp->dpcd) ? "branch" : "sink", | ||
1533 | (int)sizeof(desc->oui), desc->oui, oui_sup ? "" : "(NS)", | ||
1534 | dev_id_len, desc->device_id, | ||
1535 | desc->hw_rev >> 4, desc->hw_rev & 0xf, | ||
1536 | desc->sw_major_rev, desc->sw_minor_rev); | ||
1537 | |||
1538 | return true; | ||
1539 | } | ||
1540 | |||
1541 | static int rate_to_index(int find, const int *rates) | 1510 | static int rate_to_index(int find, const int *rates) |
1542 | { | 1511 | { |
1543 | int i = 0; | 1512 | int i = 0; |
@@ -1624,6 +1593,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, | |||
1624 | int common_rates[DP_MAX_SUPPORTED_RATES] = {}; | 1593 | int common_rates[DP_MAX_SUPPORTED_RATES] = {}; |
1625 | int common_len; | 1594 | int common_len; |
1626 | uint8_t link_bw, rate_select; | 1595 | uint8_t link_bw, rate_select; |
1596 | bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc, | ||
1597 | DP_DPCD_QUIRK_LIMITED_M_N); | ||
1627 | 1598 | ||
1628 | common_len = intel_dp_common_rates(intel_dp, common_rates); | 1599 | common_len = intel_dp_common_rates(intel_dp, common_rates); |
1629 | 1600 | ||
@@ -1753,7 +1724,8 @@ found: | |||
1753 | intel_link_compute_m_n(bpp, lane_count, | 1724 | intel_link_compute_m_n(bpp, lane_count, |
1754 | adjusted_mode->crtc_clock, | 1725 | adjusted_mode->crtc_clock, |
1755 | pipe_config->port_clock, | 1726 | pipe_config->port_clock, |
1756 | &pipe_config->dp_m_n); | 1727 | &pipe_config->dp_m_n, |
1728 | reduce_m_n); | ||
1757 | 1729 | ||
1758 | if (intel_connector->panel.downclock_mode != NULL && | 1730 | if (intel_connector->panel.downclock_mode != NULL && |
1759 | dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) { | 1731 | dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) { |
@@ -1761,7 +1733,8 @@ found: | |||
1761 | intel_link_compute_m_n(bpp, lane_count, | 1733 | intel_link_compute_m_n(bpp, lane_count, |
1762 | intel_connector->panel.downclock_mode->clock, | 1734 | intel_connector->panel.downclock_mode->clock, |
1763 | pipe_config->port_clock, | 1735 | pipe_config->port_clock, |
1764 | &pipe_config->dp_m2_n2); | 1736 | &pipe_config->dp_m2_n2, |
1737 | reduce_m_n); | ||
1765 | } | 1738 | } |
1766 | 1739 | ||
1767 | /* | 1740 | /* |
@@ -3622,7 +3595,8 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp) | |||
3622 | if (!intel_dp_read_dpcd(intel_dp)) | 3595 | if (!intel_dp_read_dpcd(intel_dp)) |
3623 | return false; | 3596 | return false; |
3624 | 3597 | ||
3625 | intel_dp_read_desc(intel_dp); | 3598 | drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc, |
3599 | drm_dp_is_branch(intel_dp->dpcd)); | ||
3626 | 3600 | ||
3627 | if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) | 3601 | if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) |
3628 | dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] & | 3602 | dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] & |
@@ -4624,7 +4598,8 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) | |||
4624 | 4598 | ||
4625 | intel_dp_print_rates(intel_dp); | 4599 | intel_dp_print_rates(intel_dp); |
4626 | 4600 | ||
4627 | intel_dp_read_desc(intel_dp); | 4601 | drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc, |
4602 | drm_dp_is_branch(intel_dp->dpcd)); | ||
4628 | 4603 | ||
4629 | intel_dp_configure_mst(intel_dp); | 4604 | intel_dp_configure_mst(intel_dp); |
4630 | 4605 | ||
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index c1f62eb07c07..989e25577ac0 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c | |||
@@ -44,6 +44,8 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |||
44 | int lane_count, slots; | 44 | int lane_count, slots; |
45 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; | 45 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
46 | int mst_pbn; | 46 | int mst_pbn; |
47 | bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc, | ||
48 | DP_DPCD_QUIRK_LIMITED_M_N); | ||
47 | 49 | ||
48 | pipe_config->has_pch_encoder = false; | 50 | pipe_config->has_pch_encoder = false; |
49 | bpp = 24; | 51 | bpp = 24; |
@@ -75,7 +77,8 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | |||
75 | intel_link_compute_m_n(bpp, lane_count, | 77 | intel_link_compute_m_n(bpp, lane_count, |
76 | adjusted_mode->crtc_clock, | 78 | adjusted_mode->crtc_clock, |
77 | pipe_config->port_clock, | 79 | pipe_config->port_clock, |
78 | &pipe_config->dp_m_n); | 80 | &pipe_config->dp_m_n, |
81 | reduce_m_n); | ||
79 | 82 | ||
80 | pipe_config->dp_m_n.tu = slots; | 83 | pipe_config->dp_m_n.tu = slots; |
81 | 84 | ||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index aaee3949a422..f630c7af5020 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -906,14 +906,6 @@ enum link_m_n_set { | |||
906 | M2_N2 | 906 | M2_N2 |
907 | }; | 907 | }; |
908 | 908 | ||
909 | struct intel_dp_desc { | ||
910 | u8 oui[3]; | ||
911 | u8 device_id[6]; | ||
912 | u8 hw_rev; | ||
913 | u8 sw_major_rev; | ||
914 | u8 sw_minor_rev; | ||
915 | } __packed; | ||
916 | |||
917 | struct intel_dp_compliance_data { | 909 | struct intel_dp_compliance_data { |
918 | unsigned long edid; | 910 | unsigned long edid; |
919 | uint8_t video_pattern; | 911 | uint8_t video_pattern; |
@@ -957,7 +949,7 @@ struct intel_dp { | |||
957 | /* Max link BW for the sink as per DPCD registers */ | 949 | /* Max link BW for the sink as per DPCD registers */ |
958 | int max_sink_link_bw; | 950 | int max_sink_link_bw; |
959 | /* sink or branch descriptor */ | 951 | /* sink or branch descriptor */ |
960 | struct intel_dp_desc desc; | 952 | struct drm_dp_desc desc; |
961 | struct drm_dp_aux aux; | 953 | struct drm_dp_aux aux; |
962 | enum intel_display_power_domain aux_power_domain; | 954 | enum intel_display_power_domain aux_power_domain; |
963 | uint8_t train_set[4]; | 955 | uint8_t train_set[4]; |
@@ -1532,9 +1524,6 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count) | |||
1532 | } | 1524 | } |
1533 | 1525 | ||
1534 | bool intel_dp_read_dpcd(struct intel_dp *intel_dp); | 1526 | bool intel_dp_read_dpcd(struct intel_dp *intel_dp); |
1535 | bool __intel_dp_read_desc(struct intel_dp *intel_dp, | ||
1536 | struct intel_dp_desc *desc); | ||
1537 | bool intel_dp_read_desc(struct intel_dp *intel_dp); | ||
1538 | int intel_dp_link_required(int pixel_clock, int bpp); | 1527 | int intel_dp_link_required(int pixel_clock, int bpp); |
1539 | int intel_dp_max_data_rate(int max_link_clock, int max_lanes); | 1528 | int intel_dp_max_data_rate(int max_link_clock, int max_lanes); |
1540 | bool intel_digital_port_connected(struct drm_i915_private *dev_priv, | 1529 | bool intel_digital_port_connected(struct drm_i915_private *dev_priv, |
diff --git a/drivers/gpu/drm/i915/intel_lspcon.c b/drivers/gpu/drm/i915/intel_lspcon.c index 71cbe9c08932..5abef482eacf 100644 --- a/drivers/gpu/drm/i915/intel_lspcon.c +++ b/drivers/gpu/drm/i915/intel_lspcon.c | |||
@@ -240,7 +240,7 @@ bool lspcon_init(struct intel_digital_port *intel_dig_port) | |||
240 | return false; | 240 | return false; |
241 | } | 241 | } |
242 | 242 | ||
243 | intel_dp_read_desc(dp); | 243 | drm_dp_read_desc(&dp->aux, &dp->desc, drm_dp_is_branch(dp->dpcd)); |
244 | 244 | ||
245 | DRM_DEBUG_KMS("Success: LSPCON init\n"); | 245 | DRM_DEBUG_KMS("Success: LSPCON init\n"); |
246 | return true; | 246 | return true; |
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c0bd0d7651a9..bb837310c07e 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h | |||
@@ -913,4 +913,55 @@ void drm_dp_aux_unregister(struct drm_dp_aux *aux); | |||
913 | int drm_dp_start_crc(struct drm_dp_aux *aux, struct drm_crtc *crtc); | 913 | int drm_dp_start_crc(struct drm_dp_aux *aux, struct drm_crtc *crtc); |
914 | int drm_dp_stop_crc(struct drm_dp_aux *aux); | 914 | int drm_dp_stop_crc(struct drm_dp_aux *aux); |
915 | 915 | ||
916 | struct drm_dp_dpcd_ident { | ||
917 | u8 oui[3]; | ||
918 | u8 device_id[6]; | ||
919 | u8 hw_rev; | ||
920 | u8 sw_major_rev; | ||
921 | u8 sw_minor_rev; | ||
922 | } __packed; | ||
923 | |||
924 | /** | ||
925 | * struct drm_dp_desc - DP branch/sink device descriptor | ||
926 | * @ident: DP device identification from DPCD 0x400 (sink) or 0x500 (branch). | ||
927 | * @quirks: Quirks; use drm_dp_has_quirk() to query for the quirks. | ||
928 | */ | ||
929 | struct drm_dp_desc { | ||
930 | struct drm_dp_dpcd_ident ident; | ||
931 | u32 quirks; | ||
932 | }; | ||
933 | |||
934 | int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, | ||
935 | bool is_branch); | ||
936 | |||
937 | /** | ||
938 | * enum drm_dp_quirk - Display Port sink/branch device specific quirks | ||
939 | * | ||
940 | * Display Port sink and branch devices in the wild have a variety of bugs, try | ||
941 | * to collect them here. The quirks are shared, but it's up to the drivers to | ||
942 | * implement workarounds for them. | ||
943 | */ | ||
944 | enum drm_dp_quirk { | ||
945 | /** | ||
946 | * @DP_DPCD_QUIRK_LIMITED_M_N: | ||
947 | * | ||
948 | * The device requires main link attributes Mvid and Nvid to be limited | ||
949 | * to 16 bits. | ||
950 | */ | ||
951 | DP_DPCD_QUIRK_LIMITED_M_N, | ||
952 | }; | ||
953 | |||
954 | /** | ||
955 | * drm_dp_has_quirk() - does the DP device have a specific quirk | ||
956 | * @desc: Device decriptor filled by drm_dp_read_desc() | ||
957 | * @quirk: Quirk to query for | ||
958 | * | ||
959 | * Return true if DP device identified by @desc has @quirk. | ||
960 | */ | ||
961 | static inline bool | ||
962 | drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk) | ||
963 | { | ||
964 | return desc->quirks & BIT(quirk); | ||
965 | } | ||
966 | |||
916 | #endif /* _DRM_DP_HELPER_H_ */ | 967 | #endif /* _DRM_DP_HELPER_H_ */ |