From: Yubing Zhang <yubing.zhang@rock-chips.com>
To: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>,
Andy Yan <andyshrk@163.com>
Cc: neil.armstrong@linaro.org, sebastian.reichel@collabora.com,
heiko@sntech.de, devicetree@vger.kernel.org, hjc@rock-chips.com,
mripard@kernel.org, linux-kernel@vger.kernel.org,
linux-rockchip@lists.infradead.org,
dri-devel@lists.freedesktop.org,
Andy Yan <andy.yan@rock-chips.com>,
krzk+dt@kernel.org, robh@kernel.org,
linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 2/6] drm/bridge: synopsys: Add DW DPTX Controller support library
Date: Mon, 3 Mar 2025 16:59:50 +0800 [thread overview]
Message-ID: <65706d63-18aa-41e0-81c4-4eab3d186250@rock-chips.com> (raw)
In-Reply-To: <563i7xcbbsxfezkgs4txsa6lar5tb5folp7zk7dc7sbvf54n6y@vqbtuwvj3fcw>
Hi Dmitry,
On 2025/3/2 2:14, Dmitry Baryshkov wrote:
> On Sun, Feb 23, 2025 at 07:30:25PM +0800, Andy Yan wrote:
>> From: Andy Yan <andy.yan@rock-chips.com>
>>
>> The DW DP TX Controller is compliant with the DisplayPort Specification
>> Version 1.4 with the following features:
>>
>> * DisplayPort 1.4a
>> * Main Link: 1/2/4 lanes
>> * Main Link Support 1.62Gbps, 2.7Gbps, 5.4Gbps and 8.1Gbps
>> * AUX channel 1Mbps
>> * Single Stream Transport(SST)
>> * Multistream Transport (MST)
>> *Type-C support (alternate mode)
>> * HDCP 2.2, HDCP 1.3
>> * Supports up to 8/10 bits per color component
>> * Supports RBG, YCbCr4:4:4, YCbCr4:2:2, YCbCr4:2:0
>> * Pixel clock up to 594MHz
>> * I2S, SPDIF audio interface
>>
>> Add library with common helpers to make it can be shared with
>> other SoC.
>>
>> Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
>>
>> drm/bridge: cleanup
>
> Stray line?
>
>>
>> ---
>>
>> drivers/gpu/drm/bridge/synopsys/Kconfig | 7 +
>> drivers/gpu/drm/bridge/synopsys/Makefile | 1 +
>> drivers/gpu/drm/bridge/synopsys/dw-dp.c | 2155 ++++++++++++++++++++++
>> include/drm/bridge/dw_dp.h | 19 +
>> 4 files changed, 2182 insertions(+)
>> create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-dp.c
......
>> +
>> +static u8 dw_dp_voltage_max(u8 preemph)
>> +{
>> + switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) {
>> + case DP_TRAIN_PRE_EMPH_LEVEL_0:
>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
>> + case DP_TRAIN_PRE_EMPH_LEVEL_1:
>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
>> + case DP_TRAIN_PRE_EMPH_LEVEL_2:
>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_1;
>> + case DP_TRAIN_PRE_EMPH_LEVEL_3:
>> + default:
>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
>> + }
>> +}
>> +
>> +static void dw_dp_link_get_adjustments(struct dw_dp_link *link,
>> + u8 status[DP_LINK_STATUS_SIZE])
>> +{
>> + struct dw_dp_link_train_set *adjust = &link->train.adjust;
>> + u8 v = 0;
>> + u8 p = 0;
>> + unsigned int i;
>> +
>> + for (i = 0; i < link->lanes; i++) {
>> + v = drm_dp_get_adjust_request_voltage(status, i);
>> + p = drm_dp_get_adjust_request_pre_emphasis(status, i);
>> + if (p >= DP_TRAIN_PRE_EMPH_LEVEL_3) {
>> + adjust->pre_emphasis[i] = DP_TRAIN_PRE_EMPH_LEVEL_3 >>
>> + DP_TRAIN_PRE_EMPHASIS_SHIFT;
>> + adjust->pre_max_reached[i] = true;
>> + } else {
>> + adjust->pre_emphasis[i] = p >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
>> + adjust->pre_max_reached[i] = false;
>> + }
>> + v = min(v, dw_dp_voltage_max(p));
>> + if (v >= DP_TRAIN_VOLTAGE_SWING_LEVEL_3) {
>> + adjust->voltage_swing[i] = DP_TRAIN_VOLTAGE_SWING_LEVEL_3 >>
>> + DP_TRAIN_VOLTAGE_SWING_SHIFT;
>> + adjust->voltage_max_reached[i] = true;
>> + } else {
>> + adjust->voltage_swing[i] = v >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
>> + adjust->voltage_max_reached[i] = false;
>> + }
>> + }
>> +}
>> +
>> +static void dw_dp_link_train_adjust(struct dw_dp_link_train *train)
>> +{
>> + struct dw_dp_link_train_set *request = &train->request;
>> + struct dw_dp_link_train_set *adjust = &train->adjust;
>> + unsigned int i;
>> +
>> + for (i = 0; i < 4; i++) {
>
> Shouldn't it be a loop up to link->lanes?
>
>> + if (request->voltage_swing[i] != adjust->voltage_swing[i])
>> + request->voltage_swing[i] = adjust->voltage_swing[i];
>> + if (request->voltage_max_reached[i] != adjust->voltage_max_reached[i])
>> + request->voltage_max_reached[i] = adjust->voltage_max_reached[i];
>> + }
>> +
>> + for (i = 0; i < 4; i++) {
>> + if (request->pre_emphasis[i] != adjust->pre_emphasis[i])
>> + request->pre_emphasis[i] = adjust->pre_emphasis[i];
>> + if (request->pre_max_reached[i] != adjust->pre_max_reached[i])
>> + request->pre_max_reached[i] = adjust->pre_max_reached[i];
>
> Why do you need separate request and adjustment structs?
During link training cr sequence, if dprx keep the LANEx_CR_DONE bit(s)
cleared, the request and adjustment structs are used to check the
old and new valud of ADJUST_REQUEST_LANEx_y register(s) is changed or not.
>
>> + }
>> +}
>> +
>> +static int dw_dp_link_clock_recovery(struct dw_dp *dp)
>> +{
>> + struct dw_dp_link *link = &dp->link;
>> + u8 status[DP_LINK_STATUS_SIZE];
>> + unsigned int tries = 0;
>> + int ret;
>> +
>> + ret = dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1);
>> + if (ret)
>> + return ret;
>> +
>> + for (;;) {
>> + ret = dw_dp_link_train_update_vs_emph(dp);
>> + if (ret)
>> + return ret;
>> +
>> + drm_dp_link_train_clock_recovery_delay(&dp->aux, link->dpcd);
>> +
>> + ret = drm_dp_dpcd_read_link_status(&dp->aux, status);
>> + if (ret < 0) {
>> + dev_err(dp->dev, "failed to read link status: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + if (drm_dp_clock_recovery_ok(status, link->lanes)) {
>> + link->train.clock_recovered = true;
>> + break;
>> + }
>> +
>> + dw_dp_link_get_adjustments(link, status);
>> +
>> + if (link->train.request.voltage_swing[0] ==
>> + link->train.adjust.voltage_swing[0])
>
> Should this take all lanes to account? I think it might be posssible to
> drop the adjust / request split and adjust tries in
> dw_dp_link_get_adjustments() instead.
Yes, here shall compare both swing and pre-emphasis for all lanes. It's
a good idea to drop the adjust / request split. The swing and
pre-emphasis compare just need by cr sequence. But both cr and eq
sequences use dw_dp_link_get_adjustments(). It will be better to delete
dw_dp_link_train_adjust() and add a new function to adjust tries for cr
sequence.
>
>> + tries++;
>> + else
>> + tries = 0;
>> +
>> + if (tries == 5)
>> + break;
>> +
>> + dw_dp_link_train_adjust(&link->train);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int dw_dp_link_channel_equalization(struct dw_dp *dp)
>> +{
>> + struct dw_dp_link *link = &dp->link;
>> + u8 status[DP_LINK_STATUS_SIZE], pattern;
>> + unsigned int tries;
>> + int ret;
>> +
>> + if (link->caps.tps4_supported)
>> + pattern = DP_TRAINING_PATTERN_4;
>> + else if (link->caps.tps3_supported)
>> + pattern = DP_TRAINING_PATTERN_3;
>> + else
>> + pattern = DP_TRAINING_PATTERN_2;
>> + ret = dw_dp_link_train_set_pattern(dp, pattern);
>> + if (ret)
>> + return ret;
>> +
>> + for (tries = 1; tries < 5; tries++) {
>> + ret = dw_dp_link_train_update_vs_emph(dp);
>> + if (ret)
>> + return ret;
>> +
>> + drm_dp_link_train_channel_eq_delay(&dp->aux, link->dpcd);
>> +
>> + ret = drm_dp_dpcd_read_link_status(&dp->aux, status);
>> + if (ret < 0)
>> + return ret;
>> +
>> + if (!drm_dp_clock_recovery_ok(status, link->lanes)) {
>> + dev_err(dp->dev, "clock recovery lost while equalizing channel\n");
>> + link->train.clock_recovered = false;
>> + break;
>> + }
>> +
>> + if (drm_dp_channel_eq_ok(status, link->lanes)) {
>> + link->train.channel_equalized = true;
>> + break;
>> + }
>> +
>> + dw_dp_link_get_adjustments(link, status);
>> + dw_dp_link_train_adjust(&link->train);
>> + }
>> +
>> + return 0;
>> +}
......
>> +
>> +struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
>> + const struct dw_dp_plat_data *plat_data);
>> +#endif /* __DW_DP__ */
>> --
>> 2.34.1
>>
>
WARNING: multiple messages have this Message-ID
From: Yubing Zhang <yubing.zhang@rock-chips.com>
To: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>,
Andy Yan <andyshrk@163.com>
Cc: neil.armstrong@linaro.org, sebastian.reichel@collabora.com,
heiko@sntech.de, devicetree@vger.kernel.org, hjc@rock-chips.com,
mripard@kernel.org, linux-kernel@vger.kernel.org,
linux-rockchip@lists.infradead.org,
dri-devel@lists.freedesktop.org,
Andy Yan <andy.yan@rock-chips.com>,
krzk+dt@kernel.org, robh@kernel.org,
linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 2/6] drm/bridge: synopsys: Add DW DPTX Controller support library
Date: Mon, 3 Mar 2025 16:59:50 +0800 [thread overview]
Message-ID: <65706d63-18aa-41e0-81c4-4eab3d186250@rock-chips.com> (raw)
Message-ID: <20250303085950.S0PNy98N-smoOdANqbUDxOUwmrvP3s5vKc5YgvwWEuQ@z> (raw)
In-Reply-To: <563i7xcbbsxfezkgs4txsa6lar5tb5folp7zk7dc7sbvf54n6y@vqbtuwvj3fcw>
Hi Dmitry,
On 2025/3/2 2:14, Dmitry Baryshkov wrote:
> On Sun, Feb 23, 2025 at 07:30:25PM +0800, Andy Yan wrote:
>> From: Andy Yan <andy.yan@rock-chips.com>
>>
>> The DW DP TX Controller is compliant with the DisplayPort Specification
>> Version 1.4 with the following features:
>>
>> * DisplayPort 1.4a
>> * Main Link: 1/2/4 lanes
>> * Main Link Support 1.62Gbps, 2.7Gbps, 5.4Gbps and 8.1Gbps
>> * AUX channel 1Mbps
>> * Single Stream Transport(SST)
>> * Multistream Transport (MST)
>> *Type-C support (alternate mode)
>> * HDCP 2.2, HDCP 1.3
>> * Supports up to 8/10 bits per color component
>> * Supports RBG, YCbCr4:4:4, YCbCr4:2:2, YCbCr4:2:0
>> * Pixel clock up to 594MHz
>> * I2S, SPDIF audio interface
>>
>> Add library with common helpers to make it can be shared with
>> other SoC.
>>
>> Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
>>
>> drm/bridge: cleanup
>
> Stray line?
>
>>
>> ---
>>
>> drivers/gpu/drm/bridge/synopsys/Kconfig | 7 +
>> drivers/gpu/drm/bridge/synopsys/Makefile | 1 +
>> drivers/gpu/drm/bridge/synopsys/dw-dp.c | 2155 ++++++++++++++++++++++
>> include/drm/bridge/dw_dp.h | 19 +
>> 4 files changed, 2182 insertions(+)
>> create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-dp.c
......
>> +
>> +static u8 dw_dp_voltage_max(u8 preemph)
>> +{
>> + switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) {
>> + case DP_TRAIN_PRE_EMPH_LEVEL_0:
>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
>> + case DP_TRAIN_PRE_EMPH_LEVEL_1:
>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
>> + case DP_TRAIN_PRE_EMPH_LEVEL_2:
>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_1;
>> + case DP_TRAIN_PRE_EMPH_LEVEL_3:
>> + default:
>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
>> + }
>> +}
>> +
>> +static void dw_dp_link_get_adjustments(struct dw_dp_link *link,
>> + u8 status[DP_LINK_STATUS_SIZE])
>> +{
>> + struct dw_dp_link_train_set *adjust = &link->train.adjust;
>> + u8 v = 0;
>> + u8 p = 0;
>> + unsigned int i;
>> +
>> + for (i = 0; i < link->lanes; i++) {
>> + v = drm_dp_get_adjust_request_voltage(status, i);
>> + p = drm_dp_get_adjust_request_pre_emphasis(status, i);
>> + if (p >= DP_TRAIN_PRE_EMPH_LEVEL_3) {
>> + adjust->pre_emphasis[i] = DP_TRAIN_PRE_EMPH_LEVEL_3 >>
>> + DP_TRAIN_PRE_EMPHASIS_SHIFT;
>> + adjust->pre_max_reached[i] = true;
>> + } else {
>> + adjust->pre_emphasis[i] = p >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
>> + adjust->pre_max_reached[i] = false;
>> + }
>> + v = min(v, dw_dp_voltage_max(p));
>> + if (v >= DP_TRAIN_VOLTAGE_SWING_LEVEL_3) {
>> + adjust->voltage_swing[i] = DP_TRAIN_VOLTAGE_SWING_LEVEL_3 >>
>> + DP_TRAIN_VOLTAGE_SWING_SHIFT;
>> + adjust->voltage_max_reached[i] = true;
>> + } else {
>> + adjust->voltage_swing[i] = v >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
>> + adjust->voltage_max_reached[i] = false;
>> + }
>> + }
>> +}
>> +
>> +static void dw_dp_link_train_adjust(struct dw_dp_link_train *train)
>> +{
>> + struct dw_dp_link_train_set *request = &train->request;
>> + struct dw_dp_link_train_set *adjust = &train->adjust;
>> + unsigned int i;
>> +
>> + for (i = 0; i < 4; i++) {
>
> Shouldn't it be a loop up to link->lanes?
>
>> + if (request->voltage_swing[i] != adjust->voltage_swing[i])
>> + request->voltage_swing[i] = adjust->voltage_swing[i];
>> + if (request->voltage_max_reached[i] != adjust->voltage_max_reached[i])
>> + request->voltage_max_reached[i] = adjust->voltage_max_reached[i];
>> + }
>> +
>> + for (i = 0; i < 4; i++) {
>> + if (request->pre_emphasis[i] != adjust->pre_emphasis[i])
>> + request->pre_emphasis[i] = adjust->pre_emphasis[i];
>> + if (request->pre_max_reached[i] != adjust->pre_max_reached[i])
>> + request->pre_max_reached[i] = adjust->pre_max_reached[i];
>
> Why do you need separate request and adjustment structs?
During link training cr sequence, if dprx keep the LANEx_CR_DONE bit(s)
cleared, the request and adjustment structs are used to check the
old and new valud of ADJUST_REQUEST_LANEx_y register(s) is changed or not
next prev parent reply other threads:[~2025-03-03 9:00 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-23 11:30 [PATCH 0/6] Add support for RK3588 DisplayPort Controller Andy Yan
2025-02-23 11:30 ` [PATCH 1/6] dt-bindings: display: rockchip: Add schema for RK3588 DPTX Controller Andy Yan
2025-02-24 20:03 ` Rob Herring
2025-02-23 11:30 ` [PATCH 2/6] drm/bridge: synopsys: Add DW DPTX Controller support library Andy Yan
2025-03-01 18:14 ` Dmitry Baryshkov
2025-03-02 10:34 ` Andy Yan
2025-03-02 16:21 ` Dmitry Baryshkov
2025-03-04 7:16 ` Andy Yan
2025-03-04 9:18 ` Dmitry Baryshkov
2025-03-04 10:16 ` Andy Yan
2025-03-03 8:59 ` Yubing Zhang [this message]
2025-03-03 8:59 ` Yubing Zhang
2025-03-03 12:57 ` Dmitry Baryshkov
2025-03-09 6:51 ` FUKAUMI Naoki
2025-02-23 11:30 ` [PATCH 3/6] drm/rockchip: Add RK3588 DPTX output support Andy Yan
2025-02-24 14:56 ` kernel test robot
2025-03-01 18:19 ` Dmitry Baryshkov
2025-03-02 10:37 ` Andy Yan
2025-02-23 11:30 ` [PATCH 4/6] arm64: dts: rockchip: Add DP0 for rk3588 Andy Yan
2025-02-23 11:30 ` [PATCH 5/6] arm64: dts: rockchip: Add DP1 " Andy Yan
2025-02-23 11:30 ` [PATCH 6/6] arm64: dts: rockchip: Enable DisplayPort for rk3588s Cool Pi 4B Andy Yan
2025-03-09 6:35 ` FUKAUMI Naoki
2025-02-28 20:30 ` [PATCH 0/6] Add support for RK3588 DisplayPort Controller Piotr Oniszczuk
2025-03-01 12:24 ` Andy Yan
2025-03-04 13:12 ` Piotr Oniszczuk
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=65706d63-18aa-41e0-81c4-4eab3d186250@rock-chips.com \
--to=yubing.zhang@rock-chips.com \
--cc=andy.yan@rock-chips.com \
--cc=andyshrk@163.com \
--cc=devicetree@vger.kernel.org \
--cc=dmitry.baryshkov@linaro.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=heiko@sntech.de \
--cc=hjc@rock-chips.com \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rockchip@lists.infradead.org \
--cc=mripard@kernel.org \
--cc=neil.armstrong@linaro.org \
--cc=robh@kernel.org \
--cc=sebastian.reichel@collabora.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®