linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP
@ 2019-12-18  0:47 Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 1/9] drm/bridge: ti-sn65dsi86: Split the setting of the dp and dsi rates Douglas Anderson
                   ` (8 more replies)
  0 siblings, 9 replies; 16+ messages in thread
From: Douglas Anderson @ 2019-12-18  0:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong
  Cc: robdclark, linux-arm-msm, bjorn.andersson, seanpaul,
	Jeffrey Hugo, Daniel Vetter, Douglas Anderson, Jonas Karlman,
	linux-kernel, dri-devel, David Airlie, Jernej Skrabec,
	Laurent Pinchart

This series contains a pile of patches that was created to support
hooking up the AUO B116XAK01 panel to the eDP side of the bridge.  In
general it should be useful for hooking up a wider variety of DP
panels to the bridge, especially those with lower resolution and lower
bits per pixel.

The overall result of this series:
* Allows panels with fewer than 4 DP lanes hooked up to work.
* Optimizes the link rate for panels with 6 bpp.
* Supports trying more than one link rate when training if the main
  link rate didn't work.
* Avoids invalid link rates.

It's not expected that this series will break any existing users but
testing is always good.

To support the AUO B116XAK01, we could actually stop at the ("Use
18-bit DP if we can") patch since that causes the panel to run at a
link rate of 1.62 which works.  The patches to try more than one link
rate were all developed prior to realizing that I could just use
18-bit mode and were validated with that patch reverted.

These patches were tested on sdm845-cheza atop mainline as of
2019-12-13 and also on another board (the one with AUO B116XAK01) atop
a downstream kernel tree.

This patch series doesn't do anything to optimize the MIPI link and
only focuses on the DP link.  For instance, it's left as an exercise
to the reader to see if we can use the 666-packed mode on the MIPI
link and save some power (because we could lower the clock rate).

I am nowhere near a display expert and my knowledge of DP and MIPI is
pretty much zero.  If something about this patch series smells wrong,
it probably is.  Please let know and I'll try to fix it.

Changes in v2:
- Squash in maybe-uninitialized fix from Rob Clark.
- Patch ("Avoid invalid rates") replaces ("Skip non-standard DP rates")

Douglas Anderson (9):
  drm/bridge: ti-sn65dsi86: Split the setting of the dp and dsi rates
  drm/bridge: ti-sn65dsi86: zero is never greater than an unsigned int
  drm/bridge: ti-sn65dsi86: Don't use MIPI variables for DP link
  drm/bridge: ti-sn65dsi86: Config number of DP lanes Mo' Betta
  drm/bridge: ti-sn65dsi86: Read num lanes from the DP sink
  drm/bridge: ti-sn65dsi86: Use 18-bit DP if we can
  drm/bridge: ti-sn65dsi86: Group DP link training bits in a function
  drm/bridge: ti-sn65dsi86: Train at faster rates if slower ones fail
  drm/bridge: ti-sn65dsi86: Avoid invalid rates

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 277 ++++++++++++++++++++++----
 1 file changed, 234 insertions(+), 43 deletions(-)

-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v2 1/9] drm/bridge: ti-sn65dsi86: Split the setting of the dp and dsi rates
  2019-12-18  0:47 [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP Douglas Anderson
@ 2019-12-18  0:47 ` Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 2/9] drm/bridge: ti-sn65dsi86: zero is never greater than an unsigned int Douglas Anderson
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Douglas Anderson @ 2019-12-18  0:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong
  Cc: robdclark, linux-arm-msm, bjorn.andersson, seanpaul,
	Jeffrey Hugo, Daniel Vetter, Douglas Anderson, Rob Clark,
	Jonas Karlman, linux-kernel, dri-devel, David Airlie,
	Jernej Skrabec, Laurent Pinchart

These two things were in one function.  Split into two.  This looks
like it's duplicating some code, but don't worry.  This is is just in
preparation for future changes.

This is intended to have zero functional change and will just make
future patches easier to understand.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
---

Changes in v2: None

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 33 +++++++++++++++++++--------
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 43abf01ebd4c..2fb9370a76e6 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -417,6 +417,24 @@ static void ti_sn_bridge_set_refclk_freq(struct ti_sn_bridge *pdata)
 			   REFCLK_FREQ(i));
 }
 
+static void ti_sn_bridge_set_dsi_rate(struct ti_sn_bridge *pdata)
+{
+	unsigned int bit_rate_mhz, clk_freq_mhz;
+	unsigned int val;
+	struct drm_display_mode *mode =
+		&pdata->bridge.encoder->crtc->state->adjusted_mode;
+
+	/* set DSIA clk frequency */
+	bit_rate_mhz = (mode->clock / 1000) *
+			mipi_dsi_pixel_format_to_bpp(pdata->dsi->format);
+	clk_freq_mhz = bit_rate_mhz / (pdata->dsi->lanes * 2);
+
+	/* for each increment in val, frequency increases by 5MHz */
+	val = (MIN_DSI_CLK_FREQ_MHZ / 5) +
+		(((clk_freq_mhz - MIN_DSI_CLK_FREQ_MHZ) / 5) & 0xFF);
+	regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val);
+}
+
 /**
  * LUT index corresponds to register value and
  * LUT values corresponds to dp data rate supported
@@ -426,22 +444,16 @@ static const unsigned int ti_sn_bridge_dp_rate_lut[] = {
 	0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
 };
 
-static void ti_sn_bridge_set_dsi_dp_rate(struct ti_sn_bridge *pdata)
+static void ti_sn_bridge_set_dp_rate(struct ti_sn_bridge *pdata)
 {
-	unsigned int bit_rate_mhz, clk_freq_mhz, dp_rate_mhz;
-	unsigned int val, i;
+	unsigned int bit_rate_mhz, dp_rate_mhz;
+	unsigned int i;
 	struct drm_display_mode *mode =
 		&pdata->bridge.encoder->crtc->state->adjusted_mode;
 
 	/* set DSIA clk frequency */
 	bit_rate_mhz = (mode->clock / 1000) *
 			mipi_dsi_pixel_format_to_bpp(pdata->dsi->format);
-	clk_freq_mhz = bit_rate_mhz / (pdata->dsi->lanes * 2);
-
-	/* for each increment in val, frequency increases by 5MHz */
-	val = (MIN_DSI_CLK_FREQ_MHZ / 5) +
-		(((clk_freq_mhz - MIN_DSI_CLK_FREQ_MHZ) / 5) & 0xFF);
-	regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val);
 
 	/* set DP data rate */
 	dp_rate_mhz = ((bit_rate_mhz / pdata->dsi->lanes) * DP_CLK_FUDGE_NUM) /
@@ -510,7 +522,8 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 			   val);
 
 	/* set dsi/dp clk frequency value */
-	ti_sn_bridge_set_dsi_dp_rate(pdata);
+	ti_sn_bridge_set_dsi_rate(pdata);
+	ti_sn_bridge_set_dp_rate(pdata);
 
 	/* enable DP PLL */
 	regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1);
-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 2/9] drm/bridge: ti-sn65dsi86: zero is never greater than an unsigned int
  2019-12-18  0:47 [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 1/9] drm/bridge: ti-sn65dsi86: Split the setting of the dp and dsi rates Douglas Anderson
@ 2019-12-18  0:47 ` Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 3/9] drm/bridge: ti-sn65dsi86: Don't use MIPI variables for DP link Douglas Anderson
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Douglas Anderson @ 2019-12-18  0:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong
  Cc: robdclark, linux-arm-msm, bjorn.andersson, seanpaul,
	Jeffrey Hugo, Daniel Vetter, Douglas Anderson, Rob Clark,
	Jonas Karlman, linux-kernel, dri-devel, David Airlie,
	Jernej Skrabec, Laurent Pinchart

When we iterate over ti_sn_bridge_dp_rate_lut, there's no reason to
start at index 0 which always contains the value 0.  0 is not a valid
link rate.

This change should have no real effect but is a small cleanup.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
---

Changes in v2: None

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 2fb9370a76e6..7b596af265e4 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -458,7 +458,7 @@ static void ti_sn_bridge_set_dp_rate(struct ti_sn_bridge *pdata)
 	/* set DP data rate */
 	dp_rate_mhz = ((bit_rate_mhz / pdata->dsi->lanes) * DP_CLK_FUDGE_NUM) /
 							DP_CLK_FUDGE_DEN;
-	for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1; i++)
+	for (i = 1; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1; i++)
 		if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz)
 			break;
 
-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 3/9] drm/bridge: ti-sn65dsi86: Don't use MIPI variables for DP link
  2019-12-18  0:47 [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 1/9] drm/bridge: ti-sn65dsi86: Split the setting of the dp and dsi rates Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 2/9] drm/bridge: ti-sn65dsi86: zero is never greater than an unsigned int Douglas Anderson
@ 2019-12-18  0:47 ` Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 4/9] drm/bridge: ti-sn65dsi86: Config number of DP lanes Mo' Betta Douglas Anderson
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Douglas Anderson @ 2019-12-18  0:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong
  Cc: robdclark, linux-arm-msm, bjorn.andersson, seanpaul,
	Jeffrey Hugo, Daniel Vetter, Douglas Anderson, Rob Clark,
	Jonas Karlman, linux-kernel, dri-devel, David Airlie,
	Jernej Skrabec, Laurent Pinchart

The ti-sn65dsi86 is a bridge from MIPI to DP and thus has two links:
the MIPI link and the DP link.  The two links do not need to have the
same format or number of lanes.  Stop using MIPI variables when
talking about the DP link.

This has zero functional change because:
* currently we are hardcoding the MIPI link as unpacked RGB888 which
  requires 24 bits and currently we are not changing the DP link rate
  from the bridge's default of 8 bits per pixel.
* currently we are hardcoding both the MIPI and DP as being 4 lanes.

This is all in prep for fixing some of the above.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
---

Changes in v2: None

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 7b596af265e4..ab644baaf90c 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -100,6 +100,7 @@ struct ti_sn_bridge {
 	struct drm_panel		*panel;
 	struct gpio_desc		*enable_gpio;
 	struct regulator_bulk_data	supplies[SN_REGULATOR_SUPPLY_NUM];
+	int				dp_lanes;
 };
 
 static const struct regmap_range ti_sn_bridge_volatile_ranges[] = {
@@ -313,6 +314,7 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge)
 	}
 
 	/* TODO: setting to 4 lanes always for now */
+	pdata->dp_lanes = 4;
 	dsi->lanes = 4;
 	dsi->format = MIPI_DSI_FMT_RGB888;
 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
@@ -451,13 +453,17 @@ static void ti_sn_bridge_set_dp_rate(struct ti_sn_bridge *pdata)
 	struct drm_display_mode *mode =
 		&pdata->bridge.encoder->crtc->state->adjusted_mode;
 
-	/* set DSIA clk frequency */
-	bit_rate_mhz = (mode->clock / 1000) *
-			mipi_dsi_pixel_format_to_bpp(pdata->dsi->format);
+	/*
+	 * Calculate minimum bit rate based on our pixel clock.  At
+	 * the moment this driver never sets the DP_18BPP_EN bit in
+	 * register 0x5b so we hardcode 24bpp.
+	 */
+	bit_rate_mhz = (mode->clock / 1000) * 24;
 
-	/* set DP data rate */
-	dp_rate_mhz = ((bit_rate_mhz / pdata->dsi->lanes) * DP_CLK_FUDGE_NUM) /
+	/* Calculate minimum DP data rate, taking 80% as per DP spec */
+	dp_rate_mhz = ((bit_rate_mhz / pdata->dp_lanes) * DP_CLK_FUDGE_NUM) /
 							DP_CLK_FUDGE_DEN;
+
 	for (i = 1; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1; i++)
 		if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz)
 			break;
@@ -517,7 +523,7 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 			   CHA_DSI_LANES_MASK, val);
 
 	/* DP lane config */
-	val = DP_NUM_LANES(pdata->dsi->lanes - 1);
+	val = DP_NUM_LANES(pdata->dp_lanes - 1);
 	regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
 			   val);
 
-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 4/9] drm/bridge: ti-sn65dsi86: Config number of DP lanes Mo' Betta
  2019-12-18  0:47 [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP Douglas Anderson
                   ` (2 preceding siblings ...)
  2019-12-18  0:47 ` [PATCH v2 3/9] drm/bridge: ti-sn65dsi86: Don't use MIPI variables for DP link Douglas Anderson
@ 2019-12-18  0:47 ` Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 5/9] drm/bridge: ti-sn65dsi86: Read num lanes from the DP sink Douglas Anderson
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Douglas Anderson @ 2019-12-18  0:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong
  Cc: robdclark, linux-arm-msm, bjorn.andersson, seanpaul,
	Jeffrey Hugo, Daniel Vetter, Douglas Anderson, Rob Clark,
	Jonas Karlman, linux-kernel, dri-devel, David Airlie,
	Jernej Skrabec, Laurent Pinchart

The driver used to say that the value to program into bridge register
0x93 was dp_lanes - 1.  Looking at the datasheet for the bridge, this
is wrong.  The data sheet says:
* 1 = 1 lane
* 2 = 2 lanes
* 3 = 4 lanes

A more proper way to express this encoding is min(dp_lanes, 3).

At the moment this change has zero effect because we've hardcoded the
number of DP lanes to 4.  ...and (4 - 1) == min(4, 3).  How fortunate!
...but soon we'll stop hardcoding the number of lanes.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
---

Changes in v2: None

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index ab644baaf90c..d55d19759796 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -523,7 +523,7 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 			   CHA_DSI_LANES_MASK, val);
 
 	/* DP lane config */
-	val = DP_NUM_LANES(pdata->dp_lanes - 1);
+	val = DP_NUM_LANES(min(pdata->dp_lanes, 3));
 	regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
 			   val);
 
-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 5/9] drm/bridge: ti-sn65dsi86: Read num lanes from the DP sink
  2019-12-18  0:47 [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP Douglas Anderson
                   ` (3 preceding siblings ...)
  2019-12-18  0:47 ` [PATCH v2 4/9] drm/bridge: ti-sn65dsi86: Config number of DP lanes Mo' Betta Douglas Anderson
@ 2019-12-18  0:47 ` Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 6/9] drm/bridge: ti-sn65dsi86: Use 18-bit DP if we can Douglas Anderson
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Douglas Anderson @ 2019-12-18  0:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong
  Cc: robdclark, linux-arm-msm, bjorn.andersson, seanpaul,
	Jeffrey Hugo, Daniel Vetter, Douglas Anderson, Rob Clark,
	Jonas Karlman, linux-kernel, dri-devel, David Airlie,
	Jernej Skrabec, Laurent Pinchart

At least one panel hooked up to the bridge (AUO B116XAK01) only
supports 1 lane of DP.  Let's read this information and stop
hardcoding 4 DP lanes.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
---

Changes in v2: None

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 32 +++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index d55d19759796..0fc9e97b2d98 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -313,8 +313,7 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge)
 		goto err_dsi_host;
 	}
 
-	/* TODO: setting to 4 lanes always for now */
-	pdata->dp_lanes = 4;
+	/* TODO: setting to 4 MIPI lanes always for now */
 	dsi->lanes = 4;
 	dsi->format = MIPI_DSI_FMT_RGB888;
 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
@@ -511,12 +510,41 @@ static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata)
 	usleep_range(10000, 10500); /* 10ms delay recommended by spec */
 }
 
+static unsigned int ti_sn_get_max_lanes(struct ti_sn_bridge *pdata)
+{
+	u8 data;
+	int ret;
+
+	ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LANE_COUNT, &data);
+	if (ret != 1) {
+		DRM_DEV_ERROR(pdata->dev,
+			      "Can't read lane count (%d); assuming 4\n", ret);
+		return 4;
+	}
+
+	return data & DP_LANE_COUNT_MASK;
+}
+
 static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 {
 	struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
 	unsigned int val;
 	int ret;
 
+	/*
+	 * Run with the maximum number of lanes that the DP sink supports.
+	 *
+	 * Depending use cases, we might want to revisit this later because:
+	 * - It's plausible that someone may have run fewer lines to the
+	 *   sink than the sink actually supports, assuming that the lines
+	 *   will just be driven at a higher rate.
+	 * - The DP spec seems to indicate that it's more important to minimize
+	 *   the number of lanes than the link rate.
+	 *
+	 * If we do revisit, it would be important to measure the power impact.
+	 */
+	pdata->dp_lanes = ti_sn_get_max_lanes(pdata);
+
 	/* DSI_A lane config */
 	val = CHA_DSI_LANES(4 - pdata->dsi->lanes);
 	regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG,
-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 6/9] drm/bridge: ti-sn65dsi86: Use 18-bit DP if we can
  2019-12-18  0:47 [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP Douglas Anderson
                   ` (4 preceding siblings ...)
  2019-12-18  0:47 ` [PATCH v2 5/9] drm/bridge: ti-sn65dsi86: Read num lanes from the DP sink Douglas Anderson
@ 2019-12-18  0:47 ` Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 7/9] drm/bridge: ti-sn65dsi86: Group DP link training bits in a function Douglas Anderson
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Douglas Anderson @ 2019-12-18  0:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong
  Cc: robdclark, linux-arm-msm, bjorn.andersson, seanpaul,
	Jeffrey Hugo, Daniel Vetter, Douglas Anderson, Rob Clark,
	Jonas Karlman, linux-kernel, dri-devel, David Airlie,
	Jernej Skrabec, Laurent Pinchart

The current bridge driver always forced us to use 24 bits per pixel
over the DP link.  This is a waste if you are hooked up to a panel
that only supports 6 bits per color or fewer, since in that case you
ran run at 18 bits per pixel and thus end up at a lower DP clock rate.

Let's support this.

While at it, let's clean up the math in the function to avoid rounding
errors (and round in the correct direction when we have to round).
Numbers are sufficiently small (because mode->clock is in kHz) that we
don't need to worry about integer overflow.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
---

Changes in v2: None

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 0fc9e97b2d98..d5990a0947b9 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -51,6 +51,7 @@
 #define SN_ENH_FRAME_REG			0x5A
 #define  VSTREAM_ENABLE				BIT(3)
 #define SN_DATA_FORMAT_REG			0x5B
+#define  BPP_18_RGB				BIT(0)
 #define SN_HPD_DISABLE_REG			0x5C
 #define  HPD_DISABLE				BIT(0)
 #define SN_AUX_WDATA_REG(x)			(0x64 + (x))
@@ -436,6 +437,14 @@ static void ti_sn_bridge_set_dsi_rate(struct ti_sn_bridge *pdata)
 	regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val);
 }
 
+static unsigned int ti_sn_bridge_get_bpp(struct ti_sn_bridge *pdata)
+{
+	if (pdata->connector.display_info.bpc <= 6)
+		return 18;
+	else
+		return 24;
+}
+
 /**
  * LUT index corresponds to register value and
  * LUT values corresponds to dp data rate supported
@@ -447,21 +456,17 @@ static const unsigned int ti_sn_bridge_dp_rate_lut[] = {
 
 static void ti_sn_bridge_set_dp_rate(struct ti_sn_bridge *pdata)
 {
-	unsigned int bit_rate_mhz, dp_rate_mhz;
+	unsigned int bit_rate_khz, dp_rate_mhz;
 	unsigned int i;
 	struct drm_display_mode *mode =
 		&pdata->bridge.encoder->crtc->state->adjusted_mode;
 
-	/*
-	 * Calculate minimum bit rate based on our pixel clock.  At
-	 * the moment this driver never sets the DP_18BPP_EN bit in
-	 * register 0x5b so we hardcode 24bpp.
-	 */
-	bit_rate_mhz = (mode->clock / 1000) * 24;
+	/* Calculate minimum bit rate based on our pixel clock. */
+	bit_rate_khz = mode->clock * ti_sn_bridge_get_bpp(pdata);
 
 	/* Calculate minimum DP data rate, taking 80% as per DP spec */
-	dp_rate_mhz = ((bit_rate_mhz / pdata->dp_lanes) * DP_CLK_FUDGE_NUM) /
-							DP_CLK_FUDGE_DEN;
+	dp_rate_mhz = DIV_ROUND_UP(bit_rate_khz * DP_CLK_FUDGE_NUM,
+				   1000 * pdata->dp_lanes * DP_CLK_FUDGE_DEN);
 
 	for (i = 1; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1; i++)
 		if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz)
@@ -550,6 +555,10 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 	regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG,
 			   CHA_DSI_LANES_MASK, val);
 
+	/* Set the DP output format (18 bpp or 24 bpp) */
+	val = (ti_sn_bridge_get_bpp(pdata) == 18) ? BPP_18_RGB : 0;
+	regmap_update_bits(pdata->regmap, SN_DATA_FORMAT_REG, BPP_18_RGB, val);
+
 	/* DP lane config */
 	val = DP_NUM_LANES(min(pdata->dp_lanes, 3));
 	regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 7/9] drm/bridge: ti-sn65dsi86: Group DP link training bits in a function
  2019-12-18  0:47 [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP Douglas Anderson
                   ` (5 preceding siblings ...)
  2019-12-18  0:47 ` [PATCH v2 6/9] drm/bridge: ti-sn65dsi86: Use 18-bit DP if we can Douglas Anderson
@ 2019-12-18  0:47 ` Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 8/9] drm/bridge: ti-sn65dsi86: Train at faster rates if slower ones fail Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates Douglas Anderson
  8 siblings, 0 replies; 16+ messages in thread
From: Douglas Anderson @ 2019-12-18  0:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong
  Cc: robdclark, linux-arm-msm, bjorn.andersson, seanpaul,
	Jeffrey Hugo, Daniel Vetter, Douglas Anderson, Rob Clark,
	Jonas Karlman, linux-kernel, dri-devel, David Airlie,
	Jernej Skrabec, Laurent Pinchart

We'll re-organize the ti_sn_bridge_enable() function a bit to group
together all the parts relating to link training and split them into a
sub-function.  This is not intended to have any functional change and
is in preparation for trying link training several times at different
rates.  One small side effect here is that if link training fails
we'll now leave the DP PLL disabled, but that seems like a sane thing
to do.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
---

Changes in v2: None

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 86 ++++++++++++++++-----------
 1 file changed, 52 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index d5990a0947b9..48fb4dc72e1c 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -530,6 +530,46 @@ static unsigned int ti_sn_get_max_lanes(struct ti_sn_bridge *pdata)
 	return data & DP_LANE_COUNT_MASK;
 }
 
+static int ti_sn_link_training(struct ti_sn_bridge *pdata)
+{
+	unsigned int val;
+	int ret;
+
+	/* set dp clk frequency value */
+	ti_sn_bridge_set_dp_rate(pdata);
+
+	/* enable DP PLL */
+	regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1);
+
+	ret = regmap_read_poll_timeout(pdata->regmap, SN_DPPLL_SRC_REG, val,
+				       val & DPPLL_SRC_DP_PLL_LOCK, 1000,
+				       50 * 1000);
+	if (ret) {
+		DRM_ERROR("DP_PLL_LOCK polling failed (%d)\n", ret);
+		goto exit;
+	}
+
+	/* Semi auto link training mode */
+	regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A);
+	ret = regmap_read_poll_timeout(pdata->regmap, SN_ML_TX_MODE_REG, val,
+				       val == ML_TX_MAIN_LINK_OFF ||
+				       val == ML_TX_NORMAL_MODE, 1000,
+				       500 * 1000);
+	if (ret) {
+		DRM_ERROR("Training complete polling failed (%d)\n", ret);
+	} else if (val == ML_TX_MAIN_LINK_OFF) {
+		DRM_ERROR("Link training failed, link is off\n");
+		ret = -EIO;
+	}
+
+exit:
+	/* Disable the PLL if we failed */
+	if (ret)
+		regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 0);
+
+	return ret;
+}
+
 static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 {
 	struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
@@ -555,29 +595,8 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 	regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG,
 			   CHA_DSI_LANES_MASK, val);
 
-	/* Set the DP output format (18 bpp or 24 bpp) */
-	val = (ti_sn_bridge_get_bpp(pdata) == 18) ? BPP_18_RGB : 0;
-	regmap_update_bits(pdata->regmap, SN_DATA_FORMAT_REG, BPP_18_RGB, val);
-
-	/* DP lane config */
-	val = DP_NUM_LANES(min(pdata->dp_lanes, 3));
-	regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
-			   val);
-
-	/* set dsi/dp clk frequency value */
+	/* set dsi clk frequency value */
 	ti_sn_bridge_set_dsi_rate(pdata);
-	ti_sn_bridge_set_dp_rate(pdata);
-
-	/* enable DP PLL */
-	regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1);
-
-	ret = regmap_read_poll_timeout(pdata->regmap, SN_DPPLL_SRC_REG, val,
-				       val & DPPLL_SRC_DP_PLL_LOCK, 1000,
-				       50 * 1000);
-	if (ret) {
-		DRM_ERROR("DP_PLL_LOCK polling failed (%d)\n", ret);
-		return;
-	}
 
 	/**
 	 * The SN65DSI86 only supports ASSR Display Authentication method and
@@ -588,19 +607,18 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 	drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET,
 			   DP_ALTERNATE_SCRAMBLER_RESET_ENABLE);
 
-	/* Semi auto link training mode */
-	regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A);
-	ret = regmap_read_poll_timeout(pdata->regmap, SN_ML_TX_MODE_REG, val,
-				       val == ML_TX_MAIN_LINK_OFF ||
-				       val == ML_TX_NORMAL_MODE, 1000,
-				       500 * 1000);
-	if (ret) {
-		DRM_ERROR("Training complete polling failed (%d)\n", ret);
-		return;
-	} else if (val == ML_TX_MAIN_LINK_OFF) {
-		DRM_ERROR("Link training failed, link is off\n");
+	/* Set the DP output format (18 bpp or 24 bpp) */
+	val = (ti_sn_bridge_get_bpp(pdata) == 18) ? BPP_18_RGB : 0;
+	regmap_update_bits(pdata->regmap, SN_DATA_FORMAT_REG, BPP_18_RGB, val);
+
+	/* DP lane config */
+	val = DP_NUM_LANES(min(pdata->dp_lanes, 3));
+	regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
+			   val);
+
+	ret = ti_sn_link_training(pdata);
+	if (ret)
 		return;
-	}
 
 	/* config video parameters */
 	ti_sn_bridge_set_video_timings(pdata);
-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 8/9] drm/bridge: ti-sn65dsi86: Train at faster rates if slower ones fail
  2019-12-18  0:47 [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP Douglas Anderson
                   ` (6 preceding siblings ...)
  2019-12-18  0:47 ` [PATCH v2 7/9] drm/bridge: ti-sn65dsi86: Group DP link training bits in a function Douglas Anderson
@ 2019-12-18  0:47 ` Douglas Anderson
  2019-12-18  0:47 ` [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates Douglas Anderson
  8 siblings, 0 replies; 16+ messages in thread
From: Douglas Anderson @ 2019-12-18  0:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong
  Cc: robdclark, linux-arm-msm, bjorn.andersson, seanpaul,
	Jeffrey Hugo, Daniel Vetter, Douglas Anderson, Rob Clark,
	Jonas Karlman, linux-kernel, dri-devel, David Airlie,
	Jernej Skrabec, Laurent Pinchart

If we fail training at a lower DP link rate let's now keep trying
until we run out of rates to try.  Basically the algorithm here is to
start at the link rate that is the theoretical minimum and then slowly
bump up until we run out of rates or hit the max rate of the sink.  We
query the sink using a DPCD read.

This is, in fact, important in practice.  Specifically at least one
panel hooked up to the bridge (AUO B116XAK01) had a theoretical min
rate more than 1.62 GHz (if run at 24 bpp) and fails to train at the
next rate (2.16 GHz).  It would train at 2.7 GHz, though.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
---

Changes in v2:
- Squash in maybe-uninitialized fix from Rob Clark.

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 71 ++++++++++++++++++++++-----
 1 file changed, 60 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 48fb4dc72e1c..e1b817ccd9c7 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -454,7 +454,7 @@ static const unsigned int ti_sn_bridge_dp_rate_lut[] = {
 	0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
 };
 
-static void ti_sn_bridge_set_dp_rate(struct ti_sn_bridge *pdata)
+static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn_bridge *pdata)
 {
 	unsigned int bit_rate_khz, dp_rate_mhz;
 	unsigned int i;
@@ -472,8 +472,42 @@ static void ti_sn_bridge_set_dp_rate(struct ti_sn_bridge *pdata)
 		if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz)
 			break;
 
-	regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG,
-			   DP_DATARATE_MASK, DP_DATARATE(i));
+	return i;
+}
+
+static int ti_sn_bridge_get_max_dp_rate_idx(struct ti_sn_bridge *pdata)
+{
+	u8 data;
+	int ret;
+
+	ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &data);
+	if (ret != 1) {
+		DRM_DEV_ERROR(pdata->dev,
+			      "Can't read max rate (%d); assuming 5.4 GHz\n",
+			      ret);
+		return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
+	}
+
+	/*
+	 * Return an index into ti_sn_bridge_dp_rate_lut.  Just hardcode
+	 * these indicies since it's not like the register spec is ever going
+	 * to change and a loop would just be more complicated.  Apparently
+	 * the DP sink can only return these few rates as supported even
+	 * though the bridge allows some rates in between.
+	 */
+	switch (data) {
+	case DP_LINK_BW_1_62:
+		return 1;
+	case DP_LINK_BW_2_7:
+		return 4;
+	case DP_LINK_BW_5_4:
+		return 7;
+	}
+
+	DRM_DEV_ERROR(pdata->dev,
+		      "Unexpected max data rate (%#x); assuming 5.4 GHz\n",
+		      (int)data);
+	return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
 }
 
 static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata)
@@ -530,13 +564,15 @@ static unsigned int ti_sn_get_max_lanes(struct ti_sn_bridge *pdata)
 	return data & DP_LANE_COUNT_MASK;
 }
 
-static int ti_sn_link_training(struct ti_sn_bridge *pdata)
+static int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx,
+			       const char **last_err_str)
 {
 	unsigned int val;
 	int ret;
 
 	/* set dp clk frequency value */
-	ti_sn_bridge_set_dp_rate(pdata);
+	regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG,
+			   DP_DATARATE_MASK, DP_DATARATE(dp_rate_idx));
 
 	/* enable DP PLL */
 	regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1);
@@ -545,7 +581,7 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata)
 				       val & DPPLL_SRC_DP_PLL_LOCK, 1000,
 				       50 * 1000);
 	if (ret) {
-		DRM_ERROR("DP_PLL_LOCK polling failed (%d)\n", ret);
+		*last_err_str = "DP_PLL_LOCK polling failed";
 		goto exit;
 	}
 
@@ -556,9 +592,9 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata)
 				       val == ML_TX_NORMAL_MODE, 1000,
 				       500 * 1000);
 	if (ret) {
-		DRM_ERROR("Training complete polling failed (%d)\n", ret);
+		*last_err_str = "Training complete polling failed";
 	} else if (val == ML_TX_MAIN_LINK_OFF) {
-		DRM_ERROR("Link training failed, link is off\n");
+		*last_err_str = "Link training failed, link is off";
 		ret = -EIO;
 	}
 
@@ -573,8 +609,11 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata)
 static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 {
 	struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
+	const char *last_err_str = "No supported DP rate";
+	int dp_rate_idx;
+	int max_dp_rate_idx;
 	unsigned int val;
-	int ret;
+	int ret = -EINVAL;
 
 	/*
 	 * Run with the maximum number of lanes that the DP sink supports.
@@ -616,9 +655,19 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 	regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
 			   val);
 
-	ret = ti_sn_link_training(pdata);
-	if (ret)
+	/* Train until we run out of rates */
+	max_dp_rate_idx = ti_sn_bridge_get_max_dp_rate_idx(pdata);
+	for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata);
+	     dp_rate_idx <= max_dp_rate_idx;
+	     dp_rate_idx++) {
+		ret = ti_sn_link_training(pdata, dp_rate_idx, &last_err_str);
+		if (!ret)
+			break;
+	}
+	if (ret) {
+		DRM_DEV_ERROR(pdata->dev, "%s (%d)\n", last_err_str, ret);
 		return;
+	}
 
 	/* config video parameters */
 	ti_sn_bridge_set_video_timings(pdata);
-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates
  2019-12-18  0:47 [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP Douglas Anderson
                   ` (7 preceding siblings ...)
  2019-12-18  0:47 ` [PATCH v2 8/9] drm/bridge: ti-sn65dsi86: Train at faster rates if slower ones fail Douglas Anderson
@ 2019-12-18  0:47 ` Douglas Anderson
  2019-12-18  4:01   ` Rob Clark
  2019-12-21 13:56   ` kbuild test robot
  8 siblings, 2 replies; 16+ messages in thread
From: Douglas Anderson @ 2019-12-18  0:47 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong
  Cc: robdclark, linux-arm-msm, bjorn.andersson, seanpaul,
	Jeffrey Hugo, Daniel Vetter, Douglas Anderson, Jonas Karlman,
	linux-kernel, dri-devel, David Airlie, Jernej Skrabec,
	Laurent Pinchart

Based on work by Bjorn Andersson <bjorn.andersson@linaro.org>,
Jeffrey Hugo <jeffrey.l.hugo@gmail.com>, and
Rob Clark <robdclark@chromium.org>.

Let's read the SUPPORTED_LINK_RATES and/or MAX_LINK_RATE (depending on
the eDP version of the sink) to figure out what eDP rates are
supported and pick the ideal one.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
---

Changes in v2:
- Patch ("Avoid invalid rates") replaces ("Skip non-standard DP rates")

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 118 ++++++++++++++++++++------
 1 file changed, 93 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index e1b817ccd9c7..da5ddf6be92b 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -475,39 +475,103 @@ static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn_bridge *pdata)
 	return i;
 }
 
-static int ti_sn_bridge_get_max_dp_rate_idx(struct ti_sn_bridge *pdata)
+static void ti_sn_bridge_read_valid_rates(struct ti_sn_bridge *pdata,
+					  bool rate_valid[])
 {
-	u8 data;
+	u8 dpcd_val;
+	int rate_times_200khz;
 	int ret;
+	int i;
 
-	ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &data);
+	ret = drm_dp_dpcd_readb(&pdata->aux, DP_EDP_DPCD_REV, &dpcd_val);
+	if (ret != 1) {
+		DRM_DEV_ERROR(pdata->dev,
+			      "Can't read eDP rev (%d), assuming 1.1\n", ret);
+		dpcd_val = DP_EDP_11;
+	}
+
+	if (dpcd_val >= DP_EDP_14) {
+		/* eDP 1.4 devices must provide a custom table */
+		__le16 sink_rates[DP_MAX_SUPPORTED_RATES];
+
+		ret = drm_dp_dpcd_read(&pdata->aux, DP_SUPPORTED_LINK_RATES,
+				       sink_rates, sizeof(sink_rates));
+
+		if (ret != sizeof(sink_rates)) {
+			DRM_DEV_ERROR(pdata->dev,
+				"Can't read supported rate table (%d)\n", ret);
+
+			/* By zeroing we'll fall back to DP_MAX_LINK_RATE. */
+			memset(sink_rates, 0, sizeof(sink_rates));
+		}
+
+		for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
+			rate_times_200khz = le16_to_cpu(sink_rates[i]);
+
+			if (!rate_times_200khz)
+				break;
+
+			switch (rate_times_200khz) {
+			case 27000:
+				rate_valid[7] = 1;
+				break;
+			case 21600:
+				rate_valid[6] = 1;
+				break;
+			case 16200:
+				rate_valid[5] = 1;
+				break;
+			case 13500:
+				rate_valid[4] = 1;
+				break;
+			case 12150:
+				rate_valid[3] = 1;
+				break;
+			case 10800:
+				rate_valid[2] = 1;
+				break;
+			case 8100:
+				rate_valid[1] = 1;
+				break;
+			default:
+				/* unsupported */
+				break;
+			}
+		}
+
+		for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut); i++) {
+			if (rate_valid[i])
+				return;
+		}
+		DRM_DEV_ERROR(pdata->dev,
+			      "No matching eDP rates in table; falling back\n");
+	}
+
+	/* On older versions best we can do is use DP_MAX_LINK_RATE */
+	ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &dpcd_val);
 	if (ret != 1) {
 		DRM_DEV_ERROR(pdata->dev,
 			      "Can't read max rate (%d); assuming 5.4 GHz\n",
 			      ret);
-		return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
+		dpcd_val = DP_LINK_BW_5_4;
 	}
 
-	/*
-	 * Return an index into ti_sn_bridge_dp_rate_lut.  Just hardcode
-	 * these indicies since it's not like the register spec is ever going
-	 * to change and a loop would just be more complicated.  Apparently
-	 * the DP sink can only return these few rates as supported even
-	 * though the bridge allows some rates in between.
-	 */
-	switch (data) {
-	case DP_LINK_BW_1_62:
-		return 1;
-	case DP_LINK_BW_2_7:
-		return 4;
+	switch (dpcd_val) {
+	default:
+		DRM_DEV_ERROR(pdata->dev,
+			      "Unexpected max rate (%#x); assuming 5.4 GHz\n",
+			      (int)dpcd_val);
+		/* fall through */
 	case DP_LINK_BW_5_4:
-		return 7;
+		rate_valid[7] = 1;
+		/* fall through */
+	case DP_LINK_BW_2_7:
+		rate_valid[4] = 1;
+		/* fall through */
+	case DP_LINK_BW_1_62:
+		rate_valid[1] = 1;
+		break;
 	}
-
-	DRM_DEV_ERROR(pdata->dev,
-		      "Unexpected max data rate (%#x); assuming 5.4 GHz\n",
-		      (int)data);
-	return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
 }
 
 static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata)
@@ -609,9 +673,9 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx,
 static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 {
 	struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
+	bool rate_valid[ARRAY_SIZE(ti_sn_bridge_dp_rate_lut)];
 	const char *last_err_str = "No supported DP rate";
 	int dp_rate_idx;
-	int max_dp_rate_idx;
 	unsigned int val;
 	int ret = -EINVAL;
 
@@ -655,11 +719,15 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 	regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
 			   val);
 
+	ti_sn_bridge_read_valid_rates(pdata, rate_valid);
+
 	/* Train until we run out of rates */
-	max_dp_rate_idx = ti_sn_bridge_get_max_dp_rate_idx(pdata);
 	for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata);
-	     dp_rate_idx <= max_dp_rate_idx;
+	     dp_rate_idx < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut);
 	     dp_rate_idx++) {
+		if (!rate_valid[dp_rate_idx])
+			continue;
+
 		ret = ti_sn_link_training(pdata, dp_rate_idx, &last_err_str);
 		if (!ret)
 			break;
-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates
  2019-12-18  0:47 ` [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates Douglas Anderson
@ 2019-12-18  4:01   ` Rob Clark
  2019-12-18  4:03     ` Rob Clark
  2019-12-21 13:56   ` kbuild test robot
  1 sibling, 1 reply; 16+ messages in thread
From: Rob Clark @ 2019-12-18  4:01 UTC (permalink / raw)
  To: Douglas Anderson
  Cc: Andrzej Hajda, Neil Armstrong, Rob Clark, Jernej Skrabec,
	Jeffrey Hugo, David Airlie, linux-arm-msm, Jonas Karlman,
	dri-devel, Bjorn Andersson, Sean Paul, Laurent Pinchart,
	Linux Kernel Mailing List

On Tue, Dec 17, 2019 at 4:48 PM Douglas Anderson <dianders@chromium.org> wrote:
>
> Based on work by Bjorn Andersson <bjorn.andersson@linaro.org>,
> Jeffrey Hugo <jeffrey.l.hugo@gmail.com>, and
> Rob Clark <robdclark@chromium.org>.
>
> Let's read the SUPPORTED_LINK_RATES and/or MAX_LINK_RATE (depending on
> the eDP version of the sink) to figure out what eDP rates are
> supported and pick the ideal one.
>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
> ---
>
> Changes in v2:
> - Patch ("Avoid invalid rates") replaces ("Skip non-standard DP rates")
>
>  drivers/gpu/drm/bridge/ti-sn65dsi86.c | 118 ++++++++++++++++++++------
>  1 file changed, 93 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> index e1b817ccd9c7..da5ddf6be92b 100644
> --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> @@ -475,39 +475,103 @@ static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn_bridge *pdata)
>         return i;
>  }
>
> -static int ti_sn_bridge_get_max_dp_rate_idx(struct ti_sn_bridge *pdata)
> +static void ti_sn_bridge_read_valid_rates(struct ti_sn_bridge *pdata,
> +                                         bool rate_valid[])
>  {
> -       u8 data;
> +       u8 dpcd_val;
> +       int rate_times_200khz;
>         int ret;
> +       int i;
>
> -       ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &data);
> +       ret = drm_dp_dpcd_readb(&pdata->aux, DP_EDP_DPCD_REV, &dpcd_val);
> +       if (ret != 1) {
> +               DRM_DEV_ERROR(pdata->dev,
> +                             "Can't read eDP rev (%d), assuming 1.1\n", ret);
> +               dpcd_val = DP_EDP_11;
> +       }
> +
> +       if (dpcd_val >= DP_EDP_14) {
> +               /* eDP 1.4 devices must provide a custom table */
> +               __le16 sink_rates[DP_MAX_SUPPORTED_RATES];
> +
> +               ret = drm_dp_dpcd_read(&pdata->aux, DP_SUPPORTED_LINK_RATES,
> +                                      sink_rates, sizeof(sink_rates));
> +
> +               if (ret != sizeof(sink_rates)) {
> +                       DRM_DEV_ERROR(pdata->dev,
> +                               "Can't read supported rate table (%d)\n", ret);
> +
> +                       /* By zeroing we'll fall back to DP_MAX_LINK_RATE. */
> +                       memset(sink_rates, 0, sizeof(sink_rates));
> +               }
> +
> +               for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
> +                       rate_times_200khz = le16_to_cpu(sink_rates[i]);
> +
> +                       if (!rate_times_200khz)
> +                               break;
> +
> +                       switch (rate_times_200khz) {
> +                       case 27000:

maybe a bit bike-sheddy, but I kinda prefer to use traditional normal
units, ie. just multiply the returned value by 200 and adjust the
switch case values.  At least then they match the values in the lut
(other than khz vs mhz), which makes this whole logic a bit more
obvious... and at that point, maybe just loop over the lut table?

BR,
-R

> +                               rate_valid[7] = 1;
> +                               break;
> +                       case 21600:
> +                               rate_valid[6] = 1;
> +                               break;
> +                       case 16200:
> +                               rate_valid[5] = 1;
> +                               break;
> +                       case 13500:
> +                               rate_valid[4] = 1;
> +                               break;
> +                       case 12150:
> +                               rate_valid[3] = 1;
> +                               break;
> +                       case 10800:
> +                               rate_valid[2] = 1;
> +                               break;
> +                       case 8100:
> +                               rate_valid[1] = 1;
> +                               break;
> +                       default:
> +                               /* unsupported */
> +                               break;
> +                       }
> +               }
> +
> +               for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut); i++) {
> +                       if (rate_valid[i])
> +                               return;
> +               }
> +               DRM_DEV_ERROR(pdata->dev,
> +                             "No matching eDP rates in table; falling back\n");
> +       }
> +
> +       /* On older versions best we can do is use DP_MAX_LINK_RATE */
> +       ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &dpcd_val);
>         if (ret != 1) {
>                 DRM_DEV_ERROR(pdata->dev,
>                               "Can't read max rate (%d); assuming 5.4 GHz\n",
>                               ret);
> -               return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
> +               dpcd_val = DP_LINK_BW_5_4;
>         }
>
> -       /*
> -        * Return an index into ti_sn_bridge_dp_rate_lut.  Just hardcode
> -        * these indicies since it's not like the register spec is ever going
> -        * to change and a loop would just be more complicated.  Apparently
> -        * the DP sink can only return these few rates as supported even
> -        * though the bridge allows some rates in between.
> -        */
> -       switch (data) {
> -       case DP_LINK_BW_1_62:
> -               return 1;
> -       case DP_LINK_BW_2_7:
> -               return 4;
> +       switch (dpcd_val) {
> +       default:
> +               DRM_DEV_ERROR(pdata->dev,
> +                             "Unexpected max rate (%#x); assuming 5.4 GHz\n",
> +                             (int)dpcd_val);
> +               /* fall through */
>         case DP_LINK_BW_5_4:
> -               return 7;
> +               rate_valid[7] = 1;
> +               /* fall through */
> +       case DP_LINK_BW_2_7:
> +               rate_valid[4] = 1;
> +               /* fall through */
> +       case DP_LINK_BW_1_62:
> +               rate_valid[1] = 1;
> +               break;
>         }
> -
> -       DRM_DEV_ERROR(pdata->dev,
> -                     "Unexpected max data rate (%#x); assuming 5.4 GHz\n",
> -                     (int)data);
> -       return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
>  }
>
>  static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata)
> @@ -609,9 +673,9 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx,
>  static void ti_sn_bridge_enable(struct drm_bridge *bridge)
>  {
>         struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
> +       bool rate_valid[ARRAY_SIZE(ti_sn_bridge_dp_rate_lut)];
>         const char *last_err_str = "No supported DP rate";
>         int dp_rate_idx;
> -       int max_dp_rate_idx;
>         unsigned int val;
>         int ret = -EINVAL;
>
> @@ -655,11 +719,15 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
>         regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
>                            val);
>
> +       ti_sn_bridge_read_valid_rates(pdata, rate_valid);
> +
>         /* Train until we run out of rates */
> -       max_dp_rate_idx = ti_sn_bridge_get_max_dp_rate_idx(pdata);
>         for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata);
> -            dp_rate_idx <= max_dp_rate_idx;
> +            dp_rate_idx < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut);
>              dp_rate_idx++) {
> +               if (!rate_valid[dp_rate_idx])
> +                       continue;
> +
>                 ret = ti_sn_link_training(pdata, dp_rate_idx, &last_err_str);
>                 if (!ret)
>                         break;
> --
> 2.24.1.735.g03f4e72817-goog
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates
  2019-12-18  4:01   ` Rob Clark
@ 2019-12-18  4:03     ` Rob Clark
  2019-12-18 22:41       ` Doug Anderson
  0 siblings, 1 reply; 16+ messages in thread
From: Rob Clark @ 2019-12-18  4:03 UTC (permalink / raw)
  To: Douglas Anderson
  Cc: Andrzej Hajda, Neil Armstrong, Rob Clark, Jernej Skrabec,
	Jeffrey Hugo, David Airlie, linux-arm-msm, Jonas Karlman,
	dri-devel, Bjorn Andersson, Sean Paul, Laurent Pinchart,
	Linux Kernel Mailing List

On Tue, Dec 17, 2019 at 8:01 PM Rob Clark <robdclark@gmail.com> wrote:
>
> On Tue, Dec 17, 2019 at 4:48 PM Douglas Anderson <dianders@chromium.org> wrote:
> >
> > Based on work by Bjorn Andersson <bjorn.andersson@linaro.org>,
> > Jeffrey Hugo <jeffrey.l.hugo@gmail.com>, and
> > Rob Clark <robdclark@chromium.org>.
> >
> > Let's read the SUPPORTED_LINK_RATES and/or MAX_LINK_RATE (depending on
> > the eDP version of the sink) to figure out what eDP rates are
> > supported and pick the ideal one.
> >
> > Signed-off-by: Douglas Anderson <dianders@chromium.org>
> > ---
> >
> > Changes in v2:
> > - Patch ("Avoid invalid rates") replaces ("Skip non-standard DP rates")
> >
> >  drivers/gpu/drm/bridge/ti-sn65dsi86.c | 118 ++++++++++++++++++++------
> >  1 file changed, 93 insertions(+), 25 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> > index e1b817ccd9c7..da5ddf6be92b 100644
> > --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> > +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> > @@ -475,39 +475,103 @@ static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn_bridge *pdata)
> >         return i;
> >  }
> >
> > -static int ti_sn_bridge_get_max_dp_rate_idx(struct ti_sn_bridge *pdata)
> > +static void ti_sn_bridge_read_valid_rates(struct ti_sn_bridge *pdata,
> > +                                         bool rate_valid[])
> >  {
> > -       u8 data;
> > +       u8 dpcd_val;
> > +       int rate_times_200khz;
> >         int ret;
> > +       int i;
> >
> > -       ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &data);
> > +       ret = drm_dp_dpcd_readb(&pdata->aux, DP_EDP_DPCD_REV, &dpcd_val);
> > +       if (ret != 1) {
> > +               DRM_DEV_ERROR(pdata->dev,
> > +                             "Can't read eDP rev (%d), assuming 1.1\n", ret);
> > +               dpcd_val = DP_EDP_11;
> > +       }
> > +
> > +       if (dpcd_val >= DP_EDP_14) {
> > +               /* eDP 1.4 devices must provide a custom table */
> > +               __le16 sink_rates[DP_MAX_SUPPORTED_RATES];
> > +
> > +               ret = drm_dp_dpcd_read(&pdata->aux, DP_SUPPORTED_LINK_RATES,
> > +                                      sink_rates, sizeof(sink_rates));
> > +
> > +               if (ret != sizeof(sink_rates)) {
> > +                       DRM_DEV_ERROR(pdata->dev,
> > +                               "Can't read supported rate table (%d)\n", ret);
> > +
> > +                       /* By zeroing we'll fall back to DP_MAX_LINK_RATE. */
> > +                       memset(sink_rates, 0, sizeof(sink_rates));
> > +               }
> > +
> > +               for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
> > +                       rate_times_200khz = le16_to_cpu(sink_rates[i]);
> > +
> > +                       if (!rate_times_200khz)
> > +                               break;
> > +
> > +                       switch (rate_times_200khz) {
> > +                       case 27000:
>
> maybe a bit bike-sheddy, but I kinda prefer to use traditional normal
> units, ie. just multiply the returned value by 200 and adjust the
> switch case values.  At least then they match the values in the lut
> (other than khz vs mhz), which makes this whole logic a bit more
> obvious... and at that point, maybe just loop over the lut table?

(hit SEND too soon)

and other than that, lgtm but haven't had a chance to test it yet
(although I guess none of us have an eDP 1.4+ screen so maybe that is
moot :-))

BR,
-R


> BR,
> -R
>
> > +                               rate_valid[7] = 1;
> > +                               break;
> > +                       case 21600:
> > +                               rate_valid[6] = 1;
> > +                               break;
> > +                       case 16200:
> > +                               rate_valid[5] = 1;
> > +                               break;
> > +                       case 13500:
> > +                               rate_valid[4] = 1;
> > +                               break;
> > +                       case 12150:
> > +                               rate_valid[3] = 1;
> > +                               break;
> > +                       case 10800:
> > +                               rate_valid[2] = 1;
> > +                               break;
> > +                       case 8100:
> > +                               rate_valid[1] = 1;
> > +                               break;
> > +                       default:
> > +                               /* unsupported */
> > +                               break;
> > +                       }
> > +               }
> > +
> > +               for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut); i++) {
> > +                       if (rate_valid[i])
> > +                               return;
> > +               }
> > +               DRM_DEV_ERROR(pdata->dev,
> > +                             "No matching eDP rates in table; falling back\n");
> > +       }
> > +
> > +       /* On older versions best we can do is use DP_MAX_LINK_RATE */
> > +       ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &dpcd_val);
> >         if (ret != 1) {
> >                 DRM_DEV_ERROR(pdata->dev,
> >                               "Can't read max rate (%d); assuming 5.4 GHz\n",
> >                               ret);
> > -               return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
> > +               dpcd_val = DP_LINK_BW_5_4;
> >         }
> >
> > -       /*
> > -        * Return an index into ti_sn_bridge_dp_rate_lut.  Just hardcode
> > -        * these indicies since it's not like the register spec is ever going
> > -        * to change and a loop would just be more complicated.  Apparently
> > -        * the DP sink can only return these few rates as supported even
> > -        * though the bridge allows some rates in between.
> > -        */
> > -       switch (data) {
> > -       case DP_LINK_BW_1_62:
> > -               return 1;
> > -       case DP_LINK_BW_2_7:
> > -               return 4;
> > +       switch (dpcd_val) {
> > +       default:
> > +               DRM_DEV_ERROR(pdata->dev,
> > +                             "Unexpected max rate (%#x); assuming 5.4 GHz\n",
> > +                             (int)dpcd_val);
> > +               /* fall through */
> >         case DP_LINK_BW_5_4:
> > -               return 7;
> > +               rate_valid[7] = 1;
> > +               /* fall through */
> > +       case DP_LINK_BW_2_7:
> > +               rate_valid[4] = 1;
> > +               /* fall through */
> > +       case DP_LINK_BW_1_62:
> > +               rate_valid[1] = 1;
> > +               break;
> >         }
> > -
> > -       DRM_DEV_ERROR(pdata->dev,
> > -                     "Unexpected max data rate (%#x); assuming 5.4 GHz\n",
> > -                     (int)data);
> > -       return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
> >  }
> >
> >  static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata)
> > @@ -609,9 +673,9 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx,
> >  static void ti_sn_bridge_enable(struct drm_bridge *bridge)
> >  {
> >         struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
> > +       bool rate_valid[ARRAY_SIZE(ti_sn_bridge_dp_rate_lut)];
> >         const char *last_err_str = "No supported DP rate";
> >         int dp_rate_idx;
> > -       int max_dp_rate_idx;
> >         unsigned int val;
> >         int ret = -EINVAL;
> >
> > @@ -655,11 +719,15 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
> >         regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
> >                            val);
> >
> > +       ti_sn_bridge_read_valid_rates(pdata, rate_valid);
> > +
> >         /* Train until we run out of rates */
> > -       max_dp_rate_idx = ti_sn_bridge_get_max_dp_rate_idx(pdata);
> >         for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata);
> > -            dp_rate_idx <= max_dp_rate_idx;
> > +            dp_rate_idx < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut);
> >              dp_rate_idx++) {
> > +               if (!rate_valid[dp_rate_idx])
> > +                       continue;
> > +
> >                 ret = ti_sn_link_training(pdata, dp_rate_idx, &last_err_str);
> >                 if (!ret)
> >                         break;
> > --
> > 2.24.1.735.g03f4e72817-goog
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates
  2019-12-18  4:03     ` Rob Clark
@ 2019-12-18 22:41       ` Doug Anderson
  0 siblings, 0 replies; 16+ messages in thread
From: Doug Anderson @ 2019-12-18 22:41 UTC (permalink / raw)
  To: Rob Clark
  Cc: Andrzej Hajda, Neil Armstrong, Rob Clark, Jernej Skrabec,
	Jeffrey Hugo, David Airlie, linux-arm-msm, Jonas Karlman,
	dri-devel, Bjorn Andersson, Sean Paul, Laurent Pinchart,
	Linux Kernel Mailing List

Hi,

On Tue, Dec 17, 2019 at 8:03 PM Rob Clark <robdclark@gmail.com> wrote:
>
> > > +               for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
> > > +                       rate_times_200khz = le16_to_cpu(sink_rates[i]);
> > > +
> > > +                       if (!rate_times_200khz)
> > > +                               break;
> > > +
> > > +                       switch (rate_times_200khz) {
> > > +                       case 27000:
> >
> > maybe a bit bike-sheddy, but I kinda prefer to use traditional normal
> > units, ie. just multiply the returned value by 200 and adjust the
> > switch case values.  At least then they match the values in the lut
> > (other than khz vs mhz), which makes this whole logic a bit more
> > obvious... and at that point, maybe just loop over the lut table?
>
> (hit SEND too soon)
>
> and other than that, lgtm but haven't had a chance to test it yet
> (although I guess none of us have an eDP 1.4+ screen so maybe that is
> moot :-))

I think v3 should look much better to you.  I also added a note to the
commit log indicating that the DP 1.4 patch was only tested via
hackery...

https://lore.kernel.org/r/20191218143416.v3.9.Ib59207b66db377380d13748752d6fce5596462c5@changeid

-Doug

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates
  2019-12-18  0:47 ` [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates Douglas Anderson
  2019-12-18  4:01   ` Rob Clark
@ 2019-12-21 13:56   ` kbuild test robot
  2020-01-06 22:43     ` Doug Anderson
  1 sibling, 1 reply; 16+ messages in thread
From: kbuild test robot @ 2019-12-21 13:56 UTC (permalink / raw)
  To: Douglas Anderson
  Cc: kbuild-all, Andrzej Hajda, Neil Armstrong, robdclark,
	Jernej Skrabec, Jeffrey Hugo, David Airlie, linux-arm-msm,
	Jonas Karlman, Douglas Anderson, dri-devel, bjorn.andersson,
	seanpaul, Laurent Pinchart, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4665 bytes --]

Hi Douglas,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.5-rc2 next-20191220]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Douglas-Anderson/drm-bridge-ti-sn65dsi86-Improve-support-for-AUO-B116XAK01-other-DP/20191221-083448
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 7e0165b2f1a912a06e381e91f0f4e495f4ac3736
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gcc (GCC) 7.5.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.5.0 make.cross ARCH=sh 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/bridge/ti-sn65dsi86.c: In function 'ti_sn_bridge_enable':
>> drivers/gpu/drm/bridge/ti-sn65dsi86.c:543:18: warning: 'rate_valid' may be used uninitialized in this function [-Wmaybe-uninitialized]
       if (rate_valid[i])
           ~~~~~~~~~~^~~

vim +/rate_valid +543 drivers/gpu/drm/bridge/ti-sn65dsi86.c

   477	
   478	static void ti_sn_bridge_read_valid_rates(struct ti_sn_bridge *pdata,
   479						  bool rate_valid[])
   480	{
   481		u8 dpcd_val;
   482		int rate_times_200khz;
   483		int ret;
   484		int i;
   485	
   486		ret = drm_dp_dpcd_readb(&pdata->aux, DP_EDP_DPCD_REV, &dpcd_val);
   487		if (ret != 1) {
   488			DRM_DEV_ERROR(pdata->dev,
   489				      "Can't read eDP rev (%d), assuming 1.1\n", ret);
   490			dpcd_val = DP_EDP_11;
   491		}
   492	
   493		if (dpcd_val >= DP_EDP_14) {
   494			/* eDP 1.4 devices must provide a custom table */
   495			__le16 sink_rates[DP_MAX_SUPPORTED_RATES];
   496	
   497			ret = drm_dp_dpcd_read(&pdata->aux, DP_SUPPORTED_LINK_RATES,
   498					       sink_rates, sizeof(sink_rates));
   499	
   500			if (ret != sizeof(sink_rates)) {
   501				DRM_DEV_ERROR(pdata->dev,
   502					"Can't read supported rate table (%d)\n", ret);
   503	
   504				/* By zeroing we'll fall back to DP_MAX_LINK_RATE. */
   505				memset(sink_rates, 0, sizeof(sink_rates));
   506			}
   507	
   508			for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
   509				rate_times_200khz = le16_to_cpu(sink_rates[i]);
   510	
   511				if (!rate_times_200khz)
   512					break;
   513	
   514				switch (rate_times_200khz) {
   515				case 27000:
   516					rate_valid[7] = 1;
   517					break;
   518				case 21600:
   519					rate_valid[6] = 1;
   520					break;
   521				case 16200:
   522					rate_valid[5] = 1;
   523					break;
   524				case 13500:
   525					rate_valid[4] = 1;
   526					break;
   527				case 12150:
   528					rate_valid[3] = 1;
   529					break;
   530				case 10800:
   531					rate_valid[2] = 1;
   532					break;
   533				case 8100:
   534					rate_valid[1] = 1;
   535					break;
   536				default:
   537					/* unsupported */
   538					break;
   539				}
   540			}
   541	
   542			for (i = 0; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut); i++) {
 > 543				if (rate_valid[i])
   544					return;
   545			}
   546			DRM_DEV_ERROR(pdata->dev,
   547				      "No matching eDP rates in table; falling back\n");
   548		}
   549	
   550		/* On older versions best we can do is use DP_MAX_LINK_RATE */
   551		ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &dpcd_val);
   552		if (ret != 1) {
   553			DRM_DEV_ERROR(pdata->dev,
   554				      "Can't read max rate (%d); assuming 5.4 GHz\n",
   555				      ret);
   556			dpcd_val = DP_LINK_BW_5_4;
   557		}
   558	
   559		switch (dpcd_val) {
   560		default:
   561			DRM_DEV_ERROR(pdata->dev,
   562				      "Unexpected max rate (%#x); assuming 5.4 GHz\n",
   563				      (int)dpcd_val);
   564			/* fall through */
   565		case DP_LINK_BW_5_4:
   566			rate_valid[7] = 1;
   567			/* fall through */
   568		case DP_LINK_BW_2_7:
   569			rate_valid[4] = 1;
   570			/* fall through */
   571		case DP_LINK_BW_1_62:
   572			rate_valid[1] = 1;
   573			break;
   574		}
   575	}
   576	

---
0-DAY kernel test infrastructure                 Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 52817 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates
  2019-12-21 13:56   ` kbuild test robot
@ 2020-01-06 22:43     ` Doug Anderson
  2020-01-07  0:55       ` [kbuild-all] " Rong Chen
  0 siblings, 1 reply; 16+ messages in thread
From: Doug Anderson @ 2020-01-06 22:43 UTC (permalink / raw)
  To: kbuild test robot
  Cc: kbuild-all, Andrzej Hajda, Neil Armstrong, Rob Clark,
	Jernej Skrabec, Jeffrey Hugo, David Airlie, linux-arm-msm,
	Jonas Karlman, dri-devel, Bjorn Andersson, Sean Paul,
	Laurent Pinchart, LKML

Dear Robot,

On Sat, Dec 21, 2019 at 5:57 AM kbuild test robot <lkp@intel.com> wrote:
>
> Hi Douglas,
>
> I love your patch! Perhaps something to improve:
>
> [auto build test WARNING on linus/master]
> [also build test WARNING on v5.5-rc2 next-20191220]
> [if your patch is applied to the wrong git tree, please drop us a note to help
> improve the system. BTW, we also suggest to use '--base' option to specify the
> base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
>
> url:    https://github.com/0day-ci/linux/commits/Douglas-Anderson/drm-bridge-ti-sn65dsi86-Improve-support-for-AUO-B116XAK01-other-DP/20191221-083448
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 7e0165b2f1a912a06e381e91f0f4e495f4ac3736
> config: sh-allmodconfig (attached as .config)
> compiler: sh4-linux-gcc (GCC) 7.5.0
> reproduce:
>         wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # save the attached .config to linux build tree
>         GCC_VERSION=7.5.0 make.cross ARCH=sh
>
> If you fix the issue, kindly add following tag
> Reported-by: kbuild test robot <lkp@intel.com>
>
> Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
> http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings
>
> All warnings (new ones prefixed by >>):
>
>    drivers/gpu/drm/bridge/ti-sn65dsi86.c: In function 'ti_sn_bridge_enable':
> >> drivers/gpu/drm/bridge/ti-sn65dsi86.c:543:18: warning: 'rate_valid' may be used uninitialized in this function [-Wmaybe-uninitialized]
>        if (rate_valid[i])
>            ~~~~~~~~~~^~~

I love your report!  Interestingly I had already noticed this problem
myself and v3 of the patch fixes the issue.  See:

https://lore.kernel.org/r/20191218143416.v3.9.Ib59207b66db377380d13748752d6fce5596462c5@changeid


If the maintainer of the robot is reading this, something to improve
about your robot is that it could have noticed v3 of the patch (which
was posted several days before your report) and skipped analyzing v2
of the patch.  I'm currently using Change-Ids embedded in my
Message-Id to help automation relate one version of my patches to the
next.  Specifically you compare the Message-Id of v2 and v3 of this
patch:

20191217164702.v2.9.Ib59207b66db377380d13748752d6fce5596462c5@changeid
20191218143416.v3.9.Ib59207b66db377380d13748752d6fce5596462c5@changeid

Since the last section before the "@changeid" remained constant it
could be assumed that this patch replaced the v2.  I know there's not
too much usage of this technique yet, but if only more tools supported
it then maybe more people would use it.


-Doug

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [kbuild-all] Re: [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates
  2020-01-06 22:43     ` Doug Anderson
@ 2020-01-07  0:55       ` Rong Chen
  0 siblings, 0 replies; 16+ messages in thread
From: Rong Chen @ 2020-01-07  0:55 UTC (permalink / raw)
  To: Doug Anderson, kbuild test robot
  Cc: kbuild-all, Andrzej Hajda, Neil Armstrong, Rob Clark,
	Jernej Skrabec, Jeffrey Hugo, David Airlie, linux-arm-msm,
	Jonas Karlman, dri-devel, Bjorn Andersson, Sean Paul,
	Laurent Pinchart, LKML



On 1/7/20 6:43 AM, Doug Anderson wrote:
> Dear Robot,
>
> On Sat, Dec 21, 2019 at 5:57 AM kbuild test robot <lkp@intel.com> wrote:
>> Hi Douglas,
>>
>> I love your patch! Perhaps something to improve:
>>
>> [auto build test WARNING on linus/master]
>> [also build test WARNING on v5.5-rc2 next-20191220]
>> [if your patch is applied to the wrong git tree, please drop us a note to help
>> improve the system. BTW, we also suggest to use '--base' option to specify the
>> base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
>>
>> url:    https://github.com/0day-ci/linux/commits/Douglas-Anderson/drm-bridge-ti-sn65dsi86-Improve-support-for-AUO-B116XAK01-other-DP/20191221-083448
>> base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 7e0165b2f1a912a06e381e91f0f4e495f4ac3736
>> config: sh-allmodconfig (attached as .config)
>> compiler: sh4-linux-gcc (GCC) 7.5.0
>> reproduce:
>>          wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>>          chmod +x ~/bin/make.cross
>>          # save the attached .config to linux build tree
>>          GCC_VERSION=7.5.0 make.cross ARCH=sh
>>
>> If you fix the issue, kindly add following tag
>> Reported-by: kbuild test robot <lkp@intel.com>
>>
>> Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
>> http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings
>>
>> All warnings (new ones prefixed by >>):
>>
>>     drivers/gpu/drm/bridge/ti-sn65dsi86.c: In function 'ti_sn_bridge_enable':
>>>> drivers/gpu/drm/bridge/ti-sn65dsi86.c:543:18: warning: 'rate_valid' may be used uninitialized in this function [-Wmaybe-uninitialized]
>>         if (rate_valid[i])
>>             ~~~~~~~~~~^~~
> I love your report!  Interestingly I had already noticed this problem
> myself and v3 of the patch fixes the issue.  See:
>
> https://lore.kernel.org/r/20191218143416.v3.9.Ib59207b66db377380d13748752d6fce5596462c5@changeid
>
>
> If the maintainer of the robot is reading this, something to improve
> about your robot is that it could have noticed v3 of the patch (which
> was posted several days before your report) and skipped analyzing v2
> of the patch.  I'm currently using Change-Ids embedded in my
> Message-Id to help automation relate one version of my patches to the
> next.  Specifically you compare the Message-Id of v2 and v3 of this
> patch:
>
> 20191217164702.v2.9.Ib59207b66db377380d13748752d6fce5596462c5@changeid
> 20191218143416.v3.9.Ib59207b66db377380d13748752d6fce5596462c5@changeid
>
> Since the last section before the "@changeid" remained constant it
> could be assumed that this patch replaced the v2.  I know there's not
> too much usage of this technique yet, but if only more tools supported
> it then maybe more people would use it.

Hi Doug,

Thanks for your suggestion, the root cause is that the v3 wasn't handled 
before this report.
We'll definitely give serious thought to your suggestion.

   v2: 
Douglas-Anderson/drm-bridge-ti-sn65dsi86-Improve-support-for-AUO-B116XAK01-other-DP/20191221-083448
   v3: 
Douglas-Anderson/drm-bridge-ti-sn65dsi86-Improve-support-for-AUO-B116XAK01-other-DP/20191222-062646

Best Regards,
Rong Chen

>
>
> -Doug
> _______________________________________________
> kbuild-all mailing list -- kbuild-all@lists.01.org
> To unsubscribe send an email to kbuild-all-leave@lists.01.org


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2020-01-07  0:55 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-18  0:47 [PATCH v2 0/9] drm/bridge: ti-sn65dsi86: Improve support for AUO B116XAK01 + other DP Douglas Anderson
2019-12-18  0:47 ` [PATCH v2 1/9] drm/bridge: ti-sn65dsi86: Split the setting of the dp and dsi rates Douglas Anderson
2019-12-18  0:47 ` [PATCH v2 2/9] drm/bridge: ti-sn65dsi86: zero is never greater than an unsigned int Douglas Anderson
2019-12-18  0:47 ` [PATCH v2 3/9] drm/bridge: ti-sn65dsi86: Don't use MIPI variables for DP link Douglas Anderson
2019-12-18  0:47 ` [PATCH v2 4/9] drm/bridge: ti-sn65dsi86: Config number of DP lanes Mo' Betta Douglas Anderson
2019-12-18  0:47 ` [PATCH v2 5/9] drm/bridge: ti-sn65dsi86: Read num lanes from the DP sink Douglas Anderson
2019-12-18  0:47 ` [PATCH v2 6/9] drm/bridge: ti-sn65dsi86: Use 18-bit DP if we can Douglas Anderson
2019-12-18  0:47 ` [PATCH v2 7/9] drm/bridge: ti-sn65dsi86: Group DP link training bits in a function Douglas Anderson
2019-12-18  0:47 ` [PATCH v2 8/9] drm/bridge: ti-sn65dsi86: Train at faster rates if slower ones fail Douglas Anderson
2019-12-18  0:47 ` [PATCH v2 9/9] drm/bridge: ti-sn65dsi86: Avoid invalid rates Douglas Anderson
2019-12-18  4:01   ` Rob Clark
2019-12-18  4:03     ` Rob Clark
2019-12-18 22:41       ` Doug Anderson
2019-12-21 13:56   ` kbuild test robot
2020-01-06 22:43     ` Doug Anderson
2020-01-07  0:55       ` [kbuild-all] " Rong Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).