From: Thierry Reding treding@nvidia.com
Hi,
Following up on the discussion about the usefulness of the drm_dp_link helpers, here's a new series that adds a couple of new DPCD parser functions and then pushes the drm_dp_link helpers down into drivers. For most drivers this was pretty easy to do since they didn't heavily rely on the struct drm_dp_link. I decided to move the drm_dp_link helpers to the Tegra driver because they are more heavily used there and I have a subsequent series that adds support for DisplayPort on various Tegra boards based on those helpers.
The plan is to merge this series into drm-misc once reviewed so that I can rebase my Tegra DP support patches on that, hopefully in time for v5.5.
I don't have access to the bridges, Rockchip or MSM hardware, so those drivers are only build-tested. Since this series really only replaces variables, I don't think there's a high risk of breaking anything.
Thierry
Thierry Reding (15): drm/dp: Sort includes alphabetically drm/dp: Remove a gratuituous blank line drm/dp: Add drm_dp_fast_training_cap() helper drm/dp: Add drm_dp_channel_coding_supported() helper drm/dp: Add drm_dp_alternate_scrambler_reset_cap() helper drm/dp: Read AUX read interval from DPCD drm/dp: Do not busy-loop during link training drm/dp: Use drm_dp_aux_rd_interval() drm/dp: Add helper to get post-cursor adjustments drm/bridge: analogix-anx78xx: Avoid drm_dp_link helpers drm/bridge: tc358767: Avoid drm_dp_link helpers drm/bridge: tc358767: Use DP nomenclature drm/msm: edp: Avoid drm_dp_link helpers drm/rockchip: Avoid drm_dp_link helpers drm/tegra: Move drm_dp_link helpers to Tegra DRM
drivers/gpu/drm/bridge/analogix-anx78xx.c | 57 ++++++-- drivers/gpu/drm/bridge/tc358767.c | 65 ++++++--- drivers/gpu/drm/drm_dp_helper.c | 167 +++------------------- drivers/gpu/drm/msm/edp/edp_ctrl.c | 70 ++++++--- drivers/gpu/drm/rockchip/cdn-dp-core.c | 12 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 3 +- drivers/gpu/drm/rockchip/cdn-dp-reg.c | 19 ++- drivers/gpu/drm/tegra/Makefile | 1 + drivers/gpu/drm/tegra/dp.c | 133 +++++++++++++++++ drivers/gpu/drm/tegra/dp.h | 26 ++++ drivers/gpu/drm/tegra/dpaux.c | 1 + drivers/gpu/drm/tegra/sor.c | 1 + include/drm/drm_dp_helper.h | 84 ++++++++--- 13 files changed, 395 insertions(+), 244 deletions(-) create mode 100644 drivers/gpu/drm/tegra/dp.c create mode 100644 drivers/gpu/drm/tegra/dp.h
From: Thierry Reding treding@nvidia.com
Keeping the list sorted alphabetically makes it much easier to determine where to add new includes.
Signed-off-by: Thierry Reding treding@nvidia.com --- include/drm/drm_dp_helper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index bf62b43aaf2b..52ff1f24a24d 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -23,9 +23,9 @@ #ifndef _DRM_DP_HELPER_H_ #define _DRM_DP_HELPER_H_
-#include <linux/types.h> -#include <linux/i2c.h> #include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/types.h>
/* * Unless otherwise noted, all values are from the DP 1.1a spec. Note that
Reviewed-by: Lyude Paul lyude@redhat.com
On Tue, 2019-10-15 at 16:34 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Keeping the list sorted alphabetically makes it much easier to determine where to add new includes.
Signed-off-by: Thierry Reding treding@nvidia.com
include/drm/drm_dp_helper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index bf62b43aaf2b..52ff1f24a24d 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -23,9 +23,9 @@ #ifndef _DRM_DP_HELPER_H_ #define _DRM_DP_HELPER_H_
-#include <linux/types.h> -#include <linux/i2c.h> #include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/types.h>
/*
- Unless otherwise noted, all values are from the DP 1.1a spec. Note that
From: Thierry Reding treding@nvidia.com
It's idiomatic to check the return value of a function call immediately after the function call, without any blank lines in between, to make it more obvious that the two lines belong together.
v2: fix outdated commit message (Philipp Zabel)
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/drm_dp_helper.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index f373798d82f6..8f2d7c4850ca 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -220,7 +220,6 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, }
ret = aux->transfer(aux, &msg); - if (ret >= 0) { native_reply = msg.reply & DP_AUX_NATIVE_REPLY_MASK; if (native_reply == DP_AUX_NATIVE_REPLY_ACK) {
Reviewed-by: Lyude Paul lyude@redhat.com
On Tue, 2019-10-15 at 16:34 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
It's idiomatic to check the return value of a function call immediately after the function call, without any blank lines in between, to make it more obvious that the two lines belong together.
v2: fix outdated commit message (Philipp Zabel)
Signed-off-by: Thierry Reding treding@nvidia.com
drivers/gpu/drm/drm_dp_helper.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index f373798d82f6..8f2d7c4850ca 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -220,7 +220,6 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, }
ret = aux->transfer(aux, &msg);
- if (ret >= 0) { native_reply = msg.reply & DP_AUX_NATIVE_REPLY_MASK; if (native_reply == DP_AUX_NATIVE_REPLY_ACK) {
From: Thierry Reding treding@nvidia.com
Add a helper that checks for the fast training capability given the DPCD receiver capabilities blob.
Signed-off-by: Thierry Reding treding@nvidia.com --- include/drm/drm_dp_helper.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 52ff1f24a24d..def3b3a543a2 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1211,6 +1211,13 @@ drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) (dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP); }
+static inline bool +drm_dp_fast_training_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_DPCD_REV] >= 0x11 && + (dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING); +} + static inline bool drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
Reviewed-by: Lyude Paul lyude@redhat.com
On Tue, 2019-10-15 at 16:34 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Add a helper that checks for the fast training capability given the DPCD receiver capabilities blob.
Signed-off-by: Thierry Reding treding@nvidia.com
include/drm/drm_dp_helper.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 52ff1f24a24d..def3b3a543a2 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1211,6 +1211,13 @@ drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) (dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP); }
+static inline bool +drm_dp_fast_training_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{
- return dpcd[DP_DPCD_REV] >= 0x11 &&
(dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING);
+}
static inline bool drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
From: Thierry Reding treding@nvidia.com
Add a helper to check whether the sink supports ANSI 8B/10B channel coding capability as specified in ANSI X3.230-1994, clause 11.
Signed-off-by: Thierry Reding treding@nvidia.com --- include/drm/drm_dp_helper.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index def3b3a543a2..7ff7bf0e742d 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -137,6 +137,7 @@ # define DP_DETAILED_CAP_INFO_AVAILABLE (1 << 4) /* DPI */
#define DP_MAIN_LINK_CHANNEL_CODING 0x006 +# define DP_CAP_ANSI_8B10B (1 << 0)
#define DP_DOWN_STREAM_PORT_COUNT 0x007 # define DP_PORT_COUNT_MASK 0x0f @@ -1283,6 +1284,12 @@ drm_dp_sink_supports_fec(const u8 fec_capable) return fec_capable & DP_FEC_CAPABLE; }
+static inline bool +drm_dp_channel_coding_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_8B10B; +} + /* * DisplayPort AUX channel */
Reviewed-by: Lyude Paul lyude@redhat.com
On Tue, 2019-10-15 at 16:34 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Add a helper to check whether the sink supports ANSI 8B/10B channel coding capability as specified in ANSI X3.230-1994, clause 11.
Signed-off-by: Thierry Reding treding@nvidia.com
include/drm/drm_dp_helper.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index def3b3a543a2..7ff7bf0e742d 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -137,6 +137,7 @@ # define DP_DETAILED_CAP_INFO_AVAILABLE (1 << 4) /* DPI */
#define DP_MAIN_LINK_CHANNEL_CODING 0x006 +# define DP_CAP_ANSI_8B10B (1 << 0)
#define DP_DOWN_STREAM_PORT_COUNT 0x007 # define DP_PORT_COUNT_MASK 0x0f @@ -1283,6 +1284,12 @@ drm_dp_sink_supports_fec(const u8 fec_capable) return fec_capable & DP_FEC_CAPABLE; }
+static inline bool +drm_dp_channel_coding_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{
- return dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_8B10B;
+}
/*
- DisplayPort AUX channel
*/
From: Thierry Reding treding@nvidia.com
Add a helper to check if the sink supports the eDP alternate scrambler reset value of 0xfffe.
Signed-off-by: Thierry Reding treding@nvidia.com --- include/drm/drm_dp_helper.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 7ff7bf0e742d..7a537ffc2fb1 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1290,6 +1290,13 @@ drm_dp_channel_coding_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) return dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_8B10B; }
+static inline bool +drm_dp_alternate_scrambler_reset_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_EDP_CONFIGURATION_CAP] & + DP_ALTERNATE_SCRAMBLER_RESET_CAP; +} + /* * DisplayPort AUX channel */
Reviewed-by: Lyude Paul lyude@redhat.com
On Tue, 2019-10-15 at 16:34 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Add a helper to check if the sink supports the eDP alternate scrambler reset value of 0xfffe.
Signed-off-by: Thierry Reding treding@nvidia.com
include/drm/drm_dp_helper.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 7ff7bf0e742d..7a537ffc2fb1 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1290,6 +1290,13 @@ drm_dp_channel_coding_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) return dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_8B10B; }
+static inline bool +drm_dp_alternate_scrambler_reset_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{
- return dpcd[DP_EDP_CONFIGURATION_CAP] &
DP_ALTERNATE_SCRAMBLER_RESET_CAP;
+}
/*
- DisplayPort AUX channel
*/
From: Thierry Reding treding@nvidia.com
Store the AUX read interval from DPCD, so that it can be used to wait for the durations given in the specification during link training.
Signed-off-by: Thierry Reding treding@nvidia.com --- include/drm/drm_dp_helper.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 7a537ffc2fb1..6c12de6f7e46 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -25,8 +25,11 @@
#include <linux/delay.h> #include <linux/i2c.h> +#include <linux/time64.h> #include <linux/types.h>
+#include <drm/drm_print.h> + /* * Unless otherwise noted, all values are from the DP 1.1a spec. Note that * DP and DPCD versions are independent. Differences from 1.0 are not noted, @@ -1297,6 +1300,36 @@ drm_dp_alternate_scrambler_reset_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) DP_ALTERNATE_SCRAMBLER_RESET_CAP; }
+/** + * drm_dp_read_aux_interval() - read the AUX read interval from the DPCD + * @dpcd: receiver capacity buffer + * + * Reads the AUX read interval (in microseconds) from the DPCD. Note that the + * TRAINING_AUX_RD_INTERVAL stores the value in units of 4 milliseconds. If no + * read interval is specified and for DPCD v1.4 and later, the read interval + * is always 100 microseconds. + * + * Returns: + * The read AUX interval in microseconds. + */ +static inline unsigned int +drm_dp_aux_rd_interval(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK; + + if (rd_interval > 4) + DRM_DEBUG_KMS("AUX interval %u, out of range (max: 4)\n", + rd_interval); + + if (rd_interval > 0 && dpcd[DP_DPCD_REV] < DP_DPCD_REV_14) + rd_interval *= 4 * USEC_PER_MSEC; + else + rd_interval = 100; + + return rd_interval; +} + /* * DisplayPort AUX channel */
On Tue, 2019-10-15 at 16:35 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Store the AUX read interval from DPCD, so that it can be used to wait for the durations given in the specification during link training.
Signed-off-by: Thierry Reding treding@nvidia.com
include/drm/drm_dp_helper.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 7a537ffc2fb1..6c12de6f7e46 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -25,8 +25,11 @@
#include <linux/delay.h> #include <linux/i2c.h> +#include <linux/time64.h> #include <linux/types.h>
+#include <drm/drm_print.h>
/*
- Unless otherwise noted, all values are from the DP 1.1a spec. Note that
- DP and DPCD versions are independent. Differences from 1.0 are not
noted, @@ -1297,6 +1300,36 @@ drm_dp_alternate_scrambler_reset_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) DP_ALTERNATE_SCRAMBLER_RESET_CAP; }
+/**
- drm_dp_read_aux_interval() - read the AUX read interval from the DPCD
- @dpcd: receiver capacity buffer
- Reads the AUX read interval (in microseconds) from the DPCD. Note that
the
- TRAINING_AUX_RD_INTERVAL stores the value in units of 4 milliseconds. If
no
- read interval is specified and for DPCD v1.4 and later, the read
interval
- is always 100 microseconds.
- Returns:
- The read AUX interval in microseconds.
- */
+static inline unsigned int +drm_dp_aux_rd_interval(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{
- unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
- if (rd_interval > 4)
DRM_DEBUG_KMS("AUX interval %u, out of range (max: 4)\n",
rd_interval);
Do you think it might be worth clamping the value to 4 here?
- if (rd_interval > 0 && dpcd[DP_DPCD_REV] < DP_DPCD_REV_14)
Also small nit pick: you can just use rd_interval instead of rd_interval > 0
rd_interval *= 4 * USEC_PER_MSEC;
- else
rd_interval = 100;
- return rd_interval;
+}
/*
- DisplayPort AUX channel
*/
On Fri, Oct 18, 2019 at 05:27:59PM -0400, Lyude Paul wrote:
On Tue, 2019-10-15 at 16:35 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Store the AUX read interval from DPCD, so that it can be used to wait for the durations given in the specification during link training.
Signed-off-by: Thierry Reding treding@nvidia.com
include/drm/drm_dp_helper.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 7a537ffc2fb1..6c12de6f7e46 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -25,8 +25,11 @@
#include <linux/delay.h> #include <linux/i2c.h> +#include <linux/time64.h> #include <linux/types.h>
+#include <drm/drm_print.h>
/*
- Unless otherwise noted, all values are from the DP 1.1a spec. Note that
- DP and DPCD versions are independent. Differences from 1.0 are not
noted, @@ -1297,6 +1300,36 @@ drm_dp_alternate_scrambler_reset_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) DP_ALTERNATE_SCRAMBLER_RESET_CAP; }
+/**
- drm_dp_read_aux_interval() - read the AUX read interval from the DPCD
- @dpcd: receiver capacity buffer
- Reads the AUX read interval (in microseconds) from the DPCD. Note that
the
- TRAINING_AUX_RD_INTERVAL stores the value in units of 4 milliseconds. If
no
- read interval is specified and for DPCD v1.4 and later, the read
interval
- is always 100 microseconds.
- Returns:
- The read AUX interval in microseconds.
- */
+static inline unsigned int +drm_dp_aux_rd_interval(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{
- unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
- if (rd_interval > 4)
DRM_DEBUG_KMS("AUX interval %u, out of range (max: 4)\n",
rd_interval);
Do you think it might be worth clamping the value to 4 here?
Yeah, I think that makes sense. It might also be worth increasing the log level for this, perhaps even make it a WARN to make sure we catch it when this happens.
- if (rd_interval > 0 && dpcd[DP_DPCD_REV] < DP_DPCD_REV_14)
Also small nit pick: you can just use rd_interval instead of rd_interval > 0
Yeah, I suppose so. I thought > 0 was making it really explicit, but I don't really mind either way.
Thierry
rd_interval *= 4 * USEC_PER_MSEC;
- else
rd_interval = 100;
- return rd_interval;
+}
/*
- DisplayPort AUX channel
*/
-- Cheers, Lyude Paul
From: Thierry Reding treding@nvidia.com
Use microsecond sleeps for the clock recovery and channel equalization delays during link training. The duration of these delays can be from 100 us up to 16 ms. It is rude to busy-loop for that amount of time.
While at it, also convert to standard coding style by putting the opening braces in a function definition on a new line.
v2: use correct multiplier for training delays (Philipp Zabel)
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/drm_dp_helper.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 8f2d7c4850ca..ad2671d2ee8f 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -120,33 +120,39 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SI } EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
-void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { - int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & - DP_TRAINING_AUX_RD_MASK; +void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK;
if (rd_interval > 4) - DRM_DEBUG_KMS("AUX interval %d, out of range (max 4)\n", + DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n", rd_interval);
if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14) - udelay(100); + rd_interval = 100; else - mdelay(rd_interval * 4); + rd_interval *= 4 * USEC_PER_MSEC; + + usleep_range(rd_interval, rd_interval * 2); } EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
-void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { - int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & - DP_TRAINING_AUX_RD_MASK; +void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK;
if (rd_interval > 4) - DRM_DEBUG_KMS("AUX interval %d, out of range (max 4)\n", + DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n", rd_interval);
if (rd_interval == 0) - udelay(400); + rd_interval = 400; else - mdelay(rd_interval * 4); + rd_interval *= 4 * USEC_PER_MSEC; + + usleep_range(rd_interval, rd_interval * 2); } EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
On Tue, 2019-10-15 at 16:35 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Use microsecond sleeps for the clock recovery and channel equalization delays during link training. The duration of these delays can be from 100 us up to 16 ms. It is rude to busy-loop for that amount of time.
While at it, also convert to standard coding style by putting the opening braces in a function definition on a new line.
v2: use correct multiplier for training delays (Philipp Zabel)
Signed-off-by: Thierry Reding treding@nvidia.com
drivers/gpu/drm/drm_dp_helper.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 8f2d7c4850ca..ad2671d2ee8f 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -120,33 +120,39 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SI } EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
-void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
- int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
+void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{
- unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
Did you mean to put this conversion from signed to unsigned in the previous patch?
if (rd_interval > 4)
DRM_DEBUG_KMS("AUX interval %d, out of range (max 4)\n",
DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n", rd_interval);
if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
udelay(100);
elserd_interval = 100;
mdelay(rd_interval * 4);
rd_interval *= 4 * USEC_PER_MSEC;
- usleep_range(rd_interval, rd_interval * 2);
} EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
-void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
- int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
+void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{
unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
if (rd_interval > 4)
DRM_DEBUG_KMS("AUX interval %d, out of range (max 4)\n",
DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n", rd_interval);
if (rd_interval == 0)
udelay(400);
elserd_interval = 400;
mdelay(rd_interval * 4);
rd_interval *= 4 * USEC_PER_MSEC;
- usleep_range(rd_interval, rd_interval * 2);
} EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
On Fri, Oct 18, 2019 at 05:31:19PM -0400, Lyude Paul wrote:
On Tue, 2019-10-15 at 16:35 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Use microsecond sleeps for the clock recovery and channel equalization delays during link training. The duration of these delays can be from 100 us up to 16 ms. It is rude to busy-loop for that amount of time.
While at it, also convert to standard coding style by putting the opening braces in a function definition on a new line.
v2: use correct multiplier for training delays (Philipp Zabel)
Signed-off-by: Thierry Reding treding@nvidia.com
drivers/gpu/drm/drm_dp_helper.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 8f2d7c4850ca..ad2671d2ee8f 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -120,33 +120,39 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SI } EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
-void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
- int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
+void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{
- unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
Did you mean to put this conversion from signed to unsigned in the previous patch?
It doesn't really belong in the previous patch, though I guess it might be better in the subsequent patch where the new interval helper is used from this function.
Thierry
if (rd_interval > 4)
DRM_DEBUG_KMS("AUX interval %d, out of range (max 4)\n",
DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n", rd_interval);
if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
udelay(100);
elserd_interval = 100;
mdelay(rd_interval * 4);
rd_interval *= 4 * USEC_PER_MSEC;
- usleep_range(rd_interval, rd_interval * 2);
} EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
-void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
- int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
+void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{
unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
if (rd_interval > 4)
DRM_DEBUG_KMS("AUX interval %d, out of range (max 4)\n",
DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n", rd_interval);
if (rd_interval == 0)
udelay(400);
elserd_interval = 400;
mdelay(rd_interval * 4);
rd_interval *= 4 * USEC_PER_MSEC;
- usleep_range(rd_interval, rd_interval * 2);
} EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
-- Cheers, Lyude Paul
From: Thierry Reding treding@nvidia.com
Make use of the newly added drm_dp_aux_rd_interval() helper in existing DP link training helpers.
v2: drop stale sentence from commit message (Philipp Zabel)
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/drm_dp_helper.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index ad2671d2ee8f..4b66010771fa 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -122,17 +122,7 @@ EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { - unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & - DP_TRAINING_AUX_RD_MASK; - - if (rd_interval > 4) - DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n", - rd_interval); - - if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14) - rd_interval = 100; - else - rd_interval *= 4 * USEC_PER_MSEC; + unsigned int rd_interval = drm_dp_aux_rd_interval(dpcd);
usleep_range(rd_interval, rd_interval * 2); } @@ -140,19 +130,9 @@ EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { - unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & - DP_TRAINING_AUX_RD_MASK; - - if (rd_interval > 4) - DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n", - rd_interval); + unsigned int min = drm_dp_aux_rd_interval(dpcd);
- if (rd_interval == 0) - rd_interval = 400; - else - rd_interval *= 4 * USEC_PER_MSEC; - - usleep_range(rd_interval, rd_interval * 2); + usleep_range(min, min * 2); } EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
This also seems like maybe it should just go into the previous patch?
On Tue, 2019-10-15 at 16:35 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Make use of the newly added drm_dp_aux_rd_interval() helper in existing DP link training helpers.
v2: drop stale sentence from commit message (Philipp Zabel)
Signed-off-by: Thierry Reding treding@nvidia.com
drivers/gpu/drm/drm_dp_helper.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index ad2671d2ee8f..4b66010771fa 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -122,17 +122,7 @@ EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
- unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
- if (rd_interval > 4)
DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n",
rd_interval);
- if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
rd_interval = 100;
- else
rd_interval *= 4 * USEC_PER_MSEC;
unsigned int rd_interval = drm_dp_aux_rd_interval(dpcd);
usleep_range(rd_interval, rd_interval * 2);
} @@ -140,19 +130,9 @@ EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
- unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
- if (rd_interval > 4)
DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n",
rd_interval);
- unsigned int min = drm_dp_aux_rd_interval(dpcd);
- if (rd_interval == 0)
rd_interval = 400;
- else
rd_interval *= 4 * USEC_PER_MSEC;
- usleep_range(rd_interval, rd_interval * 2);
- usleep_range(min, min * 2);
} EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
On Fri, Oct 18, 2019 at 05:33:12PM -0400, Lyude Paul wrote:
This also seems like maybe it should just go into the previous patch?
I suppose they could both be merged, but I think it's better to keep them separate. In fact, I'm having second thoughts about the new helper because it doesn't really take into account all the special cases. For example, the patch below will use the value returned from the helper independent of context, whereas according to the specification the value is different if used for clock recovery (100 us) or if it is used for channel equalization (400 us).
Perhaps a better order would be for the "do not busy loop" patch to go first and then introduce the new helper and finally use the new helper (along with the signed -> unsigned change) in a third patch while taking care of using the right values all the time.
I'll respin these patches and send out the fixes in a v2.
Thierry
On Tue, 2019-10-15 at 16:35 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Make use of the newly added drm_dp_aux_rd_interval() helper in existing DP link training helpers.
v2: drop stale sentence from commit message (Philipp Zabel)
Signed-off-by: Thierry Reding treding@nvidia.com
drivers/gpu/drm/drm_dp_helper.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index ad2671d2ee8f..4b66010771fa 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -122,17 +122,7 @@ EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
- unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
- if (rd_interval > 4)
DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n",
rd_interval);
- if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
rd_interval = 100;
- else
rd_interval *= 4 * USEC_PER_MSEC;
unsigned int rd_interval = drm_dp_aux_rd_interval(dpcd);
usleep_range(rd_interval, rd_interval * 2);
} @@ -140,19 +130,9 @@ EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) {
- unsigned int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_TRAINING_AUX_RD_MASK;
- if (rd_interval > 4)
DRM_DEBUG_KMS("AUX interval %u, out of range (max 4)\n",
rd_interval);
- unsigned int min = drm_dp_aux_rd_interval(dpcd);
- if (rd_interval == 0)
rd_interval = 400;
- else
rd_interval *= 4 * USEC_PER_MSEC;
- usleep_range(rd_interval, rd_interval * 2);
- usleep_range(min, min * 2);
} EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
-- Cheers, Lyude Paul
From: Thierry Reding treding@nvidia.com
If the transmitter supports pre-emphasis post cursor2 the sink will request adjustments in a similar way to how it requests adjustments to the voltage swing and pre-emphasis settings.
Add a helper to extract these adjustments on a per-lane basis from the DPCD link status.
Reviewed-by: Philipp Zabel p.zabel@pengutronix.de Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/drm_dp_helper.c | 10 ++++++++++ include/drm/drm_dp_helper.h | 10 ++++++++++ 2 files changed, 20 insertions(+)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 4b66010771fa..de8ff8ddb445 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -120,6 +120,16 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SI } EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
+u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE], + unsigned int lane) +{ + unsigned int offset = DP_ADJUST_REQUEST_POST_CURSOR2; + u8 value = dp_link_status(link_status, offset); + + return (value >> (lane << 1)) & 0x3; +} +EXPORT_SYMBOL(drm_dp_get_adjust_request_post_cursor); + void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { unsigned int rd_interval = drm_dp_aux_rd_interval(dpcd); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 6c12de6f7e46..e0b2c03f3cbb 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -608,6 +608,14 @@ # define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6
#define DP_ADJUST_REQUEST_POST_CURSOR2 0x20c +# define DP_ADJUST_POST_CURSOR2_LANE0_MASK 0x03 +# define DP_ADJUST_POST_CURSOR2_LANE0_SHIFT 0 +# define DP_ADJUST_POST_CURSOR2_LANE1_MASK 0x0c +# define DP_ADJUST_POST_CURSOR2_LANE1_SHIFT 2 +# define DP_ADJUST_POST_CURSOR2_LANE2_MASK 0x30 +# define DP_ADJUST_POST_CURSOR2_LANE2_SHIFT 4 +# define DP_ADJUST_POST_CURSOR2_LANE3_MASK 0xc0 +# define DP_ADJUST_POST_CURSOR2_LANE3_SHIFT 6
#define DP_TEST_REQUEST 0x218 # define DP_TEST_LINK_TRAINING (1 << 0) @@ -1121,6 +1129,8 @@ u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], 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_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE], + unsigned int lane);
#define DP_BRANCH_OUI_HEADER_SIZE 0xc #define DP_RECEIVER_CAP_SIZE 0xf
Reviewed-by: Lyude Paul lyude@redhat.com
On Tue, 2019-10-15 at 16:35 +0200, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
If the transmitter supports pre-emphasis post cursor2 the sink will request adjustments in a similar way to how it requests adjustments to the voltage swing and pre-emphasis settings.
Add a helper to extract these adjustments on a per-lane basis from the DPCD link status.
Reviewed-by: Philipp Zabel p.zabel@pengutronix.de Signed-off-by: Thierry Reding treding@nvidia.com
drivers/gpu/drm/drm_dp_helper.c | 10 ++++++++++ include/drm/drm_dp_helper.h | 10 ++++++++++ 2 files changed, 20 insertions(+)
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 4b66010771fa..de8ff8ddb445 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -120,6 +120,16 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SI } EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis);
+u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE],
unsigned int lane)
+{
- unsigned int offset = DP_ADJUST_REQUEST_POST_CURSOR2;
- u8 value = dp_link_status(link_status, offset);
- return (value >> (lane << 1)) & 0x3;
+} +EXPORT_SYMBOL(drm_dp_get_adjust_request_post_cursor);
void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { unsigned int rd_interval = drm_dp_aux_rd_interval(dpcd); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 6c12de6f7e46..e0b2c03f3cbb 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -608,6 +608,14 @@ # define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6
#define DP_ADJUST_REQUEST_POST_CURSOR2 0x20c +# define DP_ADJUST_POST_CURSOR2_LANE0_MASK 0x03 +# define DP_ADJUST_POST_CURSOR2_LANE0_SHIFT 0 +# define DP_ADJUST_POST_CURSOR2_LANE1_MASK 0x0c +# define DP_ADJUST_POST_CURSOR2_LANE1_SHIFT 2 +# define DP_ADJUST_POST_CURSOR2_LANE2_MASK 0x30 +# define DP_ADJUST_POST_CURSOR2_LANE2_SHIFT 4 +# define DP_ADJUST_POST_CURSOR2_LANE3_MASK 0xc0 +# define DP_ADJUST_POST_CURSOR2_LANE3_SHIFT 6
#define DP_TEST_REQUEST 0x218 # define DP_TEST_LINK_TRAINING (1 << 0) @@ -1121,6 +1129,8 @@ u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], 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_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZE],
unsigned int lane);
#define DP_BRANCH_OUI_HEADER_SIZE 0xc #define DP_RECEIVER_CAP_SIZE 0xf
From: Thierry Reding treding@nvidia.com
During the discussion of patches that enhance the drm_dp_link helpers it was concluded that these helpers aren't very useful to begin with. Start pushing the equivalent code into individual drivers to ultimately remove them.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/bridge/analogix-anx78xx.c | 57 +++++++++++++++++------ 1 file changed, 42 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index 9ddc1f3cf841..8bb4793f382b 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -71,7 +71,6 @@ struct anx78xx { struct i2c_client *client; struct edid *edid; struct drm_connector connector; - struct drm_dp_link link; struct anx78xx_platform_data pdata; struct mutex lock;
@@ -801,18 +800,34 @@ static int anx78xx_dp_link_training(struct anx78xx *anx78xx) if (err) return err;
- /* Check link capabilities */ - err = drm_dp_link_probe(&anx78xx->aux, &anx78xx->link); - if (err < 0) { - DRM_ERROR("Failed to probe link capabilities: %d\n", err); - return err; - } + /* + * Power up the sink (DP_SET_POWER register is only available on DPCD + * v1.1 and later). + */ + if (anx78xx->dpcd[DP_DPCD_REV] >= 0x11) { + err = drm_dp_dpcd_readb(&anx78xx->aux, DP_SET_POWER, &value); + if (err < 0) { + DRM_ERROR("Failed to read DP_SET_POWER register: %d\n", + err); + return err; + }
- /* Power up the sink */ - err = drm_dp_link_power_up(&anx78xx->aux, &anx78xx->link); - if (err < 0) { - DRM_ERROR("Failed to power up DisplayPort link: %d\n", err); - return err; + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D0; + + err = drm_dp_dpcd_writeb(&anx78xx->aux, DP_SET_POWER, value); + if (err < 0) { + DRM_ERROR("Failed to power up DisplayPort link: %d\n", + err); + return err; + } + + /* + * According to the DP 1.1 specification, a "Sink Device must + * exit the power saving state within 1 ms" (Section 2.5.3.1, + * Table 5-52, "Sink Control Field" (register 0x600). + */ + usleep_range(1000, 2000); }
/* Possibly enable downspread on the sink */ @@ -851,15 +866,27 @@ static int anx78xx_dp_link_training(struct anx78xx *anx78xx) if (err) return err;
- value = drm_dp_link_rate_to_bw_code(anx78xx->link.rate); + value = drm_dp_max_link_rate(anx78xx->dpcd); + value = drm_dp_link_rate_to_bw_code(value); err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_DP_MAIN_LINK_BW_SET_REG, value); if (err) return err;
- err = drm_dp_link_configure(&anx78xx->aux, &anx78xx->link); + err = drm_dp_dpcd_writeb(&anx78xx->aux, DP_LINK_BW_SET, value); + if (err < 0) { + DRM_ERROR("Failed to set link bandwidth: %d\n", err); + return err; + } + + value = drm_dp_max_lane_count(anx78xx->dpcd); + + if (drm_dp_enhanced_frame_cap(anx78xx->dpcd)) + value |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + err = drm_dp_dpcd_writeb(&anx78xx->aux, DP_LANE_COUNT_SET, value); if (err < 0) { - DRM_ERROR("Failed to configure DisplayPort link: %d\n", err); + DRM_ERROR("Failed to set link lane count: %d\n", err); return err; }
From: Thierry Reding treding@nvidia.com
During the discussion of patches that enhance the drm_dp_link helpers it was concluded that these helpers aren't very useful to begin with. Start pushing the equivalent code into individual drivers to ultimately remove them.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/bridge/tc358767.c | 63 ++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index da7e35b0893d..89063d597262 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -229,7 +229,9 @@ static bool tc_test_pattern; module_param_named(test, tc_test_pattern, bool, 0644);
struct tc_edp_link { - struct drm_dp_link base; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + u8 rate; + u8 num_lanes; u8 assr; bool scrambler_dis; bool spread; @@ -438,9 +440,9 @@ static u32 tc_srcctrl(struct tc_data *tc) reg |= DP0_SRCCTRL_SCRMBLDIS; /* Scrambler Disabled */ if (tc->link.spread) reg |= DP0_SRCCTRL_SSCG; /* Spread Spectrum Enable */ - if (tc->link.base.num_lanes == 2) + if (tc->link.num_lanes == 2) reg |= DP0_SRCCTRL_LANES_2; /* Two Main Channel Lanes */ - if (tc->link.base.rate != 162000) + if (tc->link.rate != 162000) reg |= DP0_SRCCTRL_BW27; /* 2.7 Gbps link */ return reg; } @@ -663,23 +665,35 @@ static int tc_aux_link_setup(struct tc_data *tc)
static int tc_get_display_props(struct tc_data *tc) { + u8 revision, num_lanes; + unsigned int rate; int ret; u8 reg;
/* Read DP Rx Link Capability */ - ret = drm_dp_link_probe(&tc->aux, &tc->link.base); + ret = drm_dp_dpcd_read(&tc->aux, DP_DPCD_REV, tc->link.dpcd, + DP_RECEIVER_CAP_SIZE); if (ret < 0) goto err_dpcd_read; - if (tc->link.base.rate != 162000 && tc->link.base.rate != 270000) { + + revision = tc->link.dpcd[DP_DPCD_REV]; + rate = drm_dp_max_link_rate(tc->link.dpcd); + num_lanes = drm_dp_max_lane_count(tc->link.dpcd); + + if (rate != 162000 && rate != 270000) { dev_dbg(tc->dev, "Falling to 2.7 Gbps rate\n"); - tc->link.base.rate = 270000; + rate = 270000; }
- if (tc->link.base.num_lanes > 2) { + tc->link.rate = rate; + + if (num_lanes > 2) { dev_dbg(tc->dev, "Falling to 2 lanes\n"); - tc->link.base.num_lanes = 2; + num_lanes = 2; }
+ tc->link.num_lanes = num_lanes; + ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, ®); if (ret < 0) goto err_dpcd_read; @@ -697,10 +711,10 @@ static int tc_get_display_props(struct tc_data *tc) tc->link.assr = reg & DP_ALTERNATE_SCRAMBLER_RESET_ENABLE;
dev_dbg(tc->dev, "DPCD rev: %d.%d, rate: %s, lanes: %d, framing: %s\n", - tc->link.base.revision >> 4, tc->link.base.revision & 0x0f, - (tc->link.base.rate == 162000) ? "1.62Gbps" : "2.7Gbps", - tc->link.base.num_lanes, - (tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) ? + revision >> 4, revision & 0x0f, + (tc->link.rate == 162000) ? "1.62Gbps" : "2.7Gbps", + tc->link.num_lanes, + drm_dp_enhanced_frame_cap(tc->link.dpcd) ? "enhanced" : "non-enhanced"); dev_dbg(tc->dev, "Downspread: %s, scrambler: %s\n", tc->link.spread ? "0.5%" : "0.0%", @@ -740,7 +754,7 @@ static int tc_set_video_mode(struct tc_data *tc, */
in_bw = mode->clock * bits_per_pixel / 8; - out_bw = tc->link.base.num_lanes * tc->link.base.rate; + out_bw = tc->link.num_lanes * tc->link.rate; max_tu_symbol = DIV_ROUND_UP(in_bw * TU_SIZE_RECOMMENDED, out_bw);
dev_dbg(tc->dev, "set mode %dx%d\n", @@ -902,7 +916,7 @@ static int tc_main_link_enable(struct tc_data *tc) /* SSCG and BW27 on DP1 must be set to the same as on DP0 */ ret = regmap_write(tc->regmap, DP1_SRCCTRL, (tc->link.spread ? DP0_SRCCTRL_SSCG : 0) | - ((tc->link.base.rate != 162000) ? DP0_SRCCTRL_BW27 : 0)); + ((tc->link.rate != 162000) ? DP0_SRCCTRL_BW27 : 0)); if (ret) return ret;
@@ -912,7 +926,7 @@ static int tc_main_link_enable(struct tc_data *tc)
/* Setup Main Link */ dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN | PHY_M0_EN; - if (tc->link.base.num_lanes == 2) + if (tc->link.num_lanes == 2) dp_phy_ctrl |= PHY_2LANE;
ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl); @@ -975,7 +989,13 @@ static int tc_main_link_enable(struct tc_data *tc) }
/* Setup Link & DPRx Config for Training */ - ret = drm_dp_link_configure(aux, &tc->link.base); + tmp[0] = drm_dp_link_rate_to_bw_code(tc->link.rate); + tmp[1] = tc->link.num_lanes; + + if (drm_dp_enhanced_frame_cap(tc->link.dpcd)) + tmp[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + ret = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, tmp, 2); if (ret < 0) goto err_dpcd_write;
@@ -1019,9 +1039,8 @@ static int tc_main_link_enable(struct tc_data *tc)
/* Enable DP0 to start Link Training */ ret = regmap_write(tc->regmap, DP0CTL, - ((tc->link.base.capabilities & - DP_LINK_CAP_ENHANCED_FRAMING) ? EF_EN : 0) | - DP_EN); + (drm_dp_enhanced_frame_cap(tc->link.dpcd) ? + EF_EN : 0) | DP_EN); if (ret) return ret;
@@ -1100,7 +1119,7 @@ static int tc_main_link_enable(struct tc_data *tc) ret = -ENODEV; }
- if (tc->link.base.num_lanes == 2) { + if (tc->link.num_lanes == 2) { value = (tmp[0] >> 4) & DP_CHANNEL_EQ_BITS;
if (value != DP_CHANNEL_EQ_BITS) { @@ -1171,7 +1190,7 @@ static int tc_stream_enable(struct tc_data *tc) return ret;
value = VID_MN_GEN | DP_EN; - if (tc->link.base.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) + if (drm_dp_enhanced_frame_cap(tc->link.dpcd)) value |= EF_EN; ret = regmap_write(tc->regmap, DP0CTL, value); if (ret) @@ -1297,7 +1316,7 @@ static enum drm_mode_status tc_mode_valid(struct drm_bridge *bridge, return MODE_CLOCK_HIGH;
req = mode->clock * bits_per_pixel / 8; - avail = tc->link.base.num_lanes * tc->link.base.rate; + avail = tc->link.num_lanes * tc->link.rate;
if (req > avail) return MODE_BAD;
From: Thierry Reding treding@nvidia.com
The DP specification uses the term "default framing" instead of "non- enhanced framing".
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/bridge/tc358767.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 89063d597262..cd00372b25ad 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -715,7 +715,7 @@ static int tc_get_display_props(struct tc_data *tc) (tc->link.rate == 162000) ? "1.62Gbps" : "2.7Gbps", tc->link.num_lanes, drm_dp_enhanced_frame_cap(tc->link.dpcd) ? - "enhanced" : "non-enhanced"); + "enhanced" : "default"); dev_dbg(tc->dev, "Downspread: %s, scrambler: %s\n", tc->link.spread ? "0.5%" : "0.0%", tc->link.scrambler_dis ? "disabled" : "enabled");
From: Thierry Reding treding@nvidia.com
During the discussion of patches that enhance the drm_dp_link helpers it was concluded that these helpers aren't very useful to begin with. Start pushing the equivalent code into individual drivers to ultimately remove them.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/msm/edp/edp_ctrl.c | 70 +++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 7f3dd3ffe2c9..0d9657cc70db 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -89,7 +89,6 @@ struct edp_ctrl { /* edid raw data */ struct edid *edid;
- struct drm_dp_link dp_link; struct drm_dp_aux *drm_aux;
/* dpcd raw data */ @@ -403,7 +402,7 @@ static void edp_fill_link_cfg(struct edp_ctrl *ctrl) u32 prate; u32 lrate; u32 bpp; - u8 max_lane = ctrl->dp_link.num_lanes; + u8 max_lane = drm_dp_max_lane_count(ctrl->dpcd); u8 lane;
prate = ctrl->pixel_rate; @@ -413,7 +412,7 @@ static void edp_fill_link_cfg(struct edp_ctrl *ctrl) * By default, use the maximum link rate and minimum lane count, * so that we can do rate down shift during link training. */ - ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate); + ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE];
prate *= bpp; prate /= 8; /* in kByte */ @@ -439,7 +438,7 @@ static void edp_config_ctrl(struct edp_ctrl *ctrl)
data = EDP_CONFIGURATION_CTRL_LANES(ctrl->lane_cnt - 1);
- if (ctrl->dp_link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) + if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) data |= EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING;
depth = EDP_6BIT; @@ -701,7 +700,7 @@ static int edp_link_rate_down_shift(struct edp_ctrl *ctrl)
rate = ctrl->link_rate; lane = ctrl->lane_cnt; - max_lane = ctrl->dp_link.num_lanes; + max_lane = drm_dp_max_lane_count(ctrl->dpcd);
bpp = ctrl->color_depth * 3; prate = ctrl->pixel_rate; @@ -751,18 +750,22 @@ static int edp_clear_training_pattern(struct edp_ctrl *ctrl)
static int edp_do_link_train(struct edp_ctrl *ctrl) { + u8 values[2]; int ret; - struct drm_dp_link dp_link;
DBG(""); /* * Set the current link rate and lane cnt to panel. They may have been * adjusted and the values are different from them in DPCD CAP */ - dp_link.num_lanes = ctrl->lane_cnt; - dp_link.rate = drm_dp_bw_code_to_link_rate(ctrl->link_rate); - dp_link.capabilities = ctrl->dp_link.capabilities; - if (drm_dp_link_configure(ctrl->drm_aux, &dp_link) < 0) + values[0] = ctrl->lane_cnt; + values[1] = ctrl->link_rate; + + if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) + values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + if (drm_dp_dpcd_write(ctrl->drm_aux, DP_LINK_BW_SET, values, + sizeof(values)) < 0) return EDP_TRAIN_FAIL;
ctrl->v_level = 0; /* start from default level */ @@ -952,6 +955,7 @@ static void edp_ctrl_on_worker(struct work_struct *work) { struct edp_ctrl *ctrl = container_of( work, struct edp_ctrl, on_work); + u8 value; int ret;
mutex_lock(&ctrl->dev_mutex); @@ -965,9 +969,27 @@ static void edp_ctrl_on_worker(struct work_struct *work) edp_ctrl_link_enable(ctrl, 1);
edp_ctrl_irq_enable(ctrl, 1); - ret = drm_dp_link_power_up(ctrl->drm_aux, &ctrl->dp_link); - if (ret) - goto fail; + + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ + if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { + ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); + if (ret < 0) + goto fail; + + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D0; + + ret = drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); + if (ret < 0) + goto fail; + + /* + * According to the DP 1.1 specification, a "Sink Device must + * exit the power saving state within 1 ms" (Section 2.5.3.1, + * Table 5-52, "Sink Control Field" (register 0x600). + */ + usleep_range(1000, 2000); + }
ctrl->power_on = true;
@@ -1011,7 +1033,19 @@ static void edp_ctrl_off_worker(struct work_struct *work)
edp_state_ctrl(ctrl, 0);
- drm_dp_link_power_down(ctrl->drm_aux, &ctrl->dp_link); + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ + if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { + u8 value; + int ret; + + ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); + if (ret > 0) { + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D3; + + drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); + } + }
edp_ctrl_irq_enable(ctrl, 0);
@@ -1225,14 +1259,8 @@ int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, edp_ctrl_irq_enable(ctrl, 1); }
- ret = drm_dp_link_probe(ctrl->drm_aux, &ctrl->dp_link); - if (ret) { - pr_err("%s: read dpcd cap failed, %d\n", __func__, ret); - goto disable_ret; - } - /* Initialize link rate as panel max link rate */ - ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate); + ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE];
ctrl->edid = drm_get_edid(connector, &ctrl->drm_aux->ddc); if (!ctrl->edid) {
From: Thierry Reding treding@nvidia.com
During the discussion of patches that enhance the drm_dp_link helpers it was concluded that these helpers aren't very useful to begin with. Start pushing the equivalent code into individual drivers to ultimately remove them.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/rockchip/cdn-dp-core.c | 12 ++++++------ drivers/gpu/drm/rockchip/cdn-dp-core.h | 3 ++- drivers/gpu/drm/rockchip/cdn-dp-reg.c | 19 +++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index d505ea7d5384..eed594bd38d3 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -477,8 +477,8 @@ static int cdn_dp_disable(struct cdn_dp_device *dp) cdn_dp_set_firmware_active(dp, false); cdn_dp_clk_disable(dp); dp->active = false; - dp->link.rate = 0; - dp->link.num_lanes = 0; + dp->max_lanes = 0; + dp->max_rate = 0; if (!dp->connected) { kfree(dp->edid); dp->edid = NULL; @@ -570,7 +570,7 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) struct cdn_dp_port *port = cdn_dp_connected_port(dp); u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd);
- if (!port || !dp->link.rate || !dp->link.num_lanes) + if (!port || !dp->max_rate || !dp->max_lanes) return false;
if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, @@ -952,8 +952,8 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
/* Enabled and connected with a sink, re-train if requested */ } else if (!cdn_dp_check_link_status(dp)) { - unsigned int rate = dp->link.rate; - unsigned int lanes = dp->link.num_lanes; + unsigned int rate = dp->max_rate; + unsigned int lanes = dp->max_lanes; struct drm_display_mode *mode = &dp->mode;
DRM_DEV_INFO(dp->dev, "Connected with sink. Re-train link\n"); @@ -966,7 +966,7 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
/* If training result is changed, update the video config */ if (mode->clock && - (rate != dp->link.rate || lanes != dp->link.num_lanes)) { + (rate != dp->max_rate || lanes != dp->max_lanes)) { ret = cdn_dp_config_video(dp); if (ret) { dp->connected = false; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index b85ea89eb60b..83c4586665b4 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -92,9 +92,10 @@ struct cdn_dp_device { struct reset_control *core_rst; struct audio_info audio_info; struct video_info video_info; - struct drm_dp_link link; struct cdn_dp_port *port[MAX_PHY]; u8 ports; + u8 max_lanes; + u8 max_rate; u8 lanes; int active_port;
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index 077c87021908..7361c07cb4a7 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -535,8 +535,8 @@ static int cdn_dp_get_training_status(struct cdn_dp_device *dp) if (ret) goto err_get_training_status;
- dp->link.rate = drm_dp_bw_code_to_link_rate(status[0]); - dp->link.num_lanes = status[1]; + dp->max_rate = drm_dp_bw_code_to_link_rate(status[0]); + dp->max_lanes = status[1];
err_get_training_status: if (ret) @@ -560,8 +560,8 @@ int cdn_dp_train_link(struct cdn_dp_device *dp) return ret; }
- DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->link.rate, - dp->link.num_lanes); + DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->max_rate, + dp->max_lanes); return ret; }
@@ -639,7 +639,7 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? (video->color_depth * 2) : (video->color_depth * 3);
- link_rate = dp->link.rate / 1000; + link_rate = dp->max_rate / 1000;
ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); if (ret) @@ -659,14 +659,13 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) do { tu_size_reg += 2; symbol = tu_size_reg * mode->clock * bit_per_pix; - do_div(symbol, dp->link.num_lanes * link_rate * 8); + do_div(symbol, dp->max_lanes * link_rate * 8); rem = do_div(symbol, 1000); if (tu_size_reg > 64) { ret = -EINVAL; DRM_DEV_ERROR(dp->dev, "tu error, clk:%d, lanes:%d, rate:%d\n", - mode->clock, dp->link.num_lanes, - link_rate); + mode->clock, dp->max_lanes, link_rate); goto err_config_video; } } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || @@ -680,7 +679,7 @@ int cdn_dp_config_video(struct cdn_dp_device *dp)
/* set the FIFO Buffer size */ val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate; - val /= (dp->link.num_lanes * link_rate); + val /= (dp->max_lanes * link_rate); val = div_u64(8 * (symbol + 1), bit_per_pix) - val; val += 2; ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val); @@ -833,7 +832,7 @@ static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp, u32 val;
if (audio->channels == 2) { - if (dp->link.num_lanes == 1) + if (dp->max_lanes == 1) sub_pckt_num = 2; else sub_pckt_num = 4;
From: Thierry Reding treding@nvidia.com
During the discussion of patches that enhance the drm_dp_link helpers it was concluded that these helpers aren't very useful to begin with. After all other drivers have been converted not to use these helpers anymore, move these helpers into the last remaining user: Tegra DRM.
If at some point these helpers are deemed more widely useful, they can be moved out into the DRM DP helpers again.
Signed-off-by: Thierry Reding treding@nvidia.com --- drivers/gpu/drm/drm_dp_helper.c | 128 ------------------------------ drivers/gpu/drm/tegra/Makefile | 1 + drivers/gpu/drm/tegra/dp.c | 133 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/tegra/dp.h | 26 +++++++ drivers/gpu/drm/tegra/dpaux.c | 1 + drivers/gpu/drm/tegra/sor.c | 1 + include/drm/drm_dp_helper.h | 16 ---- 7 files changed, 162 insertions(+), 144 deletions(-) create mode 100644 drivers/gpu/drm/tegra/dp.c create mode 100644 drivers/gpu/drm/tegra/dp.h
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index de8ff8ddb445..2db9e1db92b3 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -331,134 +331,6 @@ int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, } EXPORT_SYMBOL(drm_dp_dpcd_read_link_status);
-/** - * drm_dp_link_probe() - probe a DisplayPort link for capabilities - * @aux: DisplayPort AUX channel - * @link: pointer to structure in which to return link capabilities - * - * The structure filled in by this function can usually be passed directly - * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and - * configure the link based on the link's capabilities. - * - * Returns 0 on success or a negative error code on failure. - */ -int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link) -{ - u8 values[3]; - int err; - - memset(link, 0, sizeof(*link)); - - err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values)); - if (err < 0) - return err; - - link->revision = values[0]; - link->rate = drm_dp_bw_code_to_link_rate(values[1]); - link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK; - - if (values[2] & DP_ENHANCED_FRAME_CAP) - link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; - - return 0; -} -EXPORT_SYMBOL(drm_dp_link_probe); - -/** - * drm_dp_link_power_up() - power up a DisplayPort link - * @aux: DisplayPort AUX channel - * @link: pointer to a structure containing the link configuration - * - * Returns 0 on success or a negative error code on failure. - */ -int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link) -{ - u8 value; - int err; - - /* DP_SET_POWER register is only available on DPCD v1.1 and later */ - if (link->revision < 0x11) - return 0; - - err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); - if (err < 0) - return err; - - value &= ~DP_SET_POWER_MASK; - value |= DP_SET_POWER_D0; - - err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); - if (err < 0) - return err; - - /* - * According to the DP 1.1 specification, a "Sink Device must exit the - * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink - * Control Field" (register 0x600). - */ - usleep_range(1000, 2000); - - return 0; -} -EXPORT_SYMBOL(drm_dp_link_power_up); - -/** - * drm_dp_link_power_down() - power down a DisplayPort link - * @aux: DisplayPort AUX channel - * @link: pointer to a structure containing the link configuration - * - * Returns 0 on success or a negative error code on failure. - */ -int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link) -{ - u8 value; - int err; - - /* DP_SET_POWER register is only available on DPCD v1.1 and later */ - if (link->revision < 0x11) - return 0; - - err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); - if (err < 0) - return err; - - value &= ~DP_SET_POWER_MASK; - value |= DP_SET_POWER_D3; - - err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); - if (err < 0) - return err; - - return 0; -} -EXPORT_SYMBOL(drm_dp_link_power_down); - -/** - * drm_dp_link_configure() - configure a DisplayPort link - * @aux: DisplayPort AUX channel - * @link: pointer to a structure containing the link configuration - * - * Returns 0 on success or a negative error code on failure. - */ -int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link) -{ - u8 values[2]; - int err; - - values[0] = drm_dp_link_rate_to_bw_code(link->rate); - values[1] = link->num_lanes; - - if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING) - values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - - err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values)); - if (err < 0) - return err; - - return 0; -} -EXPORT_SYMBOL(drm_dp_link_configure); - /** * drm_dp_downstream_max_clock() - extract branch device max * pixel rate for legacy VGA diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile index 33c463e8d49f..d6cf202414f0 100644 --- a/drivers/gpu/drm/tegra/Makefile +++ b/drivers/gpu/drm/tegra/Makefile @@ -5,6 +5,7 @@ tegra-drm-y := \ drm.o \ gem.o \ fb.o \ + dp.o \ hub.o \ plane.o \ dc.o \ diff --git a/drivers/gpu/drm/tegra/dp.c b/drivers/gpu/drm/tegra/dp.c new file mode 100644 index 000000000000..50ba967ebcbd --- /dev/null +++ b/drivers/gpu/drm/tegra/dp.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2013-2019 NVIDIA Corporation + * Copyright (C) 2015 Rob Clark + */ + +#include <drm/drm_dp_helper.h> + +#include "dp.h" + +/** + * drm_dp_link_probe() - probe a DisplayPort link for capabilities + * @aux: DisplayPort AUX channel + * @link: pointer to structure in which to return link capabilities + * + * The structure filled in by this function can usually be passed directly + * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and + * configure the link based on the link's capabilities. + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link) +{ + u8 values[3]; + int err; + + memset(link, 0, sizeof(*link)); + + err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values)); + if (err < 0) + return err; + + link->revision = values[0]; + link->rate = drm_dp_bw_code_to_link_rate(values[1]); + link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK; + + if (values[2] & DP_ENHANCED_FRAME_CAP) + link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; + + return 0; +} + +/** + * drm_dp_link_power_up() - power up a DisplayPort link + * @aux: DisplayPort AUX channel + * @link: pointer to a structure containing the link configuration + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link) +{ + u8 value; + int err; + + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ + if (link->revision < 0x11) + return 0; + + err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); + if (err < 0) + return err; + + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D0; + + err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); + if (err < 0) + return err; + + /* + * According to the DP 1.1 specification, a "Sink Device must exit the + * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink + * Control Field" (register 0x600). + */ + usleep_range(1000, 2000); + + return 0; +} + +/** + * drm_dp_link_power_down() - power down a DisplayPort link + * @aux: DisplayPort AUX channel + * @link: pointer to a structure containing the link configuration + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link) +{ + u8 value; + int err; + + /* DP_SET_POWER register is only available on DPCD v1.1 and later */ + if (link->revision < 0x11) + return 0; + + err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value); + if (err < 0) + return err; + + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D3; + + err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value); + if (err < 0) + return err; + + return 0; +} + +/** + * drm_dp_link_configure() - configure a DisplayPort link + * @aux: DisplayPort AUX channel + * @link: pointer to a structure containing the link configuration + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link) +{ + u8 values[2]; + int err; + + values[0] = drm_dp_link_rate_to_bw_code(link->rate); + values[1] = link->num_lanes; + + if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING) + values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + + err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values)); + if (err < 0) + return err; + + return 0; +} diff --git a/drivers/gpu/drm/tegra/dp.h b/drivers/gpu/drm/tegra/dp.h new file mode 100644 index 000000000000..ca99a21d9686 --- /dev/null +++ b/drivers/gpu/drm/tegra/dp.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2013-2019 NVIDIA Corporation. + * Copyright (C) 2015 Rob Clark + */ + +#ifndef DRM_TEGRA_DP_H +#define DRM_TEGRA_DP_H 1 + +struct drm_dp_aux; + +#define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0) + +struct drm_dp_link { + unsigned char revision; + unsigned int rate; + unsigned int num_lanes; + unsigned long capabilities; +}; + +int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link); +int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link); +int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link); +int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link); + +#endif diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index a0f6f9b0d258..1144605c9737 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -22,6 +22,7 @@ #include <drm/drm_dp_helper.h> #include <drm/drm_panel.h>
+#include "dp.h" #include "dpaux.h" #include "drm.h" #include "trace.h" diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 57693260245e..91d5c5041d2c 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -25,6 +25,7 @@ #include <drm/drm_scdc_helper.h>
#include "dc.h" +#include "dp.h" #include "drm.h" #include "hda.h" #include "sor.h" diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index e0b2c03f3cbb..ec4cebe93b94 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1484,22 +1484,6 @@ static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux, int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, u8 status[DP_LINK_STATUS_SIZE]);
-/* - * DisplayPort link - */ -#define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0) - -struct drm_dp_link { - unsigned char revision; - unsigned int rate; - unsigned int num_lanes; - unsigned long capabilities; -}; - -int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link); -int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4]); int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
dri-devel@lists.freedesktop.org