Re: [PATCH v3 2/2] drm/bridge: tc358767: Expose test mode functionality via debugfs

2019-12-10 Thread Andrey Smirnov
On Mon, Dec 9, 2019 at 7:05 AM Tomi Valkeinen  wrote:
>
> On 09/12/2019 16:38, Andrey Smirnov wrote:
> > On Mon, Dec 9, 2019 at 1:38 AM Tomi Valkeinen  wrote:
> >>
> >> (Cc'ing Daniel for the last paragraph)
> >>
> >> On 09/12/2019 07:08, Andrey Smirnov wrote:
> >>> Presently, the driver code artificially limits test pattern mode to a
> >>> single pattern with fixed color selection. It being a kernel module
> >>> parameter makes switching "test pattern" <-> "proper output" modes
> >>> on-the-fly clunky and outright impossible if the driver is built into
> >>> the kernel.
> >>
> >> That's not correct, /sys/module/tc358767/parameters/test is there even if 
> >> the driver is built-in.
> >>
> >
> > True, I'll drop the "impossible" part of the descrption. Having to
> > unbind and bind device to the driver to use that parameter definitely
> > falls under "clunky" for me still, so I'll just stick to that in the
> > description.
>
> You don't need to re-bind. You can change the module parameter at runtime, 
> and if the driver happens
> to use the value, then it uses the new value. If I recall right, changing the 
> module parameter and
> then doing a full modeset from userspace made the driver to use the test mode 
> (I'm not 100% sure,
> though).
>
> In any case, I'm not advocating for the use of module parameter here =)
>
> >> Hmm, actually, just echoing 0 to tstctl multiple times, it makes the 
> >> screen go black and then
> >> restores it with every other echo.
> >>
> >
> > Strange, works on my setup every time. No error messages in kernel log
> > I assume? Probably unrelated, but when you echo "0" and the screen
>
> No errors.
>
> > stays black, what do you see in DP_SINK_STATUS register:
> >
> > dd if=/dev/drm_dp_aux0 bs=1 skip=$((0x205)) count=1 2>/dev/null | hexdump 
> > -Cv
> >
> > ? Note that this needs CONFIG_DRM_DP_AUX_CHARDEV to be enabled.
>
> I'll check this later, and do a few more tests.
>
> >>> + debugfs = debugfs_create_dir(dev_name(dev), NULL);
> >>> + if (!IS_ERR(debugfs)) {
> >>> + debugfs_create_file_unsafe("tstctl", 0200, debugfs, tc,
> >>> +_tstctl_fops);
> >>> + devm_add_action_or_reset(dev, tc_remove_debugfs, debugfs);
> >>> + }
> >>> +
> >>
> >> For me this creates debugfs/3-000f/tstctl. I don't think that's a clear or 
> >> usable path, and could
> >> even cause a name conflict in the worst case.
> >>
> >
> > I agree on usability aspect, but I am not sure I can see how a
> > conflict can happen. What scenario do you have in mind that would
> > cause that? My thinking was that the combination of I2C bus number +
> > I2C address should always be unique on the system, but maybe I am
> > missing something?
>
> Well, the dir name doesn't have "i2c" anywhere, so at least in theory, some 
> other bus could have
> "3-000f" address too.
>
> Maybe bigger problem is that it's not at all obvious what "3-000f" means. All 
> the other debugfs dirs
> make sense when you look at the name, and "3-000f" looks very odd there.
>

Fair enough, so what if we changed the name say "tc358767-3-000f" (i.
e. used "tc358767-" + dev_name(dev)), would that be a reasonable path
forward?

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v3 2/2] drm/bridge: tc358767: Expose test mode functionality via debugfs

2019-12-10 Thread Andrey Smirnov
On Mon, Dec 9, 2019 at 1:38 AM Tomi Valkeinen  wrote:
>
> (Cc'ing Daniel for the last paragraph)
>
> On 09/12/2019 07:08, Andrey Smirnov wrote:
> > Presently, the driver code artificially limits test pattern mode to a
> > single pattern with fixed color selection. It being a kernel module
> > parameter makes switching "test pattern" <-> "proper output" modes
> > on-the-fly clunky and outright impossible if the driver is built into
> > the kernel.
>
> That's not correct, /sys/module/tc358767/parameters/test is there even if the 
> driver is built-in.
>

True, I'll drop the "impossible" part of the descrption. Having to
unbind and bind device to the driver to use that parameter definitely
falls under "clunky" for me still, so I'll just stick to that in the
description.

> I think the bigger problems are that there's just one value, even if there 
> are multiple devices, and
> that with kernel parameter the driver can't act on it dynamically (afaik).
>
> > To improve the situation a bit, convert current test pattern code to
> > use debugfs instead by exposing "TestCtl" register. This way old
> > "tc_test_pattern=1" functionality can be emulated via:
> >
> >  echo -n 0x78146302 > tstctl
> >
> > and switch back to regular mode can be done with:
> >
> >  echo -n 0x78146300 > tstctl
>
> In the comment in the code you have 0 as return-to-regular-mode.

Both should work, but I'll modify commit message to match the code.

>
> With my setup, enabling test mode seems to work, but when I return to regular 
> mode, the first echo
> results in black display, but echoing 0 a second time will restore the 
> display.
>
> Hmm, actually, just echoing 0 to tstctl multiple times, it makes the screen 
> go black and then
> restores it with every other echo.
>

Strange, works on my setup every time. No error messages in kernel log
I assume? Probably unrelated, but when you echo "0" and the screen
stays black, what do you see in DP_SINK_STATUS register:

dd if=/dev/drm_dp_aux0 bs=1 skip=$((0x205)) count=1 2>/dev/null | hexdump -Cv

? Note that this needs CONFIG_DRM_DP_AUX_CHARDEV to be enabled.

> > + debugfs = debugfs_create_dir(dev_name(dev), NULL);
> > + if (!IS_ERR(debugfs)) {
> > + debugfs_create_file_unsafe("tstctl", 0200, debugfs, tc,
> > +_tstctl_fops);
> > + devm_add_action_or_reset(dev, tc_remove_debugfs, debugfs);
> > + }
> > +
>
> For me this creates debugfs/3-000f/tstctl. I don't think that's a clear or 
> usable path, and could
> even cause a name conflict in the worst case.
>

I agree on usability aspect, but I am not sure I can see how a
conflict can happen. What scenario do you have in mind that would
cause that? My thinking was that the combination of I2C bus number +
I2C address should always be unique on the system, but maybe I am
missing something?

> Not sure what's a good solution here, but only two semi-good ones come to 
> mind: have it in sysfs
> under the device's dir,

I'm fine with this option if it is the only path forward, but, given a
choice, I would _really_ rather not go the sysfs route.

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH] drm/bridge: tc358767: fix poll timeouts

2019-12-10 Thread Andrey Smirnov
+ Chris Healy

On Mon, Dec 9, 2019 at 12:27 AM Tomi Valkeinen  wrote:
>
> Link training fails with:
>
>   Link training timeout waiting for LT_LOOPDONE!
>   main link enable error: -110
>
> This is caused by too tight timeouts, which were changed recently in
> aa92213f388b ("drm/bridge: tc358767: Simplify polling in tc_link_training()").
>
> With a quick glance, the commit does not change the timeouts. However,
> the method of delaying/sleeping is different, and as the timeout in the
> previous implementation was not explicit, the new version in practice
> has much tighter timeout.
>
> The same change was made to other parts in the driver, but the link
> training timeout is the only one I have seen causing issues.
> Nevertheless, 1 us sleep is not very sane, and the timeouts look pretty
> tight, so lets fix all the timeouts.
>
> One exception was the aux busy poll, where the poll sleep was much
> longer than necessary (or optimal).
>
> I measured the times on my setup, and now the sleep times are set to
> such values that they result in multiple loops, but not too many (say,
> 5-10 loops). The timeouts were all increased to 100ms, which should be
> more than enough for all of these, but in case of bad errors, shouldn't
> stop the driver as multi-second timeouts could do.
>
> Signed-off-by: Tomi Valkeinen 
> Fixes: aa92213f388b ("drm/bridge: tc358767: Simplify polling in 
> tc_link_training()")

Tested on RDU2 with TC358767/eDP panel, doesn't seem to break anything
there, so:

Tested-by: Andrey Smirnov 

> ---
>  drivers/gpu/drm/bridge/tc358767.c | 8 
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c 
> b/drivers/gpu/drm/bridge/tc358767.c
> index 8a8d605021f0..0454675a44cb 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -294,7 +294,7 @@ static inline int tc_poll_timeout(struct tc_data *tc, 
> unsigned int addr,
>
>  static int tc_aux_wait_busy(struct tc_data *tc)
>  {
> -   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 1000, 10);
> +   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 100, 10);
>  }
>
>  static int tc_aux_write_data(struct tc_data *tc, const void *data,
> @@ -637,7 +637,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
> if (ret)
> goto err;
>
> -   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
> +   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 100, 10);
> if (ret == -ETIMEDOUT) {
> dev_err(tc->dev, "Timeout waiting for PHY to become ready");
> return ret;
> @@ -861,7 +861,7 @@ static int tc_wait_link_training(struct tc_data *tc)
> int ret;
>
> ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
> - LT_LOOPDONE, 1, 1000);
> + LT_LOOPDONE, 500, 10);
> if (ret) {
> dev_err(tc->dev, "Link training timeout waiting for 
> LT_LOOPDONE!\n");
> return ret;
> @@ -934,7 +934,7 @@ static int tc_main_link_enable(struct tc_data *tc)
> dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
> ret = regmap_write(tc->regmap, DP_PHY_CTRL, dp_phy_ctrl);
>
> -   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
> +   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 500, 10);
> if (ret) {
> dev_err(dev, "timeout waiting for phy become ready");
> return ret;
> --
> Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
> Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
>
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 0/2] tc358767 test mode

2019-12-09 Thread Andrey Smirnov
Everyone:

This series is a couple of patches exposing TestCtl register of
tc358767, which can be pretty handy when troubleshooting link problems.

Changes since [v2]:

- Series rebased on 5.4 kernel

Changes since [v1]:

- Debugfs moved into a standalone directory and is now created as
  a part of probe()

- Added tstctl_lock to ensure mutual exclusion of tstctl code and
  bridge's enable/disable methods

- tc_tstctl_set() changed to function only if bridge was previosly
  enabled

- Added comment explaining data format expected by "tstctl"

- Debugfs permission changed to reflect write-only nature of this
  feature

- Original commit split into two

- Minor formatting changes

Thanks,
Andrey Smirnov

[v1] lore.kernel.org/r/20190826182524.5064-1-andrew.smir...@gmail.com
[v2] lore.kernel.org/r/20190912013740.5638-1-andrew.smir...@gmail.com

Andrey Smirnov (2):
  drm/bridge: tc358767: Introduce __tc_bridge_enable/disable()
  drm/bridge: tc358767: Expose test mode functionality via debugfs

 drivers/gpu/drm/bridge/tc358767.c | 184 --
 1 file changed, 148 insertions(+), 36 deletions(-)

-- 
2.21.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v3 2/2] drm/bridge: tc358767: Expose test mode functionality via debugfs

2019-12-09 Thread Andrey Smirnov
Presently, the driver code artificially limits test pattern mode to a
single pattern with fixed color selection. It being a kernel module
parameter makes switching "test pattern" <-> "proper output" modes
on-the-fly clunky and outright impossible if the driver is built into
the kernel.

To improve the situation a bit, convert current test pattern code to
use debugfs instead by exposing "TestCtl" register. This way old
"tc_test_pattern=1" functionality can be emulated via:

echo -n 0x78146302 > tstctl

and switch back to regular mode can be done with:

echo -n 0x78146300 > tstctl

Note that switching to any of the test patterns, will NOT trigger link
re-establishment whereas switching to normal operation WILL. This is
done so:

a) we can isolate and verify (e)DP link functionality by switching to
   one of the test patters

b) trigger a link re-establishment by switching back to normal mode

Signed-off-by: Andrey Smirnov 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 152 --
 1 file changed, 125 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 3c252ae0ee6f..12a8829e0ed1 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -17,6 +17,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -221,11 +222,10 @@
 #define COLOR_BGENMASK(15, 8)
 #define ENI2CFILTERBIT(4)
 #define COLOR_BAR_MODE GENMASK(1, 0)
+#define COLOR_BAR_MODE_NORMAL  0
 #define COLOR_BAR_MODE_BARS2
-#define PLL_DBG0x0a04
 
-static bool tc_test_pattern;
-module_param_named(test, tc_test_pattern, bool, 0644);
+#define PLL_DBG0x0a04
 
 struct tc_edp_link {
struct drm_dp_link  base;
@@ -263,6 +263,9 @@ struct tc_data {
 
/* HPD pin number (0 or 1) or -ENODEV */
int hpd_pin;
+
+   struct mutextstctl_lock;
+   boolenabled;
 };
 
 static inline struct tc_data *aux_to_tc(struct drm_dp_aux *a)
@@ -791,16 +794,6 @@ static int tc_set_video_mode(struct tc_data *tc,
if (ret)
return ret;
 
-   /* Test pattern settings */
-   ret = regmap_write(tc->regmap, TSTCTL,
-  FIELD_PREP(COLOR_R, 120) |
-  FIELD_PREP(COLOR_G, 20) |
-  FIELD_PREP(COLOR_B, 99) |
-  ENI2CFILTER |
-  FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
-   if (ret)
-   return ret;
-
/* DP Main Stream Attributes */
vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
ret = regmap_write(tc->regmap, DP0_VIDSYNCDELAY,
@@ -1152,14 +1145,6 @@ static int tc_stream_enable(struct tc_data *tc)
 
dev_dbg(tc->dev, "enable video stream\n");
 
-   /* PXL PLL setup */
-   if (tc_test_pattern) {
-   ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk),
-   1000 * tc->mode.clock);
-   if (ret)
-   return ret;
-   }
-
ret = tc_set_video_mode(tc, >mode);
if (ret)
return ret;
@@ -1188,12 +1173,8 @@ static int tc_stream_enable(struct tc_data *tc)
if (ret)
return ret;
/* Set input interface */
-   value = DP0_AUDSRC_NO_INPUT;
-   if (tc_test_pattern)
-   value |= DP0_VIDSRC_COLOR_BAR;
-   else
-   value |= DP0_VIDSRC_DPI_RX;
-   ret = regmap_write(tc->regmap, SYSCTRL, value);
+   ret = regmap_write(tc->regmap, SYSCTRL,
+  DP0_AUDSRC_NO_INPUT | DP0_VIDSRC_DPI_RX);
if (ret)
return ret;
 
@@ -1252,8 +1233,13 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
 {
struct tc_data *tc = bridge_to_tc(bridge);
 
+   mutex_lock(>tstctl_lock);
+
if (!__tc_bridge_enable(tc))
drm_panel_enable(tc->panel);
+
+   tc->enabled = true;
+   mutex_unlock(>tstctl_lock);
 }
 
 static int __tc_bridge_disable(struct tc_data *tc)
@@ -1275,8 +1261,13 @@ static void tc_bridge_disable(struct drm_bridge *bridge)
 {
struct tc_data *tc = bridge_to_tc(bridge);
 
+   mutex_lock(>tstctl_lock);
+
drm_panel_disable(tc->panel);
__tc_bridge_disable(tc);
+
+   tc->enabled = false;
+   mutex_unlock(>tstctl_lock);
 }
 
 static void tc_bridge_post_disable(struct drm_bridge *bridge)
@@ -1388,6 +1379,99 @@ static enum drm_connector_status 
tc_connector_detect(struct drm_connector *conne
return

[PATCH v3 1/2] drm/bridge: tc358767: Introduce __tc_bridge_enable/disable()

2019-12-09 Thread Andrey Smirnov
Expose underlying implementation of bridge's enable/disable functions,
so it would be possible to use them in other parts of the driver.

Signed-off-by: Andrey Smirnov 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 32 ++-
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 8a8d605021f0..3c252ae0ee6f 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -1222,39 +1222,43 @@ static void tc_bridge_pre_enable(struct drm_bridge 
*bridge)
drm_panel_prepare(tc->panel);
 }
 
-static void tc_bridge_enable(struct drm_bridge *bridge)
+static int __tc_bridge_enable(struct tc_data *tc)
 {
-   struct tc_data *tc = bridge_to_tc(bridge);
int ret;
 
ret = tc_get_display_props(tc);
if (ret < 0) {
dev_err(tc->dev, "failed to read display props: %d\n", ret);
-   return;
+   return ret;
}
 
ret = tc_main_link_enable(tc);
if (ret < 0) {
dev_err(tc->dev, "main link enable error: %d\n", ret);
-   return;
+   return ret;
}
 
ret = tc_stream_enable(tc);
if (ret < 0) {
dev_err(tc->dev, "main link stream start error: %d\n", ret);
tc_main_link_disable(tc);
-   return;
+   return ret;
}
 
-   drm_panel_enable(tc->panel);
+   return 0;
 }
 
-static void tc_bridge_disable(struct drm_bridge *bridge)
+static void tc_bridge_enable(struct drm_bridge *bridge)
 {
struct tc_data *tc = bridge_to_tc(bridge);
-   int ret;
 
-   drm_panel_disable(tc->panel);
+   if (!__tc_bridge_enable(tc))
+   drm_panel_enable(tc->panel);
+}
+
+static int __tc_bridge_disable(struct tc_data *tc)
+{
+   int ret;
 
ret = tc_stream_disable(tc);
if (ret < 0)
@@ -1263,6 +1267,16 @@ static void tc_bridge_disable(struct drm_bridge *bridge)
ret = tc_main_link_disable(tc);
if (ret < 0)
dev_err(tc->dev, "main link disable error: %d\n", ret);
+
+   return ret;
+}
+
+static void tc_bridge_disable(struct drm_bridge *bridge)
+{
+   struct tc_data *tc = bridge_to_tc(bridge);
+
+   drm_panel_disable(tc->panel);
+   __tc_bridge_disable(tc);
 }
 
 static void tc_bridge_post_disable(struct drm_bridge *bridge)
-- 
2.21.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCH v6 03/15] drm/bridge: tc358767: Simplify polling in tc_link_training()

2019-12-06 Thread Andrey Smirnov
On Wed, Dec 4, 2019 at 10:27 AM Tomi Valkeinen  wrote:
>
> Hi Andrey,
>
> On 19/06/2019 08:27, Andrey Smirnov wrote:
>
> > @@ -748,22 +748,19 @@ static int tc_set_video_mode(struct tc_data *tc,
> >
> >   static int tc_wait_link_training(struct tc_data *tc)
> >   {
> > - u32 timeout = 1000;
> >   u32 value;
> >   int ret;
> >
> > - do {
> > - udelay(1);
> > - tc_read(DP0_LTSTAT, );
> > - } while ((!(value & LT_LOOPDONE)) && (--timeout));
> > -
> > - if (timeout == 0) {
> > + ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
> > +   LT_LOOPDONE, 1, 1000);
>
> This seems to break DP at least with some monitors for me. I think it's just 
> a timeout problem, as
> increasing the values helps.
>
> Using ktime, I can see that during link training, the first call takes ~2ms, 
> the second ~7ms. I
> think this worked before, as udelay(1) takes much longer than 1 us.
>
> We have 1000us limit in a few other places too, which I don't see causing 
> issues, but might need
> increasing too.
>
> Also, 1us sleep_us may be a bit too small to be sane. If the loops take 
> milliseconds, probably 100us
> or even more would make sense.
>
> This didn't cause any issues with your display?
>

Hmm, not that I know of. Your reasoning makes sense, though. If
increasing the timeout helps, I am all for it. And, yeah, I agree,
this is probably not the only place that could use an increased
timeout.

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v2 2/2] drm/bridge: tc358767: Expose test mode functionality via debugfs

2019-09-11 Thread Andrey Smirnov
Presently, the driver code artificially limits test pattern mode to a
single pattern with fixed color selection. It being a kernel module
parameter makes switching "test pattern" <-> "proper output" modes
on-the-fly clunky and outright impossible if the driver is built into
the kernel.

To improve the situation a bit, convert current test pattern code to
use debugfs instead by exposing "TestCtl" register. This way old
"tc_test_pattern=1" functionality can be emulated via:

echo -n 0x78146302 > tstctl

and switch back to regular mode can be done with:

echo -n 0x78146300 > tstctl

Note that switching to any of the test patterns, will NOT trigger link
re-establishment whereas switching to normal operation WILL. This is
done so:

a) we can isolate and verify (e)DP link functionality by switching to
   one of the test patters

b) trigger a link re-establishment by switching back to normal mode

Signed-off-by: Andrey Smirnov 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 152 --
 1 file changed, 125 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 8532048e0550..dfac0ce16636 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -17,6 +17,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -222,11 +223,10 @@
 #define COLOR_BGENMASK(15, 8)
 #define ENI2CFILTERBIT(4)
 #define COLOR_BAR_MODE GENMASK(1, 0)
+#define COLOR_BAR_MODE_NORMAL  0
 #define COLOR_BAR_MODE_BARS2
-#define PLL_DBG0x0a04
 
-static bool tc_test_pattern;
-module_param_named(test, tc_test_pattern, bool, 0644);
+#define PLL_DBG0x0a04
 
 struct tc_edp_link {
struct drm_dp_link  base;
@@ -265,6 +265,9 @@ struct tc_data {
/* HPD pin number (0 or 1) or -ENODEV */
int hpd_pin;
 
+   struct mutextstctl_lock;
+   boolenabled;
+
struct regulator*vdcc;
 };
 
@@ -789,16 +792,6 @@ static int tc_set_video_mode(struct tc_data *tc,
if (ret)
return ret;
 
-   /* Test pattern settings */
-   ret = regmap_write(tc->regmap, TSTCTL,
-  FIELD_PREP(COLOR_R, 120) |
-  FIELD_PREP(COLOR_G, 20) |
-  FIELD_PREP(COLOR_B, 99) |
-  ENI2CFILTER |
-  FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
-   if (ret)
-   return ret;
-
/* DP Main Stream Attributes */
vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
ret = regmap_write(tc->regmap, DP0_VIDSYNCDELAY,
@@ -1150,14 +1143,6 @@ static int tc_stream_enable(struct tc_data *tc)
 
dev_dbg(tc->dev, "enable video stream\n");
 
-   /* PXL PLL setup */
-   if (tc_test_pattern) {
-   ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk),
-   1000 * tc->mode.clock);
-   if (ret)
-   return ret;
-   }
-
ret = tc_set_video_mode(tc, >mode);
if (ret)
return ret;
@@ -1186,12 +1171,8 @@ static int tc_stream_enable(struct tc_data *tc)
if (ret)
return ret;
/* Set input interface */
-   value = DP0_AUDSRC_NO_INPUT;
-   if (tc_test_pattern)
-   value |= DP0_VIDSRC_COLOR_BAR;
-   else
-   value |= DP0_VIDSRC_DPI_RX;
-   ret = regmap_write(tc->regmap, SYSCTRL, value);
+   ret = regmap_write(tc->regmap, SYSCTRL,
+  DP0_AUDSRC_NO_INPUT | DP0_VIDSRC_DPI_RX);
if (ret)
return ret;
 
@@ -1250,8 +1231,13 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
 {
struct tc_data *tc = bridge_to_tc(bridge);
 
+   mutex_lock(>tstctl_lock);
+
if (!__tc_bridge_enable(tc))
drm_panel_enable(tc->panel);
+
+   tc->enabled = true;
+   mutex_unlock(>tstctl_lock);
 }
 
 static int __tc_bridge_disable(struct tc_data *tc)
@@ -1273,8 +1259,13 @@ static void tc_bridge_disable(struct drm_bridge *bridge)
 {
struct tc_data *tc = bridge_to_tc(bridge);
 
+   mutex_lock(>tstctl_lock);
+
drm_panel_disable(tc->panel);
__tc_bridge_disable(tc);
+
+   tc->enabled = false;
+   mutex_unlock(>tstctl_lock);
 }
 
 static void tc_bridge_post_disable(struct drm_bridge *bridge)
@@ -1386,6 +1377,99 @@ static enum drm_connector_status 
tc_connector_detect(struct drm_connector *conne
return connector_status_discon

[PATCH v2 1/2] drm/bridge: tc358767: Introduce __tc_bridge_enable/disable()

2019-09-11 Thread Andrey Smirnov
Expose underlying implementation of bridge's enable/disable functions,
so it would be possible to use them in other parts of the driver.

Signed-off-by: Andrey Smirnov 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 32 ++-
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 6308d93ad91d..8532048e0550 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -1220,39 +1220,43 @@ static void tc_bridge_pre_enable(struct drm_bridge 
*bridge)
drm_panel_prepare(tc->panel);
 }
 
-static void tc_bridge_enable(struct drm_bridge *bridge)
+static int __tc_bridge_enable(struct tc_data *tc)
 {
-   struct tc_data *tc = bridge_to_tc(bridge);
int ret;
 
ret = tc_get_display_props(tc);
if (ret < 0) {
dev_err(tc->dev, "failed to read display props: %d\n", ret);
-   return;
+   return ret;
}
 
ret = tc_main_link_enable(tc);
if (ret < 0) {
dev_err(tc->dev, "main link enable error: %d\n", ret);
-   return;
+   return ret;
}
 
ret = tc_stream_enable(tc);
if (ret < 0) {
dev_err(tc->dev, "main link stream start error: %d\n", ret);
tc_main_link_disable(tc);
-   return;
+   return ret;
}
 
-   drm_panel_enable(tc->panel);
+   return 0;
 }
 
-static void tc_bridge_disable(struct drm_bridge *bridge)
+static void tc_bridge_enable(struct drm_bridge *bridge)
 {
struct tc_data *tc = bridge_to_tc(bridge);
-   int ret;
 
-   drm_panel_disable(tc->panel);
+   if (!__tc_bridge_enable(tc))
+   drm_panel_enable(tc->panel);
+}
+
+static int __tc_bridge_disable(struct tc_data *tc)
+{
+   int ret;
 
ret = tc_stream_disable(tc);
if (ret < 0)
@@ -1261,6 +1265,16 @@ static void tc_bridge_disable(struct drm_bridge *bridge)
ret = tc_main_link_disable(tc);
if (ret < 0)
dev_err(tc->dev, "main link disable error: %d\n", ret);
+
+   return ret;
+}
+
+static void tc_bridge_disable(struct drm_bridge *bridge)
+{
+   struct tc_data *tc = bridge_to_tc(bridge);
+
+   drm_panel_disable(tc->panel);
+   __tc_bridge_disable(tc);
 }
 
 static void tc_bridge_post_disable(struct drm_bridge *bridge)
-- 
2.21.0



[PATCH v2 0/2] tc358767 test mode

2019-09-11 Thread Andrey Smirnov
Everyone:

This series is a couple of patches exposing TestCtl register of
tc358767, which can be pretty handy when troubleshooting link problems.

Changes since [v1]:

- Debugfs moved into a standalone directory and is now created as
  a part of probe()

- Added tstctl_lock to ensure mutual exclusion of tstctl code and
  bridge's enable/disable methods

- tc_tstctl_set() changed to function only if bridge was previosly
  enabled

- Added comment explaining data format expected by "tstctl"

- Debugfs permission changed to reflect write-only nature of this
  feature

- Original commit split into two

- Minor formatting changes

Thanks,
Andrey Smirnov

[v1] lore.kernel.org/r/20190826182524.5064-1-andrew.smir...@gmail.com

Andrey Smirnov (2):
  drm/bridge: tc358767: Introduce __tc_bridge_enable/disable()
  drm/bridge: tc358767: Expose test mode functionality via debugfs

 drivers/gpu/drm/bridge/tc358767.c | 184 --
 1 file changed, 148 insertions(+), 36 deletions(-)

-- 
2.21.0



Re: [PATCH] drm/bridge: tc358767: Expose test mode functionality via debugfs

2019-08-28 Thread Andrey Smirnov
On Mon, Aug 26, 2019 at 10:46 PM Tomi Valkeinen  wrote:
>
> Hi,
>
> On 26/08/2019 21:25, Andrey Smirnov wrote:
> > Presently, the driver code artificially limits test pattern mode to a
> > single pattern with fixed color selection. It being a kernel module
> > parameter makes switching "test patter" <-> "proper output" modes
> > on-the-fly clunky and outright impossible if the driver is built into
> > the kernel.
> >
> > To improve the situation a bit, convert current test pattern code to
> > use debugfs instead by exposing "TestCtl" register. This way old
> > "tc_test_pattern=1" functionality can be emulated via:
> >
> >  echo -n 0x78146312 > tstctl
> >
> > and switch back to regular mode can be done with:
> >
> >  echo -n 0x78146310 > tstctl
>
> It might be worth explaining the format in the commit msg or in a
> comment in the driver.
>

Good point. Will do if this is the format going forward.

> > Note that switching to any of the test patterns, will NOT trigger link
> > re-establishment whereas switching to normal operation WILL. This is
> > done so:
> >
> > a) we can isolate and verify (e)DP link functionality by switching to
> > one of the test patters
> >
> > b) trigger a link re-establishment by switching back to normal mode
> >
> > Signed-off-by: Andrey Smirnov 
> > Cc: Andrzej Hajda 
> > Cc: Laurent Pinchart 
> > Cc: Tomi Valkeinen 
> > Cc: Cory Tusar 
> > Cc: Chris Healy 
> > Cc: Lucas Stach 
> > Cc: dri-devel@lists.freedesktop.org
> > Cc: linux-ker...@vger.kernel.org
> > ---
> >   drivers/gpu/drm/bridge/tc358767.c | 137 ++
> >   1 file changed, 101 insertions(+), 36 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/tc358767.c 
> > b/drivers/gpu/drm/bridge/tc358767.c
> > index 6308d93ad91d..7a795b613ed0 100644
> > --- a/drivers/gpu/drm/bridge/tc358767.c
> > +++ b/drivers/gpu/drm/bridge/tc358767.c
> > @@ -17,6 +17,7 @@
> >
> >   #include 
> >   #include 
> > +#include 
> >   #include 
> >   #include 
> >   #include 
> > @@ -222,11 +223,10 @@
> >   #define COLOR_B GENMASK(15, 8)
> >   #define ENI2CFILTER BIT(4)
> >   #define COLOR_BAR_MODE  GENMASK(1, 0)
> > +#define COLOR_BAR_MODE_NORMAL0
> >   #define COLOR_BAR_MODE_BARS 2
> > -#define PLL_DBG  0x0a04
> >
> > -static bool tc_test_pattern;
> > -module_param_named(test, tc_test_pattern, bool, 0644);
> > +#define PLL_DBG  0x0a04
> >
> >   struct tc_edp_link {
> >   struct drm_dp_link  base;
> > @@ -789,16 +789,6 @@ static int tc_set_video_mode(struct tc_data *tc,
> >   if (ret)
> >   return ret;
> >
> > - /* Test pattern settings */
> > - ret = regmap_write(tc->regmap, TSTCTL,
> > -FIELD_PREP(COLOR_R, 120) |
> > -FIELD_PREP(COLOR_G, 20) |
> > -FIELD_PREP(COLOR_B, 99) |
> > -ENI2CFILTER |
> > -FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
> > - if (ret)
> > - return ret;
> > -
> >   /* DP Main Stream Attributes */
> >   vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
> >   ret = regmap_write(tc->regmap, DP0_VIDSYNCDELAY,
> > @@ -1150,14 +1140,6 @@ static int tc_stream_enable(struct tc_data *tc)
> >
> >   dev_dbg(tc->dev, "enable video stream\n");
> >
> > - /* PXL PLL setup */
> > - if (tc_test_pattern) {
> > - ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk),
> > - 1000 * tc->mode.clock);
> > - if (ret)
> > - return ret;
> > - }
> > -
> >   ret = tc_set_video_mode(tc, >mode);
> >   if (ret)
> >   return ret;
> > @@ -1186,12 +1168,8 @@ static int tc_stream_enable(struct tc_data *tc)
> >   if (ret)
> >   return ret;
> >   /* Set input interface */
> > - value = DP0_AUDSRC_NO_INPUT;
> > - if (tc_test_pattern)
> > - value |= DP0_VIDSRC_COLOR_BAR;
> > - else
> > - value |= DP0_VIDSRC_DPI_RX;
> > - ret = regmap_write(tc->regmap, SYSCTRL, value);
> > + ret = regmap_write(tc->regmap, SYSCTRL,
> > +   

Re: [PATCH] drm/bridge: tc358767: Expose test mode functionality via debugfs

2019-08-28 Thread Andrey Smirnov
On Tue, Aug 27, 2019 at 1:06 AM Laurent Pinchart
 wrote:
>
> Hi Andrey,
>
> On Mon, Aug 26, 2019 at 09:24:57PM -0700, Andrey Smirnov wrote:
> > On Mon, Aug 26, 2019 at 3:08 PM Laurent Pinchart wrote:
> > > On Mon, Aug 26, 2019 at 11:25:24AM -0700, Andrey Smirnov wrote:
> > > > Presently, the driver code artificially limits test pattern mode to a
> > > > single pattern with fixed color selection. It being a kernel module
> > > > parameter makes switching "test patter" <-> "proper output" modes
> > > > on-the-fly clunky and outright impossible if the driver is built into
> > > > the kernel.
> > > >
> > > > To improve the situation a bit, convert current test pattern code to
> > > > use debugfs instead by exposing "TestCtl" register. This way old
> > > > "tc_test_pattern=1" functionality can be emulated via:
> > > >
> > > > echo -n 0x78146312 > tstctl
> > > >
> > > > and switch back to regular mode can be done with:
> > > >
> > > > echo -n 0x78146310 > tstctl
> > >
> > > Can't we make this more userfriendly by exposing either a test pattern
> > > index, or a string ?
> >
> > We could, but then a) it would require more code in the driver b) the
> > files wouldn't correspond directly to something described in the
> > part's datasheet. Just didn't seem worth it to me.
>
> Could you then provide me with the datasheet ? :-)

Is this a rhetoric question or are you seriously asking? If its the
latter I can ping you off the list.

> The whole point of a
> driver is to avoid needing detailed knowledge of the device's internals
> in userspace.
>

You won't avoid needing detailed knowledge of the device's internals
if you don't have a priori knowledge in the form of a agreed upon/well
known abstraction you are exposing from the driver. There is no such
abstraction in this case. Whether you present "tstctl" that takes a
magic value or "red", "green", "blue" and "pattern" taking numbers and
special strings, as a user, you still would have to go read the driver
code in order to figure out how that stuff works.

Given how this is an obscure _debug_ feature for a niche part, I think
exposing raw register and leaving a comment in the driver source code
explaining how it works is reasonably user-friendly (for all 10 - 15
unique users that this feature would ever have).

To avoid any further back and forth of this subject, how about the
following. If this is up to me, then I'd like to move forward to v2
with the interface as is. If you feel strongly about this and insist
on your vision of the interface, please let me know what it looks like
(e.g. is what I described above good enough) and I'll rework v2 to
have that.

> > > Do all bits in the register need to be controlled
> > > from userspace ?
> >
> > Pretty much, yes. It's formatted as RR_GG_BB_X_M, where R, G, B
> > specifies color used for various patterns, X is irrelevant and M
> > specifies test pattern to use.
> >
> > > > Note that switching to any of the test patterns, will NOT trigger link
> > > > re-establishment whereas switching to normal operation WILL. This is
> > > > done so:
> > > >
> > > > a) we can isolate and verify (e)DP link functionality by switching to
> > > >one of the test patters
> > > >
> > > > b) trigger a link re-establishment by switching back to normal mode
> > > >
> > > > Signed-off-by: Andrey Smirnov 
> > > > Cc: Andrzej Hajda 
> > > > Cc: Laurent Pinchart 
> > > > Cc: Tomi Valkeinen 
> > > > Cc: Cory Tusar 
> > > > Cc: Chris Healy 
> > > > Cc: Lucas Stach 
> > > > Cc: dri-devel@lists.freedesktop.org
> > > > Cc: linux-ker...@vger.kernel.org
> > > > ---
> > > >  drivers/gpu/drm/bridge/tc358767.c | 137 ++
> > > >  1 file changed, 101 insertions(+), 36 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/bridge/tc358767.c 
> > > > b/drivers/gpu/drm/bridge/tc358767.c
> > > > index 6308d93ad91d..7a795b613ed0 100644
> > > > --- a/drivers/gpu/drm/bridge/tc358767.c
> > > > +++ b/drivers/gpu/drm/bridge/tc358767.c
> > > > @@ -17,6 +17,7 @@
> > > >
> > > >  #include 
> > > >  #include 
> > > > +#include 
> > > >  #include 
> > > >  #include 
> > > >  #include 
> > &g

Re: [PATCH] drm/bridge: tc358767: Expose test mode functionality via debugfs

2019-08-26 Thread Andrey Smirnov
On Mon, Aug 26, 2019 at 3:08 PM Laurent Pinchart
 wrote:
>
> Hi Andrey,
>
> Thank you for the patch.
>
> On Mon, Aug 26, 2019 at 11:25:24AM -0700, Andrey Smirnov wrote:
> > Presently, the driver code artificially limits test pattern mode to a
> > single pattern with fixed color selection. It being a kernel module
> > parameter makes switching "test patter" <-> "proper output" modes
> > on-the-fly clunky and outright impossible if the driver is built into
> > the kernel.
> >
> > To improve the situation a bit, convert current test pattern code to
> > use debugfs instead by exposing "TestCtl" register. This way old
> > "tc_test_pattern=1" functionality can be emulated via:
> >
> > echo -n 0x78146312 > tstctl
> >
> > and switch back to regular mode can be done with:
> >
> > echo -n 0x78146310 > tstctl
>
> Can't we make this more userfriendly by exposing either a test pattern
> index, or a string ?

We could, but then a) it would require more code in the driver b) the
files wouldn't correspond directly to something described in the
part's datasheet. Just didn't seem worth it to me.

> Do all bits in the register need to be controlled
> from userspace ?

Pretty much, yes. It's formatted as RR_GG_BB_X_M, where R, G, B
specifies color used for various patterns, X is irrelevant and M
specifies test pattern to use.

>
> > Note that switching to any of the test patterns, will NOT trigger link
> > re-establishment whereas switching to normal operation WILL. This is
> > done so:
> >
> > a) we can isolate and verify (e)DP link functionality by switching to
> >one of the test patters
> >
> > b) trigger a link re-establishment by switching back to normal mode
> >
> > Signed-off-by: Andrey Smirnov 
> > Cc: Andrzej Hajda 
> > Cc: Laurent Pinchart 
> > Cc: Tomi Valkeinen 
> > Cc: Cory Tusar 
> > Cc: Chris Healy 
> > Cc: Lucas Stach 
> > Cc: dri-devel@lists.freedesktop.org
> > Cc: linux-ker...@vger.kernel.org
> > ---
> >  drivers/gpu/drm/bridge/tc358767.c | 137 ++
> >  1 file changed, 101 insertions(+), 36 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/tc358767.c 
> > b/drivers/gpu/drm/bridge/tc358767.c
> > index 6308d93ad91d..7a795b613ed0 100644
> > --- a/drivers/gpu/drm/bridge/tc358767.c
> > +++ b/drivers/gpu/drm/bridge/tc358767.c
> > @@ -17,6 +17,7 @@
> >
> >  #include 
> >  #include 
> > +#include 
> >  #include 
> >  #include 
> >  #include 
> > @@ -222,11 +223,10 @@
> >  #define COLOR_B  GENMASK(15, 8)
> >  #define ENI2CFILTER  BIT(4)
> >  #define COLOR_BAR_MODE   GENMASK(1, 0)
> > +#define COLOR_BAR_MODE_NORMAL0
> >  #define COLOR_BAR_MODE_BARS  2
> > -#define PLL_DBG  0x0a04
> >
> > -static bool tc_test_pattern;
> > -module_param_named(test, tc_test_pattern, bool, 0644);
>
> I assume that his being a debug feature there's no system relying on the
> module parameter that would break if you remove it ?
>

Yeah, I don't know of any system that needs that parameter. It seems
pretty useless for anything but basic debugging.

> > +#define PLL_DBG  0x0a04
> >
> >  struct tc_edp_link {
> >   struct drm_dp_link  base;
> > @@ -789,16 +789,6 @@ static int tc_set_video_mode(struct tc_data *tc,
> >   if (ret)
> >   return ret;
> >
> > - /* Test pattern settings */
> > - ret = regmap_write(tc->regmap, TSTCTL,
> > -FIELD_PREP(COLOR_R, 120) |
> > -FIELD_PREP(COLOR_G, 20) |
> > -FIELD_PREP(COLOR_B, 99) |
> > -ENI2CFILTER |
> > -FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
> > - if (ret)
> > - return ret;
> > -
> >   /* DP Main Stream Attributes */
> >   vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
> >   ret = regmap_write(tc->regmap, DP0_VIDSYNCDELAY,
> > @@ -1150,14 +1140,6 @@ static int tc_stream_enable(struct tc_data *tc)
> >
> >   dev_dbg(tc->dev, "enable video stream\n");
> >
> > - /* PXL PLL setup */
> > - if (tc_test_pattern) {
> > - ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk),
> > - 1000 * tc->mode.clock);
> > - if (ret)
> > - return ret;
> 

[PATCH] drm/bridge: tc358767: Expose test mode functionality via debugfs

2019-08-26 Thread Andrey Smirnov
Presently, the driver code artificially limits test pattern mode to a
single pattern with fixed color selection. It being a kernel module
parameter makes switching "test patter" <-> "proper output" modes
on-the-fly clunky and outright impossible if the driver is built into
the kernel.

To improve the situation a bit, convert current test pattern code to
use debugfs instead by exposing "TestCtl" register. This way old
"tc_test_pattern=1" functionality can be emulated via:

echo -n 0x78146312 > tstctl

and switch back to regular mode can be done with:

echo -n 0x78146310 > tstctl

Note that switching to any of the test patterns, will NOT trigger link
re-establishment whereas switching to normal operation WILL. This is
done so:

a) we can isolate and verify (e)DP link functionality by switching to
   one of the test patters

b) trigger a link re-establishment by switching back to normal mode

Signed-off-by: Andrey Smirnov 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 137 ++
 1 file changed, 101 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 6308d93ad91d..7a795b613ed0 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -17,6 +17,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -222,11 +223,10 @@
 #define COLOR_BGENMASK(15, 8)
 #define ENI2CFILTERBIT(4)
 #define COLOR_BAR_MODE GENMASK(1, 0)
+#define COLOR_BAR_MODE_NORMAL  0
 #define COLOR_BAR_MODE_BARS2
-#define PLL_DBG0x0a04
 
-static bool tc_test_pattern;
-module_param_named(test, tc_test_pattern, bool, 0644);
+#define PLL_DBG0x0a04
 
 struct tc_edp_link {
struct drm_dp_link  base;
@@ -789,16 +789,6 @@ static int tc_set_video_mode(struct tc_data *tc,
if (ret)
return ret;
 
-   /* Test pattern settings */
-   ret = regmap_write(tc->regmap, TSTCTL,
-  FIELD_PREP(COLOR_R, 120) |
-  FIELD_PREP(COLOR_G, 20) |
-  FIELD_PREP(COLOR_B, 99) |
-  ENI2CFILTER |
-  FIELD_PREP(COLOR_BAR_MODE, COLOR_BAR_MODE_BARS));
-   if (ret)
-   return ret;
-
/* DP Main Stream Attributes */
vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
ret = regmap_write(tc->regmap, DP0_VIDSYNCDELAY,
@@ -1150,14 +1140,6 @@ static int tc_stream_enable(struct tc_data *tc)
 
dev_dbg(tc->dev, "enable video stream\n");
 
-   /* PXL PLL setup */
-   if (tc_test_pattern) {
-   ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk),
-   1000 * tc->mode.clock);
-   if (ret)
-   return ret;
-   }
-
ret = tc_set_video_mode(tc, >mode);
if (ret)
return ret;
@@ -1186,12 +1168,8 @@ static int tc_stream_enable(struct tc_data *tc)
if (ret)
return ret;
/* Set input interface */
-   value = DP0_AUDSRC_NO_INPUT;
-   if (tc_test_pattern)
-   value |= DP0_VIDSRC_COLOR_BAR;
-   else
-   value |= DP0_VIDSRC_DPI_RX;
-   ret = regmap_write(tc->regmap, SYSCTRL, value);
+   ret = regmap_write(tc->regmap, SYSCTRL,
+  DP0_AUDSRC_NO_INPUT | DP0_VIDSRC_DPI_RX);
if (ret)
return ret;
 
@@ -1220,39 +1198,44 @@ static void tc_bridge_pre_enable(struct drm_bridge 
*bridge)
drm_panel_prepare(tc->panel);
 }
 
-static void tc_bridge_enable(struct drm_bridge *bridge)
+static int __tc_bridge_enable(struct tc_data *tc)
 {
-   struct tc_data *tc = bridge_to_tc(bridge);
int ret;
 
ret = tc_get_display_props(tc);
if (ret < 0) {
dev_err(tc->dev, "failed to read display props: %d\n", ret);
-   return;
+   return ret;
}
 
ret = tc_main_link_enable(tc);
if (ret < 0) {
dev_err(tc->dev, "main link enable error: %d\n", ret);
-   return;
+   return ret;
}
 
ret = tc_stream_enable(tc);
if (ret < 0) {
dev_err(tc->dev, "main link stream start error: %d\n", ret);
tc_main_link_disable(tc);
-   return;
}
 
-   drm_panel_enable(tc->panel);
+   return ret;
 }
 
-static void tc_bridge_disable(struct drm_bridge *bridge)
+static void tc_bridge_enable(struct drm_bridge *bridge)
 {
struct tc_data *tc 

[PATCH v6 05/15] drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors

2019-06-18 Thread Andrey Smirnov
A very unfortunate aspect of tc_write()/tc_read() macro helpers is
that they capture quite a bit of context around them and thus require
the caller to have magic variables 'ret' and 'tc' as well as label
'err'. That makes a number of code paths rather counter-intuitive and
somewhat clunky, for example tc_stream_clock_calc() ends up being like
this:

int ret;

tc_write(DP0_VIDMNGEN1, 32768);

return 0;
err:
return ret;

which is rather surprising when you read the code for the first
time. Since those helpers arguably aren't really saving that much code
and there's no way of fixing them without making them too verbose to
be worth it change the driver code to not use them at all.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 383 ++
 1 file changed, 231 insertions(+), 152 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 5b78021d6c5b..6a3e7c7e1189 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -280,20 +280,6 @@ static inline struct tc_data *connector_to_tc(struct 
drm_connector *c)
return container_of(c, struct tc_data, connector);
 }
 
-/* Simple macros to avoid repeated error checks */
-#define tc_write(reg, var) \
-   do {\
-   ret = regmap_write(tc->regmap, reg, var);   \
-   if (ret)\
-   goto err;   \
-   } while (0)
-#define tc_read(reg, var)  \
-   do {\
-   ret = regmap_read(tc->regmap, reg, var);\
-   if (ret)\
-   goto err;   \
-   } while (0)
-
 static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
  unsigned int cond_mask,
  unsigned int cond_value,
@@ -351,7 +337,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
 
ret = tc_aux_wait_busy(tc, 100);
if (ret)
-   goto err;
+   return ret;
 
if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
/* Store data */
@@ -362,7 +348,11 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
tmp = (tmp << 8) | buf[i];
i++;
if (((i % 4) == 0) || (i == size)) {
-   tc_write(DP0_AUXWDATA((i - 1) >> 2), tmp);
+   ret = regmap_write(tc->regmap,
+  DP0_AUXWDATA((i - 1) >> 2),
+  tmp);
+   if (ret)
+   return ret;
tmp = 0;
}
}
@@ -372,23 +362,32 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
}
 
/* Store address */
-   tc_write(DP0_AUXADDR, msg->address);
+   ret = regmap_write(tc->regmap, DP0_AUXADDR, msg->address);
+   if (ret)
+   return ret;
/* Start transfer */
-   tc_write(DP0_AUXCFG0, ((size - 1) << 8) | request);
+   ret = regmap_write(tc->regmap, DP0_AUXCFG0,
+  ((size - 1) << 8) | request);
+   if (ret)
+   return ret;
 
ret = tc_aux_wait_busy(tc, 100);
if (ret)
-   goto err;
+   return ret;
 
ret = tc_aux_get_status(tc, >reply);
if (ret)
-   goto err;
+   return ret;
 
if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
/* Read data */
while (i < size) {
-   if ((i % 4) == 0)
-   tc_read(DP0_AUXRDATA(i >> 2), );
+   if ((i % 4) == 0) {
+   ret = regmap_read(tc->regmap,
+ DP0_AUXRDATA(i >> 2), );
+   if (ret)
+   return ret;
+   }
buf[i] = tmp & 0xff;
tmp = tmp >> 8;
i++;
@@ -396,8 +395,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,

[PATCH v6 13/15] drm/bridge: tc358767: Drop unnecessary 8 byte buffer

2019-06-18 Thread Andrey Smirnov
tc_get_display_props() never reads more than a byte via AUX, so
there's no need to reserve 8 for that purpose. No function change
intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 7cc26e26f371..f0baf6d7ca80 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -645,8 +645,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
 static int tc_get_display_props(struct tc_data *tc)
 {
int ret;
-   /* temp buffer */
-   u8 tmp[8];
+   u8 reg;
 
/* Read DP Rx Link Capability */
ret = drm_dp_link_probe(>aux, >link.base);
@@ -662,21 +661,21 @@ static int tc_get_display_props(struct tc_data *tc)
tc->link.base.num_lanes = 2;
}
 
-   ret = drm_dp_dpcd_readb(>aux, DP_MAX_DOWNSPREAD, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_MAX_DOWNSPREAD, );
if (ret < 0)
goto err_dpcd_read;
-   tc->link.spread = tmp[0] & DP_MAX_DOWNSPREAD_0_5;
+   tc->link.spread = reg & DP_MAX_DOWNSPREAD_0_5;
 
-   ret = drm_dp_dpcd_readb(>aux, DP_MAIN_LINK_CHANNEL_CODING, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_MAIN_LINK_CHANNEL_CODING, );
if (ret < 0)
goto err_dpcd_read;
 
tc->link.scrambler_dis = false;
/* read assr */
-   ret = drm_dp_dpcd_readb(>aux, DP_EDP_CONFIGURATION_SET, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_EDP_CONFIGURATION_SET, );
if (ret < 0)
goto err_dpcd_read;
-   tc->link.assr = tmp[0] & DP_ALTERNATE_SCRAMBLER_RESET_ENABLE;
+   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,
-- 
2.21.0



[PATCH v6 10/15] drm/bridge: tc358767: Introduce tc_set_syspllparam()

2019-06-18 Thread Andrey Smirnov
Move common code converting clock rate to an appropriate constant and
configuring SYS_PLLPARAM register into a separate routine and convert
the rest of the code to use it. No functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Laurent Pinchart 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Cory Tusar 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 46 +++
 1 file changed, 16 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index b01c1c8341e1..7a3a1b2d5c56 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -565,35 +565,40 @@ static int tc_stream_clock_calc(struct tc_data *tc)
return regmap_write(tc->regmap, DP0_VIDMNGEN1, 32768);
 }
 
-static int tc_aux_link_setup(struct tc_data *tc)
+static int tc_set_syspllparam(struct tc_data *tc)
 {
unsigned long rate;
-   u32 dp0_auxcfg1;
-   u32 value;
-   int ret;
+   u32 pllparam = SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
 
rate = clk_get_rate(tc->refclk);
switch (rate) {
case 3840:
-   value = REF_FREQ_38M4;
+   pllparam |= REF_FREQ_38M4;
break;
case 2600:
-   value = REF_FREQ_26M;
+   pllparam |= REF_FREQ_26M;
break;
case 1920:
-   value = REF_FREQ_19M2;
+   pllparam |= REF_FREQ_19M2;
break;
case 1300:
-   value = REF_FREQ_13M;
+   pllparam |= REF_FREQ_13M;
break;
default:
dev_err(tc->dev, "Invalid refclk rate: %lu Hz\n", rate);
return -EINVAL;
}
 
+   return regmap_write(tc->regmap, SYS_PLLPARAM, pllparam);
+}
+
+static int tc_aux_link_setup(struct tc_data *tc)
+{
+   int ret;
+   u32 dp0_auxcfg1;
+
/* Setup DP-PHY / PLL */
-   value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
-   ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+   ret = tc_set_syspllparam(tc);
if (ret)
goto err;
 
@@ -852,7 +857,6 @@ static int tc_main_link_enable(struct tc_data *tc)
 {
struct drm_dp_aux *aux = >aux;
struct device *dev = tc->dev;
-   unsigned int rate;
u32 dp_phy_ctrl;
u32 value;
int ret;
@@ -880,25 +884,7 @@ static int tc_main_link_enable(struct tc_data *tc)
if (ret)
return ret;
 
-   rate = clk_get_rate(tc->refclk);
-   switch (rate) {
-   case 3840:
-   value = REF_FREQ_38M4;
-   break;
-   case 2600:
-   value = REF_FREQ_26M;
-   break;
-   case 1920:
-   value = REF_FREQ_19M2;
-   break;
-   case 1300:
-   value = REF_FREQ_13M;
-   break;
-   default:
-   return -EINVAL;
-   }
-   value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
-   ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+   ret = tc_set_syspllparam(tc);
if (ret)
return ret;
 
-- 
2.21.0



[PATCH v6 12/15] drm/bridge: tc358767: Simplify tc_aux_wait_busy()

2019-06-18 Thread Andrey Smirnov
We never pass anything but 100 as timeout_ms to tc_aux_wait_busy(), so
we may as well hardcode that value and simplify function's signature.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index fe672f6bba73..7cc26e26f371 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -292,10 +292,9 @@ static inline int tc_poll_timeout(struct tc_data *tc, 
unsigned int addr,
sleep_us, timeout_us);
 }
 
-static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
+static int tc_aux_wait_busy(struct tc_data *tc)
 {
-   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
-  1000, 1000 * timeout_ms);
+   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 1000, 10);
 }
 
 static int tc_aux_write_data(struct tc_data *tc, const void *data,
@@ -339,7 +338,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (size == 0)
return 0;
 
-   ret = tc_aux_wait_busy(tc, 100);
+   ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
 
@@ -367,7 +366,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   ret = tc_aux_wait_busy(tc, 100);
+   ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
 
-- 
2.21.0



[PATCH v6 07/15] drm/bridge: tc358767: Simplify AUX data write

2019-06-18 Thread Andrey Smirnov
Simplify AUX data write by dropping index arithmetic and shifting and
replacing it with a call to a helper function that does two things:

1. Copies user-provided data into a write buffer
2. Transfers contents of the write buffer to up to 4 32-bit
   registers on the chip

Note that separate data endianness fix:

tmp = (tmp << 8) | buf[i];

that was reserved for DP_AUX_I2C_WRITE looks really strange, since it
will place data differently depending on the passed user-data
size. E.g. for a write of 1 byte, data transferred to the chip would
look like:

[byte0] [dummy1] [dummy2] [dummy3]

whereas for a write of 4 bytes we'd get:

[byte3] [byte2] [byte1] [byte0]

Since there's no indication in the datasheet that I2C write buffer
should be treated differently than AUX write buffer and no comment in
the original code explaining why it was done this way, that special
I2C write buffer transformation was dropped in this patch.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 48 +--
 1 file changed, 26 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 02f6d907f5c4..a441e8e66287 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -321,6 +321,21 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
 }
 
+static int tc_aux_write_data(struct tc_data *tc, const void *data,
+size_t size)
+{
+   u32 auxwdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)] = { 0 };
+   int ret, count = ALIGN(size, sizeof(u32));
+
+   memcpy(auxwdata, data, size);
+
+   ret = regmap_raw_write(tc->regmap, DP0_AUXWDATA(0), auxwdata, count);
+   if (ret)
+   return ret;
+
+   return size;
+}
+
 static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
 {
u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
@@ -341,9 +356,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct tc_data *tc = aux_to_tc(aux);
size_t size = min_t(size_t, 8, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
-   u8 *buf = msg->buffer;
-   u32 tmp = 0;
-   int i = 0;
int ret;
 
if (size == 0)
@@ -353,25 +365,17 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
-   /* Store data */
-   while (i < size) {
-   if (request == DP_AUX_NATIVE_WRITE)
-   tmp = tmp | (buf[i] << (8 * (i & 0x3)));
-   else
-   tmp = (tmp << 8) | buf[i];
-   i++;
-   if (((i % 4) == 0) || (i == size)) {
-   ret = regmap_write(tc->regmap,
-  DP0_AUXWDATA((i - 1) >> 2),
-  tmp);
-   if (ret)
-   return ret;
-   tmp = 0;
-   }
-   }
-   } else if (request != DP_AUX_I2C_READ &&
-  request != DP_AUX_NATIVE_READ) {
+   switch (request) {
+   case DP_AUX_NATIVE_READ:
+   case DP_AUX_I2C_READ:
+   break;
+   case DP_AUX_NATIVE_WRITE:
+   case DP_AUX_I2C_WRITE:
+   ret = tc_aux_write_data(tc, msg->buffer, size);
+   if (ret < 0)
+   return ret;
+   break;
+   default:
return -EINVAL;
}
 
-- 
2.21.0



[PATCH v6 09/15] drm/bridge: tc358767: Use reported AUX transfer size

2019-06-18 Thread Andrey Smirnov
Don't assume that requested data transfer size is the same as amount
of data that was transferred. Change the code to get that information
from DP0_AUXSTATUS instead.

Since the check for AUX_BUSY in tc_aux_get_status() is pointless (it
will always called after tc_aux_wait_busy()) and there's only one user
of it, inline its code into tc_aux_transfer() instead of trying to
accommodate the change above.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 40 ++-
 1 file changed, 12 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index bdbf88057946..b01c1c8341e1 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -152,10 +152,10 @@
 #define DP0_AUXWDATA(i)(0x066c + (i) * 4)
 #define DP0_AUXRDATA(i)(0x067c + (i) * 4)
 #define DP0_AUXSTATUS  0x068c
-#define AUX_STATUS_MASK0xf0
-#define AUX_STATUS_SHIFT   4
-#define AUX_TIMEOUTBIT(1)
-#define AUX_BUSY   BIT(0)
+#define AUX_BYTES  GENMASK(15, 8)
+#define AUX_STATUS GENMASK(7, 4)
+#define AUX_TIMEOUTBIT(1)
+#define AUX_BUSY   BIT(0)
 #define DP0_AUXI2CADR  0x0698
 
 /* Link Training */
@@ -298,29 +298,6 @@ static int tc_aux_wait_busy(struct tc_data *tc, unsigned 
int timeout_ms)
   1000, 1000 * timeout_ms);
 }
 
-static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
-{
-   int ret;
-   u32 value;
-
-   ret = regmap_read(tc->regmap, DP0_AUXSTATUS, );
-   if (ret < 0)
-   return ret;
-
-   if (value & AUX_BUSY) {
-   dev_err(tc->dev, "aux busy!\n");
-   return -EBUSY;
-   }
-
-   if (value & AUX_TIMEOUT) {
-   dev_err(tc->dev, "aux access timeout!\n");
-   return -ETIMEDOUT;
-   }
-
-   *reply = (value & AUX_STATUS_MASK) >> AUX_STATUS_SHIFT;
-   return 0;
-}
-
 static int tc_aux_write_data(struct tc_data *tc, const void *data,
 size_t size)
 {
@@ -356,6 +333,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct tc_data *tc = aux_to_tc(aux);
size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
+   u32 auxstatus;
int ret;
 
if (size == 0)
@@ -393,10 +371,16 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   ret = tc_aux_get_status(tc, >reply);
+   ret = regmap_read(tc->regmap, DP0_AUXSTATUS, );
if (ret)
return ret;
 
+   if (auxstatus & AUX_TIMEOUT)
+   return -ETIMEDOUT;
+
+   size = FIELD_GET(AUX_BYTES, auxstatus);
+   msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
+
switch (request) {
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
-- 
2.21.0



[PATCH v6 08/15] drm/bridge: tc358767: Increase AUX transfer length limit

2019-06-18 Thread Andrey Smirnov
According to the datasheet tc358767 can transfer up to 16 bytes via
its AUX channel, so the artificial limit of 8 appears to be too
low. However only up to 15-bytes seem to be actually supported and
trying to use 16-byte transfers results in transfers failing
sporadically (with bogus status in case of I2C transfers), so limit it
to 15.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 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 a441e8e66287..bdbf88057946 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -354,7 +354,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
struct tc_data *tc = aux_to_tc(aux);
-   size_t size = min_t(size_t, 8, msg->size);
+   size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
int ret;
 
-- 
2.21.0



[PATCH v6 11/15] drm/bridge: tc358767: Introduce tc_pllupdate()

2019-06-18 Thread Andrey Smirnov
tc_wait_pll_lock() is always called as a follow-up for updating
PLLUPDATE and PLLEN bit of a given PLL control register. To simplify
things, merge the two operation into a single helper function
tc_pllupdate() and convert the rest of the code to use it. No
functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Laurent Pinchart 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 30 ++
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 7a3a1b2d5c56..fe672f6bba73 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -427,10 +427,18 @@ static u32 tc_srcctrl(struct tc_data *tc)
return reg;
 }
 
-static void tc_wait_pll_lock(struct tc_data *tc)
+static int tc_pllupdate(struct tc_data *tc, unsigned int pllctrl)
 {
+   int ret;
+
+   ret = regmap_write(tc->regmap, pllctrl, PLLUPDATE | PLLEN);
+   if (ret)
+   return ret;
+
/* Wait for PLL to lock: up to 2.09 ms, depending on refclk */
usleep_range(3000, 6000);
+
+   return 0;
 }
 
 static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
@@ -530,13 +538,7 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, 
u32 pixelclock)
return ret;
 
/* Force PLL parameter update and disable bypass */
-   ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLUPDATE | PLLEN);
-   if (ret)
-   return ret;
-
-   tc_wait_pll_lock(tc);
-
-   return 0;
+   return tc_pllupdate(tc, PXL_PLLCTRL);
 }
 
 static int tc_pxl_pll_dis(struct tc_data *tc)
@@ -610,15 +612,13 @@ static int tc_aux_link_setup(struct tc_data *tc)
 * Initially PLLs are in bypass. Force PLL parameter update,
 * disable PLL bypass, enable PLL
 */
-   ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate(tc, DP0_PLLCTRL);
if (ret)
goto err;
-   tc_wait_pll_lock(tc);
 
-   ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate(tc, DP1_PLLCTRL);
if (ret)
goto err;
-   tc_wait_pll_lock(tc);
 
ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
@@ -898,15 +898,13 @@ static int tc_main_link_enable(struct tc_data *tc)
return ret;
 
/* PLL setup */
-   ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate(tc, DP0_PLLCTRL);
if (ret)
return ret;
-   tc_wait_pll_lock(tc);
 
-   ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate(tc, DP1_PLLCTRL);
if (ret)
return ret;
-   tc_wait_pll_lock(tc);
 
/* Reset/Enable Main Links */
dp_phy_ctrl |= DP_PHY_RST | PHY_M1_RST | PHY_M0_RST;
-- 
2.21.0



[PATCH v6 14/15] drm/bridge: tc358767: Replace magic number in tc_main_link_enable()

2019-06-18 Thread Andrey Smirnov
We don't need 8 byte array, DP_LINK_STATUS_SIZE (6) should be
enough. This also gets rid of a magic number as a bonus.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 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 f0baf6d7ca80..3f8a15390813 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -858,7 +858,7 @@ static int tc_main_link_enable(struct tc_data *tc)
u32 dp_phy_ctrl;
u32 value;
int ret;
-   u8 tmp[8];
+   u8 tmp[DP_LINK_STATUS_SIZE];
 
dev_dbg(tc->dev, "link enable\n");
 
-- 
2.21.0



[PATCH v6 06/15] drm/bridge: tc358767: Simplify AUX data read

2019-06-18 Thread Andrey Smirnov
Simplify AUX data read by removing index arithmetic and shifting with
a helper function that does two things:

1. Fetch data from up to 4 32-bit registers from the chip
2. Copy read data into user provided array.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 31 ++-
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 6a3e7c7e1189..02f6d907f5c4 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -321,6 +321,20 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
 }
 
+static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
+{
+   u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
+   int ret, count = ALIGN(size, sizeof(u32));
+
+   ret = regmap_raw_read(tc->regmap, DP0_AUXRDATA(0), auxrdata, count);
+   if (ret)
+   return ret;
+
+   memcpy(data, auxrdata, size);
+
+   return size;
+}
+
 static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
@@ -379,19 +393,10 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
-   /* Read data */
-   while (i < size) {
-   if ((i % 4) == 0) {
-   ret = regmap_read(tc->regmap,
- DP0_AUXRDATA(i >> 2), );
-   if (ret)
-   return ret;
-   }
-   buf[i] = tmp & 0xff;
-   tmp = tmp >> 8;
-   i++;
-   }
+   switch (request) {
+   case DP_AUX_NATIVE_READ:
+   case DP_AUX_I2C_READ:
+   return tc_aux_read_data(tc, msg->buffer, size);
}
 
return size;
-- 
2.21.0



[PATCH v6 15/15] drm/bridge: tc358767: Add support for address-only I2C transfers

2019-06-18 Thread Andrey Smirnov
Transfer size of zero means a request to do an address-only
transfer. Since the HW support this, we probably shouldn't be just
ignoring such requests. While at it allow DP_AUX_I2C_MOT flag to pass
through, since it is supported by the HW as well.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 42 +++
 1 file changed, 31 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 3f8a15390813..7b8e19d6cf29 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -145,6 +145,8 @@
 
 /* AUX channel */
 #define DP0_AUXCFG00x0660
+#define DP0_AUXCFG0_BSIZE  GENMASK(11, 8)
+#define DP0_AUXCFG0_ADDR_ONLY  BIT(4)
 #define DP0_AUXCFG10x0664
 #define AUX_RX_FILTER_EN   BIT(16)
 
@@ -326,6 +328,18 @@ static int tc_aux_read_data(struct tc_data *tc, void 
*data, size_t size)
return size;
 }
 
+static u32 tc_auxcfg0(struct drm_dp_aux_msg *msg, size_t size)
+{
+   u32 auxcfg0 = msg->request;
+
+   if (size)
+   auxcfg0 |= FIELD_PREP(DP0_AUXCFG0_BSIZE, size - 1);
+   else
+   auxcfg0 |= DP0_AUXCFG0_ADDR_ONLY;
+
+   return auxcfg0;
+}
+
 static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
@@ -335,9 +349,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;
 
-   if (size == 0)
-   return 0;
-
ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
@@ -348,9 +359,11 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
break;
case DP_AUX_NATIVE_WRITE:
case DP_AUX_I2C_WRITE:
-   ret = tc_aux_write_data(tc, msg->buffer, size);
-   if (ret < 0)
-   return ret;
+   if (size) {
+   ret = tc_aux_write_data(tc, msg->buffer, size);
+   if (ret < 0)
+   return ret;
+   }
break;
default:
return -EINVAL;
@@ -361,8 +374,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
/* Start transfer */
-   ret = regmap_write(tc->regmap, DP0_AUXCFG0,
-  ((size - 1) << 8) | request);
+   ret = regmap_write(tc->regmap, DP0_AUXCFG0, tc_auxcfg0(msg, size));
if (ret)
return ret;
 
@@ -376,14 +388,22 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
 
if (auxstatus & AUX_TIMEOUT)
return -ETIMEDOUT;
-
-   size = FIELD_GET(AUX_BYTES, auxstatus);
+   /*
+* For some reason address-only DP_AUX_I2C_WRITE (MOT), still
+* reports 1 byte transferred in its status. To deal we that
+* we ignore aux_bytes field if we know that this was an
+* address-only transfer
+*/
+   if (size)
+   size = FIELD_GET(AUX_BYTES, auxstatus);
msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
 
switch (request) {
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
-   return tc_aux_read_data(tc, msg->buffer, size);
+   if (size)
+   return tc_aux_read_data(tc, msg->buffer, size);
+   break;
}
 
return size;
-- 
2.21.0



[PATCH v6 04/15] drm/bridge: tc358767: Simplify tc_set_video_mode()

2019-06-18 Thread Andrey Smirnov
Simplify tc_set_video_mode() by replacing explicit shifting using
macros from . No functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 106 ++
 1 file changed, 78 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 31f5045e7e42..5b78021d6c5b 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -24,6 +24,7 @@
  * GNU General Public License for more details.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -56,6 +57,7 @@
 
 /* Video Path */
 #define VPCTRL00x0450
+#define VSDELAYGENMASK(31, 20)
 #define OPXLFMT_RGB666 (0 << 8)
 #define OPXLFMT_RGB888 (1 << 8)
 #define FRMSYNC_DISABLED   (0 << 4) /* Video Timing Gen Disabled */
@@ -63,9 +65,17 @@
 #define MSF_DISABLED   (0 << 0) /* Magic Square FRC disabled */
 #define MSF_ENABLED(1 << 0) /* Magic Square FRC enabled */
 #define HTIM01 0x0454
+#define HPWGENMASK(8, 0)
+#define HBPR   GENMASK(24, 16)
 #define HTIM02 0x0458
+#define HDISPR GENMASK(10, 0)
+#define HFPR   GENMASK(24, 16)
 #define VTIM01 0x045c
+#define VSPR   GENMASK(7, 0)
+#define VBPR   GENMASK(23, 16)
 #define VTIM02 0x0460
+#define VFPR   GENMASK(23, 16)
+#define VDISPR GENMASK(10, 0)
 #define VFUEN0 0x0464
 #define VFUEN  BIT(0)   /* Video Frame Timing Upload */
 
@@ -108,14 +118,28 @@
 /* Main Channel */
 #define DP0_SECSAMPLE  0x0640
 #define DP0_VIDSYNCDELAY   0x0644
+#define VID_SYNC_DLY   GENMASK(15, 0)
+#define THRESH_DLY GENMASK(31, 16)
+
 #define DP0_TOTALVAL   0x0648
+#define H_TOTALGENMASK(15, 0)
+#define V_TOTALGENMASK(31, 16)
 #define DP0_STARTVAL   0x064c
+#define H_STARTGENMASK(15, 0)
+#define V_STARTGENMASK(31, 16)
 #define DP0_ACTIVEVAL  0x0650
+#define H_ACT  GENMASK(15, 0)
+#define V_ACT  GENMASK(31, 16)
+
 #define DP0_SYNCVAL0x0654
+#define VS_WIDTH   GENMASK(30, 16)
+#define HS_WIDTH   GENMASK(14, 0)
 #define SYNCVAL_HS_POL_ACTIVE_LOW  (1 << 15)
 #define SYNCVAL_VS_POL_ACTIVE_LOW  (1 << 31)
 #define DP0_MISC   0x0658
 #define TU_SIZE_RECOMMENDED(63) /* LSCLK cycles per TU */
+#define MAX_TU_SYMBOL  GENMASK(28, 23)
+#define TU_SIZEGENMASK(21, 16)
 #define BPC_6  (0 << 5)
 #define BPC_8  (1 << 5)
 
@@ -192,6 +216,12 @@
 
 /* Test & Debug */
 #define TSTCTL 0x0a00
+#define COLOR_RGENMASK(31, 24)
+#define COLOR_GGENMASK(23, 16)
+#define COLOR_BGENMASK(15, 8)
+#define ENI2CFILTERBIT(4)
+#define COLOR_BAR_MODE GENMASK(1, 0)
+#define COLOR_BAR_MODE_BARS2
 #define PLL_DBG0x0a04
 
 static bool tc_test_pattern;
@@ -672,6 +702,7 @@ static int tc_set_video_mode(struct tc_data *tc,
int upper_margin = mode->vtotal - mode->vsync_end;
int lower_margin = mode->vsync_start - mode->vdisplay;
int vsync_len = mode->vsync_end - mode->vsync_start;
+   u32 dp0_syncval;
 
/*
 * Recommended maximum number of symbols transferred in a transfer unit:
@@ -696,50 +727,69 @@ static int tc_set_video_mode(struct tc_data *tc,
 * assume we do not need any delay when DPI is a source of
 * sync signals
 */
-   tc_write(VPCTRL0, (0 << 20) /* VSDELAY */ |
+   tc_write(VPCTRL0,
+FIELD_PREP(VSDELAY, 0) |
 OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
-   tc_write(HTIM01, (ALIGN(left_margin, 2) << 16) | /* H back porch */
-(ALIGN(hsync_len, 2) << 0));/* Hsync */
-   tc_write(HTIM02, (ALIGN(right_margin, 2) << 16) |  /* H front porch */
-(ALIGN(mode->hdisplay, 2) << 0)); /* width */
-   tc_write(VTIM01, (upper_margin << 16) | /* V back porch */
-(vsync_len << 0)); /* Vsync */
-   tc_write(VTIM02, (lower_margin <<

[PATCH v6 03/15] drm/bridge: tc358767: Simplify polling in tc_link_training()

2019-06-18 Thread Andrey Smirnov
Replace explicit polling in tc_link_training() with equivalent call to
tc_poll_timeout() for simplicity. No functional change intended (not
including slightly altered debug output).

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 15 ++-
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index f463ef6d4271..31f5045e7e42 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -748,22 +748,19 @@ static int tc_set_video_mode(struct tc_data *tc,
 
 static int tc_wait_link_training(struct tc_data *tc)
 {
-   u32 timeout = 1000;
u32 value;
int ret;
 
-   do {
-   udelay(1);
-   tc_read(DP0_LTSTAT, );
-   } while ((!(value & LT_LOOPDONE)) && (--timeout));
-
-   if (timeout == 0) {
+   ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
+ LT_LOOPDONE, 1, 1000);
+   if (ret) {
dev_err(tc->dev, "Link training timeout waiting for 
LT_LOOPDONE!\n");
-   return -ETIMEDOUT;
+   return ret;
}
 
-   return (value >> 8) & 0x7;
+   tc_read(DP0_LTSTAT, );
 
+   return (value >> 8) & 0x7;
 err:
return ret;
 }
-- 
2.21.0



[PATCH v6 02/15] drm/bridge: tc358767: Simplify polling in tc_main_link_setup()

2019-06-18 Thread Andrey Smirnov
Replace explicit polling loop with equivalent call to
tc_poll_timeout() for brevity. No functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 12 +++-
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index fb8a1942ec54..f463ef6d4271 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -774,7 +774,6 @@ static int tc_main_link_enable(struct tc_data *tc)
struct device *dev = tc->dev;
unsigned int rate;
u32 dp_phy_ctrl;
-   int timeout;
u32 value;
int ret;
u8 tmp[8];
@@ -831,15 +830,10 @@ static int tc_main_link_enable(struct tc_data *tc)
dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
tc_write(DP_PHY_CTRL, dp_phy_ctrl);
 
-   timeout = 1000;
-   do {
-   tc_read(DP_PHY_CTRL, );
-   udelay(1);
-   } while ((!(value & PHY_RDY)) && (--timeout));
-
-   if (timeout == 0) {
+   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
+   if (ret) {
dev_err(dev, "timeout waiting for phy become ready");
-   return -ETIMEDOUT;
+   return ret;
}
 
/* Set misc: 8 bits per color */
-- 
2.21.0



[PATCH v6 00/15] tc358767 driver improvements

2019-06-18 Thread Andrey Smirnov
Everyone:

This series contains various improvements (at least in my mind) and
fixes that I made to tc358767 while working with the code of the
driver. Hopefuly each patch is self explanatory.

Feedback is welcome!

Thanks,
Andrey Smirnov

Changes since [v5]:

- Fixed regression in "drm/bridge: tc358767: Add support for
  address-only I2C transfers" that broke EDID reading

- Moved said patch to be the last in case it is still causing
  problems and needs to be dropped

Changes since [v4]:

- tc_pllupdate_pllen() renamed to tc_pllupdate()

- Collected Reviewed-bys from Andrzej for the rest of the series

Changes since [v3]:

- Collected Reviewed-bys from Andrzej

- Dropped explicit check for -ETIMEDOUT in "drm/bridge: tc358767:
  Simplify polling in tc_main_link_setup()" for consistency

- AUX transfer code converted to user regmap_raw_read(),
  regmap_raw_write()

Changes since [v2]:

- Patchset rebased on top of v4 of Tomi's series that recently
  went in (https://patchwork.freedesktop.org/series/58176/#rev5)
  
- AUX transfer code converted to user regmap_bulk_read(),
  regmap_bulk_write()

Changes since [v1]:

- Patchset rebased on top of
  https://patchwork.freedesktop.org/series/58176/
  
- Patches to remove both tc_write() and tc_read() helpers added

- Patches to rework AUX transfer code added

- Both "drm/bridge: tc358767: Simplify polling in
  tc_main_link_setup()" and "drm/bridge: tc358767: Simplify
  polling in tc_link_training()" changed to use tc_poll_timeout()
  instead of regmap_read_poll_timeout()

[v5] lkml.kernel.org/r/20190612083252.15321-1-andrew.smir...@gmail.com
[v4] lkml.kernel.org/r/20190607044550.13361-1-andrew.smir...@gmail.com
[v3] lkml.kernel.org/r/20190605070507.11417-1-andrew.smir...@gmail.com
[v2] lkml.kernel.org/r/20190322032901.12045-1-andrew.smir...@gmail.com
[v1] lkml.kernel.org/r/20190226193609.9862-1-andrew.smir...@gmail.com

Andrey Smirnov (15):
  drm/bridge: tc358767: Simplify tc_poll_timeout()
  drm/bridge: tc358767: Simplify polling in tc_main_link_setup()
  drm/bridge: tc358767: Simplify polling in tc_link_training()
  drm/bridge: tc358767: Simplify tc_set_video_mode()
  drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors
  drm/bridge: tc358767: Simplify AUX data read
  drm/bridge: tc358767: Simplify AUX data write
  drm/bridge: tc358767: Increase AUX transfer length limit
  drm/bridge: tc358767: Use reported AUX transfer size
  drm/bridge: tc358767: Introduce tc_set_syspllparam()
  drm/bridge: tc358767: Introduce tc_pllupdate()
  drm/bridge: tc358767: Simplify tc_aux_wait_busy()
  drm/bridge: tc358767: Drop unnecessary 8 byte buffer
  drm/bridge: tc358767: Replace magic number in tc_main_link_enable()
  drm/bridge: tc358767: Add support for address-only I2C transfers

 drivers/gpu/drm/bridge/tc358767.c | 651 +-
 1 file changed, 376 insertions(+), 275 deletions(-)

-- 
2.21.0



[PATCH v6 01/15] drm/bridge: tc358767: Simplify tc_poll_timeout()

2019-06-18 Thread Andrey Smirnov
Implementation of tc_poll_timeout() is almost a 100% copy-and-paste of
the code for regmap_read_poll_timeout(). Replace copied code with a
call to the original. While at it change tc_poll_timeout to accept
"struct tc_data *" instead of "struct regmap *" for brevity. No
functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Reviewed-by: Laurent Pinchart 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 26 ++
 1 file changed, 6 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 58e3ca0e25af..fb8a1942ec54 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -264,34 +264,21 @@ static inline struct tc_data *connector_to_tc(struct 
drm_connector *c)
goto err;   \
} while (0)
 
-static inline int tc_poll_timeout(struct regmap *map, unsigned int addr,
+static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
  unsigned int cond_mask,
  unsigned int cond_value,
  unsigned long sleep_us, u64 timeout_us)
 {
-   ktime_t timeout = ktime_add_us(ktime_get(), timeout_us);
unsigned int val;
-   int ret;
 
-   for (;;) {
-   ret = regmap_read(map, addr, );
-   if (ret)
-   break;
-   if ((val & cond_mask) == cond_value)
-   break;
-   if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) {
-   ret = regmap_read(map, addr, );
-   break;
-   }
-   if (sleep_us)
-   usleep_range((sleep_us >> 2) + 1, sleep_us);
-   }
-   return ret ?: (((val & cond_mask) == cond_value) ? 0 : -ETIMEDOUT);
+   return regmap_read_poll_timeout(tc->regmap, addr, val,
+   (val & cond_mask) == cond_value,
+   sleep_us, timeout_us);
 }
 
 static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
 {
-   return tc_poll_timeout(tc->regmap, DP0_AUXSTATUS, AUX_BUSY, 0,
+   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
   1000, 1000 * timeout_ms);
 }
 
@@ -598,8 +585,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
tc_wait_pll_lock(tc);
 
-   ret = tc_poll_timeout(tc->regmap, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1,
- 1000);
+   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
dev_err(tc->dev, "Timeout waiting for PHY to become ready");
return ret;
-- 
2.21.0



Re: [PATCH v5 10/15] drm/bridge: tc358767: Add support for address-only I2C transfers

2019-06-18 Thread Andrey Smirnov
On Wed, Jun 12, 2019 at 9:22 AM Andrey Smirnov  wrote:
>
> On Wed, Jun 12, 2019 at 5:48 AM Tomi Valkeinen  wrote:
> >
> > Hi,
> >
> > On 12/06/2019 11:32, Andrey Smirnov wrote:
> > > Transfer size of zero means a request to do an address-only
> > > transfer. Since the HW support this, we probably shouldn't be just
> > > ignoring such requests. While at it allow DP_AUX_I2C_MOT flag to pass
> > > through, since it is supported by the HW as well.
> >
> > I bisected the EDID read issue to this patch...
> >
>
> I don't think I've had any problems on my end with this. I'll double
> check. It might be the case that yours is the only setup where the
> problem can be repro'd, though. We can drop this patch if you don't
> have time/would rather not dig into this.
>

Turns out I do have this problem. Just didn't pay enough attention to
notice. Will fix in v6.

Thanks,
Andrey Smirnov


[PATCH v5 01/15] drm/bridge: tc358767: Simplify tc_poll_timeout()

2019-06-13 Thread Andrey Smirnov
Implementation of tc_poll_timeout() is almost a 100% copy-and-paste of
the code for regmap_read_poll_timeout(). Replace copied code with a
call to the original. While at it change tc_poll_timeout to accept
"struct tc_data *" instead of "struct regmap *" for brevity. No
functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Reviewed-by: Laurent Pinchart 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 26 ++
 1 file changed, 6 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 58e3ca0e25af..fb8a1942ec54 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -264,34 +264,21 @@ static inline struct tc_data *connector_to_tc(struct 
drm_connector *c)
goto err;   \
} while (0)
 
-static inline int tc_poll_timeout(struct regmap *map, unsigned int addr,
+static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
  unsigned int cond_mask,
  unsigned int cond_value,
  unsigned long sleep_us, u64 timeout_us)
 {
-   ktime_t timeout = ktime_add_us(ktime_get(), timeout_us);
unsigned int val;
-   int ret;
 
-   for (;;) {
-   ret = regmap_read(map, addr, );
-   if (ret)
-   break;
-   if ((val & cond_mask) == cond_value)
-   break;
-   if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) {
-   ret = regmap_read(map, addr, );
-   break;
-   }
-   if (sleep_us)
-   usleep_range((sleep_us >> 2) + 1, sleep_us);
-   }
-   return ret ?: (((val & cond_mask) == cond_value) ? 0 : -ETIMEDOUT);
+   return regmap_read_poll_timeout(tc->regmap, addr, val,
+   (val & cond_mask) == cond_value,
+   sleep_us, timeout_us);
 }
 
 static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
 {
-   return tc_poll_timeout(tc->regmap, DP0_AUXSTATUS, AUX_BUSY, 0,
+   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
   1000, 1000 * timeout_ms);
 }
 
@@ -598,8 +585,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
tc_wait_pll_lock(tc);
 
-   ret = tc_poll_timeout(tc->regmap, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1,
- 1000);
+   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
dev_err(tc->dev, "Timeout waiting for PHY to become ready");
return ret;
-- 
2.21.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCH v5 10/15] drm/bridge: tc358767: Add support for address-only I2C transfers

2019-06-12 Thread Andrey Smirnov
On Wed, Jun 12, 2019 at 5:48 AM Tomi Valkeinen  wrote:
>
> Hi,
>
> On 12/06/2019 11:32, Andrey Smirnov wrote:
> > Transfer size of zero means a request to do an address-only
> > transfer. Since the HW support this, we probably shouldn't be just
> > ignoring such requests. While at it allow DP_AUX_I2C_MOT flag to pass
> > through, since it is supported by the HW as well.
>
> I bisected the EDID read issue to this patch...
>

I don't think I've had any problems on my end with this. I'll double
check. It might be the case that yours is the only setup where the
problem can be repro'd, though. We can drop this patch if you don't
have time/would rather not dig into this.

Thanks,
Andrey Smirnov


[PATCH v5 15/15] drm/bridge: tc358767: Replace magic number in tc_main_link_enable()

2019-06-12 Thread Andrey Smirnov
We don't need 8 byte array, DP_LINK_STATUS_SIZE (6) should be
enough. This also gets rid of a magic number as a bonus.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 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 81ed359487c7..b403c7bad156 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -874,7 +874,7 @@ static int tc_main_link_enable(struct tc_data *tc)
u32 dp_phy_ctrl;
u32 value;
int ret;
-   u8 tmp[8];
+   u8 tmp[DP_LINK_STATUS_SIZE];
 
dev_dbg(tc->dev, "link enable\n");
 
-- 
2.21.0



[PATCH v5 11/15] drm/bridge: tc358767: Introduce tc_set_syspllparam()

2019-06-12 Thread Andrey Smirnov
Move common code converting clock rate to an appropriate constant and
configuring SYS_PLLPARAM register into a separate routine and convert
the rest of the code to use it. No functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Laurent Pinchart 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Cory Tusar 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 46 +++
 1 file changed, 16 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 4bb9b15e1324..ac55b59249e3 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -581,35 +581,40 @@ static int tc_stream_clock_calc(struct tc_data *tc)
return regmap_write(tc->regmap, DP0_VIDMNGEN1, 32768);
 }
 
-static int tc_aux_link_setup(struct tc_data *tc)
+static int tc_set_syspllparam(struct tc_data *tc)
 {
unsigned long rate;
-   u32 dp0_auxcfg1;
-   u32 value;
-   int ret;
+   u32 pllparam = SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
 
rate = clk_get_rate(tc->refclk);
switch (rate) {
case 3840:
-   value = REF_FREQ_38M4;
+   pllparam |= REF_FREQ_38M4;
break;
case 2600:
-   value = REF_FREQ_26M;
+   pllparam |= REF_FREQ_26M;
break;
case 1920:
-   value = REF_FREQ_19M2;
+   pllparam |= REF_FREQ_19M2;
break;
case 1300:
-   value = REF_FREQ_13M;
+   pllparam |= REF_FREQ_13M;
break;
default:
dev_err(tc->dev, "Invalid refclk rate: %lu Hz\n", rate);
return -EINVAL;
}
 
+   return regmap_write(tc->regmap, SYS_PLLPARAM, pllparam);
+}
+
+static int tc_aux_link_setup(struct tc_data *tc)
+{
+   int ret;
+   u32 dp0_auxcfg1;
+
/* Setup DP-PHY / PLL */
-   value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
-   ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+   ret = tc_set_syspllparam(tc);
if (ret)
goto err;
 
@@ -868,7 +873,6 @@ static int tc_main_link_enable(struct tc_data *tc)
 {
struct drm_dp_aux *aux = >aux;
struct device *dev = tc->dev;
-   unsigned int rate;
u32 dp_phy_ctrl;
u32 value;
int ret;
@@ -896,25 +900,7 @@ static int tc_main_link_enable(struct tc_data *tc)
if (ret)
return ret;
 
-   rate = clk_get_rate(tc->refclk);
-   switch (rate) {
-   case 3840:
-   value = REF_FREQ_38M4;
-   break;
-   case 2600:
-   value = REF_FREQ_26M;
-   break;
-   case 1920:
-   value = REF_FREQ_19M2;
-   break;
-   case 1300:
-   value = REF_FREQ_13M;
-   break;
-   default:
-   return -EINVAL;
-   }
-   value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
-   ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+   ret = tc_set_syspllparam(tc);
if (ret)
return ret;
 
-- 
2.21.0



[PATCH v5 14/15] drm/bridge: tc358767: Drop unnecessary 8 byte buffer

2019-06-12 Thread Andrey Smirnov
tc_get_display_props() never reads more than a byte via AUX, so
there's no need to reserve 8 for that purpose. No function change
intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 01ca92a6d9c8..81ed359487c7 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -661,8 +661,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
 static int tc_get_display_props(struct tc_data *tc)
 {
int ret;
-   /* temp buffer */
-   u8 tmp[8];
+   u8 reg;
 
/* Read DP Rx Link Capability */
ret = drm_dp_link_probe(>aux, >link.base);
@@ -678,21 +677,21 @@ static int tc_get_display_props(struct tc_data *tc)
tc->link.base.num_lanes = 2;
}
 
-   ret = drm_dp_dpcd_readb(>aux, DP_MAX_DOWNSPREAD, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_MAX_DOWNSPREAD, );
if (ret < 0)
goto err_dpcd_read;
-   tc->link.spread = tmp[0] & DP_MAX_DOWNSPREAD_0_5;
+   tc->link.spread = reg & DP_MAX_DOWNSPREAD_0_5;
 
-   ret = drm_dp_dpcd_readb(>aux, DP_MAIN_LINK_CHANNEL_CODING, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_MAIN_LINK_CHANNEL_CODING, );
if (ret < 0)
goto err_dpcd_read;
 
tc->link.scrambler_dis = false;
/* read assr */
-   ret = drm_dp_dpcd_readb(>aux, DP_EDP_CONFIGURATION_SET, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_EDP_CONFIGURATION_SET, );
if (ret < 0)
goto err_dpcd_read;
-   tc->link.assr = tmp[0] & DP_ALTERNATE_SCRAMBLER_RESET_ENABLE;
+   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,
-- 
2.21.0



[PATCH v5 13/15] drm/bridge: tc358767: Simplify tc_aux_wait_busy()

2019-06-12 Thread Andrey Smirnov
We never pass anything but 100 as timeout_ms to tc_aux_wait_busy(), so
we may as well hardcode that value and simplify function's signature.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 28df53f7c349..01ca92a6d9c8 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -294,10 +294,9 @@ static inline int tc_poll_timeout(struct tc_data *tc, 
unsigned int addr,
sleep_us, timeout_us);
 }
 
-static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
+static int tc_aux_wait_busy(struct tc_data *tc)
 {
-   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
-  1000, 1000 * timeout_ms);
+   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 1000, 10);
 }
 
 static int tc_aux_write_data(struct tc_data *tc, const void *data,
@@ -350,7 +349,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;
 
-   ret = tc_aux_wait_busy(tc, 100);
+   ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
 
@@ -377,7 +376,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   ret = tc_aux_wait_busy(tc, 100);
+   ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
 
-- 
2.21.0



[PATCH v5 06/15] drm/bridge: tc358767: Simplify AUX data read

2019-06-12 Thread Andrey Smirnov
Simplify AUX data read by removing index arithmetic and shifting with
a helper function that does two things:

1. Fetch data from up to 4 32-bit registers from the chip
2. Copy read data into user provided array.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 31 ++-
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 7b15caec2ce5..7152b44db8a3 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -321,6 +321,20 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
 }
 
+static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
+{
+   u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
+   int ret, count = ALIGN(size, sizeof(u32));
+
+   ret = regmap_raw_read(tc->regmap, DP0_AUXRDATA(0), auxrdata, count);
+   if (ret)
+   return ret;
+
+   memcpy(data, auxrdata, size);
+
+   return size;
+}
+
 static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
@@ -379,19 +393,10 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
-   /* Read data */
-   while (i < size) {
-   if ((i % 4) == 0) {
-   ret = regmap_read(tc->regmap,
- DP0_AUXRDATA(i >> 2), );
-   if (ret)
-   return ret;
-   }
-   buf[i] = tmp & 0xff;
-   tmp = tmp >> 8;
-   i++;
-   }
+   switch (request) {
+   case DP_AUX_NATIVE_READ:
+   case DP_AUX_I2C_READ:
+   return tc_aux_read_data(tc, msg->buffer, size);
}
 
return size;
-- 
2.21.0



[PATCH v5 09/15] drm/bridge: tc358767: Use reported AUX transfer size

2019-06-12 Thread Andrey Smirnov
Don't assume that requested data transfer size is the same as amount
of data that was transferred. Change the code to get that information
from DP0_AUXSTATUS instead.

Since the check for AUX_BUSY in tc_aux_get_status() is pointless (it
will always called after tc_aux_wait_busy()) and there's only one user
of it, inline its code into tc_aux_transfer() instead of trying to
accommodate the change above.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 40 ++-
 1 file changed, 12 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 8b53dc8908d3..7d0fbb12195b 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -152,10 +152,10 @@
 #define DP0_AUXWDATA(i)(0x066c + (i) * 4)
 #define DP0_AUXRDATA(i)(0x067c + (i) * 4)
 #define DP0_AUXSTATUS  0x068c
-#define AUX_STATUS_MASK0xf0
-#define AUX_STATUS_SHIFT   4
-#define AUX_TIMEOUTBIT(1)
-#define AUX_BUSY   BIT(0)
+#define AUX_BYTES  GENMASK(15, 8)
+#define AUX_STATUS GENMASK(7, 4)
+#define AUX_TIMEOUTBIT(1)
+#define AUX_BUSY   BIT(0)
 #define DP0_AUXI2CADR  0x0698
 
 /* Link Training */
@@ -298,29 +298,6 @@ static int tc_aux_wait_busy(struct tc_data *tc, unsigned 
int timeout_ms)
   1000, 1000 * timeout_ms);
 }
 
-static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
-{
-   int ret;
-   u32 value;
-
-   ret = regmap_read(tc->regmap, DP0_AUXSTATUS, );
-   if (ret < 0)
-   return ret;
-
-   if (value & AUX_BUSY) {
-   dev_err(tc->dev, "aux busy!\n");
-   return -EBUSY;
-   }
-
-   if (value & AUX_TIMEOUT) {
-   dev_err(tc->dev, "aux access timeout!\n");
-   return -ETIMEDOUT;
-   }
-
-   *reply = (value & AUX_STATUS_MASK) >> AUX_STATUS_SHIFT;
-   return 0;
-}
-
 static int tc_aux_write_data(struct tc_data *tc, const void *data,
 size_t size)
 {
@@ -356,6 +333,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct tc_data *tc = aux_to_tc(aux);
size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
+   u32 auxstatus;
int ret;
 
if (size == 0)
@@ -393,10 +371,16 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   ret = tc_aux_get_status(tc, >reply);
+   ret = regmap_read(tc->regmap, DP0_AUXSTATUS, );
if (ret)
return ret;
 
+   if (auxstatus & AUX_TIMEOUT)
+   return -ETIMEDOUT;
+
+   size = FIELD_GET(AUX_BYTES, auxstatus);
+   msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
+
switch (request) {
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
-- 
2.21.0



[PATCH v5 05/15] drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors

2019-06-12 Thread Andrey Smirnov
A very unfortunate aspect of tc_write()/tc_read() macro helpers is
that they capture quite a bit of context around them and thus require
the caller to have magic variables 'ret' and 'tc' as well as label
'err'. That makes a number of code paths rather counter-intuitive and
somewhat clunky, for example tc_stream_clock_calc() ends up being like
this:

int ret;

tc_write(DP0_VIDMNGEN1, 32768);

return 0;
err:
return ret;

which is rather surprising when you read the code for the first
time. Since those helpers arguably aren't really saving that much code
and there's no way of fixing them without making them too verbose to
be worth it change the driver code to not use them at all.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 382 ++
 1 file changed, 230 insertions(+), 152 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 5b78021d6c5b..7b15caec2ce5 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -280,20 +280,6 @@ static inline struct tc_data *connector_to_tc(struct 
drm_connector *c)
return container_of(c, struct tc_data, connector);
 }
 
-/* Simple macros to avoid repeated error checks */
-#define tc_write(reg, var) \
-   do {\
-   ret = regmap_write(tc->regmap, reg, var);   \
-   if (ret)\
-   goto err;   \
-   } while (0)
-#define tc_read(reg, var)  \
-   do {\
-   ret = regmap_read(tc->regmap, reg, var);\
-   if (ret)\
-   goto err;   \
-   } while (0)
-
 static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
  unsigned int cond_mask,
  unsigned int cond_value,
@@ -351,7 +337,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
 
ret = tc_aux_wait_busy(tc, 100);
if (ret)
-   goto err;
+   return ret;
 
if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
/* Store data */
@@ -362,7 +348,11 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
tmp = (tmp << 8) | buf[i];
i++;
if (((i % 4) == 0) || (i == size)) {
-   tc_write(DP0_AUXWDATA((i - 1) >> 2), tmp);
+   ret = regmap_write(tc->regmap,
+  DP0_AUXWDATA((i - 1) >> 2),
+  tmp);
+   if (ret)
+   return ret;
tmp = 0;
}
}
@@ -372,23 +362,32 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
}
 
/* Store address */
-   tc_write(DP0_AUXADDR, msg->address);
+   ret = regmap_write(tc->regmap, DP0_AUXADDR, msg->address);
+   if (ret)
+   return ret;
/* Start transfer */
-   tc_write(DP0_AUXCFG0, ((size - 1) << 8) | request);
+   ret = regmap_write(tc->regmap, DP0_AUXCFG0,
+  ((size - 1) << 8) | request);
+   if (ret)
+   return ret;
 
ret = tc_aux_wait_busy(tc, 100);
if (ret)
-   goto err;
+   return ret;
 
ret = tc_aux_get_status(tc, >reply);
if (ret)
-   goto err;
+   return ret;
 
if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
/* Read data */
while (i < size) {
-   if ((i % 4) == 0)
-   tc_read(DP0_AUXRDATA(i >> 2), );
+   if ((i % 4) == 0) {
+   ret = regmap_read(tc->regmap,
+ DP0_AUXRDATA(i >> 2), );
+   if (ret)
+   return ret;
+   }
buf[i] = tmp & 0xff;
tmp = tmp >> 8;
i++;
@@ -396,8 +395,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,

[PATCH v5 07/15] drm/bridge: tc358767: Simplify AUX data write

2019-06-12 Thread Andrey Smirnov
Simplify AUX data write by dropping index arithmetic and shifting and
replacing it with a call to a helper function that does two things:

1. Copies user-provided data into a write buffer
2. Transfers contents of the write buffer to up to 4 32-bit
   registers on the chip

Note that separate data endianness fix:

tmp = (tmp << 8) | buf[i];

that was reserved for DP_AUX_I2C_WRITE looks really strange, since it
will place data differently depending on the passed user-data
size. E.g. for a write of 1 byte, data transferred to the chip would
look like:

[byte0] [dummy1] [dummy2] [dummy3]

whereas for a write of 4 bytes we'd get:

[byte3] [byte2] [byte1] [byte0]

Since there's no indication in the datasheet that I2C write buffer
should be treated differently than AUX write buffer and no comment in
the original code explaining why it was done this way, that special
I2C write buffer transformation was dropped in this patch.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 48 +--
 1 file changed, 26 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 7152b44db8a3..e60692b8cd69 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -321,6 +321,21 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
 }
 
+static int tc_aux_write_data(struct tc_data *tc, const void *data,
+size_t size)
+{
+   u32 auxwdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)] = { 0 };
+   int ret, count = ALIGN(size, sizeof(u32));
+
+   memcpy(auxwdata, data, size);
+
+   ret = regmap_raw_write(tc->regmap, DP0_AUXWDATA(0), auxwdata, count);
+   if (ret)
+   return ret;
+
+   return size;
+}
+
 static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
 {
u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
@@ -341,9 +356,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct tc_data *tc = aux_to_tc(aux);
size_t size = min_t(size_t, 8, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
-   u8 *buf = msg->buffer;
-   u32 tmp = 0;
-   int i = 0;
int ret;
 
if (size == 0)
@@ -353,25 +365,17 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
-   /* Store data */
-   while (i < size) {
-   if (request == DP_AUX_NATIVE_WRITE)
-   tmp = tmp | (buf[i] << (8 * (i & 0x3)));
-   else
-   tmp = (tmp << 8) | buf[i];
-   i++;
-   if (((i % 4) == 0) || (i == size)) {
-   ret = regmap_write(tc->regmap,
-  DP0_AUXWDATA((i - 1) >> 2),
-  tmp);
-   if (ret)
-   return ret;
-   tmp = 0;
-   }
-   }
-   } else if (request != DP_AUX_I2C_READ &&
-  request != DP_AUX_NATIVE_READ) {
+   switch (request) {
+   case DP_AUX_NATIVE_READ:
+   case DP_AUX_I2C_READ:
+   break;
+   case DP_AUX_NATIVE_WRITE:
+   case DP_AUX_I2C_WRITE:
+   ret = tc_aux_write_data(tc, msg->buffer, size);
+   if (ret < 0)
+   return ret;
+   break;
+   default:
return -EINVAL;
}
 
-- 
2.21.0



[PATCH v5 08/15] drm/bridge: tc358767: Increase AUX transfer length limit

2019-06-12 Thread Andrey Smirnov
According to the datasheet tc358767 can transfer up to 16 bytes via
its AUX channel, so the artificial limit of 8 appears to be too
low. However only up to 15-bytes seem to be actually supported and
trying to use 16-byte transfers results in transfers failing
sporadically (with bogus status in case of I2C transfers), so limit it
to 15.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 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 e60692b8cd69..8b53dc8908d3 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -354,7 +354,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
struct tc_data *tc = aux_to_tc(aux);
-   size_t size = min_t(size_t, 8, msg->size);
+   size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
int ret;
 
-- 
2.21.0



[PATCH v5 12/15] drm/bridge: tc358767: Introduce tc_pllupdate()

2019-06-12 Thread Andrey Smirnov
tc_wait_pll_lock() is always called as a follow-up for updating
PLLUPDATE and PLLEN bit of a given PLL control register. To simplify
things, merge the two operation into a single helper function
tc_pllupdate() and convert the rest of the code to use it. No
functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Laurent Pinchart 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 30 ++
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index ac55b59249e3..28df53f7c349 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -443,10 +443,18 @@ static u32 tc_srcctrl(struct tc_data *tc)
return reg;
 }
 
-static void tc_wait_pll_lock(struct tc_data *tc)
+static int tc_pllupdate(struct tc_data *tc, unsigned int pllctrl)
 {
+   int ret;
+
+   ret = regmap_write(tc->regmap, pllctrl, PLLUPDATE | PLLEN);
+   if (ret)
+   return ret;
+
/* Wait for PLL to lock: up to 2.09 ms, depending on refclk */
usleep_range(3000, 6000);
+
+   return 0;
 }
 
 static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
@@ -546,13 +554,7 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, 
u32 pixelclock)
return ret;
 
/* Force PLL parameter update and disable bypass */
-   ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLUPDATE | PLLEN);
-   if (ret)
-   return ret;
-
-   tc_wait_pll_lock(tc);
-
-   return 0;
+   return tc_pllupdate(tc, PXL_PLLCTRL);
 }
 
 static int tc_pxl_pll_dis(struct tc_data *tc)
@@ -626,15 +628,13 @@ static int tc_aux_link_setup(struct tc_data *tc)
 * Initially PLLs are in bypass. Force PLL parameter update,
 * disable PLL bypass, enable PLL
 */
-   ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate(tc, DP0_PLLCTRL);
if (ret)
goto err;
-   tc_wait_pll_lock(tc);
 
-   ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate(tc, DP1_PLLCTRL);
if (ret)
goto err;
-   tc_wait_pll_lock(tc);
 
ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
@@ -914,15 +914,13 @@ static int tc_main_link_enable(struct tc_data *tc)
return ret;
 
/* PLL setup */
-   ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate(tc, DP0_PLLCTRL);
if (ret)
return ret;
-   tc_wait_pll_lock(tc);
 
-   ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate(tc, DP1_PLLCTRL);
if (ret)
return ret;
-   tc_wait_pll_lock(tc);
 
/* Reset/Enable Main Links */
dp_phy_ctrl |= DP_PHY_RST | PHY_M1_RST | PHY_M0_RST;
-- 
2.21.0



[PATCH v5 10/15] drm/bridge: tc358767: Add support for address-only I2C transfers

2019-06-12 Thread Andrey Smirnov
Transfer size of zero means a request to do an address-only
transfer. Since the HW support this, we probably shouldn't be just
ignoring such requests. While at it allow DP_AUX_I2C_MOT flag to pass
through, since it is supported by the HW as well.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 30 +++---
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 7d0fbb12195b..4bb9b15e1324 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -145,6 +145,8 @@
 
 /* AUX channel */
 #define DP0_AUXCFG00x0660
+#define DP0_AUXCFG0_BSIZE  GENMASK(11, 8)
+#define DP0_AUXCFG0_ADDR_ONLY  BIT(4)
 #define DP0_AUXCFG10x0664
 #define AUX_RX_FILTER_EN   BIT(16)
 
@@ -327,6 +329,18 @@ static int tc_aux_read_data(struct tc_data *tc, void 
*data, size_t size)
return size;
 }
 
+static u32 tc_auxcfg0(struct drm_dp_aux_msg *msg, size_t size)
+{
+   u32 auxcfg0 = msg->request;
+
+   if (size)
+   auxcfg0 |= FIELD_PREP(DP0_AUXCFG0_BSIZE, size - 1);
+   else
+   auxcfg0 |= DP0_AUXCFG0_ADDR_ONLY;
+
+   return auxcfg0;
+}
+
 static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
@@ -336,9 +350,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;
 
-   if (size == 0)
-   return 0;
-
ret = tc_aux_wait_busy(tc, 100);
if (ret)
return ret;
@@ -362,8 +373,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
/* Start transfer */
-   ret = regmap_write(tc->regmap, DP0_AUXCFG0,
-  ((size - 1) << 8) | request);
+   ret = regmap_write(tc->regmap, DP0_AUXCFG0, tc_auxcfg0(msg, size));
if (ret)
return ret;
 
@@ -377,8 +387,14 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
 
if (auxstatus & AUX_TIMEOUT)
return -ETIMEDOUT;
-
-   size = FIELD_GET(AUX_BYTES, auxstatus);
+   /*
+* For some reason address-only DP_AUX_I2C_WRITE (MOT), still
+* reports 1 byte transferred in its status. To deal we that
+* we ignore aux_bytes field if we know that this was an
+* address-only transfer
+*/
+   if (size)
+   size = FIELD_GET(AUX_BYTES, auxstatus);
msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
 
switch (request) {
-- 
2.21.0



[PATCH v5 03/15] drm/bridge: tc358767: Simplify polling in tc_link_training()

2019-06-12 Thread Andrey Smirnov
Replace explicit polling in tc_link_training() with equivalent call to
tc_poll_timeout() for simplicity. No functional change intended (not
including slightly altered debug output).

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 15 ++-
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index f463ef6d4271..31f5045e7e42 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -748,22 +748,19 @@ static int tc_set_video_mode(struct tc_data *tc,
 
 static int tc_wait_link_training(struct tc_data *tc)
 {
-   u32 timeout = 1000;
u32 value;
int ret;
 
-   do {
-   udelay(1);
-   tc_read(DP0_LTSTAT, );
-   } while ((!(value & LT_LOOPDONE)) && (--timeout));
-
-   if (timeout == 0) {
+   ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
+ LT_LOOPDONE, 1, 1000);
+   if (ret) {
dev_err(tc->dev, "Link training timeout waiting for 
LT_LOOPDONE!\n");
-   return -ETIMEDOUT;
+   return ret;
}
 
-   return (value >> 8) & 0x7;
+   tc_read(DP0_LTSTAT, );
 
+   return (value >> 8) & 0x7;
 err:
return ret;
 }
-- 
2.21.0



[PATCH v5 04/15] drm/bridge: tc358767: Simplify tc_set_video_mode()

2019-06-12 Thread Andrey Smirnov
Simplify tc_set_video_mode() by replacing explicit shifting using
macros from . No functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 106 ++
 1 file changed, 78 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 31f5045e7e42..5b78021d6c5b 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -24,6 +24,7 @@
  * GNU General Public License for more details.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -56,6 +57,7 @@
 
 /* Video Path */
 #define VPCTRL00x0450
+#define VSDELAYGENMASK(31, 20)
 #define OPXLFMT_RGB666 (0 << 8)
 #define OPXLFMT_RGB888 (1 << 8)
 #define FRMSYNC_DISABLED   (0 << 4) /* Video Timing Gen Disabled */
@@ -63,9 +65,17 @@
 #define MSF_DISABLED   (0 << 0) /* Magic Square FRC disabled */
 #define MSF_ENABLED(1 << 0) /* Magic Square FRC enabled */
 #define HTIM01 0x0454
+#define HPWGENMASK(8, 0)
+#define HBPR   GENMASK(24, 16)
 #define HTIM02 0x0458
+#define HDISPR GENMASK(10, 0)
+#define HFPR   GENMASK(24, 16)
 #define VTIM01 0x045c
+#define VSPR   GENMASK(7, 0)
+#define VBPR   GENMASK(23, 16)
 #define VTIM02 0x0460
+#define VFPR   GENMASK(23, 16)
+#define VDISPR GENMASK(10, 0)
 #define VFUEN0 0x0464
 #define VFUEN  BIT(0)   /* Video Frame Timing Upload */
 
@@ -108,14 +118,28 @@
 /* Main Channel */
 #define DP0_SECSAMPLE  0x0640
 #define DP0_VIDSYNCDELAY   0x0644
+#define VID_SYNC_DLY   GENMASK(15, 0)
+#define THRESH_DLY GENMASK(31, 16)
+
 #define DP0_TOTALVAL   0x0648
+#define H_TOTALGENMASK(15, 0)
+#define V_TOTALGENMASK(31, 16)
 #define DP0_STARTVAL   0x064c
+#define H_STARTGENMASK(15, 0)
+#define V_STARTGENMASK(31, 16)
 #define DP0_ACTIVEVAL  0x0650
+#define H_ACT  GENMASK(15, 0)
+#define V_ACT  GENMASK(31, 16)
+
 #define DP0_SYNCVAL0x0654
+#define VS_WIDTH   GENMASK(30, 16)
+#define HS_WIDTH   GENMASK(14, 0)
 #define SYNCVAL_HS_POL_ACTIVE_LOW  (1 << 15)
 #define SYNCVAL_VS_POL_ACTIVE_LOW  (1 << 31)
 #define DP0_MISC   0x0658
 #define TU_SIZE_RECOMMENDED(63) /* LSCLK cycles per TU */
+#define MAX_TU_SYMBOL  GENMASK(28, 23)
+#define TU_SIZEGENMASK(21, 16)
 #define BPC_6  (0 << 5)
 #define BPC_8  (1 << 5)
 
@@ -192,6 +216,12 @@
 
 /* Test & Debug */
 #define TSTCTL 0x0a00
+#define COLOR_RGENMASK(31, 24)
+#define COLOR_GGENMASK(23, 16)
+#define COLOR_BGENMASK(15, 8)
+#define ENI2CFILTERBIT(4)
+#define COLOR_BAR_MODE GENMASK(1, 0)
+#define COLOR_BAR_MODE_BARS2
 #define PLL_DBG0x0a04
 
 static bool tc_test_pattern;
@@ -672,6 +702,7 @@ static int tc_set_video_mode(struct tc_data *tc,
int upper_margin = mode->vtotal - mode->vsync_end;
int lower_margin = mode->vsync_start - mode->vdisplay;
int vsync_len = mode->vsync_end - mode->vsync_start;
+   u32 dp0_syncval;
 
/*
 * Recommended maximum number of symbols transferred in a transfer unit:
@@ -696,50 +727,69 @@ static int tc_set_video_mode(struct tc_data *tc,
 * assume we do not need any delay when DPI is a source of
 * sync signals
 */
-   tc_write(VPCTRL0, (0 << 20) /* VSDELAY */ |
+   tc_write(VPCTRL0,
+FIELD_PREP(VSDELAY, 0) |
 OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
-   tc_write(HTIM01, (ALIGN(left_margin, 2) << 16) | /* H back porch */
-(ALIGN(hsync_len, 2) << 0));/* Hsync */
-   tc_write(HTIM02, (ALIGN(right_margin, 2) << 16) |  /* H front porch */
-(ALIGN(mode->hdisplay, 2) << 0)); /* width */
-   tc_write(VTIM01, (upper_margin << 16) | /* V back porch */
-(vsync_len << 0)); /* Vsync */
-   tc_write(VTIM02, (lower_margin <<

[PATCH v5 02/15] drm/bridge: tc358767: Simplify polling in tc_main_link_setup()

2019-06-12 Thread Andrey Smirnov
Replace explicit polling loop with equivalent call to
tc_poll_timeout() for brevity. No functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 12 +++-
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index fb8a1942ec54..f463ef6d4271 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -774,7 +774,6 @@ static int tc_main_link_enable(struct tc_data *tc)
struct device *dev = tc->dev;
unsigned int rate;
u32 dp_phy_ctrl;
-   int timeout;
u32 value;
int ret;
u8 tmp[8];
@@ -831,15 +830,10 @@ static int tc_main_link_enable(struct tc_data *tc)
dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
tc_write(DP_PHY_CTRL, dp_phy_ctrl);
 
-   timeout = 1000;
-   do {
-   tc_read(DP_PHY_CTRL, );
-   udelay(1);
-   } while ((!(value & PHY_RDY)) && (--timeout));
-
-   if (timeout == 0) {
+   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
+   if (ret) {
dev_err(dev, "timeout waiting for phy become ready");
-   return -ETIMEDOUT;
+   return ret;
}
 
/* Set misc: 8 bits per color */
-- 
2.21.0



[PATCH v5 00/15] tc358767 driver improvements

2019-06-12 Thread Andrey Smirnov
Everyone:

This series contains various improvements (at least in my mind) and
fixes that I made to tc358767 while working with the code of the
driver. Hopefuly each patch is self explanatory.

Feedback is welcome!

Thanks,
Andrey Smirnov

Changes since [v4]:

- tc_pllupdate_pllen() renamed to tc_pllupdate()

- Collected Reviewed-bys from Andrzej for the rest of the series

Changes since [v3]:

- Collected Reviewed-bys from Andrzej

- Dropped explicit check for -ETIMEDOUT in "drm/bridge: tc358767:
  Simplify polling in tc_main_link_setup()" for consistency

- AUX transfer code converted to user regmap_raw_read(),
  regmap_raw_write()

Changes since [v2]:

- Patchset rebased on top of v4 of Tomi's series that recently
  went in (https://patchwork.freedesktop.org/series/58176/#rev5)
  
- AUX transfer code converted to user regmap_bulk_read(),
  regmap_bulk_write()

Changes since [v1]:

- Patchset rebased on top of
  https://patchwork.freedesktop.org/series/58176/
  
- Patches to remove both tc_write() and tc_read() helpers added

- Patches to rework AUX transfer code added

- Both "drm/bridge: tc358767: Simplify polling in
  tc_main_link_setup()" and "drm/bridge: tc358767: Simplify
  polling in tc_link_training()" changed to use tc_poll_timeout()
  instead of regmap_read_poll_timeout()

[v4] lkml.kernel.org/r/20190607044550.13361-1-andrew.smir...@gmail.com
[v3] lkml.kernel.org/r/20190605070507.11417-1-andrew.smir...@gmail.com
[v2] lkml.kernel.org/r/20190322032901.12045-1-andrew.smir...@gmail.com
[v1] lkml.kernel.org/r/20190226193609.9862-1-andrew.smir...@gmail.com

Andrey Smirnov (15):
  drm/bridge: tc358767: Simplify tc_poll_timeout()
  drm/bridge: tc358767: Simplify polling in tc_main_link_setup()
  drm/bridge: tc358767: Simplify polling in tc_link_training()
  drm/bridge: tc358767: Simplify tc_set_video_mode()
  drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors
  drm/bridge: tc358767: Simplify AUX data read
  drm/bridge: tc358767: Simplify AUX data write
  drm/bridge: tc358767: Increase AUX transfer length limit
  drm/bridge: tc358767: Use reported AUX transfer size
  drm/bridge: tc358767: Add support for address-only I2C transfers
  drm/bridge: tc358767: Introduce tc_set_syspllparam()
  drm/bridge: tc358767: Introduce tc_pllupdate()
  drm/bridge: tc358767: Simplify tc_aux_wait_busy()
  drm/bridge: tc358767: Drop unnecessary 8 byte buffer
  drm/bridge: tc358767: Replace magic number in tc_main_link_enable()

 drivers/gpu/drm/bridge/tc358767.c | 648 +-
 1 file changed, 372 insertions(+), 276 deletions(-)

-- 
2.21.0



Re: [PATCH v3 06/15] drm/bridge: tc358767: Simplify AUX data read

2019-06-07 Thread Andrey Smirnov
On Thu, Jun 6, 2019 at 3:59 AM Andrzej Hajda  wrote:
>
> On 05.06.2019 09:04, Andrey Smirnov wrote:
> > Simplify AUX data read by removing index arithmetic and shifting with
> > a helper functions that does three things:
> >
> > 1. Fetch data from up to 4 32-bit registers from the chip
> > 2. Optionally fix data endianness (not needed on LE hosts)
> > 3. Copy read data into user provided array.
> >
> > Signed-off-by: Andrey Smirnov 
> > Cc: Archit Taneja 
> > Cc: Andrzej Hajda 
> > Cc: Laurent Pinchart 
> > Cc: Tomi Valkeinen 
> > Cc: Andrey Gusakov 
> > Cc: Philipp Zabel 
> > Cc: Cory Tusar 
> > Cc: Chris Healy 
> > Cc: Lucas Stach 
> > Cc: dri-devel@lists.freedesktop.org
> > Cc: linux-ker...@vger.kernel.org
> > ---
> >  drivers/gpu/drm/bridge/tc358767.c | 40 +--
> >  1 file changed, 27 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/tc358767.c 
> > b/drivers/gpu/drm/bridge/tc358767.c
> > index e197ce0fb166..da47d81e7109 100644
> > --- a/drivers/gpu/drm/bridge/tc358767.c
> > +++ b/drivers/gpu/drm/bridge/tc358767.c
> > @@ -321,6 +321,29 @@ static int tc_aux_get_status(struct tc_data *tc, u8 
> > *reply)
> >   return 0;
> >  }
> >
> > +static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
> > +{
> > + u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
> > + int ret, i, count = DIV_ROUND_UP(size, sizeof(u32));
> > +
> > + ret = regmap_bulk_read(tc->regmap, DP0_AUXRDATA(0), auxrdata, count);
> > + if (ret)
> > + return ret;
> > +
> > + for (i = 0; i < count; i++) {
> > + /*
> > +  * Our regmap is configured as LE for register data,
> > +  * so we need undo any byte swapping that might have
> > +      * happened to preserve original byte order.
> > +  */
> > + le32_to_cpus([i]);
> > + }
> > +
> > + memcpy(data, auxrdata, size);
> > +
> > + return size;
> > +}
> > +
>
>
> Hmm, cannot we just use regmap_raw_read?

I'll give it a try in v4.

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v4 15/15] drm/bridge: tc358767: Replace magic number in tc_main_link_enable()

2019-06-07 Thread Andrey Smirnov
We don't need 8 byte array, DP_LINK_STATUS_SIZE (6) should be
enough. This also gets rid of a magic number as a bonus.

Signed-off-by: Andrey Smirnov 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 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 4a245144aa83..05c5fab011f8 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -874,7 +874,7 @@ static int tc_main_link_enable(struct tc_data *tc)
u32 dp_phy_ctrl;
u32 value;
int ret;
-   u8 tmp[8];
+   u8 tmp[DP_LINK_STATUS_SIZE];
 
dev_dbg(tc->dev, "link enable\n");
 
-- 
2.21.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v4 06/15] drm/bridge: tc358767: Simplify AUX data read

2019-06-07 Thread Andrey Smirnov
Simplify AUX data read by removing index arithmetic and shifting with
a helper function that does two things:

1. Fetch data from up to 4 32-bit registers from the chip
2. Copy read data into user provided array.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 31 ++-
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 7b15caec2ce5..7152b44db8a3 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -321,6 +321,20 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
 }
 
+static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
+{
+   u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
+   int ret, count = ALIGN(size, sizeof(u32));
+
+   ret = regmap_raw_read(tc->regmap, DP0_AUXRDATA(0), auxrdata, count);
+   if (ret)
+   return ret;
+
+   memcpy(data, auxrdata, size);
+
+   return size;
+}
+
 static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
@@ -379,19 +393,10 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
-   /* Read data */
-   while (i < size) {
-   if ((i % 4) == 0) {
-   ret = regmap_read(tc->regmap,
- DP0_AUXRDATA(i >> 2), );
-   if (ret)
-   return ret;
-   }
-   buf[i] = tmp & 0xff;
-   tmp = tmp >> 8;
-   i++;
-   }
+   switch (request) {
+   case DP_AUX_NATIVE_READ:
+   case DP_AUX_I2C_READ:
+   return tc_aux_read_data(tc, msg->buffer, size);
}
 
return size;
-- 
2.21.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v4 07/15] drm/bridge: tc358767: Simplify AUX data write

2019-06-06 Thread Andrey Smirnov
Simplify AUX data write by dropping index arithmetic and shifting and
replacing it with a call to a helper function that does two things:

1. Copies user-provided data into a write buffer
2. Transfers contents of the write buffer to up to 4 32-bit
   registers on the chip

Note that separate data endianness fix:

tmp = (tmp << 8) | buf[i];

that was reserved for DP_AUX_I2C_WRITE looks really strange, since it
will place data differently depending on the passed user-data
size. E.g. for a write of 1 byte, data transferred to the chip would
look like:

[byte0] [dummy1] [dummy2] [dummy3]

whereas for a write of 4 bytes we'd get:

[byte3] [byte2] [byte1] [byte0]

Since there's no indication in the datasheet that I2C write buffer
should be treated differently than AUX write buffer and no comment in
the original code explaining why it was done this way, that special
I2C write buffer transformation was dropped in this patch.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 48 +--
 1 file changed, 26 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 7152b44db8a3..e60692b8cd69 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -321,6 +321,21 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
 }
 
+static int tc_aux_write_data(struct tc_data *tc, const void *data,
+size_t size)
+{
+   u32 auxwdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)] = { 0 };
+   int ret, count = ALIGN(size, sizeof(u32));
+
+   memcpy(auxwdata, data, size);
+
+   ret = regmap_raw_write(tc->regmap, DP0_AUXWDATA(0), auxwdata, count);
+   if (ret)
+   return ret;
+
+   return size;
+}
+
 static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
 {
u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
@@ -341,9 +356,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct tc_data *tc = aux_to_tc(aux);
size_t size = min_t(size_t, 8, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
-   u8 *buf = msg->buffer;
-   u32 tmp = 0;
-   int i = 0;
int ret;
 
if (size == 0)
@@ -353,25 +365,17 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
-   /* Store data */
-   while (i < size) {
-   if (request == DP_AUX_NATIVE_WRITE)
-   tmp = tmp | (buf[i] << (8 * (i & 0x3)));
-   else
-   tmp = (tmp << 8) | buf[i];
-   i++;
-   if (((i % 4) == 0) || (i == size)) {
-   ret = regmap_write(tc->regmap,
-  DP0_AUXWDATA((i - 1) >> 2),
-  tmp);
-   if (ret)
-   return ret;
-   tmp = 0;
-   }
-   }
-   } else if (request != DP_AUX_I2C_READ &&
-  request != DP_AUX_NATIVE_READ) {
+   switch (request) {
+   case DP_AUX_NATIVE_READ:
+   case DP_AUX_I2C_READ:
+   break;
+   case DP_AUX_NATIVE_WRITE:
+   case DP_AUX_I2C_WRITE:
+   ret = tc_aux_write_data(tc, msg->buffer, size);
+   if (ret < 0)
+   return ret;
+   break;
+   default:
return -EINVAL;
}
 
-- 
2.21.0



[PATCH v4 05/15] drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors

2019-06-06 Thread Andrey Smirnov
A very unfortunate aspect of tc_write()/tc_read() macro helpers is
that they capture quite a bit of context around them and thus require
the caller to have magic variables 'ret' and 'tc' as well as label
'err'. That makes a number of code paths rather counter-intuitive and
somewhat clunky, for example tc_stream_clock_calc() ends up being like
this:

int ret;

tc_write(DP0_VIDMNGEN1, 32768);

return 0;
err:
return ret;

which is rather surprising when you read the code for the first
time. Since those helpers arguably aren't really saving that much code
and there's no way of fixing them without making them too verbose to
be worth it change the driver code to not use them at all.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 382 ++
 1 file changed, 230 insertions(+), 152 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 5b78021d6c5b..7b15caec2ce5 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -280,20 +280,6 @@ static inline struct tc_data *connector_to_tc(struct 
drm_connector *c)
return container_of(c, struct tc_data, connector);
 }
 
-/* Simple macros to avoid repeated error checks */
-#define tc_write(reg, var) \
-   do {\
-   ret = regmap_write(tc->regmap, reg, var);   \
-   if (ret)\
-   goto err;   \
-   } while (0)
-#define tc_read(reg, var)  \
-   do {\
-   ret = regmap_read(tc->regmap, reg, var);\
-   if (ret)\
-   goto err;   \
-   } while (0)
-
 static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
  unsigned int cond_mask,
  unsigned int cond_value,
@@ -351,7 +337,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
 
ret = tc_aux_wait_busy(tc, 100);
if (ret)
-   goto err;
+   return ret;
 
if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
/* Store data */
@@ -362,7 +348,11 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
tmp = (tmp << 8) | buf[i];
i++;
if (((i % 4) == 0) || (i == size)) {
-   tc_write(DP0_AUXWDATA((i - 1) >> 2), tmp);
+   ret = regmap_write(tc->regmap,
+  DP0_AUXWDATA((i - 1) >> 2),
+  tmp);
+   if (ret)
+   return ret;
tmp = 0;
}
}
@@ -372,23 +362,32 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
}
 
/* Store address */
-   tc_write(DP0_AUXADDR, msg->address);
+   ret = regmap_write(tc->regmap, DP0_AUXADDR, msg->address);
+   if (ret)
+   return ret;
/* Start transfer */
-   tc_write(DP0_AUXCFG0, ((size - 1) << 8) | request);
+   ret = regmap_write(tc->regmap, DP0_AUXCFG0,
+  ((size - 1) << 8) | request);
+   if (ret)
+   return ret;
 
ret = tc_aux_wait_busy(tc, 100);
if (ret)
-   goto err;
+   return ret;
 
ret = tc_aux_get_status(tc, >reply);
if (ret)
-   goto err;
+   return ret;
 
if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
/* Read data */
while (i < size) {
-   if ((i % 4) == 0)
-   tc_read(DP0_AUXRDATA(i >> 2), );
+   if ((i % 4) == 0) {
+   ret = regmap_read(tc->regmap,
+ DP0_AUXRDATA(i >> 2), );
+   if (ret)
+   return ret;
+   }
buf[i] = tmp & 0xff;
tmp = tmp >> 8;
i++;
@@ -396,8 +395,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,

[PATCH v4 11/15] drm/bridge: tc358767: Introduce tc_set_syspllparam()

2019-06-06 Thread Andrey Smirnov
Move common code converting clock rate to an appropriate constant and
configuring SYS_PLLPARAM register into a separate routine and convert
the rest of the code to use it. No functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Laurent Pinchart 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Cory Tusar 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 46 +++
 1 file changed, 16 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 4bb9b15e1324..ac55b59249e3 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -581,35 +581,40 @@ static int tc_stream_clock_calc(struct tc_data *tc)
return regmap_write(tc->regmap, DP0_VIDMNGEN1, 32768);
 }
 
-static int tc_aux_link_setup(struct tc_data *tc)
+static int tc_set_syspllparam(struct tc_data *tc)
 {
unsigned long rate;
-   u32 dp0_auxcfg1;
-   u32 value;
-   int ret;
+   u32 pllparam = SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
 
rate = clk_get_rate(tc->refclk);
switch (rate) {
case 3840:
-   value = REF_FREQ_38M4;
+   pllparam |= REF_FREQ_38M4;
break;
case 2600:
-   value = REF_FREQ_26M;
+   pllparam |= REF_FREQ_26M;
break;
case 1920:
-   value = REF_FREQ_19M2;
+   pllparam |= REF_FREQ_19M2;
break;
case 1300:
-   value = REF_FREQ_13M;
+   pllparam |= REF_FREQ_13M;
break;
default:
dev_err(tc->dev, "Invalid refclk rate: %lu Hz\n", rate);
return -EINVAL;
}
 
+   return regmap_write(tc->regmap, SYS_PLLPARAM, pllparam);
+}
+
+static int tc_aux_link_setup(struct tc_data *tc)
+{
+   int ret;
+   u32 dp0_auxcfg1;
+
/* Setup DP-PHY / PLL */
-   value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
-   ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+   ret = tc_set_syspllparam(tc);
if (ret)
goto err;
 
@@ -868,7 +873,6 @@ static int tc_main_link_enable(struct tc_data *tc)
 {
struct drm_dp_aux *aux = >aux;
struct device *dev = tc->dev;
-   unsigned int rate;
u32 dp_phy_ctrl;
u32 value;
int ret;
@@ -896,25 +900,7 @@ static int tc_main_link_enable(struct tc_data *tc)
if (ret)
return ret;
 
-   rate = clk_get_rate(tc->refclk);
-   switch (rate) {
-   case 3840:
-   value = REF_FREQ_38M4;
-   break;
-   case 2600:
-   value = REF_FREQ_26M;
-   break;
-   case 1920:
-   value = REF_FREQ_19M2;
-   break;
-   case 1300:
-   value = REF_FREQ_13M;
-   break;
-   default:
-   return -EINVAL;
-   }
-   value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
-   ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+   ret = tc_set_syspllparam(tc);
if (ret)
return ret;
 
-- 
2.21.0



[PATCH v4 08/15] drm/bridge: tc358767: Increase AUX transfer length limit

2019-06-06 Thread Andrey Smirnov
According to the datasheet tc358767 can transfer up to 16 bytes via
its AUX channel, so the artificial limit of 8 appears to be too
low. However only up to 15-bytes seem to be actually supported and
trying to use 16-byte transfers results in transfers failing
sporadically (with bogus status in case of I2C transfers), so limit it
to 15.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 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 e60692b8cd69..8b53dc8908d3 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -354,7 +354,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
struct tc_data *tc = aux_to_tc(aux);
-   size_t size = min_t(size_t, 8, msg->size);
+   size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
int ret;
 
-- 
2.21.0



[PATCH v4 12/15] drm/bridge: tc358767: Introduce tc_pllupdate_pllen()

2019-06-06 Thread Andrey Smirnov
tc_wait_pll_lock() is always called as a follow-up for updating
PLLUPDATE and PLLEN bit of a given PLL control register. To simplify
things, merge the two operation into a single helper function
tc_pllupdate_pllen() and convert the rest of the code to use it. No
functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Laurent Pinchart 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 30 ++
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index ac55b59249e3..c994c72eb330 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -443,10 +443,18 @@ static u32 tc_srcctrl(struct tc_data *tc)
return reg;
 }
 
-static void tc_wait_pll_lock(struct tc_data *tc)
+static int tc_pllupdate_pllen(struct tc_data *tc, unsigned int pllctrl)
 {
+   int ret;
+
+   ret = regmap_write(tc->regmap, pllctrl, PLLUPDATE | PLLEN);
+   if (ret)
+   return ret;
+
/* Wait for PLL to lock: up to 2.09 ms, depending on refclk */
usleep_range(3000, 6000);
+
+   return 0;
 }
 
 static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
@@ -546,13 +554,7 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, 
u32 pixelclock)
return ret;
 
/* Force PLL parameter update and disable bypass */
-   ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLUPDATE | PLLEN);
-   if (ret)
-   return ret;
-
-   tc_wait_pll_lock(tc);
-
-   return 0;
+   return tc_pllupdate_pllen(tc, PXL_PLLCTRL);
 }
 
 static int tc_pxl_pll_dis(struct tc_data *tc)
@@ -626,15 +628,13 @@ static int tc_aux_link_setup(struct tc_data *tc)
 * Initially PLLs are in bypass. Force PLL parameter update,
 * disable PLL bypass, enable PLL
 */
-   ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP0_PLLCTRL);
if (ret)
goto err;
-   tc_wait_pll_lock(tc);
 
-   ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP1_PLLCTRL);
if (ret)
goto err;
-   tc_wait_pll_lock(tc);
 
ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
@@ -914,15 +914,13 @@ static int tc_main_link_enable(struct tc_data *tc)
return ret;
 
/* PLL setup */
-   ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP0_PLLCTRL);
if (ret)
return ret;
-   tc_wait_pll_lock(tc);
 
-   ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP1_PLLCTRL);
if (ret)
return ret;
-   tc_wait_pll_lock(tc);
 
/* Reset/Enable Main Links */
dp_phy_ctrl |= DP_PHY_RST | PHY_M1_RST | PHY_M0_RST;
-- 
2.21.0



[PATCH v4 09/15] drm/bridge: tc358767: Use reported AUX transfer size

2019-06-06 Thread Andrey Smirnov
Don't assume that requested data transfer size is the same as amount
of data that was transferred. Change the code to get that information
from DP0_AUXSTATUS instead.

Since the check for AUX_BUSY in tc_aux_get_status() is pointless (it
will always called after tc_aux_wait_busy()) and there's only one user
of it, inline its code into tc_aux_transfer() instead of trying to
accommodate the change above.

Signed-off-by: Andrey Smirnov 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 40 ++-
 1 file changed, 12 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 8b53dc8908d3..7d0fbb12195b 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -152,10 +152,10 @@
 #define DP0_AUXWDATA(i)(0x066c + (i) * 4)
 #define DP0_AUXRDATA(i)(0x067c + (i) * 4)
 #define DP0_AUXSTATUS  0x068c
-#define AUX_STATUS_MASK0xf0
-#define AUX_STATUS_SHIFT   4
-#define AUX_TIMEOUTBIT(1)
-#define AUX_BUSY   BIT(0)
+#define AUX_BYTES  GENMASK(15, 8)
+#define AUX_STATUS GENMASK(7, 4)
+#define AUX_TIMEOUTBIT(1)
+#define AUX_BUSY   BIT(0)
 #define DP0_AUXI2CADR  0x0698
 
 /* Link Training */
@@ -298,29 +298,6 @@ static int tc_aux_wait_busy(struct tc_data *tc, unsigned 
int timeout_ms)
   1000, 1000 * timeout_ms);
 }
 
-static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
-{
-   int ret;
-   u32 value;
-
-   ret = regmap_read(tc->regmap, DP0_AUXSTATUS, );
-   if (ret < 0)
-   return ret;
-
-   if (value & AUX_BUSY) {
-   dev_err(tc->dev, "aux busy!\n");
-   return -EBUSY;
-   }
-
-   if (value & AUX_TIMEOUT) {
-   dev_err(tc->dev, "aux access timeout!\n");
-   return -ETIMEDOUT;
-   }
-
-   *reply = (value & AUX_STATUS_MASK) >> AUX_STATUS_SHIFT;
-   return 0;
-}
-
 static int tc_aux_write_data(struct tc_data *tc, const void *data,
 size_t size)
 {
@@ -356,6 +333,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct tc_data *tc = aux_to_tc(aux);
size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
+   u32 auxstatus;
int ret;
 
if (size == 0)
@@ -393,10 +371,16 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   ret = tc_aux_get_status(tc, >reply);
+   ret = regmap_read(tc->regmap, DP0_AUXSTATUS, );
if (ret)
return ret;
 
+   if (auxstatus & AUX_TIMEOUT)
+   return -ETIMEDOUT;
+
+   size = FIELD_GET(AUX_BYTES, auxstatus);
+   msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
+
switch (request) {
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
-- 
2.21.0



[PATCH v4 10/15] drm/bridge: tc358767: Add support for address-only I2C transfers

2019-06-06 Thread Andrey Smirnov
Transfer size of zero means a request to do an address-only
transfer. Since the HW support this, we probably shouldn't be just
ignoring such requests. While at it allow DP_AUX_I2C_MOT flag to pass
through, since it is supported by the HW as well.

Signed-off-by: Andrey Smirnov 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 30 +++---
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 7d0fbb12195b..4bb9b15e1324 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -145,6 +145,8 @@
 
 /* AUX channel */
 #define DP0_AUXCFG00x0660
+#define DP0_AUXCFG0_BSIZE  GENMASK(11, 8)
+#define DP0_AUXCFG0_ADDR_ONLY  BIT(4)
 #define DP0_AUXCFG10x0664
 #define AUX_RX_FILTER_EN   BIT(16)
 
@@ -327,6 +329,18 @@ static int tc_aux_read_data(struct tc_data *tc, void 
*data, size_t size)
return size;
 }
 
+static u32 tc_auxcfg0(struct drm_dp_aux_msg *msg, size_t size)
+{
+   u32 auxcfg0 = msg->request;
+
+   if (size)
+   auxcfg0 |= FIELD_PREP(DP0_AUXCFG0_BSIZE, size - 1);
+   else
+   auxcfg0 |= DP0_AUXCFG0_ADDR_ONLY;
+
+   return auxcfg0;
+}
+
 static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
@@ -336,9 +350,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;
 
-   if (size == 0)
-   return 0;
-
ret = tc_aux_wait_busy(tc, 100);
if (ret)
return ret;
@@ -362,8 +373,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
/* Start transfer */
-   ret = regmap_write(tc->regmap, DP0_AUXCFG0,
-  ((size - 1) << 8) | request);
+   ret = regmap_write(tc->regmap, DP0_AUXCFG0, tc_auxcfg0(msg, size));
if (ret)
return ret;
 
@@ -377,8 +387,14 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
 
if (auxstatus & AUX_TIMEOUT)
return -ETIMEDOUT;
-
-   size = FIELD_GET(AUX_BYTES, auxstatus);
+   /*
+* For some reason address-only DP_AUX_I2C_WRITE (MOT), still
+* reports 1 byte transferred in its status. To deal we that
+* we ignore aux_bytes field if we know that this was an
+* address-only transfer
+*/
+   if (size)
+   size = FIELD_GET(AUX_BYTES, auxstatus);
msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
 
switch (request) {
-- 
2.21.0



[PATCH v4 13/15] drm/bridge: tc358767: Simplify tc_aux_wait_busy()

2019-06-06 Thread Andrey Smirnov
We never pass anything but 100 as timeout_ms to tc_aux_wait_busy(), so
we may as well hardcode that value and simplify function's signature.

Signed-off-by: Andrey Smirnov 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index c994c72eb330..e747f10021e3 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -294,10 +294,9 @@ static inline int tc_poll_timeout(struct tc_data *tc, 
unsigned int addr,
sleep_us, timeout_us);
 }
 
-static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
+static int tc_aux_wait_busy(struct tc_data *tc)
 {
-   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
-  1000, 1000 * timeout_ms);
+   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 1000, 10);
 }
 
 static int tc_aux_write_data(struct tc_data *tc, const void *data,
@@ -350,7 +349,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;
 
-   ret = tc_aux_wait_busy(tc, 100);
+   ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
 
@@ -377,7 +376,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   ret = tc_aux_wait_busy(tc, 100);
+   ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
 
-- 
2.21.0



[PATCH v4 04/15] drm/bridge: tc358767: Simplify tc_set_video_mode()

2019-06-06 Thread Andrey Smirnov
Simplify tc_set_video_mode() by replacing explicit shifting using
macros from . No functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 106 ++
 1 file changed, 78 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 31f5045e7e42..5b78021d6c5b 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -24,6 +24,7 @@
  * GNU General Public License for more details.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -56,6 +57,7 @@
 
 /* Video Path */
 #define VPCTRL00x0450
+#define VSDELAYGENMASK(31, 20)
 #define OPXLFMT_RGB666 (0 << 8)
 #define OPXLFMT_RGB888 (1 << 8)
 #define FRMSYNC_DISABLED   (0 << 4) /* Video Timing Gen Disabled */
@@ -63,9 +65,17 @@
 #define MSF_DISABLED   (0 << 0) /* Magic Square FRC disabled */
 #define MSF_ENABLED(1 << 0) /* Magic Square FRC enabled */
 #define HTIM01 0x0454
+#define HPWGENMASK(8, 0)
+#define HBPR   GENMASK(24, 16)
 #define HTIM02 0x0458
+#define HDISPR GENMASK(10, 0)
+#define HFPR   GENMASK(24, 16)
 #define VTIM01 0x045c
+#define VSPR   GENMASK(7, 0)
+#define VBPR   GENMASK(23, 16)
 #define VTIM02 0x0460
+#define VFPR   GENMASK(23, 16)
+#define VDISPR GENMASK(10, 0)
 #define VFUEN0 0x0464
 #define VFUEN  BIT(0)   /* Video Frame Timing Upload */
 
@@ -108,14 +118,28 @@
 /* Main Channel */
 #define DP0_SECSAMPLE  0x0640
 #define DP0_VIDSYNCDELAY   0x0644
+#define VID_SYNC_DLY   GENMASK(15, 0)
+#define THRESH_DLY GENMASK(31, 16)
+
 #define DP0_TOTALVAL   0x0648
+#define H_TOTALGENMASK(15, 0)
+#define V_TOTALGENMASK(31, 16)
 #define DP0_STARTVAL   0x064c
+#define H_STARTGENMASK(15, 0)
+#define V_STARTGENMASK(31, 16)
 #define DP0_ACTIVEVAL  0x0650
+#define H_ACT  GENMASK(15, 0)
+#define V_ACT  GENMASK(31, 16)
+
 #define DP0_SYNCVAL0x0654
+#define VS_WIDTH   GENMASK(30, 16)
+#define HS_WIDTH   GENMASK(14, 0)
 #define SYNCVAL_HS_POL_ACTIVE_LOW  (1 << 15)
 #define SYNCVAL_VS_POL_ACTIVE_LOW  (1 << 31)
 #define DP0_MISC   0x0658
 #define TU_SIZE_RECOMMENDED(63) /* LSCLK cycles per TU */
+#define MAX_TU_SYMBOL  GENMASK(28, 23)
+#define TU_SIZEGENMASK(21, 16)
 #define BPC_6  (0 << 5)
 #define BPC_8  (1 << 5)
 
@@ -192,6 +216,12 @@
 
 /* Test & Debug */
 #define TSTCTL 0x0a00
+#define COLOR_RGENMASK(31, 24)
+#define COLOR_GGENMASK(23, 16)
+#define COLOR_BGENMASK(15, 8)
+#define ENI2CFILTERBIT(4)
+#define COLOR_BAR_MODE GENMASK(1, 0)
+#define COLOR_BAR_MODE_BARS2
 #define PLL_DBG0x0a04
 
 static bool tc_test_pattern;
@@ -672,6 +702,7 @@ static int tc_set_video_mode(struct tc_data *tc,
int upper_margin = mode->vtotal - mode->vsync_end;
int lower_margin = mode->vsync_start - mode->vdisplay;
int vsync_len = mode->vsync_end - mode->vsync_start;
+   u32 dp0_syncval;
 
/*
 * Recommended maximum number of symbols transferred in a transfer unit:
@@ -696,50 +727,69 @@ static int tc_set_video_mode(struct tc_data *tc,
 * assume we do not need any delay when DPI is a source of
 * sync signals
 */
-   tc_write(VPCTRL0, (0 << 20) /* VSDELAY */ |
+   tc_write(VPCTRL0,
+FIELD_PREP(VSDELAY, 0) |
 OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
-   tc_write(HTIM01, (ALIGN(left_margin, 2) << 16) | /* H back porch */
-(ALIGN(hsync_len, 2) << 0));/* Hsync */
-   tc_write(HTIM02, (ALIGN(right_margin, 2) << 16) |  /* H front porch */
-(ALIGN(mode->hdisplay, 2) << 0)); /* width */
-   tc_write(VTIM01, (upper_margin << 16) | /* V back porch */
-(vsync_len << 0)); /* Vsync */
-   tc_write(VTIM02, (lower_margin <<

[PATCH v4 01/15] drm/bridge: tc358767: Simplify tc_poll_timeout()

2019-06-06 Thread Andrey Smirnov
Implementation of tc_poll_timeout() is almost a 100% copy-and-paste of
the code for regmap_read_poll_timeout(). Replace copied code with a
call to the original. While at it change tc_poll_timeout to accept
"struct tc_data *" instead of "struct regmap *" for brevity. No
functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Reviewed-by: Laurent Pinchart 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 26 ++
 1 file changed, 6 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 58e3ca0e25af..fb8a1942ec54 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -264,34 +264,21 @@ static inline struct tc_data *connector_to_tc(struct 
drm_connector *c)
goto err;   \
} while (0)
 
-static inline int tc_poll_timeout(struct regmap *map, unsigned int addr,
+static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
  unsigned int cond_mask,
  unsigned int cond_value,
  unsigned long sleep_us, u64 timeout_us)
 {
-   ktime_t timeout = ktime_add_us(ktime_get(), timeout_us);
unsigned int val;
-   int ret;
 
-   for (;;) {
-   ret = regmap_read(map, addr, );
-   if (ret)
-   break;
-   if ((val & cond_mask) == cond_value)
-   break;
-   if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) {
-   ret = regmap_read(map, addr, );
-   break;
-   }
-   if (sleep_us)
-   usleep_range((sleep_us >> 2) + 1, sleep_us);
-   }
-   return ret ?: (((val & cond_mask) == cond_value) ? 0 : -ETIMEDOUT);
+   return regmap_read_poll_timeout(tc->regmap, addr, val,
+   (val & cond_mask) == cond_value,
+   sleep_us, timeout_us);
 }
 
 static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
 {
-   return tc_poll_timeout(tc->regmap, DP0_AUXSTATUS, AUX_BUSY, 0,
+   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
   1000, 1000 * timeout_ms);
 }
 
@@ -598,8 +585,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
tc_wait_pll_lock(tc);
 
-   ret = tc_poll_timeout(tc->regmap, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1,
- 1000);
+   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
dev_err(tc->dev, "Timeout waiting for PHY to become ready");
return ret;
-- 
2.21.0



[PATCH v4 14/15] drm/bridge: tc358767: Drop unnecessary 8 byte buffer

2019-06-06 Thread Andrey Smirnov
tc_get_display_props() never reads more than a byte via AUX, so
there's no need to reserve 8 for that purpose. No function change
intended.

Signed-off-by: Andrey Smirnov 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index e747f10021e3..4a245144aa83 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -661,8 +661,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
 static int tc_get_display_props(struct tc_data *tc)
 {
int ret;
-   /* temp buffer */
-   u8 tmp[8];
+   u8 reg;
 
/* Read DP Rx Link Capability */
ret = drm_dp_link_probe(>aux, >link.base);
@@ -678,21 +677,21 @@ static int tc_get_display_props(struct tc_data *tc)
tc->link.base.num_lanes = 2;
}
 
-   ret = drm_dp_dpcd_readb(>aux, DP_MAX_DOWNSPREAD, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_MAX_DOWNSPREAD, );
if (ret < 0)
goto err_dpcd_read;
-   tc->link.spread = tmp[0] & DP_MAX_DOWNSPREAD_0_5;
+   tc->link.spread = reg & DP_MAX_DOWNSPREAD_0_5;
 
-   ret = drm_dp_dpcd_readb(>aux, DP_MAIN_LINK_CHANNEL_CODING, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_MAIN_LINK_CHANNEL_CODING, );
if (ret < 0)
goto err_dpcd_read;
 
tc->link.scrambler_dis = false;
/* read assr */
-   ret = drm_dp_dpcd_readb(>aux, DP_EDP_CONFIGURATION_SET, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_EDP_CONFIGURATION_SET, );
if (ret < 0)
goto err_dpcd_read;
-   tc->link.assr = tmp[0] & DP_ALTERNATE_SCRAMBLER_RESET_ENABLE;
+   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,
-- 
2.21.0



[PATCH v4 00/15] tc358767 driver improvements

2019-06-06 Thread Andrey Smirnov
Everyone:

This series contains various improvements (at least in my mind) and
fixes that I made to tc358767 while working with the code of the
driver. Hopefuly each patch is self explanatory.

Feedback is welcome!

Thanks,
Andrey Smirnov

Changes since [v3]:

- Collected Reviewed-bys from Andrzej

- Dropped explicit check for -ETIMEDOUT in "drm/bridge: tc358767:
  Simplify polling in tc_main_link_setup()" for consistency

- AUX transfer code converted to user regmap_raw_read(),
  regmap_raw_write()

Changes since [v2]:

- Patchset rebased on top of v4 of Tomi's series that recently
  went in (https://patchwork.freedesktop.org/series/58176/#rev5)
  
- AUX transfer code converted to user regmap_bulk_read(),
  regmap_bulk_write()

Changes since [v1]:

- Patchset rebased on top of
  https://patchwork.freedesktop.org/series/58176/
  
- Patches to remove both tc_write() and tc_read() helpers added

- Patches to rework AUX transfer code added

- Both "drm/bridge: tc358767: Simplify polling in
  tc_main_link_setup()" and "drm/bridge: tc358767: Simplify
  polling in tc_link_training()" changed to use tc_poll_timeout()
  instead of regmap_read_poll_timeout()

[v3] lkml.kernel.org/r/20190605070507.11417-1-andrew.smir...@gmail.com
[v2] lkml.kernel.org/r/20190322032901.12045-1-andrew.smir...@gmail.com
[v1] lkml.kernel.org/r/20190226193609.9862-1-andrew.smir...@gmail.com

Andrey Smirnov (15):
  drm/bridge: tc358767: Simplify tc_poll_timeout()
  drm/bridge: tc358767: Simplify polling in tc_main_link_setup()
  drm/bridge: tc358767: Simplify polling in tc_link_training()
  drm/bridge: tc358767: Simplify tc_set_video_mode()
  drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors
  drm/bridge: tc358767: Simplify AUX data read
  drm/bridge: tc358767: Simplify AUX data write
  drm/bridge: tc358767: Increase AUX transfer length limit
  drm/bridge: tc358767: Use reported AUX transfer size
  drm/bridge: tc358767: Add support for address-only I2C transfers
  drm/bridge: tc358767: Introduce tc_set_syspllparam()
  drm/bridge: tc358767: Introduce tc_pllupdate_pllen()
  drm/bridge: tc358767: Simplify tc_aux_wait_busy()
  drm/bridge: tc358767: Drop unnecessary 8 byte buffer
  drm/bridge: tc358767: Replace magic number in tc_main_link_enable()

 drivers/gpu/drm/bridge/tc358767.c | 648 +-
 1 file changed, 372 insertions(+), 276 deletions(-)

-- 
2.21.0



[PATCH v4 02/15] drm/bridge: tc358767: Simplify polling in tc_main_link_setup()

2019-06-06 Thread Andrey Smirnov
Replace explicit polling loop with equivalent call to
tc_poll_timeout() for brevity. No functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 12 +++-
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index fb8a1942ec54..f463ef6d4271 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -774,7 +774,6 @@ static int tc_main_link_enable(struct tc_data *tc)
struct device *dev = tc->dev;
unsigned int rate;
u32 dp_phy_ctrl;
-   int timeout;
u32 value;
int ret;
u8 tmp[8];
@@ -831,15 +830,10 @@ static int tc_main_link_enable(struct tc_data *tc)
dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
tc_write(DP_PHY_CTRL, dp_phy_ctrl);
 
-   timeout = 1000;
-   do {
-   tc_read(DP_PHY_CTRL, );
-   udelay(1);
-   } while ((!(value & PHY_RDY)) && (--timeout));
-
-   if (timeout == 0) {
+   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
+   if (ret) {
dev_err(dev, "timeout waiting for phy become ready");
-   return -ETIMEDOUT;
+   return ret;
}
 
/* Set misc: 8 bits per color */
-- 
2.21.0



[PATCH v4 03/15] drm/bridge: tc358767: Simplify polling in tc_link_training()

2019-06-06 Thread Andrey Smirnov
Replace explicit polling in tc_link_training() with equivalent call to
tc_poll_timeout() for simplicity. No functional change intended (not
including slightly altered debug output).

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 15 ++-
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index f463ef6d4271..31f5045e7e42 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -748,22 +748,19 @@ static int tc_set_video_mode(struct tc_data *tc,
 
 static int tc_wait_link_training(struct tc_data *tc)
 {
-   u32 timeout = 1000;
u32 value;
int ret;
 
-   do {
-   udelay(1);
-   tc_read(DP0_LTSTAT, );
-   } while ((!(value & LT_LOOPDONE)) && (--timeout));
-
-   if (timeout == 0) {
+   ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
+ LT_LOOPDONE, 1, 1000);
+   if (ret) {
dev_err(tc->dev, "Link training timeout waiting for 
LT_LOOPDONE!\n");
-   return -ETIMEDOUT;
+   return ret;
}
 
-   return (value >> 8) & 0x7;
+   tc_read(DP0_LTSTAT, );
 
+   return (value >> 8) & 0x7;
 err:
return ret;
 }
-- 
2.21.0



Re: [PATCH v3 05/15] drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors

2019-06-06 Thread Andrey Smirnov
On Thu, Jun 6, 2019 at 3:34 AM Andrzej Hajda  wrote:
>
> On 05.06.2019 09:04, Andrey Smirnov wrote:
> > A very unfortunate aspect of tc_write()/tc_read() macro helpers is
> > that they capture quite a bit of context around them and thus require
> > the caller to have magic variables 'ret' and 'tc' as well as label
> > 'err'. That makes a number of code paths rather counterintuitive and
> > somewhat clunky, for example tc_stream_clock_calc() ends up being like
> > this:
> >
> >   int ret;
> >
> >   tc_write(DP0_VIDMNGEN1, 32768);
> >
> >   return 0;
> > err:
> >   return ret;
> >
> > which is rather surprising when you read the code for the first
> > time. Since those helpers arguably aren't really saving that much code
> > and there's no way of fixing them without making them too verbose to
> > be worth it change the driver code to not use them at all.
>
>
> On the other side, error checking after every registry access is very
> annoying and significantly augments the code, makes it redundant and
> less readable. To avoid it one can cache error state, and do not perform
> real work until the error is clear. For example with following accessor:
>
> void tc_write(struct tc_data *tc, u32 reg, u32 val){
>
> int ret;
>
> if (tc->error) //This check is IMPORTANT
>
> return;
>
> ret =regmap_write(...);
>
> if (ret >= 0)
>
> return;
>
> tc->error = ret;
>
> dev_err(tc->dev, "Error writing register %#x\n", reg);
>
> }
>
> You can safely write code like:
>
> tc_write(tc, DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_A0_EN);
>
> tc_write(tc, DP0_PLLCTRL, PLLUPDATE | PLLEN);
>
> tc_write(tc, DP1_PLLCTRL, PLLUPDATE | PLLEN);
>
> if (tc->error) {
>
> tc->error = 0;
>
> goto err;
>
> }
>
> This is of course loose suggestion.
>

I am going to have to disagree with you on this one, unfortunately.
Using regmap API explicitly definitely makes code more verbose, less
readable or more annoying though? Not really from my perspective. With
regmap code I know what the code is doing the moment I look at it,
with the example above, not so much. I also find it annoying that I
now have to remember the tricks that tc_write is pulling internally as
well as be mindful of a global-ish error state object. My problem with
original code was that a) it traded explicitness for conciseness in a
an unfavorable way, which I still think is true for code above b) it
didn't provide a comprehensive abstraction completely removing regmap
API and still relied on things like regmap_update_bits() explicitly,
making the code even more confusing (true for above example as well).
I think this driver isn't big enough to have a dedicated person always
working on it and it will mostly see occasional commits from somewhat
random folks who are coming to the codebase fresh, so creating as
little "institutional knowledge", so to speak, in a form of a custom
exception-like mechanism and opting for explicit but verbose code
seems like a preferable choice.

Anyway, I get it that's it is a loose suggestion :-), just wanted to
provide a detailed explanation why I'd rather not go that way.

Thanks,
Andrey Smirnov


Re: [PATCH v3 03/15] drm/bridge: tc358767: Simplify polling in tc_link_training()

2019-06-06 Thread Andrey Smirnov
On Thu, Jun 6, 2019 at 1:08 AM Andrzej Hajda  wrote:
>
> On 05.06.2019 09:04, Andrey Smirnov wrote:
> > Replace explicit polling in tc_link_training() with equivalent call to
> > tc_poll_timeout() for simplicity. No functional change intended (not
> > including slightly altered debug output).
> >
> > Signed-off-by: Andrey Smirnov 
> > Cc: Archit Taneja 
> > Cc: Andrzej Hajda 
> > Cc: Laurent Pinchart 
> > Cc: Tomi Valkeinen 
> > Cc: Andrey Gusakov 
> > Cc: Philipp Zabel 
> > Cc: Cory Tusar 
> > Cc: Chris Healy 
> > Cc: Lucas Stach 
> > Cc: dri-devel@lists.freedesktop.org
> > Cc: linux-ker...@vger.kernel.org
> > ---
> >  drivers/gpu/drm/bridge/tc358767.c | 15 ++-
> >  1 file changed, 6 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/tc358767.c 
> > b/drivers/gpu/drm/bridge/tc358767.c
> > index 5e1e73a91696..115cffc55a96 100644
> > --- a/drivers/gpu/drm/bridge/tc358767.c
> > +++ b/drivers/gpu/drm/bridge/tc358767.c
> > @@ -748,22 +748,19 @@ static int tc_set_video_mode(struct tc_data *tc,
> >
> >  static int tc_wait_link_training(struct tc_data *tc)
> >  {
> > - u32 timeout = 1000;
> >   u32 value;
> >   int ret;
> >
> > - do {
> > - udelay(1);
> > - tc_read(DP0_LTSTAT, );
> > - } while ((!(value & LT_LOOPDONE)) && (--timeout));
> > -
> > - if (timeout == 0) {
> > + ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
> > +   LT_LOOPDONE, 1, 1000);
> > + if (ret) {
> >   dev_err(tc->dev, "Link training timeout waiting for 
> > LT_LOOPDONE!\n");
> > - return -ETIMEDOUT;
> > + return ret;
> >   }
>
>
> Inconsistent coding, in previous patch you check (ret == -ETIMEDOUT) but
> not here. To simplify the code you can assume that tc_poll_timeout < 0,
> means timeout, in such case please adjust previous patch.
>

Sure, will do.

Thanks,
Andrey Smirnov


[PATCH v3 09/15] drm/bridge: tc358767: Use reported AUX transfer size

2019-06-05 Thread Andrey Smirnov
Don't assume that requested data transfer size is the same as amount
of data that was transferred. Change the code to get that information
from DP0_AUXSTATUS instead.

Since the check for AUX_BUSY in tc_aux_get_status() is pointless (it
will always called after tc_aux_wait_busy()) and there's only one user
of it, inline its code into tc_aux_transfer() instead of trying to
accommodate the change above.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 40 ++-
 1 file changed, 12 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 0125e2f7e076..90ec33caacbc 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -152,10 +152,10 @@
 #define DP0_AUXWDATA(i)(0x066c + (i) * 4)
 #define DP0_AUXRDATA(i)(0x067c + (i) * 4)
 #define DP0_AUXSTATUS  0x068c
-#define AUX_STATUS_MASK0xf0
-#define AUX_STATUS_SHIFT   4
-#define AUX_TIMEOUTBIT(1)
-#define AUX_BUSY   BIT(0)
+#define AUX_BYTES  GENMASK(15, 8)
+#define AUX_STATUS GENMASK(7, 4)
+#define AUX_TIMEOUTBIT(1)
+#define AUX_BUSY   BIT(0)
 #define DP0_AUXI2CADR  0x0698
 
 /* Link Training */
@@ -298,29 +298,6 @@ static int tc_aux_wait_busy(struct tc_data *tc, unsigned 
int timeout_ms)
   1000, 1000 * timeout_ms);
 }
 
-static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
-{
-   int ret;
-   u32 value;
-
-   ret = regmap_read(tc->regmap, DP0_AUXSTATUS, );
-   if (ret < 0)
-   return ret;
-
-   if (value & AUX_BUSY) {
-   dev_err(tc->dev, "aux busy!\n");
-   return -EBUSY;
-   }
-
-   if (value & AUX_TIMEOUT) {
-   dev_err(tc->dev, "aux access timeout!\n");
-   return -ETIMEDOUT;
-   }
-
-   *reply = (value & AUX_STATUS_MASK) >> AUX_STATUS_SHIFT;
-   return 0;
-}
-
 static int tc_aux_write_data(struct tc_data *tc, const void *data,
 size_t size)
 {
@@ -376,6 +353,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct tc_data *tc = aux_to_tc(aux);
size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
+   u32 auxstatus;
int ret;
 
if (size == 0)
@@ -413,10 +391,16 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   ret = tc_aux_get_status(tc, >reply);
+   ret = regmap_read(tc->regmap, DP0_AUXSTATUS, );
if (ret)
return ret;
 
+   if (auxstatus & AUX_TIMEOUT)
+   return -ETIMEDOUT;
+
+   size = FIELD_GET(AUX_BYTES, auxstatus);
+   msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
+
switch (request) {
case DP_AUX_NATIVE_READ:
case DP_AUX_I2C_READ:
-- 
2.21.0



[PATCH v3 11/15] drm/bridge: tc358767: Introduce tc_set_syspllparam()

2019-06-05 Thread Andrey Smirnov
Move common code converting clock rate to an appropriate constant and
configuring SYS_PLLPARAM register into a separate routine and convert
the rest of the code to use it. No functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Laurent Pinchart 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Cory Tusar 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 46 +++
 1 file changed, 16 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 7b84fbb72973..c58714daa0a1 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -601,35 +601,40 @@ static int tc_stream_clock_calc(struct tc_data *tc)
return regmap_write(tc->regmap, DP0_VIDMNGEN1, 32768);
 }
 
-static int tc_aux_link_setup(struct tc_data *tc)
+static int tc_set_syspllparam(struct tc_data *tc)
 {
unsigned long rate;
-   u32 dp0_auxcfg1;
-   u32 value;
-   int ret;
+   u32 pllparam = SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
 
rate = clk_get_rate(tc->refclk);
switch (rate) {
case 3840:
-   value = REF_FREQ_38M4;
+   pllparam |= REF_FREQ_38M4;
break;
case 2600:
-   value = REF_FREQ_26M;
+   pllparam |= REF_FREQ_26M;
break;
case 1920:
-   value = REF_FREQ_19M2;
+   pllparam |= REF_FREQ_19M2;
break;
case 1300:
-   value = REF_FREQ_13M;
+   pllparam |= REF_FREQ_13M;
break;
default:
dev_err(tc->dev, "Invalid refclk rate: %lu Hz\n", rate);
return -EINVAL;
}
 
+   return regmap_write(tc->regmap, SYS_PLLPARAM, pllparam);
+}
+
+static int tc_aux_link_setup(struct tc_data *tc)
+{
+   int ret;
+   u32 dp0_auxcfg1;
+
/* Setup DP-PHY / PLL */
-   value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
-   ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+   ret = tc_set_syspllparam(tc);
if (ret)
goto err;
 
@@ -887,7 +892,6 @@ static int tc_main_link_enable(struct tc_data *tc)
 {
struct drm_dp_aux *aux = >aux;
struct device *dev = tc->dev;
-   unsigned int rate;
u32 dp_phy_ctrl;
u32 value;
int ret;
@@ -915,25 +919,7 @@ static int tc_main_link_enable(struct tc_data *tc)
if (ret)
return ret;
 
-   rate = clk_get_rate(tc->refclk);
-   switch (rate) {
-   case 3840:
-   value = REF_FREQ_38M4;
-   break;
-   case 2600:
-   value = REF_FREQ_26M;
-   break;
-   case 1920:
-   value = REF_FREQ_19M2;
-   break;
-   case 1300:
-   value = REF_FREQ_13M;
-   break;
-   default:
-   return -EINVAL;
-   }
-   value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
-   ret = regmap_write(tc->regmap, SYS_PLLPARAM, value);
+   ret = tc_set_syspllparam(tc);
if (ret)
return ret;
 
-- 
2.21.0



[PATCH v3 08/15] drm/bridge: tc358767: Increase AUX transfer length limit

2019-06-05 Thread Andrey Smirnov
According to the datasheet tc358767 can transfer up to 16 bytes via
its AUX channel, so the artificial limit of 8 apperas to be too
low. However only up to 15-bytes seem to be actually supported and
trying to use 16-byte transfers results in transfers failing
sporadically (with bogus status in case of I2C transfers), so limit it
to 15.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 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 260fbcd0271e..0125e2f7e076 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -374,7 +374,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
struct tc_data *tc = aux_to_tc(aux);
-   size_t size = min_t(size_t, 8, msg->size);
+   size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
int ret;
 
-- 
2.21.0



[PATCH v3 14/15] drm/bridge: tc358767: Drop unnecessary 8 byte buffer

2019-06-05 Thread Andrey Smirnov
tc_get_display_props() never reads more than a byte via AUX, so
there's no need to reserve 8 for that purpose. No function change
intended.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 4fe7641f84ee..41a976dff13b 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -680,8 +680,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
 static int tc_get_display_props(struct tc_data *tc)
 {
int ret;
-   /* temp buffer */
-   u8 tmp[8];
+   u8 reg;
 
/* Read DP Rx Link Capability */
ret = drm_dp_link_probe(>aux, >link.base);
@@ -697,21 +696,21 @@ static int tc_get_display_props(struct tc_data *tc)
tc->link.base.num_lanes = 2;
}
 
-   ret = drm_dp_dpcd_readb(>aux, DP_MAX_DOWNSPREAD, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_MAX_DOWNSPREAD, );
if (ret < 0)
goto err_dpcd_read;
-   tc->link.spread = tmp[0] & DP_MAX_DOWNSPREAD_0_5;
+   tc->link.spread = reg & DP_MAX_DOWNSPREAD_0_5;
 
-   ret = drm_dp_dpcd_readb(>aux, DP_MAIN_LINK_CHANNEL_CODING, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_MAIN_LINK_CHANNEL_CODING, );
if (ret < 0)
goto err_dpcd_read;
 
tc->link.scrambler_dis = false;
/* read assr */
-   ret = drm_dp_dpcd_readb(>aux, DP_EDP_CONFIGURATION_SET, tmp);
+   ret = drm_dp_dpcd_readb(>aux, DP_EDP_CONFIGURATION_SET, );
if (ret < 0)
goto err_dpcd_read;
-   tc->link.assr = tmp[0] & DP_ALTERNATE_SCRAMBLER_RESET_ENABLE;
+   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,
-- 
2.21.0



[PATCH v3 15/15] drm/bridge: tc358767: Replace magic number in tc_main_link_enable()

2019-06-05 Thread Andrey Smirnov
We don't need 8 byte array, DP_LINK_STATUS_SIZE (6) should be
enough. This also gets rid of a magic number as a bonus.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 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 41a976dff13b..cf38f943e656 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -893,7 +893,7 @@ static int tc_main_link_enable(struct tc_data *tc)
u32 dp_phy_ctrl;
u32 value;
int ret;
-   u8 tmp[8];
+   u8 tmp[DP_LINK_STATUS_SIZE];
 
dev_dbg(tc->dev, "link enable\n");
 
-- 
2.21.0



[PATCH v3 04/15] drm/bridge: tc358767: Simplify tc_set_video_mode()

2019-06-05 Thread Andrey Smirnov
Simplify tc_set_video_mode() by replacing explicit shifting using
macros from . No functional change intended.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 106 ++
 1 file changed, 78 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 115cffc55a96..c0fc686ce5ec 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -24,6 +24,7 @@
  * GNU General Public License for more details.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -56,6 +57,7 @@
 
 /* Video Path */
 #define VPCTRL00x0450
+#define VSDELAYGENMASK(31, 20)
 #define OPXLFMT_RGB666 (0 << 8)
 #define OPXLFMT_RGB888 (1 << 8)
 #define FRMSYNC_DISABLED   (0 << 4) /* Video Timing Gen Disabled */
@@ -63,9 +65,17 @@
 #define MSF_DISABLED   (0 << 0) /* Magic Square FRC disabled */
 #define MSF_ENABLED(1 << 0) /* Magic Square FRC enabled */
 #define HTIM01 0x0454
+#define HPWGENMASK(8, 0)
+#define HBPR   GENMASK(24, 16)
 #define HTIM02 0x0458
+#define HDISPR GENMASK(10, 0)
+#define HFPR   GENMASK(24, 16)
 #define VTIM01 0x045c
+#define VSPR   GENMASK(7, 0)
+#define VBPR   GENMASK(23, 16)
 #define VTIM02 0x0460
+#define VFPR   GENMASK(23, 16)
+#define VDISPR GENMASK(10, 0)
 #define VFUEN0 0x0464
 #define VFUEN  BIT(0)   /* Video Frame Timing Upload */
 
@@ -108,14 +118,28 @@
 /* Main Channel */
 #define DP0_SECSAMPLE  0x0640
 #define DP0_VIDSYNCDELAY   0x0644
+#define VID_SYNC_DLY   GENMASK(15, 0)
+#define THRESH_DLY GENMASK(31, 16)
+
 #define DP0_TOTALVAL   0x0648
+#define H_TOTALGENMASK(15, 0)
+#define V_TOTALGENMASK(31, 16)
 #define DP0_STARTVAL   0x064c
+#define H_STARTGENMASK(15, 0)
+#define V_STARTGENMASK(31, 16)
 #define DP0_ACTIVEVAL  0x0650
+#define H_ACT  GENMASK(15, 0)
+#define V_ACT  GENMASK(31, 16)
+
 #define DP0_SYNCVAL0x0654
+#define VS_WIDTH   GENMASK(30, 16)
+#define HS_WIDTH   GENMASK(14, 0)
 #define SYNCVAL_HS_POL_ACTIVE_LOW  (1 << 15)
 #define SYNCVAL_VS_POL_ACTIVE_LOW  (1 << 31)
 #define DP0_MISC   0x0658
 #define TU_SIZE_RECOMMENDED(63) /* LSCLK cycles per TU */
+#define MAX_TU_SYMBOL  GENMASK(28, 23)
+#define TU_SIZEGENMASK(21, 16)
 #define BPC_6  (0 << 5)
 #define BPC_8  (1 << 5)
 
@@ -192,6 +216,12 @@
 
 /* Test & Debug */
 #define TSTCTL 0x0a00
+#define COLOR_RGENMASK(31, 24)
+#define COLOR_GGENMASK(23, 16)
+#define COLOR_BGENMASK(15, 8)
+#define ENI2CFILTERBIT(4)
+#define COLOR_BAR_MODE GENMASK(1, 0)
+#define COLOR_BAR_MODE_BARS2
 #define PLL_DBG0x0a04
 
 static bool tc_test_pattern;
@@ -672,6 +702,7 @@ static int tc_set_video_mode(struct tc_data *tc,
int upper_margin = mode->vtotal - mode->vsync_end;
int lower_margin = mode->vsync_start - mode->vdisplay;
int vsync_len = mode->vsync_end - mode->vsync_start;
+   u32 dp0_syncval;
 
/*
 * Recommended maximum number of symbols transferred in a transfer unit:
@@ -696,50 +727,69 @@ static int tc_set_video_mode(struct tc_data *tc,
 * assume we do not need any delay when DPI is a source of
 * sync signals
 */
-   tc_write(VPCTRL0, (0 << 20) /* VSDELAY */ |
+   tc_write(VPCTRL0,
+FIELD_PREP(VSDELAY, 0) |
 OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
-   tc_write(HTIM01, (ALIGN(left_margin, 2) << 16) | /* H back porch */
-(ALIGN(hsync_len, 2) << 0));/* Hsync */
-   tc_write(HTIM02, (ALIGN(right_margin, 2) << 16) |  /* H front porch */
-(ALIGN(mode->hdisplay, 2) << 0)); /* width */
-   tc_write(VTIM01, (upper_margin << 16) | /* V back porch */
-(vsync_len << 0)); /* Vsync */
-   tc_write(VTIM02, (lower_margin <<

[PATCH v3 12/15] drm/bridge: tc358767: Introduce tc_pllupdate_pllen()

2019-06-05 Thread Andrey Smirnov
tc_wait_pll_lock() is always called as a follow-up for updating
PLLUPDATE and PLLEN bit of a given PLL control register. To simplify
things, merge the two operation into a single helper function
tc_pllupdate_pllen() and convert the rest of the code to use it. No
functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Laurent Pinchart 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 30 ++
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index c58714daa0a1..a04401cf2a92 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -463,10 +463,18 @@ static u32 tc_srcctrl(struct tc_data *tc)
return reg;
 }
 
-static void tc_wait_pll_lock(struct tc_data *tc)
+static int tc_pllupdate_pllen(struct tc_data *tc, unsigned int pllctrl)
 {
+   int ret;
+
+   ret = regmap_write(tc->regmap, pllctrl, PLLUPDATE | PLLEN);
+   if (ret)
+   return ret;
+
/* Wait for PLL to lock: up to 2.09 ms, depending on refclk */
usleep_range(3000, 6000);
+
+   return 0;
 }
 
 static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
@@ -566,13 +574,7 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, 
u32 pixelclock)
return ret;
 
/* Force PLL parameter update and disable bypass */
-   ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLUPDATE | PLLEN);
-   if (ret)
-   return ret;
-
-   tc_wait_pll_lock(tc);
-
-   return 0;
+   return tc_pllupdate_pllen(tc, PXL_PLLCTRL);
 }
 
 static int tc_pxl_pll_dis(struct tc_data *tc)
@@ -645,15 +647,13 @@ static int tc_aux_link_setup(struct tc_data *tc)
 * Initially PLLs are in bypass. Force PLL parameter update,
 * disable PLL bypass, enable PLL
 */
-   ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP0_PLLCTRL);
if (ret)
goto err;
-   tc_wait_pll_lock(tc);
 
-   ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP1_PLLCTRL);
if (ret)
goto err;
-   tc_wait_pll_lock(tc);
 
ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
@@ -933,15 +933,13 @@ static int tc_main_link_enable(struct tc_data *tc)
return ret;
 
/* PLL setup */
-   ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP0_PLLCTRL);
if (ret)
return ret;
-   tc_wait_pll_lock(tc);
 
-   ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP1_PLLCTRL);
if (ret)
return ret;
-   tc_wait_pll_lock(tc);
 
/* Reset/Enable Main Links */
dp_phy_ctrl |= DP_PHY_RST | PHY_M1_RST | PHY_M0_RST;
-- 
2.21.0



[PATCH v3 01/15] drm/bridge: tc358767: Simplify tc_poll_timeout()

2019-06-05 Thread Andrey Smirnov
Implementation of tc_poll_timeout() is almost a 100% copy-and-paste of
the code for regmap_read_poll_timeout(). Replace copied code with a
call to the original. While at it change tc_poll_timeout to accept
"struct tc_data *" instead of "struct regmap *" for brevity. No
functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Reviewed-by: Laurent Pinchart 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 26 ++
 1 file changed, 6 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 58e3ca0e25af..fb8a1942ec54 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -264,34 +264,21 @@ static inline struct tc_data *connector_to_tc(struct 
drm_connector *c)
goto err;   \
} while (0)
 
-static inline int tc_poll_timeout(struct regmap *map, unsigned int addr,
+static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
  unsigned int cond_mask,
  unsigned int cond_value,
  unsigned long sleep_us, u64 timeout_us)
 {
-   ktime_t timeout = ktime_add_us(ktime_get(), timeout_us);
unsigned int val;
-   int ret;
 
-   for (;;) {
-   ret = regmap_read(map, addr, );
-   if (ret)
-   break;
-   if ((val & cond_mask) == cond_value)
-   break;
-   if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) {
-   ret = regmap_read(map, addr, );
-   break;
-   }
-   if (sleep_us)
-   usleep_range((sleep_us >> 2) + 1, sleep_us);
-   }
-   return ret ?: (((val & cond_mask) == cond_value) ? 0 : -ETIMEDOUT);
+   return regmap_read_poll_timeout(tc->regmap, addr, val,
+   (val & cond_mask) == cond_value,
+   sleep_us, timeout_us);
 }
 
 static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
 {
-   return tc_poll_timeout(tc->regmap, DP0_AUXSTATUS, AUX_BUSY, 0,
+   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
   1000, 1000 * timeout_ms);
 }
 
@@ -598,8 +585,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
tc_wait_pll_lock(tc);
 
-   ret = tc_poll_timeout(tc->regmap, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1,
- 1000);
+   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
dev_err(tc->dev, "Timeout waiting for PHY to become ready");
return ret;
-- 
2.21.0



[PATCH v3 05/15] drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors

2019-06-05 Thread Andrey Smirnov
A very unfortunate aspect of tc_write()/tc_read() macro helpers is
that they capture quite a bit of context around them and thus require
the caller to have magic variables 'ret' and 'tc' as well as label
'err'. That makes a number of code paths rather counterintuitive and
somewhat clunky, for example tc_stream_clock_calc() ends up being like
this:

int ret;

tc_write(DP0_VIDMNGEN1, 32768);

return 0;
err:
return ret;

which is rather surprising when you read the code for the first
time. Since those helpers arguably aren't really saving that much code
and there's no way of fixing them without making them too verbose to
be worth it change the driver code to not use them at all.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 381 ++
 1 file changed, 229 insertions(+), 152 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index c0fc686ce5ec..e197ce0fb166 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -280,20 +280,6 @@ static inline struct tc_data *connector_to_tc(struct 
drm_connector *c)
return container_of(c, struct tc_data, connector);
 }
 
-/* Simple macros to avoid repeated error checks */
-#define tc_write(reg, var) \
-   do {\
-   ret = regmap_write(tc->regmap, reg, var);   \
-   if (ret)\
-   goto err;   \
-   } while (0)
-#define tc_read(reg, var)  \
-   do {\
-   ret = regmap_read(tc->regmap, reg, var);\
-   if (ret)\
-   goto err;   \
-   } while (0)
-
 static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
  unsigned int cond_mask,
  unsigned int cond_value,
@@ -351,7 +337,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
 
ret = tc_aux_wait_busy(tc, 100);
if (ret)
-   goto err;
+   return ret;
 
if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
/* Store data */
@@ -362,7 +348,11 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
tmp = (tmp << 8) | buf[i];
i++;
if (((i % 4) == 0) || (i == size)) {
-   tc_write(DP0_AUXWDATA((i - 1) >> 2), tmp);
+   ret = regmap_write(tc->regmap,
+  DP0_AUXWDATA((i - 1) >> 2),
+  tmp);
+   if (ret)
+   return ret;
tmp = 0;
}
}
@@ -372,23 +362,32 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
}
 
/* Store address */
-   tc_write(DP0_AUXADDR, msg->address);
+   ret = regmap_write(tc->regmap, DP0_AUXADDR, msg->address);
+   if (ret)
+   return ret;
/* Start transfer */
-   tc_write(DP0_AUXCFG0, ((size - 1) << 8) | request);
+   ret = regmap_write(tc->regmap, DP0_AUXCFG0,
+  ((size - 1) << 8) | request);
+   if (ret)
+   return ret;
 
ret = tc_aux_wait_busy(tc, 100);
if (ret)
-   goto err;
+   return ret;
 
ret = tc_aux_get_status(tc, >reply);
if (ret)
-   goto err;
+   return ret;
 
if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
/* Read data */
while (i < size) {
-   if ((i % 4) == 0)
-   tc_read(DP0_AUXRDATA(i >> 2), );
+   if ((i % 4) == 0) {
+   ret = regmap_read(tc->regmap,
+ DP0_AUXRDATA(i >> 2), );
+   if (ret)
+   return ret;
+   }
buf[i] = tmp & 0xff;
tmp = tmp >> 8;
i++;
@@ -396,8 +395,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,

[PATCH v3 02/15] drm/bridge: tc358767: Simplify polling in tc_main_link_setup()

2019-06-05 Thread Andrey Smirnov
Replace explicit polling loop with equivalent call to
tc_poll_timeout() for brevity. No functional change intended.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 15 +--
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index fb8a1942ec54..5e1e73a91696 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -774,7 +774,6 @@ static int tc_main_link_enable(struct tc_data *tc)
struct device *dev = tc->dev;
unsigned int rate;
u32 dp_phy_ctrl;
-   int timeout;
u32 value;
int ret;
u8 tmp[8];
@@ -831,15 +830,11 @@ static int tc_main_link_enable(struct tc_data *tc)
dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
tc_write(DP_PHY_CTRL, dp_phy_ctrl);
 
-   timeout = 1000;
-   do {
-   tc_read(DP_PHY_CTRL, );
-   udelay(1);
-   } while ((!(value & PHY_RDY)) && (--timeout));
-
-   if (timeout == 0) {
-   dev_err(dev, "timeout waiting for phy become ready");
-   return -ETIMEDOUT;
+   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
+   if (ret) {
+   if (ret == -ETIMEDOUT)
+   dev_err(dev, "timeout waiting for phy become ready");
+   return ret;
}
 
/* Set misc: 8 bits per color */
-- 
2.21.0



[PATCH v3 00/15] tc358767 driver improvements

2019-06-05 Thread Andrey Smirnov
Everyone:

This series contains various improvements (at least in my mind) and
fixes that I made to tc358767 while working with the code of the
driver. Hopefuly each patch is self explanatory.

Feedback is welcome!

Thanks,
Andrey Smirnov

Changes since [v2]:

- Patchset rebased on top of v4 of Tomi's series that recently
  went in (https://patchwork.freedesktop.org/series/58176/#rev5)
  
   - AUX transfer code converted to user regmap_bulk_read(),
 regmap_bulk_write()

Changes since [v1]:

- Patchset rebased on top of
  https://patchwork.freedesktop.org/series/58176/
  
- Patches to remove both tc_write() and tc_read() helpers added

- Patches to rework AUX transfer code added

- Both "drm/bridge: tc358767: Simplify polling in
  tc_main_link_setup()" and "drm/bridge: tc358767: Simplify
  polling in tc_link_training()" changed to use tc_poll_timeout()
  instead of regmap_read_poll_timeout()

[v2] lkml.kernel.org/r/20190322032901.12045-1-andrew.smir...@gmail.com
[v1] lkml.kernel.org/r/20190226193609.9862-1-andrew.smir...@gmail.com


Andrey Smirnov (15):
  drm/bridge: tc358767: Simplify tc_poll_timeout()
  drm/bridge: tc358767: Simplify polling in tc_main_link_setup()
  drm/bridge: tc358767: Simplify polling in tc_link_training()
  drm/bridge: tc358767: Simplify tc_set_video_mode()
  drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors
  drm/bridge: tc358767: Simplify AUX data read
  drm/bridge: tc358767: Simplify AUX data write
  drm/bridge: tc358767: Increase AUX transfer length limit
  drm/bridge: tc358767: Use reported AUX transfer size
  drm/bridge: tc358767: Add support for address-only I2C transfers
  drm/bridge: tc358767: Introduce tc_set_syspllparam()
  drm/bridge: tc358767: Introduce tc_pllupdate_pllen()
  drm/bridge: tc358767: Simplify tc_aux_wait_busy()
  drm/bridge: tc358767: Drop unnecessary 8 byte buffer
  drm/bridge: tc358767: Replace magic number in tc_main_link_enable()

 drivers/gpu/drm/bridge/tc358767.c | 668 ++
 1 file changed, 392 insertions(+), 276 deletions(-)

-- 
2.21.0



[PATCH v3 10/15] drm/bridge: tc358767: Add support for address-only I2C transfers

2019-06-05 Thread Andrey Smirnov
Transfer size of zero means a request to do an address-only
transfer. Since the HW support this, we probably shouldn't be just
ignoring such requests. While at it allow DP_AUX_I2C_MOT flag to pass
through, since it is supported by the HW as well.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 30 +++---
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 90ec33caacbc..7b84fbb72973 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -145,6 +145,8 @@
 
 /* AUX channel */
 #define DP0_AUXCFG00x0660
+#define DP0_AUXCFG0_BSIZE  GENMASK(11, 8)
+#define DP0_AUXCFG0_ADDR_ONLY  BIT(4)
 #define DP0_AUXCFG10x0664
 #define AUX_RX_FILTER_EN   BIT(16)
 
@@ -347,6 +349,18 @@ static int tc_aux_read_data(struct tc_data *tc, void 
*data, size_t size)
return size;
 }
 
+static u32 tc_auxcfg0(struct drm_dp_aux_msg *msg, size_t size)
+{
+   u32 auxcfg0 = msg->request;
+
+   if (size)
+   auxcfg0 |= FIELD_PREP(DP0_AUXCFG0_BSIZE, size - 1);
+   else
+   auxcfg0 |= DP0_AUXCFG0_ADDR_ONLY;
+
+   return auxcfg0;
+}
+
 static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
@@ -356,9 +370,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;
 
-   if (size == 0)
-   return 0;
-
ret = tc_aux_wait_busy(tc, 100);
if (ret)
return ret;
@@ -382,8 +393,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
/* Start transfer */
-   ret = regmap_write(tc->regmap, DP0_AUXCFG0,
-  ((size - 1) << 8) | request);
+   ret = regmap_write(tc->regmap, DP0_AUXCFG0, tc_auxcfg0(msg, size));
if (ret)
return ret;
 
@@ -397,8 +407,14 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
 
if (auxstatus & AUX_TIMEOUT)
return -ETIMEDOUT;
-
-   size = FIELD_GET(AUX_BYTES, auxstatus);
+   /*
+* For some reason address-only DP_AUX_I2C_WRITE (MOT), still
+* reports 1 byte transferred in its status. To deal we that
+* we ignore aux_bytes field if we know that this was an
+* address-only transfer
+*/
+   if (size)
+   size = FIELD_GET(AUX_BYTES, auxstatus);
msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
 
switch (request) {
-- 
2.21.0



[PATCH v3 06/15] drm/bridge: tc358767: Simplify AUX data read

2019-06-05 Thread Andrey Smirnov
Simplify AUX data read by removing index arithmetic and shifting with
a helper functions that does three things:

1. Fetch data from up to 4 32-bit registers from the chip
2. Optionally fix data endianness (not needed on LE hosts)
3. Copy read data into user provided array.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 40 +--
 1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index e197ce0fb166..da47d81e7109 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -321,6 +321,29 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
 }
 
+static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
+{
+   u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
+   int ret, i, count = DIV_ROUND_UP(size, sizeof(u32));
+
+   ret = regmap_bulk_read(tc->regmap, DP0_AUXRDATA(0), auxrdata, count);
+   if (ret)
+   return ret;
+
+   for (i = 0; i < count; i++) {
+   /*
+* Our regmap is configured as LE for register data,
+* so we need undo any byte swapping that might have
+* happened to preserve original byte order.
+*/
+   le32_to_cpus([i]);
+   }
+
+   memcpy(data, auxrdata, size);
+
+   return size;
+}
+
 static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
@@ -379,19 +402,10 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
-   /* Read data */
-   while (i < size) {
-   if ((i % 4) == 0) {
-   ret = regmap_read(tc->regmap,
- DP0_AUXRDATA(i >> 2), );
-   if (ret)
-   return ret;
-   }
-   buf[i] = tmp & 0xff;
-   tmp = tmp >> 8;
-   i++;
-   }
+   switch (request) {
+   case DP_AUX_NATIVE_READ:
+   case DP_AUX_I2C_READ:
+   return tc_aux_read_data(tc, msg->buffer, size);
}
 
return size;
-- 
2.21.0



[PATCH v3 07/15] drm/bridge: tc358767: Simplify AUX data write

2019-06-05 Thread Andrey Smirnov
Simplify AUX data write by dropping index arithmetic and shifting and
replacing it with a call to a helper function that does three things:

1. Copies user-provided data into a write buffer
2. Optionally fixes the endianness of the write buffer (not needed
   on LE hosts)
3. Transfers contenst of the write buffer to up to 4 32-bit
   registers on the chip

Note that separate data endianness fix:

tmp = (tmp << 8) | buf[i];

that was reserved for DP_AUX_I2C_WRITE looks really strange, since it
will place data differently depending on the passed user-data
size. E.g. for a write of 1 byte, data transferred to the chip would
look like:

[byte0] [dummy1] [dummy2] [dummy3]

whereas for a write of 4 bytes we'd get:

[byte3] [byte2] [byte1] [byte0]

Since there's no indication in the datasheet that I2C write buffer
should be treated differently than AUX write buffer and no comment in
the original code explaining why it was done this way, that special
I2C write buffer transformation was dropped in this patch.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 59 +++
 1 file changed, 37 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index da47d81e7109..260fbcd0271e 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -321,6 +321,32 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
 }
 
+static int tc_aux_write_data(struct tc_data *tc, const void *data,
+size_t size)
+{
+   u32 auxwdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)] = { 0 };
+   int ret, i, count = DIV_ROUND_UP(size, sizeof(u32));
+
+   memcpy(auxwdata, data, size);
+
+   for (i = 0; i < count; i++) {
+   /*
+* Our regmap is configured as LE
+* for register data, so we need
+* undo any byte swapping that will
+* happened to preserve original
+* byte order.
+*/
+   cpu_to_le32s([i]);
+   }
+
+   ret = regmap_bulk_write(tc->regmap, DP0_AUXWDATA(0), auxwdata, count);
+   if (ret)
+   return ret;
+
+   return size;
+}
+
 static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
 {
u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
@@ -350,9 +376,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
struct tc_data *tc = aux_to_tc(aux);
size_t size = min_t(size_t, 8, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
-   u8 *buf = msg->buffer;
-   u32 tmp = 0;
-   int i = 0;
int ret;
 
if (size == 0)
@@ -362,25 +385,17 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   if (request == DP_AUX_I2C_WRITE || request == DP_AUX_NATIVE_WRITE) {
-   /* Store data */
-   while (i < size) {
-   if (request == DP_AUX_NATIVE_WRITE)
-   tmp = tmp | (buf[i] << (8 * (i & 0x3)));
-   else
-   tmp = (tmp << 8) | buf[i];
-   i++;
-   if (((i % 4) == 0) || (i == size)) {
-   ret = regmap_write(tc->regmap,
-  DP0_AUXWDATA((i - 1) >> 2),
-  tmp);
-   if (ret)
-   return ret;
-   tmp = 0;
-   }
-   }
-   } else if (request != DP_AUX_I2C_READ &&
-  request != DP_AUX_NATIVE_READ) {
+   switch (request) {
+   case DP_AUX_NATIVE_READ:
+   case DP_AUX_I2C_READ:
+   break;
+   case DP_AUX_NATIVE_WRITE:
+   case DP_AUX_I2C_WRITE:
+   ret = tc_aux_write_data(tc, msg->buffer, size);
+   if (ret < 0)
+   return ret;
+   break;
+   default:
return -EINVAL;
}
 
-- 
2.21.0



[PATCH v3 13/15] drm/bridge: tc358767: Simplify tc_aux_wait_busy()

2019-06-05 Thread Andrey Smirnov
We never pass anything but 100 as timeout_ms to tc_aux_wait_busy(), so
we may as well hardcode that value and simplify function's signature.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index a04401cf2a92..4fe7641f84ee 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -294,10 +294,9 @@ static inline int tc_poll_timeout(struct tc_data *tc, 
unsigned int addr,
sleep_us, timeout_us);
 }
 
-static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
+static int tc_aux_wait_busy(struct tc_data *tc)
 {
-   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
-  1000, 1000 * timeout_ms);
+   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 1000, 10);
 }
 
 static int tc_aux_write_data(struct tc_data *tc, const void *data,
@@ -370,7 +369,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;
 
-   ret = tc_aux_wait_busy(tc, 100);
+   ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
 
@@ -397,7 +396,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   ret = tc_aux_wait_busy(tc, 100);
+   ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
 
-- 
2.21.0



[PATCH v3 03/15] drm/bridge: tc358767: Simplify polling in tc_link_training()

2019-06-05 Thread Andrey Smirnov
Replace explicit polling in tc_link_training() with equivalent call to
tc_poll_timeout() for simplicity. No functional change intended (not
including slightly altered debug output).

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Cory Tusar 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 15 ++-
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 5e1e73a91696..115cffc55a96 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -748,22 +748,19 @@ static int tc_set_video_mode(struct tc_data *tc,
 
 static int tc_wait_link_training(struct tc_data *tc)
 {
-   u32 timeout = 1000;
u32 value;
int ret;
 
-   do {
-   udelay(1);
-   tc_read(DP0_LTSTAT, );
-   } while ((!(value & LT_LOOPDONE)) && (--timeout));
-
-   if (timeout == 0) {
+   ret = tc_poll_timeout(tc, DP0_LTSTAT, LT_LOOPDONE,
+ LT_LOOPDONE, 1, 1000);
+   if (ret) {
dev_err(tc->dev, "Link training timeout waiting for 
LT_LOOPDONE!\n");
-   return -ETIMEDOUT;
+   return ret;
}
 
-   return (value >> 8) & 0x7;
+   tc_read(DP0_LTSTAT, );
 
+   return (value >> 8) & 0x7;
 err:
return ret;
 }
-- 
2.21.0



Re: [PATCHv2 03/22] drm/bridge: tc358767: fix ansi 8b10b use

2019-05-22 Thread Andrey Smirnov
On Mon, May 6, 2019 at 2:59 AM Tomi Valkeinen  wrote:
>
> Hi Laurent, Andrey,
>
> On 03/05/2019 20:11, Laurent Pinchart wrote:
> >> I agree that if the panel Andrey mentioned is still used, we need to
> >> handle it somehow. But I think explicitly handling such a case is better
> >> than guessing.
> >
> > The risk may not be worth it, I agree. I would explain this in details
> > in the commit message though, and add a comment to the code as well, to
> > ease future debugging.
>
> Andrey, do you still have the panel that doesn't work with 8b10b? Is it
> used in real life (i.e. it was not just a temporary development phase
> panel)? What's the model, and is there a public datasheet?

Note that I am a different Andrey, and I can't speak about the
original panel that caused the issue. However, production units are
shipped with this panel:

https://www.data-modul.com/productfinder/sites/default/files/products/NL192108AC13-02D_specification_12023727.pdf

which seems to do pretty standard DP stuff. In all of my testing of
Tomi's patches, I haven't seen any problems so far (I still have to
test v3 though), so I think we can carefully proceed assuming that
that weird panel was just a fluke.

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCHv2 02/22] drm/bridge: tc358767: reset voltage-swing & pre-emphasis

2019-04-29 Thread Andrey Smirnov
On Fri, Apr 26, 2019 at 7:14 AM Tomi Valkeinen  wrote:
>
> On 20/04/2019 23:30, Laurent Pinchart wrote:
> > Hi Tomi,
> >
> > Thank you for the patch.
> >
> > On Tue, Mar 26, 2019 at 12:31:26PM +0200, Tomi Valkeinen wrote:
> >> We need to reset DPCD voltage-swing & pre-emphasis before starting the
> >> link training, as otherwise tc358767 will use the previous values as
> >> minimums.
> >>
> >> Signed-off-by: Tomi Valkeinen 
> >> ---
> >>  drivers/gpu/drm/bridge/tc358767.c | 6 ++
> >>  1 file changed, 6 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/bridge/tc358767.c 
> >> b/drivers/gpu/drm/bridge/tc358767.c
> >> index 7031c4f52c57..11a50f7bb4be 100644
> >> --- a/drivers/gpu/drm/bridge/tc358767.c
> >> +++ b/drivers/gpu/drm/bridge/tc358767.c
> >> @@ -956,6 +956,12 @@ static int tc_main_link_setup(struct tc_data *tc)
> >>  if (ret < 0)
> >>  goto err_dpcd_write;
> >>
> >> +// Reset voltage-swing & pre-emphasis
> >
> > The driver uses C-style comments, I think it would be best to stick to
> > them to avoid a style mismatch.
>
> Oops. Yep. I often use c++ comments when hacking/developing as they're
> often easier to use. Sometimes I miss converting them to c comments...
>
> >
> >> +tmp[0] = tmp[1] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | 
> >> DP_TRAIN_PRE_EMPH_LEVEL_0;
> >
> > You may want to wrap the line.
>
> Well, I personally don't think wrapping at 80 is a good idea.

Trying to read two files side by side on a 13" laptop screen might
change your mind :-) +1 on wrapping the code around 80 character from
me.

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCHv2 21/22] drm/bridge: tc358767: add IRQ and HPD support

2019-04-15 Thread Andrey Smirnov
On Fri, Apr 12, 2019 at 1:02 AM Tomi Valkeinen  wrote:
>
> Hi Andrey,
>
> On 03/04/2019 14:34, Tomi Valkeinen wrote:
> > On 02/04/2019 05:16, Andrey Smirnov wrote:
> >
> >> The early return above causes tc_get_display_props() to never be
> >> called for eDP case, which in turn result in tc_mode_valid() returning
> >> MODE_BAD for every mode it is given since it depends on tc->link.base
> >> being initialized properly. I had to change this code to:
> >>
> >> if (tc->hpd_num < 0) {
> >> if (!tc->panel)
> >> return connector_status_unknown;
> >>
> >> conn = true;
> >> } else {
> >> tc_read(GPIOI, );
> >>
> >> conn = val & BIT(tc->hpd_num);
> >> }
> >>
> >> to fix the problem.
> >
> > Ah, right. There's tc_get_display_props() in tc_bridge_enable() but
> > that's of course too late (and maybe even not needed at all).
> >
> > What you suggest here looks fine to me, so I'll change my patch
> > accordingly. Thanks!
>
> With the change above, does the series work with your setup? Can I add
> your tested-by? I'll send v3 series soon with the DT change suggested by
> Rob and the above fix.
>

Yeah, other than that, the series seemed to work as expected on my
setup. You can add

Tested-by: Andrey Smirnov 

to v3.

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCHv2 21/22] drm/bridge: tc358767: add IRQ and HPD support

2019-04-02 Thread Andrey Smirnov
On Tue, Mar 26, 2019 at 3:33 AM Tomi Valkeinen  wrote:
>
> Add support for interrupt and hotplug handling. Both are optional.
>
> Signed-off-by: Tomi Valkeinen 
> ---
>  drivers/gpu/drm/bridge/tc358767.c | 157 ++
>  1 file changed, 139 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358767.c 
> b/drivers/gpu/drm/bridge/tc358767.c
> index 8606de29c9b2..6978129428a8 100644
> --- a/drivers/gpu/drm/bridge/tc358767.c
> +++ b/drivers/gpu/drm/bridge/tc358767.c
> @@ -71,6 +71,7 @@
>
>  /* System */
>  #define TC_IDREG   0x0500
> +#define SYSSTAT0x0508
>  #define SYSCTRL0x0510
>  #define DP0_AUDSRC_NO_INPUT(0 << 3)
>  #define DP0_AUDSRC_I2S_RX  (1 << 3)
> @@ -79,9 +80,16 @@
>  #define DP0_VIDSRC_DPI_RX  (2 << 0)
>  #define DP0_VIDSRC_COLOR_BAR   (3 << 0)
>  #define GPIOM  0x0540
> +#define GPIOC  0x0544
> +#define GPIOO  0x0548
>  #define GPIOI  0x054c
>  #define INTCTL_G   0x0560
>  #define INTSTS_G   0x0564
> +
> +#define INT_SYSERR BIT(16)
> +#define INT_GPIO_H(x)  (1 << (x == 0 ? 2 : 10))
> +#define INT_GPIO_LC(x) (1 << (x == 0 ? 3 : 11))
> +
>  #define INT_GP0_LCNT   0x0584
>  #define INT_GP1_LCNT   0x0588
>
> @@ -219,6 +227,12 @@ struct tc_data {
> struct gpio_desc*sd_gpio;
> struct gpio_desc*reset_gpio;
> struct clk  *refclk;
> +
> +   /* do we have IRQ */
> +   boolhave_irq;
> +
> +   /* HPD pin number (0 or 1) or -ENODEV */
> +   int hpd_num;
>  };
>
>  static inline struct tc_data *aux_to_tc(struct drm_dp_aux *a)
> @@ -1095,6 +1109,12 @@ static void tc_bridge_enable(struct drm_bridge *bridge)
> struct tc_data *tc = bridge_to_tc(bridge);
> int ret;
>
> +   ret = tc_get_display_props(tc);
> +   if (ret < 0) {
> +   dev_err(tc->dev, "failed to read display props: %d\n", ret);
> +   return;
> +   }
> +
> ret = tc_main_link_enable(tc);
> if (ret < 0) {
> dev_err(tc->dev, "main link enable error: %d\n", ret);
> @@ -1200,19 +1220,42 @@ static int tc_connector_get_modes(struct 
> drm_connector *connector)
> return count;
>  }
>
> -static void tc_connector_set_polling(struct tc_data *tc,
> -struct drm_connector *connector)
> -{
> -   /* TODO: add support for HPD */
> -   connector->polled = DRM_CONNECTOR_POLL_CONNECT |
> -   DRM_CONNECTOR_POLL_DISCONNECT;
> -}
> -
>  static const struct drm_connector_helper_funcs tc_connector_helper_funcs = {
> .get_modes = tc_connector_get_modes,
>  };
>
> +static enum drm_connector_status tc_connector_detect(struct drm_connector 
> *connector, bool force)
> +{
> +   struct tc_data *tc = connector_to_tc(connector);
> +   bool conn;
> +   u32 val;
> +   int ret;
> +
> +   if (tc->hpd_num < 0) {
> +   if (tc->panel)
> +   return connector_status_connected;
> +   else
> +   return connector_status_unknown;
> +   }
> +

The early return above causes tc_get_display_props() to never be
called for eDP case, which in turn result in tc_mode_valid() returning
MODE_BAD for every mode it is given since it depends on tc->link.base
being initialized properly. I had to change this code to:

if (tc->hpd_num < 0) {
if (!tc->panel)
return connector_status_unknown;

conn = true;
} else {
tc_read(GPIOI, );

conn = val & BIT(tc->hpd_num);
}

to fix the problem.

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v2 02/15] drm/bridge: tc358767: Simplify polling in tc_main_link_setup()

2019-03-24 Thread Andrey Smirnov
Replace explicit polling loop with equivalent call to
tc_poll_timeout() for brevity. No functional change intended.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 15 +--
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 89a4392dfa35..2531f4dadbf8 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -761,7 +761,6 @@ static int tc_main_link_enable(struct tc_data *tc)
struct device *dev = tc->dev;
unsigned int rate;
u32 dp_phy_ctrl;
-   int timeout;
u32 value;
int ret;
u8 tmp[8];
@@ -817,15 +816,11 @@ static int tc_main_link_enable(struct tc_data *tc)
dp_phy_ctrl &= ~(DP_PHY_RST | PHY_M1_RST | PHY_M0_RST);
tc_write(DP_PHY_CTRL, dp_phy_ctrl);
 
-   timeout = 1000;
-   do {
-   tc_read(DP_PHY_CTRL, );
-   udelay(1);
-   } while ((!(value & PHY_RDY)) && (--timeout));
-
-   if (timeout == 0) {
-   dev_err(dev, "timeout waiting for phy become ready");
-   return -ETIMEDOUT;
+   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
+   if (ret) {
+   if (ret == -ETIMEDOUT)
+   dev_err(dev, "timeout waiting for phy become ready");
+   return ret;
}
 
/* Set misc: 8 bits per color */
-- 
2.20.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCH v2 08/15] drm/bridge: tc358767: Increase AUX transfer length limit

2019-03-24 Thread Andrey Smirnov
On Fri, Mar 22, 2019 at 6:14 AM Tomi Valkeinen  wrote:
>
> On 22/03/2019 05:28, Andrey Smirnov wrote:
> > According to the datasheet tc358767 can transfer up to 16 bytes via
> > its AUX channel, so the artificial limit of 8 apperas to be too
> > low. However only up to 15-bytes seem to be actually supported and
> > trying to use 16-byte transfers results in transfers failing
> > sporadically (with bogus status in case of I2C transfers), so limit it
> > to 15.
>
> 16 is the limit from the DP spec. I agree, 8 looks odd.
>
> 15 looks odd too, so I think it warrants a comment there in the code.
>

Crap, was going to add that, but forgot. Will do in v2.

> Does 15 byte transfers ever work? Or mostly works but sometimes fails?
>

15 bytes transfers work every time (at least to extent I tested it).
For 16 byte transfers it depends on the transfer type. AUX transfers
work for a while but then fail (as tested by dd'ing AUX chardev). I2C
transfers work intermittently and when they fail return completely
bogus status.

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v2 10/15] drm/bridge: tc358767: Add support for address-only I2C transfers

2019-03-24 Thread Andrey Smirnov
Transfer size of zero means a request to do an address-only
transfer. Since the HW support this, we probably shouldn't be just
ignoring such requests. While at it allow DP_AUX_I2C_MOT flag to pass
through, since it is supported by the HW as well.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 30 +++---
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 7e4607c6907f..768f01cc2a30 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -137,6 +137,8 @@
 
 /* AUX channel */
 #define DP0_AUXCFG00x0660
+#define DP0_AUXCFG0_BSIZE  GENMASK(11, 8)
+#define DP0_AUXCFG0_ADDR_ONLY  BIT(4)
 #define DP0_AUXCFG10x0664
 #define AUX_RX_FILTER_EN   BIT(16)
 
@@ -331,6 +333,18 @@ static int tc_aux_read_data(struct tc_data *tc, void 
*data, size_t size)
return size;
 }
 
+static u32 tc_auxcfg0(struct drm_dp_aux_msg *msg, size_t size)
+{
+   u32 auxcfg0 = msg->request;
+
+   if (size)
+   auxcfg0 |= FIELD_PREP(DP0_AUXCFG0_BSIZE, size - 1);
+   else
+   auxcfg0 |= DP0_AUXCFG0_ADDR_ONLY;
+
+   return auxcfg0;
+}
+
 static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
@@ -340,9 +354,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;
 
-   if (size == 0)
-   return 0;
-
ret = tc_aux_wait_busy(tc, 100);
if (ret)
return ret;
@@ -366,8 +377,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
/* Start transfer */
-   ret = regmap_write(tc->regmap, DP0_AUXCFG0,
-  ((size - 1) << 8) | request);
+   ret = regmap_write(tc->regmap, DP0_AUXCFG0, tc_auxcfg0(msg, size));
if (ret)
return ret;
 
@@ -381,8 +391,14 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
 
if (auxstatus & AUX_TIMEOUT)
return -ETIMEDOUT;
-
-   size = FIELD_GET(AUX_BYTES, auxstatus);
+   /*
+* For some reason address-only DP_AUX_I2C_WRITE (MOT), still
+* reports 1 byte transferred in its status. To deal we that
+* we ignore aux_bytes field if we know that this was an
+* address-only transfer
+*/
+   if (size)
+   size = FIELD_GET(AUX_BYTES, auxstatus);
msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
 
switch (request) {
-- 
2.20.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCH v2 00/15] tc358767 driver improvements

2019-03-24 Thread Andrey Smirnov
On Fri, Mar 22, 2019 at 1:06 AM Tomi Valkeinen  wrote:
>
> Hi,
>
> On 22/03/2019 05:28, Andrey Smirnov wrote:
> > Everyone:
> >
> > This series contains various improvements (at least in my mind) and
> > fixes that I made to tc358767 while working with the code of the
> > driver. Hopefuly each patch is self explanatory.
> >
> > Feedback is welcome!

Ugh, I just realized that I messed up CC list of "drm/bridge:
tc358767: Simplify AUX data read" and it only went to dri-devel. Will
fix in next version.

>
> Ah, I hadn't realized there was another series for tc358767 going
> around. I should've checked dri-devel list. Sorry about that!
>

No worries, lucky for me Lucas Stach noticed your series and pointed
me to it, so it all worked out in the end.

> I'm not able to apply your patches, it fails at "Simplify
> tc_set_video_mode()", even if I think I've got the exact same base as
> you have.
>
> Can you push your branch somewhere?

Sure, it should be available here:
https://github.com/ndreys/linux/commits/rdu1-rdu2 Please ignore
"drm/bridge: tc358767: Add code to control VDCC rail", sitting on top.
I need it on my board, but it's currently purely experimental and not
meant to be upstreamed yet (or maybe ever)

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCH v2 07/15] drm/bridge: tc358767: Simplify AUX data write

2019-03-24 Thread Andrey Smirnov
On Fri, Mar 22, 2019 at 3:51 AM Tomi Valkeinen  wrote:
>
> On 22/03/2019 05:28, Andrey Smirnov wrote:
> > Simplify AUX data write by dropping index arithmetic and shifting and
> > replacing it with a call to a helper function that does three things:
> >
> > 1. Copies user-provided data into a write buffer
> > 2. Optionally fixes the endianness of the write buffer (not needed
> >on LE hosts)
> > 3. Transfers contenst of the write buffer to up to 4 32-bit
> >registers on the chip
> >
> > Note that separate data endianness fix:
> >
> > tmp = (tmp << 8) | buf[i];
> >
> > that was reserved for DP_AUX_I2C_WRITE looks really strange, since it
> > will place data differently depending on the passed user-data
> > size. E.g. for a write of 1 byte, data transferred to the chip would
> > look like:
> >
> > [byte0] [dummy1] [dummy2] [dummy3]
> >
> > whereas for a write of 4 bytes we'd get:
> >
> > [byte3] [byte2] [byte1] [byte0]
> >
> > Since there's no indication in the datasheet that I2C write buffer
> > should be treated differently than AUX write buffer and no comment in
> > the original code explaining why it was done this way, that special
> > I2C write buffer transformation was dropped in this patch.
> >
> > Signed-off-by: Andrey Smirnov 
> > Cc: Archit Taneja 
> > Cc: Andrzej Hajda 
> > Cc: Laurent Pinchart 
> > Cc: Tomi Valkeinen 
> > Cc: Andrey Gusakov 
> > Cc: Philipp Zabel 
> > Cc: Chris Healy 
> > Cc: Lucas Stach 
> > Cc: dri-devel@lists.freedesktop.org
> > Cc: linux-ker...@vger.kernel.org
> > ---
> >  drivers/gpu/drm/bridge/tc358767.c | 58 +++
> >  1 file changed, 36 insertions(+), 22 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/tc358767.c 
> > b/drivers/gpu/drm/bridge/tc358767.c
> > index 81c10a5d8106..21374565585d 100644
> > --- a/drivers/gpu/drm/bridge/tc358767.c
> > +++ b/drivers/gpu/drm/bridge/tc358767.c
> > @@ -307,6 +307,31 @@ static int tc_aux_get_status(struct tc_data *tc, u8 
> > *reply)
> >   return 0;
> >  }
> >
> > +static int tc_aux_write_data(struct tc_data *tc, const void *data,
> > +  size_t size)
> > +{
> > + u32 auxwdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)] = { 0 };
> > + int ret, i, count = DIV_ROUND_UP(size, 4);
>
> Should 4 there be sizeof(u32)?

Yup, will replace.

>
> > +
> > + memcpy(auxwdata, data, size);
> > +
> > + for (i = 0; i < count; i++) {
> > + ret = regmap_write(tc->regmap, DP0_AUXWDATA(i),
> > +/*
> > + * Our regmap is configured as LE
> > + * for register data, so we need
> > + * undo any byte swapping that will
> > + * happened to preserve original
> > + * byte order.
> > + */
> > +cpu_to_le32(auxwdata[i]));
>
> Can regmap_bulk_write or regmap_raw_write be used here?
>

Not sure, will give it a try.

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v2 04/15] drm/bridge: tc358767: Simplify tc_set_video_mode()

2019-03-24 Thread Andrey Smirnov
Simplify tc_set_video_mode() by replacing repreated calls to
tc_write()/regmap_write() with a single call to
regmap_multi_reg_write(). While at it, simplify explicit shifting by
using macros from . No functional change intended.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 146 +-
 1 file changed, 85 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 38d542f553cd..d99c9f32a133 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -24,6 +24,7 @@
  * GNU General Public License for more details.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -56,6 +57,7 @@
 
 /* Video Path */
 #define VPCTRL00x0450
+#define VSDELAYGENMASK(31, 20)
 #define OPXLFMT_RGB666 (0 << 8)
 #define OPXLFMT_RGB888 (1 << 8)
 #define FRMSYNC_DISABLED   (0 << 4) /* Video Timing Gen Disabled */
@@ -63,9 +65,17 @@
 #define MSF_DISABLED   (0 << 0) /* Magic Square FRC disabled */
 #define MSF_ENABLED(1 << 0) /* Magic Square FRC enabled */
 #define HTIM01 0x0454
+#define HPWGENMASK(8, 0)
+#define HBPR   GENMASK(24, 16)
 #define HTIM02 0x0458
+#define HDISPR GENMASK(10, 0)
+#define HFPR   GENMASK(24, 16)
 #define VTIM01 0x045c
+#define VSPR   GENMASK(7, 0)
+#define VBPR   GENMASK(23, 16)
 #define VTIM02 0x0460
+#define VFPR   GENMASK(23, 16)
+#define VDISPR GENMASK(10, 0)
 #define VFUEN0 0x0464
 #define VFUEN  BIT(0)   /* Video Frame Timing Upload */
 
@@ -100,14 +110,28 @@
 /* Main Channel */
 #define DP0_SECSAMPLE  0x0640
 #define DP0_VIDSYNCDELAY   0x0644
+#define VID_SYNC_DLY   GENMASK(15, 0)
+#define THRESH_DLY GENMASK(31, 16)
+
 #define DP0_TOTALVAL   0x0648
+#define H_TOTALGENMASK(15, 0)
+#define V_TOTALGENMASK(31, 16)
 #define DP0_STARTVAL   0x064c
+#define H_STARTGENMASK(15, 0)
+#define V_STARTGENMASK(31, 16)
 #define DP0_ACTIVEVAL  0x0650
+#define H_ACT  GENMASK(15, 0)
+#define V_ACT  GENMASK(31, 16)
+
 #define DP0_SYNCVAL0x0654
+#define VS_WIDTH   GENMASK(30, 16)
+#define HS_WIDTH   GENMASK(14, 0)
 #define SYNCVAL_HS_POL_ACTIVE_LOW  (1 << 15)
 #define SYNCVAL_VS_POL_ACTIVE_LOW  (1 << 31)
 #define DP0_MISC   0x0658
 #define TU_SIZE_RECOMMENDED(63) /* LSCLK cycles per TU */
+#define MAX_TU_SYMBOL  GENMASK(28, 23)
+#define TU_SIZEGENMASK(21, 16)
 #define BPC_6  (0 << 5)
 #define BPC_8  (1 << 5)
 
@@ -184,6 +208,12 @@
 
 /* Test & Debug */
 #define TSTCTL 0x0a00
+#define COLOR_RGENMASK(31, 24)
+#define COLOR_GGENMASK(23, 16)
+#define COLOR_BGENMASK(15, 8)
+#define ENI2CFILTERBIT(4)
+#define COLOR_BAR_MODE GENMASK(1, 0)
+#define COLOR_BAR_MODE_BARS2
 #define PLL_DBG0x0a04
 
 static bool tc_test_pattern;
@@ -647,10 +677,6 @@ static int tc_get_display_props(struct tc_data *tc)
 
 static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode)
 {
-   int ret;
-   int vid_sync_dly;
-   int max_tu_symbol;
-
int left_margin = mode->htotal - mode->hsync_end;
int right_margin = mode->hsync_start - mode->hdisplay;
int hsync_len = mode->hsync_end - mode->hsync_start;
@@ -659,76 +685,74 @@ static int tc_set_video_mode(struct tc_data *tc, struct 
drm_display_mode *mode)
int vsync_len = mode->vsync_end - mode->vsync_start;
 
/*
-* Recommended maximum number of symbols transferred in a transfer unit:
+* Recommended maximum number of symbols transferred in a
+* transfer unit:
 * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size,
 *  (output active video bandwidth in bytes))
 * Must be less than tu_size.
 */
-   max_tu_symbol = TU_SIZE_RECOMMENDED - 1;
-
-   dev_dbg(tc->dev, "set mode %dx%d\n",
-   mode->hdisplay, mode->vdisplay);
-   dev_dbg(tc->dev, "H margin %d,%d sync %d\

[PATCH v2 01/15] drm/bridge: tc358767: Simplify tc_poll_timeout()

2019-03-24 Thread Andrey Smirnov
Implementation of tc_poll_timeout() is almost a 100% copy-and-paste of
the code for regmap_read_poll_timeout(). Replace copied code with a
call to the original. While at it change tc_poll_timeout to accept
"struct tc_data *" instead of "struct regmap *" for brevity. No
functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Andrzej Hajda 
Reviewed-by: Laurent Pinchart 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 26 ++
 1 file changed, 6 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 51095ab1e996..89a4392dfa35 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -250,34 +250,21 @@ static inline struct tc_data *connector_to_tc(struct 
drm_connector *c)
goto err;   \
} while (0)
 
-static inline int tc_poll_timeout(struct regmap *map, unsigned int addr,
+static inline int tc_poll_timeout(struct tc_data *tc, unsigned int addr,
  unsigned int cond_mask,
  unsigned int cond_value,
  unsigned long sleep_us, u64 timeout_us)
 {
-   ktime_t timeout = ktime_add_us(ktime_get(), timeout_us);
unsigned int val;
-   int ret;
 
-   for (;;) {
-   ret = regmap_read(map, addr, );
-   if (ret)
-   break;
-   if ((val & cond_mask) == cond_value)
-   break;
-   if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) {
-   ret = regmap_read(map, addr, );
-   break;
-   }
-   if (sleep_us)
-   usleep_range((sleep_us >> 2) + 1, sleep_us);
-   }
-   return ret ?: (((val & cond_mask) == cond_value) ? 0 : -ETIMEDOUT);
+   return regmap_read_poll_timeout(tc->regmap, addr, val,
+   (val & cond_mask) == cond_value,
+   sleep_us, timeout_us);
 }
 
 static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
 {
-   return tc_poll_timeout(tc->regmap, DP0_AUXSTATUS, AUX_BUSY, 0,
+   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
   1000, 1000 * timeout_ms);
 }
 
@@ -584,8 +571,7 @@ static int tc_aux_link_setup(struct tc_data *tc)
tc_write(DP1_PLLCTRL, PLLUPDATE | PLLEN);
tc_wait_pll_lock(tc);
 
-   ret = tc_poll_timeout(tc->regmap, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1,
- 1000);
+   ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
dev_err(tc->dev, "Timeout waiting for PHY to become ready");
return ret;
-- 
2.20.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v2 12/15] drm/bridge: tc358767: Introduce tc_pllupdate_pllen()

2019-03-24 Thread Andrey Smirnov
tc_wait_pll_lock() is always called as a follow-up for updating
PLLUPDATE and PLLEN bit of a given PLL control register. To simplify
things, merge the two operation into a single helper function
tc_pllupdate_pllen() and convert the rest of the code to use it. No
functional change intended.

Signed-off-by: Andrey Smirnov 
Reviewed-by: Laurent Pinchart 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 32 +++
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 976a9861e537..f66a1c4a2047 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -447,10 +447,18 @@ static u32 tc_srcctrl(struct tc_data *tc)
return reg;
 }
 
-static void tc_wait_pll_lock(struct tc_data *tc)
+static int tc_pllupdate_pllen(struct tc_data *tc, unsigned int pllctrl)
 {
+   int ret;
+
+   ret = regmap_write(tc->regmap, pllctrl, PLLUPDATE | PLLEN);
+   if (ret)
+   return ret;
+
/* Wait for PLL to lock: up to 2.09 ms, depending on refclk */
usleep_range(3000, 6000);
+
+   return 0;
 }
 
 static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
@@ -550,13 +558,7 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, 
u32 pixelclock)
return ret;
 
/* Force PLL parameter update and disable bypass */
-   ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLUPDATE | PLLEN);
-   if (ret)
-   return ret;
-
-   tc_wait_pll_lock(tc);
-
-   return 0;
+   return tc_pllupdate_pllen(tc, PXL_PLLCTRL);
 }
 
 static int tc_pxl_pll_dis(struct tc_data *tc)
@@ -615,7 +617,6 @@ static int tc_set_syspllparam(struct tc_data *tc)
 static int tc_aux_link_setup(struct tc_data *tc)
 {
int ret;
-   u32 dp_phy_ctrl;
u32 dp0_auxcfg1;
 
/* Setup DP-PHY / PLL */
@@ -630,15 +631,13 @@ static int tc_aux_link_setup(struct tc_data *tc)
 * Initially PLLs are in bypass. Force PLL parameter update,
 * disable PLL bypass, enable PLL
 */
-   ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP0_PLLCTRL);
if (ret)
goto err;
-   tc_wait_pll_lock(tc);
 
-   ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP1_PLLCTRL);
if (ret)
goto err;
-   tc_wait_pll_lock(tc);
 
ret = tc_poll_timeout(tc, DP_PHY_CTRL, PHY_RDY, PHY_RDY, 1, 1000);
if (ret == -ETIMEDOUT) {
@@ -823,6 +822,7 @@ static int tc_main_link_enable(struct tc_data *tc)
 {
struct drm_dp_aux *aux = >aux;
struct device *dev = tc->dev;
+   u32 dp_phy_ctrl;
u32 value;
int ret;
u8 tmp[8];
@@ -858,15 +858,13 @@ static int tc_main_link_enable(struct tc_data *tc)
return ret;
 
/* PLL setup */
-   ret = regmap_write(tc->regmap, DP0_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP0_PLLCTRL);
if (ret)
return ret;
-   tc_wait_pll_lock(tc);
 
-   ret = regmap_write(tc->regmap, DP1_PLLCTRL, PLLUPDATE | PLLEN);
+   ret = tc_pllupdate_pllen(tc, DP1_PLLCTRL);
if (ret)
return ret;
-   tc_wait_pll_lock(tc);
 
/* Reset/Enable Main Links */
dp_phy_ctrl |= DP_PHY_RST | PHY_M1_RST | PHY_M0_RST;
-- 
2.20.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCH v2 05/15] drm/bridge: tc358767: Drop custom tc_write()/tc_read() accessors

2019-03-24 Thread Andrey Smirnov
On Fri, Mar 22, 2019 at 3:29 AM Tomi Valkeinen  wrote:
>
> On 22/03/2019 05:28, Andrey Smirnov wrote:
> > A very unfortunate aspect of tc_write()/tc_read() macro helpers is
> > that they capture quite a bit of context around them and thus require
> > the caller to have magic variables 'ret' and 'tc' as well as label
> > 'err'. That makes a number of code paths rather counterintuitive and
> > somewhat clunky, for example tc_stream_clock_calc() ends up being like
> > this:
> >
> >   int ret;
> >
> >   tc_write(DP0_VIDMNGEN1, 32768);
> >
> >   return 0;
> > err:
> >   return ret;
> >
> > which is rather surprising when you read the code for the first
> > time. Since those helpers arguably aren't really saving that much code
> > and there's no way of fixing them without making them too verbose to
> > be worth it change the driver code to not use them at all.
>
> I fully agree with this patch and thought about the same thing during my
> work.
>
> However, the timing of this patch is not too good, as this one will
> totally conflict with any other patch for tc358767, and my series is
> still evolving.
>

The reason I rebased this series on top of yours is because I think
mine should go after yours gets accepted and lands in the tree. I am
more than happy to wait for your series to mature. This submission was
done mostly for the sake of discussion, looping original authors in as
well as making you aware of its existence.

> We need to figure out how to combine this series and mine, but I think
> either this patch should be dropped for now, and reapplied after the
> other patches have stabilized, or I think preferably, this one could be
> rebased on top of 5.1-rc1, and used as a base for all other tc358767 work.
>

I think waiting for your work to be done before proceeding to apply
this series, should solve this problem.

Thanks,
Andrey Smirnov
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v2 08/15] drm/bridge: tc358767: Increase AUX transfer length limit

2019-03-24 Thread Andrey Smirnov
According to the datasheet tc358767 can transfer up to 16 bytes via
its AUX channel, so the artificial limit of 8 apperas to be too
low. However only up to 15-bytes seem to be actually supported and
trying to use 16-byte transfers results in transfers failing
sporadically (with bogus status in case of I2C transfers), so limit it
to 15.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 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 21374565585d..8adaac5ca271 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -358,7 +358,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
struct tc_data *tc = aux_to_tc(aux);
-   size_t size = min_t(size_t, 8, msg->size);
+   size_t size = min_t(size_t, DP_AUX_MAX_PAYLOAD_BYTES - 1, msg->size);
u8 request = msg->request & ~DP_AUX_I2C_MOT;
int ret;
 
-- 
2.20.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Re: [PATCH v2 04/15] drm/bridge: tc358767: Simplify tc_set_video_mode()

2019-03-24 Thread Andrey Smirnov
On Fri, Mar 22, 2019 at 3:19 AM Tomi Valkeinen  wrote:
>
> On 22/03/2019 05:28, Andrey Smirnov wrote:
> > Simplify tc_set_video_mode() by replacing repreated calls to
> > tc_write()/regmap_write() with a single call to
> > regmap_multi_reg_write(). While at it, simplify explicit shifting by
> > using macros from . No functional change intended.
> >
> > Signed-off-by: Andrey Smirnov 
> > Cc: Archit Taneja 
> > Cc: Andrzej Hajda 
> > Cc: Laurent Pinchart 
> > Cc: Tomi Valkeinen 
> > Cc: Andrey Gusakov 
> > Cc: Philipp Zabel 
> > Cc: Chris Healy 
> > Cc: Lucas Stach 
> > Cc: dri-devel@lists.freedesktop.org
> > Cc: linux-ker...@vger.kernel.org
> > ---
> >  drivers/gpu/drm/bridge/tc358767.c | 146 +-
> >  1 file changed, 85 insertions(+), 61 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/tc358767.c 
> > b/drivers/gpu/drm/bridge/tc358767.c
> > index 38d542f553cd..d99c9f32a133 100644
> > --- a/drivers/gpu/drm/bridge/tc358767.c
> > +++ b/drivers/gpu/drm/bridge/tc358767.c
> > @@ -24,6 +24,7 @@
> >   * GNU General Public License for more details.
> >   */
> >
> > +#include 
> >  #include 
> >  #include 
> >  #include 
> > @@ -56,6 +57,7 @@
> >
> >  /* Video Path */
> >  #define VPCTRL0  0x0450
> > +#define VSDELAY  GENMASK(31, 20)
> >  #define OPXLFMT_RGB666   (0 << 8)
> >  #define OPXLFMT_RGB888   (1 << 8)
> >  #define FRMSYNC_DISABLED (0 << 4) /* Video Timing Gen Disabled 
> > */
> > @@ -63,9 +65,17 @@
> >  #define MSF_DISABLED (0 << 0) /* Magic Square FRC disabled 
> > */
> >  #define MSF_ENABLED  (1 << 0) /* Magic Square FRC enabled 
> > */
> >  #define HTIM01   0x0454
> > +#define HPW  GENMASK(8, 0)
> > +#define HBPR GENMASK(24, 16)
> >  #define HTIM02   0x0458
> > +#define HDISPR   GENMASK(10, 0)
> > +#define HFPR GENMASK(24, 16)
> >  #define VTIM01   0x045c
> > +#define VSPR GENMASK(7, 0)
> > +#define VBPR GENMASK(23, 16)
> >  #define VTIM02   0x0460
> > +#define VFPR GENMASK(23, 16)
> > +#define VDISPR   GENMASK(10, 0)
> >  #define VFUEN0   0x0464
> >  #define VFUENBIT(0)   /* Video Frame 
> > Timing Upload */
> >
> > @@ -100,14 +110,28 @@
> >  /* Main Channel */
> >  #define DP0_SECSAMPLE0x0640
> >  #define DP0_VIDSYNCDELAY 0x0644
> > +#define VID_SYNC_DLY GENMASK(15, 0)
> > +#define THRESH_DLY   GENMASK(31, 16)
> > +
> >  #define DP0_TOTALVAL 0x0648
> > +#define H_TOTAL  GENMASK(15, 0)
> > +#define V_TOTAL  GENMASK(31, 16)
> >  #define DP0_STARTVAL 0x064c
> > +#define H_START  GENMASK(15, 0)
> > +#define V_START  GENMASK(31, 16)
> >  #define DP0_ACTIVEVAL0x0650
> > +#define H_ACTGENMASK(15, 0)
> > +#define V_ACTGENMASK(31, 16)
> > +
> >  #define DP0_SYNCVAL  0x0654
> > +#define VS_WIDTH GENMASK(30, 16)
> > +#define HS_WIDTH GENMASK(14, 0)
> >  #define SYNCVAL_HS_POL_ACTIVE_LOW(1 << 15)
> >  #define SYNCVAL_VS_POL_ACTIVE_LOW(1 << 31)
> >  #define DP0_MISC 0x0658
> >  #define TU_SIZE_RECOMMENDED  (63) /* LSCLK cycles per TU */
> > +#define MAX_TU_SYMBOLGENMASK(28, 23)
> > +#define TU_SIZE  GENMASK(21, 16)
> >  #define BPC_6(0 << 5)
> >  #define BPC_8(1 << 5)
> >
> > @@ -184,6 +208,12 @@
> >
> >  /* Test & Debug */
> >  #define TSTCTL   0x0a00
> > +#define COLOR_R  GENMASK(31, 24)
> > +#define COLOR_G  GENMASK(23, 16)
> > +#define COLOR_B  GENMASK(15, 8)
> > +#define ENI2CFILTER  BIT(4)
> > +#define COLOR_BAR_MODE   GENMASK(1, 0)
> > +#define COLOR_BAR_MODE_BARS  2
> >  #define PLL_DBG  0x0a04
> >
> >  static bool tc_test_pattern;
> &g

[PATCH v2 06/15] drm/bridge: tc358767: Simplify AUX data read

2019-03-24 Thread Andrey Smirnov
Simplify AUX data read by removing index arithmetic and shifting with
a helper functions that does three things:

1. Fetch data from up to 4 32-bit registers from the chip
2. Optionally fix data endianness (not needed on LE hosts)
3. Copy read data into user provided array.

Signed-off-by: Andrey Smirnov 
---
 drivers/gpu/drm/bridge/tc358767.c | 39 ---
 1 file changed, 26 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index 060e4b05095a..81c10a5d8106 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -307,6 +307,28 @@ static int tc_aux_get_status(struct tc_data *tc, u8 *reply)
return 0;
 }
 
+static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size)
+{
+   u32 auxrdata[DP_AUX_MAX_PAYLOAD_BYTES / sizeof(u32)];
+   int ret, i, count = DIV_ROUND_UP(size, 4);
+
+   for (i = 0; i < count; i++) {
+   ret = regmap_read(tc->regmap, DP0_AUXRDATA(i), [i]);
+   if (ret)
+   return ret;
+   /*
+* Our regmap is configured as LE for register data,
+* so we need undo any byte swapping that might have
+* happened to preserve original byte order.
+*/
+   le32_to_cpus([i]);
+   }
+
+   memcpy(data, auxrdata, size);
+
+   return size;
+}
+
 static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
   struct drm_dp_aux_msg *msg)
 {
@@ -365,19 +387,10 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   if (request == DP_AUX_I2C_READ || request == DP_AUX_NATIVE_READ) {
-   /* Read data */
-   while (i < size) {
-   if ((i % 4) == 0) {
-   ret = regmap_read(tc->regmap,
- DP0_AUXRDATA(i >> 2), );
-   if (ret)
-   return ret;
-   }
-   buf[i] = tmp & 0xff;
-   tmp = tmp >> 8;
-   i++;
-   }
+   switch (request) {
+   case DP_AUX_NATIVE_READ:
+   case DP_AUX_I2C_READ:
+   return tc_aux_read_data(tc, msg->buffer, size);
}
 
return size;
-- 
2.20.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[PATCH v2 13/15] drm/bridge: tc358767: Simplify tc_aux_wait_busy()

2019-03-24 Thread Andrey Smirnov
We never pass anything but 100 as timeout_ms to tc_aux_wait_busy(), so
we may as well hardcode that value and simplify function's signature.

Signed-off-by: Andrey Smirnov 
Cc: Archit Taneja 
Cc: Andrzej Hajda 
Cc: Laurent Pinchart 
Cc: Tomi Valkeinen 
Cc: Andrey Gusakov 
Cc: Philipp Zabel 
Cc: Chris Healy 
Cc: Lucas Stach 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
---
 drivers/gpu/drm/bridge/tc358767.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/tc358767.c 
b/drivers/gpu/drm/bridge/tc358767.c
index f66a1c4a2047..07d568761463 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -280,10 +280,9 @@ static inline int tc_poll_timeout(struct tc_data *tc, 
unsigned int addr,
sleep_us, timeout_us);
 }
 
-static int tc_aux_wait_busy(struct tc_data *tc, unsigned int timeout_ms)
+static int tc_aux_wait_busy(struct tc_data *tc)
 {
-   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0,
-  1000, 1000 * timeout_ms);
+   return tc_poll_timeout(tc, DP0_AUXSTATUS, AUX_BUSY, 0, 1000, 10);
 }
 
 static int tc_aux_write_data(struct tc_data *tc, const void *data,
@@ -354,7 +353,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
u32 auxstatus;
int ret;
 
-   ret = tc_aux_wait_busy(tc, 100);
+   ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
 
@@ -381,7 +380,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
if (ret)
return ret;
 
-   ret = tc_aux_wait_busy(tc, 100);
+   ret = tc_aux_wait_busy(tc);
if (ret)
return ret;
 
-- 
2.20.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  1   2   >