From 4d658cb7789e8cc9198c0a62b8415f0c85021ab0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Sep 2020 13:53:56 -0400 Subject: drm/dp: fix kernel-doc warnings at drm_dp_helper.c As warned by kernel-doc: ./drivers/gpu/drm/drm_dp_helper.c:385: warning: Function parameter or member 'type' not described in 'drm_dp_downstream_is_type' ./drivers/gpu/drm/drm_dp_helper.c:886: warning: Function parameter or member 'dev' not described in 'drm_dp_downstream_mode' Some function parameters weren't documented. Fixes: 38784f6f8805 ("drm/dp: Add helpers to identify downstream facing port types") Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20200922175357.42998-2-lyude@redhat.com --- drivers/gpu/drm/drm_dp_helper.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpu/drm/drm_dp_helper.c') diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 90807a6b415c..478dd51f738d 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -374,6 +374,10 @@ static bool is_edid_digital_input_dp(const struct edid *edid) * drm_dp_downstream_is_type() - is the downstream facing port of certain type? * @dpcd: DisplayPort configuration data * @port_cap: port capabilities + * @type: port type to be checked. Can be: + * %DP_DS_PORT_TYPE_DP, %DP_DS_PORT_TYPE_VGA, %DP_DS_PORT_TYPE_DVI, + * %DP_DS_PORT_TYPE_HDMI, %DP_DS_PORT_TYPE_NON_EDID, + * %DP_DS_PORT_TYPE_DP_DUALMODE or %DP_DS_PORT_TYPE_WIRELESS. * * Caveat: Only works with DPCD 1.1+ port caps. * @@ -870,6 +874,7 @@ EXPORT_SYMBOL(drm_dp_downstream_444_to_420_conversion); /** * drm_dp_downstream_mode() - return a mode for downstream facing port + * @dev: DRM device * @dpcd: DisplayPort configuration data * @port_cap: port capabilities * -- cgit v1.2.3 From 9782f52ab5d65a667074beda11b12490935d608b Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 7 Oct 2020 20:09:15 +0300 Subject: drm/dp: Add LTTPR helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the helpers and register definitions needed to read out the common and per-PHY LTTPR capabilities and perform link training in the LTTPR non-transparent mode. v2: - Add drm_dp_dpcd_read_phy_link_status() and DP_PHY_LTTPR() here instead of adding these to i915. (Ville) v3: - Use memmove() to convert LTTPR to DPRX link status format. (Ville) Cc: dri-devel@lists.freedesktop.org Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Acked-by: Lyude Paul Acked-by: Daniel Vetter Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20201007170917.1764556-5-imre.deak@intel.com --- drivers/gpu/drm/drm_dp_helper.c | 232 +++++++++++++++++++++++++++++++++++++++- include/drm/drm_dp_helper.h | 62 +++++++++++ 2 files changed, 290 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/drm_dp_helper.c') diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 478dd51f738d..79732402336d 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -150,11 +150,8 @@ void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) } EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay); -void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +static void __drm_dp_link_train_channel_eq_delay(unsigned long rd_interval) { - unsigned long rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & - DP_TRAINING_AUX_RD_MASK; - if (rd_interval > 4) DRM_DEBUG_KMS("AUX interval %lu, out of range (max 4)\n", rd_interval); @@ -166,8 +163,35 @@ void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) usleep_range(rd_interval, rd_interval * 2); } + +void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + __drm_dp_link_train_channel_eq_delay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK); +} EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay); +void drm_dp_lttpr_link_train_clock_recovery_delay(void) +{ + usleep_range(100, 200); +} +EXPORT_SYMBOL(drm_dp_lttpr_link_train_clock_recovery_delay); + +static u8 dp_lttpr_phy_cap(const u8 phy_cap[DP_LTTPR_PHY_CAP_SIZE], int r) +{ + return phy_cap[r - DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1]; +} + +void drm_dp_lttpr_link_train_channel_eq_delay(const u8 phy_cap[DP_LTTPR_PHY_CAP_SIZE]) +{ + u8 interval = dp_lttpr_phy_cap(phy_cap, + DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1) & + DP_TRAINING_AUX_RD_MASK; + + __drm_dp_link_train_channel_eq_delay(interval); +} +EXPORT_SYMBOL(drm_dp_lttpr_link_train_channel_eq_delay); + u8 drm_dp_link_rate_to_bw_code(int link_rate) { /* Spec says link_bw = link_rate / 0.27Gbps */ @@ -363,6 +387,59 @@ int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, } EXPORT_SYMBOL(drm_dp_dpcd_read_link_status); +/** + * drm_dp_dpcd_read_phy_link_status - get the link status information for a DP PHY + * @aux: DisplayPort AUX channel + * @dp_phy: the DP PHY to get the link status for + * @link_status: buffer to return the status in + * + * Fetch the AUX DPCD registers for the DPRX or an LTTPR PHY link status. The + * layout of the returned @link_status matches the DPCD register layout of the + * DPRX PHY link status. + * + * Returns 0 if the information was read successfully or a negative error code + * on failure. + */ +int drm_dp_dpcd_read_phy_link_status(struct drm_dp_aux *aux, + enum drm_dp_phy dp_phy, + u8 link_status[DP_LINK_STATUS_SIZE]) +{ + int ret; + + if (dp_phy == DP_PHY_DPRX) { + ret = drm_dp_dpcd_read(aux, + DP_LANE0_1_STATUS, + link_status, + DP_LINK_STATUS_SIZE); + + if (ret < 0) + return ret; + + WARN_ON(ret != DP_LINK_STATUS_SIZE); + + return 0; + } + + ret = drm_dp_dpcd_read(aux, + DP_LANE0_1_STATUS_PHY_REPEATER(dp_phy), + link_status, + DP_LINK_STATUS_SIZE - 1); + + if (ret < 0) + return ret; + + WARN_ON(ret != DP_LINK_STATUS_SIZE - 1); + + /* Convert the LTTPR to the sink PHY link status layout */ + memmove(&link_status[DP_SINK_STATUS - DP_LANE0_1_STATUS + 1], + &link_status[DP_SINK_STATUS - DP_LANE0_1_STATUS], + DP_LINK_STATUS_SIZE - (DP_SINK_STATUS - DP_LANE0_1_STATUS) - 1); + link_status[DP_SINK_STATUS - DP_LANE0_1_STATUS] = 0; + + return 0; +} +EXPORT_SYMBOL(drm_dp_dpcd_read_phy_link_status); + static bool is_edid_digital_input_dp(const struct edid *edid) { return edid && edid->revision >= 4 && @@ -2098,6 +2175,153 @@ int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_S } EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs); +/** + * drm_dp_read_lttpr_common_caps - read the LTTPR common capabilities + * @aux: DisplayPort AUX channel + * @caps: buffer to return the capability info in + * + * Read capabilities common to all LTTPRs. + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux, + u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) +{ + int ret; + + ret = drm_dp_dpcd_read(aux, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, + caps, DP_LTTPR_COMMON_CAP_SIZE); + if (ret < 0) + return ret; + + WARN_ON(ret != DP_LTTPR_COMMON_CAP_SIZE); + + return 0; +} +EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps); + +/** + * drm_dp_read_lttpr_phy_caps - read the capabilities for a given LTTPR PHY + * @aux: DisplayPort AUX channel + * @dp_phy: LTTPR PHY to read the capabilities for + * @caps: buffer to return the capability info in + * + * Read the capabilities for the given LTTPR PHY. + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux, + enum drm_dp_phy dp_phy, + u8 caps[DP_LTTPR_PHY_CAP_SIZE]) +{ + int ret; + + ret = drm_dp_dpcd_read(aux, + DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy), + caps, DP_LTTPR_PHY_CAP_SIZE); + if (ret < 0) + return ret; + + WARN_ON(ret != DP_LTTPR_PHY_CAP_SIZE); + + return 0; +} +EXPORT_SYMBOL(drm_dp_read_lttpr_phy_caps); + +static u8 dp_lttpr_common_cap(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE], int r) +{ + return caps[r - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV]; +} + +/** + * drm_dp_lttpr_count - get the number of detected LTTPRs + * @caps: LTTPR common capabilities + * + * Get the number of detected LTTPRs from the LTTPR common capabilities info. + * + * Returns: + * -ERANGE if more than supported number (8) of LTTPRs are detected + * -EINVAL if the DP_PHY_REPEATER_CNT register contains an invalid value + * otherwise the number of detected LTTPRs + */ +int drm_dp_lttpr_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) +{ + u8 count = dp_lttpr_common_cap(caps, DP_PHY_REPEATER_CNT); + + switch (hweight8(count)) { + case 0: + return 0; + case 1: + return 8 - ilog2(count); + case 8: + return -ERANGE; + default: + return -EINVAL; + } +} +EXPORT_SYMBOL(drm_dp_lttpr_count); + +/** + * drm_dp_lttpr_max_link_rate - get the maximum link rate supported by all LTTPRs + * @caps: LTTPR common capabilities + * + * Returns the maximum link rate supported by all detected LTTPRs. + */ +int drm_dp_lttpr_max_link_rate(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) +{ + u8 rate = dp_lttpr_common_cap(caps, DP_MAX_LINK_RATE_PHY_REPEATER); + + return drm_dp_bw_code_to_link_rate(rate); +} +EXPORT_SYMBOL(drm_dp_lttpr_max_link_rate); + +/** + * drm_dp_lttpr_max_lane_count - get the maximum lane count supported by all LTTPRs + * @caps: LTTPR common capabilities + * + * Returns the maximum lane count supported by all detected LTTPRs. + */ +int drm_dp_lttpr_max_lane_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) +{ + u8 max_lanes = dp_lttpr_common_cap(caps, DP_MAX_LANE_COUNT_PHY_REPEATER); + + return max_lanes & DP_MAX_LANE_COUNT_MASK; +} +EXPORT_SYMBOL(drm_dp_lttpr_max_lane_count); + +/** + * drm_dp_lttpr_voltage_swing_level_3_supported - check for LTTPR vswing3 support + * @caps: LTTPR PHY capabilities + * + * Returns true if the @caps for an LTTPR TX PHY indicate support for + * voltage swing level 3. + */ +bool +drm_dp_lttpr_voltage_swing_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]) +{ + u8 txcap = dp_lttpr_phy_cap(caps, DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1); + + return txcap & DP_VOLTAGE_SWING_LEVEL_3_SUPPORTED; +} +EXPORT_SYMBOL(drm_dp_lttpr_voltage_swing_level_3_supported); + +/** + * drm_dp_lttpr_pre_emphasis_level_3_supported - check for LTTPR preemph3 support + * @caps: LTTPR PHY capabilities + * + * Returns true if the @caps for an LTTPR TX PHY indicate support for + * pre-emphasis level 3. + */ +bool +drm_dp_lttpr_pre_emphasis_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]) +{ + u8 txcap = dp_lttpr_phy_cap(caps, DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1); + + return txcap & DP_PRE_EMPHASIS_LEVEL_3_SUPPORTED; +} +EXPORT_SYMBOL(drm_dp_lttpr_pre_emphasis_level_3_supported); + /** * drm_dp_get_phy_test_pattern() - get the requested pattern from the sink. * @aux: DisplayPort AUX channel diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c9f2851904d0..8dbbfc7a8d83 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1066,15 +1066,58 @@ struct drm_device; #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 */ + +enum drm_dp_phy { + DP_PHY_DPRX, + + DP_PHY_LTTPR1, + DP_PHY_LTTPR2, + DP_PHY_LTTPR3, + DP_PHY_LTTPR4, + DP_PHY_LTTPR5, + DP_PHY_LTTPR6, + DP_PHY_LTTPR7, + DP_PHY_LTTPR8, + + DP_MAX_LTTPR_COUNT = DP_PHY_LTTPR8, +}; + +#define DP_PHY_LTTPR(i) (DP_PHY_LTTPR1 + (i)) + +#define __DP_LTTPR1_BASE 0xf0010 /* 1.3 */ +#define __DP_LTTPR2_BASE 0xf0060 /* 1.3 */ +#define DP_LTTPR_BASE(dp_phy) \ + (__DP_LTTPR1_BASE + (__DP_LTTPR2_BASE - __DP_LTTPR1_BASE) * \ + ((dp_phy) - DP_PHY_LTTPR1)) + +#define DP_LTTPR_REG(dp_phy, lttpr1_reg) \ + (DP_LTTPR_BASE(dp_phy) - DP_LTTPR_BASE(DP_PHY_LTTPR1) + (lttpr1_reg)) + #define DP_TRAINING_PATTERN_SET_PHY_REPEATER1 0xf0010 /* 1.3 */ +#define DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy) \ + DP_LTTPR_REG(dp_phy, DP_TRAINING_PATTERN_SET_PHY_REPEATER1) + #define DP_TRAINING_LANE0_SET_PHY_REPEATER1 0xf0011 /* 1.3 */ +#define DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy) \ + DP_LTTPR_REG(dp_phy, DP_TRAINING_LANE0_SET_PHY_REPEATER1) + #define DP_TRAINING_LANE1_SET_PHY_REPEATER1 0xf0012 /* 1.3 */ #define DP_TRAINING_LANE2_SET_PHY_REPEATER1 0xf0013 /* 1.3 */ #define DP_TRAINING_LANE3_SET_PHY_REPEATER1 0xf0014 /* 1.3 */ #define DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 0xf0020 /* 1.4a */ +#define DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy) \ + DP_LTTPR_REG(dp_phy, DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1) + #define DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1 0xf0021 /* 1.4a */ +# define DP_VOLTAGE_SWING_LEVEL_3_SUPPORTED BIT(0) +# define DP_PRE_EMPHASIS_LEVEL_3_SUPPORTED BIT(1) + #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) + #define DP_LANE2_3_STATUS_PHY_REPEATER1 0xf0031 /* 1.3 */ + #define DP_LANE_ALIGN_STATUS_UPDATED_PHY_REPEATER1 0xf0032 /* 1.3 */ #define DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 0xf0033 /* 1.3 */ #define DP_ADJUST_REQUEST_LANE2_3_PHY_REPEATER1 0xf0034 /* 1.3 */ @@ -1184,9 +1227,13 @@ u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZ #define DP_DSC_RECEIVER_CAP_SIZE 0xf #define EDP_PSR_RECEIVER_CAP_SIZE 2 #define EDP_DISPLAY_CTL_CAP_SIZE 3 +#define DP_LTTPR_COMMON_CAP_SIZE 8 +#define DP_LTTPR_PHY_CAP_SIZE 3 void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]); +void drm_dp_lttpr_link_train_clock_recovery_delay(void); void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]); +void drm_dp_lttpr_link_train_channel_eq_delay(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]); u8 drm_dp_link_rate_to_bw_code(int link_rate); int drm_dp_bw_code_to_link_rate(u8 link_bw); @@ -1645,6 +1692,10 @@ int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux, int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, u8 status[DP_LINK_STATUS_SIZE]); +int drm_dp_dpcd_read_phy_link_status(struct drm_dp_aux *aux, + enum drm_dp_phy dp_phy, + u8 link_status[DP_LINK_STATUS_SIZE]); + bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux, u8 real_edid_checksum); @@ -1694,6 +1745,17 @@ bool drm_dp_read_sink_count_cap(struct drm_connector *connector, const struct drm_dp_desc *desc); int drm_dp_read_sink_count(struct drm_dp_aux *aux); +int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux, + u8 caps[DP_LTTPR_COMMON_CAP_SIZE]); +int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux, + enum drm_dp_phy dp_phy, + u8 caps[DP_LTTPR_PHY_CAP_SIZE]); +int drm_dp_lttpr_count(const u8 cap[DP_LTTPR_COMMON_CAP_SIZE]); +int drm_dp_lttpr_max_link_rate(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]); +int drm_dp_lttpr_max_lane_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]); +bool drm_dp_lttpr_voltage_swing_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]); +bool drm_dp_lttpr_pre_emphasis_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]); + void drm_dp_remote_aux_init(struct drm_dp_aux *aux); void drm_dp_aux_init(struct drm_dp_aux *aux); int drm_dp_aux_register(struct drm_dp_aux *aux); -- cgit v1.2.3 From 055f8458d95a38c20e8360634255f684378179eb Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Fri, 9 Oct 2020 16:57:50 +0800 Subject: drm/i915: Force DPCD backlight mode for BOE 2270 panel BOE 2270 panel failed to control backlight brightness. Add it in edid quirks to force using DPCD backlight control. Then the brightness can be controlled. Signed-off-by: Aaron Ma Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20201009085750.88490-2-aaron.ma@canonical.com --- drivers/gpu/drm/drm_dp_helper.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/drm_dp_helper.c') diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 79732402336d..14ddf28ecac0 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -1954,6 +1954,7 @@ static const struct edid_quirk edid_quirk_list[] = { { MFG(0x4d, 0x10), PROD_ID(0xc7, 0x14), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) }, { MFG(0x4d, 0x10), PROD_ID(0xe6, 0x14), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) }, { MFG(0x4c, 0x83), PROD_ID(0x47, 0x41), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) }, + { MFG(0x09, 0xe5), PROD_ID(0xde, 0x08), BIT(DP_QUIRK_FORCE_DPCD_BACKLIGHT) }, }; #undef MFG -- cgit v1.2.3